# 画面設計書 138-エリア管理画面

## 概要

本ドキュメントは、Medusa Admin Dashboardにおけるエリア管理画面の設計仕様を定義するものである。

### 本画面の処理概要

エリア管理画面は、サービスゾーンに紐づく対象国（地理的範囲）を管理するための画面である。

**業務上の目的・背景**：ECサイト運営において、サービスゾーンの対象国を後から変更する必要が生じることがある。例えば、配送エリアの拡大に伴い「EU配送ゾーン」に新たにスイスを追加する、または特定の国を対象外にするなどのケースに対応する。サービスゾーン編集画面では名前の変更のみを行い、対象国の変更は本画面で行う設計となっている。

**画面へのアクセス方法**：ロケーション詳細画面 > サービスゾーンのアクションメニュー > 「Manage Areas」をクリックすることでアクセスできる。URLパスは `/settings/locations/{location_id}/fulfillment-set/{fset_id}/service-zone/{zone_id}/areas`。

**主要な操作・処理内容**：
1. 現在の対象国一覧の表示
2. 対象国の追加
3. 対象国の削除
4. 「保存」ボタンで変更を反映
5. 「キャンセル」ボタンで操作を中断

**画面遷移**：
- 遷移元：ロケーション詳細画面（`/settings/locations/{location_id}`）
- 遷移先：保存完了後、ロケーション詳細画面へ自動的に戻る

**権限による表示制御**：管理者権限を持つユーザーのみがこの画面にアクセスし、サービスゾーンのエリアを管理できる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 42 | サービスゾーン管理 | 主機能 | サービスゾーンのエリア管理 |
| 47 | 地理ゾーン管理 | 補助機能 | 対象国の追加・削除 |

## 画面種別

編集画面（フルページモーダル形式）

## URL/ルーティング

- パス: `/settings/locations/:location_id/fulfillment-set/:fset_id/service-zone/:zone_id/areas`
- コンポーネント: `LocationServiceZoneManageAreas`
- ルートファイル: `packages/admin/dashboard/src/routes/locations/location-service-zone-manage-areas/location-service-zone-manage-areas.tsx`

## 入出力項目

| 項目名 | 項目ID | 入出力 | 型 | 必須 | バリデーション | 説明 |
|--------|--------|--------|-----|------|---------------|------|
| 対象国 | countries | 入力 | array | Yes | 最低1カ国 | ISO 3166-1 alpha-2形式の国コードと表示名の配列 |

## 表示項目

| 項目名 | 説明 |
|--------|------|
| ヘッダータイトル | 「Manage Areas in {zone_name}」形式の動的タイトル |
| 選択済み国一覧 | ChipGroupコンポーネントでチップ形式で表示 |
| ラベル | 「Areas」（翻訳キー: `stockLocations.serviceZones.manageAreas.label`） |
| ヒント | エリア設定についてのヒント（翻訳キー: `stockLocations.serviceZones.manageAreas.hint`） |

### 国選択モーダル（スタックモーダル）

| 項目名 | 説明 |
|--------|------|
| チェックボックス | 国の選択状態 |
| 国名 | 国の表示名（display_name） |
| 国コード | ISO 3166-1 alpha-2コード（iso_2） |
| 検索ボックス | 国名・コードでの検索 |
| ソート | 名前またはコードによるソート |
| ページネーション | 50件ずつ表示 |

## イベント仕様

### 1-保存ボタン押下

**トリガー**: 「Save」ボタンのクリック、または `Cmd/Ctrl + Enter` キーボードショートカット

**処理フロー**:
1. フォームバリデーションを実行
2. バリデーション成功時、`useUpdateFulfillmentSetServiceZone`フックを通じてAPIを呼び出し
3. APIリクエスト: `POST /admin/fulfillment-sets/{fset_id}/service-zones/{zone_id}`
4. 成功時: トースト通知を表示し、ロケーション詳細画面へ遷移
5. 失敗時: エラーメッセージをトースト通知で表示

