Skip to content

Feat/25: 메인 화면 스캔 이력 카드 탐색 및 결과 이동 구현#26

Merged
kim-subsub merged 7 commits into
developfrom
feat/25
Apr 10, 2026
Merged

Feat/25: 메인 화면 스캔 이력 카드 탐색 및 결과 이동 구현#26
kim-subsub merged 7 commits into
developfrom
feat/25

Conversation

@Ahreum02

@Ahreum02 Ahreum02 commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

Summary

메인 화면 스캔 이력 카드 탐색 및 결과 이동 구현

  • 새로운 기능

    • 스캔 기록 탐색 기능 추가: 최근 스캔 항목에서 이전/다음 버튼으로 스캔 기록 탐색 가능
    • 상태별 결과 페이지 이동: 스캔 결과 상태(안전/경고/위험)에 따라 해당 결과 페이지로 직접 이동
  • UI/UX 개선

    • 상호작용 가능한 UI 요소에 호버 및 포커스 시각 피드백 추가
    • 사용자 지시사항 텍스트 표현 개선

Task

  • QRScanPage 내 이력 카드 좌우 이동 버튼 추가 및 상세 페이지 연동
  • QRScanPage와 ScanListPage 데이터 연동 및 페이지 이동 구현
  • 스캔 이력 아이템 클릭 시 상태별 결과 화면(Safe/Warning/Critical) 연동

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 최근 스캔 기록에 이전/다음 네비게이션 버튼 추가
    • 스캔 항목 클릭 시 상태(safe/warning/critical)에 따라 결과 페이지로 이동
  • 개선 사항

    • 최근 스캔 카드 상호작용성·레이아웃 개선 및 키보드 포커스 지원
    • 최근 항목에 스캔 시간·URL·상태 레이블 명확히 표시, 빈 상태 UI 추가
    • UI 문구 및 스캔 목록 링크 경로 업데이트
  • Chores

    • 개발 도구 버전 업데이트 및 테마 색상 정리

@vercel

vercel Bot commented Apr 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
veri-q Ready Ready Preview, Comment Apr 10, 2026 1:06am

@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@Ahreum02 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 33 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 9 minutes and 33 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dd050770-1041-4b85-a2e1-83af61ed4a8e

📥 Commits

Reviewing files that changed from the base of the PR and between 48ac171 and ce38671.

📒 Files selected for processing (1)
  • src/pages/QRScan/styles/qrScanPage.css.ts

Walkthrough

최근 스캔 항목 탐색 UI/로직과 스타일이 추가되었습니다. 스캔 히스토리를 훅으로 로드·관리하며 이전/다음 순환 네비게이션을 제공하고, 항목 클릭 시 상태별(/result/safe|warning|critical)로 라우팅합니다. 스캔 리스트 항목은 결과 페이지 링크로 변경되었습니다.

Changes

