Skip to content

Commit 72e76fe

Browse files
authored
Improve storefront initial runtime performance (#4675)
2 parents 233e80f + 85dc97a commit 72e76fe

20 files changed

Lines changed: 253 additions & 145 deletions

File tree

storefront/components/Blocks/Product/LastVisitedProducts/DeferredLastVisitedProducts.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import dynamic from 'next/dynamic';
22
import { useDeferredRender } from 'utils/useDeferredRender';
3-
import { LastVisitedProductsProps } from './LastVisitedProducts';
3+
import type { LastVisitedProductsProps } from './LastVisitedProducts';
44

55
const LastVisitedProducts = dynamic(
66
() => import('./LastVisitedProducts').then((component) => component.LastVisitedProducts),
Lines changed: 16 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,30 @@
1-
import { SubmitButton } from 'components/Forms/Button/SubmitButton';
21
import { Checkbox } from 'components/Forms/Checkbox/Checkbox';
3-
import { Form } from 'components/Forms/Form/Form';
4-
import { TextInputControlled } from 'components/Forms/TextInput/TextInputControlled';
52
import { TIDs } from 'cypress/tids';
3+
import dynamic from 'next/dynamic';
64
import { useState } from 'react';
7-
import { FormProvider, SubmitHandler } from 'react-hook-form';
8-
import { PromoCodeFormType } from 'types/form';
9-
import { useApplyPromoCodeToCart } from 'utils/cart/useApplyPromoCodeToCart';
105
import { useCurrentCart } from 'utils/cart/useCurrentCart';
11-
import { blurInput } from 'utils/forms/blurInput';
126
import useTranslation from 'utils/i18n/useTranslationWrapper';
13-
import { usePromoCodeForm, usePromoCodeFormMeta } from './promoCodeFormMeta';
7+
8+
const PromoCodeForm = dynamic(() => import('./PromoCodeForm').then((component) => component.PromoCodeForm), {
9+
ssr: false,
10+
});
1411

1512
export const PromoCode: FC = () => {
1613
const { promoCodes } = useCurrentCart();
17-
const [formProviderMethods, defaultValues] = usePromoCodeForm();
18-
const formMeta = usePromoCodeFormMeta();
1914
const { t } = useTranslation();
20-
const { applyPromoCodeToCart } = useApplyPromoCodeToCart({
21-
success: t('Promo code was added to the order.'),
22-
});
15+
const hasAppliedPromoCode = promoCodes.length > 0;
16+
const [isContentVisible, setIsContentVisible] = useState(hasAppliedPromoCode);
17+
const [wasContentRequested, setWasContentRequested] = useState(hasAppliedPromoCode);
2318

24-
const [isContentVisible, setIsContentVisible] = useState(!!defaultValues.promoCode);
19+
const togglePromoCodeVisibility = () => {
20+
if (!isContentVisible) {
21+
setWasContentRequested(true);
22+
}
2523

26-
const onApplyPromoCodeHandler: SubmitHandler<PromoCodeFormType> = async (promoCodeFormData) => {
27-
blurInput();
28-
await applyPromoCodeToCart(promoCodeFormData.promoCode);
24+
setIsContentVisible(!isContentVisible);
2925
};
3026

31-
if (promoCodes.length > 0) {
27+
if (hasAppliedPromoCode) {
3228
return null;
3329
}
3430

@@ -42,42 +38,11 @@ export const PromoCode: FC = () => {
4238
data-tid={TIDs.blocks_promocode_add_button}
4339
label={t('I have a discount coupon')}
4440
value={isContentVisible}
45-
onChange={() => setIsContentVisible(!isContentVisible)}
41+
onChange={togglePromoCodeVisibility}
4642
/>
4743
</div>
48-
{isContentVisible && (
49-
<FormProvider {...formProviderMethods}>
50-
<Form
51-
className="flex flex-col gap-2.5 sm:flex-row"
52-
formName={formMeta.formName}
53-
onSubmit={formProviderMethods.handleSubmit(onApplyPromoCodeHandler)}
54-
>
55-
<div className="max-w-60">
56-
<TextInputControlled
57-
isWithoutFormLineError
58-
control={formProviderMethods.control}
59-
formName={formMeta.formName}
60-
name={formMeta.fields.promoCode.name}
61-
textInputProps={{
62-
label: formMeta.fields.promoCode.label,
63-
required: true,
64-
}}
65-
/>
66-
</div>
6744

68-
<SubmitButton
69-
aria-label={t('Apply code. Apply promo code', { ns: 'accessibility' })}
70-
className="self-start"
71-
hasDisabledCursor={!formProviderMethods.formState.isValid}
72-
size="xlarge"
73-
tid={TIDs.blocks_promocode_apply_button}
74-
variant="inverted"
75-
>
76-
{t('Apply code')}
77-
</SubmitButton>
78-
</Form>
79-
</FormProvider>
80-
)}
45+
{wasContentRequested && <PromoCodeForm isContentVisible={isContentVisible} />}
8146
</div>
8247
);
8348
};
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { SubmitButton } from 'components/Forms/Button/SubmitButton';
2+
import { Form } from 'components/Forms/Form/Form';
3+
import { TextInputControlled } from 'components/Forms/TextInput/TextInputControlled';
4+
import { TIDs } from 'cypress/tids';
5+
import { AnimatePresence, m } from 'framer-motion';
6+
import { FormProvider, SubmitHandler } from 'react-hook-form';
7+
import { PromoCodeFormType } from 'types/form';
8+
import { collapseExpandAnimation } from 'utils/animations/animationVariants';
9+
import { useApplyPromoCodeToCart } from 'utils/cart/useApplyPromoCodeToCart';
10+
import { blurInput } from 'utils/forms/blurInput';
11+
import useTranslation from 'utils/i18n/useTranslationWrapper';
12+
import { usePromoCodeForm, usePromoCodeFormMeta } from './promoCodeFormMeta';
13+
14+
type PromoCodeFormProps = {
15+
isContentVisible: boolean;
16+
};
17+
18+
export const PromoCodeForm: FC<PromoCodeFormProps> = ({ isContentVisible }) => {
19+
const [formProviderMethods] = usePromoCodeForm();
20+
const formMeta = usePromoCodeFormMeta();
21+
const { t } = useTranslation();
22+
const { applyPromoCodeToCart } = useApplyPromoCodeToCart({
23+
success: t('Promo code was added to the order.'),
24+
});
25+
26+
const onApplyPromoCodeHandler: SubmitHandler<PromoCodeFormType> = async (promoCodeFormData) => {
27+
blurInput();
28+
await applyPromoCodeToCart(promoCodeFormData.promoCode);
29+
};
30+
31+
return (
32+
<AnimatePresence initial={false}>
33+
{isContentVisible && (
34+
<m.div
35+
key="promo-code"
36+
animate="open"
37+
className="flex!"
38+
exit="closed"
39+
initial="closed"
40+
variants={collapseExpandAnimation}
41+
>
42+
<FormProvider {...formProviderMethods}>
43+
<Form
44+
className="flex flex-col gap-2.5 sm:flex-row"
45+
formName={formMeta.formName}
46+
onSubmit={formProviderMethods.handleSubmit(onApplyPromoCodeHandler)}
47+
>
48+
<div className="max-w-60">
49+
<TextInputControlled
50+
isWithoutFormLineError
51+
control={formProviderMethods.control}
52+
formName={formMeta.formName}
53+
name={formMeta.fields.promoCode.name}
54+
textInputProps={{
55+
label: formMeta.fields.promoCode.label,
56+
required: true,
57+
}}
58+
/>
59+
</div>
60+
61+
<SubmitButton
62+
aria-label={t('Apply code. Apply promo code', { ns: 'accessibility' })}
63+
className="self-start"
64+
hasDisabledCursor={!formProviderMethods.formState.isValid}
65+
size="xlarge"
66+
tid={TIDs.blocks_promocode_apply_button}
67+
variant="inverted"
68+
>
69+
{t('Apply code')}
70+
</SubmitButton>
71+
</Form>
72+
</FormProvider>
73+
</m.div>
74+
)}
75+
</AnimatePresence>
76+
);
77+
};

storefront/components/Pages/BlogArticle/BlogArticleDetailContent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Flag } from 'components/Basic/Flag/Flag';
33
import { Image } from 'components/Basic/Image/Image';
44
import { GrapesJsParser } from 'components/Basic/UserText/GrapesJsParser';
55
import { ARTICLE_INTRODUCTION_ANCHOR_ID } from 'components/Blocks/ArticleAnchorNavigation/ArticleAnchorNavigation';
6-
import { LastVisitedProducts } from 'components/Blocks/Product/LastVisitedProducts/LastVisitedProducts';
6+
import { DeferredLastVisitedProducts } from 'components/Blocks/Product/LastVisitedProducts/DeferredLastVisitedProducts';
77
import { VISIBLE_SLIDER_ITEMS_ARTICLE } from 'components/Blocks/Product/ProductsSlider';
88
import { BlogLayout } from 'components/Layout/BlogLayout';
99
import { VerticalStack } from 'components/Layout/VerticalStack/VerticalStack';
@@ -68,7 +68,7 @@ export const BlogArticleDetailContent: FC<BlogArticleDetailContentProps> = ({ bl
6868
)}
6969
</BlogLayout>
7070

71-
<LastVisitedProducts />
71+
<DeferredLastVisitedProducts />
7272
</VerticalStack>
7373
);
7474
};

storefront/components/Pages/BlogCategory/BlogCategoryContent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { LastVisitedProducts } from 'components/Blocks/Product/LastVisitedProducts/LastVisitedProducts';
1+
import { DeferredLastVisitedProducts } from 'components/Blocks/Product/LastVisitedProducts/DeferredLastVisitedProducts';
22
import { BlogLayout } from 'components/Layout/BlogLayout';
33
import { VerticalStack } from 'components/Layout/VerticalStack/VerticalStack';
44
import { DEFAULT_BLOG_PAGE_SIZE } from 'config/constants';
@@ -34,7 +34,7 @@ export const BlogCategoryContent: FC<BlogCategoryContentProps> = ({ blogCategory
3434
/>
3535
</BlogLayout>
3636

37-
<LastVisitedProducts />
37+
<DeferredLastVisitedProducts />
3838
</VerticalStack>
3939
);
4040
};

storefront/components/Pages/BrandDetail/BrandDetailContent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { CollapsibleDescriptionWithImage } from 'components/Blocks/CollapsibleDe
22
import { FilteredProductsWrapper } from 'components/Blocks/FilteredProductsWrapper/FilteredProductsWrapper';
33
import { DeferredFilterPanel } from 'components/Blocks/Product/Filter/DeferredFilterPanel';
44
import { DeferredFilterSelectedParameters } from 'components/Blocks/Product/Filter/DeferredFilterSelectedParameters';
5-
import { LastVisitedProducts } from 'components/Blocks/Product/LastVisitedProducts/LastVisitedProducts';
5+
import { DeferredLastVisitedProducts } from 'components/Blocks/Product/LastVisitedProducts/DeferredLastVisitedProducts';
66
import { DeferredFilterAndSortingBar } from 'components/Blocks/SortingBar/DeferredFilterAndSortingBar';
77
import { VerticalStack } from 'components/Layout/VerticalStack/VerticalStack';
88
import { PaginationProvider } from 'components/providers/PaginationProvider';
@@ -65,7 +65,7 @@ export const BrandDetailContent: FC<BrandDetailContentProps> = ({ brand }) => {
6565
</div>
6666
</FilteredProductsWrapper>
6767

68-
<LastVisitedProducts />
68+
<DeferredLastVisitedProducts />
6969
</VerticalStack>
7070
);
7171
};

