'use client'; import { collection, getDocs, addDoc, deleteDoc, doc, updateDoc, writeBatch, } from 'firebase/firestore'; import { onAuthStateChanged, User } from 'firebase/auth'; import Link from 'next/link'; import React, { useEffect, useState, useRef } from 'react'; import { firebaseAuth, firestore } from '../lib/firebase-client'; import { WebTelemetryReplayModal } from './web-telemetry-replay-modal'; import { generateRideGpx, generateRideCsv, downloadFile, resolveRideTelemetryPoints, TelemetryPoint, } from '../lib/telemetry-export'; export type Motorcycle = { id: string; nickname: string; makeName: string; modelName: string; variantName: string; year: number; description: string; isDefault: boolean; imageUrl?: string; vin?: string; }; export type Ride = { id: string; startedAt: Date | null; endedAt: Date | null; distanceMiles: number; topSpeedMph: number; averageSpeed: number; maxLeanLeft: number; maxLeanRight: number; maxAccelG: number; maxBrakingG: number; movingTime: number; // in seconds elevationGain: number; qualityScore: number; motorcycle: string; startLat?: number; startLon?: number; endLat?: number; endLon?: number; points?: TelemetryPoint[]; gpxContent?: string; csvContent?: string; telemetryBundlePath?: string; }; function text(value: unknown): string { return typeof value === 'string' ? value.trim() : ''; } function number(value: unknown): number { return typeof value === 'number' && Number.isFinite(value) ? value : 0; } function formatDuration(seconds: number): string { if (!seconds || seconds <= 0) return '0m'; const mins = Math.floor(seconds / 60); const hrs = Math.floor(mins / 60); const remainingMins = mins % 60; if (hrs > 0) { return `${hrs}h ${remainingMins}m`; } return `${mins}m`; } // Sleek high-tech stock sportbike vector illustration function StockMotorcycleGraphic({ className = 'w-full h-40' }: { className?: string }) { return (
{/* Background technical grid */}
{/* Front Wheel */} {/* Rear Wheel */} {/* Swingarm */} {/* Frame & Engine Block */} {/* Exhaust Pipe */} {/* Front Fork */} {/* Fuel Tank & Tail */} {/* Aerodynamic Fairing & Windscreen */} {/* Rider Seat */} {/* Gradients */} Stock Spec Render
); } interface AppCloudDataProps { syncTrigger?: number; onSyncStateChange?: (syncing: boolean) => void; onMetricsLoaded?: (metrics: { totalMiles: number; rideCount: number; peakLean: number }) => void; } export function AppCloudData({ syncTrigger = 0, onSyncStateChange, onMetricsLoaded }: AppCloudDataProps) { const [motorcycles, setMotorcycles] = useState([]); const [rides, setRides] = useState([]); const [state, setState] = useState('Loading telemetry cloud data...'); const [user, setUser] = useState(null); // Modal / Add Motorcycle Form State const [showAddModal, setShowAddModal] = useState(false); const [newYear, setNewYear] = useState(new Date().getFullYear().toString()); const [newMake, setNewMake] = useState('Yamaha'); const [newModel, setNewModel] = useState(''); const [newVariant, setNewVariant] = useState('Standard'); const [newNickname, setNewNickname] = useState(''); const [newVin, setNewVin] = useState(''); const [newIsDefault, setNewIsDefault] = useState(false); const [newImagePreview, setNewImagePreview] = useState(null); const [formBusy, setFormBusy] = useState(false); const [formError, setFormError] = useState(''); // Image Upload Target State const [uploadingMotorcycleId, setUploadingMotorcycleId] = useState(null); const fileInputRef = useRef(null); // Expandable Ride Detail state const [expandedRideId, setExpandedRideId] = useState(null); // Pagination for Recent Telemetry Sessions const [visibleRideCount, setVisibleRideCount] = useState(10); // Replay Modal & Export State const [replayRide, setReplayRide] = useState(null); const [exportNotice, setExportNotice] = useState(null); useEffect(() => { if (typeof window !== 'undefined') { (window as any).openReplayModalForTest = (r?: Partial) => { setReplayRide({ id: r?.id || 'ride_3_20260831_141255', startedAt: r?.startedAt || new Date('2026-08-28T23:50:03.000Z'), endedAt: r?.endedAt || new Date('2026-08-29T00:09:05.000Z'), distanceMiles: r?.distanceMiles || 14.2, topSpeedMph: r?.topSpeedMph || 68.5, averageSpeed: r?.averageSpeed || 44.2, maxLeanLeft: r?.maxLeanLeft || 38.5, maxLeanRight: r?.maxLeanRight || 41.2, maxAccelG: r?.maxAccelG || 0.65, maxBrakingG: r?.maxBrakingG || 0.78, movingTime: r?.movingTime || 1142, elevationGain: r?.elevationGain || 420, qualityScore: r?.qualityScore || 96, motorcycle: r?.motorcycle || '2024 Yamaha YZF-R7', startLat: r?.startLat ?? (r?.points?.[0]?.latitude ?? 34.0400856), startLon: r?.startLon ?? (r?.points?.[0]?.longitude ?? -85.2399786), endLat: r?.endLat ?? (r?.points?.[r.points.length - 1]?.latitude ?? 34.2435959), endLon: r?.endLon ?? (r?.points?.[r.points.length - 1]?.longitude ?? -85.1615908), points: r?.points, gpxContent: r?.gpxContent, csvContent: r?.csvContent, telemetryBundlePath: r?.telemetryBundlePath, }); }; } }, []); async function handleExportRideGpx(e: React.MouseEvent, ride: Ride) { e.stopPropagation(); try { setExportNotice('Loading recorded telemetry for export…'); const points = await resolveRideTelemetryPoints(ride); if (!points.length) { throw new Error('No recorded telemetry points available.'); } const gpx = generateRideGpx(ride, points); const dateStr = ride.startedAt ? ride.startedAt.toISOString().split('T')[0] : 'session'; const filename = `motorsignal_${ride.id}_${dateStr}.gpx`; downloadFile(gpx, filename, 'application/gpx+xml'); setExportNotice(`Exported GPX: ${filename}`); setTimeout(() => setExportNotice(null), 3000); } catch (err) { const msg = err instanceof Error ? err.message : 'Telemetry export failed.'; setExportNotice(`Export failed: ${msg}`); setTimeout(() => setExportNotice(null), 4000); } } async function handleExportRideCsv(e: React.MouseEvent, ride: Ride) { e.stopPropagation(); try { setExportNotice('Loading recorded telemetry for export…'); const points = await resolveRideTelemetryPoints(ride); if (!points.length) { throw new Error('No recorded telemetry points available.'); } const csv = generateRideCsv(ride, points); const dateStr = ride.startedAt ? ride.startedAt.toISOString().split('T')[0] : 'session'; const filename = `motorsignal_20hz_${ride.id}_${dateStr}.csv`; downloadFile(csv, filename, 'text/csv;charset=utf-8;'); setExportNotice(`Exported 20 Hz CSV: ${filename}`); setTimeout(() => setExportNotice(null), 3000); } catch (err) { const msg = err instanceof Error ? err.message : 'Telemetry export failed.'; setExportNotice(`Export failed: ${msg}`); setTimeout(() => setExportNotice(null), 4000); } } // Handle Delete Ride Session async function handleDeleteRide(e: React.MouseEvent, ride: Ride) { e.stopPropagation(); if (!user) return; const confirmDelete = window.confirm( `Delete telemetry session recorded on ${ride.startedAt ? ride.startedAt.toLocaleDateString() : 'session'}?` ); if (!confirmDelete) return; try { await deleteDoc(doc(firestore, 'users', user.uid, 'rides', ride.id)); setRides((prev) => { const updated = prev.filter((r) => r.id !== ride.id); if (onMetricsLoaded) { const totalMiles = updated.reduce((acc, r) => acc + r.distanceMiles, 0); let peakLean = 0; for (const r of updated) { if (r.maxLeanLeft > peakLean) peakLean = r.maxLeanLeft; if (r.maxLeanRight > peakLean) peakLean = r.maxLeanRight; } onMetricsLoaded({ totalMiles: Math.round(totalMiles), rideCount: updated.length, peakLean: Number(peakLean.toFixed(1)), }); } return updated; }); } catch (err) { console.error('Error deleting ride:', err); alert('Unable to delete telemetry session. Please check permissions.'); } } // Auto-resolved Stock Photography Cache (from /api/motorcycle-image) const [stockImages, setStockImages] = useState< Record >({}); // Resolve stock images for bikes that don't have custom uploaded images useEffect(() => { motorcycles.forEach((bike) => { if (bike.imageUrl) return; const key = `${bike.makeName}_${bike.modelName}_${bike.year || ''}`.toLowerCase(); if (key in stockImages || bike.id in stockImages) return; fetch( `/api/motorcycle-image?make=${encodeURIComponent(bike.makeName)}&model=${encodeURIComponent( bike.modelName )}&year=${bike.year || ''}` ) .then((res) => (res.ok ? res.json() : null)) .then((data) => { const val = data?.imageUrl ? { imageUrl: data.imageUrl as string, attribution: data.attribution as string, caption: data.caption as string, } : null; setStockImages((prev) => ({ ...prev, [bike.id]: val, [key]: val, })); }) .catch(() => { setStockImages((prev) => ({ ...prev, [bike.id]: null, [key]: null, })); }); }); }, [motorcycles, stockImages]); async function loadData(currentUser: User | null) { if (!currentUser) { setMotorcycles([]); setRides([]); setState('Sign in or connect your Google account to view your live telemetry.'); if (onMetricsLoaded) onMetricsLoaded({ totalMiles: 0, rideCount: 0, peakLean: 0 }); return; } if (onSyncStateChange) onSyncStateChange(true); try { const [motorcycleSnapshot, rideSnapshot] = await Promise.all([ getDocs(collection(firestore, 'users', currentUser.uid, 'motorcycles')), getDocs(collection(firestore, 'users', currentUser.uid, 'rides')), ]); const loadedMotorcycles: Motorcycle[] = motorcycleSnapshot.docs.map((snapshot) => { const data = snapshot.data(); const yearVal = number(data.year) || 0; const makeVal = text(data.makeName) || text(data.make); const modelVal = text(data.modelName) || text(data.model); const variantVal = text(data.variantName) || text(data.variant); const description = [yearVal || '', makeVal, modelVal, variantVal].filter(Boolean).join(' '); return { id: snapshot.id, nickname: text(data.nickname) || description || 'Motorcycle', makeName: makeVal, modelName: modelVal, variantName: variantVal, year: yearVal, description, isDefault: data.isDefault === true, imageUrl: text(data.imageUrl) || undefined, vin: text(data.vin) || text(data.vinNumber) || undefined, }; }).sort((a, b) => Number(b.isDefault) - Number(a.isDefault)); let totalMiles = 0; let peakLean = 0; const loadedRides: Ride[] = rideSnapshot.docs.map((snapshot) => { const data = snapshot.data(); const rawStart = text(data.startTime); const rawEnd = text(data.endTime); const startedAt = rawStart ? new Date(rawStart) : null; const endedAt = rawEnd ? new Date(rawEnd) : null; const dist = number(data.distanceMiles); const leanL = number(data.maxLeanLeft); const leanR = number(data.maxLeanRight); totalMiles += dist; if (leanL > peakLean) peakLean = leanL; if (leanR > peakLean) peakLean = leanR; const startLat = number(data.startLat) || number(data.startLatitude) || undefined; const startLon = number(data.startLon) || number(data.startLongitude) || undefined; const endLat = number(data.endLat) || number(data.endLatitude) || undefined; const endLon = number(data.endLon) || number(data.endLongitude) || undefined; const bundlePath = text(data.telemetryBundlePath) || text(data.telemetryBundle?.objectKey) || undefined; let ridePoints: TelemetryPoint[] | undefined; if (Array.isArray(data.points) && data.points.length > 0) { ridePoints = data.points; } else if (Array.isArray(data.telemetryPoints) && data.telemetryPoints.length > 0) { ridePoints = data.telemetryPoints; } return { id: snapshot.id, startedAt: startedAt && !Number.isNaN(startedAt.getTime()) ? startedAt : null, endedAt: endedAt && !Number.isNaN(endedAt.getTime()) ? endedAt : null, distanceMiles: dist, topSpeedMph: number(data.topSpeedMph), averageSpeed: number(data.averageSpeed), maxLeanLeft: leanL, maxLeanRight: leanR, maxAccelG: number(data.maxAccelG), maxBrakingG: number(data.maxBrakingG), movingTime: number(data.movingTime), elevationGain: number(data.elevationGain), qualityScore: number(data.qualityScore) || 100, motorcycle: [number(data.motorcycleYear) || '', text(data.motorcycleMake), text(data.motorcycleModel)].filter(Boolean).join(' '), startLat, startLon, endLat, endLon, points: ridePoints, gpxContent: text(data.gpxContent) || undefined, csvContent: text(data.csvContent) || undefined, telemetryBundlePath: bundlePath, }; }).sort((a, b) => (b.startedAt?.getTime() ?? 0) - (a.startedAt?.getTime() ?? 0)); setMotorcycles(loadedMotorcycles); setRides(loadedRides); setState(''); if (onMetricsLoaded) { onMetricsLoaded({ totalMiles: Math.round(totalMiles), rideCount: loadedRides.length, peakLean: Number(peakLean.toFixed(1)), }); } } catch (error) { console.error('Error loading MotorSignal cloud data:', error); setState('App cloud data could not be loaded. Please re-authenticate or click Quick Sync.'); } finally { if (onSyncStateChange) onSyncStateChange(false); } } useEffect(() => { const unsubscribe = onAuthStateChanged(firebaseAuth, (currentUser) => { setUser(currentUser); void loadData(currentUser); }); return () => unsubscribe(); }, []); // React to parent Quick Sync trigger useEffect(() => { if (syncTrigger > 0 && user) { void loadData(user); } }, [syncTrigger]); // Handle image upload compression async function handleImageFileSelected(event: React.ChangeEvent, motorcycleId?: string) { const file = event.target.files?.[0]; if (!file) return; const reader = new FileReader(); reader.onload = async (e) => { const img = new Image(); img.onload = async () => { const canvas = document.createElement('canvas'); const MAX_WIDTH = 960; const MAX_HEIGHT = 640; let width = img.width; let height = img.height; if (width > height) { if (width > MAX_WIDTH) { height *= MAX_WIDTH / width; width = MAX_WIDTH; } } else { if (height > MAX_HEIGHT) { width *= MAX_HEIGHT / height; height = MAX_HEIGHT; } } canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx?.drawImage(img, 0, 0, width, height); const dataUrl = canvas.toDataURL('image/jpeg', 0.84); if (motorcycleId && user) { // Direct update on existing motorcycle try { await updateDoc(doc(firestore, 'users', user.uid, 'motorcycles', motorcycleId), { imageUrl: dataUrl, updatedAt: new Date().toISOString(), }); setMotorcycles((prev) => prev.map((m) => (m.id === motorcycleId ? { ...m, imageUrl: dataUrl } : m)) ); } catch (err) { console.error('Failed to update motorcycle image:', err); alert('Failed to save image. Please check permissions.'); } } else { // Staged for new motorcycle modal setNewImagePreview(dataUrl); } }; img.src = e.target?.result as string; }; reader.readAsDataURL(file); // Reset file input value event.target.value = ''; } // Handle Add Motorcycle submission async function handleAddMotorcycle(event: React.FormEvent) { event.preventDefault(); if (!user) { setFormError('Please sign in to add motorcycles.'); return; } if (!newMake.trim() || !newModel.trim()) { setFormError('Make and Model are required.'); return; } setFormBusy(true); setFormError(''); try { const yearInt = parseInt(newYear, 10) || new Date().getFullYear(); const generatedNickname = newNickname.trim() || `${yearInt} ${newMake} ${newModel}`.trim(); const shouldBeDefault = newIsDefault || motorcycles.length === 0; if (shouldBeDefault && motorcycles.length > 0) { const batch = writeBatch(firestore); motorcycles.forEach((m) => { batch.update(doc(firestore, 'users', user.uid, 'motorcycles', m.id), { isDefault: false, }); }); await batch.commit(); } const docRef = await addDoc(collection(firestore, 'users', user.uid, 'motorcycles'), { year: yearInt, makeName: newMake.trim(), modelName: newModel.trim(), variantName: newVariant.trim(), nickname: generatedNickname, vin: newVin.trim() || null, isDefault: shouldBeDefault, imageUrl: newImagePreview || null, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }); const newBike: Motorcycle = { id: docRef.id, year: yearInt, makeName: newMake.trim(), modelName: newModel.trim(), variantName: newVariant.trim(), nickname: generatedNickname, description: `${yearInt} ${newMake} ${newModel} ${newVariant}`.trim(), isDefault: shouldBeDefault, imageUrl: newImagePreview || undefined, vin: newVin.trim() || undefined, }; setMotorcycles((prev) => [ newBike, ...prev.map((m) => (shouldBeDefault ? { ...m, isDefault: false } : m)), ]); // Reset form setShowAddModal(false); setNewModel(''); setNewNickname(''); setNewVin(''); setNewImagePreview(null); } catch (err) { console.error('Error adding motorcycle:', err); setFormError(err instanceof Error ? err.message : 'Unable to add motorcycle. Please retry.'); } finally { setFormBusy(false); } } // Handle Delete Motorcycle async function handleDeleteMotorcycle(motorcycle: Motorcycle) { if (!user) return; const confirmDelete = window.confirm(`Remove ${motorcycle.nickname} from your garage?`); if (!confirmDelete) return; try { await deleteDoc(doc(firestore, 'users', user.uid, 'motorcycles', motorcycle.id)); setMotorcycles((prev) => prev.filter((m) => m.id !== motorcycle.id)); } catch (err) { console.error('Error deleting motorcycle:', err); alert('Unable to delete motorcycle. Please check connection and permissions.'); } } // Handle Make Primary async function handleMakePrimary(motorcycleId: string) { if (!user) return; try { const batch = writeBatch(firestore); motorcycles.forEach((m) => { batch.update(doc(firestore, 'users', user.uid, 'motorcycles', m.id), { isDefault: m.id === motorcycleId, }); }); await batch.commit(); setMotorcycles((prev) => prev .map((m) => ({ ...m, isDefault: m.id === motorcycleId })) .sort((a, b) => Number(b.isDefault) - Number(a.isDefault)) ); } catch (err) { console.error('Error setting primary motorcycle:', err); } } // Remove custom photo to restore stock graphic async function handleRemovePhoto(motorcycleId: string) { if (!user) return; try { await updateDoc(doc(firestore, 'users', user.uid, 'motorcycles', motorcycleId), { imageUrl: null, updatedAt: new Date().toISOString(), }); setMotorcycles((prev) => prev.map((m) => (m.id === motorcycleId ? { ...m, imageUrl: undefined } : m)) ); } catch (err) { console.error('Error removing photo:', err); } } return (
{/* Hidden file input for photo uploads */} void handleImageFileSelected(e, uploadingMotorcycleId ?? undefined)} /> {/* ========================================================================= */} {/* SECTION 1: VEHICLE GARAGE (Blue & Purple Areas) */} {/* ========================================================================= */}

