From c91c4016ec5287408b877c0ebe33b2aa7efde962 Mon Sep 17 00:00:00 2001 From: EmanueleAlfano Date: Sat, 28 Feb 2026 09:52:53 +0100 Subject: [PATCH] feat: add fullscreen toggle button and improve UI consistency across components --- ai-prompts/00-welcome-agent.md | 7 -- dev.sh | 13 +++ frontend/package.json | 1 + frontend/src/components/FullscreenButton.tsx | 52 ++++++++++ frontend/src/components/UserCard.tsx | 20 ++-- frontend/src/components/index.ts | 1 + frontend/src/screens/ActiveGateScreen.tsx | 97 ++++++++++--------- frontend/src/screens/LoadingScreen.tsx | 22 ++--- frontend/src/screens/ValidatorLoginScreen.tsx | 55 ++++++----- 9 files changed, 166 insertions(+), 102 deletions(-) create mode 100644 frontend/src/components/FullscreenButton.tsx diff --git a/ai-prompts/00-welcome-agent.md b/ai-prompts/00-welcome-agent.md index e3ce3eb..659a5ca 100644 --- a/ai-prompts/00-welcome-agent.md +++ b/ai-prompts/00-welcome-agent.md @@ -149,10 +149,3 @@ VotoFocolari/ 6. **Success Modal Interrompibile**: Se durante il carosello di benvenuto si passa un nuovo badge, la modal si chiude e viene caricato subito il nuovo utente. - ---- - -## TODO (da concordare con committenti) - -- [ ] Verificare se il badge validatore debba essere validato anche lato server -- [ ] Test automatici E2E per regression detection diff --git a/dev.sh b/dev.sh index f3a9abf..b92f83d 100755 --- a/dev.sh +++ b/dev.sh @@ -346,6 +346,15 @@ cmd_test_e2e_ui() { npm run test:e2e:ui } +# Type-check frontend (senza build) +cmd_check() { + check_prereqs + info "Type-check frontend (tsc --noEmit)..." + cd "$FRONTEND_DIR" + npm run check + success "Type-check completato senza errori!" +} + # Help cmd_help() { echo "============================================" @@ -359,6 +368,7 @@ cmd_help() { echo " dev Avvia frontend (dev) + backend (api-only) in parallelo" echo " build Builda il frontend per produzione" echo " build:debug Builda il frontend in modalità DEBUG (no minify, sourcemap)" + echo " check Type-check TypeScript (senza build)" echo " server Builda frontend (se cambiato) e avvia server completo" echo " server:debug Builda DEBUG + avvia server (per debug con Chrome DevTools)" echo " backend Avvia solo il backend (api-only)" @@ -401,6 +411,9 @@ case "${1:-help}" in "build:debug") cmd_build_debug ;; + check) + cmd_check + ;; server) shift cmd_server "$@" diff --git a/frontend/package.json b/frontend/package.json index 11a731c..c4ec9b0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,6 +6,7 @@ "scripts": { "dev": "vite", "build": "tsc -b && vite build", + "check": "tsc --noEmit", "lint": "eslint .", "preview": "vite preview", "test": "vitest", diff --git a/frontend/src/components/FullscreenButton.tsx b/frontend/src/components/FullscreenButton.tsx new file mode 100644 index 0000000..65c2bd1 --- /dev/null +++ b/frontend/src/components/FullscreenButton.tsx @@ -0,0 +1,52 @@ +/** + * Fullscreen Toggle Button - Focolari Voting System + */ + +import {useCallback, useEffect, useState} from 'react'; + +export function FullscreenButton() { + const [isFullscreen, setIsFullscreen] = useState(false); + + useEffect(() => { + const handleChange = () => { + setIsFullscreen(!!document.fullscreenElement); + }; + document.addEventListener('fullscreenchange', handleChange); + return () => document.removeEventListener('fullscreenchange', handleChange); + }, []); + + const toggleFullscreen = useCallback(() => { + if (!document.fullscreenElement) { + document.documentElement.requestFullscreen().catch((err) => { + console.warn('[UI] Fullscreen non disponibile:', err); + }); + } else { + document.exitFullscreen(); + } + }, []); + + return ( + + ); +} + +export default FullscreenButton; + diff --git a/frontend/src/components/UserCard.tsx b/frontend/src/components/UserCard.tsx index c8580cc..b94e390 100644 --- a/frontend/src/components/UserCard.tsx +++ b/frontend/src/components/UserCard.tsx @@ -47,13 +47,13 @@ export function UserCard({user, size = 'full'}: UserCardProps) { } return ( -
+
{/* Foto e Dati Principali */} -
+
{`${user.nome} { (e.target as HTMLImageElement).src = 'https://via.placeholder.com/200?text=' + user.nome.charAt(0); @@ -61,16 +61,16 @@ export function UserCard({user, size = 'full'}: UserCardProps) { />
-

+

{user.nome} {user.cognome}

-
- +
+ {user.ruolo} -
-

+

Badge: {user.badge_code}

@@ -87,8 +87,8 @@ export function UserCard({user, size = 'full'}: UserCardProps) { {/* Warning Box */} {user.warning && ( -
-

+

+

⚠️ {user.warning}

diff --git a/frontend/src/components/index.ts b/frontend/src/components/index.ts index 67eafa8..60c3823 100644 --- a/frontend/src/components/index.ts +++ b/frontend/src/components/index.ts @@ -8,3 +8,4 @@ export {Button} from './Button'; export {Input} from './Input'; export {WelcomeCarousel} from './WelcomeCarousel'; export {NumLockBanner} from './NumLockBanner'; +export {FullscreenButton} from './FullscreenButton'; diff --git a/frontend/src/screens/ActiveGateScreen.tsx b/frontend/src/screens/ActiveGateScreen.tsx index c3a5ba6..b4afbe0 100644 --- a/frontend/src/screens/ActiveGateScreen.tsx +++ b/frontend/src/screens/ActiveGateScreen.tsx @@ -3,7 +3,7 @@ * Schermata principale del varco attivo */ -import {Button, CountdownTimer, Logo, NumLockBanner, RFIDStatus, UserCard} from '../components'; +import {Button, CountdownTimer, FullscreenButton, Logo, NumLockBanner, RFIDStatus, UserCard} from '../components'; import type {RFIDScannerState, RoomInfo, User} from '../types'; // Timeout per badge non trovato (30 secondi) @@ -39,16 +39,17 @@ export function ActiveGateScreen({ showValidatorBadgeNotice = false, }: ActiveGateScreenProps) { return ( -
+
{/* Header */}
- -
+ className="p-3 flex items-center justify-between border-b bg-white/80 backdrop-blur shadow-sm"> + +
-

{roomInfo.room_name}

-

ID: {roomInfo.meeting_id}

+

{roomInfo.room_name}

+

ID: {roomInfo.meeting_id}

+ @@ -168,9 +169,9 @@ export function ActiveGateScreen({ ) : currentUser ? ( // User found - Decision screen
-
+
{/* Timer bar */} -
+
{/* Action Hint */} -
+
{currentUser.ammesso ? ( -
-

+

+

✓ Utente ammesso all'ingresso

-

+

Passa il badge VALIDATORE per confermare l'accesso

) : ( -
-

+

+

⚠️ ACCESSO NON CONSENTITO

-

+

Questo utente non è autorizzato ad entrare

@@ -208,7 +209,7 @@ export function ActiveGateScreen({
{/* Cancel Button */} -
+
)} {/* Footer with RFID Status */} -