# 画面設計書 9-サブカテゴリ画面

## 概要

本ドキュメントは、Bagisto eコマースモバイルアプリのサブカテゴリ画面に関する設計書です。ドロワーから選択したカテゴリのサブカテゴリと、そのカテゴリに属する商品を表示する画面です。

### 本画面の処理概要

**業務上の目的・背景**：サブカテゴリ画面は、階層構造を持つカテゴリの中間ナビゲーションを提供します。親カテゴリを選択した際に、さらに細分化されたサブカテゴリを表示することで、ユーザーが目的の商品カテゴリに到達しやすくします。また、そのカテゴリに直接属する商品も同時に表示し、カテゴリ階層をたどりながら商品を発見できる機能を提供します。

**画面へのアクセス方法**：
- ドロワーメニューから子カテゴリを持つカテゴリを選択
- ホーム画面のカテゴリカルーセルから子カテゴリを持つカテゴリを選択
- サブカテゴリ画面からさらに下位のサブカテゴリを選択

**主要な操作・処理内容**：
1. サブカテゴリ一覧の横スクロール表示
2. カテゴリに属する商品の横スクロール表示
3. サブカテゴリタップで下位カテゴリまたは商品一覧へ遷移
4. 商品のカートへの追加
5. 商品のウィッシュリストへの追加/削除
6. 商品の比較リストへの追加
7. 「View All」ボタンで全商品一覧へ遷移
8. 商品詳細画面への遷移

**画面遷移**：
- 遷移元：ホーム画面、ドロワーメニュー、サブカテゴリ画面
- 遷移先：サブカテゴリ画面（さらに下位）、カテゴリ商品一覧画面、商品詳細画面

**権限による表示制御**：
- ウィッシュリスト・比較リスト機能：ログインユーザーのみ
- カートへの追加：全ユーザー可能

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 15 | サブカテゴリ表示 | 主機能 | 親カテゴリ配下のサブカテゴリと商品一覧を表示 |

## 画面種別

一覧画面（カテゴリナビゲーション）

## URL/ルーティング

- ルート名: `drawerSubCategoryScreen`
- パス: `/drawer-sub-category/:id`

## 入出力項目

| 項目名 | 入出力 | データ型 | 必須 | 説明 |
|--------|--------|----------|------|------|
| id | 入力 | String | Yes | カテゴリID |
| title | 入力 | String | No | カテゴリ名（AppBar表示用） |
| categorySlug | 入力 | String | No | カテゴリスラッグ |
| image | 入力 | String | No | カテゴリバナー画像URL |
| metaDescription | 入力 | String | No | カテゴリ説明 |
| parentId | 入力 | String | Yes | 親カテゴリID |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| カテゴリ名 | String | AppBarに表示されるカテゴリ名 |
| カテゴリバナー画像 | Widget | カテゴリのバナー画像 |
| サブカテゴリ一覧 | List<Category> | 横スクロール可能なサブカテゴリアイコン一覧 |
| 商品一覧 | List<NewProducts> | 横スクロール可能な商品カード一覧 |
| 商品名 | String | 各商品カードに表示される商品名 |
| 商品価格 | String (HTML) | 価格HTML（セール価格・通常価格） |
| 商品画像 | String (URL) | 商品サムネイル画像 |
| セールバッジ | Widget | セール中の商品に表示されるバッジ |
| 新着バッジ | Widget | 新着商品に表示されるバッジ |
| ウィッシュリストアイコン | Widget | お気に入り追加/削除アイコン |
| 比較アイコン | Widget | 比較リスト追加アイコン |
| View Allボタン | Button | 全商品一覧へ遷移するボタン |
| カートに追加ボタン | Button | カート追加ボタン |
| ローディングインジケータ | Widget | データ読み込み中の表示 |

## イベント仕様

### 1-画面初期化イベント（initState）

**トリガー**: 画面がマウントされたタイミング

**処理フロー**:
1. `DrawerSubCategoriesBloc`をcontext.readで取得
2. `FetchDrawerSubCategoryEvent`を送信（parentIdベースのフィルタ）
   - フィルタ条件：status=1, locale=現在のロケール, parent_id=parentId

### 2-サブカテゴリデータ取得完了イベント

**トリガー**: FetchDrawerSubCategoryEventの応答受信

**処理フロー**:
1. 成功時：categoriesDataにデータを格納
2. `fetchProducts()`を呼び出して商品データを取得
3. `FetchCategoryProductsEvent`を送信（category_idベースのフィルタ）

### 3-サブカテゴリタップイベント

**トリガー**: サブカテゴリアイコンタップ