Vehicle Garage & Telemetry Hardware

Synced bikes, ECU links, and motorcycle profiles

{/* Motorcycle Grid */} {motorcycles.length > 0 ? (
{motorcycles.map((bike) => (
{/* Accent top gradient */}
{/* Top Badges & Actions */}
{bike.isDefault ? ( Default Primary ) : ( )}
{/* Delete Motorcycle Action */}
{/* Motorcycle Image Area (Purple Area - Stock Photo or Custom) */}
{bike.imageUrl ? (
{bike.nickname}
CUSTOM RIDER PHOTO
) : (stockImages[bike.id] || stockImages[`${bike.makeName}_${bike.modelName}_${bike.year || ''}`.toLowerCase()])?.imageUrl ? (
{bike.nickname}
STOCK SPEC PHOTO {((stockImages[bike.id] || stockImages[`${bike.makeName}_${bike.modelName}_${bike.year || ''}`.toLowerCase()])! .attribution) && ( { (stockImages[bike.id] || stockImages[`${bike.makeName}_${bike.modelName}_${bike.year || ''}`.toLowerCase()])! .attribution } )}
) : ( )} {/* Image Action Overlay Button */}
{bike.imageUrl && ( )}
{/* Bike Title & Specs */}
{[bike.year || '', bike.makeName, bike.variantName || 'Standard Spec'].filter(Boolean).join(' • ')}

{bike.nickname}

{bike.vin && (

VIN: {bike.vin}

)}
{/* Telemetry Hardware Link Grid */}
Telemetry Link CAN Active
IMU Status 6-Axis Live
Cloud Sync 100% Synced
))}
) : (

No Motorcycles in Garage

Add your bike to bind CAN-bus telemetry, IMU orientation, and lean angles.

)}
{/* ========================================================================= */} {/* SECTION 2: RECENT RIDES TELEMETRY FEED (White Area) */} {/* ========================================================================= */}

