11'use client' ;
22
3+ import UserFields from '@/components/UserFields/UserFields' ;
4+ import useUserFields from '@/components/UserFields/hooks/useUserFields' ;
35import ButtonWithLoading from '@/components/common/ButtonWithLoading' ;
6+ import { authClient } from '@/graphql/clients/authClient' ;
47import {
58 EMPTY_CART_MUTATION ,
69 UPDATE_SHIPPING_METHOD ,
@@ -9,8 +12,11 @@ import {
912 CHECKOUT_MUTATION ,
1013 GET_PAYMENT_GATEWAYS ,
1114} from '@/graphql/queries/checkout' ;
15+ import { GET_CUSTOMER_BILLING } from '@/graphql/queries/customer' ;
1216import {
1317 CheckoutMutation ,
18+ GetCustomerBillingQuery ,
19+ GetCustomerBillingQueryVariables ,
1420 GetPaymentGatewaysQuery ,
1521 RemoveItemsFromCartMutation ,
1622 ShippingRate ,
@@ -20,6 +26,8 @@ import useCartQuery from '@/hooks/useCartQuery';
2026import { redirect } from '@/navigation' ;
2127import { cartAtom } from '@/store/atoms' ;
2228import { useMutation , useQuery } from '@apollo/client' ;
29+ import { yupResolver } from '@hookform/resolvers/yup' ;
30+ import { LocationOnOutlined } from '@mui/icons-material' ;
2331import {
2432 Card ,
2533 CardActions ,
@@ -31,31 +39,55 @@ import {
3139import { useAtomValue } from 'jotai' ;
3240import { useTranslations } from 'next-intl' ;
3341import { useEffect } from 'react' ;
34- import { Controller , useForm } from 'react-hook-form' ;
42+ import { Controller , FormProvider , useForm } from 'react-hook-form' ;
43+ import * as yup from 'yup' ;
3544import CheckoutBox from '../cart/components/CheckoutBox' ;
3645import CheckoutBoxSkeleton from '../cart/components/CheckoutBoxSkeleton' ;
3746import DiscountCode from '../cart/components/DiscountCode' ;
3847import AvailablePaymentGateways from './components/AvailablePaymentGateways' ;
3948import AvailableShippingMethods from './components/AvailableShippingMethods' ;
40- import Billing from './components/Billing' ;
41- import { authClient } from '@/graphql/clients/authClient' ;
49+ import CardHeader from './components/CardHeader' ;
4250import Loading from './loading' ;
4351
4452const Page = ( ) => {
4553 const t = useTranslations ( ) ;
46- const form = useForm ( ) ;
54+
55+ const { schema } = useUserFields ( ) ;
56+
57+ const checkoutSchema = yup . object ( {
58+ paymentMethod : yup . string ( ) . nullable ( ) . required ( ) ,
59+ customerNote : yup . string ( ) . max ( 500 ) . nullable ( ) ,
60+ } ) ;
61+
62+ const form = useForm ( {
63+ resolver : yupResolver ( schema . concat ( checkoutSchema ) ) ,
64+ } ) ;
65+
4766 const content = useAtomValue ( cartAtom ) ;
4867
49- const gatewaysQuery = useQuery < GetPaymentGatewaysQuery > (
50- GET_PAYMENT_GATEWAYS ,
51- {
52- onCompleted : ( data ) => {
53- form . reset ( {
54- paymentMethod : data ?. paymentGateways ?. nodes ?. [ 0 ] . id ,
55- } ) ;
56- } ,
57- } ,
58- ) ;
68+ const gatewaysQuery = useQuery < GetPaymentGatewaysQuery > ( GET_PAYMENT_GATEWAYS ) ;
69+ const customer = useQuery <
70+ GetCustomerBillingQuery ,
71+ GetCustomerBillingQueryVariables
72+ > ( GET_CUSTOMER_BILLING , {
73+ client : authClient ,
74+ } ) ;
75+
76+ useEffect ( ( ) => {
77+ if (
78+ ! customer . loading &&
79+ ! ! customer . data &&
80+ ! gatewaysQuery . loading &&
81+ ! ! gatewaysQuery . data
82+ ) {
83+ const billing = customer . data . customer ?. billing ! ;
84+ delete billing . __typename ;
85+ form . reset ( {
86+ ...billing ,
87+ paymentMethod : gatewaysQuery . data ?. paymentGateways ?. nodes ?. [ 0 ] . id ! ,
88+ } ) ;
89+ }
90+ } , [ gatewaysQuery . loading , customer . loading ] ) ;
5991
6092 const { loading, refetch } = useCartQuery ( ) ;
6193
@@ -104,10 +136,13 @@ const Page = () => {
104136 } ;
105137
106138 const onSubmit = async ( payload : any ) => {
139+ const { customerNote, paymentMethod, ...billing } = payload ;
107140 const { data } = await checkout ( {
108141 variables : {
109- customerNote : payload . customerNote ,
110- paymentMethod : payload . paymentMethod ,
142+ customerNote : customerNote ,
143+ paymentMethod : paymentMethod ,
144+ billing : billing ,
145+ shipping : billing ,
111146 } ,
112147 } ) ;
113148
@@ -120,101 +155,121 @@ const Page = () => {
120155 } ;
121156
122157 const isCartLoading = loading || shippingMethodLoading ;
123- const isButtonLoading = isCartLoading || checkoutLoading || emptyCartLoading ;
158+ const isButtonLoading =
159+ isCartLoading || customer . loading || checkoutLoading || emptyCartLoading ;
124160
125161 return (
126- < Grid
127- container
128- spacing = { 2 }
129- position = "relative"
130- component = "form"
131- onSubmit = { form . handleSubmit ( onSubmit ) }
132- >
133- < Grid item lg = { 9 } md = { 6 } xs = { 12 } >
134- < Stack spacing = { 3 } >
135- < AvailableShippingMethods
136- isFree = { isFree }
137- rates = { notFreeRates }
138- defaultValue = { content . chosenShippingMethods ?. [ 0 ] }
139- onChange = { onShippingMethodChange }
140- />
141-
142- < Billing />
143- < Controller
144- control = { form . control }
145- name = "customerNote"
146- render = { ( {
147- field : { name, value, onChange } ,
148- fieldState : { error } ,
149- } ) => {
150- return (
151- < TextField
152- onChange = { onChange }
153- name = { name }
154- multiline
155- rows = { 4 }
156- value = { value }
157- variant = "outlined"
158- fullWidth
159- placeholder = { t ( 'pages.checkout.fields.description' ) }
160- error = { ! ! error ?. message }
161- helperText = { error ?. message ?. toString ( ) }
162- />
163- ) ;
164- } }
165- />
166-
167- < Controller
168- name = "paymentMethod"
169- control = { form . control }
170- render = { ( props ) => {
171- const {
172- field : { value, onChange } ,
173- } = props ;
174- return (
175- < AvailablePaymentGateways
176- value = { value }
177- onChange = { onChange }
178- items = { gatewaysQuery . data }
179- />
180- ) ;
181- } }
182- />
183- </ Stack >
184- </ Grid >
162+ < FormProvider { ...form } >
163+ < Grid
164+ container
165+ spacing = { 2 }
166+ position = "relative"
167+ component = "form"
168+ onSubmit = { form . handleSubmit ( onSubmit ) }
169+ >
170+ < Grid item lg = { 9 } md = { 6 } xs = { 12 } >
171+ < Stack spacing = { 3 } >
172+ < AvailableShippingMethods
173+ isFree = { isFree }
174+ rates = { notFreeRates }
175+ defaultValue = { content . chosenShippingMethods ?. [ 0 ] }
176+ onChange = { onShippingMethodChange }
177+ />
178+
179+ < Card variant = "outlined" >
180+ < CardHeader
181+ title = { t ( 'pages.checkout.shipmentTo' ) }
182+ icon = { LocationOnOutlined }
183+ />
184+
185+ < CardContent >
186+ < Grid container spacing = { 2 } >
187+ < UserFields
188+ loading = { customer . loading }
189+ disabled = {
190+ checkoutLoading || customer . loading || emptyCartLoading
191+ }
192+ />
193+ </ Grid >
194+ </ CardContent >
195+ </ Card >
185196
186- < Grid item lg = { 3 } md = { 6 } xs = { 12 } >
187- < Stack spacing = { 3 } >
188- < Card variant = "outlined" >
189- < CardContent >
190- < DiscountCode />
191- </ CardContent >
192- </ Card >
193-
194- < Card variant = "outlined" >
195- < CardContent >
196- { isCartLoading ? (
197- < CheckoutBoxSkeleton />
198- ) : (
199- < CheckoutBox content = { content } />
200- ) }
201- </ CardContent >
202- < CardActions >
203- < ButtonWithLoading
204- isLoading = { isButtonLoading }
205- type = "submit"
206- variant = "contained"
207- color = "primary"
208- fullWidth
209- size = "large"
210- >
211- { t ( 'pages.checkout.buttons.placeOrder' ) }
212- </ ButtonWithLoading >
213- </ CardActions >
214- </ Card >
215- </ Stack >
197+ < Controller
198+ control = { form . control }
199+ name = "customerNote"
200+ render = { ( {
201+ field : { name, value, onChange } ,
202+ fieldState : { error } ,
203+ } ) => {
204+ return (
205+ < TextField
206+ onChange = { onChange }
207+ name = { name }
208+ multiline
209+ rows = { 4 }
210+ value = { value }
211+ variant = "outlined"
212+ fullWidth
213+ placeholder = { t ( 'pages.checkout.fields.description' ) }
214+ error = { ! ! error ?. message }
215+ helperText = { error ?. message ?. toString ( ) }
216+ />
217+ ) ;
218+ } }
219+ />
220+
221+ < Controller
222+ name = "paymentMethod"
223+ control = { form . control }
224+ render = { ( props ) => {
225+ const {
226+ field : { value, onChange } ,
227+ } = props ;
228+ return (
229+ < AvailablePaymentGateways
230+ value = { value }
231+ onChange = { onChange }
232+ items = { gatewaysQuery . data }
233+ />
234+ ) ;
235+ } }
236+ />
237+ </ Stack >
238+ </ Grid >
239+
240+ < Grid item lg = { 3 } md = { 6 } xs = { 12 } >
241+ < Stack spacing = { 3 } >
242+ < Card variant = "outlined" >
243+ < CardContent >
244+ < DiscountCode />
245+ </ CardContent >
246+ </ Card >
247+
248+ < Card variant = "outlined" >
249+ < CardContent >
250+ { isCartLoading ? (
251+ < CheckoutBoxSkeleton />
252+ ) : (
253+ < CheckoutBox content = { content } />
254+ ) }
255+ </ CardContent >
256+ < CardActions >
257+ < ButtonWithLoading
258+ isLoading = { isButtonLoading }
259+ type = "submit"
260+ variant = "contained"
261+ color = "primary"
262+ fullWidth
263+ size = "large"
264+ >
265+ { t ( 'pages.checkout.buttons.placeOrder' ) }
266+ </ ButtonWithLoading >
267+ </ CardActions >
268+ </ Card >
269+ </ Stack >
270+ </ Grid >
216271 </ Grid >
217- </ Grid >
272+ </ FormProvider >
218273 ) ;
219274} ;
220275
0 commit comments