@akinon/next 1.91.0-rc.2 → 1.91.0-rc.4

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,72 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.91.0-rc.4
4
+
5
+ ### Minor Changes
6
+
7
+ - 7eb51ca: ZERO-3424 :Update package versions
8
+ - c39c700: ZERO-3420: Refactor Modal component
9
+ - 0de5573: ZERO-3418: Update remotePatterns hostname to allow all subdomains
10
+ - 9dc7298: ZERO-3416: Refactor Accordion component to enhance props and improve styling flexibility
11
+ - 2d3f178: ZERO-3417: Enhance FileInput component with additional props for customization
12
+
13
+ ## 1.91.0-rc.3
14
+
15
+ ### Minor Changes
16
+
17
+ - 5dfeea04: ZERO-2801: Revert ZERO-2801
18
+ - 823d82f9: ZERO-3393: Enhance error handling in checkout middleware to ensure errors are checked for existence before processing
19
+ - 63774a6a: ZERO-3351: Add commerce redirection ignore list functionality and related utility
20
+ - 2d9b2b2c: ZERO-2816: Add segment to headers
21
+ - 5e1feca6: Revert "ZERO-3286: Add notFound handling for chunk URLs starting with \_next"
22
+ - d8fad39f: ZERO-3370: include plugins test to build stage
23
+ - 40a46853: ZERO-3182: Optimize basket update mutation with optimistic update
24
+ - 68bbcb27: ZERO-3393: Fix error handling in checkout middleware to check for errors array length
25
+ - 25524867: ZERO-3391: Add subdomain support to setLocale function
26
+ - f49bb74f: ZERO-3097: Add setCookie to logging in payment redirection middlewares
27
+ - e9541a13: ZERO-2816: Add headers to url
28
+ - 9b7d0de6: ZERO-3393: Improve error handling in checkout middleware to support both object and array error formats
29
+ - 72fd4d67: ZERO-3084: Fix URL search parameters encoding in default middleware
30
+ - c53ef7b9: 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.
31
+ - f8e4cac6: ZERO-3343: restrict root hostname to only locale subdomains
32
+ - 64699d3f: ZERO-2761: Fix invalid import for plugin module
33
+ - 832bee36: ZERO-3343: add domain to cookie for subdomain locale strategy
34
+ - e974d8e8: ZERO-3406: Fix rc build
35
+ - 28a59d49: ZERO-3400: refactor cookie domain logic using fallback host
36
+ - 8feabe9a: ZERO-3343: add custom NextAuth options support
37
+ - bf354de4: ZERO-3321: add babel compiler for akinon/next test
38
+ - 7727ae55: ZERO-3073: Refactor basket page to use server-side data fetching and simplify component structure
39
+ - d552629f: ZERO-3182: Refactor basketApi to use invalidatesTags and comment out onQueryStarted logic
40
+ - 448adefb: ZERO-3321: move csp test to akinon-next
41
+ - 17f87524: ZERO-2816: Make the incoming currency lowercase
42
+ - 65d3b862: ZERO-3054: Update headers in appFetch
43
+ - bbe18b9f: ZERO-2575: Fix build error
44
+ - 17bfadc4: ZERO-3275: Disable OpenTelemetry monitoring in production environment
45
+ - 4920742c: Disable getCachedTranslations
46
+ - b6e5b624: ZERO-3257: Enhance locale middleware to redirect using existing or default locale and support 303 status for POST requests
47
+ - 6c3629c2: ZERO-3321: fix jest tests in akinon-next for standalone projects
48
+ - 6bc260be: ZERO-3295: update default tailwind content list
49
+ - 7e56d6b6: ZERO-2841: Update api tagTypes
50
+ - dfaceffd: ZERO-3356: Add useLoyaltyAvailability hook and update checkout state management
51
+ - 33377cfd: ZERO-3267: Refactor import statement for ROUTES in error-page component
52
+ - 43c182ee: ZERO-3054: Update Redis variable checks to conditionally include CACHE_SECRET
53
+ - 943a239e: ZERO-3370: add allowJs in akinon-next test tsconfig
54
+ - 068dc394: ZERO-3343: update get-root-hostname logic
55
+ - 942490f2: ZERO-3295: move third party tailwind content list to akinon-next
56
+ - eeb20bea: Revert "ZERO-3054: Refactor cache handler to use custom Redis handler and implement key hashing"
57
+ - 3bf63c8a: ZERO-3286: Add notFound handling for chunk URLs starting with \_next
58
+ - 9be2c081: ZERO-3243: Improve basket update query handling with optimistic updates
59
+ - f2c92d5c: ZERO-2816: Update cookie name
60
+ - 7bd3d992: ZERO-2801: Refactor locale middleware to handle single locale configuration
61
+ - b6d5bda2: ZERO-3343: update changeset config
62
+ - fdd255ee: ZERO-3054: Refactor cache handler to use custom Redis handler and implement key hashing
63
+ - acf03209: ZERO-3321: remove babel config
64
+ - 387356b6: ZERO-3323: Refactor locale filtering logic in URL matcher regex
65
+ - 49eeebfa: ZERO-2909: Add deleteCollectionItem query to wishlistApi
66
+ - 3f9b8d7e: ZERO-2761: Update plugins.js for akinon-next
67
+ - b2ee69b9: ZERO-3321: delete unnecessary files
68
+ - 0cabbda3: ZERO-3370: replace inline monorepo check with reusable utility
69
+
3
70
  ## 1.91.0-rc.2
