# 画面設計書 115-プリチャットフォーム画面

## 概要

本ドキュメントは、Chatwootのチャットウィジェットにおけるプリチャットフォーム画面の設計書です。顧客がチャットを開始する前に連絡先情報を入力するフォーム画面として機能します。

### 本画面の処理概要

**業務上の目的・背景**：プリチャットフォームは、顧客がサポートチームと会話を開始する前に、名前、メールアドレス、電話番号などの連絡先情報を収集するための画面です。これにより、サポートエージェントは顧客情報を事前に把握でき、より効率的で個人化されたサポートを提供できます。また、会話終了後のフォローアップ連絡にも活用されます。フォームはインボックス設定でカスタマイズ可能であり、必須項目やカスタム属性を設定できます。

**画面へのアクセス方法**：ホーム画面から「Start Conversation」ボタンをクリックした際、プリチャットフォームが有効な場合に遷移します。URLハッシュパスは `/prechat-form` です。

**主要な操作・処理内容**：
1. 名前、メールアドレス、電話番号などの入力
2. カスタム属性フィールドの入力（設定に応じて）
3. 初回メッセージの入力
4. フォームバリデーション
5. 会話の作成と連絡先情報の保存
6. キャンペーン経由の場合のキャンペーン実行

**画面遷移**：
- 遷移元：ホーム画面
- 遷移先：メッセージ画面（会話作成成功後）

**権限による表示制御**：ウィジェットはWebサイト訪問者向けのため、特別な権限制御はありません。表示される入力項目はインボックスのプリチャットフォーム設定に依存します。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 163 | Widget連絡先 | 主機能 | チャット前の情報入力 |

## 画面種別

入力フォーム画面

## URL/ルーティング

- パス: `#/prechat-form`（ウィジェット内ハッシュルーティング）
- ルート名: `prechat-form`
- コンポーネント: `PreChatForm.vue`

## 入出力項目

### 標準入力項目

| 項目名 | 項目ID | 型 | 必須 | バリデーション | 説明 |
|--------|--------|-----|------|---------------|------|
| フルネーム | fullName | string | 設定依存 | - | 顧客の名前 |
| メールアドレス | emailAddress | string | 設定依存 | email形式 | 連絡用メールアドレス |
| 電話番号 | phoneNumber | string | 設定依存 | 国際電話番号形式 | 連絡用電話番号 |
| メッセージ | message | string | Yes | 必須 | 初回メッセージ（キャンペーン時は不要） |

### カスタム属性項目

| 項目名 | 項目ID | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| 会話カスタム属性 | conversationCustomAttributes | object | No | 会話に紐づくカスタム属性 |
| 連絡先カスタム属性 | contactCustomAttributes | object | No | 連絡先に紐づくカスタム属性 |

## 表示項目

### ヘッダーメッセージセクション

| 項目名 | 説明 |
|--------|------|
| ヘッダーメッセージ | プリチャットメッセージまたはキャンペーンヘッダー |

### フォームセクション

| 項目名 | 説明 |
|--------|------|
| 動的フォームフィールド | 設定に基づいた入力項目 |
| メッセージ入力欄 | 初回メッセージ（キャンペーン時は非表示） |
| 送信ボタン | 「Start Conversation」ボタン |
| ローディングスピナー | 送信中のインジケータ |

## イベント仕様

### 1-フォーム送信

**トリガー**: フォームのsubmitイベント

**処理フロー**:
1. FormKitによるバリデーション実行
2. `onSubmit`メソッド呼び出し
3. キャンペーン有無の判定:
   - **キャンペーンあり**:
     - `execute-campaign`イベント発火
     - 連絡先情報を更新（`contacts/update`）
   - **キャンペーンなし**:
     - 既存会話・属性をクリア
     - 新規会話を作成（`conversation/createConversation`）
4. カスタム属性がある場合、`contacts/setCustomAttributes`を実行
5. 会話作成完了後、`ON_CONVERSATION_CREATED`イベントをリッスンしてメッセージ画面へ遷移

### 2-会話作成成功

**トリガー**: `ON_CONVERSATION_CREATED`イベント

**処理フロー**:
1. イベントハンドラ `handleConversationCreated` が呼び出される
2. `router.replace({ name: 'messages' })` でメッセージ画面へ遷移

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| フォーム送信（新規会話） | conversations | INSERT | 新規会話レコード作成 |
| フォーム送信（新規会話） | messages | INSERT | 初回メッセージ作成 |
| フォーム送信（新規会話） | contacts | INSERT/UPDATE | 連絡先情報の作成/更新 |
| カスタム属性設定 | contact_custom_attributes | INSERT/UPDATE | カスタム属性値の保存 |

### テーブル別更新項目詳細

#### conversations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | inbox_id | ウィジェットのインボックスID | インボックス関連付け |
| INSERT | contact_id | 連絡先ID | 連絡先関連付け |
| INSERT | additional_attributes | カスタム属性JSON | 会話属性 |
| INSERT | created_at | 現在時刻 | 作成日時 |

#### contacts

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | name | フォーム入力値（fullName） | 連絡先名 |
| INSERT/UPDATE | email | フォーム入力値（emailAddress） | メールアドレス |
| INSERT/UPDATE | phone_number | フォーム入力値（phoneNumber） | 電話番号 |

## メッセージ仕様

