# 画面設計書 119-記事ビューア画面

## 概要

本ドキュメントは、Chatwootのチャットウィジェットにおける記事ビューア画面の設計書です。ヘルプセンターの記事をウィジェット内で閲覧するための画面です。

### 本画面の処理概要

**業務上の目的・背景**：記事ビューア画面は、顧客がサポートエージェントに問い合わせる前に、セルフサービスでヘルプセンターの記事を閲覧できるようにするための画面です。これにより、顧客は自己解決の機会を得られ、サポートチームの負荷軽減にも貢献します。ウィジェット内で記事を直接表示することで、シームレスなユーザー体験を提供します。

**画面へのアクセス方法**：ホーム画面の記事一覧から記事をクリック、または検索結果から記事を選択した際に遷移します。URLハッシュパスは `/article` で、クエリパラメータ `link` に記事URLが渡されます。

**主要な操作・処理内容**：
1. 記事URLをiframe内で表示
2. ローディング状態の表示
3. 読み込みエラー時のフォールバック表示

**画面遷移**：
- 遷移元：ホーム画面（記事クリック）
- 遷移先：ホーム画面（戻るボタン）

**権限による表示制御**：ウィジェットはWebサイト訪問者向けのため、特別な権限制御はありません。ただし、記事自体の公開設定に依存します。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 159 | 公開API | 主機能 | ヘルプ記事の表示 |

## 画面種別

コンテンツ表示画面

## URL/ルーティング

- パス: `#/article`（ウィジェット内ハッシュルーティング）
- ルート名: `article-viewer`
- コンポーネント: `ArticleViewer.vue`
- クエリパラメータ:
  - `link`: 表示する記事のURL

## 入出力項目

### 入力項目

本画面には直接の入力項目はありません。

### クエリパラメータ

| 項目名 | 項目ID | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| 記事URL | link | string | Yes | 表示する記事のURL |

## 表示項目

### iframeエリア

| 項目名 | 説明 |
|--------|------|
| 記事iframe | 記事URLを読み込むiframe |
| ローディングスケルトン | 読み込み中のスケルトンローダー |
| エラーメッセージ | URLなしまたは読み込みエラー時のメッセージ |

## イベント仕様

### 1-iframe読み込み完了

**トリガー**: iframeのloadイベント

**処理フロー**:
1. `handleIframeLoad`メソッド呼び出し
2. `isLoading`をfalseに設定
3. RTL（右から左）方向の適用（設定に応じて）

### 2-iframe読み込みエラー

**トリガー**: iframeのerrorイベント

**処理フロー**:
1. `handleIframeError`メソッド呼び出し
2. `isLoading`をfalseに設定
3. `showEmptyState`をtrueに設定
4. エラーメッセージを表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| - | - | - | 本画面ではDBへの直接更新なし |

本画面は表示専用であり、データベースへの更新は行いません。

## メッセージ仕様

| 種別 | キー | メッセージ内容 | 表示タイミング |
|------|-----|---------------|---------------|
| エラー | PORTAL.IFRAME_ERROR | 記事を読み込めませんでした | URL未指定またはiframe読み込みエラー時 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| URLが空 | エンプティステートを表示 |
| iframe読み込みエラー | エラーメッセージを表示 |
| クロスオリジン制限 | iframeがブロックされた場合はエラー表示 |

## 備考

- 共有コンポーネント`IframeLoader`を使用
- 記事はヘルプセンターポータルの公開記事が対象
- RTL（Right-to-Left）言語対応あり
- スケルトンローダーによる読み込み中表示
- iframeの高さは親コンテナに合わせてフル高さ

---

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

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

### 推奨読解順序

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

記事URLの受け渡し方法を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ArticleViewer.vue | `app/javascript/widget/views/ArticleViewer.vue` | L14: $route.query.link |

**読解のコツ**: 記事URLはクエリパラメータ `link` で渡される。

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

ルーティングとビューコンポーネントの構成を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | router.js | `app/javascript/widget/router.js` | L38-41: article-viewerルート定義 |
| 2-2 | ArticleViewer.vue | `app/javascript/widget/views/ArticleViewer.vue` | ビューコンポーネント |

**主要処理フロー**:
1. **L14**: テンプレートで`$route.query.link`をIframeLoaderに渡す

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

IframeLoaderの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | IframeLoader.vue | `app/javascript/shared/components/IframeLoader.vue` | iframe表示ロジック |

**IframeLoader.vue主要処理**:
- **L6-18**: props定義（url, isRtl, isDirApplied）
- **L24-25**: isLoading, showEmptyStateの状態管理
- **L29-42**: applyDirection - RTL方向の適用
- **L46-49**: handleIframeLoad - 読み込み完了処理
- **L51-54**: handleIframeError - エラー処理

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

```
ArticleViewer.vue (ビュー)
    |
    +-- IframeLoader.vue
            |
            +-- props: url
            |       |
            |       +-- $route.query.link
            |
            +-- iframe
            |       |
            |       +-- @load -> handleIframeLoad()
            |       |       |
            |       |       +-- isLoading = false
            |       |       +-- applyDirection()
            |       |
            |       +-- @error -> handleIframeError()
            |               |
            |               +-- isLoading = false
            |               +-- showEmptyState = true
            |
            +-- ArticleSkeletonLoader (ローディング中)
            |
            +-- エラーメッセージ (エラー時)
```

### データフロー図

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

$route.query.link ------> ArticleViewer.vue
        |                       |
        v                       v
   IframeLoader.vue ----> iframe src設定
        |                       |
        +-- isLoading = true    |
        |                       v
        |               iframe読み込み
        |                       |
        +---- @load ------------> handleIframeLoad()
        |                               |
        |                               +-> isLoading = false
        |                               +-> applyDirection()
        |
        +---- @error -----------> handleIframeError()
                                        |
                                        +-> showEmptyState = true
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ArticleViewer.vue | `app/javascript/widget/views/ArticleViewer.vue` | ソース | ビューコンポーネント |
| IframeLoader.vue | `app/javascript/shared/components/IframeLoader.vue` | ソース | iframe表示共有コンポーネント |
| router.js | `app/javascript/widget/router.js` | ソース | ルーティング |
| ArticleSkeletonLoader.vue | `app/javascript/shared/components/ArticleSkeletonLoader.vue` | ソース | スケルトンローダー |