Recent Telemetry Sessions

High-fidelity 20Hz GNSS, lean angles, and speed telemetry logs

{rides.length} {rides.length === 1 ? 'Session' : 'Sessions'} Recorded
{rides.length > 0 ? (
{rides.slice(0, visibleRideCount).map((ride) => { const isExpanded = expandedRideId === ride.id; const dateStr = ride.startedAt ? ride.startedAt.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric', }) : 'Session Log'; const timeStr = ride.startedAt ? ride.startedAt.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', }) : ''; return (
{/* Ride Header Info */}
{dateStr} {timeStr && • {timeStr}}
{ride.motorcycle || 'Motorcycle'} {ride.qualityScore}% Sync
{/* Metric Badges Grid */}
{/* Distance */}
Distance {ride.distanceMiles.toFixed(2)}{' '} mi
{/* Top Speed */}
Top Speed {ride.topSpeedMph.toFixed(1)}{' '} mph
{/* Peak Lean Angle */}
Max Lean (L / R) {ride.maxLeanLeft.toFixed(0)}° / {ride.maxLeanRight.toFixed(0)}°
{/* Duration */}
Duration {ride.movingTime > 0 ? formatDuration(ride.movingTime) : '< 1m'}
{/* Ride Actions */}
{/* Expanded Telemetry Drawer */} {isExpanded && (
AVG SPEED {ride.averageSpeed > 0 ? `${ride.averageSpeed.toFixed(1)} mph` : 'N/A'}
PEAK ACCEL {ride.maxAccelG > 0 ? `+${ride.maxAccelG.toFixed(2)} G` : '+0.00 G'}
PEAK DECEL {ride.maxBrakingG > 0 ? `-${ride.maxBrakingG.toFixed(2)} G` : '-0.00 G'}
ELEVATION GAIN {ride.elevationGain > 0 ? `${Math.round(ride.elevationGain)} ft` : '0 ft'}
)}
); })} {/* Show more button when more sessions exist */} {rides.length > visibleRideCount && (
Showing {Math.min(visibleRideCount, rides.length)} of {rides.length} sessions
)}
) : (

No Telemetry Rides Synced Yet

Record a ride using the MotorSignal mobile app. Rides are automatically uploaded to Cloudflare R2 and Firestore upon completion.

)}
{/* ========================================================================= */} {/* MODAL: ADD MOTORCYCLE FORM (Blue Area) */} {/* ========================================================================= */} {showAddModal && (

Add Motorcycle

Register a bike in your cloud garage

setNewYear(e.target.value)} className="w-full px-3 py-2 rounded-xl bg-surface-container-low border border-outline-variant/40 text-white font-mono text-sm outline-none focus:border-brand-cyan" />
setNewMake(e.target.value)} className="w-full px-3 py-2 rounded-xl bg-surface-container-low border border-outline-variant/40 text-white font-mono text-sm outline-none focus:border-brand-cyan" />
setNewModel(e.target.value)} className="w-full px-3 py-2 rounded-xl bg-surface-container-low border border-outline-variant/40 text-white font-mono text-sm outline-none focus:border-brand-cyan" />
setNewVariant(e.target.value)} className="w-full px-3 py-2 rounded-xl bg-surface-container-low border border-outline-variant/40 text-white font-mono text-sm outline-none focus:border-brand-cyan" />
setNewNickname(e.target.value)} className="w-full px-3 py-2 rounded-xl bg-surface-container-low border border-outline-variant/40 text-white font-mono text-sm outline-none focus:border-brand-cyan" />
setNewVin(e.target.value)} className="w-full px-3 py-2 rounded-xl bg-surface-container-low border border-outline-variant/40 text-white font-mono text-sm outline-none focus:border-brand-cyan" />
{/* Photo Upload in Modal */}
Auto-pulls stock photo if left empty
{newImagePreview ? (
Preview
) : ( )}
setNewIsDefault(e.target.checked)} className="rounded bg-surface-container-low border-outline-variant/40 text-brand-cyan focus:ring-brand-cyan" />
{formError && (

{formError}

)}
)} {/* Telemetry Replay Modal */} {replayRide && ( setReplayRide(null)} /> )} {/* Floating Export Notice Toast */} {exportNotice && (
{exportNotice}
)}
); }