refactor: extract PrizeCard component to reduce duplication
- Create reusable PrizeCard component for prize display cards - Refactor lots page to use PrizeCard with data-driven approach - Reduces code duplication in prize card rendering 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
4d46456ada
commit
f803e98a8b
|
|
@ -1,12 +1,22 @@
|
|||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { PrizeCard } from "@/components/ui";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Lots à gagner - Thé Tip Top",
|
||||
description: "Découvrez tous les magnifiques prix de notre jeu-concours. Avec 100% de gagnants garantis, chaque participant repart avec un lot !",
|
||||
};
|
||||
|
||||
const PRIZES = [
|
||||
{ imageSrc: "/images/lots/infuseur.png", imageAlt: "Infuseur à thé premium", badge: "60% des lots", title: "Infuseur à thé premium", description: "Un infuseur en acier inoxydable de haute qualité pour ressortir les arômes de vos thés en vrac" },
|
||||
{ imageSrc: "/images/lots/the-detox.png", imageAlt: "Boîte 100g thé détox", badge: "20% des lots", title: "Boîte 100g thé détox", description: "Mélange détox aux plantes bio : menthe, citronnelle, fenouil et gingembre" },
|
||||
{ imageSrc: "/images/lots/the-signature.png", imageAlt: "Boîte 100g thé signature", badge: "10% des lots", title: "Boîte 100g thé signature", description: "Notre mélange signature exclusif : Earl Grey aux agrumes et pétales de fleurs" },
|
||||
{ imageSrc: "/images/lots/coffret-39.png", imageAlt: "Coffret découverte 39€", badge: "6% des lots", title: "Coffret découverte 39€", description: "Sélection de nos 3 thés premium dans un élégant coffret cadeau" },
|
||||
{ imageSrc: "/images/lots/coffret-69.jpg", imageAlt: "Coffret prestige 69€", badge: "4% des lots", title: "Coffret prestige 69€", description: "Collection premium : 5 thés d'exception avec accessoires dans un coffret luxe" },
|
||||
{ imageSrc: "/images/lots/grand-prix.png", imageAlt: "Grand prix - 1 an de thé", badge: "1 an de THÉ", title: "Tirage Final", description: "Livraison mensuelle pendant 12 mois", isGrandPrix: true },
|
||||
];
|
||||
|
||||
export default function LotsPage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-[#f5f5f0] via-[#faf9f5] to-[#f5f5f0]">
|
||||
|
|
@ -67,139 +77,9 @@ export default function LotsPage() {
|
|||
<div className="container mx-auto px-4">
|
||||
<div className="max-w-5xl mx-auto">
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
|
||||
{/* Prize 1 - Infuseur */}
|
||||
<div className="bg-white rounded-xl shadow-md hover:shadow-xl transition-shadow overflow-hidden border border-[#e5e4dc] h-full flex flex-col">
|
||||
<div className="aspect-square bg-gradient-to-br from-[#faf9f5] to-[#f5f5f0] flex items-center justify-center p-2">
|
||||
<Image
|
||||
src="/images/lots/infuseur.png"
|
||||
alt="Infuseur à thé premium"
|
||||
width={400}
|
||||
height={400}
|
||||
className="w-full h-full object-contain object-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<div className="inline-block bg-gradient-to-r from-[#d4a574]/20 to-[#c4956a]/20 text-[#c4956a] text-sm font-bold px-3 py-1 rounded-full mb-3">
|
||||
60% des lots
|
||||
</div>
|
||||
<h3 className="text-xl font-bold text-[#5a5a4e] mb-2">Infuseur à thé premium</h3>
|
||||
<p className="text-[#8a8a7a] text-sm mb-4">
|
||||
Un infuseur en acier inoxydable de haute qualité pour ressortir les arômes de vos thés en vrac
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Prize 2 - Thé détox */}
|
||||
<div className="bg-white rounded-xl shadow-md hover:shadow-xl transition-shadow overflow-hidden border border-[#e5e4dc] h-full flex flex-col">
|
||||
<div className="aspect-square bg-gradient-to-br from-[#faf9f5] to-[#f5f5f0] flex items-center justify-center p-2">
|
||||
<Image
|
||||
src="/images/lots/the-detox.png"
|
||||
alt="Boîte 100g thé détox"
|
||||
width={400}
|
||||
height={400}
|
||||
className="w-full h-full object-contain object-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<div className="inline-block bg-gradient-to-r from-[#d4a574]/20 to-[#c4956a]/20 text-[#c4956a] text-sm font-bold px-3 py-1 rounded-full mb-3">
|
||||
20% des lots
|
||||
</div>
|
||||
<h3 className="text-xl font-bold text-[#5a5a4e] mb-2">Boîte 100g thé détox</h3>
|
||||
<p className="text-[#8a8a7a] text-sm mb-4">
|
||||
Mélange détox aux plantes bio : menthe, citronnelle, fenouil et gingembre
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Prize 3 - Thé signature */}
|
||||
<div className="bg-white rounded-xl shadow-md hover:shadow-xl transition-shadow overflow-hidden border border-[#e5e4dc] h-full flex flex-col">
|
||||
<div className="aspect-square bg-gradient-to-br from-[#faf9f5] to-[#f5f5f0] flex items-center justify-center p-2">
|
||||
<Image
|
||||
src="/images/lots/the-signature.png"
|
||||
alt="Boîte 100g thé signature"
|
||||
width={400}
|
||||
height={400}
|
||||
className="w-full h-full object-contain object-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<div className="inline-block bg-gradient-to-r from-[#d4a574]/20 to-[#c4956a]/20 text-[#c4956a] text-sm font-bold px-3 py-1 rounded-full mb-3">
|
||||
10% des lots
|
||||
</div>
|
||||
<h3 className="text-xl font-bold text-[#5a5a4e] mb-2">Boîte 100g thé signature</h3>
|
||||
<p className="text-[#8a8a7a] text-sm mb-4">
|
||||
Notre mélange signature exclusif : Earl Grey aux agrumes et pétales de fleurs
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Prize 4 - Coffret 39€ */}
|
||||
<div className="bg-white rounded-xl shadow-md hover:shadow-xl transition-shadow overflow-hidden border border-[#e5e4dc] h-full flex flex-col">
|
||||
<div className="aspect-square bg-gradient-to-br from-[#faf9f5] to-[#f5f5f0] flex items-center justify-center p-2">
|
||||
<Image
|
||||
src="/images/lots/coffret-39.png"
|
||||
alt="Coffret découverte 39€"
|
||||
width={400}
|
||||
height={400}
|
||||
className="w-full h-full object-contain object-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<div className="inline-block bg-gradient-to-r from-[#d4a574]/20 to-[#c4956a]/20 text-[#c4956a] text-sm font-bold px-3 py-1 rounded-full mb-3">
|
||||
6% des lots
|
||||
</div>
|
||||
<h3 className="text-xl font-bold text-[#5a5a4e] mb-2">Coffret découverte 39€</h3>
|
||||
<p className="text-[#8a8a7a] text-sm mb-4">
|
||||
Sélection de nos 3 thés premium dans un élégant coffret cadeau
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Prize 5 - Coffret 69€ */}
|
||||
<div className="bg-white rounded-xl shadow-md hover:shadow-xl transition-shadow overflow-hidden border border-[#e5e4dc] h-full flex flex-col">
|
||||
<div className="aspect-square bg-gradient-to-br from-[#faf9f5] to-[#f5f5f0] flex items-center justify-center p-2">
|
||||
<Image
|
||||
src="/images/lots/coffret-69.jpg"
|
||||
alt="Coffret prestige 69€"
|
||||
width={400}
|
||||
height={400}
|
||||
className="w-full h-full object-contain object-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<div className="inline-block bg-gradient-to-r from-[#d4a574]/20 to-[#c4956a]/20 text-[#c4956a] text-sm font-bold px-3 py-1 rounded-full mb-3">
|
||||
4% des lots
|
||||
</div>
|
||||
<h3 className="text-xl font-bold text-[#5a5a4e] mb-2">Coffret prestige 69€</h3>
|
||||
<p className="text-[#8a8a7a] text-sm mb-4">
|
||||
Collection premium : 5 thés d'exception avec accessoires dans un coffret luxe
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Prize 6 - Tirage Final */}
|
||||
<div className="bg-white rounded-xl shadow-md hover:shadow-xl transition-shadow overflow-hidden border-2 border-[#d4a574] h-full flex flex-col">
|
||||
<div className="aspect-square bg-gradient-to-br from-[#d4a574]/10 to-[#c4956a]/10 flex items-center justify-center p-2">
|
||||
<Image
|
||||
src="/images/lots/grand-prix.png"
|
||||
alt="Grand prix - 1 an de thé"
|
||||
width={400}
|
||||
height={400}
|
||||
className="w-full h-full object-contain object-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<div className="inline-block bg-gradient-to-r from-[#d4a574] to-[#c4956a] text-white text-sm font-bold px-3 py-1 rounded-full mb-3 shadow-md">
|
||||
1 an de THÉ
|
||||
</div>
|
||||
<h3 className="text-xl font-bold text-[#5a5a4e] mb-2">Tirage Final</h3>
|
||||
<p className="text-[#8a8a7a] text-sm mb-4">
|
||||
Livraison mensuelle pendant 12 mois
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{PRIZES.map((prize, index) => (
|
||||
<PrizeCard key={index} {...prize} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
68
components/ui/PrizeCard.tsx
Normal file
68
components/ui/PrizeCard.tsx
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import Image from 'next/image';
|
||||
import { cn } from '@/utils/helpers';
|
||||
|
||||
interface PrizeCardProps {
|
||||
imageSrc: string;
|
||||
imageAlt: string;
|
||||
badge: string;
|
||||
title: string;
|
||||
description: string;
|
||||
isGrandPrix?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const PrizeCard: React.FC<PrizeCardProps> = ({
|
||||
imageSrc,
|
||||
imageAlt,
|
||||
badge,
|
||||
title,
|
||||
description,
|
||||
isGrandPrix = false,
|
||||
className,
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'bg-white rounded-xl shadow-md hover:shadow-xl transition-shadow overflow-hidden h-full flex flex-col',
|
||||
isGrandPrix ? 'border-2 border-[#d4a574]' : 'border border-[#e5e4dc]',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'aspect-square flex items-center justify-center p-2',
|
||||
isGrandPrix
|
||||
? 'bg-gradient-to-br from-[#d4a574]/10 to-[#c4956a]/10'
|
||||
: 'bg-gradient-to-br from-[#faf9f5] to-[#f5f5f0]'
|
||||
)}
|
||||
>
|
||||
<Image
|
||||
src={imageSrc}
|
||||
alt={imageAlt}
|
||||
width={400}
|
||||
height={400}
|
||||
className="w-full h-full object-contain object-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<div
|
||||
className={cn(
|
||||
'inline-block text-sm font-bold px-3 py-1 rounded-full mb-3',
|
||||
isGrandPrix
|
||||
? 'bg-gradient-to-r from-[#d4a574] to-[#c4956a] text-white shadow-md'
|
||||
: 'bg-gradient-to-r from-[#d4a574]/20 to-[#c4956a]/20 text-[#c4956a]'
|
||||
)}
|
||||
>
|
||||
{badge}
|
||||
</div>
|
||||
<h3 className="text-xl font-bold text-[#5a5a4e] mb-2">{title}</h3>
|
||||
<p className="text-[#8a8a7a] text-sm mb-4">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrizeCard;
|
||||
|
|
@ -8,5 +8,6 @@ export { LoadingState } from './LoadingState';
|
|||
export { ErrorState } from './ErrorState';
|
||||
export { StatusBadge, getRoleBadgeColor, getTicketStatusColor, getStatusColor } from './StatusBadge';
|
||||
export { StatCard } from './StatCard';
|
||||
export { PrizeCard } from './PrizeCard';
|
||||
export { EmptyState } from './EmptyState';
|
||||
export { Pagination } from './Pagination';
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user