# 画面設計書 31-お問い合わせ画面

## 概要

本ドキュメントは、Bagisto eコマースモバイルアプリにおける「お問い合わせ画面」の画面設計書です。本画面は、ユーザーがアプリ運営者へ問い合わせを送信するためのフォーム画面を提供します。

### 本画面の処理概要

本画面は、ユーザーが名前、メールアドレス、電話番号、メッセージを入力してサポートチームへ問い合わせを送信するための機能を提供します。入力データはバリデーションを経て、GraphQL APIを通じてバックエンドサーバーに送信されます。

**業務上の目的・背景**：ECサイトを利用するユーザーは、商品に関する質問、注文のトラブル、アカウントに関する問題など、様々な理由でサポートへの問い合わせを必要とします。本画面は、ユーザーが直接サポートチームにコンタクトを取るための手段を提供し、顧客満足度の向上とカスタマーサポートの効率化に貢献します。

**画面へのアクセス方法**：ダッシュボード画面またはホーム画面のサイドドロワーメニューから「お問い合わせ」をタップすることでアクセスします。ルーティングは`contactUsScreen`という名前で定義されています。

**主要な操作・処理内容**：
1. 名前フィールドに名前を入力（必須項目）
2. メールアドレスフィールドにメールアドレスを入力（必須項目、メール形式バリデーションあり）
3. 電話番号フィールドに電話番号を入力（必須項目）
4. メッセージフィールドに問い合わせ内容を入力（必須項目）
5. 「送信」ボタンを押下してフォームを送信
6. 送信成功時は成功メッセージが表示され、フォームがクリアされる
7. 送信失敗時はエラーメッセージが表示される

**画面遷移**：本画面からの直接的な画面遷移はありません。送信完了後も同一画面に留まり、フォームがクリアされます。AppBarの戻るボタンで前の画面に戻ることができます。

**権限による表示制御**：本画面はログイン状態に関わらずアクセス可能です。認証は不要であり、ゲストユーザーでも問い合わせを送信できます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 62 | お問い合わせ送信 | 主機能 | お問い合わせフォームからの連絡送信処理 |

## 画面種別

登録（フォーム入力画面）

## URL/ルーティング

- ルート名: `contactUsScreen`
- ルート定数: `const String contactUsScreen = "contactUsScreen";`
- ナビゲーション: `Navigator.pushNamed(context, contactUsScreen)`

## 入出力項目

| 項目名 | 項目ID | 入力/出力 | データ型 | 必須 | バリデーション | 備考 |
|--------|--------|----------|----------|------|----------------|------|
| 名前 | name | 入力 | String | 必須 | 空でないこと | nameControllerで管理 |
| メールアドレス | email | 入力 | String | 必須 | 空でないこと、メール形式であること | emailControllerで管理、EmailValidatorミックスインで検証 |
| 電話番号 | phone | 入力 | String | 必須 | 空でないこと | phoneControllerで管理、キーボードタイプはphone |
| メッセージ | message | 入力 | String | 必須 | 空でないこと | commentControllerで管理、最大4行表示 |

## 表示項目

| 項目名 | 表示位置 | データソース | 表示形式 | 備考 |
|--------|----------|-------------|----------|------|
| 画面タイトル | AppBar | StringConstants.contactUs | テキスト | 「お問い合わせ」 |
| 説明テキスト | フォーム上部 | StringConstants.contactUsDetail | テキスト | フォームの説明 |
| 名前ラベル | テキストフィールド | StringConstants.name | テキスト + 必須マーク(*) | |
| メールラベル | テキストフィールド | StringConstants.email | テキスト + 必須マーク(*) | |
| 電話番号ラベル | テキストフィールド | StringConstants.contactUsPhoneLabel | テキスト + 必須マーク(*) | |
| メッセージラベル | テキストフィールド | StringConstants.whatOnYourMind | テキスト + 必須マーク(*) | |
| 送信ボタン | 画面下部 | StringConstants.submit | ボタン | 大文字で表示 |

## イベント仕様

### 1-送信ボタン押下

ボタン押下時に以下の処理が実行されます：

