Parcourir la source

refactor: merge fix

front
Lazar Kostic il y a 3 ans
Parent
révision
0b13d5ccfe

+ 177
- 164
components/cards/cart-card/CartCard.tsx Voir le fichier

@@ -1,176 +1,189 @@
import { Box, Button, ButtonGroup, Card, Typography } from '@mui/material';
import { useTranslation } from 'next-i18next';
import Image from 'next/image';
import { useState } from 'react';
import { useState, FC } from 'react';
import { ProductData } from '../../../utils/interface/productInterface';

const CartCard = ({ product, initialQuantity, remove, updateQuantity }) => {
const [quantity, setQuantity] = useState(initialQuantity);
const { t } = useTranslation('cart');
return (
<Card
interface Props {
product: ProductData;
initialQuantity: number;
remove: (x: string) => void;
updateQuantity: (x: string, y: number) => void;
}

const CartCard: FC<Props> = ({
product,
initialQuantity,
remove,
updateQuantity,
}) => {
const [quantity, setQuantity] = useState(initialQuantity);
const { t } = useTranslation('cart');
return (
<Card
sx={{
backgroundColor: '#f2f2f2',
p: 2,
mb: 2,
}}
>
<Box
sx={{
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
justifyContent: { xs: 'center' },
}}
>
<Box
sx={{
display: 'flex',
justifyContent: 'center',
mb: { xs: 2, md: 0 },
}}
>
<Image src={product.image} alt="profile" width={200} height={200} />
</Box>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyItems: 'center',
width: { md: '40%' },
}}
>
<Typography
align="center"
sx={{
backgroundColor: '#f2f2f2',
p: 2,
mb: 2,
mb: { xs: 5, sm: 5, md: 0 },
mr: { md: 5 },
width: '100%',
fontWeight: 600,
fontSize: { xs: 20, sm: 20 },
}}
>
{product?.name}
</Typography>
</Box>
<Box
sx={{
display: 'flex',
flexDirection: { xs: 'row', md: 'column' },
justifyContent: 'center',
alignItems: { xs: 'flex-end', md: 'center' },
mb: { xs: 5, sm: 5, md: 0 },
mr: { md: 5 },
}}
>
<Box
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-end',
mr: { xs: 2, md: 0 },
}}
>
<Typography
sx={{
width: '100%',
textAlign: 'center',
height: 16,
fontSize: 14,
}}
>
{t('cart:quantity')}
</Typography>
<ButtonGroup
size="small"
aria-label="small outlined button group"
sx={{
height: 35,
mt: 1,
backgroundColor: 'primary.main',
color: 'white',
border: 0,
}}
>
<Button
sx={{
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
justifyContent: { xs: 'center' },
color: 'white',
fontSize: 17,
width: 25,
}}
>
<Box
sx={{
display: 'flex',
justifyContent: 'center',
mb: { xs: 2, md: 0 },
}}
>
<Image src={product.image} alt="profile" width={200} height={200} />
</Box>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyItems: 'center',
width: { md: '40%' },
}}
>
<Typography
align="center"
sx={{
mb: { xs: 5, sm: 5, md: 0 },
mr: { md: 5 },
width: '100%',
fontWeight: 600,
fontSize: { xs: 20, sm: 20 },
}}
>
{product?.name}
</Typography>
</Box>
<Box
sx={{
display: 'flex',
flexDirection: { xs: 'row', md: 'column' },
justifyContent: 'center',
alignItems: { xs: 'flex-end', md: 'center' },
mb: { xs: 5, sm: 5, md: 0 },
mr: { md: 5 },
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-end',
mr: { xs: 2, md: 0 },
}}
>
<Typography
sx={{
width: '100%',
textAlign: 'center',
height: 16,
fontSize: 14,
}}
>
{t('cart:quantity')}
</Typography>
<ButtonGroup
size="small"
aria-label="small outlined button group"
sx={{
height: 35,
mt: 1,
backgroundColor: 'primary.main',
color: 'white',
border: 0,
}}
>
<Button
sx={{
color: 'white',
fontSize: 17,
width: 25,
}}
onClick={() => {
if (quantity > 1) {
updateQuantity(product?.customID, quantity - 1);
setQuantity((prevState) => prevState - 1);
}
}}
>
-
</Button>
<Button
sx={{
color: 'white',
fontSize: 15,
width: 25,
}}
>
{quantity}
</Button>
<Button
sx={{
color: 'white',
fontSize: 17,
width: 25,
}}
onClick={() => {
updateQuantity(product?.customID, quantity + 1);
setQuantity((prevState) => prevState + 1);
}}
>
+
</Button>
</ButtonGroup>
</Box>
<Button
disableRipple
sx={{
height: 35,
mt: 1,
width: 118,
fontSize: 15,
textTransform: 'none',
backgroundColor: '#C6453E',
color: 'white',
}}
startIcon={
<Image src="/images/x.svg" alt="remove" width={15} height={15} />
}
onClick={() => remove(product.customID)}
>
{t('cart:remove')}
</Button>
</Box>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Typography
sx={{
width: '100%',
textAlign: 'center',
height: 25,
fontSize: { xs: 15, md: 18 },
}}
>
{t('cart:priceTag')}
{product?.price}
</Typography>
</Box>
</Box>
</Card>
);
onClick={() => {
if (quantity > 1) {
updateQuantity(product?.customID, quantity - 1);
setQuantity((prevState) => prevState - 1);
}
}}
>
-
</Button>
<Button
sx={{
color: 'white',
fontSize: 15,
width: 25,
}}
>
{quantity}
</Button>
<Button
sx={{
color: 'white',
fontSize: 17,
width: 25,
}}
onClick={() => {
updateQuantity(product?.customID, quantity + 1);
setQuantity((prevState) => prevState + 1);
}}
>
+
</Button>
</ButtonGroup>
</Box>
<Button
disableRipple
sx={{
height: 35,
mt: 1,
width: 118,
fontSize: 15,
textTransform: 'none',
backgroundColor: '#C6453E',
color: 'white',
}}
startIcon={
<Image src="/images/x.svg" alt="remove" width={15} height={15} />
}
onClick={() => remove(product.customID)}
>
{t('cart:remove')}
</Button>
</Box>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Typography
sx={{
width: '100%',
textAlign: 'center',
height: 25,
fontSize: { xs: 15, md: 18 },
}}
>
{t('cart:priceTag')}
{product?.price}
</Typography>
</Box>
</Box>
</Card>
);
};

