Translate invite page to italian
This commit is contained in:
@@ -5,6 +5,8 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useParams, useSearchParams } from "next/navigation";
|
import { useParams, useSearchParams } from "next/navigation";
|
||||||
import { useGifts } from "@/context/gift-context";
|
import { useGifts } from "@/context/gift-context";
|
||||||
import { useGuests } from "@/context/guest-context";
|
import { useGuests } from "@/context/guest-context";
|
||||||
|
import { useEventThemes } from "@/context/event-theme-context";
|
||||||
|
import { useEvents } from "@/context/event-context";
|
||||||
import { GiftItem, GiftPurchase } from "@/client/types.gen";
|
import { GiftItem, GiftPurchase } from "@/client/types.gen";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
@@ -34,10 +36,11 @@ import {
|
|||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { AlertCircle, ExternalLink, Gift, Loader2 } from "lucide-react";
|
import { AlertCircle, ExternalLink, Gift, Loader2 } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
export default function GiftRegistryPage() {
|
export default function GiftRegistryPage() {
|
||||||
const { slug } = useParams<{ slug: string }>();
|
const { slug } = useParams<{ slug: string }>();
|
||||||
|
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const invitationCode = searchParams.get("code");
|
const invitationCode = searchParams.get("code");
|
||||||
|
|
||||||
@@ -64,6 +67,15 @@ export default function GiftRegistryPage() {
|
|||||||
} = useGifts();
|
} = useGifts();
|
||||||
|
|
||||||
const { findGuestByInvitationCode, guests, isLoadingGuests } = useGuests();
|
const { findGuestByInvitationCode, guests, isLoadingGuests } = useGuests();
|
||||||
|
const { themes, isLoadingThemes } = useEventThemes();
|
||||||
|
const { event, fetchEventBySlug, isLoadingEvent } = useEvents();
|
||||||
|
|
||||||
|
// Load event data based on slug
|
||||||
|
useEffect(() => {
|
||||||
|
if (slug) {
|
||||||
|
fetchEventBySlug(slug);
|
||||||
|
}
|
||||||
|
}, [slug, fetchEventBySlug]);
|
||||||
|
|
||||||
// Find current guest based on invitation code
|
// Find current guest based on invitation code
|
||||||
const currentGuest = invitationCode
|
const currentGuest = invitationCode
|
||||||
@@ -76,7 +88,7 @@ export default function GiftRegistryPage() {
|
|||||||
|
|
||||||
if (!currentGuest) {
|
if (!currentGuest) {
|
||||||
setErrorMessage(
|
setErrorMessage(
|
||||||
"Invalid invitation code. Please check your invitation link.",
|
"Codice invito non valido. Controlla il link dell'invito.",
|
||||||
);
|
);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
return;
|
return;
|
||||||
@@ -90,7 +102,7 @@ export default function GiftRegistryPage() {
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error("Error fetching gifts:", error);
|
console.error("Error fetching gifts:", error);
|
||||||
setErrorMessage(
|
setErrorMessage(
|
||||||
"Unable to load gift registry. Please try again later.",
|
"Impossibile caricare la lista regali. Riprova più tardi.",
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@@ -108,7 +120,7 @@ export default function GiftRegistryPage() {
|
|||||||
console.error("Error fetching guest purchases:", error);
|
console.error("Error fetching guest purchases:", error);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setErrorMessage("No event found for this invitation.");
|
setErrorMessage("Nessun evento trovato per questo invito.");
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
@@ -148,33 +160,58 @@ export default function GiftRegistryPage() {
|
|||||||
setReservedGifts(reserved);
|
setReservedGifts(reserved);
|
||||||
}
|
}
|
||||||
}, [items, guestPurchases]);
|
}, [items, guestPurchases]);
|
||||||
|
|
||||||
|
// Find the theme for this event
|
||||||
|
const eventTheme =
|
||||||
|
event && themes?.find((theme) => theme.id === event.theme_id);
|
||||||
|
|
||||||
|
// Enhanced color palette that works well with safari animals
|
||||||
|
const colors = eventTheme?.color_palette || {
|
||||||
|
primary: "#90B77D", // Soft jungle green
|
||||||
|
secondary: "#D2AB67", // Warm giraffe yellow
|
||||||
|
accent: "#B5A9EA", // Soft hippo purple
|
||||||
|
accent2: "#8FBDD3", // Elephant blue
|
||||||
|
accent3: "#E8B87D", // Lion tan
|
||||||
|
background: "#F9F5F0", // Cream paper texture
|
||||||
|
backgroundDark: "#F0E9D6", // Slightly darker cream for panels
|
||||||
|
text: "#5B4B49", // Warm dark brown
|
||||||
|
textLight: "#7D6D6B", // Lighter text variant
|
||||||
|
gold: "#D4AF37", // Gold accent for special elements
|
||||||
|
};
|
||||||
|
|
||||||
|
// Font selections
|
||||||
|
const fonts = eventTheme?.fonts || {
|
||||||
|
heading: "Georgia, serif",
|
||||||
|
body: "Arial, sans-serif",
|
||||||
|
};
|
||||||
|
|
||||||
// Format priority for display
|
// Format priority for display
|
||||||
const formatPriority = (priority: string) => {
|
const formatPriority = (priority: string) => {
|
||||||
switch (priority) {
|
switch (priority) {
|
||||||
case "must_have":
|
case "must_have":
|
||||||
return {
|
return {
|
||||||
label: "Must Have",
|
label: "Obbligatorio",
|
||||||
color: "bg-red-100 text-red-800 border-red-200",
|
color: `bg-opacity-20 text-opacity-90 bg-red-100 text-red-800 border-red-200`,
|
||||||
};
|
};
|
||||||
case "high":
|
case "high":
|
||||||
return {
|
return {
|
||||||
label: "High",
|
label: "Alta",
|
||||||
color: "bg-orange-100 text-orange-800 border-orange-200",
|
color: `bg-opacity-20 text-opacity-90 bg-orange-100 text-orange-800 border-orange-200`,
|
||||||
};
|
};
|
||||||
case "medium":
|
case "medium":
|
||||||
return {
|
return {
|
||||||
label: "Medium",
|
label: "Media",
|
||||||
color: "bg-blue-100 text-blue-800 border-blue-200",
|
color: `bg-opacity-20 text-opacity-90 bg-blue-100 text-blue-800 border-blue-200`,
|
||||||
};
|
};
|
||||||
case "low":
|
case "low":
|
||||||
return {
|
return {
|
||||||
label: "Low",
|
label: "Bassa",
|
||||||
color: "bg-green-100 text-green-800 border-green-200",
|
color: `bg-opacity-20 text-opacity-90 bg-green-100 text-green-800 border-green-200`,
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
label: priority,
|
label: priority,
|
||||||
color: "bg-gray-100 text-gray-800 border-gray-200",
|
color: `bg-opacity-20 text-opacity-90 bg-gray-100 text-gray-800 border-gray-200`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -189,7 +226,7 @@ export default function GiftRegistryPage() {
|
|||||||
// Remove reservation handler
|
// Remove reservation handler
|
||||||
const handleRemoveReservation = async (gift: GiftItem) => {
|
const handleRemoveReservation = async (gift: GiftItem) => {
|
||||||
if (!currentGuest) {
|
if (!currentGuest) {
|
||||||
setErrorMessage("Guest information not found.");
|
setErrorMessage("Informazioni ospite non trovate.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,14 +243,14 @@ export default function GiftRegistryPage() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error removing reservation:", error);
|
console.error("Error removing reservation:", error);
|
||||||
setErrorMessage("Unable to remove reservation. Please try again.");
|
setErrorMessage("Impossibile rimuovere la prenotazione. Riprova.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Confirm reservation handler
|
// Confirm reservation handler
|
||||||
const handleConfirmReservation = async () => {
|
const handleConfirmReservation = async () => {
|
||||||
if (!selectedGift || !currentGuest) {
|
if (!selectedGift || !currentGuest) {
|
||||||
setErrorMessage("Required information missing.");
|
setErrorMessage("Informazioni richieste mancanti.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +272,7 @@ export default function GiftRegistryPage() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error reserving gift:", error);
|
console.error("Error reserving gift:", error);
|
||||||
setErrorMessage("Unable to reserve gift. Please try again.");
|
setErrorMessage("Impossibile prenotare il regalo. Riprova.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -256,12 +293,46 @@ export default function GiftRegistryPage() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Animation variants
|
||||||
|
const containerVariants = {
|
||||||
|
hidden: { opacity: 0 },
|
||||||
|
visible: {
|
||||||
|
opacity: 1,
|
||||||
|
transition: {
|
||||||
|
staggerChildren: 0.1,
|
||||||
|
delayChildren: 0.2,
|
||||||
|
duration: 0.5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemVariants = {
|
||||||
|
hidden: { opacity: 0, y: 20 },
|
||||||
|
visible: {
|
||||||
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
|
transition: { duration: 0.5 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// Loading state
|
// Loading state
|
||||||
if (isLoading || isLoadingGuests || isLoadingItems) {
|
if (
|
||||||
|
isLoading ||
|
||||||
|
isLoadingGuests ||
|
||||||
|
isLoadingItems ||
|
||||||
|
isLoadingEvent ||
|
||||||
|
isLoadingThemes
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center min-h-[300px] p-8">
|
<div
|
||||||
<Loader2 className="h-8 w-8 animate-spin text-primary mb-4" />
|
className="flex flex-col items-center justify-center min-h-[300px] p-8"
|
||||||
<p className="text-muted-foreground">Loading gift registry...</p>
|
style={{ backgroundColor: colors.background }}
|
||||||
|
>
|
||||||
|
<Loader2
|
||||||
|
className="h-8 w-8 animate-spin mb-4"
|
||||||
|
style={{ color: colors.primary }}
|
||||||
|
/>
|
||||||
|
<p style={{ color: colors.textLight }}>Caricamento lista regali...</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -269,10 +340,10 @@ export default function GiftRegistryPage() {
|
|||||||
// Error state
|
// Error state
|
||||||
if (errorMessage) {
|
if (errorMessage) {
|
||||||
return (
|
return (
|
||||||
<div className="p-8">
|
<div className="p-8" style={{ backgroundColor: colors.background }}>
|
||||||
<Alert variant="destructive">
|
<Alert variant="destructive">
|
||||||
<AlertCircle className="h-4 w-4" />
|
<AlertCircle className="h-4 w-4" />
|
||||||
<AlertTitle>Error</AlertTitle>
|
<AlertTitle>Errore</AlertTitle>
|
||||||
<AlertDescription>{errorMessage}</AlertDescription>
|
<AlertDescription>{errorMessage}</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
</div>
|
</div>
|
||||||
@@ -280,199 +351,382 @@ export default function GiftRegistryPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container max-w-4xl mx-auto px-4 py-8">
|
<div
|
||||||
<div className="flex flex-col items-center mb-8">
|
className="min-h-screen pb-16 pt-8"
|
||||||
<h1 className="text-3xl font-bold mb-2 text-center">
|
style={{
|
||||||
🎁 Gift Registry 🎁
|
backgroundColor: colors.background,
|
||||||
</h1>
|
color: colors.text,
|
||||||
<p className="text-muted-foreground text-center">
|
fontFamily: fonts.body,
|
||||||
Choose a gift from the wishlist to help celebrate Emma's 1st birthday
|
}}
|
||||||
</p>
|
>
|
||||||
</div>
|
<motion.div
|
||||||
|
className="container max-w-4xl mx-auto px-4"
|
||||||
<Tabs
|
variants={containerVariants}
|
||||||
defaultValue="available"
|
initial="hidden"
|
||||||
value={activeTab}
|
animate="visible"
|
||||||
onValueChange={setActiveTab}
|
|
||||||
className="w-full"
|
|
||||||
>
|
>
|
||||||
<TabsList className="grid w-full grid-cols-2 mb-6">
|
{/* Back to Invitation Link */}
|
||||||
<TabsTrigger value="available" className="text-base">
|
<motion.div variants={itemVariants} className="mb-6">
|
||||||
Available Gifts
|
<Link
|
||||||
</TabsTrigger>
|
href={`/invite/${slug}?code=${invitationCode}`}
|
||||||
<TabsTrigger value="reserved" className="text-base">
|
className="inline-flex items-center text-sm hover:underline"
|
||||||
Your Reservations{" "}
|
style={{ color: colors.primary }}
|
||||||
{reservedGifts.length > 0 && `(${reservedGifts.length})`}
|
>
|
||||||
</TabsTrigger>
|
← Torna all'invito
|
||||||
</TabsList>
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
<TabsContent value="available">
|
<motion.div
|
||||||
{availableGifts.length === 0 ? (
|
variants={itemVariants}
|
||||||
<Alert>
|
className="flex flex-col items-center mb-8"
|
||||||
<AlertTitle>No Available Gifts</AlertTitle>
|
>
|
||||||
<AlertDescription>
|
<h1
|
||||||
All gifts have been reserved or there are no gifts available at
|
className="text-4xl font-bold mb-2 text-center"
|
||||||
this time.
|
style={{
|
||||||
</AlertDescription>
|
fontFamily: fonts.heading,
|
||||||
</Alert>
|
color: colors.secondary,
|
||||||
) : (
|
}}
|
||||||
<div className="overflow-x-auto">
|
>
|
||||||
<Table>
|
Lista Regali
|
||||||
<TableHeader>
|
</h1>
|
||||||
<TableRow>
|
<p className="text-center mb-2" style={{ color: colors.textLight }}>
|
||||||
<TableHead>Name</TableHead>
|
Scegli un regalo dalla lista per festeggiare il primo compleanno di
|
||||||
<TableHead>Priority</TableHead>
|
Emma
|
||||||
<TableHead>Link</TableHead>
|
</p>
|
||||||
<TableHead>Description</TableHead>
|
<div
|
||||||
<TableHead></TableHead>
|
className="w-24 h-1 rounded-full mt-2"
|
||||||
</TableRow>
|
style={{ backgroundColor: colors.accent }}
|
||||||
</TableHeader>
|
></div>
|
||||||
<TableBody>
|
</motion.div>
|
||||||
{availableGifts.map((gift) => {
|
|
||||||
const priority = formatPriority(gift.priority || "medium");
|
|
||||||
return (
|
|
||||||
<TableRow key={gift.id}>
|
|
||||||
<TableCell className="font-medium">
|
|
||||||
{gift.name}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<Badge variant="outline" className={priority.color}>
|
|
||||||
{priority.label}
|
|
||||||
</Badge>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
{gift.purchase_url ? (
|
|
||||||
<a
|
|
||||||
href={gift.purchase_url}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="inline-flex items-center text-primary hover:underline"
|
|
||||||
>
|
|
||||||
<ExternalLink size={14} className="mr-1" />
|
|
||||||
View Store
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<span className="text-muted-foreground text-sm">
|
|
||||||
None
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>{gift.description || ""}</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
onClick={() => handleReserveClick(gift)}
|
|
||||||
>
|
|
||||||
<Gift className="h-4 w-4 mr-1" />
|
|
||||||
Reserve
|
|
||||||
</Button>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</TabsContent>
|
|
||||||
|
|
||||||
<TabsContent value="reserved">
|
<motion.div variants={itemVariants}>
|
||||||
{reservedGifts.length === 0 ? (
|
<Tabs
|
||||||
<Alert>
|
defaultValue="available"
|
||||||
<AlertTitle>No Reservations</AlertTitle>
|
value={activeTab}
|
||||||
<AlertDescription>
|
onValueChange={setActiveTab}
|
||||||
You haven't reserved any gifts yet. Switch to the "Available
|
className="w-full"
|
||||||
Gifts" tab to make a selection.
|
>
|
||||||
</AlertDescription>
|
<TabsList
|
||||||
</Alert>
|
className="grid w-full grid-cols-2 mb-6 rounded-lg p-1"
|
||||||
) : (
|
style={{
|
||||||
<div className="overflow-x-auto">
|
backgroundColor: colors.backgroundDark,
|
||||||
<Table>
|
borderColor: colors.primary,
|
||||||
<TableHeader>
|
}}
|
||||||
<TableRow>
|
>
|
||||||
<TableHead>Name</TableHead>
|
<TabsTrigger
|
||||||
<TableHead>Priority</TableHead>
|
value="available"
|
||||||
<TableHead>Link</TableHead>
|
className="text-base rounded-md data-[state=active]:shadow-sm"
|
||||||
{/*<TableHead>Quantity</TableHead>*/}
|
style={{
|
||||||
<TableHead>Description</TableHead>
|
color: colors.text,
|
||||||
<TableHead></TableHead>
|
backgroundColor: "transparent",
|
||||||
</TableRow>
|
// "&[data-state=active]": {
|
||||||
</TableHeader>
|
// backgroundColor: "white",
|
||||||
<TableBody>
|
// color: colors.primary,
|
||||||
{reservedGifts.map((gift) => {
|
// },
|
||||||
const priority = formatPriority(gift.priority || "medium");
|
}}
|
||||||
const quantity = getReservationQuantity(gift);
|
>
|
||||||
return (
|
Regali Disponibili
|
||||||
<TableRow key={gift.id}>
|
</TabsTrigger>
|
||||||
<TableCell className="font-medium">
|
<TabsTrigger
|
||||||
{gift.name}
|
value="reserved"
|
||||||
</TableCell>
|
className="text-base rounded-md data-[state=active]:shadow-sm"
|
||||||
<TableCell>
|
style={{
|
||||||
<Badge variant="outline" className={priority.color}>
|
color: colors.text,
|
||||||
{priority.label}
|
backgroundColor: "transparent",
|
||||||
</Badge>
|
// "&[data-state=active]": {
|
||||||
</TableCell>
|
// backgroundColor: "white",
|
||||||
<TableCell>
|
// color: colors.primary,
|
||||||
{gift.purchase_url ? (
|
// },
|
||||||
<a
|
}}
|
||||||
href={gift.purchase_url}
|
>
|
||||||
target="_blank"
|
Le Tue Prenotazioni{" "}
|
||||||
rel="noopener noreferrer"
|
{reservedGifts.length > 0 && `(${reservedGifts.length})`}
|
||||||
className="inline-flex items-center text-primary hover:underline"
|
</TabsTrigger>
|
||||||
>
|
</TabsList>
|
||||||
<ExternalLink size={14} className="mr-1" />
|
|
||||||
View Store
|
<TabsContent value="available">
|
||||||
</a>
|
{availableGifts.length === 0 ? (
|
||||||
) : (
|
<Alert
|
||||||
<span className="text-muted-foreground text-sm">
|
style={{
|
||||||
None
|
backgroundColor: colors.backgroundDark,
|
||||||
</span>
|
color: colors.text,
|
||||||
)}
|
border: `1px solid ${colors.primary}`,
|
||||||
</TableCell>
|
}}
|
||||||
{/*<TableCell>{quantity}</TableCell>*/}
|
>
|
||||||
<TableCell>{gift.description || ""}</TableCell>
|
<AlertTitle style={{ color: colors.text }}>
|
||||||
<TableCell>
|
Nessun Regalo Disponibile
|
||||||
<Button
|
</AlertTitle>
|
||||||
variant="outline"
|
<AlertDescription style={{ color: colors.textLight }}>
|
||||||
size="sm"
|
Tutti i regali sono stati prenotati o non ci sono regali
|
||||||
onClick={() => handleRemoveReservation(gift)}
|
disponibili al momento.
|
||||||
>
|
</AlertDescription>
|
||||||
Remove
|
</Alert>
|
||||||
</Button>
|
) : (
|
||||||
</TableCell>
|
<div
|
||||||
|
className="overflow-x-auto rounded-lg border"
|
||||||
|
style={{
|
||||||
|
borderColor: colors.backgroundDark,
|
||||||
|
backgroundColor: "white",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Table>
|
||||||
|
<TableHeader
|
||||||
|
style={{ backgroundColor: colors.backgroundDark }}
|
||||||
|
>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead style={{ color: colors.text }}>
|
||||||
|
Nome
|
||||||
|
</TableHead>
|
||||||
|
<TableHead style={{ color: colors.text }}>
|
||||||
|
Priorità
|
||||||
|
</TableHead>
|
||||||
|
<TableHead style={{ color: colors.text }}>
|
||||||
|
Link
|
||||||
|
</TableHead>
|
||||||
|
<TableHead style={{ color: colors.text }}>
|
||||||
|
Descrizione
|
||||||
|
</TableHead>
|
||||||
|
<TableHead></TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
</TableHeader>
|
||||||
})}
|
<TableBody>
|
||||||
</TableBody>
|
{availableGifts.map((gift) => {
|
||||||
</Table>
|
const priority = formatPriority(
|
||||||
</div>
|
gift.priority || "medium",
|
||||||
)}
|
);
|
||||||
</TabsContent>
|
return (
|
||||||
</Tabs>
|
<TableRow
|
||||||
|
key={gift.id}
|
||||||
|
style={{ borderBottomColor: colors.backgroundDark }}
|
||||||
|
>
|
||||||
|
<TableCell
|
||||||
|
className="font-medium"
|
||||||
|
style={{ color: colors.text }}
|
||||||
|
>
|
||||||
|
{gift.name}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className={priority.color}
|
||||||
|
>
|
||||||
|
{priority.label}
|
||||||
|
</Badge>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{gift.purchase_url ? (
|
||||||
|
<a
|
||||||
|
href={gift.purchase_url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline-flex items-center hover:underline"
|
||||||
|
style={{ color: colors.primary }}
|
||||||
|
>
|
||||||
|
<ExternalLink size={14} className="mr-1" />
|
||||||
|
Vedi Negozio
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span style={{ color: colors.textLight }}>
|
||||||
|
Nessuno
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={{ color: colors.textLight }}>
|
||||||
|
{gift.description || ""}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleReserveClick(gift)}
|
||||||
|
style={{
|
||||||
|
backgroundColor: colors.secondary,
|
||||||
|
color: "white",
|
||||||
|
}}
|
||||||
|
className="hover:opacity-90"
|
||||||
|
>
|
||||||
|
<Gift className="h-4 w-4 mr-1" />
|
||||||
|
Prenota
|
||||||
|
</Button>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="reserved">
|
||||||
|
{reservedGifts.length === 0 ? (
|
||||||
|
<Alert
|
||||||
|
style={{
|
||||||
|
backgroundColor: colors.backgroundDark,
|
||||||
|
color: colors.text,
|
||||||
|
border: `1px solid ${colors.primary}`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AlertTitle style={{ color: colors.text }}>
|
||||||
|
Nessuna Prenotazione
|
||||||
|
</AlertTitle>
|
||||||
|
<AlertDescription style={{ color: colors.textLight }}>
|
||||||
|
Non hai ancora prenotato alcun regalo. Passa alla scheda
|
||||||
|
"Regali Disponibili" per fare una selezione.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
className="overflow-x-auto rounded-lg border"
|
||||||
|
style={{
|
||||||
|
borderColor: colors.backgroundDark,
|
||||||
|
backgroundColor: "white",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Table>
|
||||||
|
<TableHeader
|
||||||
|
style={{ backgroundColor: colors.backgroundDark }}
|
||||||
|
>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead style={{ color: colors.text }}>
|
||||||
|
Name
|
||||||
|
</TableHead>
|
||||||
|
<TableHead style={{ color: colors.text }}>
|
||||||
|
Priority
|
||||||
|
</TableHead>
|
||||||
|
<TableHead style={{ color: colors.text }}>
|
||||||
|
Link
|
||||||
|
</TableHead>
|
||||||
|
<TableHead style={{ color: colors.text }}>
|
||||||
|
Description
|
||||||
|
</TableHead>
|
||||||
|
<TableHead></TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{reservedGifts.map((gift) => {
|
||||||
|
const priority = formatPriority(
|
||||||
|
gift.priority || "medium",
|
||||||
|
);
|
||||||
|
const quantity = getReservationQuantity(gift);
|
||||||
|
return (
|
||||||
|
<TableRow
|
||||||
|
key={gift.id}
|
||||||
|
style={{ borderBottomColor: colors.backgroundDark }}
|
||||||
|
>
|
||||||
|
<TableCell
|
||||||
|
className="font-medium"
|
||||||
|
style={{ color: colors.text }}
|
||||||
|
>
|
||||||
|
{gift.name}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className={priority.color}
|
||||||
|
>
|
||||||
|
{priority.label}
|
||||||
|
</Badge>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{gift.purchase_url ? (
|
||||||
|
<a
|
||||||
|
href={gift.purchase_url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline-flex items-center hover:underline"
|
||||||
|
style={{ color: colors.primary }}
|
||||||
|
>
|
||||||
|
<ExternalLink size={14} className="mr-1" />
|
||||||
|
View Store
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span style={{ color: colors.textLight }}>
|
||||||
|
None
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell style={{ color: colors.textLight }}>
|
||||||
|
{gift.description || ""}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleRemoveReservation(gift)}
|
||||||
|
style={{
|
||||||
|
borderColor: colors.primary,
|
||||||
|
color: colors.primary,
|
||||||
|
backgroundColor: "white",
|
||||||
|
}}
|
||||||
|
className="hover:opacity-90"
|
||||||
|
>
|
||||||
|
Rimuovi
|
||||||
|
</Button>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
{/* Reservation Dialog */}
|
{/* Reservation Dialog */}
|
||||||
<Dialog open={isReserving} onOpenChange={setIsReserving}>
|
<Dialog open={isReserving} onOpenChange={setIsReserving}>
|
||||||
<DialogContent>
|
<DialogContent
|
||||||
|
style={{
|
||||||
|
backgroundColor: colors.background,
|
||||||
|
borderColor: colors.primary,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Reserve Gift</DialogTitle>
|
<DialogTitle
|
||||||
<DialogDescription>
|
style={{
|
||||||
|
color: colors.secondary,
|
||||||
|
fontFamily: fonts.heading,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Prenota Regalo
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogDescription style={{ color: colors.textLight }}>
|
||||||
{selectedGift?.name} - {selectedGift?.description}
|
{selectedGift?.name} - {selectedGift?.description}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="py-4">
|
<div className="py-4">
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label className="block text-sm font-medium mb-1">
|
<label
|
||||||
How many would you like to reserve?
|
className="block text-sm font-medium mb-1"
|
||||||
|
style={{ color: colors.text }}
|
||||||
|
>
|
||||||
|
Quanti ne vuoi prenotare?
|
||||||
</label>
|
</label>
|
||||||
<Select value={quantity} onValueChange={setQuantity}>
|
<Select value={quantity} onValueChange={setQuantity}>
|
||||||
<SelectTrigger>
|
<SelectTrigger
|
||||||
<SelectValue placeholder="Select quantity" />
|
style={{
|
||||||
|
borderColor: colors.backgroundDark,
|
||||||
|
color: colors.text,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectValue placeholder="Seleziona quantità" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent
|
||||||
|
style={{
|
||||||
|
backgroundColor: colors.background,
|
||||||
|
borderColor: colors.backgroundDark,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{selectedGift &&
|
{selectedGift &&
|
||||||
getQuantityOptions(selectedGift).map((num) => (
|
getQuantityOptions(selectedGift).map((num) => (
|
||||||
<SelectItem key={num} value={num.toString()}>
|
<SelectItem
|
||||||
|
key={num}
|
||||||
|
value={num.toString()}
|
||||||
|
style={{ color: colors.text }}
|
||||||
|
>
|
||||||
{num}
|
{num}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
@@ -481,27 +735,46 @@ export default function GiftRegistryPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedGift?.purchase_url && (
|
{selectedGift?.purchase_url && (
|
||||||
<div className="mt-4 p-3 bg-muted rounded-md text-sm">
|
<div
|
||||||
<p className="font-medium mb-1">Where to buy:</p>
|
className="mt-4 p-3 rounded-md text-sm"
|
||||||
|
style={{ backgroundColor: colors.backgroundDark }}
|
||||||
|
>
|
||||||
|
<p className="font-medium mb-1" style={{ color: colors.text }}>
|
||||||
|
Dove acquistare:
|
||||||
|
</p>
|
||||||
<a
|
<a
|
||||||
href={selectedGift.purchase_url}
|
href={selectedGift.purchase_url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-primary inline-flex items-center hover:underline"
|
className="inline-flex items-center hover:underline"
|
||||||
|
style={{ color: colors.primary }}
|
||||||
>
|
>
|
||||||
<ExternalLink size={14} className="mr-1" />
|
<ExternalLink size={14} className="mr-1" />
|
||||||
Visit Store
|
Visita Negozio
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="outline" onClick={() => setIsReserving(false)}>
|
<Button
|
||||||
Cancel
|
variant="outline"
|
||||||
|
onClick={() => setIsReserving(false)}
|
||||||
|
style={{
|
||||||
|
borderColor: colors.backgroundDark,
|
||||||
|
color: colors.text,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Annulla
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleConfirmReservation}>
|
<Button
|
||||||
Confirm Reservation
|
onClick={handleConfirmReservation}
|
||||||
|
style={{
|
||||||
|
backgroundColor: colors.secondary,
|
||||||
|
color: "white",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Conferma Prenotazione
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user