**処理フロー**:
1. 選択したサブカテゴリに子カテゴリがあるか確認
2. 子カテゴリがある場合：
   - `Navigator.pushNamed(context, drawerSubCategoryScreen, arguments: CategoriesArguments(...))`
   - サブカテゴリ画面に遷移（再帰的）
3. 子カテゴリがない場合：
   - `Navigator.pushNamed(context, categoryScreen, arguments: CategoriesArguments(...))`
   - カテゴリ商品一覧画面に遷移

### 4-カートに追加イベント

**トリガー**: 商品カードの「カートに追加」ボタンタップ

**処理フロー**:
1. インターネット接続を確認
2. 商品タイプを確認（simple/virtual以外またはcustomizableOptionsありの場合は商品詳細画面へ誘導）
3. `AddToCartEvent`を送信
4. 成功時：成功メッセージ表示、カート数更新
5. 失敗時：エラーメッセージ表示

### 5-ウィッシュリスト追加/削除イベント

**トリガー**: 商品カードのハートアイコンタップ

**処理フロー**:
1. ログイン状態を確認
2. 未ログインの場合：警告メッセージを表示
3. ログイン済みの場合：
   - ウィッシュリストに存在する場合：`RemoveWishlistItemEvent`を送信
   - 存在しない場合：`AddWishlistEvent`を送信
4. 完了後に`fetchProducts()`で商品データを再取得

### 6-比較リスト追加イベント

**トリガー**: 商品カードの比較アイコンタップ

**処理フロー**:
1. ログイン状態を確認
2. 未ログインの場合：警告メッセージを表示
3. ログイン済みの場合：`AddToCompareEvent`を送信

### 7-View Allボタン押下イベント

**トリガー**: 「View All」ボタンタップ

**処理フロー**:
1. `Navigator.pushNamed(context, categoryScreen, arguments: CategoriesArguments(...))`を実行
2. カテゴリ商品一覧画面に遷移

### 8-商品タップイベント

**トリガー**: 商品カードタップ

**処理フロー**:
1. `Navigator.pushNamed(context, productScreen, arguments: PassProductData(...))`を実行
2. 商品詳細画面に遷移

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| カートに追加 | cart_items (サーバー側) | INSERT/UPDATE | 商品をカートに追加 |
| ウィッシュリストに追加 | wishlist_items (サーバー側) | INSERT | 商品をウィッシュリストに追加 |
| ウィッシュリストから削除 | wishlist_items (サーバー側) | DELETE | 商品をウィッシュリストから削除 |
| 比較リストに追加 | compare_items (サーバー側) | INSERT | 商品を比較リストに追加 |

## メッセージ仕様

| メッセージID | メッセージ種別 | 表示条件 | メッセージ内容 |
|-------------|--------------|----------|--------------|
| MSG-001 | 成功 | カート追加成功 | APIから返却されるメッセージ |
| MSG-002 | エラー | カート追加失敗 | graphqlErrorsまたはエラーメッセージ |
| MSG-003 | 成功 | ウィッシュリスト追加成功 | APIから返却されるメッセージ |
| MSG-004 | エラー | ウィッシュリスト操作失敗 | エラーメッセージ |
| MSG-005 | 成功 | 比較リスト追加成功 | APIから返却されるメッセージ |
| MSG-006 | エラー | 比較リスト追加失敗 | エラーメッセージ |
| MSG-007 | 警告 | 未ログイン | 「Please login」 |
| MSG-008 | 警告 | オプション選択必要 | 「Please select options」 |
| MSG-009 | エラー | ネットワークエラー | 「Internet connection issue」 |
| MSG-010 | 情報 | データなし | 「No products」 |

## 例外処理

| 例外ケース | 処理内容 | ユーザーへの影響 |
|-----------|---------|----------------|
| サブカテゴリデータ取得失敗 | エラー状態をemit | サブカテゴリが表示されない |
| 商品データ取得失敗 | エラー状態をemit | 商品一覧が表示されない |
| カート追加失敗 | エラーメッセージを表示 | カートに追加されない |
| 商品なし | EmptyDataViewを表示 | 「No products」メッセージ表示 |

## 備考

- 親カテゴリIDが"1"（ルートカテゴリ）の場合はルート直下のカテゴリを表示
- サブカテゴリはCircleAvatarで円形アイコン表示
- 商品タイプがsimple/virtual以外の場合やcustomizableOptionsがある場合は商品詳細画面へ誘導
- ウィッシュリスト操作後は商品データを再取得してisInWishlistフラグを更新
- カテゴリバナー画像がない場合はSizedBox.shrink()を表示

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | get_categories_drawer_data_model.dart | `lib/screens/home_page/data_model/get_categories_drawer_data_model.dart` | カテゴリデータモデル（childrenフィールド含む） |
| 1-2 | new_product_data.dart | `lib/screens/home_page/data_model/new_product_data.dart` | 商品データモデル |