storefront/components/Pages/FlagDetail/FlagDetailContent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { FilteredProductsWrapper } from 'components/Blocks/FilteredProductsWrapper/FilteredProductsWrapper';
22
import { DeferredFilterPanel } from 'components/Blocks/Product/Filter/DeferredFilterPanel';
33
import { DeferredFilterSelectedParameters } from 'components/Blocks/Product/Filter/DeferredFilterSelectedParameters';
4-
import { LastVisitedProducts } from 'components/Blocks/Product/LastVisitedProducts/LastVisitedProducts';
4+
import { DeferredLastVisitedProducts } from 'components/Blocks/Product/LastVisitedProducts/DeferredLastVisitedProducts';
55
import { DeferredFilterAndSortingBar } from 'components/Blocks/SortingBar/DeferredFilterAndSortingBar';
66
import { VerticalStack } from 'components/Layout/VerticalStack/VerticalStack';
77
import { Webline } from 'components/Layout/Webline/Webline';
@@ -59,7 +59,7 @@ export const FlagDetailContent: FC<FlagDetailContentProps> = ({ flag }) => {
5959
</div>
6060
</FilteredProductsWrapper>
6161

62-
<LastVisitedProducts />
62+
<DeferredLastVisitedProducts />
6363
</VerticalStack>
6464
);
6565
};