Cohort / File(s) Summary
QR 스캔 페이지 UI/로직
src/pages/QRScan/QRScanPage.tsx
최근 스캔을 recentScanItem 기반으로 렌더링하도록 변경, 빈 상태 UI 추가, 상태별 네비게이션(useNavigate) 도입, 카드 상호작용을 버튼 기반으로 변경하고 이전/다음 화살표 버튼 추가. 일부 텍스트/링크 문구 수정(/scan-history/scan-list).
QR 스캔 페이지 훅
src/pages/QRScan/hooks/useQRScanPage.ts
스캔 히스토리 초기값 로드(getInitialScanListPageData), 비동기 페치(fetchScanListPageData), currentHistoryIndex 관리 및 순환형 handleShowPreviousHistoryItem/handleShowNextHistoryItem 추가. 반환 타입에 recentScanItem, canNavigateHistory, 네비게이션 핸들러 포함.
QR 스캔 페이지 스타일
src/pages/QRScan/styles/qrScanPage.css.ts
히스토리 카드 레이아웃을 3열 그리드로 변경, 인터랙티브/네비게이션 버튼 스타일(historyCardInteractive, historyOpenButton, historyNavButton*, historyNavIcon, historyContent) 및 상태별 톤(historyBadgeTone, historyStatusTone) 추가. 헤드라인 트렁케이션 개선 및 패딩/간격 조정.
스캔 목록 페이지 및 스타일
src/pages/ScanList/ScanListPage.tsx, src/pages/ScanList/styles/scanListPage.css.ts
각 리스트 항목을 클릭 가능한 <Link>로 변경하여 상태별 결과 경로로 이동하도록 함. 카드 스타일을 인터랙티브(포인터, 호버 트랜스폼, :focus-visible 아웃라인, transition)하게 업데이트.
공유 구성요소 스타일
src/shared/component/safeSiteCard/safeSiteCard.css.ts
officialTone.warning의 텍스트 색상 상수를 테마 변수(var.colors.warning)로 교체.
툴링 버전
package.json
개발 의존성 vite 버전 업그레이드(^7.3.1^7.3.2).

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant QRScanPage as QRScanPage
    participant Hook as useQRScanPage
    participant Router as Router
    participant Result as ResultPage

    User->>QRScanPage: 페이지 진입
    QRScanPage->>Hook: 훅 초기화/데이터 요청
    Hook->>Hook: getInitialScanListPageData (동기 초기값)
    Hook->>Hook: fetchScanListPageData (비동기 최신화)
    Hook-->>QRScanPage: recentScanItem 및 canNavigateHistory 반환

    User->>QRScanPage: 이전/다음 버튼 클릭
    QRScanPage->>Hook: handleShowPreviousHistoryItem / handleShowNextHistoryItem
    Hook->>Hook: currentHistoryIndex 업데이트
    Hook-->>QRScanPage: 업데이트된 recentScanItem

    User->>QRScanPage: 최근 항목 클릭
    QRScanPage->>Router: navigate('/result/{status}')
    Router->>Result: 결과 페이지 로드
    Result-->>User: 결과 표시
Loading
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 PR의 주요 변경사항을 명확하게 설명합니다. 메인 화면의 스캔 이력 카드 탐색 기능과 결과 페이지 이동 구현이라는 핵심 내용이 잘 반영되어 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

@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: 1

🧹 Nitpick comments (2)
src/pages/ScanList/ScanListPage.tsx (1)

11-18: resultRouteByStatus 매핑이 QRScanPage.tsx와 중복됩니다.

src/pages/QRScan/QRScanPage.tsx의 82-89 라인에 동일한 매핑이 존재합니다. 공유 유틸리티나 상수 파일로 추출하여 중복을 제거하고 유지보수성을 높이는 것을 권장합니다.

♻️ 공유 상수로 추출 제안

src/shared/constants/routes.ts 파일을 생성하여 공통 매핑을 관리할 수 있습니다:

import type { ScanListStatus } from '@/pages/ScanList/types/scanListPage.types';

export const resultRouteByStatus: Record<
  ScanListStatus,
  '/result/safe' | '/result/warning' | '/result/critical'