**送信データ**:
```typescript
{
  geo_zones: Array<{
    country_code: string,
    type: "country"
  }>
}
```

### 2-キャンセルボタン押下

**トリガー**: 「Cancel」ボタンのクリック

**処理フロー**:
1. モーダルを閉じる
2. ロケーション詳細画面に戻る

### 3-国追加

**トリガー**: 「Edit Areas」ボタンのクリック

**処理フロー**:
1. スタックモーダル（`GeoZoneForm.AreaDrawer`）を開く
2. 国一覧から選択（複数選択可能）
3. 「Save」ボタンで選択を確定
4. `countries`フィールドに反映

### 4-国削除（個別）

**トリガー**: チップの削除ボタン（×）クリック

**処理フロー**:
1. `countries`フィールドから該当国を削除
2. チップ表示を即座に更新

### 5-全国削除

**トリガー**: 「Clear all」ボタンのクリック

**処理フロー**:
1. `countries`フィールドを空配列に置換
2. 全チップ表示を即座に削除

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | geo_zone | DELETE/INSERT | 地理ゾーンの全置換 |

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

#### geo_zone

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | WHERE service_zone_id = ? | 既存のgeo_zoneを全削除 |
| INSERT | id | システム自動生成（UUID） | 主キー |
| INSERT | service_zone_id | URLパラメータのzone_id | 外部キー |
| INSERT | country_code | 選択された国のISO 3166-1 alpha-2コード | 国コード |
| INSERT | type | "country" | 地理ゾーンタイプ |

## メッセージ仕様

| メッセージ種別 | メッセージキー | 表示条件 | 表示内容 |
|--------------|---------------|----------|---------|
| 成功 | stockLocations.serviceZones.manageAreas.successToast | エリア更新成功時 | 「{name} updated successfully」 |
| エラー | - | API呼び出し失敗時 | APIから返却されたエラーメッセージ |
| バリデーション | - | 国が1つも選択されていない時 | 該当フィールドにエラー表示 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| サービスゾーンが見つからない | 404エラーをスロー |
| ネットワークエラー | トースト通知でエラーメッセージを表示 |
| サーバーエラー（5xx） | トースト通知でエラーメッセージを表示 |
| 認証エラー（401） | ログイン画面へリダイレクト |

## 備考

- 画面はフルページモーダル（`RouteFocusModal`）として実装されている
- フォームは`react-hook-form`と`zod`によるバリデーションを使用
- 国選択はスタックモーダル（`StackedFocusModal`）内の`GeoZoneForm.AreaDrawer`で行う
- `ChipGroup`コンポーネントで選択済み国をチップ形式で表示
- 国データは静的データ（`countries.ts`）から取得
- 既存の紐付けから初期選択状態を自動設定
- APIに送信時、geo_zones形式（country_code, type）に変換
- `prev`プロパティでモーダルを閉じた際の遷移先を指定

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | edit-service-zone-areas-form.tsx | `packages/admin/dashboard/src/routes/locations/location-service-zone-manage-areas/components/edit-region-areas-form/edit-service-zone-areas-form.tsx` | L19-23: `EditeServiceZoneSchema`でフォームスキーマを定義。国の配列（最低1カ国必須） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | location-service-zone-manage-areas.tsx | `packages/admin/dashboard/src/routes/locations/location-service-zone-manage-areas/location-service-zone-manage-areas.tsx` | L7-41: URLパラメータからzone_idを取得し、サービスゾーンを検索 |

**主要処理フロー**:
1. **L8**: `useParams`でURLパラメータ（location_id, fset_id, zone_id）を取得
2. **L10-13**: `useStockLocation`でロケーションとサービスゾーン情報（geo_zones含む）を取得
3. **L15-17**: URLのzone_idに一致するサービスゾーンを検索
4. **L19-24**: サービスゾーンが見つからない場合は404エラー
5. **L31-38**: フォームコンポーネントを表示

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | edit-service-zone-areas-form.tsx | `packages/admin/dashboard/src/routes/locations/location-service-zone-manage-areas/components/edit-region-areas-form/edit-service-zone-areas-form.tsx` | L31-120: フォーム初期化、国選択UI、API呼び出し |

