feat: Upgrade to Next.js 16.1 & React 19.2, migrate to Supabase SSR with async client handling

This commit is contained in:
2025-12-19 20:31:46 +01:00
parent d9b44a0ec5
commit 24e243fff8
49 changed files with 942 additions and 852 deletions

View File

@@ -1,25 +1,97 @@
import { z } from 'zod';
export const BottleMetadataSchema = z.object({
name: z.string().nullish(),
distillery: z.string().nullish(),
category: z.string().nullish(),
abv: z.number().nullish(),
age: z.number().nullish(),
vintage: z.string().nullish(),
bottleCode: z.string().nullish(),
whiskybaseId: z.string().nullish(),
distilled_at: z.string().nullish(),
bottled_at: z.string().nullish(),
batch_info: z.string().nullish(),
name: z.string().trim().min(1).max(255).nullish(),
distillery: z.string().trim().max(255).nullish(),
category: z.string().trim().max(100).nullish(),
abv: z.number().min(0).max(100).nullish(),
age: z.number().min(0).max(100).nullish(),
vintage: z.string().trim().max(50).nullish(),
bottleCode: z.string().trim().max(100).nullish(),
whiskybaseId: z.string().trim().max(50).nullish(),
distilled_at: z.string().trim().max(50).nullish(),
bottled_at: z.string().trim().max(50).nullish(),
batch_info: z.string().trim().max(255).nullish(),
is_whisky: z.boolean().default(true),
confidence: z.number().min(0).max(100).default(100),
suggested_tags: z.array(z.string()).nullish(),
suggested_custom_tags: z.array(z.string()).nullish(),
suggested_tags: z.array(z.string().trim().max(100)).nullish(),
suggested_custom_tags: z.array(z.string().trim().max(100)).nullish(),
});
export type BottleMetadata = z.infer<typeof BottleMetadataSchema>;
export const TastingNoteSchema = z.object({
bottle_id: z.string().uuid(),
session_id: z.string().uuid().optional(),
rating: z.number().min(0).max(100),
nose_notes: z.string().trim().max(2000).optional(),
palate_notes: z.string().trim().max(2000).optional(),
finish_notes: z.string().trim().max(2000).optional(),
is_sample: z.boolean().default(false),
buddy_ids: z.array(z.string().uuid()).optional(),
tag_ids: z.array(z.string().uuid()).optional(),
tasted_at: z.string().datetime().optional(),
});
export type TastingNoteData = z.infer<typeof TastingNoteSchema>;
export const UpdateBottleSchema = z.object({
name: z.string().trim().min(1).max(255).optional(),
distillery: z.string().trim().max(255).optional(),
category: z.string().trim().max(100).optional(),
abv: z.number().min(0).max(100).optional(),
age: z.number().min(0).max(100).optional(),
whiskybase_id: z.string().trim().max(50).optional(),
purchase_price: z.number().min(0).optional(),
distilled_at: z.string().trim().max(50).optional(),
bottled_at: z.string().trim().max(50).optional(),
batch_info: z.string().trim().max(255).optional(),
});
export type UpdateBottleData = z.infer<typeof UpdateBottleSchema>;
export const TagSchema = z.object({
name: z.string().trim().min(1).max(50),
category: z.enum(['nose', 'taste', 'finish', 'texture']),
});
export type TagData = z.infer<typeof TagSchema>;
export const AdminCreditUpdateSchema = z.object({
userId: z.string().uuid(),
newBalance: z.number().min(0).max(1000000),
reason: z.string().trim().min(1).max(255),
});
export type AdminCreditUpdateData = z.infer<typeof AdminCreditUpdateSchema>;
export const AdminSettingsSchema = z.object({
userId: z.string().uuid(),
dailyLimit: z.number().min(0).max(10000).nullable(),
googleSearchCost: z.number().min(0).max(1000).optional(),
geminiAiCost: z.number().min(0).max(1000).optional(),
});
export type AdminSettingsData = z.infer<typeof AdminSettingsSchema>;
export const DiscoveryDataSchema = z.object({
name: z.string().trim().min(1).max(255),
distillery: z.string().trim().max(255).optional(),
abv: z.number().min(0).max(100).optional(),
age: z.number().min(0).max(100).optional(),
distilled_at: z.string().trim().max(50).optional(),
bottled_at: z.string().trim().max(50).optional(),
batch_info: z.string().trim().max(255).optional(),
});
export type DiscoveryData = z.infer<typeof DiscoveryDataSchema>;
export const BuddySchema = z.object({
name: z.string().trim().min(1).max(100),
});
export type BuddyData = z.infer<typeof BuddySchema>;
export interface AnalysisResponse {
success: boolean;
data?: BottleMetadata;