143 lines
3.8 KiB
TypeScript
143 lines
3.8 KiB
TypeScript
"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,
|
|
};
|
|
}
|