# 画面設計書 13-ウィッシュリスト画面

## 概要

本ドキュメントは、Bagisto eコマースモバイルアプリにおけるウィッシュリスト画面の設計仕様を定義するものです。ウィッシュリスト画面は、ユーザーがお気に入りに追加した商品を管理し、後で購入するための機能を提供します。

### 本画面の処理概要

ウィッシュリスト画面は、ユーザーが「お気に入り」に登録した商品の一覧を表示し、商品の確認やカートへの追加、削除などの操作を行う画面です。

**業務上の目的・背景**：eコマースにおいてウィッシュリスト機能は、ユーザーが興味を持った商品を保存し、後で購入検討するための重要な機能です。すぐには購入しないが気になる商品を保存しておくことで、再訪問時の購入コンバージョンを高める効果があります。また、セール時や在庫復活時に通知を受け取るための基盤としても活用できます。ウィッシュリストから直接カートに追加することで、スムーズな購入フローを提供します。

**画面へのアクセス方法**：
- ボトムナビゲーションまたはナビゲーションドロワーの「ウィッシュリスト」メニューをタップ
- 商品詳細画面で「お気に入りに追加」後にウィッシュリスト画面へ遷移
- アカウント画面から「ウィッシュリスト」メニューをタップ

**主要な操作・処理内容**：
1. ウィッシュリストに追加された商品の一覧表示
2. 商品をカートに追加（カートへ移動）
3. 個別商品をウィッシュリストから削除
4. 全商品をウィッシュリストから一括削除（FloatingActionButton）
5. 商品画像/名前タップで商品詳細画面へ遷移
6. カートアイコンタップでカート画面へ遷移

**画面遷移**：
- 遷移元：商品詳細画面、アカウント画面、ナビゲーションドロワー、ボトムナビゲーション
- 遷移先：商品詳細画面、カート画面

**権限による表示制御**：ウィッシュリスト機能はログインユーザーのみ利用可能です。未ログインユーザーがアクセスした場合は、ログイン画面への誘導が必要です。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 27 | ウィッシュリスト表示 | 主機能 | お気に入り商品一覧の表示 |
| 29 | ウィッシュリストから削除 | 補助機能 | お気に入りから個別商品を削除 |
| 30 | ウィッシュリスト全削除 | 補助機能 | お気に入り商品の一括削除 |
| 31 | カートへ移動 | 補助機能 | お気に入り商品をカートに移動 |

## 画面種別

一覧

## URL/ルーティング

```dart
const String wishlistScreen = "wishlistScreen";
```

ルート定義：`Navigator.pushNamed(context, wishlistScreen)`

## 入出力項目

| 項目名 | 入力/出力 | 型 | 必須 | 説明 |
|--------|----------|-----|------|------|
| - | - | - | - | 本画面は入力パラメータなしで遷移可能 |

## 表示項目

| No | 項目名 | 型 | 表示条件 | 説明 |
|----|--------|-----|----------|------|
| 1 | AppBar | AppBar | 常時 | タイトル「ウィッシュリスト」、カートアイコン（バッジ付き） |
| 2 | 商品リスト | WishlistItemList | 商品あり | ウィッシュリスト商品の一覧 |
| 3 | 商品画像 | Image | 商品あり | 各商品のサムネイル画像 |
| 4 | 商品名 | Text | 商品あり | 商品の名称 |
| 5 | 商品価格 | Text | 商品あり | 価格（フォーマット済み） |
| 6 | 削除ボタン | IconButton | 商品あり | 個別削除アイコン |
| 7 | カート追加ボタン | Button | 商品あり | カートへ追加ボタン |
| 8 | 全削除ボタン | FloatingActionButton | 商品1件以上 | ウィッシュリスト全削除ボタン |
| 9 | 空状態表示 | EmptyDataView | 商品0件 | ウィッシュリストが空の場合の表示 |
| 10 | ローディング | WishListLoader | 読み込み中 | スケルトンローダー表示 |

## イベント仕様

### 1-ウィッシュリストデータ取得

**トリガー**：画面初期表示時

**処理フロー**：
1. `WishListBloc`に`FetchWishListEvent`を発行
2. `WishListRepository.callWishListApi()`でAPIを呼び出し
3. 取得したデータを`WishListData`モデルに変換
4. `FetchDataState.success`を発行しUIを更新
5. 商品数を`wishlistController`にストリーム送信

### 2-個別商品削除

**トリガー**：商品カードの削除ボタン押下

