Skip to content

Commit 3b6c168

Browse files
committed
feat: complete switch between shipping methoods
1 parent ad5dd77 commit 3b6c168

File tree

6 files changed

+133
-84
lines changed

6 files changed

+133
-84
lines changed

src/app/[locale]/(main)/(container)/cart/components/CheckoutBoxSkeleton.tsx

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
import { Card, CardContent, Skeleton, Stack } from '@mui/material';
2-
import React from 'react';
1+
import { Skeleton, Stack } from '@mui/material';
32

43
const CheckoutBoxSkeleton = () => {
54
return (
6-
<Card variant="outlined">
7-
<CardContent>
8-
{new Array(4).fill(1).map((key) => {
9-
return (
10-
<Stack direction="row" key={key} justifyContent="space-between">
11-
<Skeleton width="40%" />
12-
<Skeleton width="40%" />
13-
</Stack>
14-
);
15-
})}
16-
</CardContent>
17-
</Card>
5+
<>
6+
{new Array(4).fill(1).map((key) => {
7+
return (
8+
<Stack direction="row" key={key} justifyContent="space-between">
9+
<Skeleton height={30} width="40%" />
10+
<Skeleton height={30} width="40%" />
11+
</Stack>
12+
);
13+
})}
14+
</>
1815
);
1916
};
2017

src/app/[locale]/(main)/(container)/cart/loading.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { Grid } from '@mui/material';
1+
'use client';
2+
3+
import { Card, CardActions, CardContent, Grid, Skeleton } from '@mui/material';
24
import CartItemsSkeleton from './components/CartItemsSkeleton';
35
import CheckoutBoxSkeleton from './components/CheckoutBoxSkeleton';
46

