diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index 709b1f48b..b3ea2a038 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -1,4 +1,4 @@ -import { FacetValue } from './schema.d'; +import { FacetValue, UpdateAddressInput } from './schema.d'; export type Maybe = T | null export type Exact = { [K in keyof T]: T[K] @@ -304,6 +304,11 @@ export type MutationResetPasswordArgs = { } export type Address = Node & { + updateCustomerAddress: + | { + __typename?: 'Address' + id: Scalars['ID'] + } __typename?: 'Address' id: Scalars['ID'] createdAt: Scalars['DateTime'] @@ -1462,6 +1467,11 @@ export type CustomerListOptions = { } export type Customer = Node & { + updateCustomer: + | { + __typename?: 'Customer' + id: Scalars['ID'] + } __typename?: 'Customer' id: Scalars['ID'] createdAt: Scalars['DateTime'] @@ -1469,7 +1479,7 @@ export type Customer = Node & { title?: Maybe firstName: Scalars['String'] lastName: Scalars['String'] - phoneNumber?: Maybe + phoneNumber?: Maybe emailAddress: Scalars['String'] addresses?: Maybe> orders: OrderList @@ -3201,7 +3211,7 @@ export type ActiveCustomerQuery = { __typename?: 'Query' } & { activeCustomer?: Maybe< { __typename?: 'Customer' } & Pick< Customer, - 'id' | 'firstName' | 'lastName' | 'emailAddress' | 'addresses' + 'id' | 'firstName' | 'lastName' | 'emailAddress' | 'addresses' | 'phoneNumber' > > } diff --git a/framework/vendure/utils/mutations/update-customer-address-mutation.ts b/framework/vendure/utils/mutations/update-customer-address-mutation.ts new file mode 100644 index 000000000..4cac594ed --- /dev/null +++ b/framework/vendure/utils/mutations/update-customer-address-mutation.ts @@ -0,0 +1,14 @@ +export const updateCustomerAddress = /* GraphQL */ ` + mutation updateCustomerAddress($input: UpdateAddressInput!){ + updateCustomerAddress(input: $input){ + __typename + ...on Address{ + id + streetLine1 + city + postalCode + province + } + } + } +` diff --git a/framework/vendure/utils/mutations/update-customer-mutation.ts b/framework/vendure/utils/mutations/update-customer-mutation.ts new file mode 100644 index 000000000..535f80eee --- /dev/null +++ b/framework/vendure/utils/mutations/update-customer-mutation.ts @@ -0,0 +1,13 @@ +export const updateCustomer = /* GraphQL */ ` + mutation updateCustomer($input: UpdateCustomerInput!){ + updateCustomer(input:$input){ + __typename + ...on Customer{ + id + firstName + lastName + phoneNumber + } + } + } +` diff --git a/framework/vendure/utils/queries/active-customer-query.ts b/framework/vendure/utils/queries/active-customer-query.ts index 65b280743..b1598d8de 100644 --- a/framework/vendure/utils/queries/active-customer-query.ts +++ b/framework/vendure/utils/queries/active-customer-query.ts @@ -5,6 +5,13 @@ export const activeCustomerQuery = /* GraphQL */ ` firstName lastName emailAddress + phoneNumber + addresses{ + streetLine1 + city + province + postalCode + } } } ` diff --git a/framework/vendure/utils/queries/user-info-query.ts b/framework/vendure/utils/queries/user-info-query.ts index a10acd365..5e5fa24cb 100644 --- a/framework/vendure/utils/queries/user-info-query.ts +++ b/framework/vendure/utils/queries/user-info-query.ts @@ -1,14 +1,15 @@ export const userInfoQuery = /* GraphQL */ ` query activeCustomer{ activeCustomer{ + lastName + firstName emailAddress + phoneNumber addresses{ - name:fullName - address:streetLine1 + streetLine1 city - state:province + province postalCode - phoneNumber } } } diff --git a/src/components/common/SelectCommon/SelectCommon.module.scss b/src/components/common/SelectCommon/SelectCommon.module.scss index 82ce46f5b..3f213b567 100644 --- a/src/components/common/SelectCommon/SelectCommon.module.scss +++ b/src/components/common/SelectCommon/SelectCommon.module.scss @@ -11,7 +11,7 @@ width: 20.6rem; .selectTrigger { width: 20.6rem; - padding: 1.2rem 1.6rem; + padding: 1.6rem; } } &.large { diff --git a/src/components/common/SelectCommon/SelectCommon.tsx b/src/components/common/SelectCommon/SelectCommon.tsx index 9b8c88e24..122d9a78d 100644 --- a/src/components/common/SelectCommon/SelectCommon.tsx +++ b/src/components/common/SelectCommon/SelectCommon.tsx @@ -1,10 +1,12 @@ import s from './SelectCommon.module.scss' import classNames from 'classnames' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { IconVectorDown } from 'src/components/icons' import SelectOption from './SelectOption/SelectOption' interface Props { + selected?:string|null, + initValue?:string|null, placeholder? : string, size?: 'base' | 'large', type?: 'default' | 'custom', @@ -12,10 +14,14 @@ interface Props { onChange?: (value: string) => void, } -const SelectCommon = ({ type = 'default', size = 'base', option, placeholder, onChange}: Props) => { +const SelectCommon = ({selected,initValue, type = 'default', size = 'base', option, placeholder, onChange}: Props) => { const [selectedName, setSelectedName] = useState(placeholder) const [selectedValue, setSelectedValue] = useState('') + useEffect(()=>{ + setSelectedValue(selected ?? ''); + setSelectedValue(initValue ?? ''); + }) const changeSelectedName = (item:string, value: string) => { setSelectedValue(value) setSelectedName(item) diff --git a/src/components/hooks/auth/useActiveCustomer.tsx b/src/components/hooks/auth/useActiveCustomer.tsx index f0f4f6fef..353ce8ad9 100644 --- a/src/components/hooks/auth/useActiveCustomer.tsx +++ b/src/components/hooks/auth/useActiveCustomer.tsx @@ -5,7 +5,16 @@ import useSWR from 'swr' const useActiveCustomer = () => { const { data, ...rest } = useSWR([activeCustomerQuery], gglFetcher) - return { customer: data?.activeCustomer, ...rest } + return { + customer: data?.activeCustomer, + userInfo:{ + firstName: data?.activeCustomer?.firstName, + lastName:data?.activeCustomer?.lastName, + email:data?.activeCustomer?.emailAddress, + phoneNumber: data?.activeCustomer?.phoneNumber, + address: data?.activeCustomer?.addresses?.[0] + }, + ...rest } } export default useActiveCustomer diff --git a/src/components/hooks/auth/useSignup.tsx b/src/components/hooks/auth/useSignup.tsx index 922460c77..d9b085b0e 100644 --- a/src/components/hooks/auth/useSignup.tsx +++ b/src/components/hooks/auth/useSignup.tsx @@ -4,7 +4,6 @@ import { SignupMutation } from '@framework/schema' import fetcher from 'src/utils/fetcher' import { CommonError } from 'src/domains/interfaces/CommonError' import { signupMutation } from '@framework/utils/mutations/sign-up-mutation' - interface SignupInput { email: string firstName?: string diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts index cf83feb42..f2775d5bb 100644 --- a/src/components/hooks/index.ts +++ b/src/components/hooks/index.ts @@ -1 +1,4 @@ export { default as useModalCommon } from './useModalCommon' +export { default as useEditUserInfo } from './user/useEditUserInfo' +export { default as useEditCustomerAddress } from './user/useEditCustomerAddress' + diff --git a/src/components/hooks/user/useEditCustomerAddress.tsx b/src/components/hooks/user/useEditCustomerAddress.tsx new file mode 100644 index 000000000..5caae3eb1 --- /dev/null +++ b/src/components/hooks/user/useEditCustomerAddress.tsx @@ -0,0 +1,55 @@ +import { Address } from '@framework/schema' +import { updateCustomerAddress } from '@framework/utils/mutations/update-customer-address-mutation' +import { useState } from 'react' +import fetcher from 'src/utils/fetcher' +import { useActiveCustomer } from '../auth' + +interface Props { + address?:string, + city?:string|null, + postalCode?:string|null, + state?:string +} + +const useEditCustomerAddress = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const {customer,mutate} = useActiveCustomer(); + + const editCustomerAddress = ( + { address,city,postalCode,state}: Props, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + + fetcher
({ + query: updateCustomerAddress, + variables: { + input: { + id:customer?.id, + streetLine1:address, + city, + postalCode, + province:state + }, + }, + }) .then((data) => { + + if(data.updateCustomerAddress.__typename == 'Address'){ + mutate(); + fCallBack(true) + return data + } + + }) .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + + } + return { loading, editCustomerAddress, error } +} + +export default useEditCustomerAddress diff --git a/src/components/hooks/user/useEditUserInfo.tsx b/src/components/hooks/user/useEditUserInfo.tsx new file mode 100644 index 000000000..c2c8b1a83 --- /dev/null +++ b/src/components/hooks/user/useEditUserInfo.tsx @@ -0,0 +1,51 @@ +import { useState } from 'react' +import { Customer } from '@framework/schema' +import fetcher from 'src/utils/fetcher' +import { updateCustomer } from '@framework/utils/mutations/update-customer-mutation' +import { useActiveCustomer } from '../auth' + +interface Props { + firstName?: string; + lastName?: string, + phoneNumber?:string, +} + +const useEditUserInfo = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const {mutate} = useActiveCustomer(); + + const editUserInfo = ( + { firstName,lastName,phoneNumber}: Props, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + + fetcher({ + query: updateCustomer, + variables: { + input: { + firstName, + lastName, + phoneNumber + }, + }, + }) + .then((data) => { + if (data.updateCustomer.__typename == 'Customer') { + mutate(); + return data + } + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, editUserInfo, error } +} + +export default useEditUserInfo diff --git a/src/components/hooks/user/useUserInfo.tsx b/src/components/hooks/user/useUserInfo.tsx deleted file mode 100644 index 69b80a467..000000000 --- a/src/components/hooks/user/useUserInfo.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { ActiveCustomerQuery } from '@framework/schema' -import { userInfoQuery } from '@framework/utils/queries/user-info-query' -import gglFetcher from 'src/utils/gglFetcher' -import useSWR from 'swr' - -const useUserInfo = () => { - const { data } = useSWR([userInfoQuery], gglFetcher) - - return { userInfo: data?.activeCustomer} -} - -export default useUserInfo diff --git a/src/components/modules/account/AccountPage/AccountPage.tsx b/src/components/modules/account/AccountPage/AccountPage.tsx index e7154f46f..d8c169647 100644 --- a/src/components/modules/account/AccountPage/AccountPage.tsx +++ b/src/components/modules/account/AccountPage/AccountPage.tsx @@ -13,7 +13,6 @@ import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data'; import { ACCOUNT_TAB, QUERY_KEY } from "src/utils/constanst.utils" import { useRouter } from "next/router" import { useActiveCustomer } from 'src/components/hooks/auth' -import useUserInfo from "src/components/hooks/user/useUserInfo" import { AccountProps } from "./components/AccountInfomation/AccountInfomation" const waiting = [ { @@ -54,17 +53,6 @@ const delivered = [ } ] -let account = { - firstName: "Nhân", - lastName: "Trần", - email: "vuduong@gmail.com", - address: "235 Dien Bien Phu Bis, Dakao ward", - state: "District 1", - city: "HCMC", - postalCode: "700000", - phoneNumber: "(+84) 937 937 195" -} - interface AccountPageProps { defaultActiveContent?: "info" | "orders" | "favorites" } @@ -84,18 +72,8 @@ const getTabIndex = (tab?: string): number => { const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { const router = useRouter() - const {userInfo} = useUserInfo(); - - // const email = userInfo?.emailAddress; - // const [info] = userInfo?.addresses || []; - - // const accountInfo = {...info,userInfo?.emailAddress}; - - // const clone:AccountProps = Object.create(accountInfo); - // Object.assign(clone, accountInfo); - - - console.log(); + const {userInfo} = useActiveCustomer(); + const [activeTab, setActiveTab] = useState(defaultActiveContent==="info" ? 0 : defaultActiveContent==="orders" ? 1 : 2) const [modalVisible, setModalVisible] = useState(false); @@ -123,7 +101,7 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { - + @@ -133,7 +111,7 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => { - + ) } diff --git a/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx b/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx index dc32db71a..362d449ac 100644 --- a/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx +++ b/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx @@ -6,17 +6,21 @@ import avatar from '../../assets/avatar.png' import { ButtonCommon } from 'src/components/common' import { useActiveCustomer } from 'src/components/hooks/auth' +import { Address } from '@framework/schema' export interface AccountProps { - name?: string + firstName?: string + lastName?: string email?: string - address?: string - state?: string - city?: string - postalCode?: string - phoneNumber?: string + phoneNumber?:string|null + address?: Address } +const states = [ + {name: "District 1", value: "D1"}, + {name: "District 2", value: "D2"}, + {name: "District 3", value: "D3"} +] interface AccountInfomationProps { account: AccountProps onClick: () => void @@ -24,11 +28,10 @@ interface AccountInfomationProps { const AccountInfomation = ({ account, onClick }: AccountInfomationProps) => { const { customer } = useActiveCustomer() - // need to handle call back when edit account information const showEditForm = () => onClick() - + const state = states.find((val)=>val.value == account.address?.province); return (
@@ -45,8 +48,8 @@ const AccountInfomation = ({ account, onClick }: AccountInfomationProps) => {
Shipping Infomation
- {account.address + - `, ${account.state}, ${account.city}, ${account.postalCode}`} + {account.address?.streetLine1 + + `, ${state?.name}, ${account.address?.city}, ${account.address?.postalCode}`}
{account.phoneNumber}
diff --git a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss index 20acd257b..e098b9af7 100644 --- a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss +++ b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss @@ -1,6 +1,15 @@ @import '../../../../../../styles/utilities'; .editInfoModal { + .u-form{ + width: 60rem; + } + .inputName{ + @apply flex justify-between; + .input{ + width: 48.5%; + } + } .input { @apply bg-white; margin-bottom: 1.6rem; @@ -23,6 +32,7 @@ .inputPostalCode { @apply bg-white; margin-left: 0.8rem; + width: 100%; } .inputPhoneNumber { diff --git a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx index f9e4aebd5..c3a2b1e34 100644 --- a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx +++ b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx @@ -1,19 +1,34 @@ -import React from "react" +import React, { useState } from "react" import s from './EditInfoModal.module.scss' -import { ModalCommon, Inputcommon, SelectCommon, ButtonCommon } from '../../../../../common' - +import { ModalCommon, SelectCommon, ButtonCommon } from '../../../../../common' +import { Address } from "@framework/schema"; +import { + InputFiledInForm, + } from 'src/components/common' +import * as Yup from 'yup' +import { Form, Formik } from 'formik' +import { useEditCustomerAddress, useEditUserInfo } from "src/components/hooks"; +import { LANGUAGE } from 'src/utils/language.utils' +import { useMessage } from 'src/components/contexts' interface EditInfoModalProps { - accountInfo: {firstName: string,lastName: string, email: string, address: string, state: string, city: string, postalCode: string, phoneNumber: string}; + accountInfo: { + firstName?: string + lastName?: string + email?: string + phoneNumber?:string|null + address?: Address + }; visible: boolean; closeModal: () => void; } const EditInfoModal = ({ accountInfo, visible = false, closeModal }: EditInfoModalProps) => { + const [stateValue,setStateValue] = useState(''); + const { loading, editUserInfo } = useEditUserInfo(); + const {editCustomerAddress} = useEditCustomerAddress(); + const { showMessageSuccess, showMessageError } = useMessage() - function saveInfo() { - closeModal(); - } const states = [ {name: "District 1", value: "D1"}, @@ -21,43 +36,165 @@ const EditInfoModal = ({ accountInfo, visible = false, closeModal }: EditInfoMod {name: "District 3", value: "D3"} ] + const DisplayingErrorMessagesSchema = Yup.object().shape({ + firstName: Yup.string().required('Required'), + lastName: Yup.string().required('Required'), + address: Yup.string().required('Required'), + city: Yup.string().required('Required'), + postalCode: Yup.string(), + phoneNumber: Yup.string(), + }) + + function onEditUserInfo ( + values: { + firstName: string|undefined; + lastName: string|undefined, + address:string|undefined, + city?:string|null, + postalCode?:string|null, + phoneNumber?:string|null + }) { + + editUserInfo( + { + firstName: values.firstName, + lastName: values.lastName, + phoneNumber:values.phoneNumber ?? '', + },onChangUserInfoCallBack); + + editCustomerAddress( + { + address: values.address , + city:values.city, + postalCode:values.postalCode, + state:stateValue + }, + onChangUserInfoCallBack); + } + + function onChangUserInfoCallBack(isSuccess: boolean, message?: string){ + if (isSuccess) { + closeModal(); + showMessageSuccess("Change Your Information Successfully.", 15000) + } else { + showMessageError(LANGUAGE.MESSAGE.ERROR) + } + } + function state(state:string){ + setStateValue(state); + } return (
-
- -
-
- -
- -
- -
- -
- -
- - -
-
- + + {({ errors, touched, isValid, submitForm }) => ( +
+
+
+ +
+
+ +
-
- +
+
-
+ +
+ +
+ -
- -
+
+
+ +
-
- Cancel - Save -
+
+ +
+
+ +
+ +
+ +
+ Cancel + Save +
+
+ )} +
)