@@ -425,66 +488,65 @@ export default function CameraCapture({ onImageCaptured, onAnalysisComplete, onS
{t('camera.alreadyInVaultDesc')}
-
)}
- {previewUrl && !isProcessing && !error && !isQueued && !matchingBottle && (
+ {/* Analysis Results Display */}
+ {previewUrl && !isProcessing && !error && !isQueued && !matchingBottle && analysisResult && (
{t('camera.analysisSuccess')}
- {analysisResult && (
-
-
-
- {t('camera.results')}
-
-
-
- {t('bottle.nameLabel')}:
- {analysisResult.name || '-'}
-
-
- {t('bottle.distilleryLabel')}:
- {analysisResult.distillery || '-'}
-
-
- {t('bottle.categoryLabel')}:
- {shortenCategory(analysisResult.category || '-')}
-
-
- {t('bottle.abvLabel')}:
- {analysisResult.abv ? `${analysisResult.abv}%` : '-'}
-
- {analysisResult.distilled_at && (
-
- {t('bottle.distilledLabel')}:
- {analysisResult.distilled_at}
-
- )}
- {analysisResult.bottled_at && (
-
- {t('bottle.bottledLabel')}:
- {analysisResult.bottled_at}
-
- )}
- {analysisResult.batch_info && (
-
- {t('bottle.batchLabel')}:
- {analysisResult.batch_info}
-
- )}
-
+
+
+
+ {t('camera.results')}
- )}
+
+
+ {t('bottle.nameLabel')}:
+ {analysisResult.name || '-'}
+
+
+ {t('bottle.distilleryLabel')}:
+ {analysisResult.distillery || '-'}
+
+
+ {t('bottle.categoryLabel')}:
+ {shortenCategory(analysisResult.category || '-')}
+
+
+ {t('bottle.abvLabel')}:
+ {analysisResult.abv ? `${analysisResult.abv}%` : '-'}
+
+ {analysisResult.age && (
+
+ {t('bottle.ageLabel')}:
+ {analysisResult.age} {t('bottle.years')}
+
+ )}
+ {analysisResult.distilled_at && (
+
+ {t('bottle.distilledLabel')}:
+ {analysisResult.distilled_at}
+
+ )}
+ {analysisResult.bottled_at && (
+
+ {t('bottle.bottledLabel')}:
+ {analysisResult.bottled_at}
+
+ )}
+ {analysisResult.batch_info && (
+
+ {t('bottle.batchLabel')}:
+ {analysisResult.batch_info}
+
+ )}
+
+
)}
diff --git a/src/components/MainContentWrapper.tsx b/src/components/MainContentWrapper.tsx
new file mode 100644
index 0000000..e46c389
--- /dev/null
+++ b/src/components/MainContentWrapper.tsx
@@ -0,0 +1,14 @@
+'use client';
+
+import React from 'react';
+import { useSession } from '@/context/SessionContext';
+
+export default function MainContentWrapper({ children }: { children: React.ReactNode }) {
+ const { activeSession } = useSession();
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/components/SessionList.tsx b/src/components/SessionList.tsx
index e608569..aab205e 100644
--- a/src/components/SessionList.tsx
+++ b/src/components/SessionList.tsx
@@ -2,15 +2,17 @@
import React, { useState, useEffect } from 'react';
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
-import { Calendar, Plus, GlassWater, Loader2, ChevronRight, Users } from 'lucide-react';
+import { Calendar, Plus, GlassWater, Loader2, ChevronRight, Users, Check } from 'lucide-react';
import Link from 'next/link';
import { useI18n } from '@/i18n/I18nContext';
+import { useSession } from '@/context/SessionContext';
interface Session {
id: string;
name: string;
scheduled_at: string;
participant_count?: number;
+ whisky_count?: number;
}
export default function SessionList() {
@@ -20,6 +22,7 @@ export default function SessionList() {
const [isLoading, setIsLoading] = useState(true);
const [isCreating, setIsCreating] = useState(false);
const [newName, setNewName] = useState('');
+ const { activeSession, setActiveSession } = useSession();
useEffect(() => {
fetchSessions();
@@ -30,7 +33,8 @@ export default function SessionList() {
.from('tasting_sessions')
.select(`
*,
- session_participants (count)
+ session_participants (count),
+ tastings (count)
`)
.order('scheduled_at', { ascending: false });
@@ -39,7 +43,8 @@ export default function SessionList() {
} else {
setSessions(data.map(s => ({
...s,
- participant_count: s.session_participants[0]?.count || 0
+ participant_count: s.session_participants[0]?.count || 0,
+ whisky_count: s.tastings[0]?.count || 0
})) || []);
}
setIsLoading(false);
@@ -64,6 +69,7 @@ export default function SessionList() {
} else {
setSessions(prev => [data, ...prev]);
setNewName('');
+ setActiveSession({ id: data.id, name: data.name });
}
setIsCreating(false);
};
@@ -103,14 +109,18 @@ export default function SessionList() {
) : (
{sessions.map((session) => (
-
-
-
{session.name}
-
+
+
+ {session.name}
+
+
{new Date(session.scheduled_at).toLocaleDateString(locale === 'de' ? 'de-DE' : 'en-US')}
@@ -121,13 +131,35 @@ export default function SessionList() {
{session.participant_count} {t('tasting.participants')}
)}
+ {session.whisky_count! > 0 && (
+
+
+ {session.whisky_count} Whiskys
+
+ )}
+
+
+ {activeSession?.id !== session.id ? (
+
+ ) : (
+
+
+
+ )}
+
-
-
- ))}
-
+
+ ))
+ }
+
)}
-
+
);
}
diff --git a/src/components/TastingList.tsx b/src/components/TastingList.tsx
index 78209f4..4d4ae48 100644
--- a/src/components/TastingList.tsx
+++ b/src/components/TastingList.tsx
@@ -1,7 +1,8 @@
'use client';
import React, { useState, useMemo } from 'react';
-import { Calendar, Star, ArrowUpDown, Clock, Trash2, Loader2, Users } from 'lucide-react';
+import { Calendar, Star, ArrowUpDown, Clock, Trash2, Loader2, Users, GlassWater } from 'lucide-react';
+import Link from 'next/link';
import { deleteTasting } from '@/services/delete-tasting';
interface Tasting {
@@ -19,6 +20,10 @@ interface Tasting {
name: string;
}
}[];
+ tasting_sessions?: {
+ id: string;
+ name: string;
+ };
}
interface TastingListProps {
@@ -108,9 +113,17 @@ export default function TastingList({ initialTastings }: TastingListProps) {
{note.is_sample ? 'Sample' : 'Bottle'}
diff --git a/src/components/TastingNoteForm.tsx b/src/components/TastingNoteForm.tsx
index 79dd42e..50c2692 100644
--- a/src/components/TastingNoteForm.tsx
+++ b/src/components/TastingNoteForm.tsx
@@ -2,9 +2,10 @@
import React, { useState, useEffect } from 'react';
import { saveTasting } from '@/services/save-tasting';
-import { Loader2, Send, Star, Users, Check } from 'lucide-react';
+import { Loader2, Send, Star, Users, Check, Sparkles, Droplets } from 'lucide-react';
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
import { useI18n } from '@/i18n/I18nContext';
+import { useSession } from '@/context/SessionContext';
interface Buddy {
id: string;
@@ -28,6 +29,9 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
const [error, setError] = useState
(null);
const [buddies, setBuddies] = useState([]);
const [selectedBuddyIds, setSelectedBuddyIds] = useState([]);
+ const { activeSession } = useSession();
+
+ const effectiveSessionId = sessionId || activeSession?.id;
useEffect(() => {
const fetchData = async () => {
@@ -36,19 +40,21 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
setBuddies(buddiesData || []);
// If Session ID, fetch session participants and pre-select them
- if (sessionId) {
+ if (effectiveSessionId) {
const { data: participants } = await supabase
.from('session_participants')
.select('buddy_id')
- .eq('session_id', sessionId);
+ .eq('session_id', effectiveSessionId);
if (participants) {
setSelectedBuddyIds(participants.map(p => p.buddy_id));
}
+ } else {
+ setSelectedBuddyIds([]);
}
};
fetchData();
- }, [sessionId]);
+ }, [effectiveSessionId]);
const toggleBuddy = (id: string) => {
setSelectedBuddyIds(prev =>
@@ -64,7 +70,7 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
try {
const result = await saveTasting({
bottle_id: bottleId,
- session_id: sessionId,
+ session_id: effectiveSessionId,
rating,
nose_notes: nose,
palate_notes: palate,
@@ -91,6 +97,18 @@ export default function TastingNoteForm({ bottleId, sessionId }: TastingNoteForm
return (