feat: #103 /gradesページに最高ランク表示を追加#113
Conversation
- 新規エンドポイント GET /api/v1/users/me/grade-stats を追加 - 成績統計スキーマ(GradeStats, HighestRank)を実装 - grades_serviceで進捗計算・ランク判定ロジックを実装 - StatusCardに最高ランク表示セクションを追加(3カラムレイアウト) - ランク名(種子〜世界樹)を表示、画像背景透過対応 - 全体ランク方式(users.rank)を採用、最も進捗が高いカテゴリと組み合わせ fixes #103
There was a problem hiding this comment.
Pull request overview
このPRは、/gradesページに最高ランク表示機能を追加するものです。ユーザーの全体ランク(users.rank)と最も進捗が高いスキルツリーのカテゴリを組み合わせて、統計カードに最高ランク情報を表示します。
Changes:
- バックエンドに成績統計APIエンドポイント(
GET /api/v1/users/me/grade-stats)を追加 - 最高ランク計算ロジックをサービス層に実装(カテゴリ別進捗率計算、修了クエスト数取得)
- フロントエンドの統計カードに最高ランク表示セクションを追加(ランク画像とランク名を表示)
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
backend/app/schemas/grades.py |
成績統計情報のPydanticスキーマを定義(HighestRank, GradeStats) |
backend/app/services/grades_service.py |
成績統計の計算ロジックを実装(進捗率計算、最高カテゴリ取得、クエスト数カウント) |
backend/app/api/endpoints/users.py |
新規エンドポイント /me/grade-stats を追加 |
frontend/src/features/grades/types/index.ts |
TypeScript型定義に HighestRank インターフェースを追加 |
frontend/src/features/grades/components/StatusCard.tsx |
最高ランク表示セクションを追加(3カラムレイアウト) |
frontend/src/features/grades/api/mock.ts |
モックデータに highestRank を追加 |
Comments suppressed due to low confidence (1)
backend/app/services/grades_service.py:75
- 関数の戻り値の型アノテーションが正確ではありません。この関数は (カテゴリ名, 進捗率) のタプルを返すとコメントされていますが、実際には文字列のカテゴリ値("web", "ai", など)を返しています。より正確には「(カテゴリ値, 進捗率)」とするべきです。または、より厳密な型安全性のために tuple[SkillCategory, float] を使用することを検討してください。ただし、その場合は SkillCategory.WEB.value のように値に変換する必要があります。
def get_highest_progress_category(db: Session, user_id: int) -> tuple[str, float]:
"""最も進捗が高いカテゴリを取得
Args:
db: データベースセッション
user_id: ユーザーID
Returns:
(カテゴリ名, 進捗率) のタプル
| <span className="text-3xl text-[#006400] font-medium ml-3 pb-2"> | ||
| {displayRankName} | ||
| </span> |
| category_name: str # 表示用名称(例: "Web/App") | ||
| rank_name: str # ランク名(例: "林", "森", "世界樹") | ||
| color: str # 背景色(例: "#55aaff") |
There was a problem hiding this comment.
バックエンドとフロントエンドでフィールド名の命名規則に不一致があります。バックエンドでは snake_case(category_name, rank_name)を使用していますが、フロントエンド(frontend/src/features/grades/types/index.ts)では camelCase(categoryName, rankName)を期待しています。このままでは API レスポンスをフロントエンドが正しく処理できません。
解決方法として、Pydantic の ConfigDict で alias_generator を設定し、自動的に camelCase に変換するか、フィールドに個別に alias を設定してください。
| consecutive_days: int # 連続記録日数 | ||
| completed_quests: int # 修了したクエスト数 | ||
| highest_rank: HighestRank # 最高ランク情報 |
There was a problem hiding this comment.
バックエンドとフロントエンドでフィールド名の命名規則に不一致があります。バックエンドでは snake_case(consecutive_days, completed_quests, highest_rank)を使用していますが、フロントエンド(frontend/src/features/grades/types/index.ts)では camelCase(consecutiveDays, completedQuests, highestRank)を期待しています。このままでは API レスポンスをフロントエンドが正しく処理できません。
解決方法として、Pydantic の ConfigDict で alias_generator を設定し、自動的に camelCase に変換するか、フィールドに個別に alias を設定してください。
|
|
||
| console.log('Grade Stats:', stats); // デバッグ用 | ||
| console.log('Display Rank Name:', displayRankName); // デバッグ用 |
There was a problem hiding this comment.
デバッグ用の console.log が本番コードに残っています。これらは開発時のみ有効にするか、削除してください。本番環境では不要なログ出力はパフォーマンスに影響を与える可能性があります。
| console.log('Grade Stats:', stats); // デバッグ用 | |
| console.log('Display Rank Name:', displayRankName); // デバッグ用 |
|
|
||
| export const StatusCard: React.FC<StatusCardProps> = ({ stats }) => { | ||
| // ランク名を取得(rankNameがあればそれを使用、なければrankから取得) | ||
| const displayRankName = stats.highestRank.rankName || RANK_NAMES[stats.highestRank.rank] || "種子"; |
There was a problem hiding this comment.
rankName が提供されない場合のフォールバック処理が実装されていますが、stats.highestRank 自体が null または undefined の場合にエラーが発生します。GradeStats インターフェースでは highestRank が必須プロパティとして定義されていますが、API からのレスポンスが期待通りでない場合に備えて、オプショナルチェーン(?.)を使用することを推奨します。
例: const displayRankName = stats.highestRank?.rankName || RANK_NAMES[stats.highestRank?.rank ?? 0] || "種子";
| <div className="relative h-48 w-48 flex items-center justify-center"> | ||
| <Image | ||
| src={`/images/ranks/rank_tree_${stats.highestRank.rank}.png`} | ||
| alt={`Rank ${stats.highestRank.rank}`} | ||
| width={180} | ||
| height={180} | ||
| className="object-contain" | ||
| /> | ||
| </div> |
There was a problem hiding this comment.
元の要件(Issue #103)では、ランク画像の背景にカテゴリ色を表示することが指定されていました(style={{ backgroundColor: categoryColor }})が、現在の実装ではカテゴリ色が使用されていません。要件との不一致が意図的なものか確認してください。
もし意図的な変更であれば問題ありませんが、カテゴリ色の背景を追加する場合は、以下のように実装できます:
<div className="relative h-48 w-48 flex items-center justify-center rounded-lg"
style={{ backgroundColor: stats.highestRank.color }}>- ruff lintエラーF401を修正 - app/services/grades_service.pyから未使用のSkillCategoryインポートを削除
PR: /gradesページに最高ランク表示を追加 #103
概要
/gradesページの統計カードに「最高ランク」表示を追加しました。
現在の「連続記録」と「修了した問題」の左側に新しい項目として配置されています。
fixes #103
変更内容
バックエンド
新規ファイル
backend/app/schemas/grades.py: 成績統計情報のスキーマを定義HighestRank: 最高ランク情報(rank, category, categoryName, rankName, color)GradeStats: 成績統計(consecutiveDays, completedQuests, highestRank)backend/app/services/grades_service.py: 成績・統計情報の計算ロジックcalculate_skill_tree_progress(): スキルツリー進捗率計算get_highest_progress_category(): 最も進捗が高いカテゴリを取得get_completed_quests_count(): 修了クエスト数を取得get_consecutive_days(): 連続記録日数(現在は0を返す)変更ファイル
backend/app/api/endpoints/users.pyGET /api/v1/users/me/grade-statsを追加フロントエンド
変更ファイル
frontend/src/features/grades/types/index.tsHighestRankインターフェースを追加(rank, category, categoryName, rankName, color)GradeStatsにhighestRankプロパティを追加frontend/src/features/grades/components/StatusCard.tsxfrontend/src/features/grades/api/mock.tshighestRankを追加(rank: 5, rankName: "林")実装の特徴
全体ランク方式
要件に従い、現在の実装では全体で一つの
rank(users.rank)を使用しています。users.rank連続記録日数
ログイン履歴機能が未実装のため、現時点では0を返します。将来的な実装が必要です。
UI/UX
表示レイアウト
最高ランク表示
テスト
スクリーンショット
(動作確認後に追加)
チェックリスト