@akinon/projectzero 1.91.0 → 1.92.0-rc.8

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projectzeronext",
3
- "version": "1.91.0",
3
+ "version": "1.92.0-rc.8",
4
4
  "private": true,
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -24,22 +24,23 @@
24
24
  "test:middleware": "jest middleware-matcher.test.ts --bail"
25
25
  },
26
26
  "dependencies": {
27
- "@akinon/next": "1.91.0",
28
- "@akinon/pz-akifast": "1.91.0",
29
- "@akinon/pz-b2b": "1.91.0",
30
- "@akinon/pz-basket-gift-pack": "1.91.0",
31
- "@akinon/pz-bkm": "1.91.0",
32
- "@akinon/pz-checkout-gift-pack": "1.91.0",
33
- "@akinon/pz-click-collect": "1.91.0",
34
- "@akinon/pz-credit-payment": "1.91.0",
35
- "@akinon/pz-gpay": "1.91.0",
36
- "@akinon/pz-masterpass": "1.91.0",
37
- "@akinon/pz-one-click-checkout": "1.91.0",
38
- "@akinon/pz-otp": "1.91.0",
39
- "@akinon/pz-pay-on-delivery": "1.91.0",
40
- "@akinon/pz-saved-card": "1.91.0",
41
- "@akinon/pz-tabby-extension": "1.91.0",
42
- "@akinon/pz-tamara-extension": "1.91.0",
27
+ "@akinon/next": "1.92.0-rc.8",
28
+ "@akinon/pz-akifast": "1.92.0-rc.8",
29
+ "@akinon/pz-b2b": "1.92.0-rc.8",
30
+ "@akinon/pz-basket-gift-pack": "1.92.0-rc.8",
31
+ "@akinon/pz-bkm": "1.92.0-rc.8",
32
+ "@akinon/pz-checkout-gift-pack": "1.92.0-rc.8",
33
+ "@akinon/pz-click-collect": "1.92.0-rc.8",
34
+ "@akinon/pz-credit-payment": "1.92.0-rc.8",
35
+ "@akinon/pz-gpay": "1.92.0-rc.8",
36
+ "@akinon/pz-hepsipay": "1.92.0-rc.8",
37
+ "@akinon/pz-masterpass": "1.92.0-rc.8",
38
+ "@akinon/pz-one-click-checkout": "1.92.0-rc.8",
39
+ "@akinon/pz-otp": "1.92.0-rc.8",
40
+ "@akinon/pz-pay-on-delivery": "1.92.0-rc.8",
41
+ "@akinon/pz-saved-card": "1.92.0-rc.8",
42
+ "@akinon/pz-tabby-extension": "1.92.0-rc.8",
43
+ "@akinon/pz-tamara-extension": "1.92.0-rc.8",
43
44
  "@hookform/resolvers": "2.9.0",
44
45
  "@next/third-parties": "14.1.0",
45
46
  "@react-google-maps/api": "2.17.1",
@@ -62,7 +63,7 @@
62
63
  "yup": "0.32.11"
63
64
  },