1. フォームバリデーション実行（`_formKey.currentState!.validate()`）
2. バリデーション成功時、フォーム状態を保存（`_formKey.currentState!.save()`）
3. 各TextEditingControllerから値を取得
4. `ContactUsEvent`イベントをBlocに送信（name, email, phone, message）
5. SnackBarで「Form submitted successfully!」メッセージを表示
6. Bloc内でAPIリクエストを実行

### 2-API応答処理（BlocListener）

- **成功時**：
  - 緑色の通知メッセージを表示（ShowMessage.showNotification）
  - 全TextEditingControllerをクリア
- **失敗時**：
  - 赤色のエラー通知メッセージを表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 送信ボタン押下 | contacts（サーバー側） | INSERT | お問い合わせ内容をサーバーのデータベースに保存 |

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

本画面はGraphQL APIを通じてサーバー側に問い合わせデータを送信します。モバイルアプリ側のローカルデータベースへの更新はありません。

#### GraphQL Mutation: contactUs

| 操作 | 項目（パラメータ） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | ユーザー入力値 | 名前 |
| INSERT | email | ユーザー入力値 | メールアドレス |
| INSERT | phone | ユーザー入力値 | 電話番号 |
| INSERT | message | ユーザー入力値 | 問い合わせ内容 |

## メッセージ仕様

| メッセージID | メッセージ種別 | 表示条件 | メッセージ内容 | 表示方法 |
|-------------|---------------|----------|---------------|----------|
| MSG001 | 成功 | API送信成功時 | サーバーからの成功メッセージ（デフォルト:「Updated」） | 緑色通知バナー |
| MSG002 | エラー | API送信失敗時 | サーバーからのエラーメッセージ | 赤色通知バナー |
| MSG003 | バリデーション | 名前未入力時 | 「Please fill 名前」 | テキストフィールド下部 |
| MSG004 | バリデーション | メール未入力時 | 「Please fill Email」 | テキストフィールド下部 |
| MSG005 | バリデーション | メール形式不正時 | 「Please enter valid email」 | テキストフィールド下部 |
| MSG006 | バリデーション | 電話番号未入力時 | 「Please fill Phone Number」 | テキストフィールド下部 |
| MSG007 | バリデーション | メッセージ未入力時 | 「Please fill Comment」 | テキストフィールド下部 |
| MSG008 | 情報 | 送信ボタン押下時 | 「Form submitted successfully!」 | SnackBar |

## 例外処理

| 例外状況 | 対応処理 | ユーザーへの表示 |
|---------|---------|-----------------|
| ネットワークエラー | catch句でエラーキャッチ | 「SomethingWrong」エラーメッセージ表示 |
| APIエラー応答 | BaseModel.success == false | サーバーからのエラーメッセージを表示 |
| バリデーションエラー | フォーム送信をブロック | 各フィールドにエラーメッセージ表示 |

## 備考

- EmailValidatorミックスインを使用してメールアドレスの形式検証を行う
- BlocパターンによるState管理を採用（ContactUsScreenBloc）
- ScaffoldMessengerKeyを使用して通知メッセージを表示
- 送信成功後、全入力フィールドは自動的にクリアされる
- メッセージフィールドは最大4行表示に設定（maxLines: 4）

---

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

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

### 推奨読解順序

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

まず、APIリクエスト/レスポンスのデータ構造と状態管理のデータ構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | contact_us_event.dart | `lib/screens/contact_us/bloc/contact_us_event.dart` | ContactUsEventクラスで渡されるパラメータ（name, email, phone, describe）を確認 |
| 1-2 | contact_us_state.dart | `lib/screens/contact_us/bloc/contact_us_state.dart` | ContactUsStatusの状態（success, fail）とContactUsStateの構造を確認 |

**読解のコツ**: Flutter Blocパターンでは、EventがActionの役割、Stateが状態の役割を担います。イベントとステートの関係を把握することが重要です。

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

処理の起点となるViewファイルを特定します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | contact_us_view.dart | `lib/screens/contact_us/contact_us_view.dart` | フォームUI構成、バリデーション、Bloc連携を確認 |

