feat(web): integrate consent flow, Faro gating, TSI gating, and privacy link

This commit is contained in:
Antoni Nuñez Romeu
2026-08-26 15:19:24 +02:00
parent 66055a5e19
commit 1f918be99d
5 changed files with 81 additions and 5 deletions
+62
View File
@@ -12,7 +12,11 @@ import ForgotPasswordModal from './components/ForgotPasswordModal';
import ResetPasswordView from './views/ResetPasswordView';
import SavedNotifications from './components/SavedNotifications';
import BottomNav from './components/BottomNav';
import CookieBanner from './components/CookieBanner';
import HealthConsentModal from './components/HealthConsentModal';
import PrivacyView from './views/PrivacyView';
import { getFaro } from './utils/faro';
import { hasConsentChoice, getLocalConsents, saveConsents, fetchServerConsents } from './utils/consent';
function App() {
const [screen, setScreen] = useState('home');
@@ -26,6 +30,10 @@ function App() {
const [badgeCount, setBadgeCount] = useState(0);
const [prescriptionSearch, setPrescriptionSearch] = useState('');
const [productScreen, setProductScreen] = useState(null);
const [showCookieBanner, setShowCookieBanner] = useState(!hasConsentChoice());
const [showHealthConsent, setShowHealthConsent] = useState(false);
const [pendingTsiScan, setPendingTsiScan] = useState(null);
const [consents, setConsents] = useState(getLocalConsents);
const [screenSize, setScreenSize] = useState({
width: window.innerWidth,
height: window.innerHeight
@@ -109,6 +117,14 @@ function App() {
return () => { cancelled = true; };
}, [currentUser]);
useEffect(() => {
if (currentUser) {
fetchServerConsents().then(serverConsents => {
if (serverConsents) setConsents(serverConsents);
});
}
}, [currentUser]);
function refreshBadgeCount() {
if (!currentUser) return;
fetch('/api/notifications/mine', { credentials: 'include' })
@@ -150,6 +166,36 @@ function App() {
window.history.replaceState({}, '', '/');
}
async function handleCookieConsent(newConsents) {
const saved = await saveConsents(newConsents);
setConsents(saved);
setShowCookieBanner(false);
}
function handleTsiScanRequest(scanFn) {
if (consents.health_data) {
scanFn();
} else {
setPendingTsiScan(() => scanFn);
setShowHealthConsent(true);
}
}
function handleHealthConsentAccept() {
saveConsents({ ...consents, health_data: true });
setConsents(prev => ({ ...prev, health_data: true }));
setShowHealthConsent(false);
if (pendingTsiScan) {
pendingTsiScan();
setPendingTsiScan(null);
}
}
function handleHealthConsentCancel() {
setShowHealthConsent(false);
setPendingTsiScan(null);
}
function handleAdminClick() {
setScreen('admin');
}
@@ -170,6 +216,7 @@ function App() {
else setShowLogin(true);
return;
}
if (tab === 'privacy') { setScreen('privacy'); return; }
}
let activeView;
@@ -232,6 +279,8 @@ function App() {
setPrescriptionSearch(name);
setScreen('search');
}}
onTsiScanRequest={handleTsiScanRequest}
consents={consents}
/>
);
break;
@@ -246,6 +295,9 @@ function App() {
case 'admin':
activeView = <AdminView />;
break;
case 'privacy':
activeView = <PrivacyView onBack={() => setScreen('home')} />;
break;
default:
activeView = (
<HomeView
@@ -293,6 +345,16 @@ function App() {
{showSaved && currentUser && (
<SavedNotifications onClose={() => setShowSaved(false)} onNotificationChange={refreshBadgeCount} />
)}
{showCookieBanner && (
<CookieBanner
onConsent={handleCookieConsent}
onPrivacyClick={() => { setShowCookieBanner(false); setScreen('privacy'); }}
/>
)}
{showHealthConsent && (
<HealthConsentModal onAccept={handleHealthConsentAccept} onCancel={handleHealthConsentCancel} />
)}
</div>
);
}