Skip to content

feat(frontend): mobile UX elite polish — 15 recommendations#952

Merged
ericsocrat merged 1 commit intomainfrom
feat/mobile-ux-elite-polish
Mar 18, 2026
Merged

feat(frontend): mobile UX elite polish — 15 recommendations#952
ericsocrat merged 1 commit intomainfrom
feat/mobile-ux-elite-polish

Conversation

@ericsocrat
Copy link
Owner

Summary

Implements all 15 mobile UX recommendations from the comprehensive mobile audit (score 8.3/10, 31 findings analyzed).

Changes (R1–R15)

# Recommendation Files
R1 Grouped scan history by date with count badges history/page.tsx
R2 FadeSlideIn transition on scan result cards ScanResultView.tsx
R3 Primary CTA button on not-found view ScanResultView.tsx
R4 Torch/flashlight toggle for barcode scanner scan/page.tsx
R5 Scanning tips accordion below viewfinder scan/page.tsx
R6 CategoryPicker pills replacing native select CategoryPicker.tsx, submit/page.tsx
R7 Relative time formatting (just now, Xm ago) format-time.ts, history/page.tsx
R8 Score count-up animation with bounceIn badge ScanResultView.tsx, globals.css
R9 Lock icon on EAN field (read-only indicator) submit/page.tsx
R10 Empty-state illustration for submissions page submissions/page.tsx
R11 Submit button loading/success/error states submit/page.tsx
R12 Desktop-only breadcrumbs on all scan subpages 4 page files
R13 Stagger animation on list items history/page.tsx, submissions/page.tsx
R14 Viewfinder overlay with rounded corners scan/page.tsx
R15 Pull-to-refresh glow effect and scale snap PullToRefresh.tsx

New Files

  • frontend/src/components/scan/CategoryPicker.tsx — mobile-friendly category selector (button pills with aria-pressed)
  • frontend/src/components/scan/CategoryPicker.test.tsx — 7 test cases
  • frontend/src/lib/format-time.ts — relative time formatting utility
  • frontend/src/lib/format-time.test.ts — 11 test cases