**主要処理フロー**:
1. **行27-29**: initStateでContactUsScreenBlocを取得
2. **行73-227**: _reviewForm()でフォームUI構築
3. **行86-199**: 各TextFieldのバリデーション設定
4. **行230-244**: _submitForm()でフォーム送信処理
5. **行47-70**: BlocConsumerでAPI応答をハンドリング

#### Step 3: ビジネスロジック層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | contact_us_bloc.dart | `lib/screens/contact_us/bloc/contact_us_bloc.dart` | イベント受信からリポジトリ呼び出し、状態更新の流れ |

**主要処理フロー**:
- **行34-48**: ContactUsEventを受信し、repositoryのcontactUsRepoScreenを呼び出し
- **行37-40**: 成功時はContactUsState.successを発行
- **行42**: 失敗時はContactUsState.failを発行

#### Step 4: データアクセス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | contact_us_repository.dart | `lib/screens/contact_us/bloc/contact_us_repository.dart` | リポジトリインターフェースと実装 |
| 4-2 | api_client.dart | `lib/services/api_client.dart` | contactUsApiClientメソッドの実装（行1429付近） |
| 4-3 | mutation_query.dart | `lib/services/mutation_query.dart` | contactUsApi GraphQLクエリの定義（行216付近） |

**主要処理フロー**:
- **contact_us_repository.dart 行26-33**: ApiClient().contactUsApiClientを呼び出し
- **api_client.dart 行1429-1442**: GraphQL mutationを実行しBaseModelを返却
- **mutation_query.dart 行216-227**: contactUs mutationのGraphQLクエリ定義

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

```
ContactUsPage (contact_us_view.dart)
    │
    ├─ _submitForm() [行230-244]
    │      └─ ContactUsScreenBloc.add(ContactUsEvent)
    │
    └─ BlocConsumer<ContactUsScreenBloc, ContactUsBaseState>
           │
           └─ ContactUsScreenBloc (contact_us_bloc.dart)
                  │
                  └─ mapEventToState() [行31-51]
                         │
                         └─ ContactUsScreenRepository.contactUsRepoScreen()
                                │
                                └─ ContactUsScreenRepositoryImp (contact_us_repository.dart)
                                       │
                                       └─ ApiClient().contactUsApiClient() [行31]
                                              │
                                              └─ mutation.contactUsApi() [GraphQL Mutation]
```

### データフロー図

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

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│ ユーザー入力      │    │ バリデーション     │    │ バリデーション   │
│ - 名前          │───▶│ FormKey.validate │───▶│ エラー/OK       │
│ - メール        │    └──────────────────┘    └─────────────────┘
│ - 電話番号      │              │
│ - メッセージ    │              ▼ OK
└─────────────────┘    ┌──────────────────┐
                       │ ContactUsEvent   │
                       │ Bloc送信         │
                       └──────────────────┘
                               │
                               ▼
                       ┌──────────────────┐
                       │ Repository       │
                       │ API呼び出し       │
                       └──────────────────┘
                               │
                               ▼
                       ┌──────────────────┐    ┌─────────────────┐
                       │ GraphQL API      │    │ 成功/失敗通知    │
                       │ contactUs        │───▶│ フォームクリア   │
                       └──────────────────┘    └─────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| contact_us_view.dart | `lib/screens/contact_us/contact_us_view.dart` | View | お問い合わせフォームのUI表示 |
| contact_us_bloc.dart | `lib/screens/contact_us/bloc/contact_us_bloc.dart` | Bloc | 状態管理とビジネスロジック |
| contact_us_event.dart | `lib/screens/contact_us/bloc/contact_us_event.dart` | Event | Blocイベント定義 |
| contact_us_state.dart | `lib/screens/contact_us/bloc/contact_us_state.dart` | State | Bloc状態定義 |
| contact_us_repository.dart | `lib/screens/contact_us/bloc/contact_us_repository.dart` | Repository | データアクセス層 |
| api_client.dart | `lib/services/api_client.dart` | Service | APIクライアント |
| mutation_query.dart | `lib/services/mutation_query.dart` | Query | GraphQLクエリ定義 |
| app_navigation.dart | `lib/utils/app_navigation.dart` | Router | 画面ルーティング定義（行384-389） |
| route_constants.dart | `lib/utils/route_constants.dart` | Constants | ルート名定数（行42） |