**主要処理フロー**:
- **L39-51**: `useForm`でフォーム状態を初期化、既存のgeo_zonesをcountries形式に変換してデフォルト値設定
- **L53-54**: `useUpdateFulfillmentSetServiceZone`フックでAPI呼び出し関数を取得
- **L56-79**: `handleSubmit`で国データをgeo_zones形式に変換してAPI呼び出し
- **L98**: `GeoZoneForm`コンポーネントで国選択UIを表示
- **L102**: `GeoZoneForm.AreaDrawer`でスタックモーダル内の国選択を実装

#### Step 4: 国選択コンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | geo-zone-form.tsx | `packages/admin/dashboard/src/routes/locations/common/components/geo-zone-form/geo-zone-form.tsx` | L39-103: チップ表示とクリア機能、L112-271: 国選択スタックモーダル |

**主要処理フロー**:
- **L48-52**: `useFieldArray`で国配列を管理
- **L54-56**: `handleClearAll`で全国削除
- **L84-96**: `ChipGroup`で選択済み国をチップ表示
- **L125-128**: 選択状態とステートを初期化
- **L172-197**: 行選択変更時の処理（追加・削除の検知）
- **L199-205**: `handleAdd`で選択を確定しフォーム値を更新

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

```
LocationServiceZoneManageAreas (location-service-zone-manage-areas.tsx)
    │
    ├─ useStockLocation (サービスゾーン・geo_zones取得)
    │
    └─ EditServiceZoneAreasForm (edit-service-zone-areas-form.tsx)
           │
           ├─ useForm (react-hook-form)
           │      └─ defaultValues (既存geo_zones → countries変換)
           │
           ├─ GeoZoneForm (geo-zone-form.tsx)
           │      ├─ useFieldArray (countries配列管理)
           │      ├─ ChipGroup (選択済み国表示)
           │      └─ AreaDrawer (スタックモーダル)
           │             ├─ useDataTable
           │             ├─ _DataTable (国一覧テーブル)
           │             └─ handleAdd (選択確定)
           │
           └─ useUpdateFulfillmentSetServiceZone
                  └─ POST /admin/fulfillment-sets/{fset_id}/service-zones/{zone_id}
```

### データフロー図

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

既存geo_zones取得 ───▶ countries形式に変換 ───▶ フォーム初期値設定
                                                     │
                                        ┌────────────┤
                                        ▼            ▼
                               ChipGroup表示    スタックモーダル
                                        │            │
チップ削除 ──────────────────▶ remove ───┘            │
全削除 ─────────────────────▶ replace([]) ───────────┘
国選択 ─────────────────────────────────────▶ handleAdd ───▶ setValue
      │
      └─(save)──▶ geo_zones変換 ───▶ useUpdateFulfillmentSetServiceZone
                          │
                          ├─(success)──▶ toast.success + 詳細画面遷移
                          │
                          └─(error)──▶ toast.error
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| location-service-zone-manage-areas.tsx | `packages/admin/dashboard/src/routes/locations/location-service-zone-manage-areas/location-service-zone-manage-areas.tsx` | ソース | 画面エントリーポイント |
| edit-service-zone-areas-form.tsx | `packages/admin/dashboard/src/routes/locations/location-service-zone-manage-areas/components/edit-region-areas-form/edit-service-zone-areas-form.tsx` | ソース | フォームコンポーネント |
| geo-zone-form.tsx | `packages/admin/dashboard/src/routes/locations/common/components/geo-zone-form/geo-zone-form.tsx` | ソース | 国選択コンポーネント |
| countries.ts | `packages/admin/dashboard/src/lib/data/countries.ts` | ソース | 国データ定義 |
| fulfillment-sets.tsx | `packages/admin/dashboard/src/hooks/api/fulfillment-sets.tsx` | ソース | フルフィルメントセットAPI |
