From a3aa4f8b25f39a72f3e769d82e8828e088ed537c Mon Sep 17 00:00:00 2001 From: robin Date: Thu, 18 Dec 2025 09:36:13 +0100 Subject: [PATCH] fix: restore BottleGrid and apply storage URL normalization --- src/app/bottles/[id]/page.tsx | 3 +- src/components/BottleGrid.tsx | 52 +++++++++++++++++++++++------------ src/lib/supabase.ts | 30 +++++++++++++++++++- 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/src/app/bottles/[id]/page.tsx b/src/app/bottles/[id]/page.tsx index 0e148bd..46391fa 100644 --- a/src/app/bottles/[id]/page.tsx +++ b/src/app/bottles/[id]/page.tsx @@ -3,6 +3,7 @@ import { cookies } from 'next/headers'; import { notFound } from 'next/navigation'; import Link from 'next/link'; import { ChevronLeft, Calendar, Award, Droplets, MapPin, Tag, ExternalLink, Package } from 'lucide-react'; +import { getStorageUrl } from '@/lib/supabase'; import TastingNoteForm from '@/components/TastingNoteForm'; import StatusSwitcher from '@/components/StatusSwitcher'; import TastingList from '@/components/TastingList'; @@ -43,7 +44,7 @@ export default async function BottlePage({ params }: { params: { id: string } })
{bottle.name} diff --git a/src/components/BottleGrid.tsx b/src/components/BottleGrid.tsx index ead3297..75a3aec 100644 --- a/src/components/BottleGrid.tsx +++ b/src/components/BottleGrid.tsx @@ -2,10 +2,26 @@ import React, { useState, useMemo } from 'react'; import Link from 'next/link'; -import { Search, Filter, X, Calendar, Clock, Package, Lock, Unlock, Ghost, FlaskConical, AlertCircle } from 'lucide-react'; +import { Search, Filter, X, Calendar, Clock, Package, Lock, Unlock, Ghost, FlaskConical, AlertCircle, Trash2, AlertTriangle } from 'lucide-react'; +import { getStorageUrl } from '@/lib/supabase'; + +interface Bottle { + id: string; + name: string; + distillery: string; + category: string; + abv: number; + age: number; + image_url: string; + status: 'sealed' | 'open' | 'sampled' | 'empty'; + created_at: string; + last_tasted?: string | null; + is_whisky?: boolean; + confidence?: number; +} interface BottleCardProps { - bottle: any; + bottle: Bottle; } function BottleCard({ bottle }: BottleCardProps) { @@ -20,13 +36,13 @@ function BottleCard({ bottle }: BottleCardProps) { const statusStyle = statusConfig[bottle.status as keyof typeof statusConfig] || statusConfig.sealed; return ( - +
{bottle.name}
@@ -37,7 +53,7 @@ function BottleCard({ bottle }: BottleCardProps) {
)} -
+
{statusStyle.label}
@@ -54,8 +70,8 @@ function BottleCard({ bottle }: BottleCardProps) {
)}
-

+

{bottle.name || 'Unbekannte Flasche'}

@@ -178,10 +194,10 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
@@ -189,10 +205,10 @@ export default function BottleGrid({ bottles }: BottleGridProps) { @@ -206,10 +222,10 @@ export default function BottleGrid({ bottles }: BottleGridProps) {
@@ -217,10 +233,10 @@ export default function BottleGrid({ bottles }: BottleGridProps) { @@ -236,10 +252,10 @@ export default function BottleGrid({ bottles }: BottleGridProps) { diff --git a/src/lib/supabase.ts b/src/lib/supabase.ts index 44c5b2a..6fe83bb 100644 --- a/src/lib/supabase.ts +++ b/src/lib/supabase.ts @@ -9,4 +9,32 @@ if (!supabaseUrl || !supabaseAnonKey) { export const supabase = (supabaseUrl && supabaseAnonKey) ? createClient(supabaseUrl, supabaseAnonKey) - : null as any; // Fallback or handle null in services + : null as any; + +/** + * Normalisiert eine Storage-URL oder einen Pfad. + * Verhindert "Mixed Content"-Fehler in Self-Hosted Setups, + * indem interne IPs durch die öffentliche URL ersetzt werden. + */ +export function getStorageUrl(path: string | null | undefined): string { + if (!path) return ''; + + const baseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL?.replace(/\/$/, ''); + if (!baseUrl) return path; + + // Wenn es bereits eine URL ist + if (path.startsWith('http')) { + // Falls die URL eine interne IP enthält (z.B. 192.168.x.x oder localhost) + // oder falls sie über http statt https kommt (obwohl die App https nutzt) + if (path.includes('192.168.') || path.includes('localhost') || (baseUrl.startsWith('https') && path.startsWith('http:'))) { + const storagePathMatch = path.match(/\/storage\/v1\/object\/public\/bottles\/(.+)$/); + if (storagePathMatch) { + return `${baseUrl}/storage/v1/object/public/bottles/${storagePathMatch[1]}`; + } + } + return path; + } + + // Wenn es nur ein Pfad ist, vervollständigen + return `${baseUrl}/storage/v1/object/public/bottles/${path}`; +}