@akinon/next 1.41.0-rc.1 → 1.41.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,25 +1,10 @@
1
1
  # @akinon/next
2
2
 
3
- ## 1.41.0-rc.1
3
+ ## 1.41.0
4
4
 
5
5
  ### Minor Changes
6
6
 
7
- - 98bb8dc: ZERO-2706: Cache getTranlations method
8
-
9
- ## 1.41.0-rc.0
10
-
11
- ### Minor Changes
12
-
13
- - a4c8d6a: ZERO-2663: Fix the image url for gif and svgs and return them without options
14
- - c53ea3e: ZERO-2609: Reset additional form fields when selectedFormType is not company
15
- - c53ef7b: ZERO-2668: The Link component has been updated to improve the logic for handling href values. Previously, if the href was not a string or started with 'http', it would return the href as is. Now, if the href is not provided, it will default to '#' to prevent any potential errors. Additionally, if the href is a string and does not start with 'http', it will be formatted with the locale and pathname, based on the localeUrlStrategy and defaultLocaleValue. This ensures that the correct href is generated based on the localization settings.
16
- - 1448a96: ZERO-2612: add errors type in CheckoutState
17
- - 75080fd: ZERO-2630: Add max limit to postcode area
18
- - 91265bb: ZERO-2551: Improve pretty url and caching performance
19
- - bbe18b9: ZERO-2575: Fix build error
20
- - dff0d59: ZERO-2659: add formData support to proxy api requests
21
- - beb499e: ZERO-2551: Add new tsconfig paths
22
- - f046f8e: ZERO-2575: update version for react-number-format
7
+ - 8f09473: ZERO-2686: create akifast plugin
23
8
 
24
9
  ## 1.40.0
25
10
 
package/api/client.ts CHANGED
@@ -78,13 +78,12 @@ async function proxyRequest(...args) {
78
78
  fetchOptions.headers['Content-Type'] = options.contentType;
79
79
  }
80
80
 
