@akinon/projectzero 1.78.0-rc.2 → 1.78.0

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 (27) hide show
  1. package/CHANGELOG.md +1 -15
  2. package/app-template/.gitignore +0 -2
  3. package/app-template/CHANGELOG.md +166 -2734
  4. package/app-template/package.json +18 -18
  5. package/app-template/public/locales/en/common.json +0 -4
  6. package/app-template/public/locales/tr/common.json +0 -4
  7. package/app-template/sentry.edge.config.ts +3 -0
  8. package/app-template/sentry.server.config.ts +3 -0
  9. package/app-template/src/app/[commerce]/[locale]/[currency]/account/orders/[id]/cancellation/page.tsx +5 -94
  10. package/app-template/src/app/[commerce]/[locale]/[currency]/basket/page.tsx +82 -9
  11. package/app-template/src/app/[commerce]/[locale]/[currency]/orders/checkout/page.tsx +4 -7
  12. package/app-template/src/app/[commerce]/[locale]/[currency]/page.tsx +0 -8
  13. package/app-template/src/components/button.tsx +35 -50
  14. package/app-template/src/components/file-input.tsx +2 -44
  15. package/app-template/src/components/types/index.ts +1 -4
  16. package/app-template/src/middleware.ts +0 -1
  17. package/app-template/src/settings.js +1 -6
  18. package/app-template/src/views/account/address-form.tsx +2 -2
  19. package/app-template/src/views/account/contact-form.tsx +8 -3
  20. package/app-template/src/views/account/orders/order-cancellation-item.tsx +3 -4
  21. package/app-template/src/views/basket/basket-item.tsx +13 -16
  22. package/app-template/src/views/basket/summary.tsx +7 -10
  23. package/app-template/src/views/login/index.tsx +4 -28
  24. package/app-template/src/views/register/index.tsx +5 -30
  25. package/package.json +1 -1
  26. package/app-template/src/components/widget/widget-placeholder.tsx +0 -12
  27. package/app-template/src/views/basket/basket-content.tsx +0 -106
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projectzeronext",
3
- "version": "1.78.0-rc.2",
3
+ "version": "1.78.0",
4
4
  "private": true,
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -22,25 +22,25 @@
22
22
  "prestart": "pz-prestart"
23
23
  },
24
24
  "dependencies": {
25
- "@akinon/next": "1.78.0-rc.2",
26
- "@akinon/pz-akifast": "1.78.0-rc.2",
27
- "@akinon/pz-b2b": "1.78.0-rc.2",
28
- "@akinon/pz-basket-gift-pack": "1.78.0-rc.2",
29
- "@akinon/pz-bkm": "1.78.0-rc.2",
30
- "@akinon/pz-checkout-gift-pack": "1.78.0-rc.2",
31
- "@akinon/pz-click-collect": "1.78.0-rc.2",
32
- "@akinon/pz-credit-payment": "1.78.0-rc.2",
33
- "@akinon/pz-gpay": "1.78.0-rc.2",
34
- "@akinon/pz-masterpass": "1.78.0-rc.2",
35
- "@akinon/pz-one-click-checkout": "1.78.0-rc.2",
36
- "@akinon/pz-otp": "1.78.0-rc.2",
37
- "@akinon/pz-pay-on-delivery": "1.78.0-rc.2",
38
- "@akinon/pz-saved-card": "1.78.0-rc.2",
39
- "@akinon/pz-tabby-extension": "1.78.0-rc.2",
25
+ "@akinon/next": "1.78.0",
26
+ "@akinon/pz-akifast": "1.78.0",
27
+ "@akinon/pz-b2b": "1.78.0",
28
+ "@akinon/pz-basket-gift-pack": "1.78.0",
29
+ "@akinon/pz-bkm": "1.78.0",
30
+ "@akinon/pz-checkout-gift-pack": "1.78.0",
31
+ "@akinon/pz-click-collect": "1.78.0",
32
+ "@akinon/pz-credit-payment": "1.78.0",
33
+ "@akinon/pz-gpay": "1.78.0",
34
+ "@akinon/pz-masterpass": "1.78.0",
35
+ "@akinon/pz-one-click-checkout": "1.78.0",
36
+ "@akinon/pz-otp": "1.78.0",
37
+ "@akinon/pz-pay-on-delivery": "1.78.0",
38
+ "@akinon/pz-saved-card": "1.78.0",
39
+ "@akinon/pz-tabby-extension": "1.78.0",
40
40
  "@hookform/resolvers": "2.9.0",
41
41
  "@next/third-parties": "14.1.0",
42
42
  "@react-google-maps/api": "2.17.1",
43
- "@sentry/nextjs": "8.35.0",
43
+ "@sentry/nextjs": "7.116.0",
44
44
  "dayjs": "1.11.5",
45
45
  "lossless-json": "2.0.5",
46
46
  "next": "14.2.5",
@@ -61,7 +61,7 @@
61
61
  "yup": "0.32.11"
62
62
  },
