# 画面設計書 31-カテゴリ編集画面

## 概要

本ドキュメントは、Medusa Admin Dashboard におけるカテゴリ編集画面の設計を記述したものです。

### 本画面の処理概要

商品カテゴリの基本情報（名前、ハンドル、説明、ステータス、可視性）を編集するための画面です。

**業務上の目的・背景**：ECサイトにおいて商品を整理・分類するためのカテゴリを管理する必要があります。カテゴリ名やURLに使用するハンドル、カテゴリの説明文、アクティブ状態、公開/内部専用の設定を適切に変更できることで、商品の分類体系を柔軟にメンテナンスできます。これにより、顧客が商品を見つけやすくなり、運用者も効率的に商品管理を行えます。

**画面へのアクセス方法**：カテゴリ詳細画面の「編集」ボタン押下、またはカテゴリ一覧画面からカテゴリを選択後に「編集」メニューを選択することで、右側からドロワー形式で表示されます。

**主要な操作・処理内容**：
1. カテゴリ名（タイトル）の編集 - 必須項目
2. ハンドル（URL識別子）の編集 - 必須項目
3. 説明文の編集 - 任意項目
4. ステータス（アクティブ/非アクティブ）の変更
5. 可視性（公開/内部）の変更
6. 保存ボタン押下で変更内容を確定

**画面遷移**：カテゴリ詳細画面から遷移してきます。保存完了後またはキャンセル時にカテゴリ詳細画面に戻ります。

**権限による表示制御**：管理者権限を持つユーザーのみがカテゴリを編集できます。認証されていないユーザーはログイン画面にリダイレクトされます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | 商品カテゴリ管理 | 主機能 | カテゴリ情報の編集 |

## 画面種別

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

## URL/ルーティング

`/categories/:id/edit`

## 入出力項目

| 項目名 | 項目ID | 型 | 必須 | 最大長 | 入力/出力 | 説明 |
|--------|--------|-----|------|--------|-----------|------|
| カテゴリID | id | string | - | - | 入力(URL) | 編集対象のカテゴリID |
| カテゴリ名 | name | string | 必須 | - | 入出力 | カテゴリのタイトル（最低1文字） |
| ハンドル | handle | string | 必須 | - | 入出力 | URL用の識別子（最低1文字） |
| 説明 | description | string | 任意 | - | 入出力 | カテゴリの説明文 |
| ステータス | status | enum | 必須 | - | 入出力 | active/inactive |
| 可視性 | visibility | enum | 必須 | - | 入出力 | public/internal |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| ヘッダータイトル | テキスト | "Edit Category"（i18n: categories.edit.header） |
| タイトルラベル | フォームラベル | "Title"（i18n: fields.title） |
| ハンドルラベル | フォームラベル（tooltip付き） | "Handle"（i18n: fields.handle） |
| 説明ラベル | フォームラベル（optional表示） | "Description"（i18n: fields.description） |
| ステータスラベル | フォームラベル | i18n: categories.fields.status.label |
| 可視性ラベル | フォームラベル | i18n: categories.fields.visibility.label |

## イベント仕様

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

フォームのバリデーションを実行し、成功した場合はAPIを呼び出してカテゴリ情報を更新します。

**処理フロー**:
1. Zodスキーマによるバリデーション実行
2. `useUpdateProductCategory` フックを使用してAPI呼び出し
3. 成功時: トースト通知（categories.edit.successToast）を表示し、モーダルを閉じる
4. 失敗時: エラーメッセージをトーストで表示

**API呼び出し**:
- エンドポイント: `POST /admin/product-categories/:id`
- リクエストボディ:
  ```json
  {
    "name": "string",
    "description": "string",
    "handle": "string",
    "is_active": "boolean",
    "is_internal": "boolean"
  }
  ```

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

フォームの変更を破棄し、ドロワーを閉じてカテゴリ詳細画面に戻ります。

### 3-ステータス選択変更

ドロップダウンから「Active」または「Inactive」を選択します。`is_active` フラグとして保存されます。

### 4-可視性選択変更

ドロップダウンから「Public」または「Internal」を選択します。`is_internal` フラグとして保存されます。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | product_category | UPDATE | カテゴリの基本情報を更新 |

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

#### product_category

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | name | フォーム入力値 | カテゴリ名 |
| UPDATE | handle | フォーム入力値 | URL識別子 |
| UPDATE | description | フォーム入力値 | 説明文（空文字可） |
| UPDATE | is_active | status === "active" | ステータスフラグ |
| UPDATE | is_internal | visibility === "internal" | 内部専用フラグ |
| UPDATE | updated_at | 現在日時 | 自動更新 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示タイミング |
|------------|------|--------------|--------------|
| categories.edit.successToast | 成功 | カテゴリが正常に更新されました | 保存成功時 |
| - | エラー | {error.message} | API呼び出し失敗時 |
| - | バリデーションエラー | フィールド別エラーメッセージ | 入力値不正時 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| カテゴリが見つからない | エラーをスローし、エラーバウンダリで処理 |
| API通信エラー | トーストでエラーメッセージを表示 |
| バリデーションエラー | 各フィールドの下にエラーメッセージを表示 |
| 認証エラー | ログイン画面にリダイレクト |

