# 画面設計書 21-支払先編集画面（モバイル）

## 概要

本ドキュメントは、Actual Budgetアプリケーションにおけるモバイル向け支払先編集画面の設計仕様を定義するものである。

### 本画面の処理概要

モバイルデバイスにおいて、既存の支払先（Payee）の名称を編集するための専用画面である。ユーザーはこの画面を通じて支払先名を変更し、取引履歴に関連付けられた支払先情報を一元的に更新できる。

**業務上の目的・背景**：家計管理において、支払先の表記ゆれや入力ミスは取引の整理・分析を困難にする。本画面は、モバイル環境でも支払先名を迅速に修正できる機能を提供し、データ品質の維持と管理効率の向上を実現する。特にモバイルユーザーが外出先で気づいた支払先名の誤りをその場で修正できることで、ユーザーエクスペリエンスを向上させる。

**画面へのアクセス方法**：支払先管理画面（モバイル）の一覧から特定の支払先をタップすることで、`/payees/:id` のルートを通じて本画面に遷移する。このルートはナロー画面幅（モバイル）でのみアクセス可能であり、ワイド画面幅ではモーダルダイアログが使用される。

**主要な操作・処理内容**：
1. 画面表示時に指定IDの支払先情報をローカルデータから取得・表示
2. 支払先名の入力フィールドで名称を編集
3. 「Save」ボタンで変更を保存し、Undo通知を表示後に一覧画面へ戻る
4. 戻るボタンまたはキャンセル操作で編集を破棄して前画面に戻る

**画面遷移**：
- 遷移元：支払先管理画面（モバイル） `/payees`
- 遷移先：支払先管理画面（モバイル） `/payees`（保存完了時・キャンセル時）

**権限による表示制御**：特別な権限制御は設けられていない。予算ファイルにアクセスできるユーザーであれば編集可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 18 | 支払先（Payee）管理 | 主機能 | モバイルでの支払先詳細編集 |

## 画面種別

編集

## URL/ルーティング

`/payees/:id`

- `:id` - 編集対象の支払先ID（UUID形式）
- モバイル（ナロー画面幅）でのみアクセス可能
- ワイド画面幅でアクセスした場合は `/budget` にリダイレクト

## 入出力項目

| 項目名 | 項目ID | データ型 | 入力/出力 | 必須 | 説明 |
|--------|--------|----------|-----------|------|------|
| 支払先ID | id | string | 入力（URL） | 必須 | 編集対象の支払先を識別するID |
| 支払先名 | editedPayeeName | string | 入力 | 必須 | 編集可能な支払先名。空白のみは無効 |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| ヘッダータイトル | string | "Edit Payee" と表示（ローカライズ対応） |
| 支払先名入力フィールド | string | 現在の支払先名を表示し、編集可能 |
| Saveボタン | button | 変更を保存するボタン（名前未入力時は無効） |
| 戻るボタン | button | 前画面に戻るボタン |
| ローディング表示 | text | データ取得中に "Loading payee..." を表示 |

## イベント仕様

### 1-画面初期表示

URLパラメータの `id` を使用して支払先データをローカルキャッシュから検索する。

**処理フロー**:
1. `usePayees()` フックから支払先一覧を取得
2. URL パラメータの `id` と一致する支払先を検索
3. 見つかった場合：支払先データをステートに設定し、名前を入力フィールドに反映
4. 見つからない場合：`/payees` へリダイレクト

### 2-支払先名変更

入力フィールドの値を変更するとリアルタイムでステートが更新される。

**処理フロー**:
1. `onChangeValue` イベントで `setEditedPayeeName` を呼び出し
2. ステート `editedPayeeName` が更新される
3. 入力値が空または空白のみの場合、Saveボタンが無効化される

### 3-保存処理

Saveボタン押下時に支払先名の更新をサーバーに送信する。

**処理フロー**:
1. 入力値のトリム処理を実行
2. `payees-batch-change` API を呼び出し、更新データを送信
3. 成功時：Undo通知を表示し、`/payees` へ遷移
4. 失敗時：エラー通知を表示し、画面に留まる

### 4-キャンセル処理

戻るボタン押下時に編集を破棄して前画面に戻る。

**処理フロー**:
1. `navigate(-1)` で前画面に戻る
2. 未保存の変更は破棄される

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| Save押下 | payees | UPDATE | 支払先名の更新 |

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

#### payees

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | name | 編集後の支払先名（トリム済み） | WHERE id = :id |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG-001 | 成功 | "Payee {oldName} renamed to {newName}" | 保存成功時（Undo通知） |
| MSG-002 | エラー | "Failed to update payee. Please try again." | 保存失敗時 |
| MSG-003 | ローディング | "Loading payee..." | データ取得中 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 支払先が見つからない | `/payees` へリダイレクト |
| API通信エラー | エラー通知を表示し、画面に留まる |
| 空の支払先名で保存 | Saveボタンが無効化されているため発生しない |

## 備考

