@akinon/next 1.23.0 → 1.24.0-rc.1

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,29 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.24.0-rc.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 9b10323: ZERO-2440: Add type declarations for @akinon/pz-otp modules
8
+
9
+ ## 1.24.0-rc.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 8bc6085: ZERO-2472: RTK Query Invalidate
14
+ - 02a3c58: ZERO-2460: Breadcrumb checks for undefined values
15
+ - 0181251: ZERO-2440: move otp popup state to redux
16
+ - 07cc81a: Add infinite and more types to pagination
17
+ - 8d6caba: ZERO-2434: enhance error handling and logging in appFetch function
18
+ - b4452e9: ZERO-2463: Refactor Sentry initialization and add Sentry DSN option to settings
19
+ - b2da5e4: Revert ZERO-2435
20
+
21
+ ### Patch Changes
22
+
23
+ - da1e501: ZERO-2296: Fix ROUTES import
24
+ - 2e44646: ZERO-2434: Fix category URL in getCategoryDataHandler function
25
+ - 2e9476c: ZERO-2434: remove error throwing in appFetch
26
+
3
27
  ## 1.23.0
4
28
 
5
29
  ### Minor Changes
package/api/auth.ts CHANGED
@@ -220,6 +220,17 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
220
220
  pages: {
221
221
  signIn: ROUTES.AUTH,
222
222
  error: ROUTES.AUTH
223
+ },
224
+ cookies: {
225
+ sessionToken: {
226
+ name: `__Secure-next-auth.session-token`,
227
+ options: {
228
+ httpOnly: true,
229
+ sameSite: 'none',
230
+ path: '/',
231
+ secure: true
232
+ }
233
+ }
223
234
  }
224
235
  };
225
236
  };
@@ -32,10 +32,12 @@ const addressApi = api.injectEndpoints({
32
32
  query: () => buildClientRequestUrl(address.getRetailStore)
33
33
  }),
34
34
  getRetailStoreCities: builder.query<GetResponse<any>, string>({
35
- query: (country) => buildClientRequestUrl(address.getRetailStoreCities(country))
35
+ query: (country) =>
36
+ buildClientRequestUrl(address.getRetailStoreCities(country))
36
37
  }),
37
38
  getRetailStoreTownships: builder.query<GetResponse<any>, string>({
38
- query: (city) => buildClientRequestUrl(address.getRetailStoreTownships(city))
39
+ query: (city) =>
40
+ buildClientRequestUrl(address.getRetailStoreTownships(city))
39
41
  }),
