@akinon/next 1.74.0 → 1.75.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,5 +1,19 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.75.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 81248a1: ZERO-3024: Refactor urlLocaleMatcherRegex to include lookahead assertion
8
+ - cc538c6: ZERO-3048: Update hepsiPayMiddleware to use Success flag for availability check
9
+ - 663bda9: ZERO-2990: Refactor account API to include shipping option slug in getOrders query
10
+ - 94eb825: ZERO-3069: Add selectNameSpaceMainBasket mutation
11
+ - 3010514: ZERO-3011:add shipping_option_operator and custom filter to getOrders
12
+ - 37547c0: ZERO-2957: Refactor checkout middleware to include payment options in iframe and deprecate exclusion option
13
+ - 5a333a5: ZERO-3061: Add success parameter for completeWalletPage
14
+ - ca774b3: ZERO-3002:add register with loyalty url
15
+ - 3344bca: ZERO-3013: Enable web vitals tracking in settings.js
16
+
3
17
  ## 1.74.0
4
18
 
5
19
  ### Minor Changes
@@ -1,13 +1,12 @@
1
- 'use client';
2
-
3
1
  import { MouseEvent, useCallback, useEffect, useState } from 'react';
4
2
  import { PaginationProps } from '../types';
5
3
  import { twMerge } from 'tailwind-merge';
6
4
  import clsx from 'clsx';
5
+ import { Link, Button, LoaderSpinner } from '.';
7
6
  import usePagination from '@akinon/next/hooks/use-pagination';
8
7
  import { useLocalization } from '@akinon/next/hooks';
9
8
  import { useRouter } from '@akinon/next/hooks';
10
- import { Link } from './link';
9
+ import { useInView } from 'react-intersection-observer';
11
10
 
