@akinon/next 2.0.0-beta.9 → 2.0.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 +434 -23
- package/__tests__/next-config.test.ts +83 -0
- package/__tests__/tsconfig.json +23 -0
- package/api/auth.ts +367 -63
- package/api/barcode-search.ts +59 -0
- package/api/cache.ts +41 -5
- package/api/client.ts +21 -4
- package/api/form.ts +85 -0
- package/api/image-proxy.ts +75 -0
- package/api/product-categories.ts +53 -0
- package/api/similar-product-list.ts +63 -0
- package/api/similar-products.ts +111 -0
- package/api/virtual-try-on.ts +382 -0
- package/assets/styles/index.scss +84 -0
- package/babel.config.js +6 -0
- package/bin/pz-generate-routes.js +115 -0
- package/bin/pz-install-plugins.js +1 -1
- package/bin/pz-prebuild.js +1 -0
- package/bin/pz-predev.js +1 -0
- package/bin/pz-run-tests.js +99 -0
- package/components/accordion.tsx +21 -6
- package/components/client-root.tsx +119 -3
- package/components/file-input.tsx +65 -3
- package/components/index.ts +1 -0
- package/components/input.tsx +2 -2
- package/components/link.tsx +46 -16
- package/components/logger-popup.tsx +213 -0
- package/components/modal.tsx +32 -16
- package/components/plugin-module.tsx +62 -3
- package/components/price.tsx +2 -2
- package/components/select.tsx +3 -3
- package/components/selected-payment-option-view.tsx +21 -0
- package/data/client/account.ts +17 -2
- package/data/client/basket.ts +39 -0
- package/data/client/checkout.ts +336 -99
- package/data/client/misc.ts +13 -1
- package/data/server/category.ts +11 -9
- package/data/server/flatpage.ts +4 -1
- package/data/server/form.ts +4 -1
- package/data/server/landingpage.ts +4 -1
- package/data/server/list.ts +5 -4
- package/data/server/menu.ts +4 -1
- package/data/server/product.ts +97 -52
- package/data/server/seo.ts +4 -1
- package/data/server/special-page.ts +5 -4
- package/data/server/widget.ts +71 -1
- package/data/urls.ts +6 -3
- package/hocs/client/with-segment-defaults.tsx +2 -2
- package/hocs/server/with-segment-defaults.tsx +81 -20
- package/hooks/index.ts +3 -0
- package/hooks/use-localization.ts +24 -10
- package/hooks/use-logger-context.tsx +114 -0
- package/hooks/use-logger.ts +92 -0
- package/hooks/use-loyalty-availability.ts +21 -0
- package/hooks/use-payment-options.ts +2 -1
- package/hooks/use-pz-params.ts +37 -0
- package/hooks/use-router.ts +53 -19
- package/instrumentation/index.ts +0 -1
- package/instrumentation/node.ts +2 -20
- package/jest.config.js +25 -0
- package/lib/cache-handler.mjs +534 -16
- package/lib/cache.ts +269 -34
- package/localization/provider.tsx +2 -5
- package/middlewares/bfcache-headers.ts +18 -0
- package/middlewares/checkout-provider.ts +1 -1
- package/middlewares/complete-gpay.ts +32 -26
- package/middlewares/complete-masterpass.ts +33 -26
- package/middlewares/complete-wallet.ts +182 -0
- package/middlewares/default.ts +357 -203
- package/middlewares/index.ts +10 -2
- package/middlewares/locale.ts +5 -3
- package/middlewares/masterpass-rest-callback.ts +230 -0
- package/middlewares/oauth-login.ts +200 -57
- package/middlewares/pretty-url.ts +21 -8
- package/middlewares/redirection-payment.ts +32 -26
- package/middlewares/saved-card-redirection.ts +33 -26
- package/middlewares/three-d-redirection.ts +32 -26
- package/middlewares/url-redirection.ts +9 -15
- package/middlewares/wallet-complete-redirection.ts +206 -0
- package/package.json +24 -10
- package/plugins.d.ts +19 -4
- package/plugins.js +9 -1
- package/redux/actions.ts +47 -0
- package/redux/middlewares/checkout.ts +61 -8
- package/redux/middlewares/index.ts +14 -10
- package/redux/middlewares/pre-order/address.ts +1 -1
- package/redux/middlewares/pre-order/attribute-based-shipping-option.ts +1 -1
- package/redux/middlewares/pre-order/data-source-shipping-option.ts +1 -1
- package/redux/middlewares/pre-order/delivery-option.ts +1 -1
- package/redux/middlewares/pre-order/index.ts +3 -1
- package/redux/middlewares/pre-order/installment-option.ts +2 -1
- package/redux/middlewares/pre-order/payment-option-reset.ts +37 -0
- package/redux/middlewares/pre-order/payment-option.ts +1 -1
- package/redux/middlewares/pre-order/pre-order-validation.ts +4 -3
- package/redux/middlewares/pre-order/redirection.ts +2 -2
- package/redux/middlewares/pre-order/set-pre-order.ts +2 -2
- package/redux/middlewares/pre-order/shipping-option.ts +1 -1
- package/redux/middlewares/pre-order/shipping-step.ts +1 -1
- package/redux/reducers/checkout.ts +15 -1
- package/redux/reducers/index.ts +7 -1
- package/redux/reducers/widget.ts +80 -0
- package/sentry/index.ts +54 -17
- package/tailwind/content.js +16 -0
- package/types/commerce/checkout.ts +26 -1
- package/types/commerce/widget.ts +33 -0
- package/types/index.ts +114 -5
- package/types/next-auth.d.ts +2 -2
- package/types/widget.ts +80 -0
- package/utils/app-fetch.ts +7 -2
- package/utils/generate-commerce-search-params.ts +3 -2
- package/utils/get-checkout-path.ts +3 -0
- package/utils/get-root-hostname.ts +28 -0
- package/utils/index.ts +69 -18
- package/utils/mobile-3d-iframe.ts +8 -2
- package/utils/override-middleware.ts +1 -0
- package/utils/pz-segments.ts +92 -0
- package/utils/redirect-ignore.ts +35 -0
- package/utils/redirect.ts +9 -3
- package/utils/redirection-iframe.ts +8 -2
- package/utils/widget-styles.ts +107 -0
- package/with-pz-config.js +20 -7
package/utils/index.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import settings from 'settings';
|
|
2
2
|
import { LocaleUrlStrategy } from '../localization';
|
|
3
|
-
import { CDNOptions, ClientRequestOptions,
|
|
3
|
+
import { CDNOptions, ClientRequestOptions, SetCookieOptions } from '../types';
|
|
4
|
+
import getRootHostname from './get-root-hostname';
|
|
4
5
|
|
|
5
6
|
export * from './get-currency';
|
|
6
7
|
export * from './menu-generator';
|
|
7
8
|
export * from './generate-commerce-search-params';
|
|
8
9
|
export * from './get-currency-label';
|
|
10
|
+
export * from './pz-segments';
|
|
11
|
+
export * from './get-checkout-path';
|
|
9
12
|
|
|
10
13
|
export function getCookie(name: string) {
|
|
11
14
|
if (typeof document === 'undefined') {
|
|
@@ -20,14 +23,40 @@ export function getCookie(name: string) {
|
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
export function setCookie(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
export function setCookie(
|
|
27
|
+
name: string,
|
|
28
|
+
value: string,
|
|
29
|
+
options: SetCookieOptions = {}
|
|
30
|
+
) {
|
|
31
|
+
const cookieParts = [`${name}=${value}`];
|
|
32
|
+
|
|
33
|
+
if (options.expires) {
|
|
34
|
+
const date = new Date();
|
|
35
|
+
date.setTime(date.getTime() + options.expires * 24 * 60 * 60 * 1000);
|
|
36
|
+
cookieParts.push(`expires=${date.toUTCString()}`);
|
|
37
|
+
}
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
cookieParts.push(`path=${options.path ?? '/'}`);
|
|
40
|
+
|
|
41
|
+
if (options.secure) {
|
|
42
|
+
cookieParts.push('secure');
|
|
43
|
+
}
|
|
28
44
|
|
|
29
|
-
|
|
30
|
-
|
|
45
|
+
if (options.sameSite) {
|
|
46
|
+
cookieParts.push(`sameSite=${options.sameSite}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const domain =
|
|
50
|
+
options.domain ??
|
|
51
|
+
(settings.localization.localeUrlStrategy === LocaleUrlStrategy.Subdomain
|
|
52
|
+
? getRootHostname(document.location.href)
|
|
53
|
+
: null);
|
|
54
|
+
|
|
55
|
+
if (domain) {
|
|
56
|
+
cookieParts.push(`domain=${domain}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
document.cookie = cookieParts.join('; ');
|
|
31
60
|
}
|
|
32
61
|
|
|
33
62
|
export function removeCookie(name: string) {
|
|
@@ -152,23 +181,28 @@ export function buildCDNUrl(url: string, config?: CDNOptions) {
|
|
|
152
181
|
return `${rootWithoutOptions}${options}${fileExtension}`;
|
|
153
182
|
}
|
|
154
183
|
|
|
155
|
-
const { locales, localeUrlStrategy, defaultLocaleValue } =
|
|
156
|
-
settings.localization;
|
|
157
|
-
|
|
158
|
-
const isLocaleExcluded = (locale: Locale) =>
|
|
159
|
-
![LocaleUrlStrategy.ShowAllLocales, LocaleUrlStrategy.Subdomain].includes(
|
|
160
|
-
localeUrlStrategy
|
|
161
|
-
) && locale.value !== defaultLocaleValue;
|
|
162
|
-
|
|
163
184
|
export const urlLocaleMatcherRegex = new RegExp(
|
|
164
|
-
`^/(${locales
|
|
165
|
-
.filter((l) =>
|
|
185
|
+
`^/(${settings.localization.locales
|
|
186
|
+
.filter((l) =>
|
|
187
|
+
![LocaleUrlStrategy.ShowAllLocales, LocaleUrlStrategy.Subdomain].includes(
|
|
188
|
+
settings.localization.localeUrlStrategy
|
|
189
|
+
)
|
|
190
|
+
? l.value !== settings.localization.defaultLocaleValue
|
|
191
|
+
: l
|
|
192
|
+
)
|
|
166
193
|
.map((l) => l.value)
|
|
167
194
|
.join('|')})(?=/|$)`
|
|
168
195
|
);
|
|
169
196
|
|
|
170
197
|
export const getPosError = () => {
|
|
171
|
-
const
|
|
198
|
+
const cookieValue = getCookie('pz-pos-error');
|
|
199
|
+
let decoded: string;
|
|
200
|
+
try {
|
|
201
|
+
decoded = cookieValue ? decodeURIComponent(cookieValue) : '{}';
|
|
202
|
+
} catch {
|
|
203
|
+
decoded = cookieValue ?? '{}';
|
|
204
|
+
}
|
|
205
|
+
const error = JSON.parse(decoded);
|
|
172
206
|
|
|
173
207
|
// delete 'pz-pos-error' cookie when refreshing or closing page
|
|
174
208
|
window.addEventListener('beforeunload', () => {
|
|
@@ -178,6 +212,23 @@ export const getPosError = () => {
|
|
|
178
212
|
return error;
|
|
179
213
|
};
|
|
180
214
|
|
|
215
|
+
export const checkPaymentWillRedirect = (response: {
|
|
216
|
+
context_list?: Array<{
|
|
217
|
+
page_name: string;
|
|
218
|
+
page_context?: { context_data?: { redirect_url?: string } };
|
|
219
|
+
}>;
|
|
220
|
+
redirect_url?: string;
|
|
221
|
+
errors?: unknown;
|
|
222
|
+
}): boolean => {
|
|
223
|
+
if (!response) return false;
|
|
224
|
+
|
|
225
|
+
const hasThankYouPage = response.context_list?.some(
|
|
226
|
+
(c) => c.page_name === 'ThankYouPage'
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
return Boolean(hasThankYouPage || response.redirect_url);
|
|
230
|
+
};
|
|
231
|
+
|
|
181
232
|
export const urlSchemes = [
|
|
182
233
|
'http',
|
|
183
234
|
'tel:',
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
const iframeURLChange = (iframe, callback) => {
|
|
2
2
|
iframe.addEventListener('load', () => {
|
|
3
3
|
setTimeout(() => {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
try {
|
|
5
|
+
if (iframe?.contentWindow?.location) {
|
|
6
|
+
const iframeLocation = iframe.contentWindow.location;
|
|
7
|
+
|
|
8
|
+
callback(iframeLocation);
|
|
9
|
+
}
|
|
10
|
+
} catch (error) {
|
|
11
|
+
// Expected: browser blocks cross-origin iframe access for security
|
|
6
12
|
}
|
|
7
13
|
}, 0);
|
|
8
14
|
});
|
|
@@ -10,6 +10,7 @@ export enum MiddlewareNames {
|
|
|
10
10
|
DataSourceShippingOptionMiddleware = 'dataSourceShippingOptionMiddleware',
|
|
11
11
|
AttributeBasedShippingOptionMiddleware = 'attributeBasedShippingOptionMiddleware',
|
|
12
12
|
PaymentOptionMiddleware = 'paymentOptionMiddleware',
|
|
13
|
+
PaymentOptionResetMiddleware = 'paymentOptionResetMiddleware',
|
|
13
14
|
InstallmentOptionMiddleware = 'installmentOptionMiddleware',
|
|
14
15
|
ShippingStepMiddleware = 'shippingStepMiddleware'
|
|
15
16
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { PzSegmentDefinition, PzSegmentsConfig } from '../types';
|
|
2
|
+
|
|
3
|
+
export function isLegacyMode(settings: any): boolean {
|
|
4
|
+
return !settings.usePzSegment;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const DEFAULT_SEPARATOR = '--';
|
|
8
|
+
|
|
9
|
+
const DEFAULT_SEGMENTS: PzSegmentDefinition[] = [
|
|
10
|
+
{ name: 'locale' },
|
|
11
|
+
{ name: 'currency' },
|
|
12
|
+
{ name: 'url' }
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export function getPzSegmentsConfig(settings: any): PzSegmentsConfig {
|
|
16
|
+
if (settings.pzSegments) {
|
|
17
|
+
const customSegments = (settings.pzSegments.segments ?? []).filter(
|
|
18
|
+
(seg: PzSegmentDefinition) =>
|
|
19
|
+
!DEFAULT_SEGMENTS.some((d) => d.name === seg.name)
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
separator: settings.pzSegments.separator ?? DEFAULT_SEPARATOR,
|
|
24
|
+
segments: [...DEFAULT_SEGMENTS, ...customSegments]
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
separator: DEFAULT_SEPARATOR,
|
|
30
|
+
segments: DEFAULT_SEGMENTS
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function encodePzValue(
|
|
35
|
+
values: Record<string, string>,
|
|
36
|
+
config: PzSegmentsConfig
|
|
37
|
+
): string {
|
|
38
|
+
return config.segments
|
|
39
|
+
.map((seg) => values[seg.name] ?? '')
|
|
40
|
+
.join(config.separator);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function decodePzValue(
|
|
44
|
+
pzValue: string,
|
|
45
|
+
config: PzSegmentsConfig
|
|
46
|
+
): Record<string, string> {
|
|
47
|
+
const parts = pzValue.split(config.separator);
|
|
48
|
+
const result: Record<string, string> = {};
|
|
49
|
+
|
|
50
|
+
config.segments.forEach((seg, index) => {
|
|
51
|
+
result[seg.name] = parts[index] ?? '';
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getBuiltInSegments(
|
|
58
|
+
parsed: Record<string, string>,
|
|
59
|
+
settings: any
|
|
60
|
+
): { locale: string; currency: string; url: string } {
|
|
61
|
+
const { defaultLocaleValue, defaultCurrencyCode } = settings.localization;
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
locale: parsed.locale || defaultLocaleValue,
|
|
65
|
+
currency: parsed.currency || defaultCurrencyCode,
|
|
66
|
+
url: parsed.url ? decodeURIComponent(parsed.url) : ''
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function parsePzParams(
|
|
71
|
+
params: { pz?: string; locale?: string; currency?: string; url?: string },
|
|
72
|
+
settings: any
|
|
73
|
+
): { locale: string; currency: string; url: string; [key: string]: string } {
|
|
74
|
+
if (isLegacyMode(settings)) {
|
|
75
|
+
return {
|
|
76
|
+
locale:
|
|
77
|
+
params.locale ?? settings.localization.defaultLocaleValue,
|
|
78
|
+
currency:
|
|
79
|
+
params.currency ?? settings.localization.defaultCurrencyCode,
|
|
80
|
+
url: params.url ? decodeURIComponent(params.url) : ''
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const config = getPzSegmentsConfig(settings);
|
|
85
|
+
const parsed = decodePzValue(params.pz ?? '', config);
|
|
86
|
+
const builtIn = getBuiltInSegments(parsed, settings);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
...parsed,
|
|
90
|
+
...builtIn
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import settings from 'settings';
|
|
2
|
+
import { getUrlPathWithLocale } from './localization';
|
|
3
|
+
|
|
4
|
+
type IgnorePath = string | RegExp;
|
|
5
|
+
|
|
6
|
+
const defaultIgnoreList: string[] = [];
|
|
7
|
+
|
|
8
|
+
const extraIgnores: IgnorePath[] = Array.isArray(
|
|
9
|
+
settings.commerceRedirectionIgnoreList
|
|
10
|
+
)
|
|
11
|
+
? settings.commerceRedirectionIgnoreList.map((path) => {
|
|
12
|
+
if (path === '/users/reset') {
|
|
13
|
+
return /^\/users\/reset\/[^/]+\/[^/]+\/$/;
|
|
14
|
+
}
|
|
15
|
+
return path;
|
|
16
|
+
})
|
|
17
|
+
: [];
|
|
18
|
+
|
|
19
|
+
export function shouldIgnoreRedirect(
|
|
20
|
+
pathname: string,
|
|
21
|
+
locale: string
|
|
22
|
+
): boolean {
|
|
23
|
+
if (!pathname) return false;
|
|
24
|
+
|
|
25
|
+
const rawIgnoreList: IgnorePath[] = [...defaultIgnoreList, ...extraIgnores];
|
|
26
|
+
|
|
27
|
+
return rawIgnoreList.some((ignorePath) => {
|
|
28
|
+
if (ignorePath instanceof RegExp) {
|
|
29
|
+
return ignorePath.test(pathname);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const localized = getUrlPathWithLocale(ignorePath, locale);
|
|
33
|
+
return localized === pathname;
|
|
34
|
+
});
|
|
35
|
+
}
|
package/utils/redirect.ts
CHANGED
|
@@ -3,21 +3,27 @@ import Settings from 'settings';
|
|
|
3
3
|
import { headers } from 'next/headers';
|
|
4
4
|
import { ServerVariables } from '@akinon/next/utils/server-variables';
|
|
5
5
|
import { getUrlPathWithLocale } from '@akinon/next/utils/localization';
|
|
6
|
+
import { urlLocaleMatcherRegex } from '@akinon/next/utils';
|
|
6
7
|
|
|
7
8
|
export const redirect = async (path: string, type?: RedirectType) => {
|
|
8
9
|
const nextHeaders = await headers();
|
|
9
10
|
const pageUrl = new URL(
|
|
10
|
-
nextHeaders.get('pz-url') ?? process.env.NEXT_PUBLIC_URL
|
|
11
|
+
nextHeaders.get('pz-url') ?? process.env.NEXT_PUBLIC_URL ?? ''
|
|
11
12
|
);
|
|
12
13
|
|
|
13
14
|
const currentLocale = Settings.localization.locales.find(
|
|
14
15
|
(locale) => locale.value === ServerVariables.locale
|
|
15
16
|
);
|
|
16
17
|
|
|
17
|
-
const
|
|
18
|
+
const searchParams = new URLSearchParams(pageUrl.search);
|
|
19
|
+
|
|
20
|
+
const callbackUrl =
|
|
21
|
+
pageUrl.pathname.replace(urlLocaleMatcherRegex, '') +
|
|
22
|
+
(searchParams.toString() ? `?${searchParams.toString()}` : '');
|
|
23
|
+
|
|
18
24
|
const redirectUrlWithLocale = getUrlPathWithLocale(
|
|
19
25
|
path,
|
|
20
|
-
currentLocale
|
|
26
|
+
currentLocale?.value
|
|
21
27
|
);
|
|
22
28
|
|
|
23
29
|
const redirectUrl = `${redirectUrlWithLocale}?callbackUrl=${callbackUrl}`;
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
const iframeURLChange = (iframe, callback) => {
|
|
2
2
|
iframe.addEventListener('load', () => {
|
|
3
3
|
setTimeout(() => {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
try {
|
|
5
|
+
if (iframe?.contentWindow?.location) {
|
|
6
|
+
const iframeLocation = iframe.contentWindow.location;
|
|
7
|
+
|
|
8
|
+
callback(iframeLocation);
|
|
9
|
+
}
|
|
10
|
+
} catch (error) {
|
|
11
|
+
// Expected: browser blocks cross-origin iframe access for security
|
|
6
12
|
}
|
|
7
13
|
}, 0);
|
|
8
14
|
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const kebabize = (str: string) => {
|
|
2
|
+
return str.replace(
|
|
3
|
+
/[A-Z]+(?![a-z])|[A-Z]/g,
|
|
4
|
+
($, ofs) => (ofs ? '-' : '') + $.toLowerCase()
|
|
5
|
+
);
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const formatCssValue = (value: string | number) => {
|
|
9
|
+
return /^\d+$/.test(value.toString()) ? `${value}px` : value;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
interface NodeProperties {
|
|
13
|
+
style?: Record<string, any>;
|
|
14
|
+
parent_id?: string;
|
|
15
|
+
type?: string;
|
|
16
|
+
tag?: string;
|
|
17
|
+
breakpoints?: any[];
|
|
18
|
+
dataSources?: any[];
|
|
19
|
+
is_slider?: boolean;
|
|
20
|
+
iteratingNode?: string;
|
|
21
|
+
iteratorValue?: string;
|
|
22
|
+
selectedDataSourceId?: string;
|
|
23
|
+
order?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface Node {
|
|
27
|
+
key: string;
|
|
28
|
+
properties: NodeProperties;
|
|
29
|
+
label?: string;
|
|
30
|
+
data_type?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const processNode = (node: Node, selector = '', styles: string[] = []) => {
|
|
34
|
+
const { key, properties } = node;
|
|
35
|
+
const { style } = properties;
|
|
36
|
+
|
|
37
|
+
if (key && style) {
|
|
38
|
+
const baseStyles: Record<string, any> = {};
|
|
39
|
+
const breakpointStyles: Record<string, Record<string, any>> = {};
|
|
40
|
+
|
|
41
|
+
Object.entries(style).forEach(([prop, val]) => {
|
|
42
|
+
if (typeof val === 'object') {
|
|
43
|
+
breakpointStyles[prop] = val;
|
|
44
|
+
} else {
|
|
45
|
+
baseStyles[prop] = val;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const baseCssRules = Object.entries(baseStyles)
|
|
50
|
+
.map(([prop, val]) => `${kebabize(prop)}: ${formatCssValue(val)};`)
|
|
51
|
+
.join(' ');
|
|
52
|
+
|
|
53
|
+
if (baseCssRules) {
|
|
54
|
+
styles.push(`${selector} { ${baseCssRules} }`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Object.keys(breakpointStyles)
|
|
58
|
+
.map((bp) => parseInt(bp, 10))
|
|
59
|
+
.sort((a, b) => a - b)
|
|
60
|
+
.forEach((bp) => {
|
|
61
|
+
const bpCssRules = Object.entries(breakpointStyles[bp])
|
|
62
|
+
.map(([prop, val]) => `${kebabize(prop)}: ${formatCssValue(val)};`)
|
|
63
|
+
.join(' ');
|
|
64
|
+
|
|
65
|
+
if (bpCssRules) {
|
|
66
|
+
styles.push(
|
|
67
|
+
`@media only screen and (min-width: ${bp}px) { ${selector} { ${bpCssRules} } }`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return styles;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const componentToCss = (components: Record<string, Node>) => {
|
|
77
|
+
const styles: string[] = [];
|
|
78
|
+
const componentsById: Record<string, Node> = {};
|
|
79
|
+
|
|
80
|
+
Object.values(components).forEach((component) => {
|
|
81
|
+
componentsById[component.key] = component;
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const addStylesForComponent = (component: Node) => {
|
|
85
|
+
const selector = `[data-id="${component.key}"]`;
|
|
86
|
+
processNode(component, selector, styles);
|
|
87
|
+
|
|
88
|
+
Object.values(componentsById)
|
|
89
|
+
.filter((child) => child.properties.parent_id === component.key)
|
|
90
|
+
.forEach(addStylesForComponent);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
Object.values(componentsById)
|
|
94
|
+
.filter((component) => !component.properties?.parent_id)
|
|
95
|
+
.forEach(addStylesForComponent);
|
|
96
|
+
|
|
97
|
+
return styles.join(' ');
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const generateWidgetStyles = (widgetSchemas: Record<string, Node>[]) => {
|
|
101
|
+
return widgetSchemas
|
|
102
|
+
.filter((schema) => Object.keys(schema).length > 0)
|
|
103
|
+
.map((data) => componentToCss(data))
|
|
104
|
+
.join('\n');
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export type { Node, NodeProperties };
|
package/with-pz-config.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
+
const path = require('path');
|
|
1
2
|
const pzPlugins = require('./plugins');
|
|
2
3
|
const deepMerge = require('./utils/deep-merge');
|
|
3
4
|
|
|
4
5
|
/** @type {import('next').NextConfig} */
|
|
5
6
|
const defaultConfig = {
|
|
6
|
-
experimental: { instrumentationHook: true },
|
|
7
7
|
reactStrictMode: true,
|
|
8
|
-
transpilePackages: ['@akinon/next', ...pzPlugins.map((p) => `@akinon/${p}`)],
|
|
8
|
+
transpilePackages: ['@akinon/next', '@akinon/pz-theme', ...pzPlugins.map((p) => `@akinon/${p}`)],
|
|
9
9
|
skipTrailingSlashRedirect: true,
|
|
10
10
|
poweredByHeader: false,
|
|
11
11
|
cacheMaxMemorySize: 0,
|
|
12
|
+
output: 'standalone',
|
|
13
|
+
compress: false,
|
|
12
14
|
env: {
|
|
13
15
|
NEXT_PUBLIC_SENTRY_DSN: process.env.SENTRY_DSN
|
|
14
16
|
},
|
|
15
17
|
images: {
|
|
16
18
|
remotePatterns: [
|
|
19
|
+
//It has to be like this for security reasons
|
|
17
20
|
{
|
|
18
21
|
protocol: 'https',
|
|
19
22
|
hostname: '**.akinoncloud.com'
|
|
@@ -46,13 +49,19 @@ const defaultConfig = {
|
|
|
46
49
|
{
|
|
47
50
|
key: 'Content-Security-Policy',
|
|
48
51
|
value:
|
|
49
|
-
"frame-ancestors 'self' https://*.akifast.com akifast.com https://*.akinoncloud.com akinoncloud.com"
|
|
52
|
+
"frame-ancestors 'self' https://*.akifast.com akifast.com https://*.akinoncloud.com akinoncloud.com http://localhost:5174 localhost:5174"
|
|
50
53
|
}
|
|
51
54
|
]
|
|
52
55
|
}
|
|
53
56
|
];
|
|
54
57
|
},
|
|
55
58
|
webpack: (config, options) => {
|
|
59
|
+
// Alias 'redux/store' to the app's local redux/store module to prevent
|
|
60
|
+
// collision with the npm 'redux' package's exports field
|
|
61
|
+
config.resolve.alias = {
|
|
62
|
+
...config.resolve.alias,
|
|
63
|
+
'redux/store': path.resolve(process.cwd(), 'src/redux/store')
|
|
64
|
+
};
|
|
56
65
|
config.resolve.fallback = {
|
|
57
66
|
...config.resolve.fallback,
|
|
58
67
|
...pzPlugins.reduce((acc, plugin) => {
|
|
@@ -61,11 +70,15 @@ const defaultConfig = {
|
|
|
61
70
|
}, {}),
|
|
62
71
|
translations: false
|
|
63
72
|
};
|
|
73
|
+
// Ensure webpack can resolve deps from the app's node_modules when
|
|
74
|
+
// compiling transpiled packages (e.g. @akinon/next) whose imports
|
|
75
|
+
// may not be hoisted to the monorepo root.
|
|
76
|
+
const appNodeModules = path.resolve(process.cwd(), 'node_modules');
|
|
77
|
+
if (!config.resolve.modules.includes(appNodeModules)) {
|
|
78
|
+
config.resolve.modules.push(appNodeModules);
|
|
79
|
+
}
|
|
64
80
|
return config;
|
|
65
|
-
}
|
|
66
|
-
sentry: {
|
|
67
|
-
hideSourceMaps: true
|
|
68
|
-
} // TODO: This section will be reviewed again in the Sentry 8 update.
|
|
81
|
+
}
|
|
69
82
|
};
|
|
70
83
|
|
|
71
84
|
const withPzConfig = (
|