@foxpixel/react 0.2.2 → 0.2.3
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/dist/index.d.mts +30 -5
- package/dist/index.d.ts +30 -5
- package/dist/index.js +113 -83
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +113 -83
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.d.mts
CHANGED
|
@@ -22,6 +22,10 @@ interface FoxPixelConfig {
|
|
|
22
22
|
* Tenant ID (optional, can be set per request)
|
|
23
23
|
*/
|
|
24
24
|
tenantId?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Current locale for site content i18n (e.g. "en", "pt"). Omit for default.
|
|
27
|
+
*/
|
|
28
|
+
locale?: string;
|
|
25
29
|
}
|
|
26
30
|
interface Service {
|
|
27
31
|
id: string;
|
|
@@ -140,6 +144,8 @@ interface FoxPixelContextValue {
|
|
|
140
144
|
config: FoxPixelConfig;
|
|
141
145
|
/** Optional: pass QueryClient so edit-mode messaging can invalidate cache without requiring useQueryClient() in SDK (avoids "No QueryClient set" in iframe). */
|
|
142
146
|
queryClient?: QueryClient | null;
|
|
147
|
+
/** Current locale for site content i18n (e.g. "en", "pt"). From config.locale. */
|
|
148
|
+
locale?: string;
|
|
143
149
|
}
|
|
144
150
|
interface FoxPixelProviderProps {
|
|
145
151
|
children: ReactNode;
|
|
@@ -274,8 +280,10 @@ interface EditableProps {
|
|
|
274
280
|
as?: keyof JSX.IntrinsicElements;
|
|
275
281
|
multiline?: boolean;
|
|
276
282
|
className?: string;
|
|
283
|
+
/** Override locale for this editable (default: from FoxPixelProvider config.locale). */
|
|
284
|
+
locale?: string;
|
|
277
285
|
}
|
|
278
|
-
declare function Editable({ contentKey, defaultValue, as, multiline, className, }: EditableProps): React.ReactElement<{
|
|
286
|
+
declare function Editable({ contentKey, defaultValue, as, multiline, className, locale: localeProp, }: EditableProps): React.ReactElement<{
|
|
279
287
|
className: string;
|
|
280
288
|
'aria-busy': boolean;
|
|
281
289
|
'aria-label': string;
|
|
@@ -291,7 +299,7 @@ declare function Editable({ contentKey, defaultValue, as, multiline, className,
|
|
|
291
299
|
/**
|
|
292
300
|
* Renders rich HTML content from the CMS. Content is sanitized before rendering.
|
|
293
301
|
*/
|
|
294
|
-
declare function EditableHTML({ contentKey, defaultValue, as, className, }: Omit<EditableProps, 'multiline'>): React.ReactElement<{
|
|
302
|
+
declare function EditableHTML({ contentKey, defaultValue, as, className, locale: localeProp, }: Omit<EditableProps, 'multiline'>): React.ReactElement<{
|
|
295
303
|
className: string;
|
|
296
304
|
'aria-busy': boolean;
|
|
297
305
|
}, string | React.JSXElementConstructor<any>> | React.DetailedReactHTMLElement<{
|
|
@@ -311,11 +319,12 @@ interface EditableImageProps {
|
|
|
311
319
|
width?: number;
|
|
312
320
|
height?: number;
|
|
313
321
|
priority?: boolean;
|
|
322
|
+
locale?: string;
|
|
314
323
|
}
|
|
315
324
|
/**
|
|
316
325
|
* Renders an image from a CMS-managed URL. Uses native img (no Next.js Image in SDK).
|
|
317
326
|
*/
|
|
318
|
-
declare function EditableImage({ contentKey, defaultValue, alt, className, width, height, priority, }: EditableImageProps): react_jsx_runtime.JSX.Element;
|
|
327
|
+
declare function EditableImage({ contentKey, defaultValue, alt, className, width, height, priority, locale: localeProp, }: EditableImageProps): react_jsx_runtime.JSX.Element;
|
|
319
328
|
|
|
320
329
|
/**
|
|
321
330
|
* Hook to fetch and manage services (Projects module)
|
|
@@ -470,6 +479,7 @@ declare function useContactCapture(): UseContactCaptureReturn;
|
|
|
470
479
|
interface SiteContent {
|
|
471
480
|
id: string;
|
|
472
481
|
contentKey: string;
|
|
482
|
+
locale?: string;
|
|
473
483
|
value: string | null;
|
|
474
484
|
contentType: string;
|
|
475
485
|
defaultValue: string | null;
|
|
@@ -488,6 +498,10 @@ interface UseSiteContentOptions {
|
|
|
488
498
|
* Whether to fetch on mount (default: true)
|
|
489
499
|
*/
|
|
490
500
|
fetchOnMount?: boolean;
|
|
501
|
+
/**
|
|
502
|
+
* Locale for i18n (e.g. "en", "pt"). Omit for default.
|
|
503
|
+
*/
|
|
504
|
+
locale?: string;
|
|
491
505
|
}
|
|
492
506
|
interface UseSiteContentReturn {
|
|
493
507
|
/**
|
|
@@ -561,6 +575,10 @@ interface UseSiteContentsOptions {
|
|
|
561
575
|
* Default values map
|
|
562
576
|
*/
|
|
563
577
|
defaults?: Record<string, string>;
|
|
578
|
+
/**
|
|
579
|
+
* Locale for i18n (e.g. "en", "pt"). Omit for default.
|
|
580
|
+
*/
|
|
581
|
+
locale?: string;
|
|
564
582
|
}
|
|
565
583
|
interface UseSiteContentsReturn {
|
|
566
584
|
/**
|
|
@@ -647,7 +665,10 @@ interface UseSiteContentSectionReturn {
|
|
|
647
665
|
* }
|
|
648
666
|
* ```
|
|
649
667
|
*/
|
|
650
|
-
|
|
668
|
+
interface UseSiteContentSectionOptions {
|
|
669
|
+
locale?: string;
|
|
670
|
+
}
|
|
671
|
+
declare function useSiteContentSection(section: string, options?: UseSiteContentSectionOptions): UseSiteContentSectionReturn;
|
|
651
672
|
|
|
652
673
|
/**
|
|
653
674
|
* Edit-mode hooks for CMS Visual (iframe communication with Tenant Admin).
|
|
@@ -671,7 +692,7 @@ declare function useEditModeMessaging(): boolean;
|
|
|
671
692
|
* Returns a callback to send an edit request to the parent iframe.
|
|
672
693
|
* Only has effect when in edit mode.
|
|
673
694
|
*/
|
|
674
|
-
declare function useSendEditRequest(): (contentKey: string, currentValue: string, contentType?: string, section?: string, description?: string) => void;
|
|
695
|
+
declare function useSendEditRequest(): (contentKey: string, currentValue: string, contentType?: string, section?: string, description?: string, locale?: string) => void;
|
|
675
696
|
|
|
676
697
|
/**
|
|
677
698
|
* Site content hook for Editable components.
|
|
@@ -680,6 +701,8 @@ declare function useSendEditRequest(): (contentKey: string, currentValue: string
|
|
|
680
701
|
*/
|
|
681
702
|
interface UseSiteContentQueryOptions {
|
|
682
703
|
defaultValue: string;
|
|
704
|
+
/** Locale for i18n (e.g. "en", "pt"). Omit for default. */
|
|
705
|
+
locale?: string;
|
|
683
706
|
}
|
|
684
707
|
interface UseSiteContentQueryReturn {
|
|
685
708
|
value: string;
|
|
@@ -702,6 +725,8 @@ interface PrefetchSiteContentOptions {
|
|
|
702
725
|
apiKey?: string;
|
|
703
726
|
tenantId?: string;
|
|
704
727
|
contentKeys: string[];
|
|
728
|
+
/** Locale for i18n (e.g. "en", "pt"). Can pass multiple to prefetch several locales. */
|
|
729
|
+
locale?: string | string[];
|
|
705
730
|
}
|
|
706
731
|
/**
|
|
707
732
|
* Prefetch site content keys and set them on the given QueryClient.
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,10 @@ interface FoxPixelConfig {
|
|
|
22
22
|
* Tenant ID (optional, can be set per request)
|
|
23
23
|
*/
|
|
24
24
|
tenantId?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Current locale for site content i18n (e.g. "en", "pt"). Omit for default.
|
|
27
|
+
*/
|
|
28
|
+
locale?: string;
|
|
25
29
|
}
|
|
26
30
|
interface Service {
|
|
27
31
|
id: string;
|
|
@@ -140,6 +144,8 @@ interface FoxPixelContextValue {
|
|
|
140
144
|
config: FoxPixelConfig;
|
|
141
145
|
/** Optional: pass QueryClient so edit-mode messaging can invalidate cache without requiring useQueryClient() in SDK (avoids "No QueryClient set" in iframe). */
|
|
142
146
|
queryClient?: QueryClient | null;
|
|
147
|
+
/** Current locale for site content i18n (e.g. "en", "pt"). From config.locale. */
|
|
148
|
+
locale?: string;
|
|
143
149
|
}
|
|
144
150
|
interface FoxPixelProviderProps {
|
|
145
151
|
children: ReactNode;
|
|
@@ -274,8 +280,10 @@ interface EditableProps {
|
|
|
274
280
|
as?: keyof JSX.IntrinsicElements;
|
|
275
281
|
multiline?: boolean;
|
|
276
282
|
className?: string;
|
|
283
|
+
/** Override locale for this editable (default: from FoxPixelProvider config.locale). */
|
|
284
|
+
locale?: string;
|
|
277
285
|
}
|
|
278
|
-
declare function Editable({ contentKey, defaultValue, as, multiline, className, }: EditableProps): React.ReactElement<{
|
|
286
|
+
declare function Editable({ contentKey, defaultValue, as, multiline, className, locale: localeProp, }: EditableProps): React.ReactElement<{
|
|
279
287
|
className: string;
|
|
280
288
|
'aria-busy': boolean;
|
|
281
289
|
'aria-label': string;
|
|
@@ -291,7 +299,7 @@ declare function Editable({ contentKey, defaultValue, as, multiline, className,
|
|
|
291
299
|
/**
|
|
292
300
|
* Renders rich HTML content from the CMS. Content is sanitized before rendering.
|
|
293
301
|
*/
|
|
294
|
-
declare function EditableHTML({ contentKey, defaultValue, as, className, }: Omit<EditableProps, 'multiline'>): React.ReactElement<{
|
|
302
|
+
declare function EditableHTML({ contentKey, defaultValue, as, className, locale: localeProp, }: Omit<EditableProps, 'multiline'>): React.ReactElement<{
|
|
295
303
|
className: string;
|
|
296
304
|
'aria-busy': boolean;
|
|
297
305
|
}, string | React.JSXElementConstructor<any>> | React.DetailedReactHTMLElement<{
|
|
@@ -311,11 +319,12 @@ interface EditableImageProps {
|
|
|
311
319
|
width?: number;
|
|
312
320
|
height?: number;
|
|
313
321
|
priority?: boolean;
|
|
322
|
+
locale?: string;
|
|
314
323
|
}
|
|
315
324
|
/**
|
|
316
325
|
* Renders an image from a CMS-managed URL. Uses native img (no Next.js Image in SDK).
|
|
317
326
|
*/
|
|
318
|
-
declare function EditableImage({ contentKey, defaultValue, alt, className, width, height, priority, }: EditableImageProps): react_jsx_runtime.JSX.Element;
|
|
327
|
+
declare function EditableImage({ contentKey, defaultValue, alt, className, width, height, priority, locale: localeProp, }: EditableImageProps): react_jsx_runtime.JSX.Element;
|
|
319
328
|
|
|
320
329
|
/**
|
|
321
330
|
* Hook to fetch and manage services (Projects module)
|
|
@@ -470,6 +479,7 @@ declare function useContactCapture(): UseContactCaptureReturn;
|
|
|
470
479
|
interface SiteContent {
|
|
471
480
|
id: string;
|
|
472
481
|
contentKey: string;
|
|
482
|
+
locale?: string;
|
|
473
483
|
value: string | null;
|
|
474
484
|
contentType: string;
|
|
475
485
|
defaultValue: string | null;
|
|
@@ -488,6 +498,10 @@ interface UseSiteContentOptions {
|
|
|
488
498
|
* Whether to fetch on mount (default: true)
|
|
489
499
|
*/
|
|
490
500
|
fetchOnMount?: boolean;
|
|
501
|
+
/**
|
|
502
|
+
* Locale for i18n (e.g. "en", "pt"). Omit for default.
|
|
503
|
+
*/
|
|
504
|
+
locale?: string;
|
|
491
505
|
}
|
|
492
506
|
interface UseSiteContentReturn {
|
|
493
507
|
/**
|
|
@@ -561,6 +575,10 @@ interface UseSiteContentsOptions {
|
|
|
561
575
|
* Default values map
|
|
562
576
|
*/
|
|
563
577
|
defaults?: Record<string, string>;
|
|
578
|
+
/**
|
|
579
|
+
* Locale for i18n (e.g. "en", "pt"). Omit for default.
|
|
580
|
+
*/
|
|
581
|
+
locale?: string;
|
|
564
582
|
}
|
|
565
583
|
interface UseSiteContentsReturn {
|
|
566
584
|
/**
|
|
@@ -647,7 +665,10 @@ interface UseSiteContentSectionReturn {
|
|
|
647
665
|
* }
|
|
648
666
|
* ```
|
|
649
667
|
*/
|
|
650
|
-
|
|
668
|
+
interface UseSiteContentSectionOptions {
|
|
669
|
+
locale?: string;
|
|
670
|
+
}
|
|
671
|
+
declare function useSiteContentSection(section: string, options?: UseSiteContentSectionOptions): UseSiteContentSectionReturn;
|
|
651
672
|
|
|
652
673
|
/**
|
|
653
674
|
* Edit-mode hooks for CMS Visual (iframe communication with Tenant Admin).
|
|
@@ -671,7 +692,7 @@ declare function useEditModeMessaging(): boolean;
|
|
|
671
692
|
* Returns a callback to send an edit request to the parent iframe.
|
|
672
693
|
* Only has effect when in edit mode.
|
|
673
694
|
*/
|
|
674
|
-
declare function useSendEditRequest(): (contentKey: string, currentValue: string, contentType?: string, section?: string, description?: string) => void;
|
|
695
|
+
declare function useSendEditRequest(): (contentKey: string, currentValue: string, contentType?: string, section?: string, description?: string, locale?: string) => void;
|
|
675
696
|
|
|
676
697
|
/**
|
|
677
698
|
* Site content hook for Editable components.
|
|
@@ -680,6 +701,8 @@ declare function useSendEditRequest(): (contentKey: string, currentValue: string
|
|
|
680
701
|
*/
|
|
681
702
|
interface UseSiteContentQueryOptions {
|
|
682
703
|
defaultValue: string;
|
|
704
|
+
/** Locale for i18n (e.g. "en", "pt"). Omit for default. */
|
|
705
|
+
locale?: string;
|
|
683
706
|
}
|
|
684
707
|
interface UseSiteContentQueryReturn {
|
|
685
708
|
value: string;
|
|
@@ -702,6 +725,8 @@ interface PrefetchSiteContentOptions {
|
|
|
702
725
|
apiKey?: string;
|
|
703
726
|
tenantId?: string;
|
|
704
727
|
contentKeys: string[];
|
|
728
|
+
/** Locale for i18n (e.g. "en", "pt"). Can pass multiple to prefetch several locales. */
|
|
729
|
+
locale?: string | string[];
|
|
705
730
|
}
|
|
706
731
|
/**
|
|
707
732
|
* Prefetch site content keys and set them on the given QueryClient.
|
package/dist/index.js
CHANGED
|
@@ -202,7 +202,8 @@ function FoxPixelProvider({ children, config = {}, queryClient }) {
|
|
|
202
202
|
const value = (0, import_react.useMemo)(() => ({
|
|
203
203
|
client,
|
|
204
204
|
config,
|
|
205
|
-
queryClient: queryClient ?? null
|
|
205
|
+
queryClient: queryClient ?? null,
|
|
206
|
+
locale: config?.locale
|
|
206
207
|
}), [client, config, queryClient]);
|
|
207
208
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FoxPixelContext.Provider, { value, children });
|
|
208
209
|
}
|
|
@@ -477,19 +478,18 @@ function useEditModeMessaging() {
|
|
|
477
478
|
if (!queryClient) return;
|
|
478
479
|
const { type, payload } = event.data || {};
|
|
479
480
|
if (type !== "FOXPIXEL_CONTENT_UPDATED" || !payload?.contentKey) return;
|
|
480
|
-
const { contentKey, newValue } = payload;
|
|
481
|
+
const { contentKey, newValue, locale } = payload;
|
|
482
|
+
const cacheKey2 = locale != null && locale !== "" ? [SITE_CONTENT_QUERY_KEY, contentKey, locale] : [SITE_CONTENT_QUERY_KEY, contentKey];
|
|
481
483
|
if (typeof newValue === "string") {
|
|
482
484
|
queryClient.setQueryData(
|
|
483
|
-
|
|
485
|
+
cacheKey2,
|
|
484
486
|
(prev) => ({
|
|
485
487
|
value: newValue,
|
|
486
488
|
contentType: prev?.contentType ?? "TEXT"
|
|
487
489
|
})
|
|
488
490
|
);
|
|
489
491
|
}
|
|
490
|
-
queryClient.invalidateQueries({
|
|
491
|
-
queryKey: [SITE_CONTENT_QUERY_KEY, contentKey]
|
|
492
|
-
});
|
|
492
|
+
queryClient.invalidateQueries({ queryKey: cacheKey2 });
|
|
493
493
|
};
|
|
494
494
|
window.addEventListener("message", handleMessage);
|
|
495
495
|
return () => window.removeEventListener("message", handleMessage);
|
|
@@ -499,20 +499,19 @@ function useEditModeMessaging() {
|
|
|
499
499
|
function useSendEditRequest() {
|
|
500
500
|
const isEditMode = useEditMode();
|
|
501
501
|
return (0, import_react6.useCallback)(
|
|
502
|
-
(contentKey, currentValue, contentType = "text", section, description) => {
|
|
502
|
+
(contentKey, currentValue, contentType = "text", section, description, locale) => {
|
|
503
503
|
if (!isEditMode) return;
|
|
504
504
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
505
|
+
const payload = {
|
|
506
|
+
contentKey,
|
|
507
|
+
currentValue,
|
|
508
|
+
contentType,
|
|
509
|
+
section,
|
|
510
|
+
description
|
|
511
|
+
};
|
|
512
|
+
if (locale != null && locale !== "") payload.locale = locale;
|
|
505
513
|
window.parent.postMessage(
|
|
506
|
-
{
|
|
507
|
-
type: "FOXPIXEL_EDIT_CONTENT",
|
|
508
|
-
payload: {
|
|
509
|
-
contentKey,
|
|
510
|
-
currentValue,
|
|
511
|
-
contentType,
|
|
512
|
-
section,
|
|
513
|
-
description
|
|
514
|
-
}
|
|
515
|
-
},
|
|
514
|
+
{ type: "FOXPIXEL_EDIT_CONTENT", payload },
|
|
516
515
|
"*"
|
|
517
516
|
);
|
|
518
517
|
}
|
|
@@ -523,20 +522,23 @@ function useSendEditRequest() {
|
|
|
523
522
|
|
|
524
523
|
// src/hooks/useSiteContentQuery.ts
|
|
525
524
|
var import_react7 = require("react");
|
|
526
|
-
function
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
525
|
+
function queryKey(contentKey, locale) {
|
|
526
|
+
return locale != null && locale !== "" ? [SITE_CONTENT_QUERY_KEY, contentKey, locale] : [SITE_CONTENT_QUERY_KEY, contentKey];
|
|
527
|
+
}
|
|
528
|
+
function getCached(queryClient, contentKey, locale) {
|
|
529
|
+
const data = queryClient.getQueryData(
|
|
530
|
+
queryKey(contentKey, locale)
|
|
531
|
+
);
|
|
531
532
|
if (data == null) return void 0;
|
|
532
533
|
return { value: data.value ?? "", contentType: data.contentType ?? "TEXT" };
|
|
533
534
|
}
|
|
534
535
|
function useSiteContentQuery(contentKey, options) {
|
|
535
|
-
const { defaultValue } = options;
|
|
536
|
+
const { defaultValue, locale } = options;
|
|
537
|
+
const loc = locale != null && locale !== "" ? locale : void 0;
|
|
536
538
|
const { client, queryClient } = useFoxPixelContext();
|
|
537
539
|
const [state, setState] = (0, import_react7.useState)(() => {
|
|
538
540
|
if (queryClient) {
|
|
539
|
-
const cached = getCached(queryClient, contentKey);
|
|
541
|
+
const cached = getCached(queryClient, contentKey, loc);
|
|
540
542
|
if (cached) {
|
|
541
543
|
return { value: cached.value, isLoading: false, contentType: cached.contentType };
|
|
542
544
|
}
|
|
@@ -545,18 +547,20 @@ function useSiteContentQuery(contentKey, options) {
|
|
|
545
547
|
});
|
|
546
548
|
const contentKeyRef = (0, import_react7.useRef)(contentKey);
|
|
547
549
|
contentKeyRef.current = contentKey;
|
|
550
|
+
const localeRef = (0, import_react7.useRef)(loc);
|
|
551
|
+
localeRef.current = loc;
|
|
548
552
|
(0, import_react7.useEffect)(() => {
|
|
549
553
|
if (!queryClient) {
|
|
550
554
|
setState((s) => ({ ...s, value: defaultValue, isLoading: false }));
|
|
551
555
|
return;
|
|
552
556
|
}
|
|
553
557
|
const key = contentKeyRef.current;
|
|
554
|
-
const
|
|
558
|
+
const locCurrent = localeRef.current;
|
|
559
|
+
const qKey = queryKey(key, locCurrent);
|
|
555
560
|
const queryFn = async () => {
|
|
556
561
|
try {
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
);
|
|
562
|
+
const url = `/api/site/content/${encodeURIComponent(key)}` + (locCurrent ? `?locale=${encodeURIComponent(locCurrent)}` : "");
|
|
563
|
+
const content = await client.get(url);
|
|
560
564
|
if (!content) return null;
|
|
561
565
|
return {
|
|
562
566
|
value: content.value ?? "",
|
|
@@ -570,7 +574,7 @@ function useSiteContentQuery(contentKey, options) {
|
|
|
570
574
|
};
|
|
571
575
|
let cancelled = false;
|
|
572
576
|
queryClient.fetchQuery({
|
|
573
|
-
queryKey,
|
|
577
|
+
queryKey: qKey,
|
|
574
578
|
queryFn,
|
|
575
579
|
staleTime: 1e3 * 60 * 5,
|
|
576
580
|
retry: 1
|
|
@@ -586,8 +590,11 @@ function useSiteContentQuery(contentKey, options) {
|
|
|
586
590
|
setState((s) => ({ ...s, value: defaultValue, isLoading: false }));
|
|
587
591
|
});
|
|
588
592
|
const unsub = queryClient.getQueryCache().subscribe((event) => {
|
|
589
|
-
|
|
590
|
-
|
|
593
|
+
const q = event?.query;
|
|
594
|
+
const keyMatch = q?.queryKey?.[1] === key;
|
|
595
|
+
const locMatch = (q?.queryKey?.[2] ?? void 0) === locCurrent;
|
|
596
|
+
if (event?.type === "updated" && q && keyMatch && locMatch) {
|
|
597
|
+
const cached = getCached(queryClient, key, locCurrent);
|
|
591
598
|
if (cached && !cancelled) {
|
|
592
599
|
setState({
|
|
593
600
|
value: cached.value,
|
|
@@ -601,7 +608,7 @@ function useSiteContentQuery(contentKey, options) {
|
|
|
601
608
|
cancelled = true;
|
|
602
609
|
unsub();
|
|
603
610
|
};
|
|
604
|
-
}, [queryClient, contentKey, defaultValue, client]);
|
|
611
|
+
}, [queryClient, contentKey, defaultValue, client, loc]);
|
|
605
612
|
return state;
|
|
606
613
|
}
|
|
607
614
|
|
|
@@ -679,13 +686,17 @@ function Editable({
|
|
|
679
686
|
defaultValue,
|
|
680
687
|
as = "span",
|
|
681
688
|
multiline = false,
|
|
682
|
-
className
|
|
689
|
+
className,
|
|
690
|
+
locale: localeProp
|
|
683
691
|
}) {
|
|
684
692
|
const [isHovered, setIsHovered] = (0, import_react8.useState)(false);
|
|
693
|
+
const { locale: contextLocale } = useFoxPixelContext();
|
|
694
|
+
const locale = localeProp ?? contextLocale;
|
|
685
695
|
const isEditMode = useEditModeMessaging();
|
|
686
696
|
const sendEditRequest = useSendEditRequest();
|
|
687
697
|
const { value, isLoading, contentType } = useSiteContentQuery(contentKey, {
|
|
688
|
-
defaultValue
|
|
698
|
+
defaultValue,
|
|
699
|
+
locale
|
|
689
700
|
});
|
|
690
701
|
const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
|
|
691
702
|
(0, import_react8.useEffect)(() => {
|
|
@@ -703,11 +714,13 @@ function Editable({
|
|
|
703
714
|
contentKey,
|
|
704
715
|
value,
|
|
705
716
|
contentType?.toLowerCase() || "text",
|
|
706
|
-
section
|
|
717
|
+
section,
|
|
718
|
+
void 0,
|
|
719
|
+
locale
|
|
707
720
|
);
|
|
708
721
|
}
|
|
709
722
|
},
|
|
710
|
-
[isEditMode, contentKey, value, contentType, section, sendEditRequest]
|
|
723
|
+
[isEditMode, contentKey, value, contentType, section, sendEditRequest, locale]
|
|
711
724
|
);
|
|
712
725
|
if (isLoading) {
|
|
713
726
|
return (0, import_react8.createElement)(as, {
|
|
@@ -780,13 +793,17 @@ function EditableHTML({
|
|
|
780
793
|
contentKey,
|
|
781
794
|
defaultValue,
|
|
782
795
|
as = "div",
|
|
783
|
-
className
|
|
796
|
+
className,
|
|
797
|
+
locale: localeProp
|
|
784
798
|
}) {
|
|
785
799
|
const [isHovered, setIsHovered] = (0, import_react8.useState)(false);
|
|
800
|
+
const { locale: contextLocale } = useFoxPixelContext();
|
|
801
|
+
const locale = localeProp ?? contextLocale;
|
|
786
802
|
const isEditMode = useEditModeMessaging();
|
|
787
803
|
const sendEditRequest = useSendEditRequest();
|
|
788
804
|
const { value, isLoading } = useSiteContentQuery(contentKey, {
|
|
789
|
-
defaultValue
|
|
805
|
+
defaultValue,
|
|
806
|
+
locale
|
|
790
807
|
});
|
|
791
808
|
const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
|
|
792
809
|
(0, import_react8.useEffect)(() => {
|
|
@@ -800,10 +817,10 @@ function EditableHTML({
|
|
|
800
817
|
if (isEditMode) {
|
|
801
818
|
e.preventDefault();
|
|
802
819
|
e.stopPropagation();
|
|
803
|
-
sendEditRequest(contentKey, value, "html", section);
|
|
820
|
+
sendEditRequest(contentKey, value, "html", section, void 0, locale);
|
|
804
821
|
}
|
|
805
822
|
},
|
|
806
|
-
[isEditMode, contentKey, value, section, sendEditRequest]
|
|
823
|
+
[isEditMode, contentKey, value, section, sendEditRequest, locale]
|
|
807
824
|
);
|
|
808
825
|
if (isLoading) {
|
|
809
826
|
return (0, import_react8.createElement)(as, {
|
|
@@ -852,13 +869,17 @@ function EditableImage({
|
|
|
852
869
|
className,
|
|
853
870
|
width,
|
|
854
871
|
height,
|
|
855
|
-
priority = false
|
|
872
|
+
priority = false,
|
|
873
|
+
locale: localeProp
|
|
856
874
|
}) {
|
|
857
875
|
const [isHovered, setIsHovered] = (0, import_react8.useState)(false);
|
|
876
|
+
const { locale: contextLocale } = useFoxPixelContext();
|
|
877
|
+
const locale = localeProp ?? contextLocale;
|
|
858
878
|
const isEditMode = useEditModeMessaging();
|
|
859
879
|
const sendEditRequest = useSendEditRequest();
|
|
860
880
|
const { value: src, isLoading } = useSiteContentQuery(contentKey, {
|
|
861
|
-
defaultValue
|
|
881
|
+
defaultValue,
|
|
882
|
+
locale
|
|
862
883
|
});
|
|
863
884
|
const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
|
|
864
885
|
(0, import_react8.useEffect)(() => {
|
|
@@ -872,10 +893,10 @@ function EditableImage({
|
|
|
872
893
|
if (isEditMode) {
|
|
873
894
|
e.preventDefault();
|
|
874
895
|
e.stopPropagation();
|
|
875
|
-
sendEditRequest(contentKey, src, "image", section);
|
|
896
|
+
sendEditRequest(contentKey, src, "image", section, void 0, locale);
|
|
876
897
|
}
|
|
877
898
|
},
|
|
878
|
-
[isEditMode, contentKey, src, section, sendEditRequest]
|
|
899
|
+
[isEditMode, contentKey, src, section, sendEditRequest, locale]
|
|
879
900
|
);
|
|
880
901
|
if (isLoading) {
|
|
881
902
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
@@ -1021,20 +1042,20 @@ function useContactCapture() {
|
|
|
1021
1042
|
// src/hooks/useSiteContent.ts
|
|
1022
1043
|
var import_react12 = require("react");
|
|
1023
1044
|
function useSiteContent(contentKey, options = {}) {
|
|
1024
|
-
const { defaultValue = "", fetchOnMount = true } = options;
|
|
1045
|
+
const { defaultValue = "", fetchOnMount = true, locale } = options;
|
|
1025
1046
|
const { client } = useFoxPixelContext();
|
|
1026
1047
|
const { user, hasPermission } = useAuth();
|
|
1027
1048
|
const [data, setData] = (0, import_react12.useState)(null);
|
|
1028
1049
|
const [isLoading, setIsLoading] = (0, import_react12.useState)(fetchOnMount);
|
|
1029
1050
|
const [error, setError] = (0, import_react12.useState)(null);
|
|
1030
1051
|
const canEdit = user !== null && hasPermission("site:content:update");
|
|
1052
|
+
const queryLocale = locale != null && locale !== "" ? locale : void 0;
|
|
1031
1053
|
const fetchContent = (0, import_react12.useCallback)(async () => {
|
|
1032
1054
|
try {
|
|
1033
1055
|
setIsLoading(true);
|
|
1034
1056
|
setError(null);
|
|
1035
|
-
const
|
|
1036
|
-
|
|
1037
|
-
);
|
|
1057
|
+
const url = `/api/site/content/${encodeURIComponent(contentKey)}` + (queryLocale ? `?locale=${encodeURIComponent(queryLocale)}` : "");
|
|
1058
|
+
const content = await client.get(url);
|
|
1038
1059
|
setData(content);
|
|
1039
1060
|
} catch (err) {
|
|
1040
1061
|
if (err?.status === 404) {
|
|
@@ -1045,20 +1066,22 @@ function useSiteContent(contentKey, options = {}) {
|
|
|
1045
1066
|
} finally {
|
|
1046
1067
|
setIsLoading(false);
|
|
1047
1068
|
}
|
|
1048
|
-
}, [client, contentKey]);
|
|
1069
|
+
}, [client, contentKey, queryLocale]);
|
|
1049
1070
|
const updateContent = (0, import_react12.useCallback)(async (newValue) => {
|
|
1050
1071
|
try {
|
|
1051
1072
|
setError(null);
|
|
1073
|
+
const body = { value: newValue };
|
|
1074
|
+
if (queryLocale) body.locale = queryLocale;
|
|
1052
1075
|
const updated = await client.put(
|
|
1053
1076
|
`/api/site/content/${encodeURIComponent(contentKey)}`,
|
|
1054
|
-
|
|
1077
|
+
body
|
|
1055
1078
|
);
|
|
1056
1079
|
setData(updated);
|
|
1057
1080
|
} catch (err) {
|
|
1058
1081
|
setError(err);
|
|
1059
1082
|
throw err;
|
|
1060
1083
|
}
|
|
1061
|
-
}, [client, contentKey]);
|
|
1084
|
+
}, [client, contentKey, queryLocale]);
|
|
1062
1085
|
(0, import_react12.useEffect)(() => {
|
|
1063
1086
|
if (fetchOnMount) {
|
|
1064
1087
|
fetchContent();
|
|
@@ -1076,11 +1099,12 @@ function useSiteContent(contentKey, options = {}) {
|
|
|
1076
1099
|
};
|
|
1077
1100
|
}
|
|
1078
1101
|
function useSiteContents(contentKeys, options = {}) {
|
|
1079
|
-
const { defaults = {} } = options;
|
|
1102
|
+
const { defaults = {}, locale } = options;
|
|
1080
1103
|
const { client } = useFoxPixelContext();
|
|
1081
1104
|
const [data, setData] = (0, import_react12.useState)({});
|
|
1082
1105
|
const [isLoading, setIsLoading] = (0, import_react12.useState)(true);
|
|
1083
1106
|
const [error, setError] = (0, import_react12.useState)(null);
|
|
1107
|
+
const body = locale != null && locale !== "" ? { keys: contentKeys, locale } : contentKeys;
|
|
1084
1108
|
const fetchContents = (0, import_react12.useCallback)(async () => {
|
|
1085
1109
|
if (contentKeys.length === 0) {
|
|
1086
1110
|
setData({});
|
|
@@ -1092,7 +1116,7 @@ function useSiteContents(contentKeys, options = {}) {
|
|
|
1092
1116
|
setError(null);
|
|
1093
1117
|
const contents = await client.post(
|
|
1094
1118
|
"/api/site/content/batch",
|
|
1095
|
-
|
|
1119
|
+
body
|
|
1096
1120
|
);
|
|
1097
1121
|
setData(contents);
|
|
1098
1122
|
} catch (err) {
|
|
@@ -1100,7 +1124,7 @@ function useSiteContents(contentKeys, options = {}) {
|
|
|
1100
1124
|
} finally {
|
|
1101
1125
|
setIsLoading(false);
|
|
1102
1126
|
}
|
|
1103
|
-
}, [client, contentKeys.join(",")]);
|
|
1127
|
+
}, [client, contentKeys.join(","), locale]);
|
|
1104
1128
|
(0, import_react12.useEffect)(() => {
|
|
1105
1129
|
fetchContents();
|
|
1106
1130
|
}, [fetchContents]);
|
|
@@ -1119,25 +1143,25 @@ function useSiteContents(contentKeys, options = {}) {
|
|
|
1119
1143
|
refetch: fetchContents
|
|
1120
1144
|
};
|
|
1121
1145
|
}
|
|
1122
|
-
function useSiteContentSection(section) {
|
|
1146
|
+
function useSiteContentSection(section, options = {}) {
|
|
1147
|
+
const { locale } = options;
|
|
1123
1148
|
const { client } = useFoxPixelContext();
|
|
1124
1149
|
const [contents, setContents] = (0, import_react12.useState)([]);
|
|
1125
1150
|
const [isLoading, setIsLoading] = (0, import_react12.useState)(true);
|
|
1126
1151
|
const [error, setError] = (0, import_react12.useState)(null);
|
|
1152
|
+
const url = `/api/site/content/section/${encodeURIComponent(section)}` + (locale != null && locale !== "" ? `?locale=${encodeURIComponent(locale)}` : "");
|
|
1127
1153
|
const fetchContents = (0, import_react12.useCallback)(async () => {
|
|
1128
1154
|
try {
|
|
1129
1155
|
setIsLoading(true);
|
|
1130
1156
|
setError(null);
|
|
1131
|
-
const data = await client.get(
|
|
1132
|
-
`/api/site/content/section/${encodeURIComponent(section)}`
|
|
1133
|
-
);
|
|
1157
|
+
const data = await client.get(url);
|
|
1134
1158
|
setContents(data);
|
|
1135
1159
|
} catch (err) {
|
|
1136
1160
|
setError(err);
|
|
1137
1161
|
} finally {
|
|
1138
1162
|
setIsLoading(false);
|
|
1139
1163
|
}
|
|
1140
|
-
}, [client, section]);
|
|
1164
|
+
}, [client, section, locale]);
|
|
1141
1165
|
(0, import_react12.useEffect)(() => {
|
|
1142
1166
|
fetchContents();
|
|
1143
1167
|
}, [fetchContents]);
|
|
@@ -1150,33 +1174,39 @@ function useSiteContentSection(section) {
|
|
|
1150
1174
|
}
|
|
1151
1175
|
|
|
1152
1176
|
// src/prefetchSiteContent.ts
|
|
1177
|
+
function cacheKey(contentKey, locale) {
|
|
1178
|
+
return locale != null && locale !== "" ? [SITE_CONTENT_QUERY_KEY, contentKey, locale] : [SITE_CONTENT_QUERY_KEY, contentKey];
|
|
1179
|
+
}
|
|
1153
1180
|
async function prefetchSiteContent(queryClient, options) {
|
|
1154
|
-
const { apiUrl, apiKey, tenantId, contentKeys } = options;
|
|
1181
|
+
const { apiUrl, apiKey, tenantId, contentKeys, locale } = options;
|
|
1155
1182
|
const client = new FoxPixelHttpClient({ apiUrl, apiKey, tenantId });
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
)
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1183
|
+
const locales = locale == null ? [void 0] : Array.isArray(locale) ? locale : [locale];
|
|
1184
|
+
const tasks = [];
|
|
1185
|
+
for (const contentKey of contentKeys) {
|
|
1186
|
+
for (const loc of locales) {
|
|
1187
|
+
tasks.push(
|
|
1188
|
+
(async () => {
|
|
1189
|
+
try {
|
|
1190
|
+
const url = `/api/site/content/${encodeURIComponent(contentKey)}` + (loc != null && loc !== "" ? `?locale=${encodeURIComponent(loc)}` : "");
|
|
1191
|
+
const content = await client.get(url);
|
|
1192
|
+
queryClient.setQueryData(cacheKey(contentKey, loc), {
|
|
1193
|
+
value: content?.value ?? "",
|
|
1194
|
+
contentType: content?.contentType ?? "TEXT"
|
|
1195
|
+
});
|
|
1196
|
+
} catch (err) {
|
|
1197
|
+
const status = err?.response?.status;
|
|
1198
|
+
if (status === 404) {
|
|
1199
|
+
queryClient.setQueryData(cacheKey(contentKey, loc), {
|
|
1200
|
+
value: "",
|
|
1201
|
+
contentType: "TEXT"
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1167
1204
|
}
|
|
1168
|
-
)
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
value: "",
|
|
1174
|
-
contentType: "TEXT"
|
|
1175
|
-
});
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
})
|
|
1179
|
-
);
|
|
1205
|
+
})()
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
await Promise.all(tasks);
|
|
1180
1210
|
}
|
|
1181
1211
|
|
|
1182
1212
|
// src/blog/hooks.ts
|