Files
Dramlog-Prod/src/services/save-bottle.ts

109 lines
4.1 KiB
TypeScript

'use server';
import { createClient } from '@/lib/supabase/server';
import { BottleMetadataSchema } from '@/types/whisky';
import { v4 as uuidv4 } from 'uuid';
export async function saveBottle(
rawMetadata: any,
base64Image: string | null,
_ignoredUserId: string, // Keeping for signature compatibility
preUploadedUrl?: string
) {
const supabase = await createClient();
try {
const metadata = BottleMetadataSchema.parse(rawMetadata);
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
throw new Error('Nicht autorisiert oder Session abgelaufen.');
}
const userId = user.id;
let finalImageUrl = preUploadedUrl;
// 1. Upload Image to Storage if not already uploaded
if (!finalImageUrl && base64Image) {
const base64Data = base64Image.split(',')[1] || base64Image;
const buffer = Buffer.from(base64Data, 'base64');
const isWebp = base64Image.startsWith('data:image/webp');
const fileName = `${userId}/${uuidv4()}.${isWebp ? 'webp' : 'jpg'}`;
const { error: uploadError } = await supabase.storage
.from('bottles')
.upload(fileName, buffer, {
contentType: isWebp ? 'image/webp' : 'image/jpeg',
upsert: true,
});
if (uploadError) throw new Error(`Upload Error: ${uploadError.message}`);
// Get Public URL
const { data: { publicUrl } } = supabase.storage
.from('bottles')
.getPublicUrl(fileName);
finalImageUrl = publicUrl;
}
if (!finalImageUrl) {
throw new Error('Kein Bild zum Speichern vorhanden.');
}
// 1.5 Deduplication Check
// If a bottle with the same name/distillery was created by the same user in the last 5 minutes,
// we treat it as a duplicate (likely from a race condition or double sync).
const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000).toISOString();
const { data: existingBottle } = await supabase
.from('bottles')
.select('*')
.eq('user_id', userId)
.eq('name', metadata.name)
.eq('distillery', metadata.distillery)
.gte('created_at', fiveMinutesAgo)
.order('created_at', { ascending: false })
.limit(1)
.maybeSingle();
if (existingBottle) {
console.log('[saveBottle] Potential duplicate detected, returning existing bottle:', existingBottle.id);
return { success: true, data: existingBottle };
}
// 2. Save Metadata to Database
const { data: bottleData, error: dbError } = await supabase
.from('bottles')
.insert({
user_id: userId,
name: metadata.name,
distillery: metadata.distillery,
category: metadata.category,
abv: metadata.abv,
age: metadata.age,
whiskybase_id: metadata.whiskybaseId,
image_url: finalImageUrl,
status: 'sealed',
is_whisky: metadata.is_whisky ?? true,
confidence: metadata.confidence ? Math.round(metadata.confidence * 100) : 100,
distilled_at: metadata.distilled_at,
bottled_at: metadata.bottled_at,
batch_info: metadata.batch_info,
purchase_price: metadata.purchase_price,
suggested_tags: metadata.suggested_tags,
suggested_custom_tags: metadata.suggested_custom_tags,
})
.select()
.single();
if (dbError) throw new Error(`Database Error: ${dbError.message}`);
return { success: true, data: bottleData };
} catch (error) {
console.error('Save Bottle Error:', error);
return {
success: false,
error: error instanceof Error ? error.message : 'An unknown error occurred while saving.',
};
}
}