Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/app/delivery/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,20 @@ interface DeliveryOrder extends OrderWithDetails {

export default function DeliveryDashboard() {
const { deliveryPersonId } = useAuth();
const { assignments, loading, error } = useDeliveryAssignments(deliveryPersonId!);
const { assignments, loading, error } = useDeliveryAssignments(deliveryPersonId ?? '');
const [updating, setUpdating] = useState<string | null>(null);

if (!deliveryPersonId) {
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex items-center justify-center">
<div className="text-center">
<div className="w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
<p className="text-gray-500 dark:text-gray-400">Setting up delivery account...</p>
</div>
</div>
);
}

const handleStatusUpdate = async (
assignmentId: string,
newStatus: 'accepted' | 'picked_up' | 'delivered'
Expand Down
7 changes: 2 additions & 5 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "./globals.css";
import { RoleProvider } from "@/hooks/use-role";
import { AuthProvider } from "@/hooks/use-auth";
import { CartProvider } from "@/hooks/use-cart";
import { AppHeader } from "@/components/shared/app-header";

const geistSans = Geist({
variable: "--font-geist-sans",
Expand Down Expand Up @@ -38,13 +39,9 @@ export default function RootLayout({
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{process.env.NEXT_PUBLIC_DEMO_MODE === 'true' && (
<div className="bg-amber-500 text-white text-center text-xs py-1">
DEMO MODE
</div>
)}
<RoleProvider>
<AuthProvider>
<AppHeader />
<CartProvider>
{children}
</CartProvider>
Expand Down
262 changes: 120 additions & 142 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
'use client';

import Link from "next/link";
import { useRouter } from "next/navigation";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { ShoppingBag, Store, Truck, LogOut } from "lucide-react";
import { ShoppingBag, Store, Truck } from "lucide-react";
import { DEMO_MODE } from "@/lib/config/demo";
import { useAuth } from "@/hooks/use-auth";
import { useRole } from "@/hooks/use-role";
import type { UserRole } from "@/types";

const roles = [
{
name: "Customer",
role: "customer" as UserRole,
description: "Browse local vendors, add items to your cart, and place orders for delivery.",
href: "/vendors",
icon: ShoppingBag,
Expand All @@ -19,6 +23,7 @@ const roles = [
},
{
name: "Vendor",
role: "vendor" as UserRole,
description: "View incoming orders, update order status, and communicate with customers.",
href: "/vendor",
icon: Store,
Expand All @@ -28,6 +33,7 @@ const roles = [
},
{
name: "Delivery",
role: "delivery" as UserRole,
description: "Accept delivery requests, navigate to pickups, and complete deliveries.",
href: "/delivery",
icon: Truck,
Expand All @@ -38,178 +44,150 @@ const roles = [
];

export default function Home() {
const { user, loading, signOut } = useAuth();
const { user, loading } = useAuth();
const { setRole } = useRole();
const router = useRouter();

const handleRoleClick = (role: UserRole, href: string) => {
setRole(role);
router.push(href);
};

if (!DEMO_MODE) {
// Authenticated user: show role-based navigation
if (user && !loading) {
return (
<div className="min-h-screen bg-background">
<header className="border-b bg-background">
<div className="container flex h-16 items-center justify-between px-4">
<h1 className="text-2xl font-bold">Project Firefly</h1>
<div className="flex items-center gap-3">
<span className="text-sm text-muted-foreground">{user.name}</span>
<Button variant="ghost" size="sm" onClick={signOut}>
<LogOut className="h-4 w-4 mr-1" />
Sign Out
</Button>
</div>
</div>
</header>

<main className="container px-4 py-8">
<div className="mx-auto max-w-3xl space-y-8">
<div className="text-center space-y-2">
<p className="text-lg text-muted-foreground">
Welcome back, {user.name}
</p>
<p className="text-sm text-muted-foreground">
Select a role to continue
</p>
</div>

<div className="grid gap-4 md:grid-cols-3">
{roles.map((role) => (
<Link key={role.name} href={role.href}>
<Card className={`h-full transition-colors border-2 ${role.borderColor} ${role.hoverBg} cursor-pointer`}>
<CardHeader className="text-center pb-2">
<div className={`mx-auto mb-2 flex h-12 w-12 items-center justify-center rounded-full ${role.color} text-white`}>
<role.icon className="h-6 w-6" />
</div>
<CardTitle className="text-lg">{role.name}</CardTitle>
</CardHeader>
<CardContent>
<CardDescription className="text-center">
{role.description}
</CardDescription>
</CardContent>
</Card>
</Link>
))}
</div>
</div>
</main>
</div>
);
}

// Not authenticated: show sign-in / create account
return (
<div className="min-h-screen bg-background">
<header className="border-b bg-background">
<div className="container flex h-16 items-center justify-center px-4">
<h1 className="text-2xl font-bold">Project Firefly</h1>
</div>
</header>

<main className="container px-4 py-8">
<div className="mx-auto max-w-md space-y-8 text-center">
<div className="space-y-2">
<div className="mx-auto max-w-3xl space-y-8">
<div className="text-center space-y-2">
<p className="text-lg text-muted-foreground">
Community-powered food ordering for local co-ops
Welcome back, {user.name}
</p>
<p className="text-sm text-muted-foreground">
Order from local vendors, delivered by your neighbors
Select a role to continue
</p>
</div>

<div className="grid grid-cols-3 gap-4">
<div className="grid gap-4 md:grid-cols-3">
{roles.map((role) => (
<div key={role.name} className="text-center">
<div className={`mx-auto mb-2 flex h-12 w-12 items-center justify-center rounded-full ${role.color} text-white`}>
<role.icon className="h-6 w-6" />
</div>
<p className="text-sm font-medium">{role.name}</p>
</div>
<button key={role.name} onClick={() => handleRoleClick(role.role, role.href)} className="text-left">
<Card className={`h-full transition-colors border-2 ${role.borderColor} ${role.hoverBg} cursor-pointer`}>
<CardHeader className="text-center pb-2">
<div className={`mx-auto mb-2 flex h-12 w-12 items-center justify-center rounded-full ${role.color} text-white`}>
<role.icon className="h-6 w-6" />
</div>
<CardTitle className="text-lg">{role.name}</CardTitle>
</CardHeader>
<CardContent>
<CardDescription className="text-center">
{role.description}
</CardDescription>
</CardContent>
</Card>
</button>
))}
</div>

<div className="space-y-3">
<Link href="/login">
<Button className="w-full bg-green-600 hover:bg-green-700 h-12 text-base">
Sign In
</Button>
</Link>
<Link href="/register">
<Button variant="outline" className="w-full h-12 text-base">
Create Account
</Button>
</Link>
<Link href="/vendors">
<Button variant="ghost" className="w-full text-sm text-muted-foreground">
Browse vendors without signing in
</Button>
</Link>
</div>
</div>
</main>
</div>
);
}

return (
<div className="min-h-screen bg-background">
{/* Header */}
<header className="border-b bg-background">
<div className="container flex h-16 items-center justify-center px-4">
<h1 className="text-2xl font-bold">Project Firefly Demo</h1>
</div>
</header>
);
}

{/* Main Content */}
// Not authenticated: show sign-in / create account
return (
<main className="container px-4 py-8">
<div className="mx-auto max-w-3xl space-y-8">
{/* Description */}
<div className="text-center space-y-2">
<div className="mx-auto max-w-md space-y-8 text-center">
<div className="space-y-2">
<p className="text-lg text-muted-foreground">
Community-powered food ordering for local co-ops
</p>
<p className="text-sm text-muted-foreground">
Select a role below to explore the demo
Order from local vendors, delivered by your neighbors
</p>
</div>

{/* Role Cards */}
<div className="grid gap-4 md:grid-cols-3">
<div className="grid grid-cols-3 gap-4">
{roles.map((role) => (
<Link key={role.name} href={role.href}>
<Card className={`h-full transition-colors border-2 ${role.borderColor} ${role.hoverBg} cursor-pointer`}>
<CardHeader className="text-center pb-2">
<div className={`mx-auto mb-2 flex h-12 w-12 items-center justify-center rounded-full ${role.color} text-white`}>
<role.icon className="h-6 w-6" />
</div>
<CardTitle className="text-lg">{role.name}</CardTitle>
</CardHeader>
<CardContent>
<CardDescription className="text-center">
{role.description}
</CardDescription>
</CardContent>
</Card>
</Link>
<div key={role.name} className="text-center">
<div className={`mx-auto mb-2 flex h-12 w-12 items-center justify-center rounded-full ${role.color} text-white`}>
<role.icon className="h-6 w-6" />
</div>
<p className="text-sm font-medium">{role.name}</p>
</div>
))}
</div>

{/* Instructions */}
<Card>
<CardHeader>
<CardTitle className="text-lg">How to Test the Full Flow</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<ol className="list-decimal list-inside space-y-2 text-sm text-muted-foreground">
<li>Open <strong>3 browser tabs</strong> (or use incognito windows)</li>
<li>In Tab 1: Click <strong>Customer</strong> → Browse vendors and place an order</li>
<li>In Tab 2: Click <strong>Vendor</strong> → Watch for incoming orders and accept them</li>
<li>In Tab 3: Click <strong>Delivery</strong> → Accept the delivery and mark it complete</li>
</ol>
<p className="text-xs text-muted-foreground pt-2 border-t">
All roles see real-time updates via Supabase. Changes in one tab appear instantly in others.
</p>
</CardContent>
</Card>
<div className="space-y-3">
<Link href="/login">
<Button className="w-full bg-green-600 hover:bg-green-700 h-12 text-base">
Sign In
</Button>
</Link>
<Link href="/register">
<Button variant="outline" className="w-full h-12 text-base">
Create Account
</Button>
</Link>
<Link href="/vendors">
<Button variant="ghost" className="w-full text-sm text-muted-foreground">
Browse vendors without signing in
</Button>
</Link>
</div>
</div>
</main>
</div>
);
}

// Demo mode
return (
<main className="container px-4 py-8">
<div className="mx-auto max-w-3xl space-y-8">
<div className="text-center space-y-2">
<p className="text-lg text-muted-foreground">
Community-powered food ordering for local co-ops
</p>
<p className="text-sm text-muted-foreground">
Select a role below to explore the demo
</p>
</div>

<div className="grid gap-4 md:grid-cols-3">
{roles.map((role) => (
<button key={role.name} onClick={() => handleRoleClick(role.role, role.href)} className="text-left">
<Card className={`h-full transition-colors border-2 ${role.borderColor} ${role.hoverBg} cursor-pointer`}>
<CardHeader className="text-center pb-2">
<div className={`mx-auto mb-2 flex h-12 w-12 items-center justify-center rounded-full ${role.color} text-white`}>
<role.icon className="h-6 w-6" />
</div>
<CardTitle className="text-lg">{role.name}</CardTitle>
</CardHeader>
<CardContent>
<CardDescription className="text-center">
{role.description}
</CardDescription>
</CardContent>
</Card>
</button>
))}
</div>

<Card>
<CardHeader>
<CardTitle className="text-lg">How to Test the Full Flow</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<ol className="list-decimal list-inside space-y-2 text-sm text-muted-foreground">
<li>Open <strong>3 browser tabs</strong> (or use incognito windows)</li>
<li>In Tab 1: Click <strong>Customer</strong> → Browse vendors and place an order</li>
<li>In Tab 2: Click <strong>Vendor</strong> → Watch for incoming orders and accept them</li>
<li>In Tab 3: Click <strong>Delivery</strong> → Accept the delivery and mark it complete</li>
</ol>
<p className="text-xs text-muted-foreground pt-2 border-t">
All roles see real-time updates via Supabase. Changes in one tab appear instantly in others.
</p>
</CardContent>
</Card>
</div>
</main>
);
}
13 changes: 12 additions & 1 deletion src/app/vendor/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,20 @@ interface VendorOrder extends OrderWithDetails {

export default function VendorDashboard() {
const { vendorId } = useAuth();
const { orders, loading, error } = useVendorOrders(vendorId!);
const { orders, loading, error } = useVendorOrders(vendorId ?? '');
const [updating, setUpdating] = useState<string | null>(null);

if (!vendorId) {
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex items-center justify-center">
<div className="text-center">
<div className="w-8 h-8 border-4 border-amber-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
<p className="text-gray-500 dark:text-gray-400">Setting up vendor account...</p>
</div>
</div>
);
}

const handleAcceptOrder = async (orderId: string) => {
setUpdating(orderId);
try {
Expand Down
Loading
Loading