storefront/components/Pages/Order/TransportAndPayment/TransportAndPaymentContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import { OrderContentWrapper } from 'components/Blocks/OrderContentWrapper/Order
33
import { OrderLayout } from 'components/Layout/OrderLayout';
44
import { useTransportsQuery } from 'graphql/requests/transports/queries/TransportsQuery.generated';
55
import { usePersistStore } from 'store/usePersistStore';
6+
import { getTransportAndPaymentValidationMessages } from 'utils/cart/getTransportAndPaymentValidationMessages';
67
import { useChangePaymentInCart } from 'utils/cart/useChangePaymentInCart';
78
import { useChangeTransportInCart } from 'utils/cart/useChangeTransportInCart';
89
import { useCurrentCart } from 'utils/cart/useCurrentCart';
910
import { hasValidationErrors } from 'utils/errors/hasValidationErrors';
1011
import useTranslation from 'utils/i18n/useTranslationWrapper';
1112
import { TransportAndPaymentSelect } from './TransportAndPaymentSelect/TransportAndPaymentSelect';
1213
import {
13-
getTransportAndPaymentValidationMessages,
1414
useLoadTransportAndPaymentFromLastOrder,
1515
useTransportAndPaymentPageNavigation,
1616
} from './transportAndPaymentUtils';

