# 画面設計書 36-カレンダーレポート画面

## 概要

本ドキュメントは、Actual Budget アプリケーションのカレンダーレポート画面の設計仕様を記述したものである。

### 本画面の処理概要

カレンダーレポート画面は、取引データをカレンダー形式で可視化する画面である。各日の収入・支出をヒートマップ形式で表示し、日付や月をクリックすることで取引一覧をフィルタリングできる。

**業務上の目的・背景**：日々の収支パターンを把握することは、消費行動の改善に役立つ。この画面では、カレンダー上で各日の収入と支出を色の濃淡で表現し、支出が多かった日、収入があった日を一目で確認できる。特定の日や月の取引詳細を即座に確認できるため、「この日は何に使ったのか」という疑問にすぐに答えられる。季節変動や給料日後の消費パターンなど、時系列での消費傾向分析にも活用できる。

**画面へのアクセス方法**：サイドバーの「レポート」メニューをクリック後、レポートダッシュボードから「カレンダー」カードを選択、または直接 `/reports/calendar` URLにアクセスする。ダッシュボードウィジェットとして追加されている場合は、ウィジェットIDを含むURL `/reports/calendar/:id` でアクセスする。クエリパラメータ `?day=YYYY-MM-DD` または `?month=YYYY-MM` で特定日/月を指定してアクセスも可能。

**主要な操作・処理内容**：
1. 期間選択：開始月と終了月をドロップダウンから選択
2. 日付クリック：特定日をクリックしてその日の取引一覧を表示
3. 月クリック：月名をクリックしてその月の取引一覧を表示
4. フィルタ適用：口座やカテゴリなどの条件でデータをフィルタリング
5. 取引一覧操作：表示された取引のソート、詳細表示
6. ウィジェット保存：ダッシュボードウィジェットとして現在の設定を保存

**画面遷移**：レポートダッシュボード画面（`/reports`）から遷移する。取引クリック時はモバイルでは取引編集画面へ遷移する。

**権限による表示制御**：特に権限による制御はない。予算ファイルがロードされていることが前提条件となる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 33 | 収支レポート | 主機能 | カレンダー形式での取引・収支表示 |

## 画面種別

一覧・分析画面

## URL/ルーティング

- `/reports/calendar` - 基本URL
- `/reports/calendar/:id` - ダッシュボードウィジェットID指定時
- `/reports/calendar?day=YYYY-MM-DD` - 特定日指定時
- `/reports/calendar?month=YYYY-MM` - 特定月指定時

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 必須 | 説明 |
|--------|----------|---------|------|------|
| 開始月 | 入力 | string | Yes | 表示期間の開始月 |
| 終了月 | 入力 | string | Yes | 表示期間の終了月 |
| 表示モード | 入力 | string | Yes | 'static' または 'full' |
| フィルタ条件 | 入力 | array | No | RuleConditionEntity配列 |
| フィルタ演算子 | 入力 | string | No | 'and' または 'or' |
| day | 入力（クエリ） | string | No | 特定日フィルタ（YYYY-MM-DD） |
| month | 入力（クエリ） | string | No | 特定月フィルタ（YYYY-MM） |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| カレンダーグリッド | component | 各月のカレンダー表示（日ごとの収支ヒートマップ） |
| 月別サマリー | component | 各月の収入・支出合計 |
| 期間サマリー | component | 選択期間全体の収入・支出合計 |
| 取引一覧 | table/list | フィルタ条件に合致する取引の一覧 |

## イベント仕様

### 1-期間変更

ヘッダーの期間選択を変更すると、`onChangeDates`関数が呼び出され、カレンダーデータが再計算される。取引クエリも更新される。

### 2-日付クリック

カレンダー上の日付セルをクリックすると、`onDayClick`コールバックが実行され、日付フィルタが適用される。取引一覧がその日の取引のみに絞り込まれる。

### 3-月クリック

カレンダーの月名ボタンをクリックすると、月フィルタが適用され、取引一覧がその月の取引のみに絞り込まれる。

### 4-カレンダー外クリック

カレンダーコンポーネントの背景部分をクリックすると、日付フィルタがクリアされ、全期間の取引が表示される。

### 5-取引ソート

取引一覧のヘッダーをクリックすると、`onSort`コールバックにより並び順が変更される。ソートフィールドと昇順/降順が切り替わる。

### 6-取引クリック（モバイル）

モバイル画面幅で取引をクリックすると、`onOpenTransaction`により取引編集画面へ遷移する。

### 7-ウィジェット保存

「Save widget」ボタン押下時、`onSaveWidget`関数が実行され、フィルタ条件と期間設定がウィジェットのメタデータとして保存される。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ウィジェット保存 | dashboard_widgets | UPDATE | ウィジェットのmeta情報を更新 |
| カレンダーデータ取得 | transactions | SELECT | 取引データを取得して日別集計 |
| 取引一覧取得 | transactions | SELECT | フィルタ条件に合致する取引を取得 |

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

#### dashboard_widgets

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | meta | JSON（conditions, conditionsOp, timeFrame） | ウィジェット保存時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|---------|
| MSG_WIDGET_SAVED | 成功 | Dashboard widget successfully saved. | ウィジェット保存成功時 |
| MSG_WIDGET_SAVE_ERROR | エラー | Failed to save dashboard widget. | ウィジェット保存失敗時 |
| MSG_NO_TRANSACTIONS | 情報 | No transactions | 取引が存在しない場合 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| ウィジェットが存在しない | 「Save widget」ボタンが表示されない |
| 取引がない | 「No transactions」メッセージを表示 |
| ウィジェット保存失敗 | エラー通知を表示、コンソールにログ出力 |

## 備考

