fix empty cart
Build and Deploy Docker Images / build_and_deploy (push) Has been cancelled

This commit is contained in:
hamid zarghami
2026-06-15 15:46:21 +03:30
parent 6f729938c0
commit 59e446b66e
2 changed files with 147 additions and 37 deletions
+5 -37
View File
@@ -1,7 +1,5 @@
"use client";
import { useGetFoods } from "@/app/[name]/(Main)/hooks/useMenuData";
import { useGetProfile } from "@/app/[name]/(Profile)/profile/hooks/userProfileData";
import Button from "@/components/button/PrimaryButton";
import NotificationBellIcon from "@/components/icons/NotificationBellIcon";
import MenuItem from "@/components/listview/MenuItem";
@@ -17,49 +15,19 @@ import { useGetAbout } from "../about/hooks/useAboutData";
import CartSkeleton from "./components/CartSkeleton";
import CartSummary from "./components/CartSummary";
import { useCart } from "./hook/useCart";
import { useGetCartItems } from "./hooks/useCartData";
import {
cartItemsToFoods,
guestCartItemsToFoods,
hasCartEntries,
} from "./lib/cartUtils";
import { useCartPageState } from "./hooks/useCartPageState";
const CartPage = () => {
const { t } = useTranslation("parallels", { keyPrefix: "Cart" });
const router = useRouter();
const { isSuccess } = useGetProfile();
const { clearCart, items } = useCart();
const { data: cartData, isPending: cartPending } = useGetCartItems(isSuccess);
const { data: foodsResponse } = useGetFoods();
const { clearCart } = useCart();
const { data: aboutData } = useGetAbout();
const { isLoading, isCartEmpty, hasItems, cartFoods } = useCartPageState();
const [showClearConfirm, setShowClearConfirm] = React.useState(false);
const [showPagerModal, setShowPagerModal] = React.useState(false);
const isPremium = aboutData?.data?.plan === "premium";
const cartFoods = React.useMemo(() => {
const foods = foodsResponse?.data ?? [];
if (isSuccess) {
const apiItems = cartData?.data?.items ?? [];
return cartItemsToFoods(apiItems, foods);
}
return guestCartItemsToFoods(items, foods);
}, [isSuccess, cartData?.data?.items, items, foodsResponse?.data]);
const hasItems = React.useMemo(() => {
if (isSuccess) {
return (cartData?.data?.totalItems ?? 0) > 0 || hasCartEntries(items);
}
return hasCartEntries(items);
}, [isSuccess, cartData?.data?.totalItems, items]);
const guestAwaitingMenu =
!isSuccess && hasItems && cartFoods.length === 0 && !foodsResponse?.data;
const showInitialCartLoad = isSuccess && cartPending && !cartData && hasItems;
const isCartEmpty = !hasItems;
const handleClearCart = (e: React.MouseEvent) => {
e?.preventDefault();
e?.stopPropagation();
@@ -76,7 +44,7 @@ const CartPage = () => {
return (
<div className="overflow-y-auto h-full noscrollbar flex flex-col bg-background">
<div className="grid grid-cols-3 items-center mt-6">
{isCartEmpty ? (
{isCartEmpty || isLoading ? (
<span></span>
) : (
<Trash
@@ -98,7 +66,7 @@ const CartPage = () => {
</div>
<div className="mt-8 flex-1 h-full">
{showInitialCartLoad || guestAwaitingMenu ? (
{isLoading ? (
<CartSkeleton />
) : isCartEmpty ? (
<div className="flex flex-col items-center justify-center gap-4 h-full">
@@ -0,0 +1,142 @@
"use client";
import { useGetFoods } from "@/app/[name]/(Main)/hooks/useMenuData";
import { useGetProfile } from "@/app/[name]/(Profile)/profile/hooks/userProfileData";
import { hasAuthToken } from "@/lib/api/func";
import { useReceiptStore } from "@/zustand/receiptStore";
import { useEffect, useMemo, useState } from "react";
import {
cartItemsToFoods,
guestCartItemsToFoods,
hasCartEntries,
} from "../lib/cartUtils";
import { useBulkCart, useGetCartItems } from "./useCartData";
function useReceiptHydrated() {
const [hydrated, setHydrated] = useState(() =>
useReceiptStore.persist.hasHydrated()
);
useEffect(() => {
const unsub = useReceiptStore.persist.onFinishHydration(() =>
setHydrated(true)
);
setHydrated(useReceiptStore.persist.hasHydrated());
return unsub;
}, []);
return hydrated;
}
export function useCartPageState() {
const {
isSuccess,
isPending: profilePending,
isFetched: profileFetched,
} = useGetProfile();
const localItems = useReceiptStore((state) => state.items);
const clearLocalCart = useReceiptStore((state) => state.clear);
const receiptHydrated = useReceiptHydrated();
const [offlineSyncState, setOfflineSyncState] = useState<
"idle" | "syncing" | "done"
>("idle");
const {
data: cartData,
isPending: cartPending,
isFetching: cartFetching,
isFetched: cartFetched,
} = useGetCartItems(isSuccess);
const { mutate: mutateBulkCart, isPending: bulkSyncPending } = useBulkCart();
const { data: foodsResponse, isPending: foodsPending } = useGetFoods();
const foods = foodsResponse?.data ?? [];
const apiItems = cartData?.data?.items ?? [];
const apiTotalItems = cartData?.data?.totalItems ?? 0;
const apiHasItems =
apiTotalItems > 0 || apiItems.some((item) => item.quantity > 0);
const localHasItems = hasCartEntries(localItems);
useEffect(() => {
if (
!isSuccess ||
!cartFetched ||
apiHasItems ||
!localHasItems ||
offlineSyncState !== "idle" ||
bulkSyncPending
) {
return;
}
const bulkItems = Object.entries(localItems)
.filter(([, detail]) => detail?.quantity && detail.quantity > 0)
.map(([foodId, detail]) => ({
foodId: String(foodId),
quantity: detail.quantity,
}));
if (bulkItems.length === 0) {
return;
}
setOfflineSyncState("syncing");
mutateBulkCart(
{ items: bulkItems },
{
onSuccess: () => clearLocalCart(),
onSettled: () => setOfflineSyncState("done"),
}
);
}, [
isSuccess,
cartFetched,
apiHasItems,
localHasItems,
localItems,
bulkSyncPending,
offlineSyncState,
mutateBulkCart,
clearLocalCart,
]);
const cartFoods = useMemo(() => {
if (isSuccess) {
return cartItemsToFoods(apiItems, foods);
}
return guestCartItemsToFoods(localItems, foods);
}, [isSuccess, apiItems, localItems, foods]);
const isAuthResolving =
hasAuthToken() && (!profileFetched || profilePending);
const isCartResolving = isSuccess && (!cartFetched || cartPending);
const isCartRefetchingEmpty =
isSuccess && cartFetched && cartFetching && !apiHasItems;
const needsOfflineSync =
isSuccess && cartFetched && localHasItems && !apiHasItems;
const isOfflineSyncing = needsOfflineSync && offlineSyncState !== "done";
const isGuestHydrating = !hasAuthToken() && !receiptHydrated;
const guestAwaitingMenu =
!isSuccess &&
localHasItems &&
cartFoods.length === 0 &&
(foodsPending || foods.length === 0);
const isLoading =
isAuthResolving ||
isCartResolving ||
isCartRefetchingEmpty ||
isOfflineSyncing ||
isGuestHydrating ||
guestAwaitingMenu;
const hasItems = isSuccess ? apiHasItems : localHasItems;
const isCartEmpty = !isLoading && !hasItems;
return {
isLoading,
isCartEmpty,
hasItems,
cartFoods,
};
}