Testing

  • i18n keys added to en/de/pl.json (manualTipsTitle, manualTip1-3)
  • useReducedMotion mocked in animation tests (rAF + performance.now doesn't advance in jsdom)
  • 17 files changed, +690 / -270 lines

Verification

npx tsc --noEmit              → 0 errors
npx vitest run                → 351 passed | 0 failed | 5822 tests

R1: Grouped scan history by date with count badges
R2: FadeSlideIn transition on scan result cards
R3: Primary CTA button on not-found view
R4: Torch/flashlight toggle for barcode scanner
R5: Scanning tips accordion below viewfinder
R6: CategoryPicker pills replacing native select
R7: Relative time formatting (just now, Xm ago, Xh ago)
R8: Score count-up animation with bounceIn badge
R9: Lock icon on EAN field (read-only indicator)
R10: Empty-state illustration for submissions page
R11: Submit button loading/success/error states
R12: Desktop-only breadcrumbs on all scan subpages
R13: Stagger animation on list items (history, submissions)
R14: Viewfinder overlay with rounded corners
R15: Pull-to-refresh glow effect and scale snap

- 4 new files: CategoryPicker, format-time utility + tests
- i18n keys added to en/de/pl
- useReducedMotion mock for animation tests in jsdom
- All 5822 tests passing, 0 TS errors
Copilot AI review requested due to automatic review settings March 18, 2026 17:02
@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@vercel
Copy link

vercel bot commented Mar 18, 2026

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

Project Deployment Actions Updated (UTC)
tryvit Ready Ready Preview, Comment Mar 18, 2026 5:04pm

@github-actions
Copy link

Bundle Size Report

Metric Value
Main baseline 0 KB
This PR 0 KB
Delta +0 KB (+0%)
JS chunks 0
Hard limit 4000 KB

✅ Bundle size is within acceptable limits.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements a set of mobile UX improvements across the scan flow (scanner, results, history/submissions, and submit form), adding animations, better touch-first controls, and a new relative-time utility.

Changes:

  • Adds new UI components/UX affordances (CategoryPicker pills, empty-state illustration usage, desktop-only breadcrumbs + mobile back buttons).
  • Introduces/extends motion effects (FadeSlideIn wrappers, staggered list entrance, score count-up + bounce-in).
  • Adds utilities and copy for relative time formatting and manual-entry tips (with tests and new i18n strings).

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
frontend/src/styles/globals.css Reformat motion tokens and add @keyframes bounceIn for scan celebration.
frontend/src/lib/format-time.ts Adds formatRelativeTime() helper for scan history timestamps.
frontend/src/lib/format-time.test.ts Unit tests for the new relative time formatter.
frontend/src/components/scan/ScanResultView.tsx Adds FadeSlideIn transitions and TryVit score count-up + bounce animation.
frontend/src/components/scan/ScanResultView.test.tsx Updates tests to accommodate animated score display and reduced-motion behavior.
frontend/src/components/scan/CategoryPicker.tsx New pill-based category selector component.
frontend/src/components/scan/CategoryPicker.test.tsx Tests for CategoryPicker selection/toggling and aria-pressed behavior.
frontend/src/components/common/PullToRefresh.tsx Adds triggered/refreshing “glow + scale snap” styling.
frontend/src/app/app/scan/submit/page.tsx Uses CategoryPicker, adds EAN lock indicator, and submit button pending/success UI.
frontend/src/app/app/scan/submit/page.test.tsx Updates form tests to interact with CategoryPicker instead of <select>.
frontend/src/app/app/scan/submissions/page.tsx Adds empty-state illustration and staggered list entrance; adds mobile back button.
frontend/src/app/app/scan/page.tsx Adds torch pill in viewfinder, manual-entry tips, and mobile back button; adjusts viewfinder overlay.
frontend/src/app/app/scan/page.test.tsx Updates scan page test to wait for animated score value.
frontend/src/app/app/scan/history/page.tsx Adds grouping/count badges and relative timestamps; adds staggered entrance + mobile back button.
frontend/messages/en.json Adds scan manual-entry tips strings.
frontend/messages/de.json Adds scan manual-entry tips strings.
frontend/messages/pl.json Adds scan manual-entry tips strings.

Comment on lines +19 to +23

if (diffSec < MINUTE) return "just now";
if (diffSec < HOUR) return `${Math.floor(diffSec / MINUTE)}m ago`;
if (diffSec < DAY) return `${Math.floor(diffSec / HOUR)}h ago`;
if (diffSec < DAY * 7) return `${Math.floor(diffSec / DAY)}d ago`;
Comment on lines +168 to +183
// ─── R1: Group consecutive duplicate EAN scans ──────────────────────────────

type GroupedScan = ScanHistoryItem & { count: number };

function groupScans(scans: ScanHistoryItem[]): GroupedScan[] {
const grouped: GroupedScan[] = [];
for (const scan of scans) {
const prev = grouped[grouped.length - 1];
if (prev && prev.ean === scan.ean) {
prev.count += 1;
} else {
grouped.push({ ...scan, count: 1 });
}
}
return grouped;
}
<Lock
size={14}
className="absolute right-3 top-1/2 -translate-y-1/2 text-foreground-muted"
aria-label={t("submit.eanLocked")}
Comment on lines 248 to +254
<label
htmlFor="category"
className="mb-1 block text-sm font-medium text-foreground-secondary"
>
{t("submit.categoryLabel")}{" "}
<span className="font-normal text-foreground-muted">{t("common.optional")}</span>
</label>
<select
id="category"
value={category}
onChange={(e) => setCategory(e.target.value)}
className="input-field"
>
<option value="">{t("submit.categoryPlaceholder")}</option>
{FOOD_CATEGORIES.map((cat) => (
<option key={cat.slug} value={cat.slug}>
{cat.emoji} {t(cat.labelKey)}
</option>
))}
</select>
<CategoryPicker value={category} onChange={setCategory} />
Comment on lines +13 to +19
}

export function CategoryPicker({ value, onChange }: CategoryPickerProps) {
const { t } = useTranslation();

return (
<div className="flex flex-wrap gap-2">
@ericsocrat ericsocrat merged commit b27b9d4 into main Mar 18, 2026
21 checks passed
@ericsocrat ericsocrat deleted the feat/mobile-ux-elite-polish branch March 18, 2026 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants