| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- "use client";
- import {useState, useRef, useEffect, useCallback} from "react";
- import clsx from "clsx";
- import {CartDetail} from "@/types/cart/type";
- import {clientFetch} from "@/lib/restApiClient";
- import { useCustomToast } from "@/utils/hooks/useToast";
- import {useSaveCheckoutCart} from "@/utils/hooks/useSaveCheckoutCart";
- import { formatCartDetail } from "@/utils/cartDetailTools";
- import { overlayLoading } from "@/components/theme/ui/kernel/loading/api";
- import {GiftCardItem, GiftCardRespBody} from "@/types/api/gift/my-gift-cards";
- import CommonModal from "@/components/theme/ui/CommonModal";
- import { LoadingSpinner } from "@components/common/LoadingSpinner";
- export default function CheckoutGiftCardGate({
- giftcardNumber,
- formattedGiftcardAmount,
- onChangeGiftcard
- }: {
- giftcardNumber: string;
- formattedGiftcardAmount: string;
- onChangeGiftcard: (payload:CartDetail) => void;
- }) {
- const [isShow, setIsShow] = useState(false);
- const [giftCardsList, setGiftCardsList] = useState<GiftCardItem[]>([]);
- const [hasMore, setHasMore] = useState(true);
- const [loadingList, setLoadingList] = useState(false);
- const currentPageRef = useRef(1);
- const scrollerFooterRef = useRef<HTMLDivElement>(null);
- const { showToast } = useCustomToast();
- const {saveCheckoutCart} = useSaveCheckoutCart();
- const amount = Number(formattedGiftcardAmount.replace(/^\D+/ig,''));
- const getMyGiftCard = useCallback(async (page: number) => {
- // overlayLoading.start();
- setLoadingList(true);
- const params = new URLSearchParams({
- page: String(page),
- per_page: '20'
- });
- const res = await clientFetch<GiftCardRespBody>(`/api/gift/my-gift-cards?${params.toString()}`,{
- method: 'GET',
- });
- console.log(res);
- // overlayLoading.stop();
- setLoadingList(false);
- if(res.success) {
- setGiftCardsList((preList) => {
- return preList.concat(res.data);
- });
- setHasMore(res.pagination.has_more);
- currentPageRef.current = res.pagination.current_page;
- } else {
- showToast(res.message,"danger");
- }
- },[showToast]);
- useEffect(()=>{
- const element = scrollerFooterRef.current;
- if(!element) return;
- const observer = new IntersectionObserver(entries=>{
- // console.log('IntersectionObserver --- ', entries);
- // if (entries[0].intersectionRatio <= 0) return;
- if(entries[0].intersectionRatio > 0 && !loadingList && hasMore){
- getMyGiftCard(currentPageRef.current + 1);
- }
- });
- observer.observe(element);
- return ()=>observer.disconnect();
- },[loadingList,hasMore, getMyGiftCard]);
- const toggleModal = (bool: boolean) => {
- setIsShow(bool);
- if(bool && giftCardsList.length === 0) {
- getMyGiftCard(1);
- }
- };
- const applyGiftCard = async (code: string) => {
- const paramCode = code === giftcardNumber ? '' : code; // '' 表示取消应用
- overlayLoading.start();
- const saveRes = await saveCheckoutCart({
- // shippingMethod: '-1',
- // paymentMethod: '-1',
- // couponCode: '-1',
- giftCardNumber: paramCode,
- // memberDiscount: '-1'
- });
- overlayLoading.stop();
- if(!saveRes.error) {
- if(saveRes.data) {
- const newCartDetail = formatCartDetail(saveRes.data);
- onChangeGiftcard(newCartDetail);
- }
- } else {
- showToast(saveRes.msg, 'danger');
- }
- toggleModal(false);
- };
- return (
- <>
- <div className="relative box-border w-full flex justify-between items-center">
- <span className="text-ly-24 font-medium">Gift Card</span>
-
-
- <div className="flex items-center">
- {amount > 0 &&
- <span className="flex items-center text-ly-14 px-2 flex-none h-6 bg-ly-gold mr-2">
- -{formattedGiftcardAmount}
- </span>
- }
- <button className="w-6 h-6 flex-none" onClick={() => {toggleModal(true)}}>
- <svg className="block w-full h-full" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="0" y="0" width="16" height="16" fill="#FFFFFF" fillOpacity="0"></rect><path stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="square" d="M6.32031 4.27051L10.4202 8.37036L6.32031 12.4702"></path></svg>
- </button>
- </div>
- </div>
- <CommonModal
- isOpen={isShow}
- onClose={toggleModal}
- header={
- <div className="w-full box-border p-3.75 h-14.5 flex justify-between items-center shadow-md">
- <span className="text-ly-16 font-medium">
- My Gift Card
- </span>
-
- <button className="w-6 h-6" onClick={() => toggleModal(false)}>
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" aria-hidden="true" data-slot="icon" className="h-6 transition-all ease-in-out hover:scale-110"><path strokeLinecap="round" strokeLinejoin="round" d="M6 18 18 6M6 6l12 12"></path></svg>
- </button>
-
- </div>
- }
- body={
- <div className="relative box-border w-full h-auto px-3.75 pt-3.75 pb-8">
- {giftCardsList.length > 0 &&
-
- giftCardsList.map((item) => {
- const amountArr = item.formatted_remaining_giftcard_amount.split('.');
- return (
- <div key={item.id} onClick={() => {applyGiftCard(item.giftcard_number)}}
- className={clsx("relative w-full box-border mt-3 p-3 rounded-sm overflow-hidden first:mt-0",
- [
- item.giftcard_number === giftcardNumber ? "border-2 border-ly-green" : "border-1",
- ]
- )}>
- <div className="text-ly-16 font-medium">
- CODE: {item.giftcard_number}
- </div>
- <div className="mt-4 text-ly-14 text-ly-placeholder">
- Expire Date: {item.expirationdate}
- </div>
- <div className="absolute text-ly-36 font-bold right-3 top-1/2 -translate-y-1/2">
- {Number(amountArr[1]) === 0 ? amountArr[0] : item.formatted_remaining_giftcard_amount }
- </div>
- <span className={clsx("absolute top-0 right-0 w-8 h-8",{
- "hidden": item.giftcard_number !== giftcardNumber
- })}>
- <svg className="block w-full h-full fill-ly-green" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="34024" width="200" height="200"><path d="M0 0l1024 1024V0H0z m901.888 247.68l-200.234667 200.234667a28.288 28.288 0 0 1-20.096 8.32 28.288 28.288 0 0 1-20.096-8.32l-112.64-112.597334a28.501333 28.501333 0 0 1 40.234667-40.234666l92.544 92.501333 180.138667-180.096c11.093333-11.093333 29.098667-11.093333 40.234666 0a28.501333 28.501333 0 0 1-0.085333 40.192z" p-id="34025"></path></svg>
- </span>
- </div>
- );
- })
- }
- <div className="flex justify-center items-center w-full h-9" ref={scrollerFooterRef}>
- {!hasMore && <p className="text-ly-14 text-ly-placeholder">No More Data</p> }
- {(hasMore && loadingList) && <LoadingSpinner size={24} />}
- </div>
- </div>
- }
- />
- </>
- );
- }
|