@@ -10,7 +12,14 @@ const Loading = () => {
1012
</Grid>
1113

1214
<Grid item lg={3} md={6} xs={12}>
13-
<CheckoutBoxSkeleton />
15+
<Card variant="outlined">
16+
<CardContent>
17+
<CheckoutBoxSkeleton />
18+
</CardContent>
19+
<CardActions>
20+
<Skeleton width="100%" variant="rectangular" height={42} />
21+
</CardActions>
22+
</Card>
1423
</Grid>
1524
</Grid>
1625
);

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

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import useCartQuery from '@/hooks/useCartQuery';
1515
import { Link } from '@/navigation';
1616
import {
1717
Box,
18-
Button,
1918
Card,
2019
CardActions,
2120
CardContent,
@@ -26,6 +25,7 @@ import {
2625
} from '@mui/material';
2726
import { useTranslations } from 'next-intl';
2827

28+
import ButtonWithLoading from '@/components/common/ButtonWithLoading';
2929
import { cartAtom } from '@/store/atoms';
3030
import { useAtomValue } from 'jotai';
3131
import CartItemsSkeleton from './components/CartItemsSkeleton';
@@ -139,39 +139,40 @@ const Page = () => {
139139
</Grid>
140140

141141
<Grid item lg={3} md={6} xs={12}>
142-
{loading && <CheckoutBoxSkeleton />}
143-
144-
{!loading && (
145-
<Stack
146-
spacing={2}
147-
sx={{
148-
position: 'sticky',
149-
top: 196,
150-
zIndex: (theme) => theme.zIndex.drawer - 1,
151-
}}
152-
>
153-
<Card variant="outlined">
154-
<CardContent>
142+
<Stack
143+
spacing={2}
144+
sx={{
145+
position: 'sticky',
146+
top: 196,
147+
zIndex: (theme) => theme.zIndex.drawer - 1,
148+
}}
149+
>
150+
<Card variant="outlined">
151+
<CardContent>
152+
{loading ? (
153+
<CheckoutBoxSkeleton />
154+
) : (
155155
<CheckoutBox content={content!} />
156-
</CardContent>
157-
<CardActions>
158-
<Button
159-
component={Link}
160-
href="/checkout"
161-
fullWidth
162-
color="primary"
163-
size="large"
164-
variant="contained"
165-
>
166-
{t('pages.cart.buttons.registerAndNextStep')}
167-
</Button>
168-
</CardActions>
169-
</Card>
170-
<Typography variant="body2" color="gray">
171-
{t('messages.cart.reserveMessage')}
172-
</Typography>
173-
</Stack>
174-
)}
156+
)}
157+
</CardContent>
158+
<CardActions>
159+
<ButtonWithLoading
160+
isLoading={loading}
161+
component={Link}
162+
href="/checkout"
163+
fullWidth
164+
color="primary"
165+
size="large"
166+
variant="contained"
167+
>
168+
{t('pages.cart.buttons.registerAndNextStep')}
169+
</ButtonWithLoading>
170+
</CardActions>
171+
</Card>
172+
<Typography variant="body2" color="gray">
173+
{t('messages.cart.reserveMessage')}
174+
</Typography>
175+
</Stack>
175176
</Grid>
176177
</Grid>
177178
);

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

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,38 @@
11
import PriceLabel from '@/components/common/PriceLabel';
2-
import { UPDATE_SHIPPING_METHOD } from '@/graphql/queries/cart';
3-
import {
4-
ShippingRate,
5-
UpdateShippingMethodMutation,
6-
} from '@/graphql/types/graphql';
7-
import { useMutation } from '@apollo/client';
2+
import { ShippingRate } from '@/graphql/types/graphql';
83
import { Radio, Stack, Typography } from '@mui/material';
9-
import { FC } from 'react';
4+
import { FC, useState } from 'react';
105
import ShippingMethodItem from './ShippingMethodItem';
116

127
export interface AvailableShippingMethodsProps {
138
rates: ShippingRate[];
14-
value?: string | null;
9+
defaultValue?: string | null;
10+
isFree?: boolean;
11+
onChange?: Function;
1512
}
1613
const AvailableShippingMethods: FC<AvailableShippingMethodsProps> = ({
1714
rates,
18-
value,
15+
defaultValue,
16+
isFree,
17+
onChange,
1918
}) => {
20-
const [update, { loading }] = useMutation<UpdateShippingMethodMutation>(
21-
UPDATE_SHIPPING_METHOD,
22-
);
19+
const [value, setValue] = useState(defaultValue);
2320

24-
const handleChange = (value: string) => {
25-
update({
26-
variables: {
27-
shippingMethods: [value],
28-
},
29-
});
21+
const handleChange = async (newValue: string) => {
22+
try {
23+
setValue(newValue);
24+
onChange?.(newValue);
25+
} catch (error) {
26+
setValue(defaultValue);
27+
}
3028
};
3129

3230
return (
3331
<Stack spacing={0.5}>
3432
{rates?.map((rate) => {
33+
if (!rate) {
34+
return null;
35+
}
3536
const selected = rate.id === value;
3637
return (
3738
<ShippingMethodItem
@@ -41,9 +42,16 @@ const AvailableShippingMethods: FC<AvailableShippingMethodsProps> = ({
4142
>
4243
<Stack direction="row" spacing={1} alignItems="center">
4344
<Radio disableRipple checked={selected} size="small" />
45+
4446
<Typography variant="body2">{rate.label}</Typography>
4547
</Stack>
46-
{!!rate.cost && <PriceLabel value={rate.cost} />}
48+
49+
{!!rate.cost && !isFree && <PriceLabel value={rate.cost} />}
50+
{isFree && (
51+
<Typography color="primary" fontWeight={600}>
52+
رایگان
53+
</Typography>
54+
)}
4755
</ShippingMethodItem>
4856
);
4957
})}

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

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
'use client';
22

3-
import { getFragmentData } from '@/graphql/types';
4-
import { CartContentFragmentDoc, ShippingRate } from '@/graphql/types/graphql';
3+
import ButtonWithLoading from '@/components/common/ButtonWithLoading';
4+
import { UPDATE_SHIPPING_METHOD } from '@/graphql/queries/cart';
5+
import {
6+
ShippingRate,
7+
UpdateShippingMethodMutation,
8+
} from '@/graphql/types/graphql';
59
import useCartQuery from '@/hooks/useCartQuery';
10+
import { cartAtom } from '@/store/atoms';
11+
import { useMutation } from '@apollo/client';
612
import {
7-
Button,
813
Card,
914
CardActions,
1015
CardContent,
1116
Grid,
1217
Stack,
1318
TextField,
1419
} from '@mui/material';
20+
import { useAtomValue } from 'jotai';
1521
import { useTranslations } from 'next-intl';
22+
import { useEffect } from 'react';
1623
import { Controller, useForm } from 'react-hook-form';
1724
import CheckoutBox from '../cart/components/CheckoutBox';
25+
import CheckoutBoxSkeleton from '../cart/components/CheckoutBoxSkeleton';
1826
import DiscountCode from '../cart/components/DiscountCode';
1927
import AvailableShippingMethods from './components/AvailableShippingMethods';
2028
import Billing from './components/Billing';
@@ -23,19 +31,40 @@ const Page = () => {
2331
const t = useTranslations();
2432
const form = useForm();
2533

26-
const { loading, data } = useCartQuery();
34+
const { loading, refetch } = useCartQuery();
35+
36+
useEffect(() => {
37+
refetch();
38+
}, []);
2739

28-
const content = getFragmentData(CartContentFragmentDoc, data?.cart);
40+
const [update, { loading: shippingMethodLoading }] =
41+
useMutation<UpdateShippingMethodMutation>(UPDATE_SHIPPING_METHOD);
2942

43+
const content = useAtomValue(cartAtom);
3044
if (!content?.contents?.itemCount) return <></>;
3145

46+
const rates = content?.availableShippingMethods?.flatMap((item) => {
47+
return item?.rates;
48+
}) as ShippingRate[];
49+
50+
const notFreeRates = rates.filter((item) => !item.methodId.includes('free'));
51+
52+
const isFree = rates.length !== notFreeRates.length;
53+
3254
const onSubmit = (data: any) => {
3355
console.log(data);
3456
};
3557

36-
const rates = content?.availableShippingMethods?.flatMap((item) => {
37-
return item?.rates;
38-
}) as ShippingRate[];
58+
const onShippingMethodChange = async (newValue: string) => {
59+
await update({
60+
variables: {
61+
shippingMethods: [newValue],
62+
},
63+
});
64+
refetch();
65+
};
66+
67+
const isLoading = loading || shippingMethodLoading;
3968

4069
return (
4170
<Grid container spacing={2} position="relative">
@@ -44,8 +73,10 @@ const Page = () => {
4473
<CardContent>
4574
<Stack spacing={3}>
4675
<AvailableShippingMethods
47-
rates={rates}
48-
value={content.chosenShippingMethods?.[0]}
76+
isFree={isFree}
77+
rates={notFreeRates}
78+
defaultValue={content.chosenShippingMethods?.[0]}
79+
onChange={onShippingMethodChange}
4980
/>
5081

5182
<Billing />
@@ -87,18 +118,23 @@ const Page = () => {
87118

88119
<Card variant="outlined">
89120
<CardContent>
90-
<CheckoutBox content={content} />
121+
{isLoading ? (
122+
<CheckoutBoxSkeleton />
123+
) : (
124+
<CheckoutBox content={content} />
125+
)}
91126
</CardContent>
92127
<CardActions>
93-
<Button
128+
<ButtonWithLoading
129+
isLoading={isLoading}
94130
type="submit"
95131
variant="contained"
96132
color="primary"
97133
fullWidth
98134
size="large"
99135
>
100136
{t('pages.checkout.buttons.placeOrder')}
101-
</Button>
137+
</ButtonWithLoading>
102138
</CardActions>
103139
</Card>
104140
</Stack>

src/hooks/useAddOrUpdateCartItem.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ const useAddOrUpdateCartItem: IUseAddOrUpdateCartItem = () => {
5757
const addOrUpdateCartItemMutate: MutateCartFunction = async (values) => {
5858
const { quantity, variationId, productId, extraData } = values;
5959
if (!variationId) {
60-
toast.error(t('messages.cart.selectYourSize'), {
61-
toastId: 'variant-is-not-exist',
62-
});
60+
toast.error(t('messages.cart.selectYourSize'));
6361
return null;
6462
}
6563

0 commit comments

Comments
 (0)