"use client"; import { useRef, useState } from "react"; import { useTranslations } from "next-intl"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { fetchCafePublicProfile, removeGalleryPhoto, updateCafePublicProfile, uploadGalleryPhoto, type CafeProfileEdit, type UpdateCafeProfilePayload, } from "@/lib/api/cafe-public-profile"; import type { WorkingHours } from "@/lib/api/public-discover"; import { resolveMediaUrl } from "@/lib/api/client"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Card, CardContent } from "@/components/ui/card"; import { cn } from "@/lib/utils"; type Props = { cafeId: string }; type Tab = "info" | "gallery" | "hours" | "social"; const DAY_KEYS: (keyof WorkingHours)[] = ["sat", "sun", "mon", "tue", "wed", "thu", "fri"]; export function CafePublicProfilePanel({ cafeId }: Props) { const t = useTranslations("cafePublicProfile"); const qc = useQueryClient(); const [tab, setTab] = useState("info"); const [saved, setSaved] = useState(false); const fileInputRef = useRef(null); // ── Server state ────────────────────────────────────────────────────────── const { data: profile, isLoading } = useQuery({ queryKey: ["cafe-public-profile", cafeId], queryFn: () => fetchCafePublicProfile(cafeId), }); // ── Local edit state ────────────────────────────────────────────────────── const [description, setDescription] = useState(""); const [instagram, setInstagram] = useState(""); const [website, setWebsite] = useState(""); const [hours, setHours] = useState(emptyHours()); const [showOnKoja, setShowOnKoja] = useState(true); const [initialized, setInitialized] = useState(false); // Populate local state once we get server data if (profile && !initialized) { setDescription(profile.description ?? ""); setInstagram(profile.instagramHandle ?? ""); setWebsite(profile.websiteUrl ?? ""); setHours(profile.workingHours ?? emptyHours()); setShowOnKoja(profile.showOnKoja ?? true); setInitialized(true); } // ── Save info/social/hours ──────────────────────────────────────────────── const saveMutation = useMutation({ mutationFn: (override?: Partial) => updateCafePublicProfile(cafeId, { description, instagramHandle: instagram || null, websiteUrl: website || null, workingHours: hours, showOnKoja, ...override, }), onSuccess: (data) => { qc.setQueryData(["cafe-public-profile", cafeId], data); setSaved(true); setTimeout(() => setSaved(false), 2000); }, }); // ── Gallery upload ──────────────────────────────────────────────────────── const [uploading, setUploading] = useState(false); const [uploadError, setUploadError] = useState(null); const handleFileChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; setUploading(true); setUploadError(null); try { const gallery = await uploadGalleryPhoto(cafeId, file); qc.setQueryData(["cafe-public-profile", cafeId], (old) => old ? { ...old, galleryUrls: gallery } : old ); } catch (err: unknown) { const msg = err instanceof Error ? err.message : t("uploadFailed"); setUploadError(msg.includes("GALLERY_FULL") ? t("galleryFull") : t("uploadFailed")); } finally { setUploading(false); if (fileInputRef.current) fileInputRef.current.value = ""; } }; const removeMutation = useMutation({ mutationFn: (url: string) => removeGalleryPhoto(cafeId, url), onSuccess: (gallery) => { qc.setQueryData(["cafe-public-profile", cafeId], (old) => old ? { ...old, galleryUrls: gallery } : old ); }, }); // ── Hours helpers ───────────────────────────────────────────────────────── const setDayField = ( day: keyof WorkingHours, field: "isOpen" | "open" | "close", value: string | boolean ) => { setHours((prev) => ({ ...prev, [day]: { ...((prev[day] as object) ?? { isOpen: false, open: "", close: "" }), [field]: value, }, })); }; if (isLoading) { return

{t("loading")}

; } const tabs: { id: Tab; label: string }[] = [ { id: "info", label: t("tabs.info") }, { id: "gallery", label: t("tabs.gallery") }, { id: "hours", label: t("tabs.hours") }, { id: "social", label: t("tabs.social") }, ]; return (

{t("title")}

{t("subtitle")}

{/* Tab bar */}
{tabs.map((tb) => ( ))}
{/* ── Info tab ─────────────────────────────────────────────────────── */} {tab === "info" && (