"use client"; import {useMemo,useEffect, useState, useCallback} from "react"; import clsx from "clsx"; import { useQuery } from "@apollo/client/react"; import { useFormContext, useWatch, Controller } from "react-hook-form"; import { formatFinalPhoneValue, getPhoneCodeBycountryCode } from "@/components/theme/ui/PhoneNumberInput/phoneCodeMetaData"; import { GET_COUNTRY_STATES } from "@/graphql"; import { EMAIL_REGEX, IS_VALID_INPUT, IS_VALID_FULL_PHONE, IS_VALID_PHONECODE } from "@utils/constants"; import { CustomerAddressItem } from "@/types/customer/type"; import { useConfig } from "@utils/hooks/useConfig"; import InputText from "@/components/theme/ui/InputText"; import Select from "@/components/theme/ui/Select"; import PhoneNumberInput from "@/components/theme/ui/PhoneNumberInput/PhoneNumberInput"; import { LoadingSpinner } from "@components/common/LoadingSpinner"; import {LyDropDown} from "@/components/theme/ui/LyDropDown"; export default function ShippingAddressCheckout({ noAddress, isGuest, showFormField, onShowFormFieldChange, customerAddressList, onEmailChange }: { noAddress: boolean; isGuest: boolean; showFormField: boolean; onShowFormFieldChange: (e: boolean) => void; customerAddressList: CustomerAddressItem[]; onEmailChange: (value: string) => void; }) { const {countries} = useConfig(); const { getValues, setValue, register, formState: { errors }, control, } = useFormContext() // retrieve all hook methods const countriesOptions = useMemo(() => { return countries.map((country) => ({ value: country.code, label: country.name, id: String(country._id), })) },[countries]); const [ selectedCountryCode, firstName, lastName, streetAddress, stateProvince, postCode, city, phoneNumber ] = useWatch({ control, name: [ 'shippingCountry', 'shippingFirstName', 'shippingLastName', 'shippingAddress', 'shippingState', 'shippingPostcode', 'shippingCity', 'shippingPhoneNumber' ] }); const selectedCountry = useMemo(() => { return countries.find( (country) => country.code === selectedCountryCode) }, [countries, selectedCountryCode]); const { data: statesData, loading: statesLoading } = useQuery(GET_COUNTRY_STATES, { variables: { countryId: selectedCountry?._id }, skip: !selectedCountryCode, }); let statesOptions: { value: string; label: string, id: string }[] = []; if(statesData) { statesOptions = statesData.countryStates.map((state) => ({ value: state.code, label: state.defaultName, id: String(state._id), })); } const [showDropDown, setShowDropDown] = useState(false); // 是否用户手动选择过区号 const [hasUserSelectedPhoneCode, setHasUserSelectedPhoneCode] = useState(false); // 国家变更后 state字段的值需要清空 // 选择国家时同步电话区号 useEffect(() => { const preShippingPhoneNum = getValues('shippingPhoneNumber'); const regPhoneCode = IS_VALID_PHONECODE; if(preShippingPhoneNum && !hasUserSelectedPhoneCode) { const newPhoneCode = getPhoneCodeBycountryCode(selectedCountryCode); const codePart = regPhoneCode.exec(preShippingPhoneNum); let phone = preShippingPhoneNum; if(codePart) { phone = preShippingPhoneNum.replace(codePart[0], ''); } if(codePart && newPhoneCode !== codePart[0].trim()) { return; } setValue('shippingPhoneNumber',formatFinalPhoneValue(newPhoneCode, phone)) } },[selectedCountryCode,hasUserSelectedPhoneCode,getValues,setValue]); const showMyAddressList = () => { setShowDropDown(true); }; const closeMyaddressList = useCallback(() => { setShowDropDown(false); },[]); // 从地址列表选择地址 const selectAddress = (param: CustomerAddressItem | 'edit') => { if(param === 'edit') { if(!showFormField) onShowFormFieldChange(true); } else { setValue('shippingFirstName',param.firstName); setValue('shippingLastName',param.lastName); setValue('shippingAddress',param.address); setValue('shippingCountry',param.country); setValue('shippingState',param.state); setValue('shippingPostcode',param.postcode); setValue('shippingCity',param.city); setValue('shippingPhoneNumber',param.phone); } closeMyaddressList(); }; /** * 游客: * 1. 购物车没地址 -- 进来显示填写新地址,地址表单;填完地址,保存,关闭弹窗,购物车地址更新;再次进来显示填写的地址,隐藏表单;如果想修改,就点击修改,显示地址表单; * 2. 购物车有地址 -- 进来显示已有的地址,隐藏表单;如果想修改,就点击修改,显示地址表单; * * 登录用户: * 1. 购物车没地址 -- 进来显示填写新地址,地址表单; * 如果想选已有地址,点击箭头,弹出地址列表,选择地址,选完地址更新到表单,关闭地址列表(打上选中状态);如果地址列表没数据,显示没有地址供选择; * 如果不想选地址,就填写地址表单。 * 保存地址,关闭弹窗; * 再次进来,显示购物车中的地址; * * 2. 购物车有地址 -- 进来显示购物车中的地址; * 如果想修改地址,点击箭头,出现地址列表 * * 地址列表数据直接在 父组件获取 */ return (<>
{firstName} {lastName} {phoneNumber}
{!isGuest && }{item.firstName} {item.lastName}, {item.address}, {item.city}, {item.state}, {item.postcode}, {item.country}, {item.phone}
Select a shipping address from your address book or enter a new address.
{/** * 登录用户: noAddres=false and showFormField = false 时 隐藏; noAddres=true 显示 * 游客: noAddres=false and showFormField = false 时 隐藏; noAddres=true 显示 */}