freshyo/apps/web-ui/src/routes/offers.tsx
2026-09-05 11:12:47 +05:30

126 lines
4.2 KiB
TypeScript

import { createFileRoute, useNavigate } from '@tanstack/react-router'
import { useState } from 'react'
import { trpc } from '../lib/trpc-client'
import { Tag, Loader2, AlertCircle } from 'lucide-react'
import { ProductCard } from '../components/ProductCard'
import { AppLayout } from '../components/AppLayout'
import type { OffersSectionProps } from '@packages/shared'
export const Route = createFileRoute('/offers')({ component: OffersPage })
const SHOW_MORE_STEP = 6
function OffersSection({ title, subtitle, products, expanded, onExpand, onProductPress }: OffersSectionProps) {
const visible = expanded ? products : products.slice(0, SHOW_MORE_STEP)
const hasMore = products.length > SHOW_MORE_STEP && !expanded
return (
<section className="mb-10">
<div className="section-rule mb-5">
<h2 className="display-2 text-gray-900">{title}</h2>
<p className="mt-1 text-sm text-gray-500">{subtitle}</p>
</div>
{products.length === 0 ? (
<div className="flex flex-col items-center justify-center py-10">
<Tag className="mb-2 h-7 w-7 text-gray-400" />
<p className="text-gray-500">No {title.toLowerCase()} available right now</p>
</div>
) : (
<>
<div className="grid grid-cols-2 gap-3 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
{visible.map((item: any) => (
<ProductCard
key={item.id}
item={item}
onPress={() => onProductPress(item.id)}
showDeliveryInfo={false}
miniView={true}
useAddToCartDialog={true}
/>
))}
</div>
{hasMore && (
<div className="mt-6 flex justify-center">
<button
onClick={onExpand}
className="rounded-lg border border-gray-200 bg-white px-6 py-2.5 text-sm font-bold text-gray-800 shadow-sm transition-colors hover:border-brand-300 hover:text-brand-700"
>
Show More
</button>
</div>
)}
</>
)}
</section>
)
}
function OffersPage() {
const navigate = useNavigate()
const [expandedOffers, setExpandedOffers] = useState(false)
const [expandedCombos, setExpandedCombos] = useState(false)
const { data, isLoading, error } = trpc.user.product.getOffersPage.useQuery()
const combos = data?.combos || []
const offers = data?.offers || []
const handleProductPress = (id: number) => {
navigate({ to: '/home/product/$id', params: { id: String(id) } })
}
if (isLoading) {
return (
<AppLayout>
<div className="flex min-h-screen items-center justify-center">
<Loader2 className="h-8 w-8 animate-spin text-brand-500" />
<p className="ml-3 text-gray-600">Loading offers...</p>
</div>
</AppLayout>
)
}
if (error) {
return (
<AppLayout>
<div className="flex min-h-screen flex-col items-center justify-center p-4">
<AlertCircle className="mb-2 h-12 w-12 text-red-500" />
<p className="text-center text-red-600">Failed to load offers. Please try again.</p>
</div>
</AppLayout>
)
}
return (
<AppLayout>
<div className="mx-auto min-h-screen w-full max-w-7xl px-4 py-6 pb-24 md:px-8 md:pb-12">
<div className="mb-6">
<p className="text-[11px] font-black uppercase tracking-[0.22em] text-brand-600">
Deals & Bundles
</p>
<h1 className="display-2 mt-1 text-gray-900">Offers</h1>
<p className="mt-1 text-gray-500">Great prices on select items</p>
</div>
<OffersSection
title="Offers"
subtitle="Great prices on select items"
products={offers}
expanded={expandedOffers}
onExpand={() => setExpandedOffers(true)}
onProductPress={handleProductPress}
/>
<OffersSection
title="Combos"
subtitle="Bundle your favorites and save"
products={combos}
expanded={expandedCombos}
onExpand={() => setExpandedCombos(true)}
onProductPress={handleProductPress}
/>
</div>
</AppLayout>
)
}