@akinon/next 1.14.0 → 1.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +40 -40
- package/.prettierrc +13 -13
- package/CHANGELOG.md +6 -0
- package/api/auth.ts +231 -231
- package/api/cache.ts +44 -44
- package/api/client.ts +174 -174
- package/api/logout.ts +42 -42
- package/bin/pz-check-dependencies.js +98 -98
- package/bin/pz-install-plugins.js +33 -33
- package/bin/pz-install-theme.js +58 -58
- package/bin/pz-postbuild.js +1 -1
- package/bin/pz-postdev.js +1 -1
- package/bin/pz-postinstall.js +6 -6
- package/bin/pz-poststart.js +1 -1
- package/bin/pz-prebuild.js +4 -4
- package/bin/pz-predev.js +4 -4
- package/bin/pz-prestart.js +1 -1
- package/bin/run-script.js +44 -44
- package/components/accordion.tsx +52 -52
- package/components/button.tsx +46 -46
- package/components/client-root.tsx +19 -19
- package/components/icon.tsx +18 -18
- package/components/image.tsx +133 -133
- package/components/index.ts +17 -17
- package/components/input.tsx +110 -110
- package/components/lazy-component.tsx +33 -33
- package/components/loader-spinner.tsx +23 -23
- package/components/mobile-app-toggler.tsx +26 -26
- package/components/oauth-login.tsx +24 -24
- package/components/price.tsx +55 -55
- package/components/pz-providers.tsx +24 -24
- package/components/pz-root.tsx +21 -21
- package/components/radio.tsx +18 -18
- package/components/react-portal.tsx +45 -45
- package/components/redirect-three-d/content/index.tsx +74 -74
- package/components/redirect-three-d/index.tsx +17 -17
- package/components/trans.tsx +39 -39
- package/data/client/account.ts +208 -208
- package/data/client/api.ts +85 -85
- package/data/client/basket.ts +82 -82
- package/data/client/misc.ts +101 -101
- package/data/client/product.ts +89 -89
- package/data/client/user.ts +99 -99
- package/data/client/wishlist.ts +118 -118
- package/data/server/category.ts +132 -132
- package/data/server/flatpage.ts +21 -21
- package/data/server/form.ts +22 -22
- package/data/server/index.ts +10 -10
- package/data/server/landingpage.ts +24 -24
- package/data/server/list.ts +67 -67
- package/data/server/menu.ts +35 -35
- package/data/server/product.ts +86 -86
- package/data/server/seo.ts +48 -48
- package/data/server/special-page.ts +47 -47
- package/data/server/widget.ts +27 -27
- package/data/urls.ts +221 -221
- package/hocs/client/index.ts +1 -1
- package/hocs/client/with-segment-defaults.tsx +25 -25
- package/hocs/server/index.ts +1 -1
- package/hocs/server/with-segment-defaults.tsx +85 -85
- package/hooks/index.ts +10 -10
- package/hooks/use-captcha.tsx +76 -76
- package/hooks/use-common-product-attributes.ts +36 -36
- package/hooks/use-debounce.ts +20 -20
- package/hooks/use-localization.ts +78 -78
- package/hooks/use-media-query.ts +36 -36
- package/hooks/use-mobile-iframe-handler.ts +23 -23
- package/hooks/use-on-click-outside.tsx +28 -28
- package/hooks/use-router.ts +45 -45
- package/hooks/use-translation.ts +14 -14
- package/lib/cache.ts +215 -215
- package/localization/index.ts +5 -5
- package/localization/provider.tsx +58 -58
- package/middlewares/currency.ts +100 -100
- package/middlewares/default.ts +256 -256
- package/middlewares/index.ts +29 -29
- package/middlewares/locale.ts +68 -68
- package/middlewares/oauth-login.ts +79 -79
- package/middlewares/pretty-url.ts +104 -104
- package/middlewares/redirection-payment.ts +160 -160
- package/middlewares/three-d-redirection.ts +159 -159
- package/middlewares/url-redirection.ts +65 -65
- package/package.json +2 -2
- package/redux/hooks.ts +7 -7
- package/redux/middlewares/index.ts +50 -50
- package/redux/reducers/checkout.ts +184 -184
- package/redux/reducers/config.ts +28 -28
- package/redux/reducers/header.ts +59 -59
- package/redux/reducers/root.ts +61 -61
- package/sentry/index.ts +27 -27
- package/tailwind/rtl.js +137 -137
- package/types/commerce/account.ts +64 -64
- package/types/commerce/address.ts +94 -94
- package/types/commerce/basket.ts +43 -43
- package/types/commerce/category.ts +114 -114
- package/types/commerce/checkout.ts +143 -143
- package/types/commerce/flatpage.ts +7 -7
- package/types/commerce/form.ts +66 -66
- package/types/commerce/index.ts +12 -12
- package/types/commerce/landingpage.ts +7 -7
- package/types/commerce/misc.ts +127 -127
- package/types/commerce/order.ts +119 -119
- package/types/commerce/product.ts +109 -109
- package/types/commerce/widget.ts +28 -28
- package/types/gtm.ts +16 -16
- package/types/index.ts +274 -274
- package/types/metadata.ts +7 -7
- package/types/next-auth.d.ts +24 -24
- package/utils/app-fetch.ts +69 -69
- package/utils/deep-merge.js +24 -24
- package/utils/image-loader.ts +31 -31
- package/utils/index.ts +150 -150
- package/utils/localization.ts +29 -29
- package/utils/log.ts +138 -138
- package/utils/menu-generator.ts +27 -27
- package/utils/mobile-3d-iframe.ts +77 -77
- package/utils/server-translation.ts +57 -57
- package/utils/server-variables.ts +9 -9
- package/with-pz-config.js +94 -94
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
import settings from 'settings';
|
|
2
|
-
import { LayoutProps, PageProps, RootLayoutProps } from '../../types';
|
|
3
|
-
import { redirect } from 'next/navigation';
|
|
4
|
-
import { ServerVariables } from '../../utils/server-variables';
|
|
5
|
-
import { getTranslations } from '../../utils/server-translation';
|
|
6
|
-
import { ROUTES } from 'routes';
|
|
7
|
-
import logger from '../../utils/log';
|
|
8
|
-
|
|
9
|
-
type SegmentType = 'root-layout' | 'layout' | 'page';
|
|
10
|
-
|
|
11
|
-
interface SegmentDefaultsOptions {
|
|
12
|
-
segmentType: SegmentType;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const withSegmentDefaults =
|
|
16
|
-
<T extends PageProps | LayoutProps | RootLayoutProps>(
|
|
17
|
-
Component: (
|
|
18
|
-
props?: T
|
|
19
|
-
) => null | JSX.Element | Promise<JSX.Element> | Promise<JSX.Element[]>,
|
|
20
|
-
options: SegmentDefaultsOptions
|
|
21
|
-
) =>
|
|
22
|
-
async (props: T) => {
|
|
23
|
-
let componentProps = { ...props };
|
|
24
|
-
|
|
25
|
-
if (options.segmentType === 'root-layout') {
|
|
26
|
-
componentProps = (await addRootLayoutProps(
|
|
27
|
-
componentProps as RootLayoutProps
|
|
28
|
-
)) as T;
|
|
29
|
-
|
|
30
|
-
checkRedisVariables();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
ServerVariables.locale = props.params.locale;
|
|
34
|
-
ServerVariables.currency = props.params.currency;
|
|
35
|
-
|
|
36
|
-
return await (
|
|
37
|
-
<>
|
|
38
|
-
<Component {...componentProps} />
|
|
39
|
-
</>
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const addRootLayoutProps = async (componentProps: RootLayoutProps) => {
|
|
44
|
-
const params = componentProps.params;
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
params.commerce !== encodeURIComponent(decodeURI(settings.commerceUrl)) ||
|
|
48
|
-
!settings.localization.locales.find((l) => l.value === params.locale)
|
|
49
|
-
) {
|
|
50
|
-
return redirect(ROUTES.HOME);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const translations = await getTranslations(params.locale);
|
|
54
|
-
componentProps.translations = translations;
|
|
55
|
-
|
|
56
|
-
const locale = settings.localization.locales.find(
|
|
57
|
-
(l) => l.value === params.locale
|
|
58
|
-
);
|
|
59
|
-
const [isoCode] = locale.value.split('-');
|
|
60
|
-
|
|
61
|
-
componentProps.locale = {
|
|
62
|
-
...locale,
|
|
63
|
-
isoCode
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
return componentProps;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const checkRedisVariables = () => {
|
|
70
|
-
const requiredVariableValues = [
|
|
71
|
-
process.env.CACHE_HOST,
|
|
72
|
-
process.env.CACHE_PORT,
|
|
73
|
-
process.env.CACHE_SECRET
|
|
74
|
-
];
|
|
75
|
-
|
|
76
|
-
if (
|
|
77
|
-
!requiredVariableValues.every((v) => v) &&
|
|
78
|
-
process.env.NODE_ENV === 'production'
|
|
79
|
-
) {
|
|
80
|
-
logger.warn('Redis cache variables are not set', {
|
|
81
|
-
requiredVariables: ['CACHE_HOST', 'CACHE_PORT', 'CACHE_SECRET'],
|
|
82
|
-
values: requiredVariableValues
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
};
|
|
1
|
+
import settings from 'settings';
|
|
2
|
+
import { LayoutProps, PageProps, RootLayoutProps } from '../../types';
|
|
3
|
+
import { redirect } from 'next/navigation';
|
|
4
|
+
import { ServerVariables } from '../../utils/server-variables';
|
|
5
|
+
import { getTranslations } from '../../utils/server-translation';
|
|
6
|
+
import { ROUTES } from 'routes';
|
|
7
|
+
import logger from '../../utils/log';
|
|
8
|
+
|
|
9
|
+
type SegmentType = 'root-layout' | 'layout' | 'page';
|
|
10
|
+
|
|
11
|
+
interface SegmentDefaultsOptions {
|
|
12
|
+
segmentType: SegmentType;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const withSegmentDefaults =
|
|
16
|
+
<T extends PageProps | LayoutProps | RootLayoutProps>(
|
|
17
|
+
Component: (
|
|
18
|
+
props?: T
|
|
19
|
+
) => null | JSX.Element | Promise<JSX.Element> | Promise<JSX.Element[]>,
|
|
20
|
+
options: SegmentDefaultsOptions
|
|
21
|
+
) =>
|
|
22
|
+
async (props: T) => {
|
|
23
|
+
let componentProps = { ...props };
|
|
24
|
+
|
|
25
|
+
if (options.segmentType === 'root-layout') {
|
|
26
|
+
componentProps = (await addRootLayoutProps(
|
|
27
|
+
componentProps as RootLayoutProps
|
|
28
|
+
)) as T;
|
|
29
|
+
|
|
30
|
+
checkRedisVariables();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
ServerVariables.locale = props.params.locale;
|
|
34
|
+
ServerVariables.currency = props.params.currency;
|
|
35
|
+
|
|
36
|
+
return await (
|
|
37
|
+
<>
|
|
38
|
+
<Component {...componentProps} />
|
|
39
|
+
</>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const addRootLayoutProps = async (componentProps: RootLayoutProps) => {
|
|
44
|
+
const params = componentProps.params;
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
params.commerce !== encodeURIComponent(decodeURI(settings.commerceUrl)) ||
|
|
48
|
+
!settings.localization.locales.find((l) => l.value === params.locale)
|
|
49
|
+
) {
|
|
50
|
+
return redirect(ROUTES.HOME);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const translations = await getTranslations(params.locale);
|
|
54
|
+
componentProps.translations = translations;
|
|
55
|
+
|
|
56
|
+
const locale = settings.localization.locales.find(
|
|
57
|
+
(l) => l.value === params.locale
|
|
58
|
+
);
|
|
59
|
+
const [isoCode] = locale.value.split('-');
|
|
60
|
+
|
|
61
|
+
componentProps.locale = {
|
|
62
|
+
...locale,
|
|
63
|
+
isoCode
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return componentProps;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const checkRedisVariables = () => {
|
|
70
|
+
const requiredVariableValues = [
|
|
71
|
+
process.env.CACHE_HOST,
|
|
72
|
+
process.env.CACHE_PORT,
|
|
73
|
+
process.env.CACHE_SECRET
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
if (
|
|
77
|
+
!requiredVariableValues.every((v) => v) &&
|
|
78
|
+
process.env.NODE_ENV === 'production'
|
|
79
|
+
) {
|
|
80
|
+
logger.warn('Redis cache variables are not set', {
|
|
81
|
+
requiredVariables: ['CACHE_HOST', 'CACHE_PORT', 'CACHE_SECRET'],
|
|
82
|
+
values: requiredVariableValues
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
package/hooks/index.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export * from './use-router';
|
|
2
|
-
export * from './use-localization';
|
|
3
|
-
export * from './use-translation';
|
|
4
|
-
export * from './use-captcha';
|
|
5
|
-
export * from './use-common-product-attributes';
|
|
6
|
-
export * from './use-debounce';
|
|
7
|
-
export * from './use-media-query';
|
|
8
|
-
export * from './use-on-click-outside';
|
|
9
|
-
export * from './use-mobile-iframe-handler';
|
|
10
|
-
export * from './use-payment-options';
|
|
1
|
+
export * from './use-router';
|
|
2
|
+
export * from './use-localization';
|
|
3
|
+
export * from './use-translation';
|
|
4
|
+
export * from './use-captcha';
|
|
5
|
+
export * from './use-common-product-attributes';
|
|
6
|
+
export * from './use-debounce';
|
|
7
|
+
export * from './use-media-query';
|
|
8
|
+
export * from './use-on-click-outside';
|
|
9
|
+
export * from './use-mobile-iframe-handler';
|
|
10
|
+
export * from './use-payment-options';
|
package/hooks/use-captcha.tsx
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
4
|
-
import ReCAPTCHA from 'react-google-recaptcha';
|
|
5
|
-
import {
|
|
6
|
-
useGetCaptchaQuery,
|
|
7
|
-
useValidateCaptchaMutation
|
|
8
|
-
} from '../data/client/user';
|
|
9
|
-
import { setCookie } from '../utils';
|
|
10
|
-
|
|
11
|
-
interface CaptchaViewProps {
|
|
12
|
-
className?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const useCaptcha = () => {
|
|
16
|
-
const { data } = useGetCaptchaQuery();
|
|
17
|
-
const { siteKey, csrfToken } = data ?? {};
|
|
18
|
-
const [validateCaptchaMutation] = useValidateCaptchaMutation();
|
|
19
|
-
const [validated, setValidated] = useState<boolean>(false);
|
|
20
|
-
const [isVisible, setIsVisible] = useState<boolean>(false);
|
|
21
|
-
const [captchaResponse, setCaptchaResponse] = useState<string>(null);
|
|
22
|
-
|
|
23
|
-
const validate = async () => {
|
|
24
|
-
if (!captchaResponse) {
|
|
25
|
-
setIsVisible(true);
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
setValidated(false);
|
|
30
|
-
|
|
31
|
-
const response = await validateCaptchaMutation({
|
|
32
|
-
captchaResponse,
|
|
33
|
-
csrfToken
|
|
34
|
-
}).unwrap();
|
|
35
|
-
|
|
36
|
-
setValidated(response.success);
|
|
37
|
-
|
|
38
|
-
return response.success;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
if (csrfToken) {
|
|
42
|
-
setCookie('csrftoken', csrfToken);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const onCaptchaChange = useCallback(async (response) => {
|
|
46
|
-
setTimeout(() => {
|
|
47
|
-
setCaptchaResponse(response);
|
|
48
|
-
}, 500);
|
|
49
|
-
}, []);
|
|
50
|
-
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
if (captchaResponse) {
|
|
53
|
-
validate();
|
|
54
|
-
}
|
|
55
|
-
}, [captchaResponse]);
|
|
56
|
-
|
|
57
|
-
const CaptchaView = useMemo(() => {
|
|
58
|
-
const View = (props: CaptchaViewProps) =>
|
|
59
|
-
isVisible && !captchaResponse ? (
|
|
60
|
-
<ReCAPTCHA
|
|
61
|
-
sitekey={siteKey}
|
|
62
|
-
onChange={onCaptchaChange}
|
|
63
|
-
className={props.className}
|
|
64
|
-
/>
|
|
65
|
-
) : null;
|
|
66
|
-
|
|
67
|
-
return View;
|
|
68
|
-
}, [siteKey, onCaptchaChange, isVisible, captchaResponse]);
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
CaptchaView,
|
|
72
|
-
validated,
|
|
73
|
-
isVisible,
|
|
74
|
-
validate
|
|
75
|
-
};
|
|
76
|
-
};
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import ReCAPTCHA from 'react-google-recaptcha';
|
|
5
|
+
import {
|
|
6
|
+
useGetCaptchaQuery,
|
|
7
|
+
useValidateCaptchaMutation
|
|
8
|
+
} from '../data/client/user';
|
|
9
|
+
import { setCookie } from '../utils';
|
|
10
|
+
|
|
11
|
+
interface CaptchaViewProps {
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const useCaptcha = () => {
|
|
16
|
+
const { data } = useGetCaptchaQuery();
|
|
17
|
+
const { siteKey, csrfToken } = data ?? {};
|
|
18
|
+
const [validateCaptchaMutation] = useValidateCaptchaMutation();
|
|
19
|
+
const [validated, setValidated] = useState<boolean>(false);
|
|
20
|
+
const [isVisible, setIsVisible] = useState<boolean>(false);
|
|
21
|
+
const [captchaResponse, setCaptchaResponse] = useState<string>(null);
|
|
22
|
+
|
|
23
|
+
const validate = async () => {
|
|
24
|
+
if (!captchaResponse) {
|
|
25
|
+
setIsVisible(true);
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setValidated(false);
|
|
30
|
+
|
|
31
|
+
const response = await validateCaptchaMutation({
|
|
32
|
+
captchaResponse,
|
|
33
|
+
csrfToken
|
|
34
|
+
}).unwrap();
|
|
35
|
+
|
|
36
|
+
setValidated(response.success);
|
|
37
|
+
|
|
38
|
+
return response.success;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (csrfToken) {
|
|
42
|
+
setCookie('csrftoken', csrfToken);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const onCaptchaChange = useCallback(async (response) => {
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
setCaptchaResponse(response);
|
|
48
|
+
}, 500);
|
|
49
|
+
}, []);
|
|
50
|
+
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (captchaResponse) {
|
|
53
|
+
validate();
|
|
54
|
+
}
|
|
55
|
+
}, [captchaResponse]);
|
|
56
|
+
|
|
57
|
+
const CaptchaView = useMemo(() => {
|
|
58
|
+
const View = (props: CaptchaViewProps) =>
|
|
59
|
+
isVisible && !captchaResponse ? (
|
|
60
|
+
<ReCAPTCHA
|
|
61
|
+
sitekey={siteKey}
|
|
62
|
+
onChange={onCaptchaChange}
|
|
63
|
+
className={props.className}
|
|
64
|
+
/>
|
|
65
|
+
) : null;
|
|
66
|
+
|
|
67
|
+
return View;
|
|
68
|
+
}, [siteKey, onCaptchaChange, isVisible, captchaResponse]);
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
CaptchaView,
|
|
72
|
+
validated,
|
|
73
|
+
isVisible,
|
|
74
|
+
validate
|
|
75
|
+
};
|
|
76
|
+
};
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import Settings from 'settings';
|
|
4
|
-
import { useLocalization } from './use-localization';
|
|
5
|
-
|
|
6
|
-
type UseCommonProductAttributesArgs = {
|
|
7
|
-
attributes: { [key: string]: { value: string } };
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
type CommonProductAttributes = { name: string; value: string }[];
|
|
11
|
-
|
|
12
|
-
export const useCommonProductAttributes = (
|
|
13
|
-
args: UseCommonProductAttributesArgs
|
|
14
|
-
) => {
|
|
15
|
-
const { attributes } = args;
|
|
16
|
-
const commonProductAttributes: CommonProductAttributes = [];
|
|
17
|
-
const { t } = useLocalization();
|
|
18
|
-
|
|
19
|
-
Settings.commonProductAttributes.forEach((commonProductAttribute) => {
|
|
20
|
-
const attribute = Object.entries(attributes).find(
|
|
21
|
-
// Object.entries gives us an array of [key, value] pairs.
|
|
22
|
-
([key]) => key === commonProductAttribute.key
|
|
23
|
-
)?.[1]; // We only want the value, so we get the second item in the array.
|
|
24
|
-
|
|
25
|
-
if (attribute) {
|
|
26
|
-
commonProductAttributes.push({
|
|
27
|
-
name: t(
|
|
28
|
-
`common.common_product_attributes.${commonProductAttribute.translationKey}`
|
|
29
|
-
),
|
|
30
|
-
value: attribute.value
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return commonProductAttributes;
|
|
36
|
-
};
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Settings from 'settings';
|
|
4
|
+
import { useLocalization } from './use-localization';
|
|
5
|
+
|
|
6
|
+
type UseCommonProductAttributesArgs = {
|
|
7
|
+
attributes: { [key: string]: { value: string } };
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type CommonProductAttributes = { name: string; value: string }[];
|
|
11
|
+
|
|
12
|
+
export const useCommonProductAttributes = (
|
|
13
|
+
args: UseCommonProductAttributesArgs
|
|
14
|
+
) => {
|
|
15
|
+
const { attributes } = args;
|
|
16
|
+
const commonProductAttributes: CommonProductAttributes = [];
|
|
17
|
+
const { t } = useLocalization();
|
|
18
|
+
|
|
19
|
+
Settings.commonProductAttributes.forEach((commonProductAttribute) => {
|
|
20
|
+
const attribute = Object.entries(attributes).find(
|
|
21
|
+
// Object.entries gives us an array of [key, value] pairs.
|
|
22
|
+
([key]) => key === commonProductAttribute.key
|
|
23
|
+
)?.[1]; // We only want the value, so we get the second item in the array.
|
|
24
|
+
|
|
25
|
+
if (attribute) {
|
|
26
|
+
commonProductAttributes.push({
|
|
27
|
+
name: t(
|
|
28
|
+
`common.common_product_attributes.${commonProductAttribute.translationKey}`
|
|
29
|
+
),
|
|
30
|
+
value: attribute.value
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return commonProductAttributes;
|
|
36
|
+
};
|
package/hooks/use-debounce.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
// https://usehooks.com/useDebounce/
|
|
2
|
-
'use client';
|
|
3
|
-
|
|
4
|
-
import { useEffect, useState } from 'react';
|
|
5
|
-
|
|
6
|
-
export function useDebounce<T>(value: T, delay: number): T {
|
|
7
|
-
const [debouncedValue, setDebouncedValue] = useState<T>(value);
|
|
8
|
-
|
|
9
|
-
useEffect(() => {
|
|
10
|
-
const handler = setTimeout(() => {
|
|
11
|
-
setDebouncedValue(value);
|
|
12
|
-
}, delay);
|
|
13
|
-
|
|
14
|
-
return () => {
|
|
15
|
-
clearTimeout(handler);
|
|
16
|
-
};
|
|
17
|
-
}, [value, delay]);
|
|
18
|
-
|
|
19
|
-
return debouncedValue;
|
|
20
|
-
}
|
|
1
|
+
// https://usehooks.com/useDebounce/
|
|
2
|
+
'use client';
|
|
3
|
+
|
|
4
|
+
import { useEffect, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
export function useDebounce<T>(value: T, delay: number): T {
|
|
7
|
+
const [debouncedValue, setDebouncedValue] = useState<T>(value);
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const handler = setTimeout(() => {
|
|
11
|
+
setDebouncedValue(value);
|
|
12
|
+
}, delay);
|
|
13
|
+
|
|
14
|
+
return () => {
|
|
15
|
+
clearTimeout(handler);
|
|
16
|
+
};
|
|
17
|
+
}, [value, delay]);
|
|
18
|
+
|
|
19
|
+
return debouncedValue;
|
|
20
|
+
}
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { LocalizationContext } from '../localization/provider';
|
|
4
|
-
import { useContext } from 'react';
|
|
5
|
-
import { setCookie, urlLocaleMatcherRegex } from '../utils';
|
|
6
|
-
import { LocaleUrlStrategy } from '../localization';
|
|
7
|
-
import { useRouter } from 'next/navigation';
|
|
8
|
-
|
|
9
|
-
export const useLocalization = () => {
|
|
10
|
-
const {
|
|
11
|
-
translate,
|
|
12
|
-
locale,
|
|
13
|
-
currency,
|
|
14
|
-
locales,
|
|
15
|
-
currencies,
|
|
16
|
-
defaultLocaleValue,
|
|
17
|
-
defaultCurrencyCode,
|
|
18
|
-
localeUrlStrategy
|
|
19
|
-
} = useContext(LocalizationContext);
|
|
20
|
-
|
|
21
|
-
const router = useRouter();
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Sets the locale in the URL.
|
|
25
|
-
* @param locale Locale value defined in the settings.
|
|
26
|
-
*/
|
|
27
|
-
const setLocale = (locale: string) => {
|
|
28
|
-
const localePath =
|
|
29
|
-
locale === defaultLocaleValue &&
|
|
30
|
-
localeUrlStrategy !== LocaleUrlStrategy.ShowAllLocales
|
|
31
|
-
? ''
|
|
32
|
-
: `/${locale}`;
|
|
33
|
-
|
|
34
|
-
const pathnameWithoutLocale = location.pathname.replace(
|
|
35
|
-
urlLocaleMatcherRegex,
|
|
36
|
-
''
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
// router.push is not used because reloading the page also clears the client side cache.
|
|
40
|
-
location.href = `${localePath}${pathnameWithoutLocale}${location.search}`;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Sets the currency.
|
|
45
|
-
*
|
|
46
|
-
* If the currency is linked to the locale by using `getActiveCurrencyCode` function in the settings,
|
|
47
|
-
* you need to use `setLocale` instead of this.
|
|
48
|
-
* @param currency Currency code defined in the settings.
|
|
49
|
-
*/
|
|
50
|
-
const setCurrency = (currency: string) => {
|
|
51
|
-
// It is a temp cookie to set currency in `currency` middleware.
|
|
52
|
-
setCookie('pz-set-currency', currency);
|
|
53
|
-
location.reload();
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
return {
|
|
57
|
-
/**
|
|
58
|
-
* Translate function
|
|
59
|
-
* @param path
|
|
60
|
-
* Path of the translation.
|
|
61
|
-
* It is a dot separated string e.g. "common.header.title".
|
|
62
|
-
* "common" is the file name in the translations folder.
|
|
63
|
-
* "header" is the key in the file.
|
|
64
|
-
* "title" is the value of the key.
|
|
65
|
-
* @returns {string} Translated value
|
|
66
|
-
*/
|
|
67
|
-
t: (path: string) => translate(path),
|
|
68
|
-
setLocale,
|
|
69
|
-
setCurrency,
|
|
70
|
-
locale,
|
|
71
|
-
currency,
|
|
72
|
-
locales,
|
|
73
|
-
currencies,
|
|
74
|
-
defaultLocaleValue,
|
|
75
|
-
defaultCurrencyCode,
|
|
76
|
-
localeUrlStrategy
|
|
77
|
-
};
|
|
78
|
-
};
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { LocalizationContext } from '../localization/provider';
|
|
4
|
+
import { useContext } from 'react';
|
|
5
|
+
import { setCookie, urlLocaleMatcherRegex } from '../utils';
|
|
6
|
+
import { LocaleUrlStrategy } from '../localization';
|
|
7
|
+
import { useRouter } from 'next/navigation';
|
|
8
|
+
|
|
9
|
+
export const useLocalization = () => {
|
|
10
|
+
const {
|
|
11
|
+
translate,
|
|
12
|
+
locale,
|
|
13
|
+
currency,
|
|
14
|
+
locales,
|
|
15
|
+
currencies,
|
|
16
|
+
defaultLocaleValue,
|
|
17
|
+
defaultCurrencyCode,
|
|
18
|
+
localeUrlStrategy
|
|
19
|
+
} = useContext(LocalizationContext);
|
|
20
|
+
|
|
21
|
+
const router = useRouter();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Sets the locale in the URL.
|
|
25
|
+
* @param locale Locale value defined in the settings.
|
|
26
|
+
*/
|
|
27
|
+
const setLocale = (locale: string) => {
|
|
28
|
+
const localePath =
|
|
29
|
+
locale === defaultLocaleValue &&
|
|
30
|
+
localeUrlStrategy !== LocaleUrlStrategy.ShowAllLocales
|
|
31
|
+
? ''
|
|
32
|
+
: `/${locale}`;
|
|
33
|
+
|
|
34
|
+
const pathnameWithoutLocale = location.pathname.replace(
|
|
35
|
+
urlLocaleMatcherRegex,
|
|
36
|
+
''
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// router.push is not used because reloading the page also clears the client side cache.
|
|
40
|
+
location.href = `${localePath}${pathnameWithoutLocale}${location.search}`;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Sets the currency.
|
|
45
|
+
*
|
|
46
|
+
* If the currency is linked to the locale by using `getActiveCurrencyCode` function in the settings,
|
|
47
|
+
* you need to use `setLocale` instead of this.
|
|
48
|
+
* @param currency Currency code defined in the settings.
|
|
49
|
+
*/
|
|
50
|
+
const setCurrency = (currency: string) => {
|
|
51
|
+
// It is a temp cookie to set currency in `currency` middleware.
|
|
52
|
+
setCookie('pz-set-currency', currency);
|
|
53
|
+
location.reload();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
/**
|
|
58
|
+
* Translate function
|
|
59
|
+
* @param path
|
|
60
|
+
* Path of the translation.
|
|
61
|
+
* It is a dot separated string e.g. "common.header.title".
|
|
62
|
+
* "common" is the file name in the translations folder.
|
|
63
|
+
* "header" is the key in the file.
|
|
64
|
+
* "title" is the value of the key.
|
|
65
|
+
* @returns {string} Translated value
|
|
66
|
+
*/
|
|
67
|
+
t: (path: string) => translate(path),
|
|
68
|
+
setLocale,
|
|
69
|
+
setCurrency,
|
|
70
|
+
locale,
|
|
71
|
+
currency,
|
|
72
|
+
locales,
|
|
73
|
+
currencies,
|
|
74
|
+
defaultLocaleValue,
|
|
75
|
+
defaultCurrencyCode,
|
|
76
|
+
localeUrlStrategy
|
|
77
|
+
};
|
|
78
|
+
};
|