63
63
  "devDependencies": {
64
- "@akinon/eslint-plugin-projectzero": "1.78.0-rc.2",
64
+ "@akinon/eslint-plugin-projectzero": "1.78.0",
65
65
  "@semantic-release/changelog": "6.0.2",
66
66
  "@semantic-release/exec": "6.0.3",
67
67
  "@semantic-release/git": "10.0.1",
@@ -61,9 +61,5 @@
61
61
  "description": "The products in your cart will be deleted because the exchange rate has changed.",
62
62
  "close": "Close",
63
63
  "continue": "Continue"
64
- },
65
- "file_input": {
66
- "select_file": "Select File",
67
- "no_file": "No file selected"
68
64
  }
69
65
  }
@@ -61,9 +61,5 @@
61
61
  "description": "Döviz kuru değiştiği için sepetinizdeki ürünler silinecektir.",
62
62
  "close": "Kapat",
63
63
  "continue": "Devam Et"
64
- },
65
- "file_input": {
66
- "select_file": "Dosya Seç",
67
- "no_file": "Dosya seçilmedi"
68
64
  }
69
65
  }
@@ -0,0 +1,3 @@
1
+ import { initSentry } from '@akinon/next/sentry';
2
+
3
+ initSentry('Edge');
@@ -0,0 +1,3 @@
1
+ import { initSentry } from '@akinon/next/sentry';
2
+
3
+ initSentry('Server');
@@ -8,15 +8,14 @@ import {
8
8
  useGetOrderQuery,
9
9
  useGetCancellationReasonsQuery
10
10
  } from '@akinon/next/data/client/account';
11
- import type { AccountOrderCancellation } from '@akinon/next/types';
11
+ import { AccountOrderCancellation } from '@akinon/next/types';
12
12
  import {
13
13
  Button,
14
14
  Checkbox,
15
15
  Select,
16
16
  Modal,
17
17
  LoaderSpinner,
18
- Link,
19
- FileInput
18
+ Link
20
19
  } from '@theme/components';
21
20
  import { useState } from 'react';
22
21
  import { OrderDetailHeader } from '@theme/views/account/orders/order-detail-header';
@@ -40,7 +39,6 @@ const AccountOrderCancellation = ({ params }) => {
40
39
  } = useForm<AccountOrderCancellation>({
41
40
  resolver: yupResolver(accountOrderCancellationSchema)
42
41
  });
43
-
44
42
  const { data: cancellationReasons, isSuccess: cancellationReasonsSuccess } =
45
43
  useGetCancellationReasonsQuery();
46
44
 
@@ -58,9 +56,6 @@ const AccountOrderCancellation = ({ params }) => {
58
56
  const watchAllFields = watch();
59
57
  const cancelItemsLength = watchAllFields?.cancel_order_items?.length;
60
58
  const [cancelOrder] = useCancelOrderMutation();
61
- const [files, setFiles] = useState<
62
- { itemId: string; image: string; description: string }[]
63
- >([]);
64
59
 
65
60
  const modalHandleClick = () => {
66
61
  setIsModalOpen(false);
@@ -117,68 +112,8 @@ const AccountOrderCancellation = ({ params }) => {
117
112
  ]);
118
113
  };
