From 69ce4583081d35a7c88ac9db0f2b1421adf0e4d2 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Sat, 28 Feb 2026 16:37:33 +0000 Subject: [PATCH] feat: add dev auth bypass for UI testing without backend Guarded by VITE_DEV_BYPASS_AUTH env var + import.meta.env.DEV check. Vite tree-shakes the DEV branch in production builds. The .env.development.local file is gitignored (**.env pattern). Includes mock listing data to preview property cards without API. --- frontend/src/App.tsx | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 527d6ba..1568282 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -38,9 +38,44 @@ import { ListingDetailSheet } from './components/ListingDetailSheet'; import { FilterPanel } from './components/FilterPanel'; function AppContent() { - const [listingData, setListingData] = useState(null); - const [user, setUser] = useState(null); - const [queryParameters, setQueryParameters] = useState(null); + const DEV_BYPASS_AUTH = import.meta.env.DEV && import.meta.env.VITE_DEV_BYPASS_AUTH === 'true'; + + const [listingData, setListingData] = useState( + DEV_BYPASS_AUTH + ? { + type: 'FeatureCollection', + features: Array.from({ length: 12 }, (_, i): PropertyFeature => ({ + type: 'Feature', + geometry: { type: 'Point', coordinates: [-0.08 + (i % 4) * 0.03, 51.50 + Math.floor(i / 4) * 0.02] }, + properties: { + id: 100000000 + i, + url: `https://www.rightmove.co.uk/properties/${100000000 + i}`, + city: ['Shoreditch', 'Hackney', 'Islington', 'Camden', 'Dalston', 'Bethnal Green', 'Mile End', 'Bow', 'Stratford', 'Whitechapel', 'Bermondsey', 'Peckham'][i], + country: 'United Kingdom', + qm: 40 + i * 8, + qmprice: Math.round((1800 + i * 200) / (40 + i * 8)), + total_price: 1800 + i * 200, + rooms: 1 + (i % 4), + agency: ['Foxtons', 'Savills', 'KFH', 'Dexters'][i % 4], + available_from: new Date(Date.now() + i * 7 * 86400000).toISOString(), + last_seen: new Date(Date.now() - i * 2 * 86400000).toISOString(), + photo_thumbnail: `https://picsum.photos/seed/prop${i}/400/300`, + photos: [`https://picsum.photos/seed/prop${i}a/800/600`, `https://picsum.photos/seed/prop${i}b/800/600`, `https://picsum.photos/seed/prop${i}c/800/600`], + price_history: [{ id: i, price: 1800 + i * 200, last_seen: new Date().toISOString() }], + listing_type: 'RENT', + }, + })), + } + : null + ); + const [user, setUser] = useState( + DEV_BYPASS_AUTH + ? { sub: 'dev-user', email: 'dev@localhost', name: 'Dev User', accessToken: 'dev-token', provider: 'passkey' as const } + : null + ); + const [queryParameters, setQueryParameters] = useState( + DEV_BYPASS_AUTH ? { ...DEFAULT_FILTER_VALUES, available_from: new Date() } : null + ); const [submitError, setSubmitError] = useState(null); const [alertDialogIsOpen, setAlertDialogIsOpen] = useState(false); const [isLoading, setIsLoading] = useState(false); @@ -311,7 +346,7 @@ function AppContent() { // Auto-load data with default filters when user is authenticated useEffect(() => { - if (!user || initialLoadTriggeredRef.current) { + if (!user || initialLoadTriggeredRef.current || DEV_BYPASS_AUTH) { return; } initialLoadTriggeredRef.current = true;