## 備考

- ドロワー形式（RouteDrawer）で表示され、背景のカテゴリ詳細画面は薄暗く表示される
- キーボードショートカット対応（KeyboundForm）
- RTL（右から左）言語にも対応（useDocumentDirection）
- フォームの状態管理にはreact-hook-formを使用
- バリデーションにはZodスキーマを使用

---

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

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

### 推奨読解順序

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

カテゴリのデータ型とフォームのスキーマを理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | edit-category-form.tsx | `packages/admin/dashboard/src/routes/categories/category-edit/components/edit-category-form/edit-category-form.tsx` | EditCategorySchema（15-21行目）でフォームのバリデーションルールを確認 |
| 1-2 | types.ts | `packages/medusa/src/types/` | HttpTypes.AdminProductCategory の型定義を確認 |

**読解のコツ**: Zodスキーマの定義を見ることで、各フィールドの必須/任意、型、バリデーションルールが把握できます。

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

ルートコンポーネントから画面がどのように構成されるかを理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | category-edit.tsx | `packages/admin/dashboard/src/routes/categories/category-edit/category-edit.tsx` | useParamsでID取得、useProductCategoryでデータフェッチ、RouteDrawerでドロワー表示 |

**主要処理フロー**:
1. **10行目**: useParamsでURLからカテゴリIDを取得
2. **13-15行目**: useProductCategoryフックでカテゴリデータをフェッチ
3. **17行目**: データ取得完了の判定
4. **19-21行目**: エラー時の例外スロー
5. **33行目**: データ準備完了後にEditCategoryFormを表示

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

編集フォームの実装詳細を把握します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | edit-category-form.tsx | `packages/admin/dashboard/src/routes/categories/category-edit/components/edit-category-form/edit-category-form.tsx` | useForm、useUpdateProductCategory、handleSubmitの実装を確認 |

**主要処理フロー**:
- **31-40行目**: useFormでフォーム初期化、既存データをdefaultValuesに設定
- **42行目**: useUpdateProductCategoryでミューテーションフック取得
- **43-62行目**: handleSubmitで送信処理を定義
- **44-51行目**: mutateAsyncでAPI呼び出し、is_active/is_internalの変換
- **53-60行目**: 成功時のトースト表示とモーダルクローズ、エラー時のトースト表示

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | categories.tsx | `packages/admin/dashboard/src/hooks/api/categories.tsx` | useProductCategory（21-41行目）、useUpdateProductCategory（111-131行目）の実装を確認 |

**主要処理フロー**:
- **111-131行目**: useMutationでAPIコール、成功時にクエリキャッシュを無効化

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

```
CategoryEdit (category-edit.tsx)
    │
    ├─ useParams() → カテゴリID取得
    │
    ├─ useProductCategory(id) → カテゴリデータ取得
    │      └─ sdk.admin.productCategory.retrieve()
    │
    └─ EditCategoryForm (edit-category-form.tsx)
           │
           ├─ useForm() → フォーム状態管理
           │
           ├─ useUpdateProductCategory(id) → 更新ミューテーション
           │      └─ sdk.admin.productCategory.update()
           │
           └─ handleSubmit() → フォーム送信処理
                  ├─ mutateAsync() → API呼び出し
                  ├─ toast.success() → 成功通知
                  └─ handleSuccess() → モーダルクローズ
```

### データフロー図

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

URLパラメータ(:id) ───▶ useProductCategory ───▶ カテゴリデータ表示
                              │
                              ▼
フォーム入力値 ─────────▶ Zodバリデーション
                              │
                              ▼
                        useUpdateProductCategory
                              │
                              ▼
                        SDK API呼び出し ───▶ product_category更新
                              │
                              ▼
                        クエリキャッシュ無効化 ───▶ UI更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| category-edit.tsx | `packages/admin/dashboard/src/routes/categories/category-edit/category-edit.tsx` | ソース | ルートコンポーネント |
| edit-category-form.tsx | `packages/admin/dashboard/src/routes/categories/category-edit/components/edit-category-form/edit-category-form.tsx` | ソース | 編集フォームコンポーネント |
| index.ts | `packages/admin/dashboard/src/routes/categories/category-edit/index.ts` | ソース | エクスポート定義 |
| categories.tsx | `packages/admin/dashboard/src/hooks/api/categories.tsx` | ソース | カテゴリAPI フック |
| RouteDrawer | `packages/admin/dashboard/src/components/modals/` | ソース | ドロワーモーダルコンポーネント |
| Form | `packages/admin/dashboard/src/components/common/form/` | ソース | フォームコンポーネント |
| HandleInput | `packages/admin/dashboard/src/components/inputs/handle-input/` | ソース | ハンドル入力コンポーネント |
| KeyboundForm | `packages/admin/dashboard/src/components/utilities/keybound-form/` | ソース | キーバインド対応フォーム |