**処理フロー**：
1. `OnClickWishListLoaderEvent`でローダー表示
2. `FetchDeleteAddItemEvent(productId)`を発行
3. `WishListRepository.callWishListDeleteItem(productId)`でAPIを呼び出し
4. 成功時：`FetchDeleteAddItemState.success`を発行
5. 成功通知「削除しました」を表示
6. ウィッシュリストを再取得

### 3-全商品削除

**トリガー**：FloatingActionButton（ゴミ箱アイコン）押下

**処理フロー**：
1. `OnClickWishListLoaderEvent`でローダー表示
2. `RemoveAllWishlistEvent`を発行
3. `WishListRepository.removeAllWishListProducts()`でAPIを呼び出し
4. 成功時：`RemoveAllWishlistProductState.success`を発行
5. 成功通知を表示
6. ローカルのウィッシュリストをクリア

### 4-カートへ追加

**トリガー**：カート追加ボタン押下

**処理フロー**：
1. `AddToCartWishlistEvent(productId, quantity)`を発行
2. `WishListRepository.callAddToCartAPi(productId, quantity)`でAPIを呼び出し
3. 成功時：`AddToCartWishlistState.success`を発行
4. 成功通知「カートに追加しました」を表示
5. グローバルカート数を更新（`GlobalData.cartCountController.sink.add`）
6. ウィッシュリストを再取得（カートへ移動した商品は削除される）

### 5-カート画面遷移

**トリガー**：AppBarのカートアイコン押下

**処理フロー**：
1. `Navigator.pushNamed(context, cartScreen)`を実行
2. カート画面へ遷移

### 6-商品詳細画面遷移

**トリガー**：商品画像/名前タップ

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

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ウィッシュリスト取得 | wishlist_items | SELECT | ユーザーのウィッシュリスト商品を取得 |
| 個別削除 | wishlist_items | DELETE | 指定商品をウィッシュリストから削除 |
| 全削除 | wishlist_items | DELETE | ユーザーのウィッシュリスト全商品を削除 |
| カート追加 | wishlist_items, cart_items | DELETE/INSERT | ウィッシュリストから削除、カートに追加 |

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

#### wishlist_items

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, product_id, product | customer_idで絞り込み | 商品情報も結合取得 |
| DELETE | - | item_idで特定 | 個別削除 |
| DELETE | - | customer_idで絞り込み | 全削除 |

#### cart_items

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | product_id, quantity | 商品ID、数量(1) | カート追加時 |

## メッセージ仕様

| No | メッセージID | メッセージ内容 | 表示タイミング | 種別 |
|----|------------|---------------|--------------|------|
| 1 | emptyWishList | ウィッシュリストが空です | リスト空時 | 情報 |
| 2 | emptyWishListNoItem | お気に入りの商品がありません | リスト空時（説明） | 情報 |
| 3 | deletedSuccess | 削除しました | 削除成功時 | 成功 |
| 4 | addedToCart | カートに追加しました | カート追加成功時 | 成功 |
| 5 | success | 成功 | 各操作成功時 | 成功 |
| 6 | failed | 失敗 | 各操作失敗時 | エラー |
| 7 | somethingWrong | 問題が発生しました | 予期せぬエラー時 | エラー |

## 例外処理

| No | 例外状況 | 対応処理 |
|----|---------|---------|
| 1 | ウィッシュリストが空 | `EmptyDataView`を表示（emptyWishlist画像付き） |
| 2 | API通信エラー | `EmptyDataView`を表示 |
| 3 | 在庫切れ商品のカート追加失敗 | APIからのエラーメッセージを表示 |
| 4 | 未ログイン状態 | ログイン画面へ誘導（本画面到達前） |

## 備考

- FloatingActionButtonは商品が1件以上ある場合のみ表示
- カートアイコンのバッジ数はリアルタイムで更新（StreamBuilder）
- BLoCパターンによる状態管理を採用
- 商品情報には`Product`モデル（商品詳細と同じ）を使用
- カート追加時は数量1で追加（数量選択UIなし）
- ウィッシュリストはログインユーザー専用機能

---

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

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

### 推奨読解順序

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

ウィッシュリスト画面で扱うデータモデルの構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | wishlist_model.dart | `lib/screens/wishList/data_model/wishlist_model.dart` | WishListData、WishlistDataクラスの構造 |
| 1-2 | product_details_model.dart | `lib/screens/product_screen/data_model/product_details_model.dart` | Productクラスの構造（ウィッシュリスト商品に含まれる） |

**読解のコツ**: `WishlistData`は`id`、`productId`、`product`（Productモデル）を持つシンプルな構造。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | wishlist_screen.dart | `lib/screens/wishList/view/wishlist_screen.dart` | WishListScreenクラス、initStateでのBloc初期化 |