81
- const isMultipartFormData = req.headers.get('content-type')?.includes('multipart/form-data;');
82
-
83
81
  if (req.method !== 'GET') {
84
- let body: Record<string, any> | FormData = {};
82
+ const formData = new URLSearchParams();
83
+ let body = {};
85
84
 
86
85
  try {
87
- body = isMultipartFormData ? await req.formData() : await req.json();
86
+ body = await req.json();
88
87
  } catch (error) {
89
88
  logger.error(
90
89
  `Client Proxy Request - Error while parsing request body to JSON`,
@@ -95,21 +94,13 @@ async function proxyRequest(...args) {
95
94
  );
96
95
  }
97
96
 
98
- if (isMultipartFormData) {
99
- fetchOptions.body = body as FormData;
100
- } else {
101
- const formData = new FormData();
102
-
103
- Object.keys(body ?? {}).forEach((key) => {
104
- if (body[key]) {
105
- formData.append(key, body[key]);
106
- }
107
- });
97
+ Object.keys(body ?? {}).forEach((key) => {
98
+ if (body[key]) {
99
+ formData.append(key, body[key]);
100
+ }
101
+ });
108
102
 
109
- fetchOptions.body = !options.useFormData
110
- ? JSON.stringify(body)
111
- : formData;
112
- }
103
+ fetchOptions.body = !options.useFormData ? JSON.stringify(body) : formData;
113
104
  }
114
105
 
115
106
  let url = `${commerceUrl}/${slug.replace(/,/g, '/')}`;
@@ -1,29 +1,17 @@
1
1
  import clsx from 'clsx';
2
- import { forwardRef, FocusEvent, useState, Ref } from 'react';
2
+ import { forwardRef, FocusEvent, useState } from 'react';
3
3
  import { Controller } from 'react-hook-form';
4
- // @ts-ignore
5
- import { PatternFormat, PatternFormatProps } from 'react-number-format';
4
+ import NumberFormat, { NumberFormatProps } from 'react-number-format';
6
5
  import { InputProps } from '../types';
7
6
  import { twMerge } from 'tailwind-merge';
8
7
 
9
- const PatternFormatWithRef = forwardRef(
10
- (props: PatternFormatProps, ref: Ref<HTMLInputElement>) => {
11
- return <PatternFormat {...props} getInputRef={ref} />;
12
- }
13
- );
14
- PatternFormatWithRef.displayName = 'PatternFormatWithRef';
15
-
16
8
  export const Input = forwardRef<
17
9
  HTMLInputElement,
18
10
  InputProps &
19
11
  Pick<
20
- PatternFormatProps,
21
- 'mask' | 'allowEmptyFormatting' | 'onValueChange'
22
- > & {
23
- format?: string;
24
- defaultValue?: string;
25
- type?: string;
26
- }
12
+ NumberFormatProps,
13
+ 'format' | 'mask' | 'allowEmptyFormatting' | 'onValueChange'
14
+ >
27
15
  >((props, ref) => {
28
16
  const [focused, setFocused] = useState(false);
29
17
  const [hasValue, setHasValue] = useState(false);
@@ -49,7 +37,6 @@ export const Input = forwardRef<
49
37
  ),
50
38
  props.className
51
39
  );
52
-
53
40
  const inputProps: any = {
54
41
  id,
55
42
  ref,
@@ -92,14 +79,14 @@ export const Input = forwardRef<
92
79
  <Controller
93
80
  name={props.name ?? ''}
94
81
  control={props.control}
82
+ defaultValue={false}
95
83
  render={({ field }) => (
96
- <PatternFormatWithRef
84
+ <NumberFormat
97
85
  format={format}
98
86
  mask={mask ?? ''}
99
87
  {...rest}
100
88
  {...field}
101
89
  {...inputProps}
102
- type={props.type as 'text' | 'password' | 'tel'}
103
90
  />
104
91
  )}
105
92
  />
@@ -10,32 +10,28 @@ type LinkProps = Omit<
10
10
  React.AnchorHTMLAttributes<HTMLAnchorElement>,
11
11
  keyof NextLinkProps
12
12
  > &
13
- NextLinkProps & {
14
- href: string;
15
- };
13
+ NextLinkProps;
16
14
 
17
15
  export const Link = ({ children, href, ...rest }: LinkProps) => {
18
16
  const { locale, defaultLocaleValue, localeUrlStrategy } = useLocalization();
19
17
  const formattedHref = useMemo(() => {
20
- if (!href) {
21
- return '#';
18
+ if (typeof href !== 'string' || href.startsWith('http')) {
19
+ return href;
22
20
  }
23
21
 
24
- if (typeof href === 'string' && !href.startsWith('http')) {
25
- const pathnameWithoutLocale = href.replace(urlLocaleMatcherRegex, '');
26
- const hrefWithLocale = `/${locale}${pathnameWithoutLocale}`;
22
+ const pathnameWithoutLocale = href.replace(urlLocaleMatcherRegex, '');
23
+ const hrefWithLocale = `/${locale}${pathnameWithoutLocale}`;
27
24
 
28
- if (localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales) {
29
- return hrefWithLocale;
30
- } else if (
31
- localeUrlStrategy === LocaleUrlStrategy.HideDefaultLocale &&
32
- locale !== defaultLocaleValue
33
- ) {
34
- return hrefWithLocale;
35
- }
25
+ if (localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales) {
26
+ return hrefWithLocale;
27
+ } else if (
28
+ localeUrlStrategy === LocaleUrlStrategy.HideDefaultLocale &&
29
+ locale !== defaultLocaleValue
30
+ ) {
31
+ return hrefWithLocale;
36
32
  }
37
33
 
38
- return href;
34
+ return href || '#';
39
35
  }, [href, defaultLocaleValue, locale, localeUrlStrategy]);
40
36
 
41
37
  return (
@@ -4,6 +4,7 @@ import dynamic from 'next/dynamic';
4
4
  import plugins from 'plugins';
5
5
  import logger from '../utils/log';
6
6
  import { useMemo } from 'react';
7
+ import settings from 'settings';
7
8
 
8
9
  enum Plugin {
9
10
  BasketGiftPack = 'pz-basket-gift-pack',
@@ -16,13 +17,15 @@ enum Plugin {
16
17
  BKMExpress = 'pz-bkm',
17
18
  CreditPayment = 'pz-credit-payment',
18
19
  Masterpass = 'pz-masterpass',
19
- B2B = 'pz-b2b'
20
+ B2B = 'pz-b2b',
21
+ Akifast = 'pz-akifast'
20
22
  }
21
23
 
22
24
  export enum Component {
23
25
  BasketGiftPack = 'BasketGiftPack',
24
26
  ClickCollect = 'ClickCollect',
25
27
  OneClickCheckoutButtons = 'OneClickCheckoutButtons',
28
+ OneClickProviderButton = 'OneClickCheckoutButton',
26
29
  PayOnDelivery = 'PayOnDelivery',
27
30
  CheckoutGiftPack = 'CheckoutGiftPack',
28
31
  GPay = 'GPayOption',
@@ -36,13 +39,18 @@ export enum Component {
36
39
  MasterpassOtpModal = 'MasterpassOtpModal',
37
40
  MasterpassLinkModal = 'MasterpassLinkModal',
38
41
  MyQuotationsB2B = 'AccountMyQuotations',
39
- BasketB2B = 'BasketB2b'
42
+ BasketB2B = 'BasketB2b',
43
+ AkifastQuickLoginButton = 'QuickLoginButton',
44
+ AkifastCheckoutButton = 'CheckoutButton'
40
45
  }
41
46
 
42
47
  const PluginComponents = new Map([
43
48
  [Plugin.BasketGiftPack, [Component.BasketGiftPack]],
44
49
  [Plugin.ClickCollect, [Component.ClickCollect]],
45
- [Plugin.OneClickCheckout, [Component.OneClickCheckoutButtons]],
50
+ [
51
+ Plugin.OneClickCheckout,
52
+ [Component.OneClickCheckoutButtons, Component.OneClickProviderButton]
53
+ ],
46
54
  [Plugin.PayOnDelivery, [Component.PayOnDelivery]],
47
55
  [Plugin.CheckoutGiftPack, [Component.CheckoutGiftPack]],
48
56
  [Plugin.GPay, [Component.GPay]],
@@ -60,7 +68,11 @@ const PluginComponents = new Map([
60
68
  Component.MasterpassLinkModal
61
69
  ]
62
70
  ],
63
- [Plugin.B2B, [Component.MyQuotationsB2B, Component.BasketB2B]]
71
+ [Plugin.B2B, [Component.MyQuotationsB2B, Component.BasketB2B]],
72
+ [
73
+ Plugin.Akifast,
74
+ [Component.AkifastQuickLoginButton, Component.AkifastCheckoutButton]
75
+ ]
64
76
  ]);
65
77
 
66
78
  const getPlugin = (component: Component) => {
@@ -81,6 +93,14 @@ export default function PluginModule({
81
93
  children?: React.ReactNode;
82
94
  }) {
83
95
  const plugin = getPlugin(component);
96
+ const pluginSettings = settings.plugins?.[plugin];
97
+
98
+ if (pluginSettings) {
99
+ props = {
100
+ ...props,
101
+ settings: pluginSettings
102
+ };
103
+ }
84
104
 
85
105
  const Component = useMemo(
86
106
  () =>
@@ -111,6 +131,8 @@ export default function PluginModule({
111
131
  promise = import(`${'@akinon/pz-masterpass'}`);
112
132
  } else if (plugin === Plugin.B2B) {
113
133
  promise = import(`${'@akinon/pz-b2b'}`);
134
+ } else if (plugin === Plugin.Akifast) {
135
+ promise = import(`${'@akinon/pz-akifast'}`);
114
136
  }
115
137
  } catch (error) {
116
138
  logger.error(error);
@@ -1,12 +1,11 @@
1
1
  import { useMemo } from 'react';
2
- // @ts-ignore
3
- import { NumericFormat, NumericFormatProps } from 'react-number-format';
2
+ import NumberFormat, { NumberFormatProps } from 'react-number-format';
4
3
  import { getCurrency } from '@akinon/next/utils';
5
4
 
6
5
  import { useLocalization } from '@akinon/next/hooks';
7
6
  import { PriceProps } from '../types';
8
7
 
9
- export const Price = (props: NumericFormatProps & PriceProps) => {
8
+ export const Price = (props: NumberFormatProps & PriceProps) => {
10
9
  const {
11
10
  value,
12
11
  currencyCode,
@@ -40,7 +39,7 @@ export const Price = (props: NumericFormatProps & PriceProps) => {
40
39
  );
41
40
 
42
41
  return (
43
- <NumericFormat
42
+ <NumberFormat
44
43
  value={useNegative ? `-${useNegativeSpace}${_value}` : _value}
45
44
  {...{
46
45
  [useCurrencyAfterPrice ? 'suffix' : 'prefix']: currency
@@ -123,16 +123,15 @@ const accountApi = api.injectEndpoints({
123
123
  query: ({ page, status, limit }) =>
124
124
  buildClientRequestUrl(account.getQuotations(page, status, limit))
125
125
  }),
126
- sendContact: builder.mutation<void, FormData>({
127
- query: (body) => {
128
- return {
129
- url: buildClientRequestUrl(account.sendContact, {
130
- useFormData: true
131
- }),
132
- method: 'POST',
133
- body
134
- };
135
- }
126
+ sendContact: builder.mutation<void, ContactFormType>({
127
+ query: (body) => ({
128
+ url: buildClientRequestUrl(account.sendContact, {
129
+ contentType: 'application/json',
130
+ responseType: 'text'
131
+ }),
132
+ method: 'POST',
133
+ body
134
+ })
136
135
  }),
137
136
  cancelOrder: builder.mutation<void, AccountOrderCancellation>({
138
137
  query: ({ id, ...body }) => ({
@@ -8,7 +8,7 @@ import logger from '../../utils/log';
8
8
 
9
9
  function getCategoryDataHandler(
10
10
  pk: number,
11
- searchParams?: { [key: string]: string | string[] | undefined },
11
+ searchParams?: URLSearchParams,
12
12
  headers?: Record<string, string>
13
13
  ) {
14
14
  return async function () {
@@ -78,7 +78,7 @@ export const getCategoryData = ({
78
78
  headers
79
79
  }: {
80
80
  pk: number;
81
- searchParams?: { [key: string]: string | string[] | undefined };
81
+ searchParams?: URLSearchParams;
82
82
  headers?: Record<string, string>;
83
83
  }) => {
84
84
  return Cache.wrap(
@@ -7,7 +7,7 @@ import { parse } from 'lossless-json';
7
7
  import logger from '../../utils/log';
8
8
 
9
9
  const getListDataHandler = (
10
- searchParams: { [key: string]: string | string[] | undefined },
10
+ searchParams: URLSearchParams,
11
11
  headers?: Record<string, string>
12
12
  ) => {
13
13
  return async function () {
@@ -54,7 +54,7 @@ export const getListData = async ({
54
54
  searchParams,
55
55
  headers
56
56
  }: {
57
- searchParams: { [key: string]: string | string[] | undefined };
57
+ searchParams: URLSearchParams;
58
58
  headers?: Record<string, string>;
59
59
  }) => {
60
60
  return Cache.wrap(
@@ -9,7 +9,7 @@ import appFetch from '../../utils/app-fetch';
9
9
 
10
10
  type GetProduct = {
11
11
  pk: number;
12
- searchParams?: { [key: string]: string | string[] | undefined };
12
+ searchParams?: URLSearchParams;
13
13
  groupProduct?: boolean;
14
14
  };
15
15
 
@@ -74,7 +74,10 @@ export const getProductData = async ({
74
74
  groupProduct
75
75
  }: GetProduct) => {
76
76
  return Cache.wrap(
77
- CacheKey[groupProduct ? 'GroupProduct' : 'Product'](pk, searchParams ?? {}),
77
+ CacheKey[groupProduct ? 'GroupProduct' : 'Product'](
78
+ pk,
79
+ searchParams ?? new URLSearchParams()
80
+ ),
78
81
  getProductDataHandler({ pk, searchParams, groupProduct }),
79
82
  {
80
83
  expire: 300
@@ -7,7 +7,7 @@ import header from '../../redux/reducers/header';
7
7
 
8
8
  const getSpecialPageDataHandler = (
9
9
  pk: number,
10
- searchParams: { [key: string]: string | string[] | undefined },
10
+ searchParams: URLSearchParams,
11
11
  headers?: Record<string, string>
12
12
  ) => {
13
13
  return async function () {
@@ -34,7 +34,7 @@ export const getSpecialPageData = async ({
34
34
  headers
35
35
  }: {
36
36
  pk: number;
37
- searchParams: { [key: string]: string | string[] | undefined };
37
+ searchParams: URLSearchParams;
38
38
  headers?: Record<string, string>;
39
39
  }) => {
40
40
  return Cache.wrap(
@@ -2,7 +2,7 @@ import settings from 'settings';
2
2
  import { LayoutProps, PageProps, RootLayoutProps } from '../../types';
3
3
  import { redirect } from 'next/navigation';
4
4
  import { ServerVariables } from '../../utils/server-variables';
5
- import { getCachedTranslations } from '../../utils/server-translation';
5
+ import { getTranslations } from '../../utils/server-translation';
6
6
  import { ROUTES } from 'routes';
7
7
  import logger from '../../utils/log';
8
8
 
@@ -50,7 +50,7 @@ const addRootLayoutProps = async (componentProps: RootLayoutProps) => {
50
50
  return redirect(ROUTES.HOME);
51
51
  }
52
52
 
53
- const translations = await getCachedTranslations(params.locale);
53
+ const translations = await getTranslations(params.locale);
54
54
  componentProps.translations = translations;
55
55
 
56
56
  const locale = settings.localization.locales.find(
package/lib/cache.ts CHANGED
@@ -20,16 +20,13 @@ const hashCacheKey = (object?: Record<string, string>) => {
20
20
  return `_${encodeURIComponent(cacheKey)}`;
21
21
  };
22
22
  export const CacheKey = {
23
- List: (
24
- searchParams: { [key: string]: string | string[] | undefined },
25
- headers?: Record<string, string>
26
- ) =>
23
+ List: (searchParams: URLSearchParams, headers?: Record<string, string>) =>
27
24
  `list_${encodeURIComponent(JSON.stringify(searchParams))}${hashCacheKey(
28
25
  headers
29
26
  )}`,
30
27
  Category: (
31
28
  pk: number,
32
- searchParams?: { [key: string]: string | string[] | undefined },
29
+ searchParams?: URLSearchParams,
33
30
  headers?: Record<string, string>
34
31
  ) =>
35
32
  `category_${pk}_${encodeURIComponent(
@@ -38,20 +35,15 @@ export const CacheKey = {
38
35
  CategorySlug: (slug: string) => `category_${slug}`,
39
36
  SpecialPage: (
40
37
  pk: number,
41
- searchParams: { [key: string]: string | string[] | undefined },
38
+ searchParams: URLSearchParams,
42
39
  headers?: Record<string, string>
43
40
  ) =>
44
41
  `special_page_${pk}_${encodeURIComponent(
45
42
  JSON.stringify(searchParams)
46
43
  )}${hashCacheKey(headers)}`,
47
- Product: (
48
- pk: number,
49
- searchParams: { [key: string]: string | string[] | undefined }
50
- ) => `product_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
51
- GroupProduct: (
52
- pk: number,
53
- searchParams: { [key: string]: string | string[] | undefined }
54
- ) =>
44
+ Product: (pk: number, searchParams: URLSearchParams) =>
45
+ `product_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
46
+ GroupProduct: (pk: number, searchParams: URLSearchParams) =>
55
47
  `group_product_${pk}_${encodeURIComponent(JSON.stringify(searchParams))}`,
56
48
  FlatPage: (pk: number) => `flat_page_${pk}`,
57
49
  LandingPage: (pk: number) => `landing_page_${pk}`,
@@ -166,10 +158,6 @@ export class Cache {
166
158
  handler: () => Promise<T>,
167
159
  options?: CacheOptions
168
160
  ): Promise<T> {
169
- if (Settings.usePrettyUrlRoute) {
170
- return await handler();
171
- }
172
-
173
161
  const requiredVariables = [
174
162
  process.env.CACHE_HOST,
175
163
  process.env.CACHE_PORT,
@@ -203,15 +203,6 @@ const withPzDefault =
203
203
  );
204
204
  }
205
205
 
206
- if (
207
- Settings.usePrettyUrlRoute &&
208
- url.searchParams.toString().length > 0
209
- ) {
210
- url.pathname =
211
- url.pathname +
212
- `searchparams|${url.searchParams.toString()}`;
213
- }
214
-
215
206
  Settings.rewrites.forEach((rewrite) => {
216
207
  url.pathname = url.pathname.replace(
217
208
  rewrite.source,
@@ -56,10 +56,6 @@ const resolvePrettyUrl = async (pathname: string, ip: string | null) => {
56
56
  const withPrettyUrl =
57
57
  (middleware: NextMiddleware) =>
58
58
  async (req: PzNextRequest, event: NextFetchEvent) => {
59
- if (Settings.usePrettyUrlRoute) {
60
- return middleware(req, event);
61
- }
62
-
63
59
  const url = req.nextUrl.clone();
64
60
  const matchedLanguagePrefix = url.pathname.match(
65
61
  urlLocaleMatcherRegex
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.41.0-rc.1",
4
+ "version": "1.41.0",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -20,12 +20,11 @@
20
20
  "@opentelemetry/sdk-trace-node": "1.19.0",
21
21
  "@opentelemetry/semantic-conventions": "1.19.0",
22
22
  "@reduxjs/toolkit": "1.9.7",
23
- "@neshca/cache-handler": "1.0.7",
24
23
  "cross-spawn": "7.0.3",
25
24
  "generic-pool": "3.9.0",
26
25
  "react-redux": "8.1.3",
27
26
  "react-string-replace": "1.1.1",
28
- "redis": "4.6.13",
27
+ "redis": "4.5.1",
29
28
  "semver": "7.5.4",
30
29
  "set-cookie-parser": "2.6.0"
31
30
  },
@@ -35,7 +34,7 @@
35
34
  "@typescript-eslint/eslint-plugin": "6.7.4",
36
35
  "@typescript-eslint/parser": "6.7.4",
37
36
  "eslint": "^8.14.0",
38
- "@akinon/eslint-plugin-projectzero": "1.41.0-rc.1",
37
+ "@akinon/eslint-plugin-projectzero": "1.41.0",
39
38
  "eslint-config-prettier": "8.5.0"
40
39
  }
41
40
  }
package/plugins.js CHANGED
@@ -9,5 +9,6 @@ module.exports = [
9
9
  'pz-bkm',
10
10
  'pz-credit-payment',
11
11
  'pz-masterpass',
12
- 'pz-b2b'
12
+ 'pz-b2b',
13
+ 'pz-akifast'
13
14
  ];
@@ -29,7 +29,7 @@ import { showMobile3dIframe } from '../../utils/mobile-3d-iframe';
29
29
 
30
30
  interface CheckoutResult {
31
31
  payload: {
32
- errors?: Record<string, string[]>;
32
+ errors?: any;
33
33
  pre_order?: PreOrder;
34
34
  context_list?: CheckoutContext[];
35
35
  };
@@ -18,7 +18,8 @@ import {
18
18
  } from '../../types';
19
19
 
20
20
  export interface CheckoutState {
21
- errors: Record<string, string[]>;
21
+ // TODO: Add types
22
+ errors: any;
22
23
  hasGiftBox: boolean;
23
24
  canGuestPurchase: boolean;
24
25
  steps: {
@@ -6,8 +6,6 @@ import { Config } from '../../types';
6
6
  const initialState: Config = {
7
7
  user_phone_regex: '^(05)\\d{9}$',
8
8
  user_phone_format: '05999999999',
9
- user_post_code_regex: '^\\d{5}$',
10
- user_post_code_format: '99999',
11
9
  country: {
12
10
  pk: 1,
13
11
  name: 'Türkiye',
@@ -61,5 +61,4 @@ export type ContactFormType = {
61
61
  order?: string;
62
62
  country_code?: string;
63
63
  order_needed?: boolean;
64
- file?: FileList
65
64
  };
@@ -17,7 +17,7 @@ export type AddressFormType = {
17
17
  line: string;
18
18
  postcode: string;
19
19
  company_name?: string;
20
- tax_no?: string;
20
+ tax_no?: number;
21
21
  tax_office?: string;
22
22
  e_bill_taxpayer?: boolean;
23
23
  country_code?: string;
@@ -2,8 +2,6 @@ import { District } from './address';
2
2
  export interface Config {
3
3
  user_phone_regex: string;
4
4
  user_phone_format: string;
5
- user_post_code_regex: string;
6
- user_post_code_format: string;
7
5
  country: {
8
6
  pk: number;
9
7
  name: string;
package/types/index.ts CHANGED
@@ -8,6 +8,7 @@ declare global {
8
8
  // we did it like this because declare types needs to be identical, if not it will fail
9
9
  // eslint-disable-next-line @typescript-eslint/ban-types
10
10
  dataLayer?: Object[];
11
+
11
12
  [key: string]: any;
12
13
  }
13
14
  }
@@ -70,7 +71,6 @@ export interface Currency {
70
71
  }
71
72
 
72
73
  export interface Settings {
73
- usePrettyUrlRoute?: boolean;
74
74
  commerceUrl: string;
75
75
  redis: {
76
76
  defaultExpirationTime: number;
@@ -183,6 +183,7 @@ export interface Settings {
183
183
  masterpassJsUrl?: string;
184
184
  };
185
185
  customNotFoundEnabled: boolean;
186
+ plugins?: Record<string, Record<string, any>>;
186
187
  }
187
188
 
188
189
  export interface CacheOptions {
@@ -215,7 +216,7 @@ export type Translations = { [key: string]: object };
215
216
 
216
217
  export interface PageProps<T = any> {
217
218
  params: T;
218
- searchParams: { [key: string]: string | string[] | undefined };
219
+ searchParams: URLSearchParams;
219
220
  }
220
221
 
221
222
  export interface LayoutProps<T = any> extends PageProps<T> {
@@ -278,3 +279,7 @@ export interface AccordionProps {
278
279
  titleClassName?: string;
279
280
  dataTestId?: string;
280
281
  }
282
+
283
+ export interface PluginModuleComponentProps {
284
+ settings?: Record<string, any>;
285
+ }
@@ -41,7 +41,7 @@ const appFetch = async <T>(
41
41
  };
42
42
 
43
43
  init.next = {
44
- revalidate: Settings.usePrettyUrlRoute ? 0 : 60
44
+ revalidate: 60
45
45
  };
46
46
 
47
47
  logger.debug(`FETCH START ${url}`, { requestURL, init, ip });
@@ -1,15 +1,11 @@
1
1
  import logger from './log';
2
2
 
3
- export const generateCommerceSearchParams = (searchParams?: {
4
- [key: string]: string | string[] | undefined;
5
- }) => {
3
+ export const generateCommerceSearchParams = (searchParams?: URLSearchParams) => {
6
4
  if (!searchParams) {
7
5
  return null;
8
6
  }
9
7
 
10
- const urlSerchParams = new URLSearchParams(
11
- searchParams as Record<string, string>
12
- );
8
+ const urlSerchParams = new URLSearchParams(searchParams);
13
9
 
14
10
  Object.entries(searchParams).forEach(([key, value]) => {
15
11
  if (typeof value === 'object') {
package/utils/index.ts CHANGED
@@ -102,12 +102,6 @@ export function buildCDNUrl(url: string, config?: CDNOptions) {
102
102
  ''
103
103
  );
104
104
 
105
- const noOptionFileExtension = url?.split('.').pop()?.toLowerCase() ?? '';
106
-
107
- if (noOptionFileExtension === 'svg' || noOptionFileExtension === 'gif') {
108
- return url;
109
- }
110
-
111
105
  let options = '';
112
106
 
113
107
  if (config) {
@@ -5,10 +5,10 @@ import { getTranslateFn } from '../utils';
5
5
  import { Translations } from '../types';
6
6
  import settings from 'settings';
7
7
  import logger from './log';
8
- import { unstable_cache } from 'next/cache';
9
8
 
10
9
  export const translations: Translations = {};
11
10
 
11
+ // TODO: Read translations from cache
12
12
  export async function getTranslations(locale_: string) {
13
13
  try {
14
14
  const locale = settings.localization.locales.find(
@@ -52,10 +52,6 @@ export async function getTranslations(locale_: string) {
52
52
  return translations;
53
53
  }
54
54
 
55
- export const getCachedTranslations = unstable_cache(async (locale: string) =>
56
- getTranslations(locale)
57
- );
58
-
59
55
  export function t(path: string) {
60
56
  return getTranslateFn(path, translations);
61
57
  }
package/with-pz-config.js CHANGED
@@ -8,7 +8,6 @@ const defaultConfig = {
8
8
  transpilePackages: ['@akinon/next', ...pzPlugins.map((p) => `@akinon/${p}`)],
9
9
  skipTrailingSlashRedirect: true,
10
10
  poweredByHeader: false,
11
- cacheMaxMemorySize: 0,
12
11
  env: {
13
12
  NEXT_PUBLIC_SENTRY_DSN: process.env.SENTRY_DSN
14
13
  },
@@ -66,12 +65,7 @@ const defaultConfig = {
66
65
  }
67
66
  };
68
67
 
69
- const withPzConfig = (
70
- myNextConfig = {},
71
- options = {
72
- useCacheHandler: false
73
- }
74
- ) => {
68
+ const withPzConfig = (myNextConfig = {}) => {
75
69
  let extendedConfig = deepMerge({}, defaultConfig, myNextConfig);
76
70
 
77
71
  const originalPzHeadersFunction = defaultConfig.headers;
@@ -97,10 +91,6 @@ const withPzConfig = (
97
91
  return [...pzRewrites, ...myRewrites];
98
92
  };
99
93
 
100
- if (options.useCacheHandler) {
101
- extendedConfig.cacheHandler = require.resolve('./lib/cache-handler.mjs');
102
- }
103
-
104
94
  return extendedConfig;
105
95
  };
106
96
 
@@ -1,33 +0,0 @@
1
- import { CacheHandler } from '@neshca/cache-handler';
2
- import createLruHandler from '@neshca/cache-handler/local-lru';
3
- import createRedisHandler from '@neshca/cache-handler/redis-stack';
4
- import { createClient } from 'redis';
5
-
6
- CacheHandler.onCreation(async () => {
7
- const redisUrl = `redis://${process.env.CACHE_HOST}:${
8
- process.env.CACHE_PORT
9
- }/${process.env.CACHE_BUCKET ?? '0'}`;
10
-
11
- const client = createClient({
12
- url: redisUrl
13
- });
14
-
15
- client.on('error', (error) => {
16
- console.error('Redis client error', { redisUrl, error });
17
- });
18
-
19
- await client.connect();
20
-
21
- const redisHandler = await createRedisHandler({
22
- client,
23
- timeoutMs: 5000
24
- });
25
-
26
- const localHandler = createLruHandler();
27
-
28
- return {
29
- handlers: [redisHandler, localHandler]
30
- };
31
- });
32
-
33
- export default CacheHandler;
@@ -1,194 +0,0 @@
1
- import { URLS } from '@akinon/next/data/urls';
2
- import { Metadata, PageProps } from '@akinon/next/types';
3
- import logger from '@akinon/next/utils/log';
4
- import { notFound } from 'next/navigation';
5
-
6
- type PrettyUrlResult = {
7
- matched: boolean;
8
- path?: string;
9
- pk?: number;
10
- };
11
-
12
- const resolvePrettyUrlHandler =
13
- (pathname: string, ip: string | null) => async () => {
14
- let results = [] as { old_path: string }[];
15
- let prettyUrlResult: PrettyUrlResult = {
16
- matched: false
17
- };
18
-
19
- try {
20
- const requestUrl = URLS.misc.prettyUrls(`/${pathname}/`);
21
-
22
- logger.debug(`Resolving pretty url`, { pathname, requestUrl, ip });
23
-
24
- const start = Date.now();
25
- const apiResponse = await fetch(requestUrl, {
26
- next: {
27
- revalidate: 0
28
- }
29
- });
30
- const data = await apiResponse.json();
31
- ({ results } = data);
32
- const end = Date.now();
33
- console.warn('Pretty url response time', end - start, requestUrl);
34
-
35
- const matched = results.length > 0;
36
- const [{ old_path: path } = { old_path: '' }] = results;
37
- let pk;
38
-
39
- if (matched) {
40
- const pkRegex = /\/(\d+)\/$/;
41
- const match = path.match(pkRegex);
42
- pk = match ? parseInt(match[1]) : undefined;
43
- }
44
-
45
- prettyUrlResult = {
46
- matched,
47
- path,
48
- pk
49
- };
50
-
51
- logger.trace('Pretty url result', { prettyUrlResult, ip });
52
- } catch (error) {
53
- logger.error('Error resolving pretty url', { error, pathname, ip });
54
- }
55
-
56
- return prettyUrlResult;
57
- };
58
-
59
- export async function generateMetadata({ params }: PageProps) {
60
- let result: Metadata = {};
61
- const { prettyurl } = params;
62
- const pageSlug = prettyurl
63
- .filter((x) => !x.startsWith('searchparams'))
64
- .join('/');
65
-
66
- const searchParams = Object.fromEntries(
67
- new URLSearchParams(
68
- decodeURIComponent(
69
- prettyurl
70
- .find((x) => x.startsWith('searchparams'))
71
- ?.replace('searchparams%7C', '')
72
- ) ?? {}
73
- ).entries()
74
- );
75
-
76
- const prettyUrlResult = await resolvePrettyUrlHandler(pageSlug, null)();
77
-
78
- if (!prettyUrlResult.matched) {
79
- return notFound();
80
- }
81
-
82
- const commonProps = {
83
- params: {
84
- ...params,
85
- pk: prettyUrlResult.pk
86
- },
87
- searchParams
88
- };
89
-
90
- try {
91
- if (prettyUrlResult.path.startsWith('/product/')) {
92
- await import('@product/[pk]/page').then(async (module) => {
93
- result = await module['generateMetadata']?.(commonProps);
94
- });
95
- }
96
-
97
- if (prettyUrlResult.path.startsWith('/group-product/')) {
98
- await import('@group-product/[pk]/page').then(async (module) => {
99
- result = await module['generateMetadata']?.(commonProps);
100
- });
101
- }
102
-
103
- if (prettyUrlResult.path.startsWith('/category/')) {
104
- await import('@category/[pk]/page').then(async (module) => {
105
- result = await module['generateMetadata']?.(commonProps);
106
- });
107
- }
108
-
109
- if (prettyUrlResult.path.startsWith('/special-page/')) {
110
- await import('@special-page/[pk]/page').then(async (module) => {
111
- result = await module['generateMetadata']?.(commonProps);
112
- });
113
- }
114
-
115
- if (prettyUrlResult.path.startsWith('/flat-page/')) {
116
- await import('@flat-page/[pk]/page').then(async (module) => {
117
- result = await module['generateMetadata']?.(commonProps);
118
- });
119
- }
120
- // eslint-disable-next-line no-empty
121
- } catch (error) {}
122
-
123
- return result;
124
- }
125
-
126
- export const dynamic = 'force-static';
127
- export const revalidate = 300;
128
-
129
- export default async function Page({ params }) {
130
- const { prettyurl } = params;
131
- const pageSlug = prettyurl
132
- .filter((x) => !x.startsWith('searchparams'))
133
- .join('/');
134
-
135
- const urlSearchParams = new URLSearchParams(
136
- decodeURIComponent(
137
- prettyurl
138
- .find((x) => x.startsWith('searchparams'))
139
- ?.replace('searchparams%7C', '')
140
- ) ?? {}
141
- );
142
-
143
- const searchParams = {};
144
-
145
- for (const [key, value] of urlSearchParams.entries() as unknown as Array<
146
- [string, string]
147
- >) {
148
- if (!searchParams[key]) {
149
- searchParams[key] = [];
150
- }
151
- searchParams[key].push(value);
152
- }
153
-
154
- const result = await resolvePrettyUrlHandler(pageSlug, null)();
155
-
156
- if (!result.matched) {
157
- return notFound();
158
- }
159
-
160
- const commonProps = {
161
- params: {
162
- ...params,
163
- pk: result.pk
164
- },
165
- searchParams
166
- };
167
-
168
- if (result.path.startsWith('/category/')) {
169
- const CategoryPage = (await import('@category/[pk]/page')).default;
170
- return <CategoryPage {...commonProps} />;
171
- }
172
-
173
- if (result.path.startsWith('/product/')) {
174
- const ProductPage = (await import('@product/[pk]/page')).default;
175
- return <ProductPage {...commonProps} />;
176
- }
177
-
178
- if (result.path.startsWith('/group-product/')) {
179
- const GroupProduct = (await import('@group-product/[pk]/page')).default;
180
- return <GroupProduct {...commonProps} />;
181
- }
182
-
183
- if (result.path.startsWith('/special-page/')) {
184
- const SpecialPage = (await import('@special-page/[pk]/page')).default;
185
- return <SpecialPage {...commonProps} />;
186
- }
187
-
188
- if (result.path.startsWith('/flat-page/')) {
189
- const FlatPage = (await import('@flat-page/[pk]/page')).default;
190
- return <FlatPage {...commonProps} />;
191
- }
192
-
193
- return null;
194
- }