# 画面設計書 81-顧客編集画面

## 概要

本ドキュメントは、Medusa Admin Dashboard における顧客編集画面の設計仕様を定義したものである。既存顧客の基本情報を更新するためのモーダル形式の画面について記述する。

### 本画面の処理概要

顧客編集画面は、既存の顧客情報を編集・更新するためのモーダル（ドロワー）形式の画面である。

**業務上の目的・背景**：ECサイト運営において、顧客情報は注文処理、配送、マーケティング活動の基盤となる。顧客のメールアドレス変更、名前の修正、会社情報の更新など、顧客ライフサイクルにおいて情報の更新は頻繁に発生する。本画面は、管理者が効率的に顧客情報を修正できる機能を提供し、データの正確性を維持することで、顧客サービスの品質向上に貢献する。

**画面へのアクセス方法**：顧客詳細画面のアクションメニューから「編集」を選択するか、URLパス `/customers/:id/edit` に直接アクセスすることで本画面を開く。画面は右側からスライドインするドロワー形式で表示される。

**主要な操作・処理内容**：
1. メールアドレスの編集（アカウント未作成の顧客のみ）
2. 名（First Name）の編集
3. 姓（Last Name）の編集
4. 会社名の編集
5. 電話番号の編集
6. 保存ボタンで変更を確定

**画面遷移**：顧客詳細画面から遷移してくる。保存成功後またはキャンセル時に顧客詳細画面に戻る。

**権限による表示制御**：認証済みの管理者ユーザーのみがアクセス可能。メールアドレス項目は、顧客がアカウントを持っている場合（`has_account` が true の場合）は編集不可となり、ツールチップでその理由が表示される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | 顧客CRUD | 主機能 | 顧客情報の編集 |

## 画面種別

編集（モーダル/ドロワー形式）

## URL/ルーティング

`/customers/:id/edit`

## 入出力項目

| 項目名 | 項目ID | データ型 | 必須 | 最大長 | 入力/出力 | バリデーション | 備考 |
|--------|--------|----------|------|--------|-----------|----------------|------|
| メールアドレス | email | string | 必須 | - | 入力 | メール形式（zod.string().email()） | has_account=true の場合は編集不可 |
| 名 | first_name | string | 任意 | - | 入力 | なし | |
| 姓 | last_name | string | 任意 | - | 入力 | なし | |
| 会社名 | company_name | string | 任意 | - | 入力 | なし | |
| 電話番号 | phone | string | 任意 | - | 入力 | なし | |

## 表示項目

| 項目名 | 表示位置 | 説明 |
|--------|----------|------|
| ヘッダータイトル | ドロワーヘッダー | 「顧客を編集」（customers.edit.header） |
| メールアドレス無効ツールチップ | メールフィールド | アカウント有りの顧客の場合に表示（customers.edit.emailDisabledTooltip） |
| キャンセルボタン | フッター | モーダルを閉じる |
| 保存ボタン | フッター | 変更を保存 |

## イベント仕様

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

ユーザーが保存ボタンを押下すると、以下の処理が実行される：
1. フォームのバリデーションを実行
2. バリデーション成功時、`useUpdateCustomer` フックを通じて API を呼び出し
3. API 呼び出し時、`has_account` が true の場合はメールアドレスを送信しない
4. 成功時：成功トーストを表示し、モーダルを閉じる
5. 失敗時：エラートーストを表示

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

モーダルを閉じて顧客詳細画面に戻る。

### 3-フォーム入力

各入力フィールドへの入力は React Hook Form によって管理され、リアルタイムでバリデーションが実行される。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | customer | UPDATE | 顧客情報の更新 |

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

#### customer

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | email | フォーム入力値（has_account=false の場合のみ） | アカウント有りの場合は更新しない |
| UPDATE | first_name | フォーム入力値 または null | 空文字の場合は null |
| UPDATE | last_name | フォーム入力値 または null | 空文字の場合は null |
| UPDATE | phone | フォーム入力値 または null | 空文字の場合は null |
| UPDATE | company_name | フォーム入力値 または null | 空文字の場合は null |

## メッセージ仕様

| 種別 | メッセージキー | 表示条件 | メッセージ内容（参考） |
|------|---------------|----------|----------------------|
| 成功 | customers.edit.successToast | 保存成功時 | 顧客 {email} を更新しました |
| エラー | (動的) | API エラー時 | エラーメッセージを表示 |
| 情報 | customers.edit.emailDisabledTooltip | has_account=true 時 | アカウントを持つ顧客のメールアドレスは変更できません |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| 顧客データ取得エラー | エラーをスローしてエラー境界で処理 |
| API 更新エラー | エラートーストを表示 |
| バリデーションエラー | 各フィールドにエラーメッセージを表示 |