**主要処理フロー**:
1. **行32-39**: initStateでカート数取得、Blocを取得し`FetchWishListEvent`を発行
2. **行53-97**: buildメソッドでScaffold構築（AppBar、body、FloatingActionButton）
3. **行76-95**: FloatingActionButtonの表示制御（StreamBuilder使用）
4. **行115-167**: BlocConsumerでイベント処理
5. **行171-232**: buildContainerで状態に応じたUI構築

#### Step 3: 状態管理（BLoC）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | wishlist_bloc.dart | `lib/screens/wishList/bloc/wishlist_bloc.dart` | イベント処理の実装 |
| 3-2 | wishlist_event.dart | `lib/screens/wishList/bloc/wishlist_event.dart` | 各イベントクラスの定義 |
| 3-3 | wishlist_state.dart | `lib/screens/wishList/bloc/wishlist_state.dart` | 各状態クラスの定義 |

**主要処理フロー**:
- **行24-36**: FetchWishListEvent処理
- **行37-48**: FetchDeleteAddItemEvent処理（個別削除）
- **行49-65**: AddToCartWishlistEvent処理（カート追加）
- **行66-68**: OnClickWishListLoaderEvent処理
- **行69-82**: RemoveAllWishlistEvent処理（全削除）
- **行83-91**: GetCartCountEvent処理（カート数取得）

#### Step 4: API通信（Repository）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | wishlist_repository.dart | `lib/screens/wishList/bloc/wishlist_repository.dart` | API呼び出しの実装 |

#### Step 5: UIコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | wishlist_Item_list.dart | `lib/screens/wishList/view/widget/wishlist_Item_list.dart` | 商品リスト表示 |
| 5-2 | wishlist_loader.dart | `lib/screens/wishList/view/widget/wishlist_loader.dart` | ローディング表示 |

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

```
WishListScreen (wishlist_screen.dart)
    │
    ├─ WishListBloc (wishlist_bloc.dart)
    │      │
    │      ├─ FetchWishListEvent
    │      │      └─ WishListRepository.callWishListApi()
    │      │
    │      ├─ FetchDeleteAddItemEvent
    │      │      └─ WishListRepository.callWishListDeleteItem()
    │      │
    │      ├─ AddToCartWishlistEvent
    │      │      └─ WishListRepository.callAddToCartAPi()
    │      │
    │      ├─ RemoveAllWishlistEvent
    │      │      └─ WishListRepository.removeAllWishListProducts()
    │      │
    │      └─ GetCartCountEvent
    │             └─ WishListRepository.cartCountApi()
    │
    └─ WishlistItemList (wishlist_Item_list.dart)
```

### データフロー図

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

ユーザー操作 ─────▶ WishListBloc ─────▶ UI更新
   │                     │
   │                     ├─ WishListRepository
   │                     │         │
   │                     │         └─ GraphQL API
   │                     │
   │                     └─ State発行
   │                            │
   └───────────────────────────▶ BlocConsumer
                                      │
                                      └─ Widget再描画
                                             │
                                             ├─ wishlistController (商品数)
                                             │
                                             └─ GlobalData.cartCountController
                                                      │
                                                      └─ カートバッジ更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| wishlist_screen.dart | `lib/screens/wishList/view/wishlist_screen.dart` | ソース | メイン画面ウィジェット |
| wishlist_bloc.dart | `lib/screens/wishList/bloc/wishlist_bloc.dart` | ソース | 状態管理BLoC |
| wishlist_event.dart | `lib/screens/wishList/bloc/wishlist_event.dart` | ソース | イベント定義 |
| wishlist_state.dart | `lib/screens/wishList/bloc/wishlist_state.dart` | ソース | 状態定義 |
| wishlist_repository.dart | `lib/screens/wishList/bloc/wishlist_repository.dart` | ソース | API通信 |
| wishlist_model.dart | `lib/screens/wishList/data_model/wishlist_model.dart` | ソース | データモデル |
| wishlist_Item_list.dart | `lib/screens/wishList/view/widget/wishlist_Item_list.dart` | ソース | 商品リストWidget |
| wishlist_loader.dart | `lib/screens/wishList/view/widget/wishlist_loader.dart` | ソース | ローダーWidget |
| index.dart | `lib/screens/wishList/utils/index.dart` | ソース | エクスポート集約 |
| route_constants.dart | `lib/utils/route_constants.dart` | 設定 | ルート定数定義 |
