Revert to guest-cart architecture, drop in-site auth/checkout
Per api.meshkee.com/docs/website/AI_PROMPT.md's hard rules (which an
earlier pass on this branch missed): login, register, OTP, the real
cart, addresses, and payment are the customer dashboard's job
(customer.sanihome.ir), not this storefront's. This site should only
ever run a local guest mini-cart and hand off to the dashboard.
- Remove: AuthContext, LoginModal, lib/auth.ts, lib/cart.ts (the real
/businesses/{id}/cart integration), and the /checkout page entirely.
- Add lib/guestCart.ts: localStorage + shared cookie
(meshkee-guest-cart, Domain=.sanihome.ir) cart, storeItemVariantId
keyed, matching the spec's line shape and ~3500-char cookie-size
cutoff.
- CartContext is now a thin React wrapper over the guest cart (no
server round-trip, so add/update/remove are synchronous); CartPopup's
"Continue" builds the exact customer.sanihome.ir/checkout/cart
(or /login?redirect=...) URL from the spec, base64url-encoding the
cart and detecting an existing dashboard session via the shared
meshkee_customer_access_token cookie.
- ProductCard and ProductPurchasePanel add to the guest cart directly;
no login gate on add-to-cart anymore.
- Comments panel is a plain guest name/email/text form again (the
comments API never required auth — gating it on the now-removed
login system was wrong regardless).
- CONTEXT.md rewritten to document the guest-cart contract explicitly
and flag this exact mistake so it doesn't get reintroduced.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
053a9ba361
commit
5152b16d61
@@ -1,17 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { useAuth } from "@/context/AuthContext";
|
||||
import { useCart } from "@/context/CartContext";
|
||||
|
||||
export function CartButton() {
|
||||
const { user } = useAuth();
|
||||
const { itemCount, openPopup } = useCart();
|
||||
const { openLoginModal } = useAuth();
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={user ? openPopup : openLoginModal}
|
||||
onClick={openPopup}
|
||||
className="relative flex items-center gap-1.5 rounded-lg border border-border px-3 py-2 transition-colors hover:border-red hover:text-red"
|
||||
>
|
||||
<span aria-hidden>🛒</span>
|
||||
|
||||
@@ -4,12 +4,12 @@ import { useEffect, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { formatPrice } from "@/data/sample";
|
||||
import { useCart } from "@/context/CartContext";
|
||||
import { continueToCheckoutUrl } from "@/lib/guestCart";
|
||||
import { EmptyState } from "@/components/ui/EmptyState";
|
||||
|
||||
export function CartPopup() {
|
||||
const { cart, popupOpen, closePopup, updateItem, removeItem } = useCart();
|
||||
const { items, subtotal, popupOpen, closePopup, updateItem, removeItem } = useCart();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const [busyId, setBusyId] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => setMounted(true), []);
|
||||
|
||||
@@ -22,15 +22,6 @@ export function CartPopup() {
|
||||
|
||||
if (!mounted) return null;
|
||||
|
||||
const items = cart?.items ?? [];
|
||||
|
||||
const changeQty = async (itemId: string, quantity: number) => {
|
||||
setBusyId(itemId);
|
||||
if (quantity <= 0) await removeItem(itemId);
|
||||
else await updateItem(itemId, quantity);
|
||||
setBusyId(null);
|
||||
};
|
||||
|
||||
return createPortal(
|
||||
<div aria-hidden={!popupOpen}>
|
||||
<div
|
||||
@@ -65,22 +56,18 @@ export function CartPopup() {
|
||||
<li key={item.id} className="flex gap-3 border-b border-border pb-4">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={item.productImage ?? "/images/placeholder.svg"}
|
||||
alt={item.productNameFa ?? item.productTitle}
|
||||
src={item.image || "/images/placeholder.svg"}
|
||||
alt={item.name}
|
||||
className="h-16 w-16 shrink-0 rounded-lg border border-border object-contain p-1"
|
||||
/>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="line-clamp-2 text-sm font-medium">
|
||||
{item.productNameFa ?? item.productTitle}
|
||||
</p>
|
||||
{item.label && <p className="mt-0.5 text-xs text-muted">{item.label}</p>}
|
||||
<p className="line-clamp-2 text-sm font-medium">{item.name}</p>
|
||||
<div className="mt-2 flex items-center justify-between">
|
||||
<div className="flex items-center rounded-lg border border-border">
|
||||
<button
|
||||
type="button"
|
||||
disabled={busyId === item.id}
|
||||
onClick={() => changeQty(item.id, item.quantity + 1)}
|
||||
className="px-2 py-1 text-sm disabled:opacity-40"
|
||||
onClick={() => updateItem(item.id, item.quantity + 1)}
|
||||
className="px-2 py-1 text-sm"
|
||||
aria-label="افزایش تعداد"
|
||||
>
|
||||
+
|
||||
@@ -88,37 +75,44 @@ export function CartPopup() {
|
||||
<span className="min-w-6 text-center text-xs font-medium">{item.quantity}</span>
|
||||
<button
|
||||
type="button"
|
||||
disabled={busyId === item.id}
|
||||
onClick={() => changeQty(item.id, item.quantity - 1)}
|
||||
className="px-2 py-1 text-sm disabled:opacity-40"
|
||||
onClick={() => updateItem(item.id, item.quantity - 1)}
|
||||
className="px-2 py-1 text-sm"
|
||||
aria-label="کاهش تعداد"
|
||||
>
|
||||
−
|
||||
</button>
|
||||
</div>
|
||||
<span className="text-sm font-bold text-red-dark">
|
||||
{formatPrice(item.lineTotal)}
|
||||
{formatPrice(item.price * item.quantity)}
|
||||
<span className="mr-0.5 text-[11px] font-normal text-muted">تومان</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeItem(item.id)}
|
||||
aria-label="حذف از سبد"
|
||||
className="shrink-0 self-start text-muted transition-colors hover:text-red-dark"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{items.length > 0 && cart && (
|
||||
{items.length > 0 && (
|
||||
<div className="border-t border-border p-5">
|
||||
<div className="mb-4 flex items-center justify-between text-sm">
|
||||
<span className="text-muted">جمع کل</span>
|
||||
<span className="text-base font-bold text-red-dark">
|
||||
{formatPrice(cart.subtotal)}
|
||||
{formatPrice(subtotal)}
|
||||
<span className="mr-0.5 text-xs font-normal text-muted">تومان</span>
|
||||
</span>
|
||||
</div>
|
||||
<a
|
||||
href="/checkout"
|
||||
href={continueToCheckoutUrl(items)}
|
||||
className="block w-full rounded-xl bg-red py-3 text-center text-sm font-medium text-white transition-colors hover:bg-red-dark"
|
||||
>
|
||||
ادامه فرآیند خرید
|
||||
|
||||
Reference in New Issue
Block a user