Skip to content

feat: 공통 네비바 + 대시보드 + 즐겨찾기 단축키 + 선택 다시 풀기 - #13

Merged
ginaseo merged 5 commits into
mainfrom
nav-and-dashboard
Jul 30, 2026
Merged

feat: 공통 네비바 + 대시보드 + 즐겨찾기 단축키 + 선택 다시 풀기#13
ginaseo merged 5 commits into
mainfrom
nav-and-dashboard

Conversation

@ginaseo

@ginaseo ginaseo commented Jul 30, 2026

Copy link
Copy Markdown
Owner

기능 설명

수동 QA 중 나온 4개 요구사항 처리.

  1. 복습/문제풀이 화면에서 홈·대시보드로 이동 불가 → 공통 네비바(layout.tsx)로 모든 페이지에서 이동 가능
  2. 즐겨찾기가 마우스 클릭만 지원 → F 키 단축키 추가
  3. 복습 화면이 "전체 다시 풀기"만 지원 → 체크박스로 문항 선택해서 "선택 다시 풀기" 가능
  4. 대시보드 화면 부재 → ProgressRepository.getDashboardSummary()(기존 구현·테스트됨) 소비하는 /dashboard 화면 신설

작업내용

  • src/features/nav/NavBar.tsx 신설, src/app/layout.tsx에 삽입
  • src/app/dashboard/page.tsx 신설
  • src/features/practice/PracticeSession.tsxhandleKeyDownF 키 분기 추가
  • src/features/review/ReviewList.tsx — 체크박스 다중선택, onRetryAllonRetry(questions) 시그니처 변경
  • src/app/review/page.tsxhandleRetryAllhandleRetry(selectedQuestions)로 교체

검증: npx tsc --noEmit, npm run lint, npm run build 전부 통과. /, /practice, /review, /dashboard 라우트 curl 스모크테스트로 네비 링크·대시보드 렌더 확인. Codex 리뷰 1회 돌림 — P1 4건 나왔으나 직접 코드 대조 결과 전부 오탐(codex 샌드박스가 npm run build/tsc 실행을 거부당해 PowerShell Get-Content로 한글 파일 읽다 인코딩 깨진 것으로 추정) — 조치 없음.

Closes #10, #11, #12

참고문서

docs/superpowers/plans/2026-07-31-nav-and-dashboard.md (로컬 전용, repo 미포함)

Summary by CodeRabbit

  • 새로운 기능
    • 오늘 및 전체 문제 풀이 수와 정답률을 확인할 수 있는 대시보드를 추가했습니다.
    • 홈, 문제 풀이, 복습, 대시보드로 이동할 수 있는 상단 내비게이션을 추가했습니다.
    • 복습 목록에서 문제를 선택해 다시 풀 수 있습니다.
    • F 키로 현재 문제를 즐겨찾기에 추가하거나 해제할 수 있습니다.
  • 개선 사항
    • 앱 이름과 설명을 PassFlow에 맞게 변경하고 한국어 환경을 적용했습니다.
    • 대시보드 데이터 로딩 중 안내 메시지를 제공합니다.

@github-actions github-actions Bot added the enhancement New feature or request label Jul 30, 2026
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ginaseo, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b7a7af2a-ebc6-4f9a-adcb-8f1d11dca4de

📥 Commits

Reviewing files that changed from the base of the PR and between fc97b81 and 4df02dc.

📒 Files selected for processing (2)
  • src/app/dashboard/page.tsx
  • src/features/nav/NavBar.tsx
📝 Walkthrough

Walkthrough

대시보드와 공통 네비게이션이 추가되었고, 복습 문제를 선택적으로 다시 풀 수 있도록 변경되었다. PracticeSession에는 F/f 즐겨찾기 단축키가 추가되었다.

Changes

앱 학습 기능 개선

Layer / File(s) Summary
공통 네비게이션과 대시보드
src/app/layout.tsx, src/features/nav/NavBar.tsx, src/app/dashboard/page.tsx
루트 레이아웃에 한국어 메타데이터와 공통 네비게이션을 추가하고, IndexedDB 요약 데이터를 대시보드 카드에 표시한다.
선택 복습 재시도
src/features/review/ReviewList.tsx, src/app/review/page.tsx
복습 목록에서 문제를 선택해 선택 항목 또는 전체 문제를 다시 풀도록 콜백과 상태 흐름을 변경한다.
즐겨찾기 키보드 단축키
src/features/practice/PracticeSession.tsx
F/f 입력으로 현재 문제의 즐겨찾기를 전환하고 키보드 안내 문구를 갱신한다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

  • ginaseo/passflow#11: PracticeSession의 즐겨찾기 F/f 단축키 추가 목적과 직접 일치한다.

Possibly related PRs

  • ginaseo/passflow#8: ReviewList/ReviewPage의 선택 재시도 흐름과 PracticeSession 즐겨찾기 토글을 같은 코드 영역에서 다룬다.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 대시보드, F 단축키, 선택 다시 풀기는 링크된 #10 범위를 넘어선 별도 기능 변경입니다. 이 기능들은 별도 이슈로 분리하거나 링크된 이슈 목록에 추가해 PR 범위를 명확히 해주세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 공통 네비바, 대시보드, F 단축키, 선택 다시 풀기 등 실제 변경의 핵심을 간결하게 요약합니다.
