@akinon/next 2.0.0-beta.2 → 2.0.0-beta.20
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/.eslintrc.js +12 -0
- package/CHANGELOG.md +377 -7
- package/__tests__/next-config.test.ts +83 -0
- package/__tests__/tsconfig.json +23 -0
- package/api/auth.ts +133 -44
- 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-prebuild.js +1 -0
- package/bin/pz-predev.js +1 -0
- package/bin/pz-run-tests.js +99 -0
- package/bin/run-prebuild-tests.js +46 -0
- package/components/accordion.tsx +20 -5
- package/components/button.tsx +51 -36
- package/components/client-root.tsx +138 -2
- package/components/file-input.tsx +65 -3
- package/components/index.ts +1 -0
- package/components/input.tsx +1 -1
- 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 +1 -1
- package/components/selected-payment-option-view.tsx +21 -0
- package/components/theme-editor/blocks/accordion-block.tsx +136 -0
- package/components/theme-editor/blocks/block-renderer-registry.tsx +77 -0
- package/components/theme-editor/blocks/button-block.tsx +593 -0
- package/components/theme-editor/blocks/counter-block.tsx +348 -0
- package/components/theme-editor/blocks/divider-block.tsx +20 -0
- package/components/theme-editor/blocks/embed-block.tsx +208 -0
- package/components/theme-editor/blocks/group-block.tsx +116 -0
- package/components/theme-editor/blocks/hotspot-block.tsx +147 -0
- package/components/theme-editor/blocks/icon-block.tsx +230 -0
- package/components/theme-editor/blocks/image-block.tsx +137 -0
- package/components/theme-editor/blocks/image-gallery-block.tsx +269 -0
- package/components/theme-editor/blocks/input-block.tsx +123 -0
- package/components/theme-editor/blocks/link-block.tsx +216 -0
- package/components/theme-editor/blocks/lottie-block.tsx +325 -0
- package/components/theme-editor/blocks/map-block.tsx +89 -0
- package/components/theme-editor/blocks/slider-block.tsx +595 -0
- package/components/theme-editor/blocks/tab-block.tsx +10 -0
- package/components/theme-editor/blocks/text-block.tsx +52 -0
- package/components/theme-editor/blocks/video-block.tsx +122 -0
- package/components/theme-editor/components/action-toolbar.tsx +305 -0
- package/components/theme-editor/components/designer-overlay.tsx +74 -0
- package/components/theme-editor/components/with-designer-features.tsx +142 -0
- package/components/theme-editor/dynamic-font-loader.tsx +79 -0
- package/components/theme-editor/hooks/use-designer-features.tsx +100 -0
- package/components/theme-editor/hooks/use-external-designer.tsx +95 -0
- package/components/theme-editor/hooks/use-native-widget-data.ts +188 -0
- package/components/theme-editor/hooks/use-visibility-context.ts +27 -0
- package/components/theme-editor/placeholder-registry.ts +31 -0
- package/components/theme-editor/sections/before-after-section.tsx +245 -0
- package/components/theme-editor/sections/contact-form-section.tsx +563 -0
- package/components/theme-editor/sections/countdown-campaign-banner-section.tsx +433 -0
- package/components/theme-editor/sections/coupon-banner-section.tsx +710 -0
- package/components/theme-editor/sections/divider-section.tsx +62 -0
- package/components/theme-editor/sections/featured-product-spotlight-section.tsx +507 -0
- package/components/theme-editor/sections/find-in-store-section.tsx +1995 -0
- package/components/theme-editor/sections/hover-showcase-section.tsx +326 -0
- package/components/theme-editor/sections/image-hotspot-section.tsx +142 -0
- package/components/theme-editor/sections/installment-options-section.tsx +1065 -0
- package/components/theme-editor/sections/notification-banner-section.tsx +173 -0
- package/components/theme-editor/sections/order-tracking-lookup-section.tsx +1379 -0
- package/components/theme-editor/sections/posts-slider-section.tsx +472 -0
- package/components/theme-editor/sections/pre-order-launch-banner-section.tsx +663 -0
- package/components/theme-editor/sections/section-renderer-registry.tsx +89 -0
- package/components/theme-editor/sections/section-wrapper.tsx +135 -0
- package/components/theme-editor/sections/shipping-threshold-progress-section.tsx +586 -0
- package/components/theme-editor/sections/stats-counter-section.tsx +486 -0
- package/components/theme-editor/sections/tabs-section.tsx +578 -0
- package/components/theme-editor/theme-block.tsx +102 -0
- package/components/theme-editor/theme-placeholder-client.tsx +218 -0
- package/components/theme-editor/theme-placeholder-wrapper.tsx +732 -0
- package/components/theme-editor/theme-placeholder.tsx +288 -0
- package/components/theme-editor/theme-section.tsx +1224 -0
- package/components/theme-editor/theme-settings-context.tsx +13 -0
- package/components/theme-editor/utils/index.ts +792 -0
- package/components/theme-editor/utils/iterator-utils.ts +234 -0
- package/components/theme-editor/utils/publish-window.ts +86 -0
- package/components/theme-editor/utils/visibility-rules.ts +188 -0
- package/data/client/account.ts +17 -2
- package/data/client/api.ts +2 -0
- package/data/client/basket.ts +66 -5
- package/data/client/checkout.ts +391 -99
- package/data/client/misc.ts +38 -2
- package/data/client/product.ts +19 -2
- package/data/client/user.ts +16 -8
- package/data/server/category.ts +11 -9
- package/data/server/flatpage.ts +11 -4
- package/data/server/form.ts +15 -4
- package/data/server/landingpage.ts +11 -4
- package/data/server/list.ts +5 -4
- package/data/server/menu.ts +11 -3
- package/data/server/product.ts +111 -55
- package/data/server/seo.ts +14 -4
- package/data/server/special-page.ts +5 -4
- package/data/server/widget.ts +90 -5
- package/data/urls.ts +16 -5
- package/hocs/client/with-segment-defaults.tsx +2 -2
- package/hocs/server/with-segment-defaults.tsx +65 -20
- package/hooks/index.ts +4 -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 +51 -14
- package/hooks/use-sentry-uncaught-errors.ts +24 -0
- package/instrumentation/index.ts +10 -1
- package/instrumentation/node.ts +2 -20
- package/jest.config.js +25 -0
- package/lib/cache-handler.mjs +534 -16
- package/lib/cache.ts +272 -37
- package/localization/index.ts +2 -1
- 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 +360 -215
- package/middlewares/index.ts +10 -2
- package/middlewares/locale.ts +34 -11
- 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 +11 -1
- package/middlewares/wallet-complete-redirection.ts +206 -0
- package/package.json +25 -10
- package/plugins.d.ts +19 -4
- package/plugins.js +10 -1
- package/redux/actions.ts +47 -0
- package/redux/middlewares/checkout.ts +63 -138
- package/redux/middlewares/index.ts +14 -10
- package/redux/middlewares/pre-order/address.ts +7 -2
- package/redux/middlewares/pre-order/attribute-based-shipping-option.ts +7 -1
- package/redux/middlewares/pre-order/data-source-shipping-option.ts +7 -1
- package/redux/middlewares/pre-order/delivery-option.ts +7 -1
- package/redux/middlewares/pre-order/index.ts +16 -10
- package/redux/middlewares/pre-order/installment-option.ts +8 -1
- package/redux/middlewares/pre-order/payment-option-reset.ts +37 -0
- package/redux/middlewares/pre-order/payment-option.ts +7 -1
- package/redux/middlewares/pre-order/pre-order-validation.ts +8 -3
- package/redux/middlewares/pre-order/redirection.ts +8 -2
- package/redux/middlewares/pre-order/set-pre-order.ts +6 -2
- package/redux/middlewares/pre-order/shipping-option.ts +7 -1
- package/redux/middlewares/pre-order/shipping-step.ts +5 -1
- package/redux/reducers/checkout.ts +23 -3
- package/redux/reducers/index.ts +11 -3
- package/redux/reducers/root.ts +7 -2
- package/redux/reducers/widget.ts +80 -0
- package/sentry/index.ts +69 -13
- package/tailwind/content.js +16 -0
- package/types/commerce/account.ts +5 -1
- package/types/commerce/checkout.ts +35 -1
- package/types/commerce/widget.ts +33 -0
- package/types/index.ts +101 -6
- 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 +64 -10
- package/utils/localization.ts +4 -0
- package/utils/mobile-3d-iframe.ts +8 -2
- package/utils/override-middleware.ts +7 -12
- 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/views/error-page.tsx +93 -0
- package/with-pz-config.js +13 -6
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
|
|
3
|
+
import { getCollectionWidgetData, getWidgetData, getWidgetSchemaData } from '@akinon/next/data/server';
|
|
4
|
+
import ThemePlaceholderWrapper from './theme-placeholder-wrapper';
|
|
5
|
+
import { Section } from './theme-section';
|
|
6
|
+
import { generateThemeCSS } from './utils';
|
|
7
|
+
|
|
8
|
+
type ThemePlaceholderData = {
|
|
9
|
+
theme_editor_placeholder: Array<{
|
|
10
|
+
section_slug: string;
|
|
11
|
+
order: number;
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
interface ThemePlaceholderProps {
|
|
16
|
+
slug: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default async function ThemePlaceholder({
|
|
20
|
+
slug
|
|
21
|
+
}: ThemePlaceholderProps) {
|
|
22
|
+
try {
|
|
23
|
+
let dataSources: any[] = [];
|
|
24
|
+
let themeSettings: Record<string, unknown> | null = null;
|
|
25
|
+
try {
|
|
26
|
+
const themeConfigData = await getWidgetData<any>({
|
|
27
|
+
slug: 'theme-config'
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (themeConfigData?.attributes?.theme_dataSources) {
|
|
31
|
+
try {
|
|
32
|
+
const raw = themeConfigData.attributes.theme_dataSources;
|
|
33
|
+
// Handle both plain string/array and { value: "..." } attribute format
|
|
34
|
+
const resolved =
|
|
35
|
+
typeof raw === 'string'
|
|
36
|
+
? raw
|
|
37
|
+
: typeof raw === 'object' && raw !== null && !Array.isArray(raw)
|
|
38
|
+
? (raw as { value?: any }).value ?? raw
|
|
39
|
+
: raw;
|
|
40
|
+
|
|
41
|
+
if (typeof resolved === 'string') {
|
|
42
|
+
dataSources = JSON.parse(resolved);
|
|
43
|
+
} else if (Array.isArray(resolved)) {
|
|
44
|
+
dataSources = resolved;
|
|
45
|
+
}
|
|
46
|
+
} catch (e) {
|
|
47
|
+
console.error('Failed to parse theme_dataSources:', e);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (themeConfigData?.attributes?.theme_settings) {
|
|
52
|
+
try {
|
|
53
|
+
const rawSettings = themeConfigData.attributes.theme_settings;
|
|
54
|
+
const resolvedValue =
|
|
55
|
+
typeof rawSettings === 'string'
|
|
56
|
+
? rawSettings
|
|
57
|
+
: typeof rawSettings === 'object' && rawSettings !== null
|
|
58
|
+
? (rawSettings as { value?: string }).value ?? rawSettings
|
|
59
|
+
: null;
|
|
60
|
+
|
|
61
|
+
if (resolvedValue) {
|
|
62
|
+
if (typeof resolvedValue === 'string') {
|
|
63
|
+
themeSettings = JSON.parse(resolvedValue);
|
|
64
|
+
} else if (typeof resolvedValue === 'object') {
|
|
65
|
+
themeSettings = resolvedValue as Record<string, unknown>;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch (e) {
|
|
69
|
+
console.error('Failed to parse theme_settings:', e);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch (configError) {}
|
|
73
|
+
|
|
74
|
+
const data = await getWidgetData<ThemePlaceholderData>({
|
|
75
|
+
slug
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const sections: Section[] = [];
|
|
79
|
+
|
|
80
|
+
if (data?.attributes?.theme_editor_placeholder) {
|
|
81
|
+
let placeholderData = data.attributes.theme_editor_placeholder;
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
typeof placeholderData === 'object' &&
|
|
85
|
+
placeholderData !== null &&
|
|
86
|
+
'value' in placeholderData
|
|
87
|
+
) {
|
|
88
|
+
placeholderData = (
|
|
89
|
+
placeholderData as {
|
|
90
|
+
value: { section_slug: string; order: number }[];
|
|
91
|
+
}
|
|
92
|
+
).value;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (typeof placeholderData === 'string') {
|
|
96
|
+
try {
|
|
97
|
+
placeholderData = JSON.parse(placeholderData);
|
|
98
|
+
} catch {
|
|
99
|
+
placeholderData = [];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!Array.isArray(placeholderData)) {
|
|
104
|
+
placeholderData = [];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const sectionPromises = placeholderData.map(async (item: any) => {
|
|
108
|
+
try {
|
|
109
|
+
const sectionSlug = item.value?.section_slug || item.section_slug;
|
|
110
|
+
const sectionOrder = item.value?.order ?? item.order ?? 0;
|
|
111
|
+
|
|
112
|
+
if (!sectionSlug) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const [regularSectionData, sectionSchema] = await Promise.all([
|
|
117
|
+
getWidgetData<any>({
|
|
118
|
+
slug: sectionSlug
|
|
119
|
+
}),
|
|
120
|
+
getWidgetSchemaData<any>({
|
|
121
|
+
widgetSlug: sectionSlug
|
|
122
|
+
})
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
let sectionData = regularSectionData;
|
|
126
|
+
if (!sectionData) {
|
|
127
|
+
try {
|
|
128
|
+
sectionData = await getCollectionWidgetData<any>({
|
|
129
|
+
slug: sectionSlug
|
|
130
|
+
});
|
|
131
|
+
} catch {
|
|
132
|
+
// Not a collection widget either; sectionData stays null
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const sectionSchemaEntry = sectionSchema?.schema?.[sectionSlug];
|
|
137
|
+
const sectionMetadata = sectionSchemaEntry?.metadata || {};
|
|
138
|
+
|
|
139
|
+
const getBlockValue = (blockId: string): unknown => {
|
|
140
|
+
const attrData = sectionData?.attributes?.[blockId];
|
|
141
|
+
if (attrData === undefined || attrData === null) return undefined;
|
|
142
|
+
|
|
143
|
+
if (typeof attrData === 'string') {
|
|
144
|
+
try {
|
|
145
|
+
return JSON.parse(attrData);
|
|
146
|
+
} catch {
|
|
147
|
+
return attrData;
|
|
148
|
+
}
|
|
149
|
+
} else if (typeof attrData === 'object' && 'value' in attrData) {
|
|
150
|
+
return attrData.value;
|
|
151
|
+
}
|
|
152
|
+
return attrData;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const reconstructBlock = (blockSchema: any): any => {
|
|
156
|
+
return {
|
|
157
|
+
id: blockSchema.id,
|
|
158
|
+
type: blockSchema.type || 'text',
|
|
159
|
+
label: blockSchema.label || blockSchema.id,
|
|
160
|
+
order: blockSchema.order || 0,
|
|
161
|
+
isIterator: blockSchema.isIterator,
|
|
162
|
+
iteratorDataPath: blockSchema.iteratorDataPath,
|
|
163
|
+
value: getBlockValue(blockSchema.id),
|
|
164
|
+
styles: blockSchema.styles || {},
|
|
165
|
+
properties: blockSchema.properties || {},
|
|
166
|
+
hidden: blockSchema.hidden || false,
|
|
167
|
+
blocks: (blockSchema.blocks || []).map((b: any) =>
|
|
168
|
+
reconstructBlock(b)
|
|
169
|
+
)
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const blocks: any[] = [];
|
|
174
|
+
if (sectionMetadata.blocks && Array.isArray(sectionMetadata.blocks)) {
|
|
175
|
+
sectionMetadata.blocks.forEach((blockSchema: any) => {
|
|
176
|
+
blocks.push(reconstructBlock(blockSchema));
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
blocks.sort((a, b) => a.order - b.order);
|
|
181
|
+
|
|
182
|
+
// dataSourceId may be stored in schema metadata OR in widget data attributes
|
|
183
|
+
// (theme editor saves it as a widget attribute when user selects a data source)
|
|
184
|
+
const dataSourceId =
|
|
185
|
+
sectionMetadata.dataSourceId ||
|
|
186
|
+
(getBlockValue('dataSourceId') as string | undefined) ||
|
|
187
|
+
(getBlockValue('selectedDataSourceId') as string | undefined);
|
|
188
|
+
|
|
189
|
+
const dataSource = dataSourceId
|
|
190
|
+
? dataSources.find((ds) => ds.id === dataSourceId)
|
|
191
|
+
: undefined;
|
|
192
|
+
|
|
193
|
+
let dataSourceWithData = dataSource;
|
|
194
|
+
if (dataSource && dataSource.details) {
|
|
195
|
+
// Only fetch collection data if we have a valid widget slug
|
|
196
|
+
// (not the section's own slug which contains config, not products)
|
|
197
|
+
const collectionSlug = dataSource.details.collection?.slug;
|
|
198
|
+
if (collectionSlug) {
|
|
199
|
+
try {
|
|
200
|
+
let collectionData = await getWidgetData<{
|
|
201
|
+
[key: string]: unknown;
|
|
202
|
+
}>({
|
|
203
|
+
slug: collectionSlug
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
if (!collectionData) {
|
|
207
|
+
collectionData = await getCollectionWidgetData<{
|
|
208
|
+
[key: string]: unknown;
|
|
209
|
+
}>({
|
|
210
|
+
slug: collectionSlug
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (collectionData) {
|
|
215
|
+
dataSourceWithData = {
|
|
216
|
+
...dataSource,
|
|
217
|
+
details: {
|
|
218
|
+
...dataSource.details,
|
|
219
|
+
collection: {
|
|
220
|
+
...dataSource.details.collection,
|
|
221
|
+
data: collectionData
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.error(
|
|
228
|
+
`Error fetching widget data for section ${sectionSlug}:`,
|
|
229
|
+
error
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// If no collection slug, the saved products from editor
|
|
234
|
+
// (details.collection.products) will be used as fallback
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const section: Section = {
|
|
238
|
+
id: sectionSlug,
|
|
239
|
+
type: sectionMetadata.type || 'default',
|
|
240
|
+
name: sectionMetadata.name || sectionSlug,
|
|
241
|
+
label: sectionMetadata.label || sectionSlug,
|
|
242
|
+
properties: sectionMetadata.properties || {},
|
|
243
|
+
styles: sectionMetadata.styles || {},
|
|
244
|
+
blocks,
|
|
245
|
+
order: sectionOrder,
|
|
246
|
+
hidden: sectionMetadata.hidden || false,
|
|
247
|
+
dataSourceId,
|
|
248
|
+
dataSource: dataSourceWithData
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
return section;
|
|
252
|
+
} catch (error) {
|
|
253
|
+
const errorSlug =
|
|
254
|
+
item.value?.section_slug || item.section_slug || 'unknown';
|
|
255
|
+
console.error(
|
|
256
|
+
`Error parsing section metadata for ${errorSlug}:`,
|
|
257
|
+
error
|
|
258
|
+
);
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const resolvedSections = await Promise.all(sectionPromises);
|
|
264
|
+
sections.push(
|
|
265
|
+
...resolvedSections.filter((s): s is Section => s !== null)
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const themeCSS = generateThemeCSS(sections);
|
|
270
|
+
|
|
271
|
+
return (
|
|
272
|
+
<>
|
|
273
|
+
{themeCSS && <style dangerouslySetInnerHTML={{ __html: themeCSS }} />}
|
|
274
|
+
<ThemePlaceholderWrapper
|
|
275
|
+
slug={slug}
|
|
276
|
+
initialSections={sections}
|
|
277
|
+
initialPlaceholderId={data?.slug?.toString() || ''}
|
|
278
|
+
isDesignMode={false}
|
|
279
|
+
dataSources={dataSources}
|
|
280
|
+
initialThemeSettings={themeSettings}
|
|
281
|
+
/>
|
|
282
|
+
</>
|
|
283
|
+
);
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error(`Error fetching theme placeholder data for ${slug}:`, error);
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
}
|