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 CHANGED
@@ -266,41 +266,39 @@ function ProductContent() {
266
  </div>
267
  </div>
268
 
269
- {/* === 6. SELLER CARDS WITH COUNTDOWN === */}
270
- {groupBuys.length > 0 && (
271
- <div className="px-3 pt-3 space-y-2">
272
- {groupBuys.slice(0, 2).map((gb) => (
273
- <Card key={gb.id} className="p-3 border-slate-100">
274
- <div className="flex items-center gap-2">
275
- {/* Seller avatar */}
276
- <Link href={`/seller-profile?id=${gb.seller_id || seller?.id}`}>
277
- <div className="w-9 h-9 rounded-full brand-gradient flex items-center justify-center text-white font-bold text-sm shrink-0">
278
- {(seller?.business_name || 'S').charAt(0)}
279
- </div>
280
- </Link>
281
- <div className="flex-1 min-w-0">
282
- <div className="flex items-center gap-1.5">
283
- <span className="font-bold text-sm text-black truncate">{seller?.business_name || 'Seller'}</span>
284
- <span className="border border-primary text-primary text-[10px] font-bold px-1 py-0.5 rounded">Repeat customer</span>
285
- </div>
286
- <div className="flex items-center gap-1 mt-0.5">
287
- <span className="text-primary text-xs font-bold">Ending soon</span>
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
- </Card>
301
- ))}
302
- </div>
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 page
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
  <>