**読解のコツ**: GetDrawerCategoriesDataにはdataリストがあり、各カテゴリにはchildren（子カテゴリ）が含まれる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | drawer_sub_categories.dart | `lib/screens/drawer_sub_categories/drawer_sub_categories.dart` | サブカテゴリ画面のメインウィジェット |

**主要処理フロー**:
1. **48-56行目**: `initState()`でBloc取得、FetchDrawerSubCategoryEvent送信
2. **58-62行目**: `fetchProducts()`で商品データ取得
3. **75-311行目**: `_subCategoriesList()`でBlocConsumer構築
4. **168-244行目**: サブカテゴリ一覧表示（親カテゴリとその子）
5. **313-660行目**: `productsView()`で商品カード表示

#### Step 3: Blocレイヤーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | drawer_sub_categories_bloc.dart | `lib/screens/drawer_sub_categories/bloc/drawer_sub_categories_bloc.dart` | 状態管理Bloc |

**主要処理フロー**:
- `FetchDrawerSubCategoryEvent`: サブカテゴリ取得
- `FetchCategoryProductsEvent`: カテゴリ商品取得
- `AddToCartEvent`: カート追加
- `AddWishlistEvent`: ウィッシュリスト追加
- `AddToCompareEvent`: 比較リスト追加

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

```
DrawerSubCategoryView (StatefulWidget)
    │
    ├─ initState()
    │      ├─ DrawerSubCategoriesBloc (context.read)
    │      └─ DrawerSubCategoriesBloc.add(FetchDrawerSubCategoryEvent)
    │
    ├─ build()
    │      └─ Scaffold
    │             ├─ AppBar(title)
    │             └─ _subCategoriesList() → BlocConsumer<DrawerSubCategoriesBloc>
    │                    ├─ FetchDrawerSubCategoryState
    │                    │      └─ fetchProducts()
    │                    │             └─ FetchCategoryProductsEvent
    │                    │
    │                    └─ SingleChildScrollView
    │                           ├─ ImageView (カテゴリバナー)
    │                           ├─ サブカテゴリ一覧 (Row with CircleAvatar)
    │                           │      └─ onTap
    │                           │             ├─ children有: drawerSubCategoryScreen
    │                           │             └─ children無: categoryScreen
    │                           │
    │                           └─ productsView()
    │                                  ├─ View Allボタン → categoryScreen
    │                                  └─ 商品カード一覧
    │                                         ├─ onTap → productScreen
    │                                         ├─ ウィッシュリストアイコン
    │                                         ├─ 比較アイコン
    │                                         └─ カートに追加ボタン
```

### データフロー図

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

parentId ───────────────▶ FetchDrawerSubCategoryEvent ──▶ GetDrawerCategoriesData
    │                            │
    │                            ▼
    │                    fetchProducts()
    │                            │
    │                            ▼
categoryId ─────────────▶ FetchCategoryProductsEvent ───▶ NewProductsModel
                                │
                                ▼
                         画面表示
                         ├─ サブカテゴリ一覧
                         └─ 商品カード一覧

サブカテゴリタップ ──────▶ children有無判定
                                │
                         ┌──────┴──────┐
                         ▼             ▼
                    children有    children無
                         │             │
                         ▼             ▼
            drawerSubCategoryScreen  categoryScreen
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| drawer_sub_categories.dart | `lib/screens/drawer_sub_categories/drawer_sub_categories.dart` | ソース | サブカテゴリ画面のメインウィジェット |
| drawer_sub_categories_bloc.dart | `lib/screens/drawer_sub_categories/bloc/drawer_sub_categories_bloc.dart` | ソース | 状態管理Bloc |
| drawer_sub_categories_event.dart | `lib/screens/drawer_sub_categories/bloc/drawer_sub_categories_event.dart` | ソース | イベント定義 |
| drawer_sub_categories_state.dart | `lib/screens/drawer_sub_categories/bloc/drawer_sub_categories_state.dart` | ソース | 状態定義 |
| drawer_sub_categories_repository.dart | `lib/screens/drawer_sub_categories/bloc/drawer_sub_categories_repository.dart` | ソース | API通信処理 |
| get_categories_drawer_data_model.dart | `lib/screens/home_page/data_model/get_categories_drawer_data_model.dart` | ソース | カテゴリデータモデル |
| new_product_data.dart | `lib/screens/home_page/data_model/new_product_data.dart` | ソース | 商品データモデル |
| index.dart | `lib/screens/drawer_sub_categories/utils/index.dart` | ソース | エクスポート集約 |
| route_constants.dart | `lib/utils/route_constants.dart` | ソース | ルーティング定数 |