4
71
 
5
72
  ### Minor Changes
package/api/auth.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NextApiRequest, NextApiResponse } from 'next';
2
- import NextAuth, { Session } from 'next-auth';
2
+ import NextAuth, { Session, NextAuthOptions } from 'next-auth';
3
3
  import CredentialProvider from 'next-auth/providers/credentials';
4
4
  import { ROUTES } from 'routes';
5
5
  import { URLS, user } from '../data/urls';
@@ -7,6 +7,8 @@ import Settings from 'settings';
7
7
  import { urlLocaleMatcherRegex } from '../utils';
8
8
  import logger from '@akinon/next/utils/log';
9
9
  import { AuthError } from '../types';
10
+ import getRootHostname from '../utils/get-root-hostname';
11
+ import { LocaleUrlStrategy } from '../localization';
10
12
 
11
13
  async function getCurrentUser(sessionId: string, currency = '') {
12
14
  const headers = {
@@ -40,7 +42,15 @@ async function getCurrentUser(sessionId: string, currency = '') {
40
42
  };
41
43
  }
42
44
 
43
- const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
45
+ type CustomNextAuthOptions = (
46
+ req: NextApiRequest,
47
+ res: NextApiResponse
48
+ ) => Partial<NextAuthOptions>;
49
+
50
+ const defaultNextAuthOptions = (
51
+ req: NextApiRequest,
52
+ res: NextApiResponse
53
+ ): NextAuthOptions => {
44
54
  return {
45
55
  providers: [
46
56
  CredentialProvider({
@@ -150,7 +160,19 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
150
160
 
151
161
  if (sessionId) {
152
162
  const maxAge = 30 * 24 * 60 * 60; // 30 days in seconds
153
- const cookieOptions = `Path=/; HttpOnly; Secure; Max-Age=${maxAge}`;
163
+ const { localeUrlStrategy } = Settings.localization;
164
+
165
+ const fallbackHost =
166
+ req.headers['x-forwarded-host']?.toString() ||
167
+ req.headers.host?.toString();
168
+ const hostname =
169
+ process.env.NEXT_PUBLIC_URL || `https://${fallbackHost}`;
170
+ const rootHostname =
171
+ localeUrlStrategy === LocaleUrlStrategy.Subdomain
172
+ ? getRootHostname(hostname)
173
+ : null;
174
+ const domainOption = rootHostname ? `Domain=${rootHostname};` : '';
175
+ const cookieOptions = `Path=/; HttpOnly; Secure; Max-Age=${maxAge}; ${domainOption}`;
154
176
 
155
177
  res.setHeader('Set-Cookie', [
156
178
  `osessionid=${sessionId}; ${cookieOptions}`,
@@ -253,8 +275,36 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
253
275
  };
254
276
  };
255
277
 
256
- const Auth = (req, res) => {
257
- return NextAuth(req, res, nextAuthOptions(req, res));
278
+ const Auth = (
279
+ req: NextApiRequest,
280
+ res: NextApiResponse,
281
+ customOptions?: CustomNextAuthOptions
282
+ ) => {
283
+ const baseOptions = defaultNextAuthOptions(req, res);
284
+ const customOptionsResult = customOptions ? customOptions(req, res) : {};
285
+
286
+ const mergedOptions = {
287
+ ...baseOptions,
288
+ ...customOptionsResult,
289
+ providers: [
290
+ ...baseOptions.providers,
291
+ ...(customOptionsResult.providers || [])
292
+ ],
293
+ callbacks: {
294
+ ...baseOptions.callbacks,
295
+ ...customOptionsResult.callbacks
296
+ },
297
+ events: {
298
+ ...baseOptions.events,
299
+ ...customOptionsResult.events
300
+ },
301
+ pages: {
302
+ ...baseOptions.pages,
303
+ ...customOptionsResult.pages
304
+ }
305
+ };
306
+
307
+ return NextAuth(req, res, mergedOptions);
258
308
  };
259
309
 
260
310
  export default Auth;
package/api/client.ts CHANGED
@@ -5,6 +5,8 @@ import logger from '../utils/log';
5
5
  import formatCookieString from '../utils/format-cookie-string';
6
6
  import cookieParser from 'set-cookie-parser';
7
7
  import { cookies } from 'next/headers';
8
+ import getRootHostname from '../utils/get-root-hostname';
9
+ import { LocaleUrlStrategy } from '../localization';
8
10
 
9
11
  interface RouteParams {
10
12
  params: {
@@ -190,8 +192,23 @@ async function proxyRequest(...args) {
190
192
  const responseHeaders: any = {};
191
193
 
192
194
  if (filteredCookies.length > 0) {
195
+ const { localeUrlStrategy } = settings.localization;
196
+
197
+ const fallbackHost =
198
+ req.headers.get('x-forwarded-host') || req.headers.get('host');
199
+ const hostname = process.env.NEXT_PUBLIC_URL || `https://${fallbackHost}`;
200
+ const rootHostname =
201
+ localeUrlStrategy === LocaleUrlStrategy.Subdomain
202
+ ? getRootHostname(hostname)
203
+ : null;
204
+
193
205
  responseHeaders['set-cookie'] = filteredCookies
194
- .map(formatCookieString)
206
+ .map((cookie) => {
207
+ if (!cookie.domain && rootHostname) {
208
+ cookie.domain = rootHostname;
209
+ }
210
+ return formatCookieString(cookie);
211
+ })
195
212
  .join(', ');
196
213
  }
197
214
 
@@ -7,15 +7,19 @@ import { AccordionProps } from '../types';
7
7
 
8
8
  export const Accordion = ({
9
9
  isCollapse = false,
10
+ collapseClassName,
10
11
  title,
11
12
  subTitle,
12
13
  icons = ['chevron-up', 'chevron-down'],
13
14
  iconSize = 16,
14
15
  iconColor = 'fill-[#000000]',
15
16
  children,
17
+ headerClassName,
16
18
  className,
17
19
  titleClassName,
18
- dataTestId
20
+ subTitleClassName,
21
+ dataTestId,
22
+ contentClassName
19
23
  }: AccordionProps) => {
20
24
  const [collapse, setCollapse] = useState(isCollapse);
21
25
 
@@ -27,15 +31,22 @@ export const Accordion = ({
27
31
  )}
28
32
  >
29
33
  <div
30
- className="flex items-center justify-between cursor-pointer"
34
+ className={twMerge(
35
+ 'flex items-center justify-between cursor-pointer',
36
+ headerClassName
37
+ )}
31
38
  onClick={() => setCollapse(!collapse)}
32
39
  data-testid={dataTestId}
33
40
  >
34
- <div className="flex flex-col">
41
+ <div className={twMerge('flex flex-col', contentClassName)}>
35
42
  {title && (
36
43
  <h3 className={twMerge('text-sm', titleClassName)}>{title}</h3>
37
44
  )}
38
- {subTitle && <h4 className="text-xs text-gray-700">{subTitle}</h4>}
45
+ {subTitle && (
46
+ <h4 className={twMerge('text-xs text-gray-700', subTitleClassName)}>
47
+ {subTitle}
48
+ </h4>
49
+ )}
39
50
  </div>
40
51
 
41
52
  {icons && (
@@ -46,7 +57,11 @@ export const Accordion = ({
46
57
  />
47
58
  )}
48
59
  </div>
49
- {collapse && <div className="mt-3 text-sm">{children}</div>}
60
+ {collapse && (
61
+ <div className={twMerge('mt-3 text-sm', collapseClassName)}>
62
+ {children}
63
+ </div>
64
+ )}
50
65
  </div>
51
66
  );
52
67
  };
@@ -1,8 +1,70 @@
1
+ import { useState } from 'react';
1
2
  import { forwardRef } from 'react';
2
- import { FileInputProps } from '../types/index';
3
+ import { useLocalization } from '@akinon/next/hooks';
4
+ import { twMerge } from 'tailwind-merge';
5
+ import { FileInputProps } from '../types';
3
6
 
4
7
  export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
5
- function fileInput(props, ref) {
6
- return <input type="file" {...props} ref={ref} />;
8
+ function FileInput(
9
+ {
10
+ buttonClassName,
11
+ onChange,
12
+ fileClassName,
13
+ fileNameWrapperClassName,
14
+ fileInputClassName,
15
+ ...props
16
+ },
17
+ ref
18
+ ) {
19
+ const { t } = useLocalization();
20
+ const [fileNames, setFileNames] = useState<string[]>([]);
21
+
22
+ const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
23
+ const files = Array.from(event.target.files || []);
24
+ setFileNames(files.map((file) => file.name));
25
+
26
+ if (onChange) {
27
+ onChange(event);
28
+ }
29
+ };
30
+
31
+ return (
32
+ <div className="relative">
33
+ <input
34
+ type="file"
35
+ {...props}
36
+ ref={ref}
37
+ className={twMerge(
38
+ 'absolute inset-0 w-full h-full opacity-0 cursor-pointer',
39
+ fileInputClassName
40
+ )}
41
+ onChange={handleFileChange}
42
+ />
43
+ <button
44
+ type="button"
45
+ className={twMerge(
46
+ 'bg-primary text-white py-2 px-4 text-sm',
47
+ buttonClassName
48
+ )}
49
+ >
50
+ {t('common.file_input.select_file')}
51
+ </button>
52
+ <div
53
+ className={twMerge('mt-1 text-gray-500', fileNameWrapperClassName)}
54
+ >
55
+ {fileNames.length > 0 ? (
56
+ <ul className={twMerge('list-disc pl-4 text-xs', fileClassName)}>
57
+ {fileNames.map((name, index) => (
58
+ <li key={index}>{name}</li>
59
+ ))}
60
+ </ul>
61
+ ) : (
62
+ <span className={twMerge('text-xs', fileClassName)}>
63
+ {t('common.file_input.no_file')}
64
+ </span>
65
+ )}
66
+ </div>
67
+ </div>
68
+ );
7
69
  }
8
70
  );
@@ -4,16 +4,7 @@ import { ReactPortal } from './react-portal';
4
4
  import { Icon } from './icon';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { useEffect } from 'react';
7
-
8
- export interface ModalProps {
9
- portalId: string;
10
- children?: React.ReactNode;
11
- open?: boolean;
12
- setOpen?: (open: boolean) => void;
13
- title?: React.ReactNode;
14
- showCloseButton?: React.ReactNode;
15
- className?: string;
16
- }
7
+ import { ModalProps } from '../types';
17
8
 
18
9
  export const Modal = (props: ModalProps) => {
19
10
  const {
@@ -23,7 +14,14 @@ export const Modal = (props: ModalProps) => {
23
14
  setOpen,
24
15
  title = '',
25
16
  showCloseButton = true,
26
- className
17
+ className,
18
+ overlayClassName,
19
+ headerWrapperClassName,
20
+ titleClassName,
21
+ closeButtonClassName,
22
+ iconName = 'close',
23
+ iconSize = 16,
24
+ iconClassName
27
25
  } = props;
28
26
 
29
27
  useEffect(() => {
@@ -38,7 +36,12 @@ export const Modal = (props: ModalProps) => {
38
36
 
39
37
  return (
40
38
  <ReactPortal wrapperId={portalId}>
41
- <div className="fixed top-0 left-0 w-screen h-screen bg-primary bg-opacity-60 z-50" />
39
+ <div
40
+ className={twMerge(
41
+ 'fixed top-0 left-0 w-screen h-screen bg-primary bg-opacity-60 z-50',
42
+ overlayClassName
43
+ )}
44
+ />
42
45
  <section
43
46
  className={twMerge(
44
47
  'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 bg-white',
@@ -46,15 +49,28 @@ export const Modal = (props: ModalProps) => {
46
49
  )}
47
50
  >
48
51
  {(showCloseButton || title) && (
49
- <div className="flex px-6 py-4 border-b border-gray-400">
50
- {title && <h3 className="text-lg font-light">{title}</h3>}
52
+ <div
53
+ className={twMerge(
54
+ 'flex px-6 py-4 border-b border-gray-400',
55
+ headerWrapperClassName
56
+ )}
57
+ >
58
+ {title && (
59
+ <h3 className={twMerge('text-lg font-light', titleClassName)}>
60
+ {title}
61
+ </h3>
62
+ )}
51
63
  {showCloseButton && (
52
64
  <button
53
65
  type="button"
54
66
  onClick={() => setOpen(false)}
55
- className="ml-auto"
67
+ className={twMerge('ml-auto', closeButtonClassName)}
56
68
  >
57
- <Icon name="close" size={16} />
69
+ <Icon
70
+ name={iconName}
71
+ size={iconSize}
72
+ className={iconClassName}
73
+ />
58
74
  </button>
59
75
  )}
60
76
  </div>
@@ -20,7 +20,8 @@ enum Plugin {
20
20
  B2B = 'pz-b2b',
21
21
  Akifast = 'pz-akifast',
22
22
  MultiBasket = 'pz-multi-basket',
23
- SavedCard = 'pz-saved-card'
23
+ SavedCard = 'pz-saved-card',
24
+ Hepsipay = 'pz-hepsipay'
24
25
  }
25
26
 
26
27
  export enum Component {
@@ -45,7 +46,8 @@ export enum Component {
45
46
  AkifastQuickLoginButton = 'QuickLoginButton',
46
47
  AkifastCheckoutButton = 'CheckoutButton',
47
48
  MultiBasket = 'MultiBasket',
48
- SavedCard = 'SavedCardOption'
49
+ SavedCard = 'SavedCardOption',
50
+ Hepsipay = 'Hepsipay'
49
51
  }
50
52
 
51
53
  const PluginComponents = new Map([
@@ -78,7 +80,8 @@ const PluginComponents = new Map([
78
80
  [Component.AkifastQuickLoginButton, Component.AkifastCheckoutButton]
79
81
  ],
80
82
  [Plugin.MultiBasket, [Component.MultiBasket]],
81
- [Plugin.SavedCard, [Component.SavedCard]]
83
+ [Plugin.SavedCard, [Component.SavedCard]],
84
+ [Plugin.Hepsipay, [Component.Hepsipay]]
82
85
  ]);
83
86
 
84
87
  const getPlugin = (component: Component) => {
@@ -143,6 +146,8 @@ export default function PluginModule({
143
146
  promise = import(`${'@akinon/pz-multi-basket'}`);
144
147
  } else if (plugin === Plugin.SavedCard) {
145
148
  promise = import(`${'@akinon/pz-saved-card'}`);
149
+ } else if (plugin === Plugin.Hepsipay) {
150
+ promise = import(`${'@akinon/pz-hepsipay'}`);
146
151
  }
147
152
  } catch (error) {
148
153
  logger.error(error);
@@ -19,6 +19,8 @@ import withLocale from './locale';
19
19
  import logger from '../utils/log';
20
20
  import { user } from '../data/urls';
21
21
  import { getUrlPathWithLocale } from '../utils/localization';
22
+ import getRootHostname from '../utils/get-root-hostname';
23
+ import { LocaleUrlStrategy } from '../localization';
22
24
 
23
25
  const withPzDefault =
24
26
  (middleware: NextMiddleware) =>
@@ -296,7 +298,7 @@ const withPzDefault =
296
298
  !req.middlewareParams.found &&
297
299
  Settings.customNotFoundEnabled
298
300
  ) {
299
- let pathname = url.pathname
301
+ const pathname = url.pathname
300
302
  .replace(/\/+$/, '')
301
303
  .split('/');
302
304
  url.pathname = url.pathname.replace(
@@ -341,6 +343,21 @@ const withPzDefault =
341
343
  middlewareResult = NextResponse.rewrite(url);
342
344
  }
343
345
 
346
+ const { localeUrlStrategy } =
347
+ Settings.localization;
348
+
349
+ const fallbackHost =
350
+ req.headers.get('x-forwarded-host') ||
351
+ req.headers.get('host');
352
+ const hostname =
353
+ process.env.NEXT_PUBLIC_URL ||
354
+ `https://${fallbackHost}`;
355
+ const rootHostname =
356
+ localeUrlStrategy ===
357
+ LocaleUrlStrategy.Subdomain
358
+ ? getRootHostname(hostname)
359
+ : null;
360
+
344
361
  if (
345
362
  !url.pathname.startsWith(`/${currency}/orders`)
346
363
  ) {
@@ -350,6 +367,7 @@ const withPzDefault =
350
367
  ? locale
351
368
  : defaultLocaleValue,
352
369
  {
370
+ domain: rootHostname,
353
371
  sameSite: 'none',
354
372
  secure: true,
355
373
  expires: new Date(
@@ -358,10 +376,12 @@ const withPzDefault =
358
376
  }
359
377
  );
360
378
  }
379
+
361
380
  middlewareResult.cookies.set(
362
381
  'pz-currency',
363
382
  currency,
364
383
  {
384
+ domain: rootHostname,
365
385
  sameSite: 'none',
366
386
  secure: true,
367
387
  expires: new Date(
@@ -410,7 +430,10 @@ const withPzDefault =
410
430
  ).json();
411
431
  middlewareResult.cookies.set(
412
432
  'csrftoken',
413
- csrf_token
433
+ csrf_token,
434
+ {
435
+ domain: rootHostname
436
+ }
414
437
  );
415
438
  }
416
439
  } catch (error) {
@@ -13,7 +13,8 @@ const getMatchedLocale = (pathname: string, req: PzNextRequest) => {
13
13
  const { localeUrlStrategy, defaultLocaleValue } = settings.localization;
14
14
 
15
15
  if (localeUrlStrategy === LocaleUrlStrategy.Subdomain) {
16
- const host = req.headers.get('x-forwarded-host');
16
+ const host =
17
+ req.headers.get('x-forwarded-host') || req.headers.get('host') || '';
17
18
 
18
19
  if (host) {
19
20
  const subDomain = host.split('.')[0] || '';
@@ -44,7 +45,9 @@ const withLocale =
44
45
  try {
45
46
  const url = req.nextUrl.clone();
46
47
  const matchedLocale = getMatchedLocale(url.pathname, req);
47
- let { localeUrlStrategy, defaultLocaleValue, redirectToDefaultLocale } =
48
+ let { localeUrlStrategy } = settings.localization;
49
+
50
+ const { defaultLocaleValue, redirectToDefaultLocale } =
48
51
  settings.localization;
49
52
 
50
53
  localeUrlStrategy =
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.91.0-rc.2",
4
+ "version": "1.91.0-rc.4",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -34,7 +34,11 @@
34
34
  "set-cookie-parser": "2.6.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@akinon/eslint-plugin-projectzero": "1.91.0-rc.2",
37
+ "@akinon/eslint-plugin-projectzero": "1.91.0-rc.4",
38
+ "@babel/core": "7.26.10",
39
+ "@babel/preset-env": "7.26.9",
40
+ "@babel/preset-typescript": "7.27.0",
41
+ "@types/jest": "29.5.14",
38
42
  "@types/react-redux": "7.1.30",
39
43
  "@types/set-cookie-parser": "2.4.7",
40
44
  "@typescript-eslint/eslint-plugin": "6.7.4",
package/plugins.js CHANGED
@@ -15,5 +15,6 @@ module.exports = [
15
15
  'pz-saved-card',
16
16
  'pz-tabby-extension',
17
17
  'pz-apple-pay',
18
- 'pz-tamara-extension'
18
+ 'pz-tamara-extension',
19
+ 'pz-hepsipay'
19
20
  ];
@@ -0,0 +1,16 @@
1
+ const defaultPlugins = require('../plugins');
2
+
3
+ const getAkinonNextContent = (plugins = defaultPlugins) => {
4
+ return [
5
+ `./node_modules/@akinon/next/components/**/*.{js,ts,jsx,tsx}`,
6
+ `../../node_modules/@akinon/next/components/**/*.{js,ts,jsx,tsx}`,
7
+ ...plugins
8
+ .map((plugin) => [
9
+ `./node_modules/@akinon/${plugin}/**/*.{js,ts,jsx,tsx}`,
10
+ `../../node_modules/@akinon/${plugin}/**/*.{js,ts,jsx,tsx}`
11
+ ])
12
+ .flat()
13
+ ];
14
+ };
15
+
16
+ module.exports = getAkinonNextContent;
package/types/index.ts CHANGED
@@ -283,7 +283,13 @@ export interface ButtonProps
283
283
  target?: '_blank' | '_self' | '_parent' | '_top';
284
284
  }
285
285
 
286
- export type FileInputProps = React.HTMLProps<HTMLInputElement>;
286
+ export interface FileInputProps extends React.HTMLProps<HTMLInputElement> {
287
+ fileClassName?: string;
288
+ fileNameWrapperClassName?: string;
289
+ fileInputClassName?: string;
290
+ onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
291
+ buttonClassName?: string;
292
+ }
287
293
 
288
294
  export interface PriceProps {
289
295
  currencyCode?: string;
@@ -304,15 +310,19 @@ export interface InputProps extends React.HTMLProps<HTMLInputElement> {
304
310
 
305
311
  export interface AccordionProps {
306
312
  isCollapse?: boolean;
313
+ collapseClassName?: string;
307
314
  title?: string;
308
315
  subTitle?: string;
309
316
  icons?: string[];
310
317
  iconSize?: number;
311
318
  iconColor?: string;
312
319
  children?: ReactNode;
320
+ headerClassName?: string;
313
321
  className?: string;
314
322
  titleClassName?: string;
323
+ subTitleClassName?: string;
315
324
  dataTestId?: string;
325
+ contentClassName?: string;
316
326
  }
317
327
 
318
328
  export interface PluginModuleComponentProps {
@@ -337,3 +347,20 @@ export interface PaginationProps {
337
347
  direction?: 'next' | 'prev';
338
348
  isLoading?: boolean;
339
349
  }
350
+
351
+ export interface ModalProps {
352
+ portalId: string;
353
+ children?: React.ReactNode;
354
+ open?: boolean;
355
+ setOpen?: (open: boolean) => void;
356
+ title?: React.ReactNode;
357
+ showCloseButton?: React.ReactNode;
358
+ className?: string;
359
+ overlayClassName?: string;
360
+ headerWrapperClassName?: string;
361
+ titleClassName?: string;
362
+ closeButtonClassName?: string;
363
+ iconName?: string;
364
+ iconSize?: number;
365
+ iconClassName?: string;
366
+ }
@@ -0,0 +1,28 @@
1
+ import Settings from 'settings';
2
+
3
+ export default function getRootHostname(
4
+ url: string | undefined
5
+ ): string | null {
6
+ if (!url) return null;
7
+
8
+ try {
9
+ const urlObj = new URL(url);
10
+ const hostname = urlObj.hostname;
11
+ const parts = hostname.split('.');
12
+
13
+ const firstPart = parts[0];
14
+
15
+ const isLocale = Settings.localization.locales.some(
16
+ (locale) => locale.value === firstPart
17
+ );
18
+
19
+ if (isLocale) {
20
+ const hostnameAfterLocale = parts.slice(1).join('.');
21
+ return `.${hostnameAfterLocale}`;
22
+ }
23
+
24
+ return `.${hostname}`;
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
package/with-pz-config.js CHANGED
@@ -16,12 +16,8 @@ const defaultConfig = {
16
16
  remotePatterns: [
17
17
  {
18
18
  protocol: 'https',
19
- hostname: '**.akinoncloud.com'
19
+ hostname: '**'
20
20
  },
21
- {
22
- protocol: 'https',
23
- hostname: '**.akinoncdn.com'
24
- }
25
21
  ]
26
22
  },
27
23
  modularizeImports: {