Преглед изворни кода

添加通用登录弹窗;CommonModal支持创建、销毁模式

fogwind пре 2 дана
родитељ
комит
9f95215d30

+ 54 - 0
src/actions/mergeCartAction.ts

@@ -0,0 +1,54 @@
+"use server";
+
+
+import {cookies} from "next/headers";
+import { GUEST_CART_ID, GUEST_CART_TOKEN, IS_GUEST } from "@/utils/constants";
+import { bagistoFetch } from "@utils/bagisto";
+import { CREATE_MERGE_CART } from "@/graphql";
+import { CreateMergeCartData } from "@/types/cart/type";
+
+export async function mergeCartAction(){
+
+    const cookieStore = await cookies();
+
+    const guestCartId = cookieStore.get(GUEST_CART_ID)?.value;
+
+    cookieStore.delete(GUEST_CART_ID);
+    cookieStore.delete(GUEST_CART_TOKEN);
+    cookieStore.set(IS_GUEST,"false");
+    if(!guestCartId){
+        
+        return {
+            cartDetail: null,
+            success:true,
+            msg: ''
+        };
+    }
+    try{
+        // 调 Bagisto merge cart mutation
+        const response = await bagistoFetch<{
+            data: CreateMergeCartData,
+            variables: {cartId:number}
+        }>({
+            query: CREATE_MERGE_CART,
+            variables: {
+                cartId: Number(guestCartId)
+            },
+            cache: "no-store",
+        });
+        // cookieStore.delete(GUEST_CART_ID);
+        // cookieStore.delete(GUEST_CART_TOKEN);
+        // cookieStore.set(IS_GUEST,"false");
+        return {
+            cartDetail: response.body.data.createMergeCart.mergeCart,
+            success:true,
+            msg: ''
+        };
+    } catch(e: any) {
+        return {
+            cartDetail: null,
+            success:false,
+            msg: e.message || 'Fail to merge cart.'
+        };
+    }
+}

Разлика између датотеке није приказан због своје велике величине
+ 473 - 0
src/components/common/LoginModal/LoginModal.tsx


+ 59 - 18
src/components/theme/ui/CommonModal.tsx