storefront/components/Pages/Order/TransportAndPayment/transportAndPaymentUtils.tsx

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { usePersistStore } from 'store/usePersistStore';
2222
import { useSessionStore } from 'store/useSessionStore';
2323
import { useClient } from 'urql';
2424
import { useIsUserLoggedIn } from 'utils/auth/useIsUserLoggedIn';
25+
import type { TransportAndPaymentErrorsType } from 'utils/cart/getTransportAndPaymentValidationMessages';
2526
import { getLastOrderPickupPlace, PICKUP_POINT_NOT_SET_ERROR_MESSAGE } from 'utils/cart/pickupPlaceCalculations';
2627
import { ChangePaymentInCart } from 'utils/cart/useChangePaymentInCart';
2728
import { ChangeTransportInCart } from 'utils/cart/useChangeTransportInCart';
@@ -221,60 +222,6 @@ export const useTransportChangeInSelect = (
221222
};
222223
};
223224

224-
type TransportAndPaymentErrorsType = {
225-
transport: {
226-
name: 'transport';
227-
label: string;
228-
errorMessage: string | undefined;
229-
};
230-
payment: {
231-
name: 'payment';
232-
label: string;
233-
errorMessage: string | undefined;
234-
};
235-
goPaySwift: {
236-
name: 'goPaySwift';
237-
label: string;
238-
errorMessage: string | undefined;
239-
};
240-
};
241-
242-
export const getTransportAndPaymentValidationMessages = (
243-
transport: Maybe<TypeTransportWithAvailablePaymentsFragment>,
244-
pickupPlace: Maybe<StoreOrPacketeryPoint>,
245-
payment: Maybe<TypeSimplePaymentFragment>,
246-
t: Translate,
247-
) => {
248-
const errors: Partial<TransportAndPaymentErrorsType> = {};
249-
250-
if (!transport) {
251-
errors.transport = {
252-
name: 'transport',
253-
label: t('Choose transport'),
254-
errorMessage: t('Please select transport'),
255-
};
256-
257-
return errors;
258-
}
259-
260-
if (transport.isPersonalPickup && !pickupPlace?.identifier) {
261-
errors.transport = {
262-
name: 'transport',
263-
label: t('Choose transport'),
264-
errorMessage: t('Please select transport with a personal pickup place'),
265-
};
266-
}
267-
if (!payment) {
268-
errors.payment = {
269-
name: 'payment',
270-
label: t('Choose payment'),
271-
errorMessage: t('Please select payment'),
272-
};
273-
}
274-
275-
return errors;
276-
};
277-
278225
export const useLoadTransportAndPaymentFromLastOrder = (
279226
changeTransportInCart: ChangeTransportInCart,
280227
changePaymentInCart: ChangePaymentInCart,

storefront/components/Pages/ProductComparison/ProductComparison.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { CompareIcon } from 'components/Basic/Icon/CompareIcon';
22
import { TrashCanIcon } from 'components/Basic/Icon/TrashCanIcon';
3-
import { RemoveAllProductsPopup } from 'components/Blocks/Popup/RemoveAllProductsPopup';
4-
import { LastVisitedProducts } from 'components/Blocks/Product/LastVisitedProducts/LastVisitedProducts';
3+
import { DeferredLastVisitedProducts } from 'components/Blocks/Product/LastVisitedProducts/DeferredLastVisitedProducts';
54
import { SkeletonModuleComparison } from 'components/Blocks/Skeleton/SkeletonModuleComparison';
65
import { Button } from 'components/Forms/Button/Button';
76
import { PageHero } from 'components/Layout/PageHero/PageHero';
@@ -10,11 +9,20 @@ import { Webline } from 'components/Layout/Webline/Webline';
109
import { TIDs } from 'cypress/tids';
1110
import { GtmProductListNameType } from 'gtm/enums/GtmProductListNameType';
1211
import { useGtmSliderProductListViewEvent } from 'gtm/utils/pageReadyEvents/productList/useGtmSliderProductListViewEvent';
12+
import dynamic from 'next/dynamic';
1313
import { useSessionStore } from 'store/useSessionStore';
1414
import useTranslation from 'utils/i18n/useTranslationWrapper';
1515
import { useComparison } from 'utils/productLists/comparison/useComparison';
1616
import { ProductComparisonContent } from './ProductComparisonContent';
1717

18+
const RemoveAllProductsPopup = dynamic(
19+
() =>
20+
import('components/Blocks/Popup/RemoveAllProductsPopup').then((component) => component.RemoveAllProductsPopup),
21+
{
22+
ssr: false,
23+
},
24+
);
25+
1826
export const ProductComparison: FC = () => {
1927
const { t } = useTranslation();
2028
const { comparison, isProductListFetching, removeComparison } = useComparison();
@@ -73,7 +81,7 @@ export const ProductComparison: FC = () => {
7381
)}
7482
</Webline>
7583

76-
<LastVisitedProducts />
84+
<DeferredLastVisitedProducts />
7785
</VerticalStack>
7886
);
7987
};

0 commit comments

Comments
 (0)