export default CartCard;

+ 71
- 63
components/cards/order-summary-card/OrderSummaryCard.tsx Voir le fichier

@@ -4,70 +4,78 @@ import { useTranslation } from 'next-i18next';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { setCookie } from 'nookies';
import { FC } from 'react';

const OrderSummaryCard = ({ data }) => {
const { t } = useTranslation('cart');
const router = useRouter();
return (
<Card sx={{ p: 3, width: '100%', mb: 2, backgroundColor: '#f1f1f1' }}>
<Typography
sx={{
fontSize: 26,
color: 'primary.main',
textAlign: 'center',
width: '100%',
}}
>
{t('cart:orderTitle')}
</Typography>
<Typography sx={{ mt: 4 }}>
{t('cart:itemsTotal')}
{data.totalPrice.toFixed(2)}
</Typography>
<Typography sx={{ mt: 1.5 }}>{t('cart:shipping')}</Typography>
<Typography sx={{ mt: 1.5, mb: 1.5 }}>
{t('cart:total')}
{data.totalPrice.toFixed(2)}
</Typography>
<Divider />
<Box sx={{ textAlign: 'center', mt: 4, width: '100%' }}>
<Button
disableRipple
sx={{
'&.Mui-disabled': {
backgroundColor: '#0066ff',
color: '#fff',
opacity: '0.6',
},
'&:hover': {
backgroundColor: '#0066ff',
color: 'white',
boxShadow: 'none',
},
backgroundColor: '#0066ff',
color: 'white',
textTransform: 'none',
px: 2,
}}
startIcon={
<Image src="/images/lock.svg" alt="lock" width={18} height={18} />
}
disabled={data.totalQuantity > 0 ? false : true}
onClick={() => {
router.push('/checkout');
setCookie(null, 'checkout-session', 'active', {
maxAge: 3600,
expires: new Date(Date.now() + 3600),
path: '/',
});
}}
>
{t('cart:proceed')}
</Button>
</Box>
<Typography sx={{ mt: 3, fontSize: 13 }}>{t('cart:infoMsg')}</Typography>
</Card>
);
interface Props {
data: {
totalPrice: number;
totalQuantity: number;
};
}

const OrderSummaryCard: FC<Props> = ({ data }) => {
const { t } = useTranslation('cart');
const router = useRouter();
return (
<Card sx={{ p: 3, width: '100%', mb: 2, backgroundColor: '#f1f1f1' }}>
<Typography
sx={{
fontSize: 26,
color: 'primary.main',
textAlign: 'center',
width: '100%',
}}
>
{t('cart:orderTitle')}
</Typography>
<Typography sx={{ mt: 4 }}>
{t('cart:itemsTotal')}
{data.totalPrice.toFixed(2)}
</Typography>
<Typography sx={{ mt: 1.5 }}>{t('cart:shipping')}</Typography>
<Typography sx={{ mt: 1.5, mb: 1.5 }}>
{t('cart:total')}
{data.totalPrice.toFixed(2)}
</Typography>
<Divider />
<Box sx={{ textAlign: 'center', mt: 4, width: '100%' }}>
<Button
disableRipple
sx={{
'&.Mui-disabled': {
backgroundColor: '#0066ff',
color: '#fff',
opacity: '0.6',
},
'&:hover': {
backgroundColor: '#0066ff',
color: 'white',
boxShadow: 'none',
},
backgroundColor: '#0066ff',
color: 'white',
textTransform: 'none',
px: 2,
}}
startIcon={
<Image src="/images/lock.svg" alt="lock" width={18} height={18} />
}
disabled={data.totalQuantity > 0 ? false : true}
onClick={() => {
router.push('/checkout');
setCookie(null, 'checkout-session', 'active', {
maxAge: 3600,
expires: new Date(Date.now() + 3600),
path: '/',
});
}}
>
{t('cart:proceed')}
</Button>
</Box>
<Typography sx={{ mt: 3, fontSize: 13 }}>{t('cart:infoMsg')}</Typography>
</Card>
);
};

export default OrderSummaryCard;

+ 12
- 2
components/cart-content/CartContent.tsx Voir le fichier

@@ -3,6 +3,7 @@ import { useTranslation } from 'next-i18next';
import { destroyCookie } from 'nookies';
import { useEffect, useState } from 'react';
import { useStore, useStoreUpdate } from '../../store/cart-context';
import { ProductData } from '../../utils/interface/productInterface';
import CartCard from '../cards/cart-card/CartCard';
import OrderSummaryCard from '../cards/order-summary-card/OrderSummaryCard';
import EmptyCart from '../empty-cart/EmptyCart';
@@ -10,11 +11,20 @@ import ContentContainer from '../layout/content-wrapper/ContentContainer';
import PageWrapper from '../layout/page-wrapper/PageWrapper';
import StepTitle from '../layout/steps-title/StepTitle';

const CartContent: React.FC = () => {
interface ICartInfo {
cartStorage: {
product: ProductData;
quantity: number;
}[];
totalPrice: number;
totalQuantity: number;
}

const CartContent = () => {
const { t } = useTranslation('cart');
const { cartStorage, totalPrice, totalQuantity } = useStore();
const { removeCartValue, updateItemQuantity } = useStoreUpdate();
const [cartInfo, setCartInfo] = useState({
const [cartInfo, setCartInfo] = useState<ICartInfo>({
cartStorage: [],
totalPrice: 0,
totalQuantity: 0,

+ 26
- 14
components/checkout-content/CheckoutContent.tsx Voir le fichier

@@ -4,7 +4,7 @@ import { useTranslation } from 'next-i18next';
import { useRouter } from 'next/router';
import { setCookie } from 'nookies';
import { useEffect, useState } from 'react';
import { useStore } from '../../store/cart-context';
import { ICart, useStore } from '../../store/cart-context';
import { useCheckoutDataUpdate } from '../../store/checkout-context';
import CardContainer from '../cards/card-container/CardContainer';
import DataCard from '../cards/data-card/DataCard';
@@ -14,12 +14,21 @@ import PageWrapper from '../layout/page-wrapper/PageWrapper';
import StepTitle from '../layout/steps-title/StepTitle';
import PageDescription from '../page-description/PageDescription';

interface FormValues {
fullName: string;
address: string;
address2: string;
city: string;
country: string;
postcode: string;
}

const CheckoutContent = () => {
const { t } = useTranslation('cart');
const { cartStorage } = useStore();
const { addCheckoutValue } = useCheckoutDataUpdate();

const [cartData, setCartData] = useState([]);
const [cartData, setCartData] = useState<ICart[]>([]);

const { data: session } = useSession();
const router = useRouter();
@@ -28,18 +37,20 @@ const CheckoutContent = () => {
setCartData(cartStorage);
}, [cartStorage]);

const submitHandler = (formValues) => {
addCheckoutValue(
cartData,
{ ...formValues, email: session.user.email },
session.user._id
);
setCookie(null, 'shipping-session', 'active', {
maxAge: 3600,
expires: new Date(Date.now() + 3600),
path: '/',
});
router.push('/shipping');
const submitHandler = (formValues: FormValues) => {
if (session?.user) {
addCheckoutValue(
cartData,
{ ...formValues, email: session?.user?.email },
session?.user?._id
);
setCookie(null, 'shipping-session', 'active', {
maxAge: 3600,
expires: new Date(Date.now() + 3600),
path: '/',
});
router.push('/shipping');
}
};

const mapProductsToDom = () => {
@@ -62,6 +73,7 @@ const CheckoutContent = () => {
<ContentContainer>
<Box flexGrow={1} sx={{ minWidth: '65%' }}>
<ShippingDetailsForm
enableBtn={false}
backBtn={true}
isCheckout={true}
submitHandler={submitHandler}

+ 20
- 4
components/forms/shipping-details/ShippingDetailsForm.tsx Voir le fichier

@@ -2,15 +2,31 @@ import { Box, Button, Card, TextField } from '@mui/material';
import { useFormik } from 'formik';
import { useTranslation } from 'next-i18next';
import { useRouter } from 'next/router';
import { useState } from 'react';
import { useState, FC } from 'react';
import { registerSchema } from '../../../schemas/shippingDetailsSchema';
import { useUserData } from '../../../store/user-context';
import ErrorMessageComponent from '../../mui/ErrorMessageComponent';

const ShippingDetailsForm = ({
interface FormValues {
fullName: string;
address: string;
address2: string;
city: string;
country: string;
postcode: string;
}

interface Props {
submitHandler: (x: FormValues) => void;
backBtn: boolean;
isCheckout: boolean;
enableBtn: boolean;
}

const ShippingDetailsForm: FC<Props> = ({
submitHandler,
backBtn = false,
isCheckout = false,
submitHandler,
enableBtn = true,
}) => {
const { t } = useTranslation('addressForm');
@@ -18,7 +34,7 @@ const ShippingDetailsForm = ({
const { userStorage } = useUserData();
const router = useRouter();

const formikSubmitHandler = async (values) => {
const formikSubmitHandler = async (values: FormValues) => {
submitHandler(values);
};


+ 17
- 13
components/layout/content-wrapper/ContentContainer.tsx Voir le fichier

@@ -1,18 +1,22 @@
import { Box } from '@mui/system';
import { FC, ReactNode } from 'react';

const ContentContainer = ({ children }) => {
return (
<Box
sx={{
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
mr: { xs: 2, md: 12 },
ml: { xs: 2, md: 12 },
}}
>
{children}
</Box>
);
interface Props {
children: ReactNode;
}
const ContentContainer: FC<Props> = ({ children }) => {
return (
<Box
sx={{
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
mr: { xs: 2, md: 12 },
ml: { xs: 2, md: 12 },
}}
>
{children}
</Box>
);
};

export default ContentContainer;

+ 7
- 2
components/layout/page-wrapper/PageWrapper.tsx Voir le fichier

@@ -1,7 +1,12 @@
import { Box } from '@mui/system';
import { FC, ReactNode } from 'react';

const PageWrapper = ({ children }) => {
return <Box sx={{ py: 10, height: '100%', width: '100%' }}>{children}</Box>;
interface Props {
children: ReactNode;
}

const PageWrapper: FC<Props> = ({ children }) => {
return <Box sx={{ py: 10, height: '100%', width: '100%' }}>{children}</Box>;
};

export default PageWrapper;

+ 52
- 46
components/layout/steps-title/StepTitle.tsx Voir le fichier

@@ -1,55 +1,61 @@
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
import { Breadcrumbs, Divider, Grid, Typography } from '@mui/material';
import { FC } from 'react';

const StepTitle = ({ title, breadcrumbsArray }) => {
return (
<>
<Grid item xs={12}>
interface Props {
title: string;
breadcrumbsArray: string[];
}

const StepTitle: FC<Props> = ({ title, breadcrumbsArray }) => {
return (
<>
<Grid item xs={12}>
<Typography
variant="h4"
sx={{
ml: { xs: 2, md: 12 },
mt: 12,
height: '100%',
color: 'primary.main',
}}
>
{title}
</Typography>
</Grid>
<Grid item xs={12}>
<Divider
sx={{
backgroundColor: 'primary.main',
ml: { xs: 2, md: 12 },
mr: { xs: 2, md: 12 },
}}
/>
</Grid>
<Grid item xs={12} sx={{ mt: 4 }}>
<Breadcrumbs
aria-label="breadcrumb"
separator={<NavigateNextIcon fontSize="small" />}
sx={{ ml: { xs: 2, md: 12 }, fontSize: 20 }}
>
{breadcrumbsArray &&
breadcrumbsArray.map((entry, index) => {
return (
<Typography
variant="h4"
sx={{
ml: { xs: 2, md: 12 },
mt: 12,
height: '100%',
color: 'primary.main',
}}
sx={{ fontSize: { xs: '16px', md: '22px' } }}
key={index}
color={
index === breadcrumbsArray.length - 1 ? 'red' : 'black'
}
>
{title}
{entry}
</Typography>
</Grid>
<Grid item xs={12}>
<Divider
sx={{
backgroundColor: 'primary.main',
ml: { xs: 2, md: 12 },
mr: { xs: 2, md: 12 },
}}
/>
</Grid>
<Grid item xs={12} sx={{ mt: 4 }}>
<Breadcrumbs
aria-label="breadcrumb"
separator={<NavigateNextIcon fontSize="small" />}
sx={{ ml: { xs: 2, md: 12 }, fontSize: 20 }}
>
{breadcrumbsArray &&
breadcrumbsArray.map((entry, index) => {
return (
<Typography
sx={{ fontSize: { xs: '16px', md: '22px' } }}
key={index}
color={
index === breadcrumbsArray.length - 1 ? 'red' : 'black'
}
>
{entry}
</Typography>
);
})}
</Breadcrumbs>
</Grid>
</>
);
);
})}
</Breadcrumbs>
</Grid>
</>
);
};

export default StepTitle;

+ 173
- 173
components/review-content/ReviewContent.tsx Voir le fichier

@@ -5,11 +5,11 @@ import { useRouter } from 'next/router';
import { destroyCookie } from 'nookies';

import { useEffect, useState } from 'react';
import { postOrder } from '../../requests/products/postOrderRequest';
import { postOrder } from '../../requests/orders/postOrderRequest';
import { useStoreUpdate } from '../../store/cart-context';
import {
useCheckoutData,
useCheckoutDataUpdate,
useCheckoutData,
useCheckoutDataUpdate,
} from '../../store/checkout-context';
import PageWrapper from '../layout/page-wrapper/PageWrapper';
import StepTitle from '../layout/steps-title/StepTitle';
@@ -17,179 +17,179 @@ import StepTitle from '../layout/steps-title/StepTitle';
let initialRender = true;

const ReviewContent = () => {
const { t } = useTranslation('review');
const { checkoutStorage } = useCheckoutData();
const { parseCheckoutValue, clearCheckout } = useCheckoutDataUpdate();
const { clearCart } = useStoreUpdate();
const [orderData, setOrderData] = useState({});
const { t } = useTranslation('review');
const { checkoutStorage } = useCheckoutData();
const { parseCheckoutValue, clearCheckout } = useCheckoutDataUpdate();
const { clearCart } = useStoreUpdate();
const [orderData, setOrderData] = useState({});

const router = useRouter();
const router = useRouter();

useEffect(() => {
if (initialRender) {
setOrderData(parseCheckoutValue());
postOrder(parseCheckoutValue());
initialRender = false;
return () => {
clearCheckout();
clearCart();
destroyCookie(null, 'checkout-session', {
path: '/',
});
destroyCookie(null, 'shipping-session', {
path: '/',
});
destroyCookie(null, 'review-session', {
path: '/',
});
};
}
}, [checkoutStorage]);
useEffect(() => {
if (initialRender) {
setOrderData(parseCheckoutValue());
postOrder(parseCheckoutValue());
initialRender = false;
return () => {
clearCheckout();
clearCart();
destroyCookie(null, 'checkout-session', {
path: '/',
});
destroyCookie(null, 'shipping-session', {
path: '/',
});
destroyCookie(null, 'review-session', {
path: '/',
});
};
}
}, [checkoutStorage]);

return (
<PageWrapper>
<StepTitle
title="Review"
breadcrumbsArray={['Cart', 'Checkout', 'Shipping', 'Payment', 'Review']}
/>
<Box sx={{ ml: { xs: 2 }, mr: { xs: 2 }, mt: 6 }}>
<Box>
<Typography
sx={{
width: '100%',
textAlign: 'center',
color: 'primary.main',
fontWeight: 600,
fontSize: 22,
}}
>
{t('review:orderMsg')}
</Typography>
</Box>
<Box sx={{ mt: 1 }}>
<Typography
sx={{
width: '100%',
fontWeight: 600,
mt: 2,
textAlign: 'center',
}}
>
{t('review:note')}
</Typography>
</Box>
<Box sx={{ mt: 1 }}>
<Typography
sx={{
width: '100%',
textAlign: 'center',
mt: 4,
mb: 4,
fontSize: 44,
fontWeight: 600,
}}
>
{t('review:title')}
</Typography>
</Box>
<Box
sx={{
backgroundColor: '#f2f2f2',
my: 1,
ml: { md: 12 },
mr: { md: 12 },
borderRadius: 2,
p: 2,
}}
>
<Typography sx={{ fontSize: 18, fontWeight: 600 }}>
{t('review:date')}
{orderData.time}
</Typography>
</Box>
<Box
sx={{
backgroundColor: '#f2f2f2',
ml: { md: 12 },
mr: { md: 12 },
borderRadius: 2,
p: 2,
my: 1,
}}
>
<Typography sx={{ fontSize: 18, fontWeight: 600 }}>
{t('review:email')}
{orderData?.shippingAddress?.email}
</Typography>
</Box>
<Box
sx={{
backgroundColor: '#f2f2f2',
ml: { md: 12 },
mr: { md: 12 },
borderRadius: 2,
p: 2,
my: 1,
}}
>
<Typography sx={{ fontSize: 18, fontWeight: 600 }}>
{t('review:total')}
{orderData?.totalPrice?.toFixed(2)}
</Typography>
</Box>
<Box
sx={{
backgroundColor: '#f2f2f2',
ml: { md: 12 },
mr: { md: 12 },
borderRadius: 2,
p: 2,
my: 1,
}}
>
<Typography sx={{ fontSize: 18, fontWeight: 600 }}>
{t('review:shipping')}
{orderData?.shippingAddress?.address},{' '}
{orderData?.shippingAddress?.city},{' '}
{orderData?.shippingAddress?.country},{' '}
{orderData?.shippingAddress?.postcode}
</Typography>
</Box>
<Box sx={{ mt: 1 }}>
<Box
sx={{
width: '100%',
display: 'flex',
justifyContent: 'center',
mt: 2,
borderRadius: 2,
p: 1,
}}
>
<Button
variant="contained"
sx={{
mt: 3,
mb: 2,
height: 50,
width: 150,
textTransform: 'none',
backgroundColor: '#CBA213',
color: 'white',
mr: 2,
fontSize: 16,
}}
onClick={() => {
router.push('/');
}}
>
{t('review:back')}
</Button>
</Box>
</Box>
</Box>
</PageWrapper>
);
return (
<PageWrapper>
<StepTitle
title="Review"
breadcrumbsArray={['Cart', 'Checkout', 'Shipping', 'Payment', 'Review']}
/>
<Box sx={{ ml: { xs: 2 }, mr: { xs: 2 }, mt: 6 }}>
<Box>
<Typography
sx={{
width: '100%',
textAlign: 'center',
color: 'primary.main',
fontWeight: 600,
fontSize: 22,
}}
>
{t('review:orderMsg')}
</Typography>
</Box>
<Box sx={{ mt: 1 }}>
<Typography
sx={{
width: '100%',
fontWeight: 600,
mt: 2,
textAlign: 'center',
}}
>
{t('review:note')}
</Typography>
</Box>
<Box sx={{ mt: 1 }}>
<Typography
sx={{
width: '100%',
textAlign: 'center',
mt: 4,
mb: 4,
fontSize: 44,
fontWeight: 600,
}}
>
{t('review:title')}
</Typography>
</Box>
<Box
sx={{
backgroundColor: '#f2f2f2',
my: 1,
ml: { md: 12 },
mr: { md: 12 },
borderRadius: 2,
p: 2,
}}
>
<Typography sx={{ fontSize: 18, fontWeight: 600 }}>
{t('review:date')}
{orderData.time}
</Typography>
</Box>
<Box
sx={{
backgroundColor: '#f2f2f2',
ml: { md: 12 },
mr: { md: 12 },
borderRadius: 2,
p: 2,
my: 1,
}}
>
<Typography sx={{ fontSize: 18, fontWeight: 600 }}>
{t('review:email')}
{orderData?.shippingAddress?.email}
</Typography>
</Box>
<Box
sx={{
backgroundColor: '#f2f2f2',
ml: { md: 12 },
mr: { md: 12 },
borderRadius: 2,
p: 2,
my: 1,
}}
>
<Typography sx={{ fontSize: 18, fontWeight: 600 }}>
{t('review:total')}
{orderData?.totalPrice?.toFixed(2)}
</Typography>
</Box>
<Box
sx={{
backgroundColor: '#f2f2f2',
ml: { md: 12 },
mr: { md: 12 },
borderRadius: 2,
p: 2,
my: 1,
}}
>
<Typography sx={{ fontSize: 18, fontWeight: 600 }}>
{t('review:shipping')}
{orderData?.shippingAddress?.address},{' '}
{orderData?.shippingAddress?.city},{' '}
{orderData?.shippingAddress?.country},{' '}
{orderData?.shippingAddress?.postcode}
</Typography>
</Box>
<Box sx={{ mt: 1 }}>
<Box
sx={{
width: '100%',
display: 'flex',
justifyContent: 'center',
mt: 2,
borderRadius: 2,
p: 1,
}}
>
<Button
variant="contained"
sx={{
mt: 3,
mb: 2,
height: 50,
width: 150,
textTransform: 'none',
backgroundColor: '#CBA213',
color: 'white',
mr: 2,
fontSize: 16,
}}
onClick={() => {
router.push('/');
}}
>
{t('review:back')}
</Button>
</Box>
</Box>
</Box>
</PageWrapper>
);
};

export default ReviewContent;

+ 2
- 3
models/order.ts Voir le fichier

@@ -1,8 +1,7 @@
const validator = require('validator');
import { ProductData as IProduct } from '../utils/interface/productInterface';
import { OrderData as IOrder } from '../utils/interface/orderInterface';
import { Schema, model, Types } from 'mongoose';

import { Schema, model, Types, models } from 'mongoose';
const OrderSchema = new Schema<IOrder>(
{
products: Array<IProduct>,
@@ -87,6 +86,6 @@ const OrderSchema = new Schema<IOrder>(
}
);

const Order = model<IOrder>('Order', OrderSchema, 'Order');
const Order = models.Order || model<IOrder>('Order', OrderSchema, 'Order');

module.exports = Order;

+ 2
- 2
models/product.ts Voir le fichier

@@ -1,5 +1,5 @@
import { ProductData as IProduct } from '../utils/interface/productInterface';
import { Schema, model } from 'mongoose';
import { Schema, model, models } from 'mongoose';

const ProductSchema = new Schema<IProduct>({
category: {
@@ -68,6 +68,6 @@ const ProductSchema = new Schema<IProduct>({
},
});

const Product = model<IProduct>('Product', ProductSchema);
const Product = models.Product || model<IProduct>('Product', ProductSchema);

module.exports = Product;

+ 3
- 2
models/question.ts Voir le fichier

@@ -1,4 +1,4 @@
import { Schema, model } from 'mongoose';
import { Schema, model, models } from 'mongoose';
import { QuestionData as IQusetion } from '../utils/interface/questionInterface';

const validator = require('validator');
@@ -35,5 +35,6 @@ const QuestionSchema = new Schema<IQusetion>({
},
});

const Question = model<IQusetion>('Question', QuestionSchema, 'Questions');
const Question =
models.Question || model<IQusetion>('Question', QuestionSchema, 'Questions');
module.exports = Question;

+ 2
- 2
models/user.ts Voir le fichier

@@ -1,4 +1,4 @@
import { Schema, model, Model } from 'mongoose';
import { Schema, model, Model, models } from 'mongoose';
import {
hashPassword,
verifyPassword,
@@ -124,5 +124,5 @@ UserSchema.pre('save', async function (next) {
next();
});

const User = model<IUser, UserModel>('User', UserSchema, 'User');
const User = models.User || model<IUser, UserModel>('User', UserSchema, 'User');
module.exports = User;

+ 1
- 0
package.json Voir le fichier

@@ -19,6 +19,7 @@
"@tanstack/react-query": "^4.10.3",
"@types/bcryptjs": "^2.4.2",
"@types/mongodb": "^4.0.7",
"@types/nookies": "^2.0.3",
"@types/validator": "^13.7.7",
"bcryptjs": "^2.4.3",
"formik": "^2.2.9",

+ 16
- 18
pages/api/auth/[...nextauth].ts Voir le fichier

@@ -3,37 +3,35 @@ import Credentials from 'next-auth/providers/credentials';
import dbConnect from '../../../utils/helpers/dbHelpers';
const User = require('../../../models/user');

// @ts-ignore
export default NextAuth({
session: {
strategy: 'jwt',
// @ts-ignore
jwt: true,
},
callbacks: {
async jwt({ token, user, account, profile, isNewUser }) {
async jwt({ token, user }) {
return { ...token, ...user };
},
async session({ session, token, user }) {
return session;
// @ts-ignore
async session({ token }) {
return token;
},
},
providers: [
Credentials({
name: 'Credentials',
credentials: {
username: { label: 'Username', type: 'text' },
password: { label: 'Password', type: 'password' },
},
// @ts-ignore
async authorize(credentials) {
if (credentials) {
await dbConnect();
await dbConnect();

const userData = await User.findByCredentials(
credentials.username,
credentials.password
);
return { user: userData };
}
return null;
// @ts-ignore
const userData = await User.findByCredentials(
// @ts-ignore
credentials.username,
// @ts-ignore
credentials.password
);
return { user: userData };
},
}),
],

+ 9
- 9
pages/cart/index.tsx Voir le fichier

@@ -1,17 +1,17 @@
import { NextPage } from 'next';
import { NextPage, GetStaticProps } from 'next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import CartContent from '../../components/cart-content/CartContent';

const CartPage: NextPage = () => {
return <CartContent></CartContent>;
return <CartContent></CartContent>;
};

export async function getStaticProps({ locale }: any) {
return {
props: {
...(await serverSideTranslations(locale, ['cart'])),
},
};
}
export const getStaticProps: GetStaticProps = async ({ locale }: any) => {
return {
props: {
...(await serverSideTranslations(locale, ['cart'])),
},
};
};

export default CartPage;

+ 2
- 2
pages/checkout/index.tsx Voir le fichier

@@ -1,4 +1,4 @@
import { NextPage } from 'next';
import { NextPage, GetServerSideProps } from 'next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import nookies from 'nookies';
import CheckoutContent from '../../components/checkout-content/CheckoutContent';
@@ -7,7 +7,7 @@ const CheckoutPage: NextPage = () => {
return <CheckoutContent></CheckoutContent>;
};

export const getServerSideProps = async (ctx: any) => {
export const getServerSideProps: GetServerSideProps = async (ctx: any) => {
const cookies = nookies.get(ctx);

if (!cookies['checkout-session']) {

+ 47
- 25
store/cart-context.tsx Voir le fichier

@@ -1,17 +1,40 @@
import { createContext, useContext, useState } from 'react';
import { createContext, useContext, useState, FC, ReactNode } from 'react';
import { getStorage, setStorage } from '../utils/helpers/storage';

const StorageContext = createContext({
import { ProductData } from '../utils/interface/productInterface';

export interface ICart {
product: ProductData;
quantity: number;
}

interface IStorage {
cartStorage: ICart[];
totalPrice: number;
totalQuantity: number;
}

interface IStorageDispatch {
addCartValue: (x: ProductData, y: number) => void;
clearCart: () => void;
removeCartValue: (x: string) => void;
updateItemQuantity: (x: string, y: number) => void;
}

interface Props {
children: ReactNode;
}

const StorageContext = createContext<IStorage>({
cartStorage: [],
totalPrice: 0,
totalQuantity: 0,
});
const StorageDispatchContext = createContext({
addCartValue: (product, quantity) => {},

const StorageDispatchContext = createContext<IStorageDispatch>({
addCartValue: (product: ProductData, quantity: number) => {},
clearCart: () => {},
removeCartValue: (productId) => {},
setCartStorage: (cart) => {},
updateItemQuantity: (productId, quantity) => {},
removeCartValue: (productId: string) => {},
updateItemQuantity: (productId: string, quantity: number) => {},
});

export const useStore = () => {
@@ -23,20 +46,20 @@ export const useStoreUpdate = () => {

const useStorage = () => {
const CART_KEY = 'cart-products';
const [cartStorage, setCartStorage] = useState(getStorage(CART_KEY));
const [totalPrice, setTotalPrice] = useState(() => {
const cart = getStorage(CART_KEY);
const [cartStorage, setCartStorage] = useState<ICart[]>(getStorage(CART_KEY));
const [totalPrice, setTotalPrice] = useState<number>(() => {
const cart: ICart[] = getStorage(CART_KEY);

if (cart && cart.length) {
return cart
.map((entry) => entry?.product.price * entry?.quantity)
.reduce((accum, curValue) => accum + curValue);
.reduce((accum: number, curValue: number) => accum + curValue);
} else {
return 0;
}
});

const [totalQuantity, setTotalQuantity] = useState(() => {
const [totalQuantity, setTotalQuantity] = useState<number>(() => {
const cart = getStorage(CART_KEY);

if (cart && cart.length) {
@@ -46,11 +69,11 @@ const useStorage = () => {
}
});

const addCartValue = (product, quantity) => {
const items = getStorage(CART_KEY);
const addCartValue = (product: ProductData, quantity: number) => {
const items: ICart[] = getStorage(CART_KEY);

if (!items) {
setStorage(CART_KEY, [{ product, quantity }]);
setStorage(CART_KEY, { product, quantity });
} else {
const isItemDuplicate = items.some(
(item) => item.product.customID === product.customID
@@ -58,7 +81,7 @@ const useStorage = () => {

if (!isItemDuplicate) {
items.push({ product, quantity });
setTotalQuantity((prevState) => prevState + 1);
setTotalQuantity((prevState: number) => prevState + 1);
setStorage(CART_KEY, items);
} else {
return;
@@ -74,9 +97,9 @@ const useStorage = () => {
setCartStorage(items);
};

const updateItemQuantity = (productId, quantity) => {
const updateItemQuantity = (productId: string, quantity: number) => {
if (quantity < 0) return;
const items = getStorage(CART_KEY);
const items: ICart[] = getStorage(CART_KEY);
let updatedItems = items;

if (items) {
@@ -100,14 +123,14 @@ const useStorage = () => {
};

const clearCart = () => {
setStorage(CART_KEY, []);
setStorage(CART_KEY, {});
setTotalQuantity(0);
setTotalPrice(0);
setCartStorage([]);
};

const removeCartValue = (productId) => {
const items = getStorage(CART_KEY);
const removeCartValue = (productId: string) => {
const items: ICart[] = getStorage(CART_KEY);

const newStorage = items?.filter(
(item) => item.product.customID !== productId
@@ -121,7 +144,7 @@ const useStorage = () => {
.reduce((accum, curValue) => accum + curValue);
setTotalPrice(newTotalPrice);
}
setTotalQuantity((prevState) => prevState - 1);
setTotalQuantity((prevState: number) => prevState - 1);
setStorage(CART_KEY, newStorage);
setCartStorage(newStorage);
};
@@ -138,7 +161,7 @@ const useStorage = () => {
};
};

const StorageProvider = ({ children }) => {
const StorageProvider: FC<Props> = ({ children }) => {
const {
cartStorage,
totalPrice,
@@ -157,7 +180,6 @@ const StorageProvider = ({ children }) => {
addCartValue,
clearCart,
removeCartValue,
setCartStorage,
updateItemQuantity,
}}
>

+ 70
- 21
store/checkout-context.tsx Voir le fichier

@@ -1,15 +1,63 @@
import { createContext, useContext, useState } from 'react';
import { createContext, useContext, useState, FC, ReactNode } from 'react';
import { getSStorage, setSStorage } from '../utils/helpers/storage';

const CheckoutContext = createContext({
checkoutStorage: {},
import { ShippingData } from '../utils/interface/orderInterface';
import { ProductData } from '../utils/interface/productInterface';
import { UserData } from '../utils/interface/userInterface';

interface Props {
children: ReactNode;
}

interface Products {
product: ProductData;
quantity: number;
}

interface CheckoutData {
products: Products[];
userInfo: ShippingData;
userID: string;
}

interface OrderData {
products: Array<ProductData>;
time: string;
shippingAddress: ShippingData;
totalPrice: number;
numberOfItems: number;
fulfilled: boolean;
owner: string;
stripeCheckoutId: string;
}

interface ICheckout {
checkoutStorage: CheckoutData;
}

interface ICheckoutDispatch {
addCheckoutValue: (x: Products[], y: ShippingData, z: string) => void;
changeContact: (x: string) => void;
changeShippingData: (x: ShippingData) => void;
clearCheckout: () => void;
parseCheckoutValue: () => OrderData;
}

const CheckoutContext = createContext<ICheckout>({
checkoutStorage: {} as CheckoutData,
});
const CheckoutDispatchContext = createContext({
addCheckoutValue: (products, userInfo, userID) => {},
changeContact: (email) => {},
changeShippingData: (shippingData) => {},

const CheckoutDispatchContext = createContext<ICheckoutDispatch>({
addCheckoutValue: (
products: Products[],
userInfo: ShippingData,
userID: string
) => {},
changeContact: (email: string) => {},
changeShippingData: (shippingData: ShippingData) => {},
clearCheckout: () => {},
parseCheckoutValue: () => {},
parseCheckoutValue: () => {
return {} as OrderData;
},
});

export const useCheckoutData = () => {
@@ -21,11 +69,15 @@ export const useCheckoutDataUpdate = () => {

const useCheckout = () => {
const CHECKOUT_KEY = 'checkout-data';
const [checkoutStorage, setCheckoutStorage] = useState(
const [checkoutStorage, setCheckoutStorage] = useState<CheckoutData>(
getSStorage(CHECKOUT_KEY)
);

const addCheckoutValue = (products, userInfo, userID) => {
const addCheckoutValue = (
products: Products[],
userInfo: ShippingData,
userID: string
) => {
setSStorage(CHECKOUT_KEY, { products, userInfo, userID });

setCheckoutStorage({ products, userInfo, userID });
@@ -33,7 +85,7 @@ const useCheckout = () => {

const clearCheckout = () => {
setSStorage(CHECKOUT_KEY, {});
setCheckoutStorage({});
setCheckoutStorage({} as CheckoutData);
};

const parseCheckoutValue = () => {
@@ -58,8 +110,8 @@ const useCheckout = () => {
return dataToStore;
};

const changeContact = (email) => {
const items = getSStorage(CHECKOUT_KEY);
const changeContact = (email: string) => {
const items: CheckoutData = getSStorage(CHECKOUT_KEY);

items.userInfo.email = email;
setSStorage(CHECKOUT_KEY, { ...items });
@@ -67,10 +119,10 @@ const useCheckout = () => {
setCheckoutStorage(items);
};

const changeShippingData = (shippingData) => {
const items = getSStorage(CHECKOUT_KEY);
const changeShippingData = (shippingData: ShippingData) => {
const items: CheckoutData = getSStorage(CHECKOUT_KEY);

items.userInfo = { email: items.userInfo.email, ...shippingData };
items.userInfo = { ...shippingData, email: items.userInfo.email };

setSStorage(CHECKOUT_KEY, { ...items });

@@ -83,15 +135,13 @@ const useCheckout = () => {
parseCheckoutValue,
changeContact,
changeShippingData,
setCheckoutStorage,
checkoutStorage,
};
};

const CheckoutProvider = ({ children }) => {
const CheckoutProvider: FC<Props> = ({ children }) => {
const {
checkoutStorage,
setCheckoutStorage,
addCheckoutValue,
clearCheckout,
parseCheckoutValue,
@@ -103,7 +153,6 @@ const CheckoutProvider = ({ children }) => {
<CheckoutContext.Provider value={{ checkoutStorage }}>
<CheckoutDispatchContext.Provider
value={{
setCheckoutStorage,
addCheckoutValue,
clearCheckout,
parseCheckoutValue,

+ 25
- 13
store/user-context.tsx Voir le fichier

@@ -1,17 +1,32 @@
import { createContext, useContext, useState } from 'react';
import { createContext, useContext, useState, FC, ReactNode } from 'react';
import {
getStorage,
removeStorage,
setStorage,
} from '../utils/helpers/storage';
import { UserData } from '../utils/interface/userInterface';

const UserContext = createContext({
userStorage: [],
interface Props {
children: ReactNode;
}

interface IUserContext {
userStorage: UserData;
}

interface IUserDispatch {
addUser: (x: UserData) => void;
clearUser: () => void;
updateUserInfo: (x: UserData) => void;
}

const UserContext = createContext<IUserContext>({
userStorage: {} as UserData,
});
const UserDispatchContext = createContext({
addUser: (userData) => {},
const UserDispatchContext = createContext<IUserDispatch>({
addUser: (userData: UserData) => {},
clearUser: () => {},
updateUserInfo: (newUserData) => {},
updateUserInfo: (newUserData: UserData) => {},
});

export const useUserData = () => {
@@ -25,12 +40,12 @@ const useUser = () => {
const USER_KEY = 'user-data';
const [userStorage, setUserStorage] = useState(getStorage(USER_KEY));

const addUser = (userData) => {
const addUser = (userData: UserData) => {
setStorage(USER_KEY, userData);
setUserStorage(userData);
};

const updateUserInfo = (newUserData) => {
const updateUserInfo = (newUserData: UserData) => {
setStorage(USER_KEY, newUserData);
setUserStorage(newUserData);
};
@@ -42,22 +57,19 @@ const useUser = () => {

return {
userStorage,
setUserStorage,
addUser,
updateUserInfo,
clearUser,
};
};

const UserProvider = ({ children }) => {
const { userStorage, setUserStorage, addUser, updateUserInfo, clearUser } =
useUser();
const UserProvider: FC<Props> = ({ children }) => {
const { userStorage, addUser, updateUserInfo, clearUser } = useUser();

return (
<UserContext.Provider value={{ userStorage }}>
<UserDispatchContext.Provider
value={{
setUserStorage,
addUser,
updateUserInfo,
clearUser,

+ 1
- 1
tsconfig.json Voir le fichier

@@ -15,6 +15,6 @@
"jsx": "preserve",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "types/**/*.ts"],
"exclude": ["node_modules"]
}

+ 20
- 0
types/next-auth.d.ts Voir le fichier

@@ -0,0 +1,20 @@
import NextAuth from 'next-auth';
import { UserData } from '../utils/interface/userInterface';

declare module 'next-auth' {
/**
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
*/
interface Session {
user: {
address: string;
address2: string;
city: string;
country: string;
fullName: string;
postcode: string;
email: string;
_id: string;
};
}
}

+ 2
- 2
utils/helpers/storage.ts Voir le fichier

@@ -1,4 +1,4 @@
export const setStorage = (key: string, value: string) => {
export const setStorage = (key: string, value: object) => {
window.localStorage.setItem(key, JSON.stringify(value));
};

@@ -19,7 +19,7 @@ export const removeStorage = (key: string) => {
window.localStorage.removeItem(key);
};

export const setSStorage = (key: string, value: string) => {
export const setSStorage = (key: string, value: object) => {
window.sessionStorage.setItem(key, JSON.stringify(value));
};


+ 1
- 12
utils/interface/orderInterface.ts Voir le fichier

@@ -2,18 +2,7 @@ import { ProductData } from './productInterface';
import { UserData } from './userInterface';
import { ObjectId } from 'mongodb';

export interface OrderCard {
date: Date;
name: string;
totalPrice: number;
}

export interface OrderSummary {
totalPrice: number;
totalQuantity: number;
}

interface ShippingData extends UserData {
export interface ShippingData extends UserData {
email: string;
}


+ 24
- 5
yarn.lock Voir le fichier

@@ -336,7 +336,14 @@
core-js-pure "^3.25.1"
regenerator-runtime "^0.13.4"

"@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.18.9", "@babel/runtime@^7.19.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
"@babel/runtime@^7.10.2", "@babel/runtime@^7.18.9":
version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
dependencies:
regenerator-runtime "^0.13.4"

"@babel/runtime@^7.12.5", "@babel/runtime@^7.14.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.19.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.19.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78"
integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==
@@ -801,9 +808,9 @@
"@sendgrid/helpers" "^7.7.0"

"@stripe/stripe-js@^1.39.0":
version "1.41.0"
resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.41.0.tgz#986f3f222ba4466301f7809934afafafde9b28fd"
integrity sha512-9cbv1CO/fF37qDiHFCxkRgSJjlIZLV0bl+m6zu4dUObRnfYq5bpczCByOvhiSWtbrKqNhYL1j+otPSogRfSqGw==
version "1.39.0"
resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.39.0.tgz#b70d4d276862771c4b2c86558795358e08f0b77e"
integrity sha512-BR7yzewVSBQgRao3V4HsTldpO4HpJUKcIlMDmBQaHqXUvkMpXHgOMF8/CZgFVMACS+pqvZIMmGuy3YvZlLEA2w==

"@swc/[email protected]":
version "0.4.11"
@@ -881,6 +888,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.8.3.tgz#ce750ab4017effa51aed6a7230651778d54e327c"
integrity sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==

"@types/nookies@^2.0.3":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/nookies/-/nookies-2.0.3.tgz#2173e8977a9163defc37fdcc3140a834f21373d1"
integrity sha512-+PO/CKwVx7gDG5Pjr+UU/hL6/vFm1ppgW8cilV4AreLEpjbz0wiFvZ5Nld1VIRTr/RiB/KFmiyOzr8GboJfpqg==
dependencies:
nookies "*"

"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
@@ -1992,6 +2006,11 @@ follow-redirects@^1.14.8:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==

follow-redirects@^1.14.8:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==

for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -2962,7 +2981,7 @@ node-releases@^2.0.6:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==

nookies@^2.5.2:
nookies@*, nookies@^2.5.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/nookies/-/nookies-2.5.2.tgz#cc55547efa982d013a21475bd0db0c02c1b35b27"
integrity sha512-x0TRSaosAEonNKyCrShoUaJ5rrT5KHRNZ5DwPCuizjgrnkpE5DRf3VL7AyyQin4htict92X1EQ7ejDbaHDVdYA==

Chargement…
Annuler
Enregistrer