119
114
 
120
- const handleFileChange = async (
121
- e: React.ChangeEvent<HTMLInputElement>,
122
- itemId: string,
123
- description: string
124
- ) => {
125
- const selectedFiles = Array.from(e.target.files || []);
126
-
127
- const base64Files = await Promise.all(
128
- selectedFiles.map((file) => {
129
- return new Promise<string>((resolve, reject) => {
130
- const reader = new FileReader();
131
- reader.onload = () => resolve(reader.result as string);
132
- reader.onerror = reject;
133
- reader.readAsDataURL(file);
134
- });
135
- })
136
- );
137
-
138
- const validFiles = base64Files.filter((file) =>
139
- /^data:image\/(jpeg|png|jpg);base64,.+/.test(file)
140
- );
141
-
142
- const formattedFiles = validFiles.map((file) => ({
143
- itemId,
144
- image: file,
145
- description
146
- }));
147
-
148
- setFiles((prevFiles) => [
149
- ...prevFiles.filter((f) => f.itemId !== itemId),
150
- ...formattedFiles
151
- ]);
152
- };
153
-
154
- const fileInputCondition = (item, description: string) => {
155
- if (item.is_refundable && !item.active_cancellation_request) {
156
- return (
157
- <FileInput
158
- name="files"
159
- title="files"
160
- multiple
161
- onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
162
- handleFileChange(e, item.id, description)
163
- }
164
- />
165
- );
166
- }
167
- };
168
-
169
115
  const onSubmit: SubmitHandler<AccountOrderCancellation> = (orderItems) => {
170
- const mergedData = {
171
- ...orderItems,
172
- cancel_order_items: orderItems.cancel_order_items.map((orderItem) => ({
173
- ...orderItem,
174
- ...(files.length > 0 && {
175
- cancellation_request_image_set: files.filter(
176
- (file) => file.itemId === orderItem.order_item
177
- )
178
- })
179
- }))
180
- };
181
- cancelOrder({ id: order.number, ...mergedData })
116
+ cancelOrder({ id: order.number, ...orderItems })
182
117
  .unwrap()
183
118
  .then(() => {
184
119
  setResponseMessage({
@@ -187,33 +122,10 @@ const AccountOrderCancellation = ({ params }) => {
187
122
  });
188
123
  setIsModalOpen(true);
189
124
  })
190
- .catch((err) => {
191
- console.error('Err', err);
192
-
193
- const errorMessages = new Set();
194
-
195
- if (err?.data?.cancel_order_items) {
196
- err.data.cancel_order_items.forEach((item) => {
197
- if (item.cancellation_request_image_set) {
198
- item.cancellation_request_image_set.forEach((error) => {
199
- if (typeof error === 'string') {
200
- errorMessages.add(error);
201
- } else if (typeof error === 'object' && error?.image) {
202
- error.image.forEach((msg) => errorMessages.add(msg));
203
- }
204
- });
205
- }
206
- });
207
- }
208
-
209
- const errorContent =
210
- errorMessages.size > 0
211
- ? Array.from(errorMessages).join('\n')
212
- : t('account.my_orders.return.error.description').toString();
213
-
125
+ .catch(() => {
214
126
  setResponseMessage({
215
127
  title: t('account.my_orders.return.error.title').toString(),
216
- content: errorContent
128
+ content: t('account.my_orders.return.error.description').toString()
217
129
  });
218
130
  setIsModalOpen(true);
219
131
  });
@@ -268,7 +180,6 @@ const AccountOrderCancellation = ({ params }) => {
268
180
  onChange={onChange}
269
181
  value={value}
270
182
  selectOption={selectOption}
271
- fileInput={fileInputCondition(item, item.product.name)}
272
183
  />
273
184
  );
274
185
  }}
@@ -1,14 +1,87 @@
1
- import { BasketContent } from '@theme/views/basket/basket-content';
2
- import { getBasketData } from '@akinon/next/data/server/basket';
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';
3
11
  import settings from '@theme/settings';
4
12
 
5
- export default async function Page() {
6
- const { basket } = await getBasketData();
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>
7
72
 
8
- const multiBasket: boolean =
9
- typeof settings.plugins?.multiBasket === 'boolean'
10
- ? settings.plugins.multiBasket
11
- : false;
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>
12
77
 
13
- return <BasketContent initialBasket={basket} multiBasket={multiBasket} />;
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
+ );
14
87
  }
@@ -11,7 +11,7 @@ import {
11
11
  } from '@akinon/next/redux/reducers/checkout';
12
12
  import { RootState } from '@theme/redux/store';
13
13
  import { ROUTES } from '@theme/routes';
14
- import { useFetchCheckoutQuery, useResetCheckoutStateQuery } from '@akinon/next/data/client/checkout';
14
+ import { useFetchCheckoutQuery } from '@akinon/next/data/client/checkout';
15
15
  import { Button, LoaderSpinner } from '@theme/components';
16
16
  import { pushAddPaymentInfo, pushAddShippingInfo } from '@theme/utils/gtm';
17
17
  import { CheckoutStep } from '@akinon/next/types';
@@ -25,8 +25,6 @@ const Checkout = () => {
25
25
  (state: RootState) => state.checkout
26
26
  );
27
27
 
28
- const { data: indexData, isLoading: isResetStateLoading } = useResetCheckoutStateQuery(null);
29
-
30
28
  const {
31
29
  data: checkoutData,
32
30
  isFetching,
@@ -34,8 +32,7 @@ const Checkout = () => {
34
32
  isSuccess,
35
33
  refetch: refetchCheckout
36
34
  } = useFetchCheckoutQuery(null, {
37
- refetchOnMountOrArgChange: true,
38
- skip: isResetStateLoading || !indexData
35
+ refetchOnMountOrArgChange: true
39
36
  });
40
37
  const initialStepChanged = useRef<boolean>(false);
41
38
  const router = useRouter();
@@ -97,10 +94,10 @@ const Checkout = () => {
97
94
  );
98
95
  }
99
96
 
100
- if (isResetStateLoading || isFetching || isError) {
97
+ if (isFetching || isError) {
101
98
  return (
102
99
  <div className="flex flex-col items-center justify-center h-80">
103
- {isResetStateLoading || isFetching ? (
100
+ {isFetching ? (
104
101
  <LoaderSpinner />
105
102
  ) : (
106
103
  <>
@@ -4,7 +4,6 @@ import { HOME_WIDGETS } from '@theme/widgets';
4
4
  import { getWidgetData } from '@akinon/next/data/server';
5
5
  import { withSegmentDefaults } from '@akinon/next/hocs/server';
6
6
  import LazyComponent from '@akinon/next/components/lazy-component';
7
- import WidgetPlaceholder from '@theme/components/widget/widget-placeholder';
8
7
 
9
8
  type HomeWidgetOrderType = {
10
9
  widget_order: Array<{
@@ -17,13 +16,6 @@ export const dynamic = 'force-static';
17
16
  export const revalidate = 600;
18
17
 
19
18
  async function Page() {
20
- return (
21
- <>
22
- <WidgetPlaceholder slug="home-widget-order" />
23
- <WidgetPlaceholder slug="home-widget-order-2" />
24
- </>
25
- );
26
-
27
19
  const data = await getWidgetData<HomeWidgetOrderType>({
28
20
  slug: 'home-widget-order'
29
21
  });
@@ -1,61 +1,46 @@
1
1
  'use client';
2
2
 
3
- import { Link } from '@theme/components';
4
3
  import { ButtonProps } from '@theme/components/types';
5
4
  import clsx from 'clsx';
6
5
  import { twMerge } from 'tailwind-merge';
7
6
 
8
7
  export const Button = (props: ButtonProps) => {
9
- const {
10
- appearance = 'filled',
11
- size = 'md',
12
- href,
13
- target,
14
- children,
15
- className,
16
- ...rest
17
- } = props;
18
-
19
- const variants = {
20
- filled:
21
- 'bg-primary text-primary-foreground border border-primary hover:bg-white hover:border-primary hover:text-primary',
22
- outlined:
23
- 'bg-transparent text-primary hover:bg-primary hover:text-primary-foreground',
24
- ghost:
25
- 'bg-transparent border-transparent text-primary hover:bg-primary hover:text-primary-foreground',
26
- link: 'px-0 h-auto underline underline-offset-2'
27
- };
28
-
29
- const sizes = {
30
- sm: 'h-8',
31
- md: 'h-10',
32
- lg: 'h-12',
33
- xl: 'h-14'
34
- };
35
-
36
- const buttonClasses = twMerge(
37
- clsx(
38
- 'px-4 text-xs transition-all duration-200',
39
- 'inline-flex gap-2 justify-center items-center',
40
- variants[appearance],
41
- sizes[size],
42
- className
43
- ),
44
- className
45
- );
46
-
47
- return props.href ? (
48
- <Link
49
- prefetch={false}
50
- target={target}
51
- href={href}
52
- className={buttonClasses}
8
+ return (
9
+ <button
10
+ {...props}
11
+ className={twMerge(
12
+ clsx(
13
+ [
14
+ 'px-4',
15
+ 'h-10',
16
+ 'text-xs',
17
+ 'bg-primary',
18
+ 'text-primary-foreground',
19
+ 'border',
20
+ 'border-primary',
21
+ 'transition-all',
22
+ 'hover:bg-white',
23
+ 'hover:border-primary',
24
+ 'hover:text-primary'
25
+ ],
26
+ props.appearance === 'outlined' && [
27
+ 'bg-transparent ',
28
+ 'text-primary ',
29
+ 'hover:bg-primary ',
30
+ 'hover:text-primary-foreground'
31
+ ],
32
+ props.appearance === 'ghost' && [
33
+ 'bg-transparent',
34
+ 'border-transparent',
35
+ 'text-primary',
36
+ 'hover:bg-primary',
37
+ 'hover:text-primary-foreground'
38
+ ]
39
+ ),
40
+ props.className
41
+ )}
53
42
  >
54
- {children}
55
- </Link>
56
- ) : (
57
- <button {...rest} className={buttonClasses}>
58
- {children}
43
+ {props.children}
59
44
  </button>
60
45
  );
61
46
  };
@@ -1,50 +1,8 @@
1
- import { useState } from 'react';
2
1
  import { forwardRef } from 'react';
3
2
  import { FileInputProps } from '@theme/components/types';
4
- import clsx from 'clsx';
5
- import { useLocalization } from '@akinon/next/hooks';
6
3
 
7
4
  export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
8
- function FileInput({ className, onChange, ...props }, ref) {
9
- const { t } = useLocalization();
10
- const [fileNames, setFileNames] = useState<string[]>([]);
11
-
12
- const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
13
- const files = Array.from(event.target.files || []);
14
- setFileNames(files.map((file) => file.name));
15
-
16
- if (onChange) {
17
- onChange(event);
18
- }
19
- };
20
-
21
- return (
22
- <div className="relative">
23
- <input
24
- type="file"
25
- {...props}
26
- ref={ref}
27
- className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
28
- onChange={handleFileChange}
29
- />
30
- <button
31
- type="button"
32
- className={clsx('bg-primary text-white py-2 px-4 text-sm', className)}
33
- >
34
- {t('common.file_input.select_file')}
35
- </button>
36
- <div className="mt-1 text-gray-500">
37
- {fileNames.length > 0 ? (
38
- <ul className="list-disc pl-4 text-xs">
39
- {fileNames.map((name, index) => (
40
- <li key={index}>{name}</li>
41
- ))}
42
- </ul>
43
- ) : (
44
- <span className="text-xs">{t('common.file_input.no_file')}</span>
45
- )}
46
- </div>
47
- </div>
48
- );
5
+ function fileInput(props, ref) {
6
+ return <input type="file" {...props} ref={ref} />;
49
7
  }
50
8
  );
@@ -4,10 +4,7 @@ import { UsePaginationType } from '@akinon/next/hooks/use-pagination';
4
4
 
5
5
  export interface ButtonProps
6
6
  extends React.ButtonHTMLAttributes<HTMLButtonElement> {
7
- appearance?: 'filled' | 'outlined' | 'ghost' | 'link' | string;
8
- size?: 'sm' | 'md' | 'lg' | 'xl';
9
- href?: string;
10
- target?: '_blank' | '_self' | '_parent' | '_top';
7
+ appearance?: 'filled' | 'outlined' | 'ghost';
11
8
  }
12
9
 
13
10
  export interface PaginationProps {
@@ -9,7 +9,6 @@ import { NextMiddleware, NextResponse } from 'next/server';
9
9
  */
10
10
 
11
11
  export const config = {
12
- // For .xml.gz type sitemap urls, update '/(.*sitemap\\.xml)' with this regex '/(.*sitemap\\.xml|sitemap/.*.xml(?:.gz)?)/',
13
12
  matcher: [
14
13
  '/((?!api|_next|[\\w-\\/*]+\\.\\w+).*)',
15
14
  '/(.*sitemap\\.xml)',
@@ -1,10 +1,6 @@
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
-
8
4
  const commerceUrl = encodeURI(process.env.SERVICE_BACKEND_URL ?? 'default');
9
5
 
10
6
  /** @type {import('@akinon/next/types').Settings} */
@@ -18,7 +14,6 @@ module.exports = {
18
14
  { translationKey: 'size', key: 'size' }
19
15
  ],
20
16
  localization: {
21
- // If there is one locale in the locales array, the default locale will be hidden in the URL.
22
17
  locales: [
23
18
  {
24
19
  label: 'EN',
@@ -46,7 +41,7 @@ module.exports = {
46
41
  }
47
42
  ],
48
43
  defaultLocaleValue: 'en',
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.
44
+ localeUrlStrategy: LocaleUrlStrategy.HideDefaultLocale,
50
45
  redirectToDefaultLocale: true,
51
46
  defaultCurrencyCode: 'usd'
52
47
  },
@@ -247,7 +247,7 @@ export const AddressForm = (props: Props) => {
247
247
  />
248
248
  <Input
249
249
  label={t('account.address_book.form.phone.placeholder')}
250
- format={config.user_phone_format.replaceAll(/9/g, '#')}
250
+ format={config.user_phone_format.replaceAll(/\9/g, '#')}
251
251
  mask="_"
252
252
  allowEmptyFormatting={true}
253
253
  control={control}
@@ -339,7 +339,7 @@ export const AddressForm = (props: Props) => {
339
339
  error={errors.postcode}
340
340
  data-testid="address-form-post-code"
341
341
  required
342
- format={config.user_post_code_format.replaceAll(/9/g, '#')}
342
+ format={config.user_post_code_format.replaceAll(/\9/g, '#')}
343
343
  control={control}
344
344
  mask="_"
345
345
  allowEmptyFormatting
@@ -192,7 +192,7 @@ const ContactForm = () => {
192
192
  label={t('account.contact.form.phone.placeholder')}
193
193
  type="tel"
194
194
  className="mb-1"
195
- format={user_phone_format.replace(/9/g, '#')}
195
+ format={user_phone_format.replace(/\9/g, '#')}
196
196
  mask="_"
197
197
  allowEmptyFormatting={true}
198
198
  control={control}
@@ -255,8 +255,13 @@ const ContactForm = () => {
255
255
  <label className="text-xs text-gray-800 mb-2 block">
256
256
  {t('account.contact.form.file.title')}
257
257
  </label>
258
- <FileInput name="file" title="file" {...register('file')} />
259
- <Button type="submit" className="w-full font-medium mt-4">
258
+ <FileInput
259
+ name="file"
260
+ title="file"
261
+ className="w-full mb-5"
262
+ {...register('file')}
263
+ />
264
+ <Button type="submit" className="w-full font-medium">
260
265
  {t('account.contact.form.submit_button')}
261
266
  </Button>
262
267
  </form>