Connect the storefront to Meshkee catalog, blogs, and static image slots.
Wire homepage specials, product/blog pages, instant search, and the customer portal so the live pharmacy site can be managed from the dashboard. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
cd2f9dfc9d
commit
66e604c426
@@ -0,0 +1,71 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Minus, Plus, ShoppingBag } from "lucide-react";
|
||||
import { customerPortalUrl } from "@/lib/config";
|
||||
|
||||
export function AddToCart({ variantId, maxQuantity }: { variantId: string; maxQuantity?: number | null }) {
|
||||
const [quantity, setQuantity] = useState(1);
|
||||
const [status, setStatus] = useState<"idle" | "loading" | "ok" | "error">("idle");
|
||||
const cap = maxQuantity && maxQuantity > 0 ? maxQuantity : 99;
|
||||
|
||||
const change = (delta: number) => {
|
||||
setQuantity((current) => Math.min(cap, Math.max(1, current + delta)));
|
||||
};
|
||||
|
||||
const add = async () => {
|
||||
const token =
|
||||
window.localStorage.getItem("accessToken") ||
|
||||
window.localStorage.getItem("meshkeeToken") ||
|
||||
window.localStorage.getItem("token");
|
||||
|
||||
if (!token) {
|
||||
window.location.href = customerPortalUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus("loading");
|
||||
try {
|
||||
const response = await fetch("/api/cart/items", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ storeItemVariantId: variantId, quantity }),
|
||||
});
|
||||
if (response.status === 401) {
|
||||
window.location.href = customerPortalUrl;
|
||||
return;
|
||||
}
|
||||
setStatus(response.ok ? "ok" : "error");
|
||||
} catch {
|
||||
setStatus("error");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mt-6 flex flex-col gap-3 sm:flex-row sm:items-center">
|
||||
<div className="flex h-12 items-center rounded-xl border border-line bg-white">
|
||||
<button type="button" className="grid size-12 place-items-center text-navy" onClick={() => change(-1)} aria-label="کاهش">
|
||||
<Minus className="size-4" />
|
||||
</button>
|
||||
<span className="min-w-[2rem] text-center text-[15px] font-bold text-navy">{quantity}</span>
|
||||
<button type="button" className="grid size-12 place-items-center text-navy" onClick={() => change(1)} aria-label="افزایش">
|
||||
<Plus className="size-4" />
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={add}
|
||||
disabled={status === "loading"}
|
||||
className="flex h-12 flex-1 items-center justify-center gap-2 rounded-xl bg-primary text-[14px] font-bold text-white transition hover:bg-primary-hover disabled:opacity-70"
|
||||
>
|
||||
<ShoppingBag className="size-4" />
|
||||
{status === "loading" ? "در حال افزودن..." : "افزودن به سبد خرید"}
|
||||
</button>
|
||||
{status === "ok" ? <p className="text-[12px] text-ok">به سبد اضافه شد.</p> : null}
|
||||
{status === "error" ? <p className="text-[12px] text-sale">افزودن به سبد انجام نشد.</p> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user