> = {
  safe: '/result/safe',
  warning: '/result/warning',
  critical: '/result/critical',
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/ScanList/ScanListPage.tsx` around lines 11 - 18, Extract the
duplicate resultRouteByStatus mapping into a shared constant and import it from
both ScanListPage and QRScanPage; create a new constant (e.g.,
resultRouteByStatus) in a shared module (suggested name:
src/shared/constants/routes.ts) typed with ScanListStatus and the union
'/result/safe'|' /result/warning'|' /result/critical', then replace the local
definitions in ScanListPage (resultRouteByStatus) and in QRScanPage with imports
from the new module so both components reference the single shared mapping.
src/pages/QRScan/QRScanPage.tsx (1)

91-95: statusLabelByTone 매핑도 ScanListPage.tsx와 중복됩니다.

ScanListPage.tsx의 20-24 라인에 동일한 매핑이 존재합니다. resultRouteByStatus와 함께 공유 상수로 추출하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/QRScan/QRScanPage.tsx` around lines 91 - 95, Duplicate mapping
statusLabelByTone (and resultRouteByStatus) appears in QRScanPage.tsx and
ScanListPage.tsx; extract these shared constants into a single exported module
(e.g., create a new constants file) and replace local definitions by importing
the shared constants. Update references to the exported symbol names
(statusLabelByTone and resultRouteByStatus) in QRScanPage.tsx and
ScanListPage.tsx so both files import the same source of truth, and ensure the
new module exports the same types (Record<ScanListStatus, string>) so TypeScript
types continue to work.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/QRScan/QRScanPage.tsx`:
- Around line 255-296: The article currently uses role="button" and contains
real <button> controls (the nav buttons), causing nested interactive controls
and an accessibility issue; fix by removing the button role/tabIndex/onKeyDown
from the article and instead create a single dedicated interactive element for
opening the recent scan (e.g., an internal focusable element that calls
handleOpenRecentScanResult and uses the accessible label from
statusLabelByTone[recentScanItem.status]) while leaving the previous/next
controls (handleShowPreviousHistoryItem, historyNavButton classes,
HistoryPrevIcon) as plain buttons outside that interactive element or visually
separate them from the clickable card area so buttons are not nested inside a
role="button" container.

---

Nitpick comments:
In `@src/pages/QRScan/QRScanPage.tsx`:
- Around line 91-95: Duplicate mapping statusLabelByTone (and
resultRouteByStatus) appears in QRScanPage.tsx and ScanListPage.tsx; extract
these shared constants into a single exported module (e.g., create a new
constants file) and replace local definitions by importing the shared constants.
Update references to the exported symbol names (statusLabelByTone and
resultRouteByStatus) in QRScanPage.tsx and ScanListPage.tsx so both files import
the same source of truth, and ensure the new module exports the same types
(Record<ScanListStatus, string>) so TypeScript types continue to work.

In `@src/pages/ScanList/ScanListPage.tsx`:
- Around line 11-18: Extract the duplicate resultRouteByStatus mapping into a
shared constant and import it from both ScanListPage and QRScanPage; create a
new constant (e.g., resultRouteByStatus) in a shared module (suggested name:
src/shared/constants/routes.ts) typed with ScanListStatus and the union
'/result/safe'|' /result/warning'|' /result/critical', then replace the local
definitions in ScanListPage (resultRouteByStatus) and in QRScanPage with imports
from the new module so both components reference the single shared mapping.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b6fc135e-3426-438f-b089-61cecec268c3

📥 Commits

Reviewing files that changed from the base of the PR and between 2dccf60 and 5d97f14.

📒 Files selected for processing (5)
  • src/pages/QRScan/QRScanPage.tsx
  • src/pages/QRScan/hooks/useQRScanPage.ts
  • src/pages/QRScan/styles/qrScanPage.css.ts
  • src/pages/ScanList/ScanListPage.tsx
  • src/pages/ScanList/styles/scanListPage.css.ts

Comment thread src/pages/QRScan/QRScanPage.tsx Outdated
@kim-subsub
kim-subsub self-requested a review April 10, 2026 00:42
@kim-subsub kim-subsub added the documentation Improvements or additions to documentation label Apr 10, 2026

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/QRScan/QRScanPage.tsx`:
- Around line 269-273: The current button uses aria-label which overrides the
visible card text (recentScanItem details) and hides it from assistive tech;
update the button (the element with classNames
styles.historyOpenButton/styles.historyCardInteractive and onClick handler
handleOpenRecentScanResult) by removing the aria-label and either leaving the
visible content as the accessible name or replace aria-label with
aria-labelledby/aria-describedby that references the card text nodes (e.g., IDs
for the scan time/URL/status rendered from recentScanItem and the
statusLabelByTone mapping) so screen readers announce the card content plus a
short auxiliary “결과 페이지로 이동” hint.

In `@src/pages/QRScan/styles/qrScanPage.css.ts`:
- Around line 415-418: The center column and the historyHeadline text can
overflow when long URLs are rendered; update the grid/element styles for the
middle column and the historyHeadline container (the rule that uses
gridTemplateColumns: '40px minmax(0, 1fr) 40px' and the other similar block at
the second occurrence) to allow shrinking and text clipping: ensure the middle
column has min-width: 0 (or use minmax(0, 1fr)) and add overflow: hidden,
text-overflow: ellipsis and white-space: nowrap to the historyHeadline element
so long URLs are truncated instead of overflowing or overlapping the navigation
buttons; apply the same changes to the second occurrence (lines ~499-506) as
well.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: be3875e8-f96d-4106-9515-bbbdc30a5634

📥 Commits

Reviewing files that changed from the base of the PR and between 5d97f14 and badf22a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • package.json
  • src/pages/QRScan/QRScanPage.tsx
  • src/pages/QRScan/styles/qrScanPage.css.ts
  • src/shared/component/safeSiteCard/safeSiteCard.css.ts
✅ Files skipped from review due to trivial changes (2)
  • package.json
  • src/shared/component/safeSiteCard/safeSiteCard.css.ts

Comment on lines +269 to +273
<button
aria-label={`${statusLabelByTone[recentScanItem.status]} 결과 페이지로 이동`}
className={`${styles.historyOpenButton} ${styles.historyCardInteractive}`}
onClick={handleOpenRecentScanResult}
type="button"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

aria-label 때문에 카드 본문 정보가 보조기기에서 사라질 수 있습니다.

Line 270의 aria-label이 버튼 안의 가시 텍스트(스캔 시각, URL, 상태 설명)를 accessible name으로 덮어써서, 스크린리더 사용자는 어떤 기록을 여는지 알기 어렵습니다. 이 버튼은 aria-label을 제거해 본문을 그대로 읽히게 하거나, aria-labelledby/aria-describedby로 “결과 페이지로 이동”만 보조 설명으로 붙이는 편이 안전합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/QRScan/QRScanPage.tsx` around lines 269 - 273, The current button
uses aria-label which overrides the visible card text (recentScanItem details)
and hides it from assistive tech; update the button (the element with classNames
styles.historyOpenButton/styles.historyCardInteractive and onClick handler
handleOpenRecentScanResult) by removing the aria-label and either leaving the
visible content as the accessible name or replace aria-label with
aria-labelledby/aria-describedby that references the card text nodes (e.g., IDs
for the scan time/URL/status rendered from recentScanItem and the
statusLabelByTone mapping) so screen readers announce the card content plus a
short auxiliary “결과 페이지로 이동” hint.

Comment thread src/pages/QRScan/styles/qrScanPage.css.ts

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/QRScan/styles/qrScanPage.css.ts`:
- Around line 499-506: The right padding in the historyContent style
(paddingRight: '70px') is smaller than the badge minWidth ('86px'), which can
let text overlap the absolutely positioned badge; update historyContent to use a
right inset at least equal to the badge width (e.g., paddingRight: '86px' or
preferably a shared constant/vars like vars.badgeWidth) and apply the same fix
to the other similar style blocks around lines 509-514 so all insets are >= the
badge minWidth used in QRScanPage badge layout.
- Around line 464-480: The disabled state currently still shows hover colors
because &:hover and &:disabled can both match; update the disabled selector (the
object containing '&:disabled') to explicitly reset visual styles by either
adding backgroundColor and color (e.g., backgroundColor: vars.colors.disabledBg,
color: vars.colors.disabledText) or combine selectors as '&:disabled,
&:disabled:hover' and set opacity/cursor/backgroundColor/color/transform so the
disabled button cannot appear hover-active; modify the selectors around
'&:hover' and '&:disabled' in the same style block to ensure disabled styles
take precedence.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 36e29d66-997a-474a-b4ad-e49d9a3a97f0

📥 Commits

Reviewing files that changed from the base of the PR and between badf22a and 48ac171.

📒 Files selected for processing (1)
  • src/pages/QRScan/styles/qrScanPage.css.ts

Comment thread src/pages/QRScan/styles/qrScanPage.css.ts
Comment thread src/pages/QRScan/styles/qrScanPage.css.ts Outdated

@kim-subsub kim-subsub left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

수고하셨습니다.

@kim-subsub
kim-subsub merged commit f46d472 into develop Apr 10, 2026
8 checks passed
@kim-subsub
kim-subsub deleted the feat/25 branch April 10, 2026 01:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants