@akinon/next 1.1.1 → 1.3.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.
package/CHANGELOG.md CHANGED
@@ -1,10 +1,21 @@
1
1
  # @akinon/next
2
2
 
3
- ## 1.1.1
3
+ ## 1.3.0
4
4
 
5
- ### Patch Changes
5
+ ### Minor Changes
6
+
7
+ - Refactor currency and locale selection
8
+ - Update TS types
9
+ - Fix 3D redirection middleware
10
+ - Refactor logging
11
+
12
+ ## 1.2.0
13
+
14
+ ### Minor Changes
6
15
 
7
- - Refactor Sentry configs
16
+ - Refactor Sentry config.
17
+ - Add localeIncludedPrettyUrlPattern option to settings.
18
+ - Refactor getRetailStoreStock mutation.
8
19
 
9
20
  ## 1.1.0
10
21
 
@@ -1,15 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { usePathname } from 'next/navigation';
4
- import { useEffect } from 'react';
5
- import { api } from '../data/client/api';
6
- import {
7
- useClearBasketMutation,
8
- useGetBasketQuery
9
- } from '../data/client/basket';
10
- import { useAppDispatch, useAppSelector } from '../redux/hooks';
11
- import { getCookie, removeCookie } from '../utils';
12
- import { useRouter } from '../hooks';
4
+ import { useAppSelector } from '../redux/hooks';
13
5
 
