Spaces:
Sleeping
Sleeping
eeshaAI commited on
Commit ·
025f320
1
Parent(s): 5ac7518
feat: Migrate frontend from static HTML to Next.js 16 App Router
Browse files- All 16 buyer pages: home, login, product, cart, checkout, payment,
categories, search, seller-profile, profile, orders, wishlist,
videos, live, live-watch, group-buy, ai-chat, link-account, telegram
- 7 seller dashboard pages with shared sidebar layout
- 22 API route proxies to existing Supabase Edge Functions
- Suspense boundaries for useSearchParams pages
- Standalone output build for Docker deployment
- Dockerfile (multi-stage Node 20 alpine, port 7860)
- README with HF Space YAML frontmatter
- .hfignore for lean Docker context
Backend unchanged: 27 Supabase Edge Functions, Render bot, OpenWA,
PalmPay payment verifier — all remain in place.
- src/app/product/page.tsx +31 -33
- src/components/layout-shell.tsx +2 -2
src/app/product/page.tsx
CHANGED
|
@@ -266,41 +266,39 @@ function ProductContent() {
|
|
| 266 |
</div>
|
| 267 |
</div>
|
| 268 |
|
| 269 |
-
{/* === 6. SELLER CARDS WITH COUNTDOWN === */}
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
{
|
| 273 |
-
<
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
<
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
<div className="flex-
|
| 282 |
-
<
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
<
|
| 287 |
-
|
| 288 |
-
<span className="text-black text-xs font-mono">{formatCountdown()}</span>
|
| 289 |
-
</div>
|
| 290 |
</div>
|
| 291 |
-
<button
|
| 292 |
-
onClick={buyNow}
|
| 293 |
-
disabled={adding}
|
| 294 |
-
className="relative brand-gradient text-white font-bold text-sm px-4 py-2 rounded-lg"
|
| 295 |
-
>
|
| 296 |
-
Buy Now
|
| 297 |
-
<span className="absolute -top-1.5 -right-1.5 bg-yellow-400 text-primary text-[9px] font-bold px-1 py-0.5 rounded">Ready</span>
|
| 298 |
-
</button>
|
| 299 |
</div>
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 304 |
|
| 305 |
{/* === 7. SHIPPING / RETURNS ROW === */}
|
| 306 |
<div className="px-3 pt-3">
|
|
|
|
| 266 |
</div>
|
| 267 |
</div>
|
| 268 |
|
| 269 |
+
{/* === 6. SELLER CARDS WITH COUNTDOWN (always show at least 1 card) === */}
|
| 270 |
+
<div className="px-3 pt-3 space-y-2">
|
| 271 |
+
{(groupBuys.length > 0 ? groupBuys.slice(0, 2) : [null, null]).map((gb, i) => (
|
| 272 |
+
<Card key={gb?.id || i} className="p-3 border-slate-100">
|
| 273 |
+
<div className="flex items-center gap-2">
|
| 274 |
+
{/* Seller avatar */}
|
| 275 |
+
<Link href={`/seller-profile?id=${gb?.seller_id || seller?.id || ''}`}>
|
| 276 |
+
<div className="w-9 h-9 rounded-full brand-gradient flex items-center justify-center text-white font-bold text-sm shrink-0">
|
| 277 |
+
{(seller?.business_name || 'S').charAt(0)}
|
| 278 |
+
</div>
|
| 279 |
+
</Link>
|
| 280 |
+
<div className="flex-1 min-w-0">
|
| 281 |
+
<div className="flex items-center gap-1.5">
|
| 282 |
+
<span className="font-bold text-sm text-black truncate">{seller?.business_name || 'Seller'}</span>
|
| 283 |
+
<span className="border border-primary text-primary text-[10px] font-bold px-1 py-0.5 rounded">Repeat customer</span>
|
| 284 |
+
</div>
|
| 285 |
+
<div className="flex items-center gap-1 mt-0.5">
|
| 286 |
+
<span className="text-primary text-xs font-bold">Ending soon</span>
|
| 287 |
+
<span className="text-black text-xs font-mono">{formatCountdown()}</span>
|
|
|
|
|
|
|
| 288 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
</div>
|
| 290 |
+
<button
|
| 291 |
+
onClick={buyNow}
|
| 292 |
+
disabled={adding}
|
| 293 |
+
className="relative brand-gradient text-white font-bold text-sm px-4 py-2 rounded-lg"
|
| 294 |
+
>
|
| 295 |
+
Buy Now
|
| 296 |
+
<span className="absolute -top-1.5 -right-1.5 bg-yellow-400 text-primary text-[9px] font-bold px-1 py-0.5 rounded">Ready</span>
|
| 297 |
+
</button>
|
| 298 |
+
</div>
|
| 299 |
+
</Card>
|
| 300 |
+
))}
|
| 301 |
+
</div>
|
| 302 |
|
| 303 |
{/* === 7. SHIPPING / RETURNS ROW === */}
|
| 304 |
<div className="px-3 pt-3">
|
src/components/layout-shell.tsx
CHANGED
|
@@ -15,8 +15,8 @@ import { MobileNav } from '@/components/mobile-nav';
|
|
| 15 |
export function LayoutShell({ children }: { children: React.ReactNode }) {
|
| 16 |
const pathname = usePathname();
|
| 17 |
|
| 18 |
-
// Hide mobile nav on login
|
| 19 |
-
const hideMobileNav = pathname === '/login';
|
| 20 |
|
| 21 |
return (
|
| 22 |
<>
|
|
|
|
| 15 |
export function LayoutShell({ children }: { children: React.ReactNode }) {
|
| 16 |
const pathname = usePathname();
|
| 17 |
|
| 18 |
+
// Hide mobile nav on login + product detail pages (they have their own bottom bars)
|
| 19 |
+
const hideMobileNav = pathname === '/login' || pathname.startsWith('/product');
|
| 20 |
|
| 21 |
return (
|
| 22 |
<>
|