@akinon/next 1.96.0-snapshot-ZERO-35861-20250908151109 → 1.96.0-snapshot-ZERO-3620-20250915165755

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +1395 -45
  2. package/__tests__/next-config.test.ts +1 -10
  3. package/__tests__/redirect.test.ts +319 -0
  4. package/api/cache.ts +5 -39
  5. package/api/image-proxy.ts +75 -0
  6. package/api/similar-product-list.ts +84 -0
  7. package/api/similar-products.ts +120 -0
  8. package/components/accordion.tsx +20 -5
  9. package/components/file-input.tsx +65 -3
  10. package/components/input.tsx +2 -0
  11. package/components/link.tsx +16 -12
  12. package/components/modal.tsx +32 -16
  13. package/components/plugin-module.tsx +30 -3
  14. package/data/client/checkout.ts +5 -4
  15. package/data/server/basket.ts +72 -0
  16. package/data/server/category.ts +50 -32
  17. package/data/server/flatpage.ts +17 -16
  18. package/data/server/form.ts +1 -4
  19. package/data/server/landingpage.ts +16 -12
  20. package/data/server/list.ts +24 -15
  21. package/data/server/menu.ts +2 -5
  22. package/data/server/product.ts +67 -41
  23. package/data/server/special-page.ts +16 -12
  24. package/data/server/widget.ts +1 -4
  25. package/data/urls.ts +5 -1
  26. package/hocs/server/with-segment-defaults.tsx +5 -2
  27. package/hooks/use-localization.ts +2 -3
  28. package/jest.config.js +7 -1
  29. package/lib/cache-handler.mjs +87 -365
  30. package/lib/cache.ts +25 -252
  31. package/middlewares/complete-gpay.ts +2 -1
  32. package/middlewares/complete-masterpass.ts +2 -1
  33. package/middlewares/default.ts +50 -13
  34. package/middlewares/locale.ts +9 -1
  35. package/middlewares/pretty-url.ts +1 -2
  36. package/middlewares/redirection-payment.ts +2 -1
  37. package/middlewares/saved-card-redirection.ts +2 -1
  38. package/middlewares/three-d-redirection.ts +2 -1
  39. package/middlewares/url-redirection.ts +8 -14
  40. package/package.json +3 -4
  41. package/plugins.d.ts +8 -0
  42. package/plugins.js +3 -1
  43. package/redux/middlewares/checkout.ts +5 -1
  44. package/types/commerce/order.ts +1 -0
  45. package/types/index.ts +34 -2
  46. package/utils/app-fetch.ts +7 -2
  47. package/utils/redirect-ignore.ts +35 -0
  48. package/utils/redirect.ts +31 -6
  49. package/with-pz-config.js +1 -5
package/types/index.ts CHANGED
@@ -83,6 +83,12 @@ export interface Settings {
83
83
  };
84
84
  usePrettyUrlRoute?: boolean;
85
85
  commerceUrl: string;
86
+ /**
87
+ * This option allows you to track Sentry events on the client side, in addition to server and edge environments.
88
+ *
89
+ * It overrides process.env.NEXT_PUBLIC_SENTRY_DSN and process.env.SENTRY_DSN.
90
+ */
91
+ sentryDsn?: string;
86
92
  redis: {
87
93
  defaultExpirationTime: number;
88
94
  };
@@ -216,7 +222,6 @@ export interface CacheOptions {
216
222
  cache?: boolean;
217
223
  expire?: number;
218
224
  useProxy?: boolean;
219
- compressed?: boolean;
220
225
  }
221
226
 
222
227
  export interface SetCookieOptions {
@@ -292,7 +297,13 @@ export interface ButtonProps
292
297
  target?: '_blank' | '_self' | '_parent' | '_top';
293
298
  }
294
299
 
295
- export type FileInputProps = React.HTMLProps<HTMLInputElement>;
300
+ export interface FileInputProps extends React.HTMLProps<HTMLInputElement> {
301
+ fileClassName?: string;
302
+ fileNameWrapperClassName?: string;
303
+ fileInputClassName?: string;
304
+ onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
305
+ buttonClassName?: string;
306
+ }
296
307
 
