@akinon/next 2.0.0-beta.5 → 2.0.0-beta.7

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 2.0.0-beta.7
4
+
5
+ ## 2.0.0-beta.6
6
+
7
+ ### Minor Changes
8
+
9
+ - 8f05f9b: ZERO-3250: Beta branch synchronized with Main branch
10
+
3
11
  ## 2.0.0-beta.5
4
12
 
5
13
  ### Minor Changes
package/api/auth.ts CHANGED
@@ -92,6 +92,8 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
92
92
  req.headers['x-app-device']?.toString() ?? ''
93
93
  );
94
94
 
95
+ headers.set('x-frontend-id', req.cookies['pz-frontend-id'] || '');
96
+
95
97
  logger.debug('Trying to login/register', {
96
98
  formType: credentials.formType,
97
99
  userIp
@@ -22,7 +22,7 @@ export const Accordion = ({
22
22
  return (
23
23
  <div
24
24
  className={twMerge(
25
- 'flex flex-col justify-center border-b pb-4 mb-4 last:border-none',
25
+ 'flex flex-col justify-center border-b border-gray-200 pb-4 mb-4 last:border-none',
26
26
  className
27
27
  )}
28
28
  >
@@ -1,46 +1,61 @@
1
1
  'use client';
2
2
 
3
- import { ButtonProps } from '../types/index';
3
+ import { ButtonProps } from '../types';
4
4
  import clsx from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
+ import { Link } from './link';
6
7
 
7
8
  export const Button = (props: ButtonProps) => {
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
- )}
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}
42
53
  >
43
- {props.children}
54
+ {children}
55
+ </Link>
56
+ ) : (
57
+ <button {...rest} className={buttonClasses}>
58
+ {children}
44
59
  </button>
45
60
  );
46
61
  };
@@ -40,7 +40,7 @@ export const Input = forwardRef<
40
40
  const inputClass = twMerge(
41
41
  clsx(
42
42
  'text-xs border px-2.5 h-10 placeholder:text-gray-600 peer',
43
- 'focus-visible:outline-none', // disable outline on focus
43
+ 'focus-visible:outline-hidden', // disable outline on focus
44
44
  error
45
45
  ? 'border-error focus:border-error'
46
46
  : 'border-gray-500 hover:border-black focus:border-black'
@@ -38,7 +38,7 @@ export const Modal = (props: ModalProps) => {
38
38
 
39
39
  return (
40
40
  <ReactPortal wrapperId={portalId}>
41
- <div className="fixed top-0 left-0 w-screen h-screen bg-primary bg-opacity-60 z-50" />
41
+ <div className="fixed top-0 left-0 w-screen h-screen bg-primary/60 z-50" />
42
42
  <section
43
43
  className={twMerge(
44
44
  'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 bg-white',
@@ -41,7 +41,7 @@ const Select = forwardRef<HTMLSelectElement, SelectProps>((props, ref) => {
41
41
  ref={ref}
42
42
  className={twMerge(
43
43
  clsx(
44
- 'cursor-pointer truncate h-10 w-40 px-2.5 shrink-0 outline-none',
44
+ 'cursor-pointer truncate h-10 w-40 px-2.5 shrink-0 outline-hidden',
45
45
  !borderless &&
46
46
  'border border-gray-200 transition-all duration-150 hover:border-primary'
47
47
  ),
@@ -72,6 +72,7 @@ export const api = createApi({
72
72
  'DraftsB2b',
73
73
  'Product',
74
74
  'Checkout',
75
+ 'PaymentOptions',
75
76
  'Favorite',
76
77
  'Addresses',
77
78
  'Profile',
@@ -2,6 +2,7 @@ import {
2
2
  setBankAccounts,
3
3
  setCardType,
4
4
  setInstallmentOptions,
5
+ setPaymentOptions,
5
6
  setPaymentStepBusy,
6
7
  setSelectedBankAccountPk,
7
8
  setSelectedCreditPaymentPk,
@@ -182,6 +183,11 @@ export const checkoutApi = api.injectEndpoints({
182
183
  }),
183
184
  providesTags: ['Checkout']
184
185
  }),
186
+ resetCheckoutState: build.query<CheckoutResponse, void>({
187
+ query: () => ({
188
+ url: buildClientRequestUrl(checkout.guestLogin, {})
189
+ })
190
+ }),
185
191
  fetchCheckoutResult: build.query<{ order: Order }, string>({
186
192
  query: (token: string) =>
187
193
  buildClientRequestUrl(checkout.fetchCheckoutResult(token))
@@ -419,6 +425,12 @@ export const checkoutApi = api.injectEndpoints({
419
425
  }
420
426
  })
421
427
  }),
428
+ fetchPaymentOptions: build.query<CheckoutResponse, void>({
429
+ query: () => ({
430
+ url: buildClientRequestUrl(checkout.setPaymentOption)
431
+ }),
432
+ providesTags: ['PaymentOptions']
433
+ }),
422
434
  setPaymentOption: build.mutation<CheckoutResponse, number>({
423
435
  query: (pk: number) => ({
424
436
  url: buildClientRequestUrl(checkout.setPaymentOption, {
@@ -467,16 +479,15 @@ export const checkoutApi = api.injectEndpoints({
467
479
  CheckoutResponse,
468
480
  {
469
481
  payment_token?: string;
482
+ [key: string]: any;
470
483
  }
471
484
  >({
472
- query: ({ payment_token }) => ({
485
+ query: (requestBody) => ({
473
486
  url: buildClientRequestUrl(checkout.setWalletPaymentPage, {
474
487
  useFormData: true
475
488
  }),
476
489
  method: 'POST',
477
- body: {
478
- payment_token
479
- }
490
+ body: requestBody
480
491
  }),
481
492
  async onQueryStarted(arg, { dispatch, queryFulfilled }) {
482
493
  dispatch(setPaymentStepBusy(true));
@@ -732,7 +743,27 @@ export const checkoutApi = api.injectEndpoints({
732
743
  body: {
733
744
  loyalty_amount_to_use: amount
734
745
  }
735
- })
746
+ }),
747
+ async onQueryStarted(arg, { dispatch, queryFulfilled }) {
748
+ dispatch(setPaymentStepBusy(true));
749
+ dispatch(setPaymentOptions([]));
750
+ await queryFulfilled;
751
+
752
+ const paymentOptionsData = await dispatch(
753
+ checkoutApi.endpoints.fetchPaymentOptions.initiate()
754
+ ).unwrap();
755
+
756
+ const paymentOptions = paymentOptionsData?.context_list?.find(
757
+ (context) => context?.page_name === 'PaymentOptionSelectionPage'
758
+ )?.page_context?.payment_options;
759
+
760
+ if (paymentOptions) {
761
+ dispatch(setPaymentOptions(paymentOptions));
762
+ }
763
+
764
+ dispatch(setPaymentStepBusy(false));
765
+ },
766
+ invalidatesTags: ['PaymentOptions']
736
767
  }),
737
768
  setOrderNote: build.mutation<CheckoutResponse, string>({
738
769
  query: (notes) => ({
@@ -835,6 +866,7 @@ export const {
835
866
  useSetAddressesMutation,
836
867
  useSetShippingOptionMutation,
837
868
  useSetDataSourceShippingOptionsMutation,
869
+ useFetchPaymentOptionsQuery,
838
870
  useSetPaymentOptionMutation,
839
871
  useSetBinNumberMutation,
840
872
  useSetInstallmentOptionMutation,
@@ -859,5 +891,6 @@ export const {
859
891
  useSetLoyaltyDataMutation,
860
892
  useSetWalletSelectionPageMutation,
861
893
  useSetWalletPaymentPageMutation,
862
- useSetWalletCompletePageMutation
894
+ useSetWalletCompletePageMutation,
895
+ useResetCheckoutStateQuery
863
896
  } = checkoutApi;
@@ -1,7 +1,7 @@
1
1
  import { api } from './api';
2
2
  import { user } from '../urls';
3
3
  import { ForgotPasswordFormType, Order } from '../../types';
4
- import { buildClientRequestUrl } from '../../utils';
4
+ import { buildClientRequestUrl, getCookie } from '../../utils';
5
5
 
6
6
  interface GetCaptchaResponse {
7
7
  siteKey: string;
@@ -64,13 +64,21 @@ const userApi = api.injectEndpoints({
64
64
  })
65
65
  }),
66
66
  forgotPassword: build.mutation<void, ForgotPasswordFormType>({
67
- query: (body) => ({
68
- url: buildClientRequestUrl(user.forgotPassword, {
69
- contentType: 'application/json'
70
- }),
71
- method: 'POST',
72
- body
73
- })
67
+ query: (body) => {
68
+ const frontendId = getCookie('pz-frontend-id');
69
+ const headers = frontendId
70
+ ? { 'x-frontend-id': frontendId }
71
+ : undefined;
72
+
73
+ return {
74
+ url: buildClientRequestUrl(user.forgotPassword, {
75
+ contentType: 'application/json'
76
+ }),
77
+ method: 'POST',
78
+ body,
79
+ headers
80
+ };
81
+ }
74
82
  }),
75
83
  otpLogin: build.mutation<void, { phone: string }>({
76
84
  query: ({ phone }) => ({
@@ -31,7 +31,7 @@ const getProductDataHandler = ({
31
31
  url +=
32
32
  '?' +
33
33
  Object.keys(searchParams)
34
- .map((key) => `${key}=${searchParams[key]}`)
34
+ .map((key) => `${key}=${encodeURIComponent(searchParams[key])}`)
35
35
  .join('&');
36
36
  }
37
37
 
@@ -60,6 +60,22 @@ const withUrlRedirection =
60
60
 
61
61
  const setCookies = request.headers.getSetCookie();
62
62
 
63
+ if (settings.commerceRedirectionIgnoreList) {
64
+ const shouldIgnoreRedirect =
65
+ settings.commerceRedirectionIgnoreList.some((ignorePath) =>
66
+ redirectUrl.pathname.startsWith(
67
+ getUrlPathWithLocale(
68
+ ignorePath,
69
+ req.middlewareParams.rewrites.locale
70
+ )
71
+ )
72
+ );
73
+
74
+ if (shouldIgnoreRedirect) {
75
+ return middleware(req, event);
76
+ }
77
+ }
78
+
63
79
  const response = NextResponse.redirect(redirectUrl.toString(), {
64
80
  status: request.status
65
81
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@akinon/next",
3
3
  "description": "Core package for Project Zero Next",
4
- "version": "2.0.0-beta.5",
4
+ "version": "2.0.0-beta.7",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -30,7 +30,7 @@
30
30
  "set-cookie-parser": "2.6.0"
31
31
  },
32
32
  "devDependencies": {
33
- "@akinon/eslint-plugin-projectzero": "2.0.0-beta.5",
33
+ "@akinon/eslint-plugin-projectzero": "2.0.0-beta.7",
34
34
  "@types/react-redux": "7.1.30",
35
35
  "@types/set-cookie-parser": "2.4.7",
36
36
  "@typescript-eslint/eslint-plugin": "8.18.2",
package/plugins.js CHANGED
@@ -14,5 +14,6 @@ module.exports = [
14
14
  'pz-multi-basket',
15
15
  'pz-saved-card',
16
16
  'pz-tabby-extension',
17
- 'pz-apple-pay'
17
+ 'pz-apple-pay',
18
+ 'pz-tamara-extension'
18
19
  ];
@@ -1,7 +1,6 @@
1
1
  import { Middleware } from '@reduxjs/toolkit';
2
2
  import { CheckoutResult, MiddlewareParams } from '../../../types';
3
3
  import { checkoutApi } from '../../../data/client/checkout';
4
- import { setPreOrder } from '../../../redux/reducers/checkout';
5
4
 
6
5
  export const setAddressMiddleware: Middleware = ({
7
6
  getState,
@@ -43,3 +42,7 @@ export const setAddressMiddleware: Middleware = ({
43
42
  return result;
44
43
  };
45
44
  };
45
+
46
+ Object.defineProperty(setAddressMiddleware, 'name', {
47
+ value: 'setAddressMiddleware'
48
+ });
@@ -38,3 +38,7 @@ export const attributeBasedShippingOptionMiddleware: Middleware = ({
38
38
  return result;
39
39
  };
40
40
  };
41
+
42
+ Object.defineProperty(attributeBasedShippingOptionMiddleware, 'name', {
43
+ value: 'attributeBasedShippingOptionMiddleware'
44
+ });
@@ -35,3 +35,7 @@ export const dataSourceShippingOptionMiddleware: Middleware = ({
35
35
  return result;
36
36
  };
37
37
  };
38
+
39
+ Object.defineProperty(dataSourceShippingOptionMiddleware, 'name', {
40
+ value: 'dataSourceShippingOptionMiddleware'
41
+ });
@@ -32,3 +32,7 @@ export const deliveryOptionMiddleware: Middleware = ({
32
32
  return result;
33
33
  };
34
34
  };
35
+
36
+ Object.defineProperty(deliveryOptionMiddleware, 'name', {
37
+ value: 'deliveryOptionMiddleware'
38
+ });
@@ -34,3 +34,7 @@ export const installmentOptionMiddleware: Middleware = ({
34
34
  return result;
35
35
  };
36
36
  };
37
+
38
+ Object.defineProperty(installmentOptionMiddleware, 'name', {
39
+ value: 'installmentOptionMiddleware'
40
+ });
@@ -26,3 +26,7 @@ export const paymentOptionMiddleware: Middleware = ({
26
26
  return result;
27
27
  };
28
28
  };
29
+
30
+ Object.defineProperty(paymentOptionMiddleware, 'name', {
31
+ value: 'paymentOptionMiddleware'
32
+ });
@@ -18,3 +18,7 @@ export const preOrderValidationMiddleware: Middleware = () => {
18
18
  return result;
19
19
  };
20
20
  };
21
+
22
+ Object.defineProperty(preOrderValidationMiddleware, 'name', {
23
+ value: 'preOrderValidationMiddleware'
24
+ });
@@ -32,3 +32,7 @@ export const redirectionMiddleware: Middleware = ({
32
32
  return result;
33
33
  };
34
34
  };
35
+
36
+ Object.defineProperty(redirectionMiddleware, 'name', {
37
+ value: 'redirectionMiddleware'
38
+ });
@@ -16,3 +16,7 @@ export const setPreOrderMiddleware: Middleware = ({
16
16
  return result;
17
17
  };
18
18
  };
19
+
20
+ Object.defineProperty(setPreOrderMiddleware, 'name', {
21
+ value: 'setPreOrderMiddleware'
22
+ });
@@ -36,3 +36,7 @@ export const shippingOptionMiddleware: Middleware = ({
36
36
  return result;
37
37
  };
38
38
  };
39
+
40
+ Object.defineProperty(shippingOptionMiddleware, 'name', {
41
+ value: 'shippingOptionMiddleware'
42
+ });
@@ -32,3 +32,7 @@ export const shippingStepMiddleware: Middleware = ({
32
32
  return result;
33
33
  };
34
34
  };
35
+
36
+ Object.defineProperty(shippingStepMiddleware, 'name', {
37
+ value: 'shippingStepMiddleware'
38
+ });
@@ -19,6 +19,10 @@ export type AccountOrderCancellation = {
19
19
  description: string;
20
20
  order_item: string;
21
21
  reason: string;
22
+ cancellation_request_image_set?: Array<{
23
+ image: string;
24
+ description: string;
25
+ }>;
22
26
  }>;
23
27
  };
24
28
 
@@ -61,5 +65,5 @@ export type ContactFormType = {
61
65
  order?: string;
62
66
  country_code?: string;
63
67
  order_needed?: boolean;
64
- file?: FileList
68
+ file?: FileList;
65
69
  };
package/types/index.ts CHANGED
@@ -202,11 +202,13 @@ export interface Settings {
202
202
  useOptimizedTranslations?: boolean;
203
203
  plugins?: Record<string, Record<string, any>>;
204
204
  includedProxyHeaders?: string[];
205
+ commerceRedirectionIgnoreList?: string[];
205
206
  /**
206
207
  * By default, the currency will be reset when the currency is changed.
207
208
  * If you want to keep the basket when the currency is changed, you can set this option to `false`.
208
209
  */
209
210
  resetBasketOnCurrencyChange?: boolean;
211
+ frontendIds?: Record<string, number>;
210
212
  }
211
213
 
212
214
  export interface CacheOptions {
@@ -274,7 +276,10 @@ export interface IconProps extends React.ComponentPropsWithRef<'i'> {
274
276
 
275
277
  export interface ButtonProps
276
278
  extends React.ButtonHTMLAttributes<HTMLButtonElement> {
277
- appearance?: 'filled' | 'outlined' | 'ghost';
279
+ appearance?: 'filled' | 'outlined' | 'ghost' | 'link' | string;
280
+ size?: 'sm' | 'md' | 'lg' | 'xl';
281
+ href?: string;
282
+ target?: '_blank' | '_self' | '_parent' | '_top';
278
283
  }
279
284
 
280
285
  export type FileInputProps = React.HTMLProps<HTMLInputElement>;
@@ -15,17 +15,11 @@ export enum MiddlewareNames {
15
15
  }
16
16
 
17
17
  export const overrideMiddleware = (
18
- middlewares: Middleware[],
19
- updates: { name: MiddlewareNames; middleware: Middleware }[]
20
- ): void => {
21
- const updatesMap = new Map(
22
- updates.map(({ name, middleware }) => [name, middleware])
23
- );
24
-
25
- middlewares.forEach((mw, index) => {
26
- const updatedMiddleware = updatesMap.get(mw.name as MiddlewareNames);
27
- if (updatedMiddleware) {
28
- middlewares[index] = updatedMiddleware;
29
- }
18
+ originalMiddlewares: Middleware[],
19
+ overrides: Record<string, Middleware>
20
+ ): Middleware[] => {
21
+ return originalMiddlewares.map((middleware) => {
22
+ const middlewareKey = middleware.name || middleware.toString();
23
+ return overrides[middlewareKey] || middleware;
30
24
  });
31
25
  };
package/with-pz-config.js CHANGED
@@ -44,8 +44,8 @@ const defaultConfig = {
44
44
  value: 'max-age=63072000; includeSubDomains; preload'
45
45
  },
46
46
  {
47
- key: 'X-Frame-Options',
48
- value: 'SAMEORIGIN'
47
+ key: 'Content-Security-Policy',
48
+ value: "frame-ancestors 'self' https://*.akifast.com akifast.com"
49
49
  }
50
50
  ]
51
51
  }