Mobile scanner redesign + backend live search

- Scanner page: fullscreen mobile-first layout, Scan/Search/Recent tabs
- Scan tab: auto-start camera, switch camera, vibration/sound feedback
- Valid/invalid fullscreen states, confirm check-in, auto-return to camera
- Search tab: live backend search (300ms debounce), tap card for detail + check-in
- Recent tab: last 20 check-ins, session counter
- Backend: GET /api/tickets/search (live search), GET /api/tickets/stats/checkin
- Admin layout: hide sidebar on scanner page; fix hooks order (no early return before useEffect)
- Back button to dashboard/events (staff → events, others → admin)
- API: searchLive, getCheckinStats, LiveSearchResult; PostgreSQL LOWER cast for UUID

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Michilis
2026-02-14 04:26:44 +00:00
parent b9f46b02cc
commit 62bf048680
8 changed files with 1125 additions and 459 deletions

View File

@@ -43,7 +43,7 @@ function MobileNavLink({ href, children, onClick }: { href: string; children: Re
export default function Header() {
const { t } = useLanguage();
const { user, isAdmin, logout } = useAuth();
const { user, hasAdminAccess, logout } = useAuth();
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const menuRef = useRef<HTMLDivElement>(null);
const touchStartX = useRef<number>(0);
@@ -148,7 +148,7 @@ export default function Header() {
{t('nav.dashboard')}
</Button>
</Link>
{isAdmin && (
{hasAdminAccess && (
<Link href="/admin">
<Button variant="ghost" size="sm">
{t('nav.admin')}
@@ -270,7 +270,7 @@ export default function Header() {
{t('nav.dashboard')}
</Button>
</Link>
{isAdmin && (
{hasAdminAccess && (
<Link href="/admin" onClick={closeMenu}>
<Button variant="outline" className="w-full justify-center">
{t('nav.admin')}