- カレンダーは週の開始曜日設定（firstDayOfWeekIdx）に従って表示
- 収入は緑色、支出は赤色で表示され、金額に応じて濃淡が変化
- デスクトップ画面幅では取引一覧がテーブル形式、モバイルではリスト形式
- モバイルでは取引一覧がボトムシート（ドラッグ可能）として表示
- react-springを使用したアニメーション（モバイルボトムシート）
- @use-gesture/reactを使用したドラッグジェスチャー対応

---

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

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

### 推奨読解順序

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

まず、カレンダーレポートで使用されるデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | models.ts | `loot-core/types/models` | `CalendarWidget`, `TransactionEntity`型の定義を確認 |
| 1-2 | calendar-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/calendar-spreadsheet.ts` | `CalendarDataType`、日別集計ロジック |

**読解のコツ**: カレンダーデータは月ごとに配列化され、各月に日別データが含まれる構造を理解する。

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

処理の起点となるメインコンポーネントを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Calendar.tsx | `packages/desktop-client/src/components/reports/reports/Calendar.tsx` | `Calendar`関数コンポーネントがエントリーポイント |

**主要処理フロー**:
1. **85-98行**: `Calendar`関数 - URLパラメータとクエリパラメータの取得
2. **105-764行**: `CalendarInner`関数 - メインのレンダリングロジック
3. **145-181行**: URLクエリパラメータからのフィルタ適用
4. **183-195行**: calendarSpreadsheetパラメータの生成
5. **200-230行**: 取引クエリの生成
6. **248行**: useReportフック呼び出し

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

カレンダー表示と取引一覧の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CalendarGraph.tsx | `packages/desktop-client/src/components/reports/graphs/CalendarGraph.tsx` | カレンダーグリッドの描画 |
| 3-2 | TransactionList.tsx | `packages/desktop-client/src/components/transactions/TransactionList.tsx` | デスクトップ取引一覧 |
| 3-3 | TransactionList.tsx | `packages/desktop-client/src/components/mobile/transactions/TransactionList.tsx` | モバイル取引一覧 |

#### Step 4: カレンダーカードコンポーネントを理解する

各月のカレンダーカード表示を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Calendar.tsx 内CalendarWithHeader | 同上 行766-932 | 月別カレンダーカードコンポーネント |
| 4-2 | Calendar.tsx 内CalendarCardHeader | 同上 行934-1007 | サマリーカード表示 |

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

```
Calendar (エントリーポイント)
    │
    ├─ useWidget (ウィジェットデータ取得)
    │
    ├─ useSearchParams (クエリパラメータ取得)
    │
    └─ CalendarInner (メインコンポーネント)
           │
           ├─ useRuleConditionFilters (フィルタ管理)
           │
           ├─ useTransactions (取引データ取得)
           │
           ├─ calendarSpreadsheet (カレンダーデータ計算)
           │      └─ useReport (データ取得フック)
           │
           ├─ Header (期間・フィルタUI)
           │
           ├─ CalendarWithHeader (月別カレンダーカード)
           │      └─ CalendarGraph (カレンダーグリッド)
           │
           ├─ CalendarCardHeader (サマリー)
           │
           └─ TransactionList (取引一覧)
                  │
                  ├─ デスクトップ: TransactionList
                  │
                  └─ モバイル: animated.div + TransactionListMobile
                         └─ useDrag (ジェスチャー)
```

### データフロー図

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

URLパラメータ ─────────▶ useWidget ─────────────────▶ ウィジェットメタデータ
    │
クエリパラメータ ──────▶ useSearchParams
    │                         │
    ├─ ?day=YYYY-MM-DD ───────┼──▶ 日付フィルタ適用
    └─ ?month=YYYY-MM ────────┼──▶ 月フィルタ適用
                              │
期間選択 ──────────────▶ state (start, end, mode)
                              │
フィルタ ──────────────▶ useRuleConditionFilters
                              │
                              ▼
                    calendarSpreadsheet
                              │
                              ▼
                        useReport
                              │
                              ▼
取引データ(DB) ──────▶ 日別集計処理 ─────────────▶ calendarData[]
                                                      │ start, end
                                                      │ data[]
                                                      │ totalIncome
                                                      │ totalExpense
                              │
                              ▼
                    CalendarWithHeader[]
                              │
                              ├──▶ CalendarGraph
                              │
                              └──▶ 月別サマリー

取引クエリ ────────────▶ useTransactions ─────────▶ 取引一覧
                                                         │
                                                         ▼
                                               TransactionList
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Calendar.tsx | `packages/desktop-client/src/components/reports/reports/Calendar.tsx` | ソース | メインコンポーネント |
| calendar-spreadsheet.ts | `packages/desktop-client/src/components/reports/spreadsheets/calendar-spreadsheet.ts` | ソース | カレンダーデータ集計 |
| CalendarGraph.tsx | `packages/desktop-client/src/components/reports/graphs/CalendarGraph.tsx` | ソース | カレンダーグリッド描画 |
| Header.tsx | `packages/desktop-client/src/components/reports/Header.tsx` | ソース | 期間選択ヘッダー |
| TransactionList.tsx | `packages/desktop-client/src/components/transactions/TransactionList.tsx` | ソース | デスクトップ取引一覧 |
| TransactionList.tsx | `packages/desktop-client/src/components/mobile/transactions/TransactionList.tsx` | ソース | モバイル取引一覧 |
| useTransactions.ts | `packages/desktop-client/src/hooks/useTransactions.ts` | ソース | 取引データ取得フック |
| DateRange.tsx | `packages/desktop-client/src/components/reports/DateRange.tsx` | ソース | 期間表示コンポーネント |
