@foxpixel/react 0.2.0 → 0.2.2
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 +49 -26
- package/dist/index.d.ts +49 -26
- package/dist/index.js +419 -200
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +399 -181
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -40,6 +40,7 @@ __export(index_exports, {
|
|
|
40
40
|
ProtectedRoute: () => ProtectedRoute,
|
|
41
41
|
SITE_CONTENT_QUERY_KEY: () => SITE_CONTENT_QUERY_KEY,
|
|
42
42
|
getBlogPostSchemaLd: () => getBlogPostSchemaLd,
|
|
43
|
+
prefetchSiteContent: () => prefetchSiteContent,
|
|
43
44
|
useAdminBlogAnalytics: () => useAdminBlogAnalytics,
|
|
44
45
|
useAdminBlogCategories: () => useAdminBlogCategories,
|
|
45
46
|
useAdminBlogComments: () => useAdminBlogComments,
|
|
@@ -76,7 +77,7 @@ __export(index_exports, {
|
|
|
76
77
|
module.exports = __toCommonJS(index_exports);
|
|
77
78
|
|
|
78
79
|
// src/context/FoxPixelContext.tsx
|
|
79
|
-
var import_react = require("react");
|
|
80
|
+
var import_react = __toESM(require("react"));
|
|
80
81
|
|
|
81
82
|
// src/client/http.ts
|
|
82
83
|
var import_axios = __toESM(require("axios"));
|
|
@@ -188,15 +189,21 @@ var FoxPixelHttpClient = class {
|
|
|
188
189
|
|
|
189
190
|
// src/context/FoxPixelContext.tsx
|
|
190
191
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
192
|
+
if (!import_react.default || typeof import_react.default.useMemo !== "function") {
|
|
193
|
+
throw new Error(
|
|
194
|
+
'@foxpixel/react: React is not available. Ensure your app uses a single React instance and the SDK is not bundled with a different React. In Next.js use transpilePackages: ["@foxpixel/react"] and ensure react/react-dom resolve to one module (see next.config.js).'
|
|
195
|
+
);
|
|
196
|
+
}
|
|
191
197
|
var FoxPixelContext = (0, import_react.createContext)(null);
|
|
192
|
-
function FoxPixelProvider({ children, config = {} }) {
|
|
198
|
+
function FoxPixelProvider({ children, config = {}, queryClient }) {
|
|
193
199
|
const client = (0, import_react.useMemo)(() => {
|
|
194
200
|
return new FoxPixelHttpClient(config);
|
|
195
201
|
}, [config.apiUrl, config.apiKey, config.tenantId]);
|
|
196
202
|
const value = (0, import_react.useMemo)(() => ({
|
|
197
203
|
client,
|
|
198
|
-
config
|
|
199
|
-
|
|
204
|
+
config,
|
|
205
|
+
queryClient: queryClient ?? null
|
|
206
|
+
}), [client, config, queryClient]);
|
|
200
207
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FoxPixelContext.Provider, { value, children });
|
|
201
208
|
}
|
|
202
209
|
function useFoxPixelContext() {
|
|
@@ -423,12 +430,33 @@ function withAuth(Component, options = {}) {
|
|
|
423
430
|
}
|
|
424
431
|
|
|
425
432
|
// src/components/Editable.tsx
|
|
426
|
-
var
|
|
433
|
+
var import_react8 = require("react");
|
|
427
434
|
|
|
428
435
|
// src/hooks/useEditMode.ts
|
|
429
436
|
var import_react6 = require("react");
|
|
430
|
-
var import_react_query = require("@tanstack/react-query");
|
|
431
437
|
var SITE_CONTENT_QUERY_KEY = "siteContent";
|
|
438
|
+
var contentKeysOnPage = /* @__PURE__ */ new Set();
|
|
439
|
+
var flushTimer = null;
|
|
440
|
+
function scheduleFlushContentKeys() {
|
|
441
|
+
if (flushTimer) return;
|
|
442
|
+
flushTimer = setTimeout(() => {
|
|
443
|
+
flushTimer = null;
|
|
444
|
+
if (typeof window !== "undefined" && window.parent !== window) {
|
|
445
|
+
window.parent.postMessage(
|
|
446
|
+
{ type: "FOXPIXEL_READY", payload: { contentKeys: Array.from(contentKeysOnPage) } },
|
|
447
|
+
"*"
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
}, 150);
|
|
451
|
+
}
|
|
452
|
+
function registerContentKey(key) {
|
|
453
|
+
contentKeysOnPage.add(key);
|
|
454
|
+
scheduleFlushContentKeys();
|
|
455
|
+
}
|
|
456
|
+
function unregisterContentKey(key) {
|
|
457
|
+
contentKeysOnPage.delete(key);
|
|
458
|
+
scheduleFlushContentKeys();
|
|
459
|
+
}
|
|
432
460
|
function useEditMode() {
|
|
433
461
|
const [isEditMode, setIsEditMode] = (0, import_react6.useState)(false);
|
|
434
462
|
(0, import_react6.useEffect)(() => {
|
|
@@ -439,18 +467,29 @@ function useEditMode() {
|
|
|
439
467
|
return isEditMode;
|
|
440
468
|
}
|
|
441
469
|
function useEditModeMessaging() {
|
|
442
|
-
const
|
|
470
|
+
const ctx = useFoxPixelContext();
|
|
471
|
+
const queryClient = ctx?.queryClient ?? null;
|
|
443
472
|
const isEditMode = useEditMode();
|
|
444
473
|
(0, import_react6.useEffect)(() => {
|
|
445
474
|
if (!isEditMode || typeof window === "undefined") return;
|
|
446
475
|
window.parent.postMessage({ type: "FOXPIXEL_READY" }, "*");
|
|
447
476
|
const handleMessage = (event) => {
|
|
477
|
+
if (!queryClient) return;
|
|
448
478
|
const { type, payload } = event.data || {};
|
|
449
|
-
if (type
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
479
|
+
if (type !== "FOXPIXEL_CONTENT_UPDATED" || !payload?.contentKey) return;
|
|
480
|
+
const { contentKey, newValue } = payload;
|
|
481
|
+
if (typeof newValue === "string") {
|
|
482
|
+
queryClient.setQueryData(
|
|
483
|
+
[SITE_CONTENT_QUERY_KEY, contentKey],
|
|
484
|
+
(prev) => ({
|
|
485
|
+
value: newValue,
|
|
486
|
+
contentType: prev?.contentType ?? "TEXT"
|
|
487
|
+
})
|
|
488
|
+
);
|
|
453
489
|
}
|
|
490
|
+
queryClient.invalidateQueries({
|
|
491
|
+
queryKey: [SITE_CONTENT_QUERY_KEY, contentKey]
|
|
492
|
+
});
|
|
454
493
|
};
|
|
455
494
|
window.addEventListener("message", handleMessage);
|
|
456
495
|
return () => window.removeEventListener("message", handleMessage);
|
|
@@ -483,16 +522,40 @@ function useSendEditRequest() {
|
|
|
483
522
|
}
|
|
484
523
|
|
|
485
524
|
// src/hooks/useSiteContentQuery.ts
|
|
486
|
-
var
|
|
525
|
+
var import_react7 = require("react");
|
|
526
|
+
function getCached(queryClient, contentKey) {
|
|
527
|
+
const data = queryClient.getQueryData([
|
|
528
|
+
SITE_CONTENT_QUERY_KEY,
|
|
529
|
+
contentKey
|
|
530
|
+
]);
|
|
531
|
+
if (data == null) return void 0;
|
|
532
|
+
return { value: data.value ?? "", contentType: data.contentType ?? "TEXT" };
|
|
533
|
+
}
|
|
487
534
|
function useSiteContentQuery(contentKey, options) {
|
|
488
535
|
const { defaultValue } = options;
|
|
489
|
-
const { client } = useFoxPixelContext();
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
536
|
+
const { client, queryClient } = useFoxPixelContext();
|
|
537
|
+
const [state, setState] = (0, import_react7.useState)(() => {
|
|
538
|
+
if (queryClient) {
|
|
539
|
+
const cached = getCached(queryClient, contentKey);
|
|
540
|
+
if (cached) {
|
|
541
|
+
return { value: cached.value, isLoading: false, contentType: cached.contentType };
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return { value: defaultValue, isLoading: true, contentType: "TEXT" };
|
|
545
|
+
});
|
|
546
|
+
const contentKeyRef = (0, import_react7.useRef)(contentKey);
|
|
547
|
+
contentKeyRef.current = contentKey;
|
|
548
|
+
(0, import_react7.useEffect)(() => {
|
|
549
|
+
if (!queryClient) {
|
|
550
|
+
setState((s) => ({ ...s, value: defaultValue, isLoading: false }));
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
const key = contentKeyRef.current;
|
|
554
|
+
const queryKey = [SITE_CONTENT_QUERY_KEY, key];
|
|
555
|
+
const queryFn = async () => {
|
|
493
556
|
try {
|
|
494
557
|
const content = await client.get(
|
|
495
|
-
`/api/site/content/${encodeURIComponent(
|
|
558
|
+
`/api/site/content/${encodeURIComponent(key)}`
|
|
496
559
|
);
|
|
497
560
|
if (!content) return null;
|
|
498
561
|
return {
|
|
@@ -500,23 +563,50 @@ function useSiteContentQuery(contentKey, options) {
|
|
|
500
563
|
contentType: content.contentType ?? "TEXT"
|
|
501
564
|
};
|
|
502
565
|
} catch (err) {
|
|
503
|
-
const status = err?.status;
|
|
566
|
+
const status = err?.response?.status;
|
|
504
567
|
if (status === 404) return null;
|
|
505
568
|
throw err;
|
|
506
569
|
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
570
|
+
};
|
|
571
|
+
let cancelled = false;
|
|
572
|
+
queryClient.fetchQuery({
|
|
573
|
+
queryKey,
|
|
574
|
+
queryFn,
|
|
575
|
+
staleTime: 1e3 * 60 * 5,
|
|
576
|
+
retry: 1
|
|
577
|
+
}).then((data) => {
|
|
578
|
+
if (cancelled) return;
|
|
579
|
+
setState({
|
|
580
|
+
value: data?.value ?? defaultValue,
|
|
581
|
+
isLoading: false,
|
|
582
|
+
contentType: data?.contentType ?? "TEXT"
|
|
583
|
+
});
|
|
584
|
+
}).catch(() => {
|
|
585
|
+
if (cancelled) return;
|
|
586
|
+
setState((s) => ({ ...s, value: defaultValue, isLoading: false }));
|
|
587
|
+
});
|
|
588
|
+
const unsub = queryClient.getQueryCache().subscribe((event) => {
|
|
589
|
+
if (event?.type === "updated" && event?.query?.queryKey[1] === key) {
|
|
590
|
+
const cached = getCached(queryClient, key);
|
|
591
|
+
if (cached && !cancelled) {
|
|
592
|
+
setState({
|
|
593
|
+
value: cached.value,
|
|
594
|
+
isLoading: false,
|
|
595
|
+
contentType: cached.contentType
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
return () => {
|
|
601
|
+
cancelled = true;
|
|
602
|
+
unsub();
|
|
603
|
+
};
|
|
604
|
+
}, [queryClient, contentKey, defaultValue, client]);
|
|
605
|
+
return state;
|
|
516
606
|
}
|
|
517
607
|
|
|
518
608
|
// src/utils/sanitize.ts
|
|
519
|
-
var
|
|
609
|
+
var import_sanitize_html = __toESM(require("sanitize-html"));
|
|
520
610
|
var DEFAULT_ALLOWED_TAGS = [
|
|
521
611
|
"p",
|
|
522
612
|
"br",
|
|
@@ -547,13 +637,16 @@ var DEFAULT_ALLOWED_TAGS = [
|
|
|
547
637
|
"th",
|
|
548
638
|
"td"
|
|
549
639
|
];
|
|
550
|
-
var DEFAULT_ALLOWED_ATTR =
|
|
640
|
+
var DEFAULT_ALLOWED_ATTR = {
|
|
641
|
+
a: ["href", "target", "rel", "title"],
|
|
642
|
+
img: ["src", "alt", "title", "width", "height"],
|
|
643
|
+
"*": ["class"]
|
|
644
|
+
};
|
|
551
645
|
function sanitizeHtml(html) {
|
|
552
646
|
if (typeof html !== "string") return "";
|
|
553
|
-
return
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
ADD_ATTR: ["target"]
|
|
647
|
+
return (0, import_sanitize_html.default)(html, {
|
|
648
|
+
allowedTags: DEFAULT_ALLOWED_TAGS,
|
|
649
|
+
allowedAttributes: DEFAULT_ALLOWED_ATTR
|
|
557
650
|
});
|
|
558
651
|
}
|
|
559
652
|
|
|
@@ -564,6 +657,23 @@ function cn(...args) {
|
|
|
564
657
|
|
|
565
658
|
// src/components/Editable.tsx
|
|
566
659
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
660
|
+
var EDIT_MODE_TOOLTIP_STYLE = {
|
|
661
|
+
position: "absolute",
|
|
662
|
+
top: "-28px",
|
|
663
|
+
left: "50%",
|
|
664
|
+
transform: "translateX(-50%)",
|
|
665
|
+
fontSize: "10px",
|
|
666
|
+
fontFamily: "system-ui, sans-serif",
|
|
667
|
+
padding: "4px 8px",
|
|
668
|
+
backgroundColor: "rgb(37 99 235)",
|
|
669
|
+
color: "white",
|
|
670
|
+
borderRadius: "4px",
|
|
671
|
+
whiteSpace: "nowrap",
|
|
672
|
+
pointerEvents: "none",
|
|
673
|
+
zIndex: 100,
|
|
674
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.2)",
|
|
675
|
+
transition: "opacity 0.15s ease"
|
|
676
|
+
};
|
|
567
677
|
function Editable({
|
|
568
678
|
contentKey,
|
|
569
679
|
defaultValue,
|
|
@@ -571,13 +681,20 @@ function Editable({
|
|
|
571
681
|
multiline = false,
|
|
572
682
|
className
|
|
573
683
|
}) {
|
|
684
|
+
const [isHovered, setIsHovered] = (0, import_react8.useState)(false);
|
|
574
685
|
const isEditMode = useEditModeMessaging();
|
|
575
686
|
const sendEditRequest = useSendEditRequest();
|
|
576
687
|
const { value, isLoading, contentType } = useSiteContentQuery(contentKey, {
|
|
577
688
|
defaultValue
|
|
578
689
|
});
|
|
579
690
|
const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
|
|
580
|
-
|
|
691
|
+
(0, import_react8.useEffect)(() => {
|
|
692
|
+
if (isEditMode) {
|
|
693
|
+
registerContentKey(contentKey);
|
|
694
|
+
return () => unregisterContentKey(contentKey);
|
|
695
|
+
}
|
|
696
|
+
}, [isEditMode, contentKey]);
|
|
697
|
+
const handleClick = (0, import_react8.useCallback)(
|
|
581
698
|
(e) => {
|
|
582
699
|
if (isEditMode) {
|
|
583
700
|
e.preventDefault();
|
|
@@ -593,7 +710,7 @@ function Editable({
|
|
|
593
710
|
[isEditMode, contentKey, value, contentType, section, sendEditRequest]
|
|
594
711
|
);
|
|
595
712
|
if (isLoading) {
|
|
596
|
-
return (0,
|
|
713
|
+
return (0, import_react8.createElement)(as, {
|
|
597
714
|
className: cn(
|
|
598
715
|
"animate-pulse bg-muted rounded",
|
|
599
716
|
multiline ? "h-20" : "h-6",
|
|
@@ -604,36 +721,59 @@ function Editable({
|
|
|
604
721
|
"aria-label": "Loading content..."
|
|
605
722
|
});
|
|
606
723
|
}
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
724
|
+
const editModeWrapperStyle = isEditMode ? {
|
|
725
|
+
position: "relative",
|
|
726
|
+
display: "inline",
|
|
727
|
+
cursor: "pointer",
|
|
728
|
+
borderRadius: "2px",
|
|
729
|
+
outline: isHovered ? "2px solid rgb(59 130 246)" : "none",
|
|
730
|
+
outlineOffset: "2px",
|
|
731
|
+
backgroundColor: isHovered ? "rgba(59 130 246 / 0.08)" : void 0
|
|
732
|
+
} : {};
|
|
733
|
+
const tooltipSpan = isEditMode ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
734
|
+
"span",
|
|
735
|
+
{
|
|
736
|
+
style: {
|
|
737
|
+
...EDIT_MODE_TOOLTIP_STYLE,
|
|
738
|
+
opacity: isHovered ? 1 : 0
|
|
739
|
+
},
|
|
740
|
+
"aria-hidden": true,
|
|
741
|
+
children: "Click to edit"
|
|
742
|
+
}
|
|
743
|
+
) : null;
|
|
744
|
+
const hoverHandlers = isEditMode ? {
|
|
745
|
+
onMouseEnter: () => setIsHovered(true),
|
|
746
|
+
onMouseLeave: () => setIsHovered(false)
|
|
747
|
+
} : {};
|
|
613
748
|
if (multiline && value.includes("\n")) {
|
|
614
749
|
const safeBr = sanitizeHtml(value.replace(/\n/g, "<br />"));
|
|
615
|
-
return (0,
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
750
|
+
return (0, import_react8.createElement)(
|
|
751
|
+
"span",
|
|
752
|
+
{ style: editModeWrapperStyle, ...hoverHandlers },
|
|
753
|
+
(0, import_react8.createElement)(as, {
|
|
754
|
+
className,
|
|
755
|
+
"data-content-key": contentKey,
|
|
756
|
+
"data-editable": isEditMode ? "true" : void 0,
|
|
757
|
+
onClick: isEditMode ? handleClick : void 0,
|
|
758
|
+
dangerouslySetInnerHTML: { __html: safeBr }
|
|
759
|
+
}),
|
|
760
|
+
tooltipSpan
|
|
761
|
+
);
|
|
623
762
|
}
|
|
624
|
-
return (0,
|
|
625
|
-
|
|
626
|
-
{
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
763
|
+
return (0, import_react8.createElement)(
|
|
764
|
+
"span",
|
|
765
|
+
{ style: editModeWrapperStyle, ...hoverHandlers },
|
|
766
|
+
(0, import_react8.createElement)(
|
|
767
|
+
as,
|
|
768
|
+
{
|
|
769
|
+
className,
|
|
770
|
+
"data-content-key": contentKey,
|
|
771
|
+
"data-editable": isEditMode ? "true" : void 0,
|
|
772
|
+
onClick: isEditMode ? handleClick : void 0
|
|
773
|
+
},
|
|
774
|
+
value
|
|
775
|
+
),
|
|
776
|
+
tooltipSpan
|
|
637
777
|
);
|
|
638
778
|
}
|
|
639
779
|
function EditableHTML({
|
|
@@ -642,13 +782,20 @@ function EditableHTML({
|
|
|
642
782
|
as = "div",
|
|
643
783
|
className
|
|
644
784
|
}) {
|
|
785
|
+
const [isHovered, setIsHovered] = (0, import_react8.useState)(false);
|
|
645
786
|
const isEditMode = useEditModeMessaging();
|
|
646
787
|
const sendEditRequest = useSendEditRequest();
|
|
647
788
|
const { value, isLoading } = useSiteContentQuery(contentKey, {
|
|
648
789
|
defaultValue
|
|
649
790
|
});
|
|
650
791
|
const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
|
|
651
|
-
|
|
792
|
+
(0, import_react8.useEffect)(() => {
|
|
793
|
+
if (isEditMode) {
|
|
794
|
+
registerContentKey(contentKey);
|
|
795
|
+
return () => unregisterContentKey(contentKey);
|
|
796
|
+
}
|
|
797
|
+
}, [isEditMode, contentKey]);
|
|
798
|
+
const handleClick = (0, import_react8.useCallback)(
|
|
652
799
|
(e) => {
|
|
653
800
|
if (isEditMode) {
|
|
654
801
|
e.preventDefault();
|
|
@@ -659,26 +806,44 @@ function EditableHTML({
|
|
|
659
806
|
[isEditMode, contentKey, value, section, sendEditRequest]
|
|
660
807
|
);
|
|
661
808
|
if (isLoading) {
|
|
662
|
-
return (0,
|
|
809
|
+
return (0, import_react8.createElement)(as, {
|
|
663
810
|
className: cn("animate-pulse bg-muted rounded h-32", className),
|
|
664
811
|
"aria-busy": true
|
|
665
812
|
});
|
|
666
813
|
}
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
"
|
|
672
|
-
|
|
814
|
+
const wrapperStyle = isEditMode ? {
|
|
815
|
+
position: "relative",
|
|
816
|
+
cursor: "pointer",
|
|
817
|
+
borderRadius: "2px",
|
|
818
|
+
outline: isHovered ? "2px solid rgb(59 130 246)" : "none",
|
|
819
|
+
outlineOffset: "2px",
|
|
820
|
+
backgroundColor: isHovered ? "rgba(59 130 246 / 0.08)" : void 0
|
|
821
|
+
} : {};
|
|
673
822
|
const safeHtml = sanitizeHtml(value);
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
"
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
823
|
+
const hoverHandlers = isEditMode ? { onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false) } : {};
|
|
824
|
+
return (0, import_react8.createElement)(
|
|
825
|
+
"div",
|
|
826
|
+
{ style: wrapperStyle, ...hoverHandlers },
|
|
827
|
+
(0, import_react8.createElement)(as, {
|
|
828
|
+
className: cn("prose prose-slate dark:prose-invert", className),
|
|
829
|
+
"data-content-key": contentKey,
|
|
830
|
+
"data-editable": isEditMode ? "true" : void 0,
|
|
831
|
+
onClick: isEditMode ? handleClick : void 0,
|
|
832
|
+
dangerouslySetInnerHTML: { __html: safeHtml }
|
|
833
|
+
}),
|
|
834
|
+
isEditMode && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
835
|
+
"span",
|
|
836
|
+
{
|
|
837
|
+
style: {
|
|
838
|
+
...EDIT_MODE_TOOLTIP_STYLE,
|
|
839
|
+
top: "-24px",
|
|
840
|
+
opacity: isHovered ? 1 : 0
|
|
841
|
+
},
|
|
842
|
+
"aria-hidden": true,
|
|
843
|
+
children: "Click to edit"
|
|
844
|
+
}
|
|
845
|
+
)
|
|
846
|
+
);
|
|
682
847
|
}
|
|
683
848
|
function EditableImage({
|
|
684
849
|
contentKey,
|
|
@@ -689,13 +854,20 @@ function EditableImage({
|
|
|
689
854
|
height,
|
|
690
855
|
priority = false
|
|
691
856
|
}) {
|
|
857
|
+
const [isHovered, setIsHovered] = (0, import_react8.useState)(false);
|
|
692
858
|
const isEditMode = useEditModeMessaging();
|
|
693
859
|
const sendEditRequest = useSendEditRequest();
|
|
694
860
|
const { value: src, isLoading } = useSiteContentQuery(contentKey, {
|
|
695
861
|
defaultValue
|
|
696
862
|
});
|
|
697
863
|
const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
|
|
698
|
-
|
|
864
|
+
(0, import_react8.useEffect)(() => {
|
|
865
|
+
if (isEditMode) {
|
|
866
|
+
registerContentKey(contentKey);
|
|
867
|
+
return () => unregisterContentKey(contentKey);
|
|
868
|
+
}
|
|
869
|
+
}, [isEditMode, contentKey]);
|
|
870
|
+
const handleClick = (0, import_react8.useCallback)(
|
|
699
871
|
(e) => {
|
|
700
872
|
if (isEditMode) {
|
|
701
873
|
e.preventDefault();
|
|
@@ -715,39 +887,55 @@ function EditableImage({
|
|
|
715
887
|
}
|
|
716
888
|
);
|
|
717
889
|
}
|
|
718
|
-
const
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
890
|
+
const wrapperStyle = isEditMode ? {
|
|
891
|
+
position: "relative",
|
|
892
|
+
display: "inline-block",
|
|
893
|
+
cursor: "pointer",
|
|
894
|
+
borderRadius: "2px",
|
|
895
|
+
outline: isHovered ? "2px solid rgb(59 130 246)" : "none",
|
|
896
|
+
outlineOffset: "2px"
|
|
897
|
+
} : {};
|
|
898
|
+
const hoverHandlers = isEditMode ? { onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false) } : {};
|
|
899
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: wrapperStyle, ...hoverHandlers, children: [
|
|
725
900
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
726
901
|
"img",
|
|
727
902
|
{
|
|
728
903
|
src,
|
|
729
904
|
alt,
|
|
730
|
-
className
|
|
905
|
+
className,
|
|
906
|
+
style: isEditMode && isHovered ? { opacity: 0.95 } : void 0,
|
|
731
907
|
width,
|
|
732
908
|
height,
|
|
733
909
|
loading: priority ? "eager" : "lazy",
|
|
734
910
|
"data-content-key": contentKey,
|
|
735
911
|
"data-editable": isEditMode ? "true" : void 0,
|
|
736
|
-
onClick: isEditMode ? handleClick : void 0
|
|
737
|
-
title: isEditMode ? "Click to edit image" : void 0
|
|
912
|
+
onClick: isEditMode ? handleClick : void 0
|
|
738
913
|
}
|
|
739
914
|
),
|
|
740
|
-
isEditMode && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
915
|
+
isEditMode && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
916
|
+
"span",
|
|
917
|
+
{
|
|
918
|
+
style: {
|
|
919
|
+
...EDIT_MODE_TOOLTIP_STYLE,
|
|
920
|
+
top: "8px",
|
|
921
|
+
left: "8px",
|
|
922
|
+
transform: "none",
|
|
923
|
+
opacity: isHovered ? 1 : 0
|
|
924
|
+
},
|
|
925
|
+
"aria-hidden": true,
|
|
926
|
+
children: "Click to edit image"
|
|
927
|
+
}
|
|
928
|
+
)
|
|
741
929
|
] });
|
|
742
930
|
}
|
|
743
931
|
|
|
744
932
|
// src/hooks/useServices.ts
|
|
745
|
-
var
|
|
933
|
+
var import_react9 = require("react");
|
|
746
934
|
function useServices(options = {}) {
|
|
747
935
|
const { client } = useFoxPixelContext();
|
|
748
|
-
const [services, setServices] = (0,
|
|
749
|
-
const [isLoading, setIsLoading] = (0,
|
|
750
|
-
const [error, setError] = (0,
|
|
936
|
+
const [services, setServices] = (0, import_react9.useState)(null);
|
|
937
|
+
const [isLoading, setIsLoading] = (0, import_react9.useState)(true);
|
|
938
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
751
939
|
const fetchServices = async () => {
|
|
752
940
|
try {
|
|
753
941
|
setIsLoading(true);
|
|
@@ -765,7 +953,7 @@ function useServices(options = {}) {
|
|
|
765
953
|
setIsLoading(false);
|
|
766
954
|
}
|
|
767
955
|
};
|
|
768
|
-
(0,
|
|
956
|
+
(0, import_react9.useEffect)(() => {
|
|
769
957
|
fetchServices();
|
|
770
958
|
}, [options.category, options.active]);
|
|
771
959
|
return {
|
|
@@ -777,11 +965,11 @@ function useServices(options = {}) {
|
|
|
777
965
|
}
|
|
778
966
|
|
|
779
967
|
// src/hooks/useLeadCapture.ts
|
|
780
|
-
var
|
|
968
|
+
var import_react10 = require("react");
|
|
781
969
|
function useLeadCapture() {
|
|
782
970
|
const { client } = useFoxPixelContext();
|
|
783
|
-
const [isLoading, setIsLoading] = (0,
|
|
784
|
-
const [error, setError] = (0,
|
|
971
|
+
const [isLoading, setIsLoading] = (0, import_react10.useState)(false);
|
|
972
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
785
973
|
const captureLead = async (data) => {
|
|
786
974
|
try {
|
|
787
975
|
setIsLoading(true);
|
|
@@ -804,11 +992,11 @@ function useLeadCapture() {
|
|
|
804
992
|
}
|
|
805
993
|
|
|
806
994
|
// src/hooks/useContactCapture.ts
|
|
807
|
-
var
|
|
995
|
+
var import_react11 = require("react");
|
|
808
996
|
function useContactCapture() {
|
|
809
997
|
const { client } = useFoxPixelContext();
|
|
810
|
-
const [isLoading, setIsLoading] = (0,
|
|
811
|
-
const [error, setError] = (0,
|
|
998
|
+
const [isLoading, setIsLoading] = (0, import_react11.useState)(false);
|
|
999
|
+
const [error, setError] = (0, import_react11.useState)(null);
|
|
812
1000
|
const captureContact = async (data) => {
|
|
813
1001
|
try {
|
|
814
1002
|
setIsLoading(true);
|
|
@@ -831,16 +1019,16 @@ function useContactCapture() {
|
|
|
831
1019
|
}
|
|
832
1020
|
|
|
833
1021
|
// src/hooks/useSiteContent.ts
|
|
834
|
-
var
|
|
1022
|
+
var import_react12 = require("react");
|
|
835
1023
|
function useSiteContent(contentKey, options = {}) {
|
|
836
1024
|
const { defaultValue = "", fetchOnMount = true } = options;
|
|
837
1025
|
const { client } = useFoxPixelContext();
|
|
838
1026
|
const { user, hasPermission } = useAuth();
|
|
839
|
-
const [data, setData] = (0,
|
|
840
|
-
const [isLoading, setIsLoading] = (0,
|
|
841
|
-
const [error, setError] = (0,
|
|
1027
|
+
const [data, setData] = (0, import_react12.useState)(null);
|
|
1028
|
+
const [isLoading, setIsLoading] = (0, import_react12.useState)(fetchOnMount);
|
|
1029
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
842
1030
|
const canEdit = user !== null && hasPermission("site:content:update");
|
|
843
|
-
const fetchContent = (0,
|
|
1031
|
+
const fetchContent = (0, import_react12.useCallback)(async () => {
|
|
844
1032
|
try {
|
|
845
1033
|
setIsLoading(true);
|
|
846
1034
|
setError(null);
|
|
@@ -858,7 +1046,7 @@ function useSiteContent(contentKey, options = {}) {
|
|
|
858
1046
|
setIsLoading(false);
|
|
859
1047
|
}
|
|
860
1048
|
}, [client, contentKey]);
|
|
861
|
-
const updateContent = (0,
|
|
1049
|
+
const updateContent = (0, import_react12.useCallback)(async (newValue) => {
|
|
862
1050
|
try {
|
|
863
1051
|
setError(null);
|
|
864
1052
|
const updated = await client.put(
|
|
@@ -871,7 +1059,7 @@ function useSiteContent(contentKey, options = {}) {
|
|
|
871
1059
|
throw err;
|
|
872
1060
|
}
|
|
873
1061
|
}, [client, contentKey]);
|
|
874
|
-
(0,
|
|
1062
|
+
(0, import_react12.useEffect)(() => {
|
|
875
1063
|
if (fetchOnMount) {
|
|
876
1064
|
fetchContent();
|
|
877
1065
|
}
|
|
@@ -890,10 +1078,10 @@ function useSiteContent(contentKey, options = {}) {
|
|
|
890
1078
|
function useSiteContents(contentKeys, options = {}) {
|
|
891
1079
|
const { defaults = {} } = options;
|
|
892
1080
|
const { client } = useFoxPixelContext();
|
|
893
|
-
const [data, setData] = (0,
|
|
894
|
-
const [isLoading, setIsLoading] = (0,
|
|
895
|
-
const [error, setError] = (0,
|
|
896
|
-
const fetchContents = (0,
|
|
1081
|
+
const [data, setData] = (0, import_react12.useState)({});
|
|
1082
|
+
const [isLoading, setIsLoading] = (0, import_react12.useState)(true);
|
|
1083
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
1084
|
+
const fetchContents = (0, import_react12.useCallback)(async () => {
|
|
897
1085
|
if (contentKeys.length === 0) {
|
|
898
1086
|
setData({});
|
|
899
1087
|
setIsLoading(false);
|
|
@@ -913,10 +1101,10 @@ function useSiteContents(contentKeys, options = {}) {
|
|
|
913
1101
|
setIsLoading(false);
|
|
914
1102
|
}
|
|
915
1103
|
}, [client, contentKeys.join(",")]);
|
|
916
|
-
(0,
|
|
1104
|
+
(0, import_react12.useEffect)(() => {
|
|
917
1105
|
fetchContents();
|
|
918
1106
|
}, [fetchContents]);
|
|
919
|
-
const getValue = (0,
|
|
1107
|
+
const getValue = (0, import_react12.useCallback)((key, defaultValue) => {
|
|
920
1108
|
const content = data[key];
|
|
921
1109
|
if (content?.value) {
|
|
922
1110
|
return content.value;
|
|
@@ -933,10 +1121,10 @@ function useSiteContents(contentKeys, options = {}) {
|
|
|
933
1121
|
}
|
|
934
1122
|
function useSiteContentSection(section) {
|
|
935
1123
|
const { client } = useFoxPixelContext();
|
|
936
|
-
const [contents, setContents] = (0,
|
|
937
|
-
const [isLoading, setIsLoading] = (0,
|
|
938
|
-
const [error, setError] = (0,
|
|
939
|
-
const fetchContents = (0,
|
|
1124
|
+
const [contents, setContents] = (0, import_react12.useState)([]);
|
|
1125
|
+
const [isLoading, setIsLoading] = (0, import_react12.useState)(true);
|
|
1126
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
1127
|
+
const fetchContents = (0, import_react12.useCallback)(async () => {
|
|
940
1128
|
try {
|
|
941
1129
|
setIsLoading(true);
|
|
942
1130
|
setError(null);
|
|
@@ -950,7 +1138,7 @@ function useSiteContentSection(section) {
|
|
|
950
1138
|
setIsLoading(false);
|
|
951
1139
|
}
|
|
952
1140
|
}, [client, section]);
|
|
953
|
-
(0,
|
|
1141
|
+
(0, import_react12.useEffect)(() => {
|
|
954
1142
|
fetchContents();
|
|
955
1143
|
}, [fetchContents]);
|
|
956
1144
|
return {
|
|
@@ -961,13 +1149,43 @@ function useSiteContentSection(section) {
|
|
|
961
1149
|
};
|
|
962
1150
|
}
|
|
963
1151
|
|
|
1152
|
+
// src/prefetchSiteContent.ts
|
|
1153
|
+
async function prefetchSiteContent(queryClient, options) {
|
|
1154
|
+
const { apiUrl, apiKey, tenantId, contentKeys } = options;
|
|
1155
|
+
const client = new FoxPixelHttpClient({ apiUrl, apiKey, tenantId });
|
|
1156
|
+
await Promise.all(
|
|
1157
|
+
contentKeys.map(async (contentKey) => {
|
|
1158
|
+
try {
|
|
1159
|
+
const content = await client.get(
|
|
1160
|
+
`/api/site/content/${encodeURIComponent(contentKey)}`
|
|
1161
|
+
);
|
|
1162
|
+
queryClient.setQueryData(
|
|
1163
|
+
[SITE_CONTENT_QUERY_KEY, contentKey],
|
|
1164
|
+
{
|
|
1165
|
+
value: content?.value ?? "",
|
|
1166
|
+
contentType: content?.contentType ?? "TEXT"
|
|
1167
|
+
}
|
|
1168
|
+
);
|
|
1169
|
+
} catch (err) {
|
|
1170
|
+
const status = err?.response?.status;
|
|
1171
|
+
if (status === 404) {
|
|
1172
|
+
queryClient.setQueryData([SITE_CONTENT_QUERY_KEY, contentKey], {
|
|
1173
|
+
value: "",
|
|
1174
|
+
contentType: "TEXT"
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
})
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
964
1182
|
// src/blog/hooks.ts
|
|
965
|
-
var
|
|
1183
|
+
var import_react13 = require("react");
|
|
966
1184
|
function useBlogPosts(options = {}) {
|
|
967
1185
|
const { client } = useFoxPixelContext();
|
|
968
|
-
const [data, setData] = (0,
|
|
969
|
-
const [isLoading, setIsLoading] = (0,
|
|
970
|
-
const [error, setError] = (0,
|
|
1186
|
+
const [data, setData] = (0, import_react13.useState)(null);
|
|
1187
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(true);
|
|
1188
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
971
1189
|
const page = options.page ?? 0;
|
|
972
1190
|
const limit = options.limit ?? 10;
|
|
973
1191
|
const fetchPosts = async () => {
|
|
@@ -987,7 +1205,7 @@ function useBlogPosts(options = {}) {
|
|
|
987
1205
|
setIsLoading(false);
|
|
988
1206
|
}
|
|
989
1207
|
};
|
|
990
|
-
(0,
|
|
1208
|
+
(0, import_react13.useEffect)(() => {
|
|
991
1209
|
fetchPosts();
|
|
992
1210
|
}, [page, limit]);
|
|
993
1211
|
return {
|
|
@@ -999,9 +1217,9 @@ function useBlogPosts(options = {}) {
|
|
|
999
1217
|
}
|
|
1000
1218
|
function useBlogPost(slug) {
|
|
1001
1219
|
const { client } = useFoxPixelContext();
|
|
1002
|
-
const [data, setData] = (0,
|
|
1003
|
-
const [isLoading, setIsLoading] = (0,
|
|
1004
|
-
const [error, setError] = (0,
|
|
1220
|
+
const [data, setData] = (0, import_react13.useState)(null);
|
|
1221
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(!!slug);
|
|
1222
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1005
1223
|
const fetchPost = async () => {
|
|
1006
1224
|
if (!slug) {
|
|
1007
1225
|
setData(null);
|
|
@@ -1020,7 +1238,7 @@ function useBlogPost(slug) {
|
|
|
1020
1238
|
setIsLoading(false);
|
|
1021
1239
|
}
|
|
1022
1240
|
};
|
|
1023
|
-
(0,
|
|
1241
|
+
(0, import_react13.useEffect)(() => {
|
|
1024
1242
|
fetchPost();
|
|
1025
1243
|
}, [slug]);
|
|
1026
1244
|
return {
|
|
@@ -1032,9 +1250,9 @@ function useBlogPost(slug) {
|
|
|
1032
1250
|
}
|
|
1033
1251
|
function useBlogCategories() {
|
|
1034
1252
|
const { client } = useFoxPixelContext();
|
|
1035
|
-
const [data, setData] = (0,
|
|
1036
|
-
const [isLoading, setIsLoading] = (0,
|
|
1037
|
-
const [error, setError] = (0,
|
|
1253
|
+
const [data, setData] = (0, import_react13.useState)(null);
|
|
1254
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(true);
|
|
1255
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1038
1256
|
const fetchCategories = async () => {
|
|
1039
1257
|
try {
|
|
1040
1258
|
setIsLoading(true);
|
|
@@ -1048,7 +1266,7 @@ function useBlogCategories() {
|
|
|
1048
1266
|
setIsLoading(false);
|
|
1049
1267
|
}
|
|
1050
1268
|
};
|
|
1051
|
-
(0,
|
|
1269
|
+
(0, import_react13.useEffect)(() => {
|
|
1052
1270
|
fetchCategories();
|
|
1053
1271
|
}, []);
|
|
1054
1272
|
return {
|
|
@@ -1060,9 +1278,9 @@ function useBlogCategories() {
|
|
|
1060
1278
|
}
|
|
1061
1279
|
function useBlogTags() {
|
|
1062
1280
|
const { client } = useFoxPixelContext();
|
|
1063
|
-
const [data, setData] = (0,
|
|
1064
|
-
const [isLoading, setIsLoading] = (0,
|
|
1065
|
-
const [error, setError] = (0,
|
|
1281
|
+
const [data, setData] = (0, import_react13.useState)(null);
|
|
1282
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(true);
|
|
1283
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1066
1284
|
const fetchTags = async () => {
|
|
1067
1285
|
try {
|
|
1068
1286
|
setIsLoading(true);
|
|
@@ -1076,7 +1294,7 @@ function useBlogTags() {
|
|
|
1076
1294
|
setIsLoading(false);
|
|
1077
1295
|
}
|
|
1078
1296
|
};
|
|
1079
|
-
(0,
|
|
1297
|
+
(0, import_react13.useEffect)(() => {
|
|
1080
1298
|
fetchTags();
|
|
1081
1299
|
}, []);
|
|
1082
1300
|
return {
|
|
@@ -1088,9 +1306,9 @@ function useBlogTags() {
|
|
|
1088
1306
|
}
|
|
1089
1307
|
function useBlogComments(slug) {
|
|
1090
1308
|
const { client } = useFoxPixelContext();
|
|
1091
|
-
const [data, setData] = (0,
|
|
1092
|
-
const [isLoading, setIsLoading] = (0,
|
|
1093
|
-
const [error, setError] = (0,
|
|
1309
|
+
const [data, setData] = (0, import_react13.useState)(null);
|
|
1310
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(!!slug);
|
|
1311
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1094
1312
|
const fetchComments = async () => {
|
|
1095
1313
|
if (!slug) {
|
|
1096
1314
|
setData(null);
|
|
@@ -1111,7 +1329,7 @@ function useBlogComments(slug) {
|
|
|
1111
1329
|
setIsLoading(false);
|
|
1112
1330
|
}
|
|
1113
1331
|
};
|
|
1114
|
-
(0,
|
|
1332
|
+
(0, import_react13.useEffect)(() => {
|
|
1115
1333
|
fetchComments();
|
|
1116
1334
|
}, [slug]);
|
|
1117
1335
|
return {
|
|
@@ -1123,8 +1341,8 @@ function useBlogComments(slug) {
|
|
|
1123
1341
|
}
|
|
1124
1342
|
function useBlogCommentSubmit(slug) {
|
|
1125
1343
|
const { client } = useFoxPixelContext();
|
|
1126
|
-
const [isSubmitting, setIsSubmitting] = (0,
|
|
1127
|
-
const [error, setError] = (0,
|
|
1344
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react13.useState)(false);
|
|
1345
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1128
1346
|
const submit = async (payload) => {
|
|
1129
1347
|
if (!slug) return null;
|
|
1130
1348
|
try {
|
|
@@ -1152,9 +1370,9 @@ function useBlogCommentSubmit(slug) {
|
|
|
1152
1370
|
}
|
|
1153
1371
|
function useBlogFeaturedPosts(limit = 6) {
|
|
1154
1372
|
const { client } = useFoxPixelContext();
|
|
1155
|
-
const [data, setData] = (0,
|
|
1156
|
-
const [isLoading, setIsLoading] = (0,
|
|
1157
|
-
const [error, setError] = (0,
|
|
1373
|
+
const [data, setData] = (0, import_react13.useState)(null);
|
|
1374
|
+
const [isLoading, setIsLoading] = (0, import_react13.useState)(true);
|
|
1375
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1158
1376
|
const fetchFeatured = async () => {
|
|
1159
1377
|
try {
|
|
1160
1378
|
setIsLoading(true);
|
|
@@ -1172,7 +1390,7 @@ function useBlogFeaturedPosts(limit = 6) {
|
|
|
1172
1390
|
setIsLoading(false);
|
|
1173
1391
|
}
|
|
1174
1392
|
};
|
|
1175
|
-
(0,
|
|
1393
|
+
(0, import_react13.useEffect)(() => {
|
|
1176
1394
|
fetchFeatured();
|
|
1177
1395
|
}, [limit]);
|
|
1178
1396
|
return {
|
|
@@ -1184,9 +1402,9 @@ function useBlogFeaturedPosts(limit = 6) {
|
|
|
1184
1402
|
}
|
|
1185
1403
|
function useNewsletterSubscribe() {
|
|
1186
1404
|
const { client } = useFoxPixelContext();
|
|
1187
|
-
const [isSubmitting, setIsSubmitting] = (0,
|
|
1188
|
-
const [error, setError] = (0,
|
|
1189
|
-
const [success, setSuccess] = (0,
|
|
1405
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react13.useState)(false);
|
|
1406
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1407
|
+
const [success, setSuccess] = (0, import_react13.useState)(false);
|
|
1190
1408
|
const subscribe = async (payload) => {
|
|
1191
1409
|
try {
|
|
1192
1410
|
setIsSubmitting(true);
|
|
@@ -1219,9 +1437,9 @@ function useNewsletterSubscribe() {
|
|
|
1219
1437
|
}
|
|
1220
1438
|
function useNewsletterUnsubscribe() {
|
|
1221
1439
|
const { client } = useFoxPixelContext();
|
|
1222
|
-
const [isSubmitting, setIsSubmitting] = (0,
|
|
1223
|
-
const [error, setError] = (0,
|
|
1224
|
-
const [success, setSuccess] = (0,
|
|
1440
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react13.useState)(false);
|
|
1441
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
1442
|
+
const [success, setSuccess] = (0, import_react13.useState)(false);
|
|
1225
1443
|
const unsubscribe = async (email) => {
|
|
1226
1444
|
try {
|
|
1227
1445
|
setIsSubmitting(true);
|
|
@@ -1266,15 +1484,15 @@ function useNewsletterUnsubscribe() {
|
|
|
1266
1484
|
}
|
|
1267
1485
|
|
|
1268
1486
|
// src/blog/admin-hooks.ts
|
|
1269
|
-
var
|
|
1487
|
+
var import_react14 = require("react");
|
|
1270
1488
|
function useAdminBlogPosts(options = {}) {
|
|
1271
1489
|
const { client } = useFoxPixelContext();
|
|
1272
|
-
const [data, setData] = (0,
|
|
1273
|
-
const [isLoading, setIsLoading] = (0,
|
|
1274
|
-
const [error, setError] = (0,
|
|
1490
|
+
const [data, setData] = (0, import_react14.useState)(null);
|
|
1491
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
|
|
1492
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1275
1493
|
const page = options.page ?? 0;
|
|
1276
1494
|
const size = options.size ?? 20;
|
|
1277
|
-
const fetchPosts = (0,
|
|
1495
|
+
const fetchPosts = (0, import_react14.useCallback)(async () => {
|
|
1278
1496
|
try {
|
|
1279
1497
|
setIsLoading(true);
|
|
1280
1498
|
setError(null);
|
|
@@ -1289,17 +1507,17 @@ function useAdminBlogPosts(options = {}) {
|
|
|
1289
1507
|
setIsLoading(false);
|
|
1290
1508
|
}
|
|
1291
1509
|
}, [client, page, size]);
|
|
1292
|
-
(0,
|
|
1510
|
+
(0, import_react14.useEffect)(() => {
|
|
1293
1511
|
fetchPosts();
|
|
1294
1512
|
}, [fetchPosts]);
|
|
1295
1513
|
return { data, isLoading, error, refetch: fetchPosts };
|
|
1296
1514
|
}
|
|
1297
1515
|
function useAdminBlogPost(id) {
|
|
1298
1516
|
const { client } = useFoxPixelContext();
|
|
1299
|
-
const [data, setData] = (0,
|
|
1300
|
-
const [isLoading, setIsLoading] = (0,
|
|
1301
|
-
const [error, setError] = (0,
|
|
1302
|
-
const fetchPost = (0,
|
|
1517
|
+
const [data, setData] = (0, import_react14.useState)(null);
|
|
1518
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(!!id);
|
|
1519
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1520
|
+
const fetchPost = (0, import_react14.useCallback)(async () => {
|
|
1303
1521
|
if (!id) {
|
|
1304
1522
|
setData(null);
|
|
1305
1523
|
setIsLoading(false);
|
|
@@ -1316,15 +1534,15 @@ function useAdminBlogPost(id) {
|
|
|
1316
1534
|
setIsLoading(false);
|
|
1317
1535
|
}
|
|
1318
1536
|
}, [client, id]);
|
|
1319
|
-
(0,
|
|
1537
|
+
(0, import_react14.useEffect)(() => {
|
|
1320
1538
|
fetchPost();
|
|
1321
1539
|
}, [fetchPost]);
|
|
1322
1540
|
return { data, isLoading, error, refetch: fetchPost };
|
|
1323
1541
|
}
|
|
1324
1542
|
function useAdminBlogPostMutations() {
|
|
1325
1543
|
const { client } = useFoxPixelContext();
|
|
1326
|
-
const [isLoading, setIsLoading] = (0,
|
|
1327
|
-
const [error, setError] = (0,
|
|
1544
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
|
|
1545
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1328
1546
|
const create = async (payload) => {
|
|
1329
1547
|
try {
|
|
1330
1548
|
setIsLoading(true);
|
|
@@ -1368,10 +1586,10 @@ function useAdminBlogPostMutations() {
|
|
|
1368
1586
|
}
|
|
1369
1587
|
function useAdminBlogCategories() {
|
|
1370
1588
|
const { client } = useFoxPixelContext();
|
|
1371
|
-
const [data, setData] = (0,
|
|
1372
|
-
const [isLoading, setIsLoading] = (0,
|
|
1373
|
-
const [error, setError] = (0,
|
|
1374
|
-
const fetchCategories = (0,
|
|
1589
|
+
const [data, setData] = (0, import_react14.useState)(null);
|
|
1590
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
|
|
1591
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1592
|
+
const fetchCategories = (0, import_react14.useCallback)(async () => {
|
|
1375
1593
|
try {
|
|
1376
1594
|
setIsLoading(true);
|
|
1377
1595
|
setError(null);
|
|
@@ -1383,7 +1601,7 @@ function useAdminBlogCategories() {
|
|
|
1383
1601
|
setIsLoading(false);
|
|
1384
1602
|
}
|
|
1385
1603
|
}, [client]);
|
|
1386
|
-
(0,
|
|
1604
|
+
(0, import_react14.useEffect)(() => {
|
|
1387
1605
|
fetchCategories();
|
|
1388
1606
|
}, [fetchCategories]);
|
|
1389
1607
|
const create = async (payload) => {
|
|
@@ -1420,10 +1638,10 @@ function useAdminBlogCategories() {
|
|
|
1420
1638
|
}
|
|
1421
1639
|
function useAdminBlogTags() {
|
|
1422
1640
|
const { client } = useFoxPixelContext();
|
|
1423
|
-
const [data, setData] = (0,
|
|
1424
|
-
const [isLoading, setIsLoading] = (0,
|
|
1425
|
-
const [error, setError] = (0,
|
|
1426
|
-
const fetchTags = (0,
|
|
1641
|
+
const [data, setData] = (0, import_react14.useState)(null);
|
|
1642
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
|
|
1643
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1644
|
+
const fetchTags = (0, import_react14.useCallback)(async () => {
|
|
1427
1645
|
try {
|
|
1428
1646
|
setIsLoading(true);
|
|
1429
1647
|
setError(null);
|
|
@@ -1435,7 +1653,7 @@ function useAdminBlogTags() {
|
|
|
1435
1653
|
setIsLoading(false);
|
|
1436
1654
|
}
|
|
1437
1655
|
}, [client]);
|
|
1438
|
-
(0,
|
|
1656
|
+
(0, import_react14.useEffect)(() => {
|
|
1439
1657
|
fetchTags();
|
|
1440
1658
|
}, [fetchTags]);
|
|
1441
1659
|
const create = async (payload) => {
|
|
@@ -1472,11 +1690,11 @@ function useAdminBlogTags() {
|
|
|
1472
1690
|
}
|
|
1473
1691
|
function useAdminBlogComments(options = {}) {
|
|
1474
1692
|
const { client } = useFoxPixelContext();
|
|
1475
|
-
const [data, setData] = (0,
|
|
1476
|
-
const [isLoading, setIsLoading] = (0,
|
|
1477
|
-
const [error, setError] = (0,
|
|
1693
|
+
const [data, setData] = (0, import_react14.useState)(null);
|
|
1694
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
|
|
1695
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1478
1696
|
const { status, postId, page = 0, size = 20 } = options;
|
|
1479
|
-
const fetchComments = (0,
|
|
1697
|
+
const fetchComments = (0, import_react14.useCallback)(async () => {
|
|
1480
1698
|
try {
|
|
1481
1699
|
setIsLoading(true);
|
|
1482
1700
|
setError(null);
|
|
@@ -1493,7 +1711,7 @@ function useAdminBlogComments(options = {}) {
|
|
|
1493
1711
|
setIsLoading(false);
|
|
1494
1712
|
}
|
|
1495
1713
|
}, [client, status, postId, page, size]);
|
|
1496
|
-
(0,
|
|
1714
|
+
(0, import_react14.useEffect)(() => {
|
|
1497
1715
|
fetchComments();
|
|
1498
1716
|
}, [fetchComments]);
|
|
1499
1717
|
const updateStatus = async (id, newStatus) => {
|
|
@@ -1520,11 +1738,11 @@ function useAdminBlogComments(options = {}) {
|
|
|
1520
1738
|
}
|
|
1521
1739
|
function useAdminNewsletterSubscribers(options = {}) {
|
|
1522
1740
|
const { client } = useFoxPixelContext();
|
|
1523
|
-
const [data, setData] = (0,
|
|
1524
|
-
const [isLoading, setIsLoading] = (0,
|
|
1525
|
-
const [error, setError] = (0,
|
|
1741
|
+
const [data, setData] = (0, import_react14.useState)(null);
|
|
1742
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
|
|
1743
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1526
1744
|
const { status, page = 0, size = 20 } = options;
|
|
1527
|
-
const fetchSubscribers = (0,
|
|
1745
|
+
const fetchSubscribers = (0, import_react14.useCallback)(async () => {
|
|
1528
1746
|
try {
|
|
1529
1747
|
setIsLoading(true);
|
|
1530
1748
|
setError(null);
|
|
@@ -1540,7 +1758,7 @@ function useAdminNewsletterSubscribers(options = {}) {
|
|
|
1540
1758
|
setIsLoading(false);
|
|
1541
1759
|
}
|
|
1542
1760
|
}, [client, status, page, size]);
|
|
1543
|
-
(0,
|
|
1761
|
+
(0, import_react14.useEffect)(() => {
|
|
1544
1762
|
fetchSubscribers();
|
|
1545
1763
|
}, [fetchSubscribers]);
|
|
1546
1764
|
const remove = async (id) => {
|
|
@@ -1557,10 +1775,10 @@ function useAdminNewsletterSubscribers(options = {}) {
|
|
|
1557
1775
|
}
|
|
1558
1776
|
function useAdminNewsletterStats() {
|
|
1559
1777
|
const { client } = useFoxPixelContext();
|
|
1560
|
-
const [data, setData] = (0,
|
|
1561
|
-
const [isLoading, setIsLoading] = (0,
|
|
1562
|
-
const [error, setError] = (0,
|
|
1563
|
-
const fetchStats = (0,
|
|
1778
|
+
const [data, setData] = (0, import_react14.useState)(null);
|
|
1779
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
|
|
1780
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1781
|
+
const fetchStats = (0, import_react14.useCallback)(async () => {
|
|
1564
1782
|
try {
|
|
1565
1783
|
setIsLoading(true);
|
|
1566
1784
|
setError(null);
|
|
@@ -1572,17 +1790,17 @@ function useAdminNewsletterStats() {
|
|
|
1572
1790
|
setIsLoading(false);
|
|
1573
1791
|
}
|
|
1574
1792
|
}, [client]);
|
|
1575
|
-
(0,
|
|
1793
|
+
(0, import_react14.useEffect)(() => {
|
|
1576
1794
|
fetchStats();
|
|
1577
1795
|
}, [fetchStats]);
|
|
1578
1796
|
return { data, isLoading, error, refetch: fetchStats };
|
|
1579
1797
|
}
|
|
1580
1798
|
function useAdminBlogSettings() {
|
|
1581
1799
|
const { client } = useFoxPixelContext();
|
|
1582
|
-
const [data, setData] = (0,
|
|
1583
|
-
const [isLoading, setIsLoading] = (0,
|
|
1584
|
-
const [error, setError] = (0,
|
|
1585
|
-
const fetchSettings = (0,
|
|
1800
|
+
const [data, setData] = (0, import_react14.useState)(null);
|
|
1801
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
|
|
1802
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1803
|
+
const fetchSettings = (0, import_react14.useCallback)(async () => {
|
|
1586
1804
|
try {
|
|
1587
1805
|
setIsLoading(true);
|
|
1588
1806
|
setError(null);
|
|
@@ -1594,7 +1812,7 @@ function useAdminBlogSettings() {
|
|
|
1594
1812
|
setIsLoading(false);
|
|
1595
1813
|
}
|
|
1596
1814
|
}, [client]);
|
|
1597
|
-
(0,
|
|
1815
|
+
(0, import_react14.useEffect)(() => {
|
|
1598
1816
|
fetchSettings();
|
|
1599
1817
|
}, [fetchSettings]);
|
|
1600
1818
|
const update = async (settings) => {
|
|
@@ -1611,10 +1829,10 @@ function useAdminBlogSettings() {
|
|
|
1611
1829
|
}
|
|
1612
1830
|
function useAdminBlogAnalytics() {
|
|
1613
1831
|
const { client } = useFoxPixelContext();
|
|
1614
|
-
const [data, setData] = (0,
|
|
1615
|
-
const [isLoading, setIsLoading] = (0,
|
|
1616
|
-
const [error, setError] = (0,
|
|
1617
|
-
const fetchAnalytics = (0,
|
|
1832
|
+
const [data, setData] = (0, import_react14.useState)(null);
|
|
1833
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(true);
|
|
1834
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
1835
|
+
const fetchAnalytics = (0, import_react14.useCallback)(async () => {
|
|
1618
1836
|
try {
|
|
1619
1837
|
setIsLoading(true);
|
|
1620
1838
|
setError(null);
|
|
@@ -1626,7 +1844,7 @@ function useAdminBlogAnalytics() {
|
|
|
1626
1844
|
setIsLoading(false);
|
|
1627
1845
|
}
|
|
1628
1846
|
}, [client]);
|
|
1629
|
-
(0,
|
|
1847
|
+
(0, import_react14.useEffect)(() => {
|
|
1630
1848
|
fetchAnalytics();
|
|
1631
1849
|
}, [fetchAnalytics]);
|
|
1632
1850
|
return { data, isLoading, error, refetch: fetchAnalytics };
|
|
@@ -1675,6 +1893,7 @@ function getBlogPostSchemaLd(post, options) {
|
|
|
1675
1893
|
ProtectedRoute,
|
|
1676
1894
|
SITE_CONTENT_QUERY_KEY,
|
|
1677
1895
|
getBlogPostSchemaLd,
|
|
1896
|
+
prefetchSiteContent,
|
|
1678
1897
|
useAdminBlogAnalytics,
|
|
1679
1898
|
useAdminBlogCategories,
|
|
1680
1899
|
useAdminBlogComments,
|