40
42
  addAddress: builder.mutation<Address, Partial<Address>>({
41
43
  query: (body) => ({
@@ -48,7 +50,7 @@ const addressApi = api.injectEndpoints({
48
50
  type: body.is_corporate === 'true' ? 'corporate' : 'personal'
49
51
  }
50
52
  }),
51
- invalidatesTags: ['Addresses', 'Checkout'] // TODO: Invalidate one of these tags when necessary (e.g. Address page invalidates Addresses tag, Checkout page invalidates Checkout tag)
53
+ invalidatesTags: (_, error) => (error ? [] : ['Addresses', 'Checkout'])
52
54
  }),
53
55
  editAddress: builder.mutation<Address, Partial<Address>>({
54
56
  query: ({ pk, ...body }) => ({
@@ -62,14 +64,14 @@ const addressApi = api.injectEndpoints({
62
64
  type: body.is_corporate === 'true' ? 'corporate' : 'personal'
63
65
  }
64
66
  }),
65
- invalidatesTags: ['Addresses', 'Checkout'] // TODO: Invalidate one of these tags when necessary (e.g. Address page invalidates Addresses tag, Checkout page invalidates Checkout tag)
67
+ invalidatesTags: (_, error) => (error ? [] : ['Addresses', 'Checkout']) // TODO: Invalidate one of these tags when necessary (e.g. Address page invalidates Addresses tag, Checkout page invalidates Checkout tag)
66
68
  }),
67
69
  removeAddress: builder.mutation<void, number>({
68
70
  query: (id) => ({
69
71
  url: buildClientRequestUrl(address.removeAddress(id)),
70
72
  method: 'DELETE'
71
73
  }),
72
- invalidatesTags: ['Addresses', 'Checkout'] // TODO: Invalidate one of these tags when necessary (e.g. Address page invalidates Addresses tag, Checkout page invalidates Checkout tag)
74
+ invalidatesTags: (_, error) => (error ? [] : ['Addresses', 'Checkout']) // TODO: Invalidate one of these tags when necessary (e.g. Address page invalidates Addresses tag, Checkout page invalidates Checkout tag)
73
75
  }),
74
76
  setDefaultAddress: builder.mutation<Address, Partial<Address>>({
75
77
  query: ({ pk, primary }) => ({
@@ -79,7 +81,7 @@ const addressApi = api.injectEndpoints({
79
81
  method: 'PATCH',
80
82
  body: { primary }
81
83
  }),
82
- invalidatesTags: ['Addresses']
84
+ invalidatesTags: (_, error) => (error ? [] : ['Addresses'])
83
85
  }),
84
86
  getStores: builder.query<GetResponse<Address>, void>({
85
87
  query: () => ({
@@ -20,6 +20,8 @@ interface GetStockParams {
20
20
  }
21
21
 
22
22
  interface GetFavoritesResponse {
23
+ next?: string | null;
24
+ previous?: string | null;
23
25
  count: number;
24
26
  results: FavoriteItem[];
25
27
  }
@@ -71,14 +73,14 @@ export const wishlistApi = api.injectEndpoints({
71
73
  product: productPk
72
74
  }
73
75
  }),
74
- invalidatesTags: ['Favorite']
76
+ invalidatesTags: (_, error) => (error ? [] : ['Favorite'])
75
77
  }),
76
78
  removeFavorite: build.mutation<RemoteFavoriteResponse, number>({
77
79
  query: (favPk: number) => ({
78
80
  url: buildClientRequestUrl(wishlist.removeFavorite(favPk)),
79
81
  method: 'DELETE'
80
82
  }),
81
- invalidatesTags: ['Favorite']
83
+ invalidatesTags: (_, error) => (error ? [] : ['Favorite'])
82
84
  }),
83
85
  addStockAlert: build.mutation<AddStockAlertResponse, AddStockAlertRequest>({
84
86
  query: ({ productPk, email }) => ({
@@ -39,7 +39,7 @@ function getCategoryDataHandler(
39
39
  numberValueParser
40
40
  ) as GetCategoryResponse;
41
41
  } catch (error) {
42
- logger.error('Error while parsing category data', {
42
+ logger.fatal('Error while parsing category data', {
43
43
  handler: 'getCategoryDataHandler',
44
44
  error,
45
45
  rawData: rawData.startsWith('<!DOCTYPE html>')
@@ -50,6 +50,14 @@ function getCategoryDataHandler(
50
50
 
51
51
  const menuItemModel = data?.category?.menuitemmodel;
52
52
 
53
+ if (!menuItemModel) {
54
+ logger.warn('menuItemModel is undefined, skipping breadcrumbData fetch', {
55
+ handler: 'getCategoryDataHandler',
56
+ pk
57
+ });
58
+ return { data, breadcrumbData: undefined };
59
+ }
60
+
53
61
  const breadcrumbData = await appFetch<any>(
54
62
  product.breadcrumbUrl(menuItemModel),
55
63
  {
@@ -108,7 +116,7 @@ function getCategoryBySlugDataHandler(slug: string) {
108
116
  numberValueParser
109
117
  ) as GetCategoryResponse;
110
118
  } catch (error) {
111
- logger.error('Error while parsing category data', {
119
+ logger.fatal('Error while parsing category data', {
112
120
  handler: 'getCategoryBySlugDataHandler',
113
121
  error,
114
122
  rawData: rawData.startsWith('<!DOCTYPE html>')
@@ -38,7 +38,7 @@ const getListDataHandler = (
38
38
  numberValueParser
39
39
  ) as GetCategoryResponse;
40
40
  } catch (error) {
41
- logger.error('Error while parsing list data', {
41
+ logger.fatal('Error while parsing list data', {
42
42
  error,
43
43
  rawData: rawData.startsWith('<!DOCTYPE html>')
44
44
  ? `${rawData.substring(0, 50)}...`
@@ -70,10 +70,6 @@ export default function usePagination(
70
70
  dispatch({ type: 'setLimit', payload: limit });
71
71
  }, [limit]);
72
72
 
73
- useEffect(() => {
74
- window.scrollTo(0, 0);
75
- }, [state.page, state.limit]);
76
-
77
73
  const setTotal = useCallback(
78
74
  (total: number) => {
79
75
  dispatch({ type: 'setTotal', payload: total });
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.23.0",
4
+ "version": "1.24.0-rc.1",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -32,7 +32,7 @@
32
32
  "@typescript-eslint/eslint-plugin": "6.7.4",
33
33
  "@typescript-eslint/parser": "6.7.4",
34
34
  "eslint": "^8.14.0",
35
- "@akinon/eslint-plugin-projectzero": "1.23.0",
35
+ "@akinon/eslint-plugin-projectzero": "1.24.0-rc.1",
36
36
  "eslint-config-prettier": "8.5.0"
37
37
  }
38
38
  }
package/plugins.d.ts CHANGED
@@ -13,3 +13,11 @@ declare module '@akinon/pz-masterpass/src/redux/reducer' {
13
13
  export const setError: any;
14
14
  export const setOtpModalVisible: any;
15
15
  }
16
+
17
+ declare module '@akinon/pz-otp' {
18
+ export const otpReducer: any;
19
+ }
20
+
21
+ declare module '@akinon/pz-otp/src/redux/reducer' {
22
+ export const showPopup: any;
23
+ }
@@ -6,6 +6,7 @@ import { api } from '../../data/client/api';
6
6
 
7
7
  // Plugin reducers
8
8
  import { masterpassReducer } from '@akinon/pz-masterpass';
9
+ import { otpReducer } from '@akinon/pz-otp';
9
10
 
10
11
  const reducers = {
11
12
  [api.reducerPath]: api.reducer,
@@ -13,7 +14,8 @@ const reducers = {
13
14
  checkout: checkoutReducer,
14
15
  config: configReducer,
15
16
  header: headerReducer,
16
- masterpass: masterpassReducer
17
+ masterpass: masterpassReducer,
18
+ otp: otpReducer
17
19
  };
18
20
 
19
21
  export default reducers;
package/sentry/index.ts CHANGED
@@ -1,27 +1,33 @@
1
1
  import * as Sentry from '@sentry/nextjs';
2
+ import settings from 'settings';
2
3
 
3
4
  const SENTRY_DSN: string =
4
- process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
5
+ settings.sentryDsn ||
6
+ process.env.SENTRY_DSN ||
7
+ process.env.NEXT_PUBLIC_SENTRY_DSN;
5
8
 
6
9
  export const initSentry = (
7
10
  type: 'Server' | 'Client' | 'Edge',
8
- options: Sentry.BrowserOptions | Sentry.NodeOptions | Sentry.EdgeOptions = {}
11
+ options: Sentry.BrowserOptions | Sentry.NodeOptions | Sentry.EdgeOptions = {
12
+ dsn: SENTRY_DSN,
13
+ integrations: [],
14
+ tracesSampleRate: 1.0
15
+ }
9
16
  ) => {
10
- // TODO: Handle options with ESLint rules
11
-
12
- // TODO: Remove Zero Project DSN
13
-
14
- Sentry.init({
15
- dsn:
16
- SENTRY_DSN ||
17
- 'https://d8558ef8997543deacf376c7d8d7cf4b@o64293.ingest.sentry.io/4504338423742464',
17
+ const initOptions = {
18
+ ...options,
18
19
  initialScope: {
19
20
  tags: {
21
+ ...((
22
+ options.initialScope as {
23
+ tags?: Record<string, string>;
24
+ }
25
+ )?.tags ?? {}),
20
26
  APP_TYPE: 'ProjectZeroNext',
21
27
  TYPE: type
22
28
  }
23
- },
24
- tracesSampleRate: 1.0,
25
- integrations: []
26
- });
29
+ }
30
+ };
31
+
32
+ Sentry.init(initOptions);
27
33
  };
package/types/index.ts CHANGED
@@ -71,6 +71,12 @@ export interface Currency {
71
71
 
72
72
  export interface Settings {
73
73
  commerceUrl: string;
74
+ /**
75
+ * This option allows you to track Sentry events on the client side, in addition to server and edge environments.
76
+ *
77
+ * It overrides process.env.NEXT_PUBLIC_SENTRY_DSN and process.env.SENTRY_DSN.
78
+ */
79
+ sentryDsn?: string;
74
80
  redis: {
75
81
  defaultExpirationTime: number;
76
82
  };
@@ -12,7 +12,7 @@ const appFetch = async <T>(
12
12
  url: RequestInfo,
13
13
  init: RequestInit = {},
14
14
  responseType = FetchResponseType.JSON
15
- ) => {
15
+ ): Promise<T> => {
16
16
  let response: T;
17
17
  let status: number;
18
18
  let ip = '';
@@ -48,18 +48,18 @@ const appFetch = async <T>(
48
48
  status = req.status;
49
49
  logger.debug(`FETCH END ${url}`, { status: req.status, ip });
50
50
 
51
- const rawData = await req.text();
52
-
53
51
  if (responseType === FetchResponseType.JSON) {
54
- response = JSON.parse(rawData);
52
+ response = (await req.json()) as T;
55
53
  } else {
56
- response = rawData as unknown as T;
54
+ response = (await req.text()) as unknown as T;
57
55
  }
58
56
 
59
57
  logger.trace(`FETCH RESPONSE`, { url, response, ip });
60
58
  } catch (error) {
59
+ const logType = status === 500 ? 'fatal' : 'error';
60
+
61
61
  if (!url.toString().includes('/cms/seo/')) {
62
- logger.error(`FETCH FAILED`, { url, status, error, ip });
62
+ logger[logType](`FETCH FAILED`, { url, status, error, ip });
63
63
  }
64
64
  }
65
65