@@ -10,6 +10,7 @@ import Portal from "@/components/common/portal/Portal";
  */
  */
 export default function CommonModal({ 
 export default function CommonModal({ 
     isOpen,
     isOpen,
+    destroyOnClose = false,
     contentClassName,
     contentClassName,
     clickOutsideClose,
     clickOutsideClose,
     onClose,
     onClose,
@@ -18,6 +19,7 @@ export default function CommonModal({
     footer
     footer
 }: {
 }: {
     isOpen: boolean;
     isOpen: boolean;
+    destroyOnClose?: boolean;
     contentClassName?: string;
     contentClassName?: string;
     clickOutsideClose?: boolean;
     clickOutsideClose?: boolean;
     onClose: (e: boolean) => void;
     onClose: (e: boolean) => void;
@@ -29,6 +31,7 @@ export default function CommonModal({
     // outing - 隐藏动画中
     // outing - 隐藏动画中
     // hidden - 隐藏
     // hidden - 隐藏
     const [rootVisible, setRootVisible] = useState<'show' | 'outing' | 'hidden'>('hidden');
     const [rootVisible, setRootVisible] = useState<'show' | 'outing' | 'hidden'>('hidden');
+    const [mounted, setMounted] = useState(false);
     
     
     const cssInit = useRef(false);
     const cssInit = useRef(false);
     const rootRef = useRef<HTMLDivElement>(null);
     const rootRef = useRef<HTMLDivElement>(null);
@@ -38,33 +41,65 @@ export default function CommonModal({
     const [rootPddingBottom, setRootPddingBottom] = useState(0);
     const [rootPddingBottom, setRootPddingBottom] = useState(0);
     const [rootPddingTop, setRootPddingTop] = useState(0);
     const [rootPddingTop, setRootPddingTop] = useState(0);
 
 
-    const baseClassNname = "absolute box-border w-full bg-white transition-transform duration-300 ease-out";
-    let applyClassName = "bottom-0 left-0 h-17/20";
+    const baseClassNname = "absolute box-border transition-transform duration-300 ease-out";
+    let applyClassName = "bottom-0 left-0 h-17/20 w-full bg-white";
     if(contentClassName) {
     if(contentClassName) {
         applyClassName = contentClassName;
         applyClassName = contentClassName;
     }
     }
 
 
     useLayoutEffect(() => {
     useLayoutEffect(() => {
         const original = document.documentElement.style.overflow;
         const original = document.documentElement.style.overflow;
-        if(isOpen) {
+        if(isOpen){
+            // destroy模式重新创建DOM
+            if(destroyOnClose){
+                // eslint-disable-next-line react-hooks/set-state-in-effect
+                setMounted(true);
+            }
             document.documentElement.style.overflow = "hidden";
             document.documentElement.style.overflow = "hidden";
-        } else {
+            requestAnimationFrame(()=>{
+                setRootVisible("show");
+            });
+        }else{
             document.documentElement.style.overflow = "";
             document.documentElement.style.overflow = "";
-        }
-        // intent: 为了实现关闭时也有动画效果,告诉eslint忽略这个错误
-        if(isOpen) {
-            // eslint-disable-next-line react-hooks/set-state-in-effect
-            setRootVisible('show');
-        } else {
-            if(cssInit.current) {
-                // eslint-disable-next-line react-hooks/set-state-in-effect
-                setRootVisible('outing');
+            if(destroyOnClose){
+                // 先播放关闭动画
+                if(mounted){
+                    // eslint-disable-next-line react-hooks/set-state-in-effect
+                    setRootVisible("outing");
+                }
+            }else{
+                // 保留DOM
+                if(cssInit.current){
+                    // eslint-disable-next-line react-hooks/set-state-in-effect
+                    setRootVisible("outing");
+                }
             }
             }
-            
+
         }
         }
+        return ()=>{ document.documentElement.style.overflow = original; };
+    },[isOpen, destroyOnClose, mounted]);
 
 
-        return () => { document.documentElement.style.overflow = original; };
-    },[isOpen]);
+    // useLayoutEffect(() => {
+    //     const original = document.documentElement.style.overflow;
+    //     if(isOpen) {
+    //         document.documentElement.style.overflow = "hidden";
+    //     } else {
+    //         document.documentElement.style.overflow = "";
+    //     }
+    //     // intent: 为了实现关闭时也有动画效果,告诉eslint忽略这个错误
+    //     if(isOpen) {
+    //         // eslint-disable-next-line react-hooks/set-state-in-effect
+    //         setRootVisible('show');
+    //     } else {
+    //         if(cssInit.current) {
+    //             // eslint-disable-next-line react-hooks/set-state-in-effect
+    //             setRootVisible('outing');
+    //         }
+            
+    //     }
+
+    //     return () => { document.documentElement.style.overflow = original; };
+    // },[isOpen]);
     // 当弹窗完全显示后计算 footer 高度
     // 当弹窗完全显示后计算 footer 高度
     useLayoutEffect(() => {
     useLayoutEffect(() => {
         if (rootVisible === 'show' && !cssInit.current && footerRef.current && headerRef.current) {
         if (rootVisible === 'show' && !cssInit.current && footerRef.current && headerRef.current) {
@@ -85,12 +120,18 @@ export default function CommonModal({
     const handlerAnimationEnd = (e: React.AnimationEvent<HTMLDivElement>) => {
     const handlerAnimationEnd = (e: React.AnimationEvent<HTMLDivElement>) => {
         if(e.animationName === "fade-out") {
         if(e.animationName === "fade-out") {
             setRootVisible('hidden');
             setRootVisible('hidden');
-        } 
-        
+            if(destroyOnClose){
+                setMounted(false);
+                cssInit.current=false;
+            }
+        }
     }
     }
     // 初始化时是隐藏状态
     // 初始化时是隐藏状态
     // fade-in的时候display block + fade-in
     // fade-in的时候display block + fade-in
     // fade-out的时候需要先加fade-out 类名,动画效果结束之后才能display none 
     // fade-out的时候需要先加fade-out 类名,动画效果结束之后才能display none 
+    if(destroyOnClose && !mounted){
+        return null;
+    }
     return (
     return (
         <Portal>
         <Portal>
             <div 
             <div 

+ 4 - 2
src/components/theme/ui/InputText.tsx

@@ -1,5 +1,7 @@
-import React from "react";
+"use client";
 
 
+import React from "react";
+type InputType = 'text' | 'email';
 function InputText({
 function InputText({
     type = 'text',
     type = 'text',
     placeholder,
     placeholder,
@@ -10,7 +12,7 @@ function InputText({
     ref
     ref
 }: {
 }: {
     // 用于react-hook-form时,推荐使用useForm的 defaultValues 对整个表单设置默认值
     // 用于react-hook-form时,推荐使用useForm的 defaultValues 对整个表单设置默认值
-    type?: 'text' | 'email' | 'password';
+    type?: InputType;
     placeholder: string;
     placeholder: string;
     // 用于react-hook-form时,React 事件处理器类型定义中的“双变(bivariance)”特性 和返回值void的兼容性,使typescript没有提示类型错误
     // 用于react-hook-form时,React 事件处理器类型定义中的“双变(bivariance)”特性 和返回值void的兼容性,使typescript没有提示类型错误
     onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
     onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;

+ 74 - 0
src/components/theme/ui/PasswordInput.tsx

@@ -0,0 +1,74 @@
+"use client";
+
+import React, {useState} from "react";
+import clsx from "clsx";
+type InputType = 'text' | 'password';
+function PasswordInput({
+    placeholder,
+    onChange,
+    onBlur,
+    name,
+    error,
+    ref
+}: {
+    // 用于react-hook-form时,推荐使用useForm的 defaultValues 对整个表单设置默认值
+    placeholder: string;
+    // 用于react-hook-form时,React 事件处理器类型定义中的“双变(bivariance)”特性 和返回值void的兼容性,使typescript没有提示类型错误
+    onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
+    onBlur: (e: React.ChangeEvent<HTMLInputElement>) => void;
+    name: string;
+    error?: string;
+    ref?: React.Ref<HTMLInputElement>;
+}) {
+    const [inputType, setInputType] = useState<InputType>('password');
+    const changeType = () => {
+        if(inputType === 'text') {
+            setInputType('password');
+        }
+         if(inputType === 'password') {
+            setInputType('text');
+        }
+    };
+    return (
+        <div className="w-full">
+            <div className="relative w-full">
+                <input className="ly-input w-full" 
+                    type={inputType}
+                    placeholder={placeholder}
+                    onChange={onChange}
+                    onBlur={onBlur}
+                    name={name}
+                    ref={ref}
+                />
+                
+                <div className="absolute top-1/2 right-3 -translate-y-1/2 w-4 h-4" onClick={changeType}>
+                    <svg className={clsx("block w-full h-full icon-eyehide",{
+                        "hidden": inputType !== 'password'
+                    })} 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">
+                        <path fill="none" stroke="#000000" strokeWidth="1.5" strokeLinecap="round" d="M3.28587 6C2.07945 7 1.33325 8 1.33325 8C1.33325 8 4.31802 12 7.99992 12C8.45655 12 8.90245 11.9385 9.33325 11.8307M6.67719 4.16667C7.10472 4.06053 7.54705 4 7.99992 4C11.6818 4 14.6666 8 14.6666 8C14.6666 8 13.9204 9 12.714 10">
+                        </path>
+                        <path fill="none" stroke="#000000" strokeWidth="1.3333333333333333" strokeLinejoin="round" strokeLinecap="round" d="M6.77132 6.87372C6.49929 7.17032 6.33325 7.56575 6.33325 7.99995C6.33325 8.92042 7.07945 9.66662 7.99992 9.66662C8.45415 9.66662 8.86595 9.48489 9.16658 9.19018">
+                        </path>
+                        <path fill="none"  stroke="#000000"strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round" d="M14 14L2 2">
+                        </path>
+                    </svg> 
+                    <svg className={clsx("block w-full h-full icon-eyeshow",{
+                        "hidden": inputType !== 'text'
+                    })} 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">
+                        <path stroke="#000000" d="M7.99992 12C11.6818 12 14.6666 8 14.6666 8C14.6666 8 11.6818 4 7.99992 4C4.31802 4 1.33325 8 1.33325 8C1.33325 8 4.31802 12 7.99992 12Z" fill="none" strokeWidth="1.5">
+                        </path>
+                        <path stroke="#000000" d="M7.99992 9.66665C8.92039 9.66665 9.66658 8.92045 9.66658 7.99998C9.66658 7.07951 8.92039 6.33331 7.99992 6.33331C7.07945 6.33331 6.33325 7.07951 6.33325 7.99998C6.33325 8.92045 7.07945 9.66665 7.99992 9.66665Z" fill="none" strokeWidth="1.5" strokeLinejoin="round">
+                        </path>
+                    </svg>
+                </div>
+
+            </div>
+            
+            {error && <p className="text-red-500 text-ly-12">{error}</p>}
+        </div> 
+    );
+}
+// 设置 displayName,便于调试
+PasswordInput.displayName = 'PasswordInput';
+
+export default PasswordInput;

+ 6 - 6
src/components/theme/ui/PhoneNumberInput/PhoneNumberInput.tsx

@@ -46,9 +46,9 @@ interface PhoneNumberInputProps {
     name: string;
     name: string;
     error?: string;
     error?: string;
     ref?: React.Ref<HTMLInputElement>;
     ref?: React.Ref<HTMLInputElement>;
-    countryCode: string;//父组件表单国家字段
-    onHasUserSelectedPhoneCode: () => void;
-    hasUserSelectedPhoneCode: boolean;
+    countryCode?: string;//父组件表单国家字段
+    onHasUserSelectedPhoneCode?: () => void;
+    hasUserSelectedPhoneCode?: boolean;
 }
 }
 function PhoneNumberInput({
 function PhoneNumberInput({
     value,
     value,
@@ -58,7 +58,7 @@ function PhoneNumberInput({
     name,
     name,
     error,
     error,
     ref,
     ref,
-    countryCode,
+    countryCode = 'US',
     onHasUserSelectedPhoneCode,
     onHasUserSelectedPhoneCode,
     hasUserSelectedPhoneCode
     hasUserSelectedPhoneCode
 }: PhoneNumberInputProps) {
 }: PhoneNumberInputProps) {
@@ -142,7 +142,7 @@ function PhoneNumberInput({
         setSelectedPhoneCode(pCode);
         setSelectedPhoneCode(pCode);
         setSelectedCountryForPhoneCode(ccode);
         setSelectedCountryForPhoneCode(ccode);
         
         
-        if(!hasUserSelectedPhoneCode) {
+        if(!hasUserSelectedPhoneCode && onHasUserSelectedPhoneCode) {
             onHasUserSelectedPhoneCode(); // 标记为用户手动选择过
             onHasUserSelectedPhoneCode(); // 标记为用户手动选择过
         }
         }
         setShowCodeList(false);
         setShowCodeList(false);
@@ -169,7 +169,7 @@ function PhoneNumberInput({
                 ref={ref}
                 ref={ref}
             />
             />
             <div className="flex gap-4 box-border border-1 border-ly-inputborder">
             <div className="flex gap-4 box-border border-1 border-ly-inputborder">
-                <div className="flex-auto px-3.75" onClick={handleShowCodeList}>
+                <div className="px-3.75" onClick={handleShowCodeList}>
                     <div className="h-11.5 text-ly-12 flex items-center">
                     <div className="h-11.5 text-ly-12 flex items-center">
                         
                         
                         <Image alt="china flag" width={24} height={18} className="w-6 h-4.5 mr-2"
                         <Image alt="china flag" width={24} height={18} className="w-6 h-4.5 mr-2"

+ 70 - 0
src/graphql/cart/mutations/CreateApplyCoupon.ts

@@ -0,0 +1,70 @@
+import { gql, TypedDocumentNode } from "@apollo/client";
+import { CreateApplyCouponData } from "@/types/cart/type";
+
+export const CREATE_APPLY_COUPON: TypedDocumentNode<CreateApplyCouponData> = gql`
+    mutation createApplyCoupon (
+        $couponCode: String!
+    ) {
+        createApplyCoupon(input: {
+            couponCode: $couponCode
+        }) {
+                applyCoupon {
+                    id
+                    appliedTaxes
+                    itemsQty
+                    isGuest
+                    itemsCount
+                    items {
+                    edges {
+                        node {
+                        id
+                        cartId
+                        productId
+                        name
+                        price
+                        baseImage
+                        sku
+                        quantity
+                        type
+                        productUrlKey
+                        canChangeQty
+                        }
+                    }
+                    }
+                    isVip
+                    vipDiscountAmount
+                    formattedVipDiscountAmount
+                    giftcardNumber
+                    subtotal
+                    subTotalInclTax
+                    discountAmount
+                    giftcardAmount
+                    vipPlusAmount
+                    vipExpireDate
+                    taxAmount
+                    taxTotal
+                    shippingAmount
+                    shippingAmountInclTax
+                    grandTotal
+                    formattedSubtotal
+                    formattedSubTotalInclTax
+                    formattedGiftcardAmount
+                    formattedDiscountAmount
+                    formattedVipPlusAmount
+                    formattedTaxAmount
+                    formattedTaxTotal
+                    formattedShippingAmount
+                    formattedShippingAmountInclTax
+                    formattedGrandTotal
+                    couponCode
+                    selectedShippingRate
+                    selectedShippingRateTitle
+                    paymentMethod
+                    paymentMethodTitle
+                    haveStockableItems
+                    billingAddress
+                    shippingAddress
+                }
+            }
+    }
+`;

+ 2 - 1
src/graphql/cart/mutations/index.ts

@@ -3,4 +3,5 @@ export {REMOVE_CART_ITEM} from './RemoveCartItem';
 export {UPDATE_CART_ITEM} from './UpdateCartItems';
 export {UPDATE_CART_ITEM} from './UpdateCartItems';
 export {GET_CART_ITEM} from './GetCartItem';
 export {GET_CART_ITEM} from './GetCartItem';
 export {CREATE_CART_TOKEN} from './CreateCartToken';
 export {CREATE_CART_TOKEN} from './CreateCartToken';
-export {CREATE_MERGE_CART} from "./CreateMergeCart"
+export {CREATE_MERGE_CART} from "./CreateMergeCart"
+export {CREATE_APPLY_COUPON} from "./CreateApplyCoupon"

+ 3 - 2
src/graphql/customer/mutations/CustomerRegistration.ts

@@ -1,6 +1,7 @@
-import { gql } from "@apollo/client";
+import { gql, TypedDocumentNode } from "@apollo/client";
+import {CreateUserResponse} from "@/types/types";
 
 
-export const CUSTOMER_REGISTRATION = gql`
+export const CUSTOMER_REGISTRATION: TypedDocumentNode<CreateUserResponse> = gql`
   mutation registerCustomer($input: createCustomerInput!) {
   mutation registerCustomer($input: createCustomerInput!) {
     createCustomer(input: $input) {
     createCustomer(input: $input) {
       customer {
       customer {

+ 1 - 0
src/graphql/index.ts

@@ -6,6 +6,7 @@ export * from "./cart/mutations";
 export * from "./checkout/queries";
 export * from "./checkout/queries";
 export * from "./checkout/mutations";
 export * from "./checkout/mutations";
 export * from "./customer/query/index";
 export * from "./customer/query/index";
+export * from "./customer/mutations/index";
 export * from "./currency/query/index";
 export * from "./currency/query/index";
 export * from "./types";
 export * from "./types";
 
 

+ 4 - 1
src/providers/GlobalProviders.tsx

@@ -5,6 +5,7 @@ import { ThemeProvider } from "./ThemeProvider";
 import { ToastProvider } from "./ToastProvider";
 import { ToastProvider } from "./ToastProvider";
 import { ApolloWrapper } from "./ApolloWrapper";
 import { ApolloWrapper } from "./ApolloWrapper";
 import { PaymentSDKProvider } from "./PaymentSDKProvider";
 import { PaymentSDKProvider } from "./PaymentSDKProvider";
+import { LoginModalProvider } from "./LoginModalProvider";
 
 
 export function GlobalProviders({ children }: { children: ReactNode }) {
 export function GlobalProviders({ children }: { children: ReactNode }) {
   return (
   return (
@@ -12,7 +13,9 @@ export function GlobalProviders({ children }: { children: ReactNode }) {
         <ToastProvider>
         <ToastProvider>
           <ApolloWrapper>
           <ApolloWrapper>
             <PaymentSDKProvider>
             <PaymentSDKProvider>
-            {children}
+              <LoginModalProvider>
+                {children}
+              </LoginModalProvider>
             </PaymentSDKProvider>
             </PaymentSDKProvider>
           </ApolloWrapper>
           </ApolloWrapper>
         </ToastProvider>
         </ToastProvider>

+ 103 - 0
src/providers/LoginModalProvider.tsx

@@ -0,0 +1,103 @@
+"use client";
+
+import {
+    createContext,
+    useContext,
+    useState,
+    ReactNode,
+    useCallback
+} from "react";
+
+import LoginModal, {LoginModalReult} from "@/components/common/LoginModal/LoginModal";
+
+type LoginModalOptions = {
+    callbackUrl?: string;
+    onFinalResult?:(param:LoginModalReult)=>void | Promise<void>;
+};
+
+type LoginModalContextType = {
+    isOpen: boolean;
+    openLoginModal: (options?:LoginModalOptions)=>void;
+    closeLoginModal:()=>void;
+};
+
+const LoginModalContext = createContext<LoginModalContextType|null>(null);
+
+
+export function LoginModalProvider({
+    children
+}:{
+    children:ReactNode;
+}){
+
+
+    const [isOpen,setIsOpen]=useState(false);
+
+    const [modalOptions,setModalOptions]= useState<LoginModalOptions|null>(null);
+
+
+
+    const openLoginModal = useCallback((options?:LoginModalOptions)=>{
+
+        setModalOptions(options ?? null);
+
+        setIsOpen(true);
+
+    },[]);
+
+
+
+    const closeLoginModal = useCallback(()=>{
+
+        setIsOpen(false);
+
+        setModalOptions(null);
+
+    },[]);
+
+
+
+    return (
+
+        <LoginModalContext.Provider
+            value={{
+                isOpen,
+                openLoginModal,
+                closeLoginModal
+            }}
+        >
+
+            {children}
+
+
+            <LoginModal
+                isShow={isOpen}
+                closeModal={closeLoginModal}
+                callbackUrl={modalOptions?.callbackUrl}
+                onFinalResult={ modalOptions?.onFinalResult }
+            />
+
+
+        </LoginModalContext.Provider>
+
+    );
+
+}
+
+
+
+export function useLoginModal(){
+
+    const context=useContext(LoginModalContext);
+
+
+    if(!context){
+        throw new Error(
+            "useLoginModal must be used inside LoginModalProvider"
+        );
+    }
+
+
+    return context;
+
+}

+ 15 - 1
src/types/customer/type.ts

@@ -8,4 +8,18 @@ export type {
     AddressListInOrderDetails,
     AddressListInOrderDetails,
     AddressInOrderDetails,
     AddressInOrderDetails,
     OrderAddressType
     OrderAddressType
-} from "./order";
+} from "./order";
+
+export interface CustomerLoginData{
+    id: string;
+    apiToken: string;
+    token: string;
+    message: string;
+    success: boolean;
+}
+export interface CustomerLoginResponse{
+    createCustomerLogin:{
+        customerLogin: CustomerLoginData
+    }
+    
+}

+ 13 - 9
src/types/types.ts

@@ -591,14 +591,8 @@ export type BagistoUserTypes = {
   };
   };
 };
 };
 
 
-export type BagistoCreateUserOperation = {
-  data: {
-    createCustomer: {
-      customer: BagistoUser;
-    };
-  };
-  variables: {
-    input: {
+export type CreateUserVariables = {
+  input: {
       firstName: string;
       firstName: string;
       lastName: string;
       lastName: string;
       email: string;
       email: string;
@@ -611,8 +605,13 @@ export type BagistoCreateUserOperation = {
       isVerified?: string;
       isVerified?: string;
       isSuspended?: string;
       isSuspended?: string;
       subscribedToNewsLetter?: boolean;
       subscribedToNewsLetter?: boolean;
-    };
   };
   };
+}
+
+export type CreateUserResponse = {
+    createCustomer: {
+      customer: BagistoUser;
+    }
 };
 };
 
 
 export type BagistoUser = {
 export type BagistoUser = {
@@ -636,6 +635,11 @@ export type BagistoUser = {
   name: string;
   name: string;
 };
 };
 
 
+export type BagistoCreateUserOperation = {
+  data: CreateUserResponse;
+  variables: CreateUserVariables;
+};
+
 export type SuperAttribute = {
 export type SuperAttribute = {
   attributeId: number;
   attributeId: number;
   attributeOptionId: number;
   attributeOptionId: number;

+ 5 - 1
src/utils/auth.ts

@@ -2,6 +2,7 @@ import NextAuth, { NextAuthOptions } from "next-auth";
 import CredentialsProvider from "next-auth/providers/credentials";
 import CredentialsProvider from "next-auth/providers/credentials";
 import { bagistoFetch, /*restApiFetch*/} from "@/utils/bagisto";
 import { bagistoFetch, /*restApiFetch*/} from "@/utils/bagisto";
 import { CUSTOMER_LOGIN } from "@/graphql/customer/mutations";
 import { CUSTOMER_LOGIN } from "@/graphql/customer/mutations";
+import {CustomerLoginResponse} from "@/types/customer/type";
 
 
 export const authOptions: NextAuthOptions = {
 export const authOptions: NextAuthOptions = {
   session: {
   session: {
@@ -30,7 +31,10 @@ export const authOptions: NextAuthOptions = {
         };
         };
 
 
 
 
-        const res = await bagistoFetch<any>({
+        const res = await bagistoFetch<{
+          data: CustomerLoginResponse,
+          variables: {input:{email:string;password:string;}}
+        }>({
           query: CUSTOMER_LOGIN,
           query: CUSTOMER_LOGIN,
           variables: { input },
           variables: { input },
           cache: "no-store",
           cache: "no-store",

+ 45 - 0
src/utils/hooks/useUserRegister.ts

@@ -0,0 +1,45 @@
+import {useCallback} from "react";
+import { useApolloClient } from "@apollo/client/react";
+import { CUSTOMER_REGISTRATION } from "@/graphql";
+import {
+    BagistoUser,
+    CreateUserVariables
+} from "@/types/types";
+
+interface UserRegisterResult {
+    data: BagistoUser | null;
+    msg: string;
+    error: boolean;
+}
+
+export const useUserRegister = () => {
+    const client = useApolloClient();
+    const userRegister = useCallback((params: CreateUserVariables) => {
+        return client.mutate({
+            mutation: CUSTOMER_REGISTRATION,
+            variables: params
+        }).then((res) => {
+            const resData = res.data?.createCustomer.customer ?? null; 
+            const result: UserRegisterResult = { 
+                data:resData,
+                msg: '',
+                error: false
+            };
+            return result;
+        }).catch((err) => {
+            const result: UserRegisterResult = {
+                data: null,
+                msg: err.message,
+                error: true
+            };
+            return result;
+        });
+
+    },[client]);
+
+
+
+  return {
+    userRegister
+  };
+};