297
308
  export interface PriceProps {
298
309
  currencyCode?: string;
@@ -313,15 +324,19 @@ export interface InputProps extends React.HTMLProps<HTMLInputElement> {
313
324
 
314
325
  export interface AccordionProps {
315
326
  isCollapse?: boolean;
327
+ collapseClassName?: string;
316
328
  title?: string;
317
329
  subTitle?: string;
318
330
  icons?: string[];
319
331
  iconSize?: number;
320
332
  iconColor?: string;
321
333
  children?: ReactNode;
334
+ headerClassName?: string;
322
335
  className?: string;
323
336
  titleClassName?: string;
337
+ subTitleClassName?: string;
324
338
  dataTestId?: string;
339
+ contentClassName?: string;
325
340
  }
326
341
 
327
342
  export interface PluginModuleComponentProps {
@@ -346,3 +361,20 @@ export interface PaginationProps {
346
361
  direction?: 'next' | 'prev';
347
362
  isLoading?: boolean;
348
363
  }
364
+
365
+ export interface ModalProps {
366
+ portalId: string;
367
+ children?: React.ReactNode;
368
+ open?: boolean;
369
+ setOpen?: (open: boolean) => void;
370
+ title?: React.ReactNode;
371
+ showCloseButton?: React.ReactNode;
372
+ className?: string;
373
+ overlayClassName?: string;
374
+ headerWrapperClassName?: string;
375
+ titleClassName?: string;
376
+ closeButtonClassName?: string;
377
+ iconName?: string;
378
+ iconSize?: number;
379
+ iconClassName?: string;
380
+ }
@@ -43,12 +43,12 @@ const appFetch = async <T>({
43
43
  const requestURL = `${decodeURIComponent(commerceUrl)}${url}`;
44
44
 
45
45
  init.headers = {
46
+ cookie: nextCookies.toString(),
46
47
  ...(init.headers ?? {}),
47
48
  ...(ServerVariables.globalHeaders ?? {}),
48
49
  'Accept-Language': currentLocale.apiValue,
49
50
  'x-currency': currency,
50
- 'x-forwarded-for': ip,
51
- cookie: nextCookies.toString()
51
+ 'x-forwarded-for': ip
52
52
  };
53
53
 
54
54
  init.next = {
@@ -60,6 +60,11 @@ const appFetch = async <T>({
60
60
  status = req.status;
61
61
  logger.debug(`FETCH END ${url}`, { status: req.status, ip });
62
62
 
63
+ if (!req.ok) {
64
+ const errorMessage = `HTTP ${req.status}: ${req.statusText}`;
65
+ throw new Error(errorMessage);
66
+ }
67
+
63
68
  if (responseType === FetchResponseType.JSON) {
64
69
  response = (await req.json()) as T;
65
70
  } else {
@@ -0,0 +1,35 @@
1
+ import settings from 'settings';
2
+ import { getUrlPathWithLocale } from './localization';
3
+
4
+ type IgnorePath = string | RegExp;
5
+
6
+ const defaultIgnoreList: string[] = [];
7
+
8
+ const extraIgnores: IgnorePath[] = Array.isArray(
9
+ settings.commerceRedirectionIgnoreList
10
+ )
11
+ ? settings.commerceRedirectionIgnoreList.map((path) => {
12
+ if (path === '/users/reset') {
13
+ return /^\/users\/reset\/[^/]+\/[^/]+\/$/;
14
+ }
15
+ return path;
16
+ })
17
+ : [];
18
+
19
+ export function shouldIgnoreRedirect(
20
+ pathname: string,
21
+ locale: string
22
+ ): boolean {
23
+ if (!pathname) return false;
24
+
25
+ const rawIgnoreList: IgnorePath[] = [...defaultIgnoreList, ...extraIgnores];
26
+
27
+ return rawIgnoreList.some((ignorePath) => {
28
+ if (ignorePath instanceof RegExp) {
29
+ return ignorePath.test(pathname);
30
+ }
31
+
32
+ const localized = getUrlPathWithLocale(ignorePath, locale);
33
+ return localized === pathname;
34
+ });
35
+ }
package/utils/redirect.ts CHANGED
@@ -1,23 +1,48 @@
1
1
  import { redirect as nextRedirect, RedirectType } from 'next/navigation';
2
2
  import Settings from 'settings';
3
- import { headers } from 'next/headers';
4
- import { ServerVariables } from '@akinon/next/utils/server-variables';
3
+ import { headers, cookies } from 'next/headers';
5
4
  import { getUrlPathWithLocale } from '@akinon/next/utils/localization';
5
+ import { urlLocaleMatcherRegex } from '@akinon/next/utils';
6
6
 
7
7
  export const redirect = (path: string, type?: RedirectType) => {
8
8
  const nextHeaders = headers();
9
+ const nextCookies = cookies();
9
10
  const pageUrl = new URL(
10
- nextHeaders.get('pz-url') ?? process.env.NEXT_PUBLIC_URL
11
+ nextHeaders.get('pz-url') ?? process.env.NEXT_PUBLIC_URL ?? ''
11
12
  );
12
13
 
14
+ let currentLocaleValue = Settings.localization.defaultLocaleValue;
15
+ const urlLocaleMatch = pageUrl.pathname.match(urlLocaleMatcherRegex);
16
+
17
+ if (urlLocaleMatch && urlLocaleMatch[0]) {
18
+ currentLocaleValue = urlLocaleMatch[0].replace('/', '');
19
+ } else {
20
+ const cookieLocale = nextCookies.get('pz-locale')?.value;
21
+ if (
22
+ cookieLocale &&
23
+ Settings.localization.locales.find((l) => l.value === cookieLocale)
24
+ ) {
25
+ currentLocaleValue = cookieLocale;
26
+ }
27
+ }
28
+
13
29
  const currentLocale = Settings.localization.locales.find(
14
- (locale) => locale.value === ServerVariables.locale
30
+ (locale) => locale.value === currentLocaleValue
15
31
  );
16
32
 
17
- const callbackUrl = pageUrl.pathname;
33
+ if (!currentLocale) {
34
+ currentLocaleValue = Settings.localization.defaultLocaleValue;
35
+ }
36
+
37
+ const searchParams = new URLSearchParams(pageUrl.search);
38
+
39
+ const callbackUrl =
40
+ pageUrl.pathname.replace(urlLocaleMatcherRegex, '') +
41
+ (searchParams.toString() ? `?${searchParams.toString()}` : '');
42
+
18
43
  const redirectUrlWithLocale = getUrlPathWithLocale(
19
44
  path,
20
- currentLocale.localePath ?? currentLocale.value
45
+ currentLocale?.value
21
46
  );
22
47
 
23
48
  const redirectUrl = `${redirectUrlWithLocale}?callbackUrl=${callbackUrl}`;
package/with-pz-config.js CHANGED
@@ -16,12 +16,8 @@ const defaultConfig = {
16
16
  remotePatterns: [
17
17
  {
18
18
  protocol: 'https',
19
- hostname: '**.akinoncloud.com'
19
+ hostname: '**'
20
20
  },
21
- {
22
- protocol: 'https',
23
- hostname: '**.akinoncdn.com'
24
- }
25
21
  ]
26
22
  },
27
23
  modularizeImports: {