@@ -6,6 +6,7 @@ import Header from "@/components/Header";
66import LoadingSpinner from "@/components/LoadingSpinner" ;
77import NewBadge from "@/components/NewBadge" ;
88import ProductImage from "@/components/ProductImage" ;
9+ import ProductDialog from "@/components/ProductDialog" ;
910import { getPrimaryImageUrl , type Product } from "@/lib/product" ;
1011
1112const basePath = process . env . NEXT_PUBLIC_BASE_PATH ?? "" ;
@@ -15,23 +16,24 @@ function ProductTile({
1516 variant,
1617 delay = 0 ,
1718 elevated = false ,
19+ onSelect,
1820} : {
1921 product : Product ;
2022 variant : "featured" | "standard" | "wide" ;
2123 delay ?: number ;
22- /** Above mascot on home page so card stays opaque */
2324 elevated ?: boolean ;
25+ onSelect : ( product : Product ) => void ;
2426} ) {
25- const href = `/products/${ product . id } ` ;
2627 const price = `$${ ( product . price_cents / 100 ) . toFixed ( 2 ) } ` ;
2728
2829 const elevatedClass = elevated ? "relative z-30" : "" ;
2930
3031 if ( variant === "featured" ) {
3132 return (
32- < Link
33- href = { href }
34- className = { `group relative flex h-full min-h-[280px] flex-col overflow-hidden rounded-2xl border border-slate-300 bg-slate-100 shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-xl hover:shadow-[#6a4ff5]/15 hover:border-[#6a4ff5]/30 animate-card-reveal ${ elevatedClass } ` }
33+ < button
34+ type = "button"
35+ onClick = { ( ) => onSelect ( product ) }
36+ className = { `group relative flex h-full min-h-[280px] w-full flex-col overflow-hidden rounded-2xl border border-slate-300 bg-slate-100 text-left shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-xl hover:shadow-[#6a4ff5]/15 hover:border-[#6a4ff5]/30 animate-card-reveal ${ elevatedClass } ` }
3537 style = { { animationDelay : `${ delay } s` } }
3638 >
3739 { product . is_new && < NewBadge size = "default" /> }
@@ -60,15 +62,16 @@ function ProductTile({
6062 Shop now →
6163 </ span >
6264 </ div >
63- </ Link >
65+ </ button >
6466 ) ;
6567 }
6668
6769 if ( variant === "wide" ) {
6870 return (
69- < Link
70- href = { href }
71- className = { `group relative flex flex-col overflow-hidden rounded-2xl border border-slate-300 bg-white shadow-sm transition-all duration-300 hover:-translate-y-1 hover:border-[#6a4ff5]/30 hover:shadow-xl hover:shadow-[#6a4ff5]/10 animate-card-reveal sm:flex-row ${ elevatedClass } ` }
71+ < button
72+ type = "button"
73+ onClick = { ( ) => onSelect ( product ) }
74+ className = { `group relative flex w-full flex-col overflow-hidden rounded-2xl border border-slate-300 bg-white text-left shadow-sm transition-all duration-300 hover:-translate-y-1 hover:border-[#6a4ff5]/30 hover:shadow-xl hover:shadow-[#6a4ff5]/10 animate-card-reveal sm:flex-row ${ elevatedClass } ` }
7275 style = { { animationDelay : `${ delay } s` } }
7376 >
7477 { product . is_new && < NewBadge size = "default" /> }
@@ -98,15 +101,16 @@ function ProductTile({
98101 </ p >
99102 ) }
100103 </ div >
101- </ Link >
104+ </ button >
102105 ) ;
103106 }
104107
105108 // standard
106109 return (
107- < Link
108- href = { href }
109- className = { `group relative flex flex-col overflow-hidden rounded-2xl border border-slate-300 bg-white shadow-sm transition-all duration-300 hover:-translate-y-1 hover:border-[#6a4ff5]/30 hover:shadow-xl hover:shadow-[#6a4ff5]/10 animate-card-reveal ${ elevatedClass } ` }
110+ < button
111+ type = "button"
112+ onClick = { ( ) => onSelect ( product ) }
113+ className = { `group relative flex w-full flex-col overflow-hidden rounded-2xl border border-slate-300 bg-white text-left shadow-sm transition-all duration-300 hover:-translate-y-1 hover:border-[#6a4ff5]/30 hover:shadow-xl hover:shadow-[#6a4ff5]/10 animate-card-reveal ${ elevatedClass } ` }
110114 style = { { animationDelay : `${ delay } s` } }
111115 >
112116 { product . is_new && < NewBadge size = "default" /> }
@@ -131,14 +135,15 @@ function ProductTile({
131135 </ h2 >
132136 < p className = "mt-1 font-semibold text-[#6a4ff5]" > { price } </ p >
133137 </ div >
134- </ Link >
138+ </ button >
135139 ) ;
136140}
137141
138142export default function Home ( ) {
139143 const [ products , setProducts ] = useState < Product [ ] > ( [ ] ) ;
140144 const [ loading , setLoading ] = useState ( true ) ;
141145 const [ error , setError ] = useState < string | null > ( null ) ;
146+ const [ selectedProduct , setSelectedProduct ] = useState < Product | null > ( null ) ;
142147
143148 useEffect ( ( ) => {
144149 fetch ( `${ basePath } /api/products` )
@@ -207,26 +212,26 @@ export default function Home() {
207212 : ""
208213 }
209214 >
210- < ProductTile product = { featured } variant = "featured" delay = { 0 } elevated />
215+ < ProductTile product = { featured } variant = "featured" delay = { 0 } elevated onSelect = { setSelectedProduct } />
211216 </ div >
212217 ) }
213218 { /* Side tiles - products 2 and 3 stacked on the right (or single tile spans 2 rows) */ }
214219 { rest [ 0 ] && (
215220 < div
216221 className = { `md:col-span-2 ${ rest [ 1 ] ? "md:row-span-1" : "md:row-span-2" } ` }
217222 >
218- < ProductTile product = { rest [ 0 ] } variant = "standard" delay = { 0.06 } elevated />
223+ < ProductTile product = { rest [ 0 ] } variant = "standard" delay = { 0.06 } elevated onSelect = { setSelectedProduct } />
219224 </ div >
220225 ) }
221226 { rest [ 1 ] && (
222227 < div className = "md:col-span-2 md:row-span-1" >
223- < ProductTile product = { rest [ 1 ] } variant = "standard" delay = { 0.12 } elevated />
228+ < ProductTile product = { rest [ 1 ] } variant = "standard" delay = { 0.12 } elevated onSelect = { setSelectedProduct } />
224229 </ div >
225230 ) }
226231 { /* Bottom row - product 4 as wide horizontal tile */ }
227232 { rest [ 2 ] && (
228233 < div className = "md:col-span-4" >
229- < ProductTile product = { rest [ 2 ] } variant = "wide" delay = { 0.18 } elevated />
234+ < ProductTile product = { rest [ 2 ] } variant = "wide" delay = { 0.18 } elevated onSelect = { setSelectedProduct } />
230235 </ div >
231236 ) }
232237 { /* Products 5+ in a grid */ }
@@ -239,6 +244,7 @@ export default function Home() {
239244 variant = "standard"
240245 delay = { 0.24 + i * 0.06 }
241246 elevated
247+ onSelect = { setSelectedProduct }
242248 />
243249 ) ) }
244250 </ div >
@@ -268,6 +274,13 @@ export default function Home() {
268274 </ div >
269275 </ section >
270276 </ main >
277+
278+ { selectedProduct && (
279+ < ProductDialog
280+ product = { selectedProduct }
281+ onClose = { ( ) => setSelectedProduct ( null ) }
282+ />
283+ ) }
271284 </ div >
272285 ) ;
273286}
0 commit comments