14
6
  export default function ClientRoot({
15
7
  children,
@@ -18,39 +10,8 @@ export default function ClientRoot({
18
10
  children: React.ReactNode;
19
11
  sessionId?: string;
20
12
  }) {
21
- const dispatch = useAppDispatch();
22
13
  const pathname = usePathname();
23
- const router = useRouter();
24
14
  const { isMobileApp } = useAppSelector((state) => state.root);
25
- const { data: basketData, isSuccess } = useGetBasketQuery();
26
- const [clearBasket] = useClearBasketMutation();
27
- const resetClientCache = getCookie('pz-reset-client-cache') === 'true';
28
- const resetBasket = getCookie('pz-reset-basket') === 'true';
29
-
30
- useEffect(() => {
31
- if (basketData?.basketitem_set.length && resetBasket) {
32
- dispatch(
33
- api.util.invalidateTags([
34
- 'Checkout',
35
- 'Product',
36
- 'Addresses',
37
- 'Favorite',
38
- 'Basket'
39
- ])
40
- );
41
-
42
- clearBasket();
43
- }
44
-
45
- removeCookie('pz-reset-basket');
46
- }, [resetBasket, isSuccess, basketData]);
47
-
48
- useEffect(() => {
49
- if (resetClientCache) {
50
- removeCookie('pz-reset-client-cache');
51
- location.reload();
52
- }
53
- }, [resetClientCache]);
54
15
 
55
16
  if (isMobileApp && pathname.includes('/orders/completed')) {
56
17
  ((window.parent || window) as any)?.ReactNativeWebView?.postMessage?.(
@@ -51,6 +51,9 @@ export default function SelectedPaymentOptionView() {
51
51
  } else if (payment_option.payment_type === 'loyalty_money') {
52
52
  promise = import(`views/checkout/steps/payment/options/loyalty`);
53
53
  }
54
+ // else if (payment_option.payment_type === 'gpay') {
55
+ // promise = import(`views/checkout/steps/payment/options/gpay`);
56
+ // }
54
57
  } catch (error) {}
55
58
 
56
59
  return promise
@@ -23,7 +23,7 @@ type GetProduct = {
23
23
  pk: number;
24
24
  searchParams?: URLSearchParams;
25
25
  groupProduct?: boolean;
26
- [key:string]: any;
26
+ [key: string]: any;
27
27
  };
28
28
 
29
29
  export const productApi = api.injectEndpoints({
@@ -34,7 +34,7 @@ export const productApi = api.injectEndpoints({
34
34
  })
35
35
  }),
36
36
  getProductByParams: build.query<ProductResult, GetProduct>({
37
- query: ({pk, searchParams, groupProduct, ...params}) => {
37
+ query: ({ pk, searchParams, groupProduct, ...params }) => {
38
38
  let url = groupProduct
39
39
  ? product.getGroupProductByPk(pk)
40
40
  : product.getProductByPk(pk);
@@ -50,11 +50,10 @@ export const productApi = api.injectEndpoints({
50
50
  }),
51
51
  getRetailStoreStock: build.mutation<StockResultType, FindInStoreFormType>({
52
52
  query: (body) => {
53
- const { productPk, store, variant } = body;
54
- const hasVariant = variant ? `&integration_beden=${variant}` : '';
53
+ const { productPk, queryString } = body;
55
54
  return {
56
55
  url: buildClientRequestUrl(
57
- product.getRetailStoreStock(productPk, store, hasVariant),
56
+ product.getRetailStoreStock(productPk, queryString),
58
57
  {
59
58
  contentType: 'application/json'
60
59
  }
package/data/urls.ts CHANGED
@@ -116,8 +116,8 @@ export const product = {
116
116
  installments: (productId: number) => `/payments/cards/product/${productId}`,
117
117
  getProductByPk: (pk: number) => `/product/${pk}`,
118
118
  getGroupProductByPk: (pk: number) => `/group-product/${pk}`,
119
- getRetailStoreStock: (productPk: string, store: string, hasVariant: string) =>
120
- `/retail_store_stock/${productPk}?city_id=${store}${hasVariant}`,
119
+ getRetailStoreStock: (productPk: string, queryString: string) =>
120
+ `/retail_store_stock/${productPk}?${queryString}`,
121
121
  addProduct: '/baskets/basket',
122
122
  slug: (slug: string) => `/${slug}`,
123
123
  categoryUrl: (pk: number) => `/products/${pk}/category_nodes/?limit=1`,
@@ -74,7 +74,10 @@ const checkRedisVariables = () => {
74
74
  process.env.CACHE_SECRET
75
75
  ];
76
76
 
77
- if (!requiredVariableValues.every((v) => v)) {
77
+ if (
78
+ !requiredVariableValues.every((v) => v) &&
79
+ process.env.NODE_ENV === 'production'
80
+ ) {
78
81
  logger.warn('Redis cache variables are not set', {
79
82
  requiredVariables: ['CACHE_HOST', 'CACHE_PORT', 'CACHE_SECRET'],
80
83
  values: requiredVariableValues
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { LocalizationContext } from '../localization/provider';
4
4
  import { useContext } from 'react';
5
- import { urlLocaleMatcherRegex } from '../utils';
5
+ import { setCookie, urlLocaleMatcherRegex } from '../utils';
6
6
  import { LocaleUrlStrategy } from '../localization';
7
7
  import { useRouter } from 'next/navigation';
8
8
 
@@ -36,7 +36,21 @@ export const useLocalization = () => {
36
36
  ''
37
37
  );
38
38
 
39
- router.push(`${localePath}${pathnameWithoutLocale}${location.search}`);
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();
40
54
  };
41
55
 
42
56
  return {
@@ -52,12 +66,13 @@ export const useLocalization = () => {
52
66
  */
53
67
  t: (path: string) => translate(path),
54
68
  setLocale,
69
+ setCurrency,
55
70
  locale,
56
71
  currency,
57
72
  locales,
58
73
  currencies,
59
74
  defaultLocaleValue,
60
75
  defaultCurrencyCode,
61
- localeUrlStrategy,
76
+ localeUrlStrategy
62
77
  };
63
78
  };
package/lib/cache.ts CHANGED
@@ -140,7 +140,7 @@ export class Cache {
140
140
  }
141
141
  }
142
142
 
143
- logger.info('Redis cache miss. Setting new value...', { key });
143
+ logger.debug('Redis cache miss. Setting new value...', { key });
144
144
 
145
145
  const data = await handler();
146
146
 
@@ -1,8 +1,20 @@
1
1
  import { NextFetchEvent, NextMiddleware } from 'next/server';
2
- import { ROUTES } from 'routes';
3
2
  import settings from 'settings';
4
3
  import { PzNextRequest } from '.';
5
4
  import logger from '../utils/log';
5
+ import { basket } from '../data/urls';
6
+
7
+ const resetBasket = async (req: PzNextRequest) => {
8
+ await fetch(`${settings.commerceUrl}${basket.getBasket}`, {
9
+ method: 'DELETE',
10
+ headers: {
11
+ Cookie: req.headers.get('cookie') || '',
12
+ 'Content-Type': 'application/json',
13
+ 'X-CSRFToken': req.cookies.get('csrftoken')?.value ?? '',
14
+ Referer: settings.commerceUrl
15
+ }
16
+ });
17
+ };
6
18
 
7
19
  const withCurrency =
8
20
  (middleware: NextMiddleware) =>
@@ -34,6 +46,10 @@ const withCurrency =
34
46
  defaultCurrencyCode
35
47
  });
36
48
 
49
+ if (req.cookies.get('pz-set-currency')) {
50
+ activeCurrency = req.cookies.get('pz-set-currency')?.value;
51
+ }
52
+
37
53
  if (
38
54
  !activeCurrency ||
39
55
  !currencies.find((c) => c.code === activeCurrency)
@@ -44,6 +60,10 @@ const withCurrency =
44
60
  activeCurrency = defaultCurrencyCode;
45
61
  }
46
62
 
63
+ if (req.cookies.get('pz-currency')?.value !== activeCurrency) {
64
+ resetBasket(req);
65
+ }
66
+
47
67
  req.middlewareParams.rewrites.currency = activeCurrency;
48
68
  } catch (error) {
49
69
  logger.error('withCurrency error', error);
@@ -154,18 +154,6 @@ const withPzDefault =
154
154
  secure: true
155
155
  });
156
156
 
157
- if (
158
- req.cookies.get('pz-currency') &&
159
- req.cookies.get('pz-currency').value !== currency
160
- ) {
161
- logger.debug('Currency changed', {
162
- currency,
163
- oldCurrency: req.cookies.get('pz-currency')?.value
164
- });
165
-
166
- middlewareResult.cookies.set('pz-reset-basket', 'true');
167
- }
168
-
169
157
  if (
170
158
  req.cookies.get('pz-locale') &&
171
159
  req.cookies.get('pz-locale').value !== locale
@@ -174,11 +162,6 @@ const withPzDefault =
174
162
  locale,
175
163
  oldLocale: req.cookies.get('pz-locale')?.value
176
164
  });
177
-
178
- middlewareResult.cookies.set(
179
- 'pz-reset-client-cache',
180
- 'true'
181
- );
182
165
  }
183
166
 
184
167
  middlewareResult.headers.set(
@@ -186,6 +169,10 @@ const withPzDefault =
186
169
  req.nextUrl.toString()
187
170
  );
188
171
 
172
+ if (req.cookies.get('pz-set-currency')) {
173
+ middlewareResult.cookies.delete('pz-set-currency');
174
+ }
175
+
189
176
  if (process.env.ACC_APP_VERSION) {
190
177
  middlewareResult.headers.set(
191
178
  'acc-app-version',
@@ -76,7 +76,13 @@ const withPrettyUrl =
76
76
  return middleware(req, event);
77
77
  }
78
78
 
79
- const prettyUrlResult = await resolvePrettyUrl(prettyUrlPathname);
79
+ const prettyUrlResult = await resolvePrettyUrl(
80
+ Settings.localization.localeIncludedPrettyUrlPattern?.test(
81
+ prettyUrlPathname
82
+ )
83
+ ? url.pathname
84
+ : prettyUrlPathname
85
+ );
80
86
 
81
87
  if (prettyUrlResult.matched) {
82
88
  req.middlewareParams.rewrites.prettyUrl = prettyUrlResult.path;
@@ -38,25 +38,6 @@ const withThreeDRedirection =
38
38
  }
39
39
 
40
40
  const body = await streamToString(req.body);
41
- const params = body.split('&');
42
- const encodedPzParams = decodeURIComponent(
43
- params.find((param) => param.startsWith('pzparams'))?.split('=')[1] ?? ''
44
- );
45
-
46
- logger.debug('Encoded 3D form extra params', encodedPzParams);
47
-
48
- if (!encodedPzParams.length) {
49
- logger.warn('No pzparams found in 3D form params');
50
- return middleware(req, event);
51
- }
52
-
53
- const pzParams = JSON.parse(decodeURIComponent(encodedPzParams)) as {
54
- session: string;
55
- locale: string;
56
- };
57
-
58
- logger.debug('3D form extra params', pzParams);
59
-
60
41
  const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
61
42
 
62
43
  const request = await fetch(requestUrl, {
@@ -64,7 +45,7 @@ const withThreeDRedirection =
64
45
  headers: {
65
46
  'X-Requested-With': 'XMLHttpRequest',
66
47
  'Content-Type': 'application/x-www-form-urlencoded',
67
- Cookie: `osessionid=${pzParams.session}`
48
+ Cookie: `osessionid=${req.cookies.get('osessionid')?.value ?? ''}`
68
49
  },
69
50
  body
70
51
  });
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": "1.1.1",
4
+ "version": "1.3.0",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
package/plugins.js CHANGED
@@ -4,4 +4,5 @@ module.exports = [
4
4
  'pz-one-click-checkout',
5
5
  'pz-pay-on-delivery',
6
6
  'pz-checkout-gift-pack',
7
+ 'pz-gpay'
7
8
  ];
@@ -42,18 +42,14 @@ export type AccountChangePasswordFormType = {
42
42
  };
43
43
 
44
44
  export type AccountProfileFormType = {
45
+ date_of_birth: string;
46
+ email_allowed: boolean;
45
47
  first_name: string;
48
+ gender: string;
46
49
  last_name: string;
47
50
  phone: string;
48
- email_allowed: boolean;
49
51
  sms_allowed: boolean;
50
- gender: string;
51
- email: string;
52
- birthdate_day: string;
53
- birthdate_month: string;
54
- birthdate_year: string;
55
- country_code: string;
56
- date_of_birth: string;
52
+ [key: string]: any;
57
53
  };
58
54
 
59
55
  export type ContactFormType = {
@@ -83,9 +83,8 @@ export type StockResultType = [
83
83
  ];
84
84
 
85
85
  export type FindInStoreFormType = {
86
- store: string;
87
- variant: string;
88
86
  productPk: string;
87
+ queryString: string;
89
88
  };
90
89
 
91
90
  export interface ProductCategoryResult {
package/types/index.ts CHANGED
@@ -148,6 +148,20 @@ export interface Settings {
148
148
  locale: string;
149
149
  defaultCurrencyCode: string;
150
150
  }) => string;
151
+ /**
152
+ * By default, pretty url resolver excludes locale from url.
153
+ * In some cases, you may want to create flatpages and include locale in urls.
154
+ * This is useful if you want to manage your flatpages for different countries by using locale value.
155
+ *
156
+ * @example
157
+ * // URL entered in Omnitron: /en-us/pages/about-us
158
+ * // Locale Strategy: LocaleUrlStrategy.ShowAllLocales
159
+ *
160
+ * // If you don't use this option, pretty url resolver will remove the locale and it will be resolved as '/pages/about-us' and you will get 404. Because there is no page with this url. But if you use this option, it will be resolved as '/en-us/pages/about-us' and you will get the page.
161
+ * // Following pattern will include locale for all urls including '/pages/'.
162
+ * localeIncludedPrettyUrlPattern: new RegExp('.+/pages/.+$')
163
+ */
164
+ localeIncludedPrettyUrlPattern?: RegExp;
151
165
  };
152
166
  rewrites?: Array<{
153
167
  source: string;
package/utils/index.ts CHANGED
@@ -35,6 +35,9 @@ export function removeCookie(name: string) {
35
35
  document.cookie = name + '=' + '; expires=' + date + '; path=/';
36
36
  }
37
37
 
38
+ /**
39
+ * @deprecated Use setCurrency method in useLocalization hook instead.
40
+ */
38
41
  export function setCurrency(currency: string) {
39
42
  if (getCookie('pz-currency') !== currency) {
40
43
  setCookie('pz-reset-basket', 'true');
package/utils/log.ts CHANGED
@@ -1,5 +1,3 @@
1
- import * as Sentry from '@sentry/nextjs';
2
-
3
1
  enum LogLevel {
4
2
  TRACE = 'trace',
5
3
  DEBUG = 'debug',
@@ -94,15 +92,6 @@ const error: LoggerFn = (message, payload) => {
94
92
  message,
95
93
  payload
96
94
  });
97
-
98
- Sentry.withScope(function (scope) {
99
- scope.setLevel('error');
100
-
101
- Sentry.captureException({
102
- message,
103
- extra: payload
104
- });
105
- });
106
95
  };
107
96
 
108
97
  const warn: LoggerFn = (message, payload) => {
@@ -111,15 +100,6 @@ const warn: LoggerFn = (message, payload) => {
111
100
  message,
112
101
  payload
113
102
  });
114
-
115
- Sentry.withScope(function (scope) {
116
- scope.setLevel('warning');
117
-
118
- Sentry.captureEvent({
119
- message,
120
- extra: payload
121
- });
122
- });
123
103
  };
124
104
 
125
105
  const debug: LoggerFn = (message, payload) => {