| 種別 | キー | メッセージ内容 | 表示タイミング |
|------|-----|---------------|---------------|
| ラベル | PRE_CHAT_FORM.FIELDS.EMAIL_ADDRESS.LABEL | メールアドレス | フィールドラベル |
| ラベル | PRE_CHAT_FORM.FIELDS.FULL_NAME.LABEL | お名前 | フィールドラベル |
| ラベル | PRE_CHAT_FORM.FIELDS.PHONE_NUMBER.LABEL | 電話番号 | フィールドラベル |
| ラベル | PRE_CHAT_FORM.FIELDS.MESSAGE.LABEL | メッセージ | フィールドラベル |
| エラー | PRE_CHAT_FORM.REQUIRED | この項目は必須です | 必須項目未入力時 |
| エラー | PRE_CHAT_FORM.FIELDS.EMAIL_ADDRESS.VALID_ERROR | 有効なメールアドレスを入力してください | メール形式不正時 |
| エラー | PRE_CHAT_FORM.FIELDS.PHONE_NUMBER.VALID_ERROR | 有効な電話番号を入力してください | 電話番号形式不正時 |
| エラー | PRE_CHAT_FORM.FIELDS.PHONE_NUMBER.DIAL_CODE_VALID_ERROR | 国番号を含めてください | 国番号なし時 |
| ボタン | START_CONVERSATION | 会話を開始 | 送信ボタン |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| バリデーションエラー | フィールド下部にエラーメッセージ表示 |
| 会話作成失敗 | try-catch内で処理、UIは維持 |
| ネットワークエラー | 送信ボタンの状態リセット |

## 備考

- FormKitライブラリを使用した動的フォーム生成
- 電話番号入力にはカスタムPhoneInputコンポーネントを使用
- 既存の連絡先情報（メール、電話番号、識別子）がある場合、該当フィールドは非表示
- キャンペーン経由のアクセス時はメッセージフィールドが非表示
- 正規表現パターンによるカスタムバリデーションに対応
- emitterを使用したイベント駆動の画面遷移

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

フォーム設定とカスタム属性の構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PreChatForm.vue | `app/javascript/widget/views/PreChatForm.vue` | L36-44: onSubmitの引数構造 |
| 1-2 | Form.vue | `app/javascript/widget/components/PreChat/Form.vue` | L80-82: preChatFields構造 |

**読解のコツ**: preChatFieldsはインボックス設定から動的に取得される配列で、各フィールドのname, type, required, enabled等を含む。

#### Step 2: エントリーポイントを理解する

ルーティングとビューコンポーネントの構成を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | router.js | `app/javascript/widget/router.js` | L28-30: prechat-formルート定義 |
| 2-2 | PreChatForm.vue | `app/javascript/widget/views/PreChatForm.vue` | ビューコンポーネント |

**主要処理フロー**:
1. **L19-21**: マウント時にON_CONVERSATION_CREATEDイベントリスナー登録
2. **L23-24**: アンマウント時にリスナー解除
3. **L29-34**: handleConversationCreated - 遷移処理
4. **L36-73**: onSubmit - フォーム送信処理

#### Step 3: フォームコンポーネントを理解する

FormKitを使用したフォームの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Form.vue | `app/javascript/widget/components/PreChat/Form.vue` | フォームコンポーネント本体 |
| 3-2 | PhoneInput.vue | `app/javascript/widget/components/Form/PhoneInput.vue` | 電話番号入力コンポーネント |

**Form.vue主要処理**:
- **L83-104**: filteredPreChatFields - 既存情報に基づくフィルタリング
- **L106-116**: enabledPreChatFields - 有効なフィールドのみ抽出
- **L178-209**: getValidation - バリデーションルール生成
- **L234-244**: onSubmit - イベント発火

### プログラム呼び出し階層図

```
PreChatForm.vue (ビュー)
    |
    +-- PreChatForm (コンポーネント)
            |
            +-- FormKit (form)
            |       |
            |       +-- FormKit (各フィールド)
            |       |       +-- PhoneInput (電話番号用)
            |       |
            |       +-- FormKit (message textarea)
            |       |
            |       +-- CustomButton (送信ボタン)
            |
            +-- @submitPreChat -> onSubmit()
                    |
                    +-- キャンペーンあり:
                    |       +-- emitter.emit('execute-campaign')
                    |       +-- contacts/update
                    |
                    +-- キャンペーンなし:
                            +-- clearConversations()
                            +-- conversation/createConversation
                                    |
                                    +-- API: createConversationAPI
                                            |
                                            +-- emitter.emit(ON_CONVERSATION_CREATED)
                                                    |
                                                    +-- handleConversationCreated()
                                                            +-- router.replace('messages')
```

### データフロー図

```
[入力]                    [処理]                         [出力]

フォーム入力 ---------> バリデーション ------------> エラー表示（失敗時）
    |                       |
    v                       v
onSubmit() -----------> createConversation ------> API呼び出し
    |                                                   |
    +-- contactCustomAttributes                         v
    |                                              conversations
    +-- conversationCustomAttributes                contacts
                                                    messages
                                                       |
                                                       v
                                               ON_CONVERSATION_CREATED
                                                       |
                                                       v
                                               router -> messages
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PreChatForm.vue | `app/javascript/widget/views/PreChatForm.vue` | ソース | ビューコンポーネント |
| Form.vue | `app/javascript/widget/components/PreChat/Form.vue` | ソース | フォームコンポーネント |
| router.js | `app/javascript/widget/router.js` | ソース | ウィジェットルーティング |
| actions.js | `app/javascript/widget/store/modules/conversation/actions.js` | ソース | createConversationアクション |
| conversation.js | `app/javascript/widget/api/conversation.js` | ソース | 会話API |
| PhoneInput.vue | `app/javascript/widget/components/Form/PhoneInput.vue` | ソース | 電話番号入力 |
| configMixin.js | `app/javascript/widget/mixins/configMixin.js` | ソース | preChatFormOptions提供 |
| widgetBusEvents.js | `app/javascript/widget/constants/widgetBusEvents.js` | ソース | イベント定数 |
