diff --git a/src/app/bottles/[id]/page.tsx b/src/app/bottles/[id]/page.tsx index 235c94e..19956cd 100644 --- a/src/app/bottles/[id]/page.tsx +++ b/src/app/bottles/[id]/page.tsx @@ -8,6 +8,7 @@ import TastingNoteForm from '@/components/TastingNoteForm'; import StatusSwitcher from '@/components/StatusSwitcher'; import TastingList from '@/components/TastingList'; import DeleteBottleButton from '@/components/DeleteBottleButton'; +import { validateSession } from '@/services/validate-session'; export default async function BottlePage({ params, @@ -16,7 +17,15 @@ export default async function BottlePage({ params: { id: string }, searchParams: { session_id?: string } }) { - const sessionId = searchParams.session_id; + let sessionId = searchParams.session_id; + + // Validate Session Age (12 hour limit) + if (sessionId) { + const isValid = await validateSession(sessionId); + if (!isValid) { + sessionId = undefined; + } + } const supabase = createServerComponentClient({ cookies }); const { data: bottle } = await supabase diff --git a/src/components/BottleGrid.tsx b/src/components/BottleGrid.tsx index 41f9272..d801693 100644 --- a/src/components/BottleGrid.tsx +++ b/src/components/BottleGrid.tsx @@ -5,6 +5,7 @@ import Link from 'next/link'; import { Search, Filter, X, Calendar, Clock, Package, Lock, Unlock, Ghost, FlaskConical, AlertCircle, Trash2, AlertTriangle, PlusCircle } from 'lucide-react'; import { getStorageUrl } from '@/lib/supabase'; import { useSearchParams } from 'next/navigation'; +import { validateSession } from '@/services/validate-session'; interface Bottle { id: string; @@ -115,6 +116,19 @@ interface BottleGridProps { export default function BottleGrid({ bottles }: BottleGridProps) { const searchParams = useSearchParams(); const sessionId = searchParams.get('session_id'); + const [validatedSessionId, setValidatedSessionId] = useState(null); + + React.useEffect(() => { + const checkSession = async () => { + if (sessionId) { + const isValid = await validateSession(sessionId); + setValidatedSessionId(isValid ? sessionId : null); + } else { + setValidatedSessionId(null); + } + }; + checkSession(); + }, [sessionId]); const [searchQuery, setSearchQuery] = useState(''); const [selectedCategory, setSelectedCategory] = useState(null); @@ -284,7 +298,7 @@ export default function BottleGrid({ bottles }: BottleGridProps) { {filteredBottles.length > 0 ? (
{filteredBottles.map((bottle) => ( - + ))}
) : ( diff --git a/src/components/CameraCapture.tsx b/src/components/CameraCapture.tsx index 5254fe8..164ce87 100644 --- a/src/components/CameraCapture.tsx +++ b/src/components/CameraCapture.tsx @@ -10,6 +10,7 @@ import { BottleMetadata } from '@/types/whisky'; import { savePendingBottle } from '@/lib/offline-db'; import { v4 as uuidv4 } from 'uuid'; import { findMatchingBottle } from '@/services/find-matching-bottle'; +import { validateSession } from '@/services/validate-session'; import Link from 'next/link'; interface CameraCaptureProps { @@ -23,6 +24,19 @@ export default function CameraCapture({ onImageCaptured, onAnalysisComplete, onS const router = useRouter(); const searchParams = useSearchParams(); const sessionId = searchParams.get('session_id'); + const [validatedSessionId, setValidatedSessionId] = React.useState(null); + + React.useEffect(() => { + const checkSession = async () => { + if (sessionId) { + const isValid = await validateSession(sessionId); + setValidatedSessionId(isValid ? sessionId : null); + } else { + setValidatedSessionId(null); + } + }; + checkSession(); + }, [sessionId]); const fileInputRef = useRef(null); const [isProcessing, setIsProcessing] = useState(false); @@ -222,7 +236,7 @@ export default function CameraCapture({ onImageCaptured, onAnalysisComplete, onS