- 本画面はモバイル専用であり、デスクトップ版ではモーダルダイアログが使用される
- 支払先名の変更はUndo機能によって取り消し可能
- 支払先の削除機能は本画面には含まれない（一覧画面で提供）

---

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

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

### 推奨読解順序

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

まず、支払先データの型定義を理解することで、画面で扱うデータの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models/index.d.ts | `packages/loot-core/src/types/models/index.d.ts` | PayeeEntity型の定義を確認。id, name, transfer_acct等のプロパティ構造を理解する |

**読解のコツ**: TypeScriptの型定義ファイルであり、`type PayeeEntity` を検索して支払先の構造を確認する。

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

画面コンポーネントの全体構造とReactフックの使用方法を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | MobilePayeeEditPage.tsx | `packages/desktop-client/src/components/mobile/payees/MobilePayeeEditPage.tsx` | 画面コンポーネント全体。useParams, usePayees, useNavigate等のフック使用を確認 |

**主要処理フロー**:
1. **23-29行目**: コンポーネント定義とフック初期化（useTranslation, useNavigate, useParams, useDispatch, useUndo, usePayees）
2. **31-33行目**: ローカルステート定義（payee, editedPayeeName, isLoading）
3. **36-49行目**: useEffectによる初期データ取得とリダイレクト処理
4. **55-82行目**: handleSave関数でのAPI呼び出しと通知処理
5. **112-151行目**: JSXによる画面レンダリング（Page, MobilePageHeader, InputField, Button）

#### Step 3: データ取得層を理解する

支払先データの取得元とキャッシュ機構を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | usePayees.ts | `packages/desktop-client/src/hooks/usePayees.ts` | useSelectorを使用したReduxストアからの支払先データ取得 |

**主要処理フロー**:
- usePayeesフックはReduxストアの `state.account.payees` から支払先一覧を取得
- データはアプリ起動時にサーバーから同期されキャッシュされている

#### Step 4: API通信層を理解する

データ更新時のサーバー通信処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | fetch/index.ts | `packages/loot-core/src/platform/client/fetch/index.ts` | send関数によるIPC/HTTP通信の実装 |
| 4-2 | payees.ts (server) | `packages/loot-core/src/server/payees.ts` | payees-batch-change APIのサーバー側実装 |

**主要処理フロー**:
- `send('payees-batch-change', { updated: [...] })` でバッチ更新リクエストを送信
- サーバー側で `db.update('payees', ...)` を実行してデータベースを更新

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

```
MobilePayeeEditPage (コンポーネント)
    │
    ├─ usePayees()
    │      └─ useSelector(state.account.payees)
    │
    ├─ useParams()
    │      └─ React Router から id を取得
    │
    ├─ handleSave()
    │      ├─ send('payees-batch-change', ...)
    │      │      └─ サーバーAPI呼び出し
    │      ├─ showUndoNotification()
    │      │      └─ Undo通知の表示
    │      └─ navigate('/payees')
    │
    └─ handleCancel()
           └─ navigate(-1)
```

### データフロー図

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

URL param (id) ───────▶ useParams() ─────────────────────▶ 対象支払先の特定
                             │
Redux Store ──────────▶ usePayees() ─────────────────────▶ 支払先データ取得
    (payees)                 │
                             ▼
                     payee state に設定
                             │
ユーザー入力 ─────────▶ InputField ───────────────────────▶ editedPayeeName state
                             │
                             ▼
Save押下 ─────────────▶ send('payees-batch-change') ──────▶ サーバーDB更新
                             │
                             ├──▶ showUndoNotification() ──▶ Undo通知表示
                             │
                             └──▶ navigate('/payees') ─────▶ 一覧画面へ遷移
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| MobilePayeeEditPage.tsx | `packages/desktop-client/src/components/mobile/payees/MobilePayeeEditPage.tsx` | ソース | 画面コンポーネント本体 |
| usePayees.ts | `packages/desktop-client/src/hooks/usePayees.ts` | ソース | 支払先データ取得フック |
| useNavigate.ts | `packages/desktop-client/src/hooks/useNavigate.ts` | ソース | 画面遷移フック |
| useUndo.ts | `packages/desktop-client/src/hooks/useUndo.ts` | ソース | Undo通知表示フック |
| MobileForms.tsx | `packages/desktop-client/src/components/mobile/MobileForms.tsx` | ソース | InputFieldコンポーネント |
| MobileBackButton.tsx | `packages/desktop-client/src/components/mobile/MobileBackButton.tsx` | ソース | 戻るボタンコンポーネント |
| Page.tsx | `packages/desktop-client/src/components/Page.tsx` | ソース | ページレイアウトコンポーネント |
| fetch/index.ts | `packages/loot-core/src/platform/client/fetch/index.ts` | ソース | API通信関数 |
| FinancesApp.tsx | `packages/desktop-client/src/components/FinancesApp.tsx` | ソース | ルーティング定義（283-288行目） |
| models/index.d.ts | `packages/loot-core/src/types/models/index.d.ts` | 型定義 | PayeeEntity型定義 |