64
65
  "devDependencies": {
65
- "@akinon/eslint-plugin-projectzero": "1.91.0",
66
+ "@akinon/eslint-plugin-projectzero": "1.92.0-rc.8",
66
67
  "@semantic-release/changelog": "6.0.2",
67
68
  "@semantic-release/exec": "6.0.3",
68
69
  "@semantic-release/git": "10.0.1",
@@ -90,7 +91,7 @@
90
91
  "jest-environment-jsdom": "29.7.0",
91
92
  "lint-staged": "13.1.0",
92
93
  "prettier": "2.6.2",
93
- "react-number-format": "5.3.4",
94
+ "react-number-format": "5.4.3",
94
95
  "sass": "1.49.9",
95
96
  "semantic-release": "19.0.5",
96
97
  "server-only": "0.0.1",
@@ -1,87 +1,14 @@
1
- 'use client';
2
-
3
- import { useEffect } from 'react';
4
- import { ROUTES } from '@theme/routes';
5
- import { useGetBasketQuery } from '@akinon/next/data/client/basket';
6
- import { pushCartView } from '@theme/utils/gtm';
7
- import { Button, LoaderSpinner, Link } from '@theme/components';
8
- import { BasketItem, Summary } from '@theme/views/basket';
9
- import { useLocalization } from '@akinon/next/hooks';
10
- import PluginModule, { Component } from '@akinon/next/components/plugin-module';
1
+ import { BasketContent } from '@theme/views/basket/basket-content';
2
+ import { getBasketData } from '@akinon/next/data/server/basket';
11
3
  import settings from '@theme/settings';
12
4
 
13
- export default function Page() {
14
- const { data: basket, isLoading, isSuccess } = useGetBasketQuery();
15
- const { t } = useLocalization();
16
- const multiBasket = settings.plugins?.multiBasket ?? false;
17
-
18
- useEffect(() => {
19
- if (isSuccess) {
20
- const products = basket.basketitem_set.map((basketItem) => ({
21
- ...basketItem.product
22
- }));
23
- pushCartView(products);
24
- }
25
- }, [basket, isSuccess]);
26
-
27
- return (
28
- <div className="max-w-screen-xl p-4 flex flex-col text-primary-800 lg:p-8 xl:flex-row xl:mx-auto">
29
- {isLoading && (
30
- <div className="flex justify-center w-full">
31
- <LoaderSpinner />
32
- </div>
33
- )}
34
- {isSuccess &&
35
- (basket && basket.basketitem_set && basket.basketitem_set.length > 0 ? (
36
- <>
37
- <div className="flex-1 xl:mr-16">
38
- <div className="flex items-center justify-between py-2 border-b border-gray-200 lg:py-3">
39
- <h2 className="text-xl lg:text-2xl font-light">
40
- {t('basket.my_cart')}
41
- </h2>
42
- <Link
43
- href={ROUTES.HOME}
44
- className="text-xs hover:text-secondary-500"
45
- >
46
- {t('basket.back_to_shopping')}
47
- </Link>
48
- </div>
49
- <ul>
50
- {multiBasket ? (
51
- <PluginModule
52
- component={Component.MultiBasket}
53
- props={{ BasketItem }}
54
- />
55
- ) : (
56
- basket.basketitem_set.map((basketItem, index) => (
57
- <BasketItem basketItem={basketItem} key={index} />
58
- ))
59
- )}
60
- </ul>
61
- </div>
62
- <Summary basket={basket} />
63
- </>
64
- ) : (
65
- <div className="flex flex-col items-center container max-w-screen-sm py-4 px-4 xs:py-6 xs:px-6 sm:py-8 sm:px-8 lg:max-w-screen-xl">
66
- <h1
67
- className="w-full text-xl font-light text-secondary text-center sm:text-2xl"
68
- data-testid="basket-empty"
69
- >
70
- {t('basket.empty.title')}
71
- </h1>
5
+ export default async function Page() {
6
+ const { basket } = await getBasketData();
72
7
 
73
- <div className="w-full text-sm text-black-800 text-center my-4 mb-2 sm:text-base">
74
- <p>{t('basket.empty.content_first')}</p>
75
- <p>{t('basket.empty.content_second')}.</p>
76
- </div>
8
+ const multiBasket: boolean =
9
+ typeof settings.plugins?.multiBasket === 'boolean'
10
+ ? settings.plugins.multiBasket
11
+ : false;
77
12
 
78
- <Link href={ROUTES.HOME} passHref>
79
- <Button className="px-10 mt-2" appearance="filled">
80
- {t('basket.empty.button')}
81
- </Button>
82
- </Link>
83
- </div>
84
- ))}
85
- </div>
86
- );
13
+ return <BasketContent initialBasket={basket} multiBasket={multiBasket} />;
87
14
  }
@@ -0,0 +1,67 @@
1
+ import { Skeleton, SkeletonWrapper } from 'components';
2
+
3
+ export default function Loading() {
4
+ return (
5
+ <div className="container mx-auto">
6
+ <div className="max-w-5xl mx-auto my-5 px-7">
7
+ <SkeletonWrapper className="md:mb-7">
8
+ <Skeleton className="w-[17.25rem] h-4 lg:w-64" />
9
+ </SkeletonWrapper>
10
+ </div>
11
+ <div className="grid max-w-5xl grid-cols-2 lg:gap-8 mx-auto px-7">
12
+ <div className="col-span-2 mb-7 md:mb-0 lg:col-span-1">
13
+ <div className="flex gap-1">
14
+ <SkeletonWrapper className="hidden md:block md:mb-7">
15
+ {Array(5)
16
+ .fill(null)
17
+ .map((_, index) => (
18
+ <Skeleton key={index} className="w-20 h-24 mb-2" />
19
+ ))}
20
+ </SkeletonWrapper>
21
+
22
+ <div className="flex-1">
23
+ <SkeletonWrapper className="md:mb-7">
24
+ <Skeleton className="w-full h-[30.375rem] md:h-[36.375rem]" />
25
+ </SkeletonWrapper>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ <div className="flex flex-col items-center col-span-2 lg:col-span-1">
30
+ <div className="w-full">
31
+ <SkeletonWrapper className="w-full md:mb-7 flex justify-center items-center">
32
+ <Skeleton className="w-96 h-16 mb-9" />
33
+ <Skeleton className="hidden w-36 h-14 mb-9 md:block" />
34
+
35
+ <div className="flex flex-col justify-center items-center mb-9">
36
+ <Skeleton className="w-36 h-4 mb-2" />
37
+ <div className="flex items-center gap-2">
38
+ {Array(3)
39
+ .fill(null)
40
+ .map((_, index) => (
41
+ <Skeleton key={index} className="w-24 h-10" />
42
+ ))}
43
+ </div>
44
+ </div>
45
+
46
+ <div className="flex flex-col justify-center items-center mb-4">
47
+ <Skeleton className="w-36 h-4 mb-2" />
48
+ <div className="flex items-center gap-2">
49
+ {Array(5)
50
+ .fill(null)
51
+ .map((_, index) => (
52
+ <Skeleton key={index} className="w-11 h-11" />
53
+ ))}
54
+ </div>
55
+ </div>
56
+
57
+ <Skeleton className="hidden w-full h-14 mb-6 md:block" />
58
+ <Skeleton className="w-40 h-10 mb-9 md:w-72" />
59
+ <Skeleton className="w-24 h-10 mb-7" />
60
+ <Skeleton className="w-full h-36" />
61
+ </SkeletonWrapper>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ </div>
66
+ );
67
+ }
@@ -1,33 +1,25 @@
1
1
  'use client';
2
2
 
3
- import { ReactNode, useState } from 'react';
3
+ import { useState } from 'react';
4
4
  import { Icon } from './icon';
5
5
  import { twMerge } from 'tailwind-merge';
6
-
7
- type AccordionProps = {
8
- isCollapse?: boolean;
9
- title?: string;
10
- subTitle?: string;
11
- icons?: string[];
12
- iconSize?: number;
13
- iconColor?: string;
14
- children?: ReactNode;
15
- className?: string;
16
- titleClassName?: string;
17
- dataTestId?: string;
18
- };
6
+ import { AccordionProps } from './types';
19
7
 
20
8
  export const Accordion = ({
21
9
  isCollapse = false,
10
+ collapseClassName,
22
11
  title,
23
12
  subTitle,
24
13
  icons = ['chevron-up', 'chevron-down'],
25
14
  iconSize = 16,
26
15
  iconColor = 'fill-[#000000]',
27
16
  children,
17
+ headerClassName,
28
18
  className,
29
19
  titleClassName,
30
- dataTestId
20
+ subTitleClassName,
21
+ dataTestId,
22
+ contentClassName
31
23
  }: AccordionProps) => {
32
24
  const [collapse, setCollapse] = useState(isCollapse);
33
25
 
@@ -39,15 +31,22 @@ export const Accordion = ({
39
31
  )}
40
32
  >
41
33
  <div
42
- className="flex items-center justify-between cursor-pointer"
34
+ className={twMerge(
35
+ 'flex items-center justify-between cursor-pointer',
36
+ headerClassName
37
+ )}
43
38
  onClick={() => setCollapse(!collapse)}
44
39
  data-testid={dataTestId}
45
40
  >
46
- <div className="flex flex-col">
41
+ <div className={twMerge('flex flex-col', contentClassName)}>
47
42
  {title && (
48
43
  <h3 className={twMerge('text-sm', titleClassName)}>{title}</h3>
49
44
  )}
50
- {subTitle && <h4 className="text-xs text-gray-700">{subTitle}</h4>}
45
+ {subTitle && (
46
+ <h4 className={twMerge('text-xs text-gray-700', subTitleClassName)}>
47
+ {subTitle}
48
+ </h4>
49
+ )}
51
50
  </div>
52
51
 
53
52
  {icons && (
@@ -58,7 +57,11 @@ export const Accordion = ({
58
57
  />
59
58
  )}
60
59
  </div>
61
- {collapse && <div className="mt-3 text-sm">{children}</div>}
60
+ {collapse && (
61
+ <div className={twMerge('mt-3 text-sm', collapseClassName)}>
62
+ {children}
63
+ </div>
64
+ )}
62
65
  </div>
63
66
  );
64
67
  };
@@ -70,6 +70,7 @@ export const CurrencySelect = (props: CurrencySelectProps) => {
70
70
  onClick={confirmModalHandleClick}
71
71
  appearance="filled"
72
72
  className="font-medium px-10 py-4 h-12"
73
+ data-testid="currency-modal-confirm"
73
74
  >
74
75
  {t('common.currency_modal.continue')}
75
76
  </Button>
@@ -1,11 +1,21 @@
1
1
  import { useState } from 'react';
2
2
  import { forwardRef } from 'react';
3
3
  import { FileInputProps } from '@theme/components/types';
4
- import clsx from 'clsx';
5
4
  import { useLocalization } from '@akinon/next/hooks';
5
+ import { twMerge } from 'tailwind-merge';
6
6
 
7
7
  export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
8
- function FileInput({ className, onChange, ...props }, ref) {
8
+ function FileInput(
9
+ {
10
+ buttonClassName,
11
+ onChange,
12
+ fileClassName,
13
+ fileNameWrapperClassName,
14
+ fileInputClassName,
15
+ ...props
16
+ },
17
+ ref
18
+ ) {
9
19
  const { t } = useLocalization();
10
20
  const [fileNames, setFileNames] = useState<string[]>([]);
11
21
 
@@ -24,24 +34,34 @@ export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
24
34
  type="file"
25
35
  {...props}
26
36
  ref={ref}
27
- className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
37
+ className={twMerge(
38
+ 'absolute inset-0 w-full h-full opacity-0 cursor-pointer',
39
+ fileInputClassName
40
+ )}
28
41
  onChange={handleFileChange}
29
42
  />
30
43
  <button
31
44
  type="button"
32
- className={clsx('bg-primary text-white py-2 px-4 text-sm', className)}
45
+ className={twMerge(
46
+ 'bg-primary text-white py-2 px-4 text-sm',
47
+ buttonClassName
48
+ )}
33
49
  >
34
50
  {t('common.file_input.select_file')}
35
51
  </button>
36
- <div className="mt-1 text-gray-500">
52
+ <div
53
+ className={twMerge('mt-1 text-gray-500', fileNameWrapperClassName)}
54
+ >
37
55
  {fileNames.length > 0 ? (
38
- <ul className="list-disc pl-4 text-xs">
56
+ <ul className={twMerge('list-disc pl-4 text-xs', fileClassName)}>
39
57
  {fileNames.map((name, index) => (
40
58
  <li key={index}>{name}</li>
41
59
  ))}
42
60
  </ul>
43
61
  ) : (
44
- <span className="text-xs">{t('common.file_input.no_file')}</span>
62
+ <span className={twMerge('text-xs', fileClassName)}>
63
+ {t('common.file_input.no_file')}
64
+ </span>
45
65
  )}
46
66
  </div>
47
67
  </div>
@@ -72,7 +72,8 @@ export const Input = forwardRef<
72
72
  hasFloatingLabel,
73
73
  'mb-2': !hasFloatingLabel,
74
74
  '-translate-y-2 bg-white inline-flex h-auto':
75
- hasFloatingLabel && (focused || hasValue)
75
+ hasFloatingLabel &&
76
+ (focused || hasValue || props.value || props.format)
76
77
  })
77
78
  )}
78
79
  >
@@ -4,16 +4,7 @@ import ReactPortal from './react-portal';
4
4
  import { Icon } from './icon';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { useEffect } from 'react';
7
-
8
- export interface ModalProps {
9
- portalId: string;
10
- children?: React.ReactNode;
11
- open?: boolean;
12
- setOpen?: (open: boolean) => void;
13
- title?: React.ReactNode;
14
- showCloseButton?: React.ReactNode;
15
- className?: string;
16
- }
7
+ import { ModalProps } from '@theme/types';
17
8
 
18
9
  export const Modal = (props: ModalProps) => {
19
10
  const {
@@ -23,7 +14,14 @@ export const Modal = (props: ModalProps) => {
23
14
  setOpen,
24
15
  title = '',
25
16
  showCloseButton = true,
26
- className
17
+ className,
18
+ overlayClassName,
19
+ headerWrapperClassName,
20
+ titleClassName,
21
+ closeButtonClassName,
22
+ iconName = 'close',
23
+ iconSize = 16,
24
+ iconClassName
27
25
  } = props;
28
26
 
29
27
  useEffect(() => {
@@ -38,7 +36,12 @@ export const Modal = (props: ModalProps) => {
38
36
 
39
37
  return (
40
38
  <ReactPortal wrapperId={portalId}>
41
- <div className="fixed top-0 left-0 w-screen h-screen bg-primary bg-opacity-60 z-50" />
39
+ <div
40
+ className={twMerge(
41
+ 'fixed top-0 left-0 w-screen h-screen bg-primary bg-opacity-60 z-50',
42
+ overlayClassName
43
+ )}
44
+ />
42
45
  <section
43
46
  className={twMerge(
44
47
  'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 bg-white',
@@ -46,15 +49,28 @@ export const Modal = (props: ModalProps) => {
46
49
  )}
47
50
  >
48
51
  {(showCloseButton || title) && (
49
- <div className="flex px-6 py-4 border-b border-gray-400">
50
- {title && <h3 className="text-lg font-light">{title}</h3>}
52
+ <div
53
+ className={twMerge(
54
+ 'flex px-6 py-4 border-b border-gray-400',
55
+ headerWrapperClassName
56
+ )}
57
+ >
58
+ {title && (
59
+ <h3 className={twMerge('text-lg font-light', titleClassName)}>
60
+ {title}
61
+ </h3>
62
+ )}
51
63
  {showCloseButton && (
52
64
  <button
53
65
  type="button"
54
66
  onClick={() => setOpen(false)}
55
- className="ml-auto"
67
+ className={twMerge('ml-auto', closeButtonClassName)}
56
68
  >
57
- <Icon name="close" size={16} />
69
+ <Icon
70
+ name={iconName}
71
+ size={iconSize}
72
+ className={iconClassName}
73
+ />
58
74
  </button>
59
75
  )}
60
76
  </div>
@@ -14,14 +14,18 @@ const Select = forwardRef<HTMLSelectElement, SelectProps>((props, ref) => {
14
14
  error,
15
15
  label,
16
16
  required = false,
17
+ labelClassName,
17
18
  ...rest
18
19
  } = props;
19
20
 
20
21
  return (
21
22
  <label
22
- className={clsx('flex flex-col relative text-xs text-gray-800', {
23
- 'pl-7': icon
24
- })}
23
+ className={twMerge(
24
+ clsx('flex flex-col relative text-xs text-gray-800', {
25
+ 'pl-7': icon
26
+ }),
27
+ labelClassName
28
+ )}
25
29
  >
26
30
  {icon && (
27
31
  <Icon
@@ -32,32 +36,40 @@ const Select = forwardRef<HTMLSelectElement, SelectProps>((props, ref) => {
32
36
  )}
33
37
 
34
38
  {label && (
35
- <span className="mb-1">
39
+ <span className={twMerge('mb-1', labelClassName)}>
36
40
  {label} {required && <span className="text-secondary">*</span>}
37
41
  </span>
38
42
  )}
39
- <select
40
- {...rest}
41
- ref={ref}
42
- className={twMerge(
43
- clsx(
44
- 'cursor-pointer truncate h-10 w-40 px-2.5 shrink-0 outline-none',
45
- !borderless &&
46
- 'border border-gray-200 transition-all duration-150 hover:border-primary'
47
- ),
48
- className
49
- )}
50
- >
51
- {options?.map((option) => (
52
- <option
53
- key={option.value}
54
- value={option.value}
55
- className={option.class}
56
- >
57
- {option.label}
58
- </option>
59
- ))}
60
- </select>
43
+ <div className="relative">
44
+ <select
45
+ {...rest}
46
+ ref={ref}
47
+ className={twMerge(
48
+ clsx(
49
+ 'cursor-pointer truncate h-10 w-40 px-2.5 shrink-0 outline-none',
50
+ !borderless &&
51
+ 'border border-gray-200 transition-all duration-150 hover:border-primary',
52
+ 'appearance-none bg-transparent'
53
+ ),
54
+ className
55
+ )}
56
+ >
57
+ {options?.map((option) => (
58
+ <option
59
+ key={option.value}
60
+ value={option.value}
61
+ className={option.class}
62
+ >
63
+ {option.label}
64
+ </option>
65
+ ))}
66
+ </select>
67
+ <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
68
+ <svg className="h-4 w-4 fill-current" viewBox="0 0 20 20">
69
+ <path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" />
70
+ </svg>
71
+ </div>
72
+ </div>
61
73
  {error && (
62
74
  <span className="mt-1 text-sm text-error">{error.message}</span>
63
75
  )}
@@ -29,7 +29,13 @@ export interface PaginationProps {
29
29
  isLoading?: boolean;
30
30
  }
31
31
 
32
- export type FileInputProps = React.HTMLProps<HTMLInputElement>;
32
+ export interface FileInputProps extends React.HTMLProps<HTMLInputElement> {
33
+ fileClassName?: string;
34
+ fileNameWrapperClassName?: string;
35
+ fileInputClassName?: string;
36
+ onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
37
+ buttonClassName?: string;
38
+ }
33
39
 
34
40
  export type RadioProps = React.HTMLProps<HTMLInputElement>;
35
41
 
@@ -58,6 +64,7 @@ export interface SelectProps extends React.HTMLProps<HTMLSelectElement> {
58
64
  iconSize?: number;
59
65
  error?: FieldError | undefined;
60
66
  required?: boolean;
67
+ labelClassName?: string;
61
68
  }
62
69
  export interface IconProps extends React.ComponentPropsWithRef<'i'> {
63
70
  name: string;
@@ -91,3 +98,20 @@ export interface BadgeProps {
91
98
  children: ReactNode;
92
99
  className?: string;
93
100
  }
101
+
102
+ export type AccordionProps = {
103
+ isCollapse?: boolean;
104
+ collapseClassName?: string;
105
+ title?: string;
106
+ subTitle?: string;
107
+ icons?: string[];
108
+ iconSize?: number;
109
+ iconColor?: string;
110
+ children?: ReactNode;
111
+ headerClassName?: string;
112
+ className?: string;
113
+ titleClassName?: string;
114
+ subTitleClassName?: string;
115
+ dataTestId?: string;
116
+ contentClassName?: string;
117
+ };
@@ -14,5 +14,6 @@ module.exports = [
14
14
  'pz-akifast',
15
15
  'pz-saved-card',
16
16
  'pz-tabby-extension',
17
- 'pz-tamara-extension'
17
+ 'pz-tamara-extension',
18
+ 'pz-hepsipay'
18
19
  ];
@@ -1,6 +1,10 @@
1
1
  const { LocaleUrlStrategy } = require('@akinon/next/localization');
2
2
  const { ROUTES } = require('@theme/routes');
3
3
 
4
+ /* IMPORTANT *
5
+ * In order to use one locale in the locales array and hide the default locale in the URL, you need to set the localeUrlStrategy to LocaleUrlStrategy.ShowAllLocales.
6
+ */
7
+
4
8
  const commerceUrl = encodeURI(process.env.SERVICE_BACKEND_URL ?? 'default');
5
9
 
6
10
  /** @type {import('@akinon/next/types').Settings} */
@@ -14,6 +18,7 @@ module.exports = {
14
18
  { translationKey: 'size', key: 'size' }
15
19
  ],
16
20
  localization: {
21
+ // If there is one locale in the locales array, the default locale will be hidden in the URL.
17
22
  locales: [
18
23
  {
19
24
  label: 'EN',
@@ -41,7 +46,7 @@ module.exports = {
41
46
  }
42
47
  ],
43
48
  defaultLocaleValue: 'en',
44
- localeUrlStrategy: LocaleUrlStrategy.HideDefaultLocale,
49
+ localeUrlStrategy: LocaleUrlStrategy.HideDefaultLocale, // If there is one locale in the locales array, the default locale will be hidden in the URL and localeUrlStrategy should be set to LocaleUrlStrategy.ShowAllLocales.
45
50
  redirectToDefaultLocale: true,
46
51
  defaultCurrencyCode: 'usd'
47
52
  },
@@ -62,5 +67,6 @@ module.exports = {
62
67
  redis: {
63
68
  defaultExpirationTime: 900 // 15 min
64
69
  },
65
- customNotFoundEnabled: false
70
+ customNotFoundEnabled: false,
71
+ commerceRedirectionIgnoreList: ['/users/reset']
66
72
  };
@@ -71,3 +71,20 @@ export interface SeoProps {
71
71
  ogPriceAmount?: string;
72
72
  ogPriceCurrency?: string;
73
73
  }
74
+
75
+ export interface ModalProps {
76
+ portalId: string;
77
+ children?: React.ReactNode;
78
+ open?: boolean;
79
+ setOpen?: (open: boolean) => void;
80
+ title?: React.ReactNode;
81
+ showCloseButton?: React.ReactNode;
82
+ className?: string;
83
+ overlayClassName?: string;
84
+ headerWrapperClassName?: string;
85
+ titleClassName?: string;
86
+ closeButtonClassName?: string;
87
+ iconName?: string;
88
+ iconSize?: number;
89
+ iconClassName?: string;
90
+ }