Description check ✅ Passed 요약·테스트·참고문서 내용이 모두 포함되어 있어 템플릿 요구사항을 대부분 충족합니다.
Linked Issues check ✅ Passed 공통 네비바를 layout에 삽입해 /review와 /practice에서도 홈·대시보드로 이동 가능해져 #10을 충족합니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch nav-and-dashboard

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/dashboard/page.tsx`:
- Around line 26-29: Update the getDashboardSummary error handler so failures
are stored in a separate error state instead of replacing the summary with
EMPTY_SUMMARY. Render a clear error message with a retry action when that state
is set, while preserving EMPTY_SUMMARY only for a successful response that
contains no learning records.

In `@src/features/nav/NavBar.tsx`:
- Around line 19-22: Update the Link elements in NavBar to expose the active
navigation state to assistive technology: set aria-current to "page" when
pathname matches link.href, and pass undefined for inactive links. Keep the
existing className styling behavior unchanged.

In `@src/features/practice/PracticeSession.tsx`:
- Around line 86-87: Update the F-key handler in PracticeSession to branch on
the current favorite state, calling addFavorite() when the item is not favorited
and removeFavorite() when it is already favorited; do not call toggleFavorite(),
so repeated F presses both add and remove the favorite as indicated by the
shortcut.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e3959107-6baa-4899-b6d1-b82a97bc85fd

📥 Commits

Reviewing files that changed from the base of the PR and between 6465491 and fc97b81.

📒 Files selected for processing (6)
  • src/app/dashboard/page.tsx
  • src/app/layout.tsx
  • src/app/review/page.tsx
  • src/features/nav/NavBar.tsx
  • src/features/practice/PracticeSession.tsx
  • src/features/review/ReviewList.tsx

Comment on lines +26 to +29
(err) => {
console.error("getDashboardSummary failed:", err);
setSummary(EMPTY_SUMMARY);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

조회 실패를 빈 학습 기록으로 표시하지 마세요.

getDashboardSummary()가 실패했을 때 EMPTY_SUMMARY를 렌더링하면 IndexedDB 오류가 “풀이 0건, 정답률 0%”로 오인됩니다. 오류 상태를 별도로 저장하고 재시도 또는 오류 안내를 표시해야 합니다.

수정 예시
+  const [loadError, setLoadError] = useState(false);
+
   useEffect(() => {
     progressRepository.getDashboardSummary().then(
       (result) => setSummary(result),
       (err) => {
         console.error("getDashboardSummary failed:", err);
-        setSummary(EMPTY_SUMMARY);
+        setLoadError(true);
       }
     );
   }, []);
 
+  if (loadError) {
+    return <p className="text-center p-10">통계를 불러오지 못했습니다.</p>;
+  }
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
(err) => {
console.error("getDashboardSummary failed:", err);
setSummary(EMPTY_SUMMARY);
}
const [loadError, setLoadError] = useState(false);
useEffect(() => {
progressRepository.getDashboardSummary().then(
(result) => setSummary(result),
(err) => {
console.error("getDashboardSummary failed:", err);
setLoadError(true);
}
);
}, []);
if (loadError) {
return <p className="text-center p-10">통계를 불러오지 못했습니다.</p>;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/dashboard/page.tsx` around lines 26 - 29, Update the
getDashboardSummary error handler so failures are stored in a separate error
state instead of replacing the summary with EMPTY_SUMMARY. Render a clear error
message with a retry action when that state is set, while preserving
EMPTY_SUMMARY only for a successful response that contains no learning records.

Comment thread src/features/nav/NavBar.tsx
Comment on lines +86 to +87
} else if (e.key === "f" || e.key === "F") {
toggleFavorite();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

F 단축키가 실제로 즐겨찾기를 전환하도록 수정하세요.

현재 toggleFavorite()은 이미 선택된 경우 반환하므로 F를 다시 눌러도 해제되지 않습니다. 상태에 따라 addFavorite()removeFavorite()을 분기해 안내 문구의 “F: 즐겨찾기” 동작을 충족해야 합니다.

수정 예시
 function toggleFavorite() {
-  if (favorited[current]) return;
-  setFavorited((prev) => ({ ...prev, [current]: true }));
-  progressRepository
-    .addFavorite(question.questionId)
+  const nextFavorited = !(favorited[current] ?? false);
+  setFavorited((prev) => ({ ...prev, [current]: nextFavorited }));
+  const update = nextFavorited
+    ? progressRepository.addFavorite(question.questionId)
+    : progressRepository.removeFavorite(question.questionId);
+  update
     .catch((err) => console.error("addFavorite failed:", err));
 }

Also applies to: 124-124

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/practice/PracticeSession.tsx` around lines 86 - 87, Update the
F-key handler in PracticeSession to branch on the current favorite state,
calling addFavorite() when the item is not favorited and removeFavorite() when
it is already favorited; do not call toggleFavorite(), so repeated F presses
both add and remove the favorite as indicated by the shortcut.

@ginaseo
ginaseo merged commit a59e3ea into main Jul 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

1 participant