fix: restore BottleGrid and apply storage URL normalization
This commit is contained in:
@@ -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 } })
|
||||
<section className="grid grid-cols-1 md:grid-cols-2 gap-8 items-start">
|
||||
<div className="aspect-[4/5] rounded-3xl overflow-hidden shadow-2xl border border-zinc-200 dark:border-zinc-800">
|
||||
<img
|
||||
src={bottle.image_url}
|
||||
src={getStorageUrl(bottle.image_url)}
|
||||
alt={bottle.name}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
|
||||
@@ -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) {
|
||||
@@ -24,9 +40,9 @@ function BottleCard({ bottle }: BottleCardProps) {
|
||||
<div className="h-full bg-white dark:bg-zinc-900 rounded-[2rem] overflow-hidden border border-zinc-200 dark:border-zinc-800 shadow-sm transition-all duration-300 hover:shadow-2xl hover:shadow-amber-900/10 hover:-translate-y-1 group-hover:border-amber-500/30">
|
||||
<div className="aspect-[4/3] overflow-hidden bg-zinc-100 dark:bg-zinc-800 relative">
|
||||
<img
|
||||
src={bottle.image_url}
|
||||
src={getStorageUrl(bottle.image_url)}
|
||||
alt={bottle.name}
|
||||
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
|
||||
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/40 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
|
||||
|
||||
@@ -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}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user