| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 |
- "use client";
- import { FC, useState, useEffect } from "react";
- import { useForm, useWatch } from "react-hook-form";
- import { AddressDataTypes } from "@/types/types";
- import { EMAIL, getLocalStorage } from "@/store/local-storage";
- import { IS_VALID_ADDRESS, IS_VALID_PHONE, IS_VALID_INPUT } from "@/utils/constants";
- import { isObject } from "@/utils/type-guards";
- import { useCheckout } from "@utils/hooks/useCheckout";
- import InputText from "@components/common/form/Input";
- import { ProceedToCheckout } from "./ProceedToCheckout";
- import CheckBox from "@components/theme/ui/element/Checkbox";
- import { useDispatch } from "react-redux";
- import { setCheckoutAddresses } from "@/store/slices/cart-slice";
- export const GuestAddAdressForm: FC<{
- billingAddress?: AddressDataTypes | null;
- shippingAddress?: AddressDataTypes | null;
- currentStep?: string;
- }> = ({
- billingAddress: initialBilling,
- shippingAddress: initialShipping,
- currentStep,
- }) => {
- const email = getLocalStorage(EMAIL);
- const dispatch = useDispatch();
- const [isOpen, setIsOpen] = useState(currentStep !== "address");
- const [billingAddress, setBillingAddress] = useState<AddressDataTypes | null>(
- initialBilling ?? null
- );
- const [shippingAddress, setShippingAddress] =
- useState<AddressDataTypes | null>(initialShipping ?? null);
- const [prevStep, setPrevStep] = useState(currentStep);
- if (currentStep !== prevStep) {
- setPrevStep(currentStep);
- setIsOpen(currentStep !== "address" && isObject(shippingAddress) && isObject(billingAddress));
- }
- const {
- register,
- control,
- handleSubmit,
- reset,
- formState: { errors },
- } = useForm({
- mode: "onSubmit",
- defaultValues: {
- billing: {
- email: billingAddress?.email ?? email ?? "",
- firstName: billingAddress?.firstName || "",
- lastName: billingAddress?.lastName || "",
- companyName: billingAddress?.companyName || "",
- address: billingAddress?.address || "",
- country: billingAddress?.country || "IN",
- state: billingAddress?.state || "UP",
- city: billingAddress?.city || "",
- postcode: billingAddress?.postcode || "",
- phone: billingAddress?.phone || "",
- },
- shipping: {
- email: shippingAddress?.email ?? email ?? "",
- firstName: shippingAddress?.firstName || "",
- lastName: shippingAddress?.lastName || "",
- companyName: shippingAddress?.companyName || "",
- address: shippingAddress?.address || "",
- country: shippingAddress?.country || "IN",
- state: shippingAddress?.state || "UP",
- city: shippingAddress?.city || "",
- postcode: shippingAddress?.postcode || "",
- phone: shippingAddress?.phone || "",
- },
- useForShipping: true,
- },
- });
- useEffect(() => {
- if (initialBilling || initialShipping) {
- const billing = initialBilling ?? null;
- const shipping = initialShipping ?? null;
- requestAnimationFrame(() => {
- setBillingAddress(billing);
- setShippingAddress(shipping);
- setIsOpen(currentStep !== "address" && isObject(shipping) && isObject(billing));
- });
- reset({
- billing: {
- email: initialBilling?.email ?? email ?? "",
- firstName: initialBilling?.firstName || "",
- lastName: initialBilling?.lastName || "",
- companyName: initialBilling?.companyName || "",
- address: initialBilling?.address || "",
- country: initialBilling?.country || "IN",
- state: initialBilling?.state || "UP",
- city: initialBilling?.city || "",
- postcode: initialBilling?.postcode || "",
- phone: initialBilling?.phone || "",
- },
- shipping: {
- email: initialShipping?.email ?? email ?? "",
- firstName: initialShipping?.firstName || "",
- lastName: initialShipping?.lastName || "",
- companyName: initialShipping?.companyName || "",
- address: initialShipping?.address || "",
- country: initialShipping?.country || "IN",
- state: initialShipping?.state || "UP",
- city: initialShipping?.city || "",
- postcode: initialShipping?.postcode || "",
- phone: initialShipping?.phone || "",
- },
- useForShipping: true,
- });
- }
- }, [initialBilling, initialShipping, reset, email]);
- const { isLoadingToSave, saveCheckoutAddress } = useCheckout();
- const watchUseForShipping = useWatch({
- control,
- name: "useForShipping",
- defaultValue: true,
- });
- const addGuestAddress = async (data: any) => {
- const billing = data?.billing;
- const shipping = data?.shipping;
- const useForShipping = Boolean(data.useForShipping);
- const shippingSource = useForShipping ? billing : shipping;
- const payload: any = {
- billingFirstName: billing.firstName,
- billingLastName: billing.lastName,
- billingEmail: billing.email ?? email ?? "",
- billingAddress: billing.address,
- billingCity: billing.city,
- billingCountry: billing.country || "IN",
- billingState: billing.state || "UP",
- billingPostcode: billing.postcode,
- billingPhoneNumber: billing.phone,
- billingCompanyName: billing.companyName,
- useForShipping,
- };
- if (!useForShipping) {
- payload.shippingFirstName = shipping.firstName;
- payload.shippingLastName = shipping.lastName;
- payload.shippingEmail = shipping.email ?? email ?? "";
- payload.shippingAddress = shipping.address;
- payload.shippingCity = shipping.city;
- payload.shippingCountry = shipping.country;
- payload.shippingState = shipping.state;
- payload.shippingPostcode = shipping.postcode;
- payload.shippingPhoneNumber = shipping.phone;
- payload.shippingCompanyName = shipping.companyName;
- }
- try {
- await saveCheckoutAddress(payload as any);
- dispatch(
- setCheckoutAddresses({
- billing: {
- ...billing,
- email: billing.email ?? email ?? "",
- },
- shipping: {
- ...shippingSource,
- email: shippingSource.email ?? email ?? "",
- },
- })
- );
- setBillingAddress({
- ...billing,
- email: billing.email ?? email ?? "",
- } as AddressDataTypes);
- setShippingAddress({
- ...shippingSource,
- email: shippingSource.email ?? email ?? "",
- } as AddressDataTypes);
- setIsOpen(true);
- } catch (error) {
- console.error("Failed to save checkout address", error);
- }
- };
- const showSummary = isObject(shippingAddress) && isObject(billingAddress);
- if (showSummary && isOpen) {
- return (
- <>
- <div className="mt-4 items-start hidden sm:flex">
- <div className="flex flex-col justify-between w-full">
- <div className="flex">
- <p className="w-[184px] text-base font-normal text-black/60 dark:text-white/60">
- Billing Address
- </p>
- <div className="block cursor-pointer rounded-xl p-2 max-sm:rounded-lg">
- <div className="flex flex-col">
- <p className="text-base font-medium">
- {`${billingAddress?.firstName || ""} ${billingAddress?.lastName || ""
- }`}
- </p>
- <p className="text-base font-medium text-zinc-500">
- {`${billingAddress?.companyName || ""}`}
- </p>
- </div>
- <p className="mt-2 text-sm text-zinc-500 max-md:mt-2 max-sm:mt-0">
- {`${billingAddress?.address || ""}, ${billingAddress?.postcode || ""
- }`}
- </p>
- <p className="text-zinc-500">
- {billingAddress?.city || ""} {billingAddress?.state || ""},
- {billingAddress?.country || ""}
- </p>
- <p className="mt-2 text-sm text-zinc-500 max-md:mt-2 max-sm:mt-0">
- {`T: ${billingAddress?.phone || ""}`}
- </p>
- </div>
- </div>
- <div className="flex">
- <p className="w-[184px] text-base font-normal text-black/60 dark:text-white/60">
- Shipping Address
- </p>
- <div className="block cursor-pointer rounded-xl p-2 max-sm:rounded-lg">
- <div className="flex flex-col">
- <p className="text-base font-medium">
- {`${shippingAddress?.firstName || ""} ${shippingAddress?.lastName || ""
- }`}
- </p>
- <p className="text-base font-medium text-zinc-500">
- {`${shippingAddress?.companyName || ""}`}
- </p>
- </div>
- <p className="mt-2 text-sm text-zinc-500 max-md:mt-2 max-sm:mt-0">
- {`${shippingAddress?.address || ""}, ${shippingAddress?.postcode || ""
- }`}
- </p>
- <p className="text-zinc-500">
- {shippingAddress?.city || ""} {shippingAddress?.state || ""},
- {shippingAddress?.country || ""}
- </p>
- <p className="mt-2 text-sm text-zinc-500 max-md:mt-2 max-sm:mt-0">
- {`T: ${shippingAddress?.phone || ""}`}
- </p>
- </div>
- </div>
- </div>
- <button
- onClick={() => {
- setIsOpen(false);
- }}
- className="cursor-pointer text-base font-normal text-black/[60%] underline dark:text-neutral-300"
- >
- Change
- </button>
- </div>
- <div className="mt-4 flex sm:hidden items-start justify-between relative">
- <div className="flex flex-col justify-between w-full">
- <div className="flex justify-between justify-between flex-1 wrap">
- <p className="w-[184px] text-base font-normal text-black/60 dark:text-white/60">
- Billing Address
- </p>
- <div className="block cursor-pointer rounded-xl p-2 max-sm:rounded-lg">
- <div className="flex flex-col">
- <p className="text-base font-medium">
- {`${billingAddress?.firstName || ""} ${billingAddress?.lastName || ""
- }`}
- </p>
- <p className="text-base font-medium text-zinc-500">
- {`${billingAddress?.companyName || ""}`}
- </p>
- </div>
- <p className="mt-2 text-sm text-zinc-500 max-md:mt-2 max-sm:mt-0">
- {`${billingAddress?.address || ""}, ${billingAddress?.postcode || ""
- }`}
- </p>
- <p className="text-zinc-500">
- {billingAddress?.city || ""} {billingAddress?.state || ""},
- {billingAddress?.country || ""}
- </p>
- <p className="mt-2 text-sm text-zinc-500 max-md:mt-2 max-sm:mt-0">
- {`T: ${billingAddress?.phone || ""}`}
- </p>
- </div>
- </div>
- <div className="flex justify-between justify-between flex-1 wrap">
- <p className="w-[184px] text-base font-normal text-black/60 dark:text-white/60">
- Shipping Address
- </p>
- <div className="block cursor-pointer rounded-xl p-2 max-sm:rounded-lg">
- <div className="flex flex-col">
- <p className="text-base font-medium">
- {`${shippingAddress?.firstName || ""} ${shippingAddress?.lastName || ""
- }`}
- </p>
- <p className="text-base font-medium text-zinc-500">
- {`${shippingAddress?.companyName || ""}`}
- </p>
- </div>
- <p className="mt-2 text-sm text-zinc-500 max-md:mt-2 max-sm:mt-0">
- {`${shippingAddress?.address || ""}, ${shippingAddress?.postcode || ""
- }`}
- </p>
- <p className="text-zinc-500">
- {shippingAddress?.city || ""} {shippingAddress?.state || ""},
- {shippingAddress?.country || ""}
- </p>
- <p className="mt-2 text-sm text-zinc-500 max-md:mt-2 max-sm:mt-0">
- {`T: ${shippingAddress?.phone || ""}`}
- </p>
- </div>
- </div>
- </div>
- <button
- onClick={() => {
- setIsOpen(false);
- }}
- className="cursor-pointer absolute right-0 text-base font-normal text-black/[60%] underline dark:text-neutral-300"
- style={{ top: "-36px" }}
- >
- Change
- </button>
- </div>
- </>
- );
- }
- return (
- <form className="my-5" onSubmit={handleSubmit(addGuestAddress)}>
- <div className="my-7 grid grid-cols-6 gap-4">
- <InputText
- {...register("billing.firstName", {
- required: "First name is required",
- pattern: {
- value: IS_VALID_INPUT,
- message: "Invalid First Name",
- },
- })}
- className="col-span-6 xxs:col-span-3 mb-4"
- errorMsg={errors?.billing?.firstName?.message}
- label="First Name *"
- size="md"
- />
- <InputText
- {...register("billing.lastName", {
- required: "Last name is required",
- pattern: {
- value: IS_VALID_INPUT,
- message: "Invalid Last Name",
- },
- })}
- className="col-span-6 xxs:col-span-3 mb-4"
- errorMsg={errors?.billing?.lastName?.message}
- label="Last Name *"
- size="md"
- />
- <InputText
- {...register("billing.companyName", {
- pattern: {
- value: IS_VALID_INPUT,
- message: "Invalid Company Name",
- },
- })}
- className="col-span-6 mb-2"
- errorMsg={errors?.billing?.companyName?.message}
- label="Company Name"
- size="md"
- />
- <InputText
- {...register("billing.address", {
- required: "Address field is required",
- pattern: {
- value: IS_VALID_ADDRESS,
- message: "Invalid Address",
- },
- })}
- className="col-span-6 mb-4"
- errorMsg={errors?.billing?.address?.message}
- label="Street Address *"
- size="md"
- />
- <InputText
- {...register("billing.city", {
- required: "City field is required",
- pattern: {
- value: IS_VALID_INPUT,
- message: "Invalid City",
- },
- })}
- className="col-span-6 xxs:col-span-3 mb-4"
- errorMsg={errors?.billing?.city?.message}
- label="City *"
- size="md"
- />
- <InputText
- {...register("billing.postcode", {
- required: "Postcode field is required",
- pattern: {
- value: IS_VALID_INPUT,
- message: "Invalid Postcode",
- },
- })}
- className="col-span-6 xxs:col-span-3"
- errorMsg={errors?.billing?.postcode?.message}
- label="Zip Code *"
- size="md"
- />
- <InputText
- {...register("billing.phone", {
- required: "Phone field is required",
- pattern: {
- value: IS_VALID_PHONE,
- message: "Enter Valid Phone Number",
- },
- })}
- type="tel"
- inputMode="tel"
- autoComplete="tel"
- className="col-span-6"
- errorMsg={errors?.billing?.phone?.message}
- label="Phone *"
- size="md"
- />
- <CheckBox
- className="col-span-6 mt-3"
- defaultValue={watchUseForShipping}
- id="useForShipping"
- label="Billing address is same as shipping address"
- {...register("useForShipping")}
- />
- </div>
- {!watchUseForShipping && (
- <div className="my-7 grid grid-cols-6 gap-4">
- <InputText
- {...register("shipping.firstName", {
- required: "First name is required",
- pattern: {
- value: IS_VALID_INPUT,
- message: "Invalid First Name",
- },
- })}
- className="col-span-3 mb-4"
- errorMsg={errors?.shipping?.firstName?.message}
- label="First Name *"
- size="md"
- />
- <InputText
- {...register("shipping.lastName", {
- required: "Last name is required",
- pattern: {
- value: IS_VALID_INPUT,
- message: "Invalid Last Name",
- },
- })}
- className="col-span-3 mb-4"
- errorMsg={errors?.shipping?.lastName?.message}
- label="Last Name *"
- size="md"
- />
- <InputText
- {...register("shipping.companyName", {
- pattern: {
- value: IS_VALID_INPUT,
- message: "Invalid Company Name",
- },
- })}
- className="col-span-6 mb-4"
- errorMsg={errors?.shipping?.companyName?.message}
- label="Company Name"
- size="md"
- />
- <InputText
- {...register("shipping.address", {
- required: "Address field is required",
- pattern: {
- value: IS_VALID_ADDRESS,
- message: "Invalid Address",
- },
- })}
- className="col-span-6 mb-4"
- errorMsg={errors?.shipping?.address?.message}
- label="Street Address *"
- size="md"
- />
- <InputText
- {...register("shipping.city", {
- required: "City field is required",
- pattern: {
- value: IS_VALID_INPUT,
- message: "Invalid City",
- },
- })}
- className="col-span-3 mb-4"
- errorMsg={errors?.shipping?.city?.message}
- label="City *"
- size="md"
- />
- <InputText
- {...register("shipping.postcode", {
- required: "Postcode field is required",
- pattern: {
- value: IS_VALID_INPUT,
- message: "Invalid Postcode",
- },
- })}
- className="col-span-3"
- errorMsg={errors?.shipping?.postcode?.message}
- label="Zip Code *"
- size="md"
- />
- <InputText
- {...register("shipping.phone", {
- required: "Phone field is required",
- pattern: {
- value: IS_VALID_PHONE,
- message: "Enter Valid Phone Number",
- },
- })}
- className="col-span-6"
- errorMsg={errors?.shipping?.phone?.message}
- label="Phone *"
- size="md"
- />
- </div>
- )}
- <div className="justify-self-end">
- <ProceedToCheckout buttonName="Next" pending={isLoadingToSave} />
- </div>
- </form>
- );
- };
|