## 備考

- モーダルは RouteDrawer コンポーネントを使用しており、URL ベースのルーティングで管理される
- フォームは KeyboundForm を使用しており、キーボードショートカットによる操作が可能
- アカウントを持つ顧客（has_account=true）のメールアドレスは、セキュリティ上の理由から変更不可
- 任意項目で空文字が入力された場合は null として API に送信される

---

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

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

### 推奨読解順序

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

顧客データの型定義と更新スキーマを把握することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | edit-customer-form.tsx | `packages/admin/dashboard/src/routes/customers/customer-edit/components/edit-customer-form/edit-customer-form.tsx` | EditCustomerSchema（20-26行目）で定義されるフォームのバリデーションスキーマ |

**読解のコツ**: zod ライブラリによるスキーマ定義。`zod.string().email()` でメール形式のバリデーション、`.optional()` で任意項目を定義。

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

ルートコンポーネントの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | customer-edit.tsx | `packages/admin/dashboard/src/routes/customers/customer-edit/customer-edit.tsx` | CustomerEdit コンポーネント（8-26行目）。useParams で顧客IDを取得し、useCustomer で顧客データを取得 |

**主要処理フロー**:
1. **11行目**: `useParams()` で URL から顧客 ID を取得
2. **12行目**: `useCustomer(id!)` で顧客データを取得
3. **14-16行目**: エラー時はエラーをスロー
4. **18-25行目**: RouteDrawer 内に EditCustomerForm を描画

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

フォームの実装詳細を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | edit-customer-form.tsx | `packages/admin/dashboard/src/routes/customers/customer-edit/components/edit-customer-form/edit-customer-form.tsx` | フォームの実装全体（28-178行目） |

**主要処理フロー**:
- **32-41行目**: useForm でフォーム初期化、顧客データをデフォルト値として設定
- **43行目**: useUpdateCustomer フックで更新用ミューテーションを取得
- **45-69行目**: handleSubmit で保存処理を実装。has_account による条件分岐あり
- **76-95行目**: メールフィールドの実装。ConditionalTooltip と disabled 制御

#### Step 4: API フックを理解する

バックエンドとの通信処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | customers.tsx | `packages/admin/dashboard/src/hooks/api/customers.tsx` | useUpdateCustomer フック（81-99行目） |

**主要処理フロー**:
- **89行目**: sdk.admin.customer.update(id, payload) で API 呼び出し
- **91-93行目**: 成功時にキャッシュを無効化

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

```
CustomerEdit (customer-edit.tsx)
    │
    ├─ useParams() ─── URL から ID 取得
    │
    ├─ useCustomer(id) ─── 顧客データ取得
    │      └─ sdk.admin.customer.retrieve()
    │
    └─ EditCustomerForm (edit-customer-form.tsx)
           │
           ├─ useForm() ─── フォーム状態管理
           │
           ├─ useUpdateCustomer(id)
           │      └─ sdk.admin.customer.update()
           │             └─ queryClient.invalidateQueries()
           │
           └─ Form.Field × 5 ─── 各入力フィールド
```

### データフロー図

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

URL パラメータ (id) ───▶ useParams() ───▶ 顧客ID
                              │
                              ▼
                        useCustomer(id) ───▶ 顧客データ
                              │
                              ▼
フォーム入力値 ───────▶ useForm() ───▶ バリデーション済みデータ
                              │
                              ▼
                        useUpdateCustomer() ───▶ API 更新リクエスト
                              │
                              ▼
                        成功/エラー ───▶ トースト通知 + モーダルクローズ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| customer-edit.tsx | `packages/admin/dashboard/src/routes/customers/customer-edit/customer-edit.tsx` | ソース | ルートコンポーネント |
| edit-customer-form.tsx | `packages/admin/dashboard/src/routes/customers/customer-edit/components/edit-customer-form/edit-customer-form.tsx` | ソース | フォームコンポーネント |
| index.ts | `packages/admin/dashboard/src/routes/customers/customer-edit/index.ts` | ソース | エクスポート定義 |
| customers.tsx | `packages/admin/dashboard/src/hooks/api/customers.tsx` | ソース | 顧客 API フック |
| RouteDrawer | `packages/admin/dashboard/src/components/modals/` | ソース | モーダルコンポーネント |
| Form | `packages/admin/dashboard/src/components/common/form/` | ソース | フォームコンポーネント |
| ConditionalTooltip | `packages/admin/dashboard/src/components/common/conditional-tooltip/` | ソース | 条件付きツールチップ |