12
11
  export const Pagination = (props: PaginationProps) => {
13
12
  const { t } = useLocalization();
@@ -21,8 +20,13 @@ export const Pagination = (props: PaginationProps) => {
21
20
  prevClassName,
22
21
  pageClassName,
23
22
  nextClassName,
23
+ moreButtonClassName,
24
24
  threshold = 1,
25
- render
25
+ type = 'list',
26
+ onPageChange,
27
+ direction,
28
+ render,
29
+ isLoading
26
30
  } = props;
27
31
 
28
32
  const pagination = usePagination(total, limit, currentPage, numberOfPages);
@@ -33,12 +37,16 @@ export const Pagination = (props: PaginationProps) => {
33
37
  pageList,
34
38
  prev,
35
39
  next,
40
+ last,
36
41
  setTotal,
37
42
  setLimit
38
43
  } = pagination;
39
44
 
40
45
  const [paginationItems, setPaginationItems] = useState([]);
41
- const showNext = currentPage * paginationLimit < total;
46
+ const showNext = currentPage * paginationLimit < paginationTotal;
47
+ const { ref, inView } = useInView({ threshold: 0.75 });
48
+ const [prevPage, setPrevPage] = useState(page);
49
+ const [nextPage, setNextPage] = useState(page);
42
50
 
43
51
  const createListItems = useCallback(() => {
44
52
  setPaginationItems([]);
@@ -98,9 +106,38 @@ export const Pagination = (props: PaginationProps) => {
98
106
  router.push(newUrl.pathname + newUrl.search, undefined);
99
107
  };
100
108
 
109
+ const handlePageChange = () => {
110
+ let changingPage;
111
+
112
+ if (direction === 'prev') {
113
+ changingPage = Number(type !== 'list' ? prevPage : page) - 1;
114
+ setPrevPage(changingPage);
115
+ } else {
116
+ changingPage = Number(type !== 'list' ? nextPage : page) + 1;
117
+ setNextPage(changingPage);
118
+ }
119
+
120
+ onPageChange(changingPage);
121
+ };
122
+
123
+ useEffect(() => {
124
+ if (type === 'infinite' && page === 1) {
125
+ setPrevPage(1);
126
+ setNextPage(1);
127
+ }
128
+ }, [page]);
129
+
130
+ useEffect(() => {
131
+ if (inView) {
132
+ handlePageChange();
133
+ }
134
+ }, [inView]); // eslint-disable-line react-hooks/exhaustive-deps
135
+
101
136
  useEffect(() => {
102
- createListItems();
103
- }, [createListItems, page]);
137
+ if (type === 'list') {
138
+ createListItems();
139
+ }
140
+ }, [page]); // eslint-disable-line react-hooks/exhaustive-deps
104
141
 
105
142
  useEffect(() => {
106
143
  if (total && total !== paginationTotal) {
@@ -118,76 +155,128 @@ export const Pagination = (props: PaginationProps) => {
118
155
  return <>{render(pagination)}</>;
119
156
  }
120
157
 
121
- return (
122
- <ul
123
- className={twMerge(
124
- 'flex mt-8 mb-4 justify-center items-center',
125
- containerClassName
126
- )}
127
- >
128
- {prev && (
129
- <li>
130
- <Link
131
- onClick={(e) => handleClick(e, prev)}
132
- href={prev}
158
+ return direction === 'prev' && type !== 'list' ? (
159
+ <>
160
+ <div className="flex items-center justify-center">
161
+ <Button
162
+ className={twMerge('px-5', moreButtonClassName)}
163
+ onClick={() => handlePageChange()}
164
+ >
165
+ {isLoading ? (
166
+ <LoaderSpinner className="h-4 w-4" />
167
+ ) : (
168
+ t('category.pagination.load_previous_page')
169
+ )}
170
+ </Button>
171
+ </div>
172
+ </>
173
+ ) : (
174
+ <>
175
+ {type === 'more' && (
176
+ <div className="flex items-center justify-center">
177
+ <Button
133
178
  className={twMerge(
134
- 'flex cursor-pointer text-sm px-2',
135
- prevClassName
179
+ 'px-5',
180
+ Number(nextPage) === Number(last)
181
+ ? 'bg-gray-600 border-gray-600 pointer-events-none'
182
+ : 'bg-black',
183
+ moreButtonClassName
136
184
  )}
185
+ onClick={() => handlePageChange()}
186
+ disabled={Number(nextPage) === Number(last)}
137
187
  >
138
- <span>&lt;</span>
139
- <span className="hidden lg:inline-block ms-4">
140
- {t('category.pagination.previous')}
141
- </span>
142
- </Link>
143
- </li>
188
+ {isLoading ? (
189
+ <LoaderSpinner className="h-4 w-4" />
190
+ ) : (
191
+ t('category.pagination.more')
192
+ )}
193
+ </Button>
194
+ </div>
144
195
  )}
145
196
 
146
- {paginationItems &&
147
- paginationItems?.map((item, i) => (
148
- <li key={i}>
149
- {item?.url != '#' ? (
197
+ {type === 'infinite' && Number(nextPage) !== last && (
198
+ <div ref={ref}></div>
199
+ )}
200
+
201
+ {(type === 'infinite' || type === 'more') &&
202
+ Number(nextPage) === last &&
203
+ !isLoading && (
204
+ <p className="mt-8 text-center">
205
+ {t('category.pagination.shown_items')}
206
+ </p>
207
+ )}
208
+
209
+ {type === 'list' && (
210
+ <ul
211
+ className={twMerge(
212
+ 'mb-4 mt-8 flex items-center justify-center',
213
+ containerClassName
214
+ )}
215
+ >
216
+ {prev && currentPage !== 1 && (
217
+ <li>
150
218
  <Link
151
- onClick={(e) => handleClick(e, item.url)}
152
- href={item.url}
219
+ onClick={(e) => handleClick(e, prev)}
220
+ href={prev}
153
221
  className={twMerge(
154
- clsx(
155
- 'text-xs px-2 cursor-pointer',
156
- { 'pointer-events-none': item.url === null },
157
- Number(page) === Number(item?.page)
158
- ? 'font-semibold text-black-800'
159
- : 'text-gray-400'
160
- ),
161
- pageClassName
222
+ 'flex cursor-pointer px-2 text-sm items-center',
223
+ prevClassName
162
224
  )}
163
225
  >
164
- {item?.page}
226
+ <span>&lt;</span>
227
+ <span className="ms-4 hidden lg:inline-block">
228
+ {t('category.pagination.previous')}
229
+ </span>
165
230
  </Link>
166
- ) : (
167
- <span className="cursor-default text-xs flex items-center justify-center">
168
- {item?.page}
169
- </span>
170
- )}
171
- </li>
172
- ))}
173
-
174
- {showNext && (
175
- <li>
176
- <Link
177
- onClick={(e) => handleClick(e, next)}
178
- href={next}
179
- className={twMerge(
180
- 'flex cursor-pointer text-xs px-2',
181
- nextClassName
182
- )}
183
- >
184
- <span className="hidden lg:inline-block me-4">
185
- {t('category.pagination.next')}
186
- </span>
187
- <span>&gt;</span>
188
- </Link>
189
- </li>
231
+ </li>
232
+ )}
233
+
234
+ {paginationItems.map((item, i) => (
235
+ <li key={i}>
236
+ {item?.url != '#' ? (
237
+ <Link
238
+ onClick={(e) => handleClick(e, item.url)}
239
+ href={item.url}
240
+ className={twMerge(
241
+ clsx(
242
+ 'cursor-pointer px-2 text-xs items-center',
243
+ { 'pointer-events-none': item.url === null },
244
+ Number(page) === Number(item?.page)
245
+ ? 'font-semibold text-black-800'
246
+ : 'text-gray-400'
247
+ ),
248
+ pageClassName
249
+ )}
250
+ >
251
+ {item?.page}
252
+ </Link>
253
+ ) : (
254
+ <span className="flex cursor-default items-center justify-center text-xs">
255
+ {item?.page}
256
+ </span>
257
+ )}
258
+ </li>
259
+ ))}
260
+
261
+ {showNext && (
262
+ <li>
263
+ <Link
264
+ onClick={(e) => handleClick(e, next)}
265
+ href={next}
266
+ className={twMerge(
267
+ 'flex cursor-pointer px-2 text-xs items-center',
268
+ nextClassName
269
+ )}
270
+ >
271
+ <span className="me-4 hidden lg:inline-block">
272
+ {t('category.pagination.next')}
273
+ </span>
274
+ <span>&gt;</span>
275
+ </Link>
276
+ </li>
277
+ )}
278
+ </ul>
190
279
  )}
191
- </ul>
280
+ </>
192
281
  );
193
282
  };
@@ -3,24 +3,26 @@
3
3
  import { useReportWebVitals } from 'next/web-vitals';
4
4
  import { useSelectedLayoutSegment } from 'next/navigation';
5
5
  import { usePathname } from 'next/navigation';
6
+ import settings from 'settings';
6
7
 
7
8
  export function WebVitals() {
8
9
  let layoutSegment = useSelectedLayoutSegment();
9
10
  const pathname = usePathname();
11
+ const { enabled } = settings.webVitals || { enabled: false };
10
12
 
11
13
  if (pathname === '/' && layoutSegment === null) {
12
14
  layoutSegment = 'home';
13
15
  }
14
16
 
15
17
  useReportWebVitals((metric) => {
16
- if (process.env.NODE_ENV !== 'development') {
18
+ if (process.env.NODE_ENV !== 'development' || !enabled) {
17
19
  return;
18
20
  }
19
21
 
20
22
  const { name, value, rating } = metric;
21
23
  const page = layoutSegment || 'unknown';
22
24
 
23
- fetch(`${process.env.NEXT_PUBLIC_URL}/api/web-vitals`, {
25
+ fetch(`/api/web-vitals`, {
24
26
  method: 'POST',
25
27
  headers: {
26
28
  'Content-Type': 'application/json'
@@ -21,6 +21,10 @@ interface GetOrdersParams {
21
21
  page?: number;
22
22
  createdDate?: string;
23
23
  endDate?: string;
24
+ shipping_option_slug?: string;
25
+ shipping_option_operator?: string;
26
+ filterType?: string;
27
+ filterValue?: string;
24
28
  currency?: string;
25
29
  }
26
30
 
@@ -115,9 +119,29 @@ const accountApi = api.injectEndpoints({
115
119
  query: (id) => buildClientRequestUrl(account.orderId(id))
116
120
  }),
117
121
  getOrders: builder.query<GetOrdersResponse, GetOrdersParams>({
118
- query: ({ page, limit, createdDate, endDate, currency } = {}) =>
122
+ query: ({
123
+ page,
124
+ limit,
125
+ createdDate,
126
+ endDate,
127
+ shipping_option_operator,
128
+ shipping_option_slug,
129
+ filterType,
130
+ filterValue,
131
+ currency
132
+ } = {}) =>
119
133
  buildClientRequestUrl(
120
- account.getOrders({ page, limit, createdDate, endDate, currency })
134
+ account.getOrders({
135
+ page,
136
+ limit,
137
+ createdDate,
138
+ endDate,
139
+ shipping_option_operator,
140
+ shipping_option_slug,
141
+ filterType,
142
+ filterValue,
143
+ currency
144
+ })
121
145
  )
122
146
  }),
123
147
  getOldOrders: builder.query<GetOrdersResponse, GetOrdersParams>({
@@ -59,6 +59,20 @@ export const basketApi = api.injectEndpoints({
59
59
  transformResponse: (response: { baskets: Basket }) => response.baskets,
60
60
  invalidatesTags: ['MultiBasket', 'Basket']
61
61
  }),
62
+ selectNameSpaceMainBasket: build.mutation<Basket, { namespace: string }>({
63
+ query: ({ namespace }) => ({
64
+ url: buildClientRequestUrl(
65
+ basket.selectNameSpaceMainBasket(namespace),
66
+ {
67
+ contentType: 'application/json'
68
+ }
69
+ ),
70
+ method: 'POST',
71
+ body: { namespace }
72
+ }),
73
+ transformResponse: (response: { baskets: Basket }) => response.baskets,
74
+ invalidatesTags: ['MultiBasket', 'Basket']
75
+ }),
62
76
  updateQuantity: build.mutation<
63
77
  UpdateQuantityResponse,
64
78
  UpdateQuantityRequest
@@ -115,6 +129,7 @@ export const {
115
129
  useGetAllBasketsQuery,
116
130
  useRemoveBasketMutation,
117
131
  useSelectMainBasketMutation,
132
+ useSelectNameSpaceMainBasketMutation,
118
133
  useUpdateQuantityMutation,
119
134
  useClearBasketMutation,
120
135
  useApplyVoucherCodeMutation,
@@ -484,10 +484,13 @@ export const checkoutApi = api.injectEndpoints({
484
484
  dispatch(setPaymentStepBusy(false));
485
485
  }
486
486
  }),
487
- setWalletCompletePage: build.mutation<CheckoutResponse, void>({
488
- query: () => ({
487
+ setWalletCompletePage: build.mutation<CheckoutResponse, boolean>({
488
+ query: (success: boolean) => ({
489
489
  url: buildClientRequestUrl(checkout.setWalletCompletePage),
490
- method: 'POST'
490
+ method: 'POST',
491
+ body: {
492
+ success
493
+ }
491
494
  }),
492
495
  async onQueryStarted(arg, { dispatch, queryFulfilled }) {
493
496
  dispatch(setPaymentStepBusy(true));
package/data/urls.ts CHANGED
@@ -19,6 +19,9 @@ export const account = {
19
19
  createdDate,
20
20
  endDate,
21
21
  shipping_option_slug,
22
+ shipping_option_operator = '=',
23
+ filterType,
24
+ filterValue,
22
25
  currency
23
26
  }: {
24
27
  page?: number;
@@ -26,15 +29,19 @@ export const account = {
26
29
  createdDate?: string;
27
30
  endDate?: string;
28
31
  shipping_option_slug?: string;
32
+ shipping_option_operator?: string;
33
+ filterType?: string;
34
+ filterValue?: string;
29
35
  currency?: string;
30
36
  }) =>
31
37
  `/users/orders/?page=${page || 1}&limit=${limit || 12}${
32
38
  createdDate ? `&created_date__gte=${createdDate}` : ''
33
39
  }${endDate ? `&created_date__lte=${endDate}` : ''}${
34
40
  shipping_option_slug
35
- ? `&shipping_option_slug=${shipping_option_slug}`
41
+ ? `&shipping_option_slug${shipping_option_operator}${shipping_option_slug}`
36
42
  : ''
37
- }${currency ? `&currency=${currency}` : ''}`,
43
+ }${currency ? `&currency=${currency}` : ''}
44
+ ${filterType && filterValue ? `&${filterType}=${filterValue}` : ''}`,
38
45
  getOldOrders: ({ page, limit }: { page?: number; limit?: number }) =>
39
46
  `/users/old-orders/?page=${page || 1}&limit=${limit || 12}}`,
40
47
  getQuotations: (page?: number, status?: string, limit?: number) =>
@@ -70,7 +77,9 @@ export const basket = {
70
77
  getBasketDetail: (namespace: string) => `/baskets/basket/${namespace}/`,
71
78
  getAllBaskets: '/baskets/basket-list/',
72
79
  removeBasket: (pk: number) => `/baskets/basket-list/${pk}/`,
73
- selectMainBasket: (pk: number) => `/baskets/basket-list/id/${pk}/main/`
80
+ selectMainBasket: (pk: number) => `/baskets/basket-list/id/${pk}/main/`,
81
+ selectNameSpaceMainBasket: (namespace: string) =>
82
+ `/baskets/basket-list/ns/${namespace}/main/`
74
83
  };
75
84
 
76
85
  export const category = {
@@ -208,7 +217,8 @@ export const user = {
208
217
  confirmEmailVerification: (token: string) =>
209
218
  `/users/registration/account-confirm-email/${token}/`,
210
219
  csrfToken: '/csrf_token/',
211
- anonymousOrderTracking: '/users/orders/anonymous'
220
+ anonymousOrderTracking: '/users/orders/anonymous',
221
+ loyaltyRegister: '/users/register-with-loyalty/'
212
222
  };
213
223
 
214
224
  export const b2b = {
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.74.0",
4
+ "version": "1.75.0",
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": "1.74.0",
33
+ "@akinon/eslint-plugin-projectzero": "1.75.0",
34
34
  "@types/react-redux": "7.1.30",
35
35
  "@types/set-cookie-parser": "2.4.7",
36
36
  "@typescript-eslint/eslint-plugin": "6.7.4",
@@ -231,15 +231,15 @@ export const contextListMiddleware: Middleware = ({
231
231
  const isMobileDevice =
232
232
  isMobileApp ||
233
233
  /iPad|iPhone|iPod|Android/i.test(navigator.userAgent);
234
- const isIframePaymentOptionExcluded =
235
- settings.checkout?.iframeExcludedPaymentOptions?.includes(
234
+ const isIframePaymentOptionIncluded =
235
+ settings.checkout?.iframeIncludedPaymentOptions?.includes(
236
236
  result.payload?.pre_order?.payment_option?.slug
237
237
  );
238
238
  urlObj.searchParams.set('t', new Date().getTime().toString());
239
239
 
240
- if (isMobileDevice && !isIframePaymentOptionExcluded) {
240
+ if (isMobileDevice && isIframePaymentOptionIncluded) {
241
241
  showMobile3dIframe(urlObj.toString());
242
- } else if (isIframe && !isIframePaymentOptionExcluded) {
242
+ } else if (isIframe) {
243
243
  showRedirectionIframe(urlObj.toString());
244
244
  } else {
245
245
  window.location.href = urlObj.toString();
@@ -368,8 +368,7 @@ export const hepsiPayMiddleware: Middleware = ({
368
368
  ) {
369
369
  dispatch(
370
370
  setHepsipayAvailability(
371
- walletSelectionPage.page_context.paymentData.data
372
- .IsAccountAlreadyLinked
371
+ walletSelectionPage.page_context.paymentData.data.Success
373
372
  )
374
373
  );
375
374
  }
package/types/index.ts CHANGED
@@ -78,6 +78,9 @@ export interface Currency {
78
78
  }
79
79
 
80
80
  export interface Settings {
81
+ webVitals?: {
82
+ enabled: boolean;
83
+ };
81
84
  usePrettyUrlRoute?: boolean;
82
85
  commerceUrl: string;
83
86
  redis: {
@@ -184,9 +187,15 @@ export interface Settings {
184
187
  }>;
185
188
  checkout?: {
186
189
  /**
190
+ * @deprecated All payment options will be excluded from the iframe by default. This option is deprecated and will be removed in future releases.
191
+ *
187
192
  * If there is a need to exclude certain payment options from the iframe, for instance, due to CORS issues, this option can be utilized by passing the slugs associated with the desired payment options.
188
193
  */
189
194
  iframeExcludedPaymentOptions?: string[];
195
+ /**
196
+ * If there is a need to include certain payment options in the iframe, this option can be utilized by passing the slugs associated with the desired payment options.
197
+ */
198
+ iframeIncludedPaymentOptions?: string[];
190
199
  extraPaymentTypes?: string[];
191
200
  masterpassJsUrl?: string;
192
201
  };
@@ -321,4 +330,5 @@ export interface PaginationProps {
321
330
  type?: 'infinite' | 'list' | 'more';
322
331
  onPageChange?: (page: number) => void;
323
332
  direction?: 'next' | 'prev';
333
+ isLoading?: boolean;
324
334
  }
package/utils/index.ts CHANGED
@@ -161,7 +161,7 @@ export const urlLocaleMatcherRegex = new RegExp(
161
161
  : l
162
162
  )
163
163
  .map((l) => l.value)
164
- .join('|')})`
164
+ .join('|')})(?=/|$)`
165
165
  );
166
166
 
167
167
  export const getPosError = () => {