import { useState, useEffect } from "react";
import { useSearch, Link } from "wouter";
import { useQuery, useMutation } from "@tanstack/react-query";
import { queryClient, apiRequest } from "../lib/queryClient";
import { toast } from "../hooks/use-toast";
import { Package, User, LogOut, Mail } from "lucide-react";
interface Customer {
id: number;
email: string;
firstName?: string;
lastName?: string;
phone?: string;
}
interface Order {
id: number;
orderNumber: string;
status: string;
paymentStatus: string;
fulfillmentStatus: string;
total: string;
createdAt: string;
trackingNumber?: string;
trackingCarrier?: string;
}
function LoginForm() {
const [email, setEmail] = useState("");
const [sent, setSent] = useState(false);
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
try {
await apiRequest("POST", "/api/auth/magic-link", { email });
setSent(true);
} catch (err: any) {
toast({ title: "Error", description: err.message, variant: "destructive" });
} finally {
setLoading(false);
}
};
if (sent) {
return (
Check your email
We sent a sign-in link to {email}. Click it to sign in.
Link expires in 15 minutes.
);
}
return (
Sign in
We'll send a magic link to your email — no password needed.
);
}
function AccountDashboard({ customer }: { customer: Customer }) {
const { data: orders, isLoading } = useQuery({
queryKey: ["/api/account/orders"],
queryFn: async () => { const r = await fetch("/api/account/orders", { credentials: "include" }); return r.json(); },
});
const logoutMutation = useMutation({
mutationFn: () => apiRequest("POST", "/api/auth/logout"),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["/api/auth/me"] }),
});
const statusBadge = (status: string) => {
const colors: Record = {
confirmed: "bg-blue-100 text-blue-700",
pending: "bg-yellow-100 text-yellow-700",
cancelled: "bg-red-100 text-red-700",
fulfilled: "bg-green-100 text-green-700",
};
return colors[status] || "bg-muted text-muted-foreground";
};
return (
My Account
{customer.email}
Orders
{isLoading ? (
) : !orders?.length ? (
No orders yet
Start shopping
) : (
{orders.map((order) => (
#{order.orderNumber}
{new Date(order.createdAt).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" })}
{order.status}
${parseFloat(order.total).toFixed(2)}
{order.trackingNumber && (
Tracking: {order.trackingNumber}{order.trackingCarrier && ` (${order.trackingCarrier})`}
)}
))}
)}
);
}
export default function AccountPage() {
const search = useSearch();
const token = new URLSearchParams(search).get("token");
const [verifying, setVerifying] = useState(!!token);
const { data, isLoading } = useQuery<{ customer: Customer | null }>({
queryKey: ["/api/auth/me"],
queryFn: async () => { const r = await fetch("/api/auth/me", { credentials: "include" }); return r.json(); },
});
useEffect(() => {
if (!token) return;
(async () => {
try {
const res = await fetch(`/api/auth/verify?token=${token}`, { credentials: "include" });
if (res.ok) {
await queryClient.invalidateQueries({ queryKey: ["/api/auth/me"] });
toast({ title: "Signed in!", description: "Welcome back." });
} else {
toast({ title: "Link expired", description: "Please request a new sign-in link.", variant: "destructive" });
}
} finally {
setVerifying(false);
window.history.replaceState({}, "", "/account");
}
})();
}, [token]);
if (isLoading || verifying) {
return Loading...
;
}
return (
{data?.customer ? (
) : (
)}
);
}