Skip to content

Commit 1a35ceb

Browse files
committed
feat: add all checkout fields
1 parent eee7664 commit 1a35ceb

File tree

10 files changed

+491
-425
lines changed

10 files changed

+491
-425
lines changed

src/app/[locale]/(main)/(container)/checkout/components/Billing.tsx

Lines changed: 0 additions & 57 deletions
This file was deleted.

src/app/[locale]/(main)/(container)/checkout/page.tsx

Lines changed: 162 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
'use client';
22

3+
import UserFields from '@/components/UserFields/UserFields';
4+
import useUserFields from '@/components/UserFields/hooks/useUserFields';
35
import ButtonWithLoading from '@/components/common/ButtonWithLoading';
6+
import { authClient } from '@/graphql/clients/authClient';
47
import {
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';
1216
import {
1317
CheckoutMutation,
18+
GetCustomerBillingQuery,
19+
GetCustomerBillingQueryVariables,
1420
GetPaymentGatewaysQuery,
1521
RemoveItemsFromCartMutation,
1622
ShippingRate,
@@ -20,6 +26,8 @@ import useCartQuery from '@/hooks/useCartQuery';
2026
import { redirect } from '@/navigation';
2127
import { cartAtom } from '@/store/atoms';
2228
import { useMutation, useQuery } from '@apollo/client';
29+
import { yupResolver } from '@hookform/resolvers/yup';
30+
import { LocationOnOutlined } from '@mui/icons-material';
2331
import {
2432
Card,
2533
CardActions,
@@ -31,31 +39,55 @@ import {
3139
import { useAtomValue } from 'jotai';
3240
import { useTranslations } from 'next-intl';
3341
import { 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';
3544
import CheckoutBox from '../cart/components/CheckoutBox';
3645
import CheckoutBoxSkeleton from '../cart/components/CheckoutBoxSkeleton';
3746
import DiscountCode from '../cart/components/DiscountCode';
3847
import AvailablePaymentGateways from './components/AvailablePaymentGateways';
3948
import AvailableShippingMethods from './components/AvailableShippingMethods';
40-
import Billing from './components/Billing';
41-
import { authClient } from '@/graphql/clients/authClient';
49+
import CardHeader from './components/CardHeader';
4250
import Loading from './loading';
4351

4452
const 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

Comments
 (0)