@foxpixel/react 0.1.1 → 0.2.1
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 +309 -3
- package/dist/index.d.ts +309 -3
- package/dist/index.js +767 -97
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +755 -97
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -3
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/context/FoxPixelContext.tsx
|
|
2
|
-
import { createContext, useContext, useMemo } from "react";
|
|
2
|
+
import React, { createContext, useContext, useMemo } from "react";
|
|
3
3
|
|
|
4
4
|
// src/client/http.ts
|
|
5
5
|
import axios from "axios";
|
|
@@ -111,15 +111,21 @@ var FoxPixelHttpClient = class {
|
|
|
111
111
|
|
|
112
112
|
// src/context/FoxPixelContext.tsx
|
|
113
113
|
import { jsx } from "react/jsx-runtime";
|
|
114
|
+
if (!React || typeof React.useMemo !== "function") {
|
|
115
|
+
throw new Error(
|
|
116
|
+
'@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).'
|
|
117
|
+
);
|
|
118
|
+
}
|
|
114
119
|
var FoxPixelContext = createContext(null);
|
|
115
|
-
function FoxPixelProvider({ children, config = {} }) {
|
|
120
|
+
function FoxPixelProvider({ children, config = {}, queryClient }) {
|
|
116
121
|
const client = useMemo(() => {
|
|
117
122
|
return new FoxPixelHttpClient(config);
|
|
118
123
|
}, [config.apiUrl, config.apiKey, config.tenantId]);
|
|
119
124
|
const value = useMemo(() => ({
|
|
120
125
|
client,
|
|
121
|
-
config
|
|
122
|
-
|
|
126
|
+
config,
|
|
127
|
+
queryClient: queryClient ?? null
|
|
128
|
+
}), [client, config, queryClient]);
|
|
123
129
|
return /* @__PURE__ */ jsx(FoxPixelContext.Provider, { value, children });
|
|
124
130
|
}
|
|
125
131
|
function useFoxPixelContext() {
|
|
@@ -238,7 +244,8 @@ function AuthProvider({
|
|
|
238
244
|
logout,
|
|
239
245
|
register,
|
|
240
246
|
updateProfile,
|
|
241
|
-
refetch: fetchCurrentUser
|
|
247
|
+
refetch: fetchCurrentUser,
|
|
248
|
+
hasPermission: (permission) => user !== null && permission === "site:content:update"
|
|
242
249
|
};
|
|
243
250
|
return /* @__PURE__ */ jsx2(AuthContext.Provider, { value, children });
|
|
244
251
|
}
|
|
@@ -344,13 +351,473 @@ function withAuth(Component, options = {}) {
|
|
|
344
351
|
};
|
|
345
352
|
}
|
|
346
353
|
|
|
354
|
+
// src/components/Editable.tsx
|
|
355
|
+
import { createElement, useCallback as useCallback3, useState as useState7 } from "react";
|
|
356
|
+
|
|
357
|
+
// src/hooks/useEditMode.ts
|
|
358
|
+
import { useEffect as useEffect5, useState as useState5, useCallback as useCallback2 } from "react";
|
|
359
|
+
var SITE_CONTENT_QUERY_KEY = "siteContent";
|
|
360
|
+
function useEditMode() {
|
|
361
|
+
const [isEditMode, setIsEditMode] = useState5(false);
|
|
362
|
+
useEffect5(() => {
|
|
363
|
+
if (typeof window === "undefined") return;
|
|
364
|
+
const params = new URLSearchParams(window.location.search);
|
|
365
|
+
setIsEditMode(params.get("edit-mode") === "true");
|
|
366
|
+
}, []);
|
|
367
|
+
return isEditMode;
|
|
368
|
+
}
|
|
369
|
+
function useEditModeMessaging() {
|
|
370
|
+
const ctx = useFoxPixelContext();
|
|
371
|
+
const queryClient = ctx?.queryClient ?? null;
|
|
372
|
+
const isEditMode = useEditMode();
|
|
373
|
+
useEffect5(() => {
|
|
374
|
+
if (!isEditMode || typeof window === "undefined") return;
|
|
375
|
+
window.parent.postMessage({ type: "FOXPIXEL_READY" }, "*");
|
|
376
|
+
const handleMessage = (event) => {
|
|
377
|
+
if (!queryClient) return;
|
|
378
|
+
const { type, payload } = event.data || {};
|
|
379
|
+
if (type !== "FOXPIXEL_CONTENT_UPDATED" || !payload?.contentKey) return;
|
|
380
|
+
const { contentKey, newValue } = payload;
|
|
381
|
+
if (typeof newValue === "string") {
|
|
382
|
+
queryClient.setQueryData(
|
|
383
|
+
[SITE_CONTENT_QUERY_KEY, contentKey],
|
|
384
|
+
(prev) => ({
|
|
385
|
+
value: newValue,
|
|
386
|
+
contentType: prev?.contentType ?? "TEXT"
|
|
387
|
+
})
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
queryClient.invalidateQueries({
|
|
391
|
+
queryKey: [SITE_CONTENT_QUERY_KEY, contentKey]
|
|
392
|
+
});
|
|
393
|
+
};
|
|
394
|
+
window.addEventListener("message", handleMessage);
|
|
395
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
396
|
+
}, [isEditMode, queryClient]);
|
|
397
|
+
return isEditMode;
|
|
398
|
+
}
|
|
399
|
+
function useSendEditRequest() {
|
|
400
|
+
const isEditMode = useEditMode();
|
|
401
|
+
return useCallback2(
|
|
402
|
+
(contentKey, currentValue, contentType = "text", section, description) => {
|
|
403
|
+
if (!isEditMode) return;
|
|
404
|
+
if (typeof window !== "undefined" && window.parent !== window) {
|
|
405
|
+
window.parent.postMessage(
|
|
406
|
+
{
|
|
407
|
+
type: "FOXPIXEL_EDIT_CONTENT",
|
|
408
|
+
payload: {
|
|
409
|
+
contentKey,
|
|
410
|
+
currentValue,
|
|
411
|
+
contentType,
|
|
412
|
+
section,
|
|
413
|
+
description
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
"*"
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
[isEditMode]
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// src/hooks/useSiteContentQuery.ts
|
|
425
|
+
import { useState as useState6, useEffect as useEffect6, useRef } from "react";
|
|
426
|
+
function getCached(queryClient, contentKey) {
|
|
427
|
+
const data = queryClient.getQueryData([
|
|
428
|
+
SITE_CONTENT_QUERY_KEY,
|
|
429
|
+
contentKey
|
|
430
|
+
]);
|
|
431
|
+
if (data == null) return void 0;
|
|
432
|
+
return { value: data.value ?? "", contentType: data.contentType ?? "TEXT" };
|
|
433
|
+
}
|
|
434
|
+
function useSiteContentQuery(contentKey, options) {
|
|
435
|
+
const { defaultValue } = options;
|
|
436
|
+
const { client, queryClient } = useFoxPixelContext();
|
|
437
|
+
const [state, setState] = useState6(() => {
|
|
438
|
+
if (queryClient) {
|
|
439
|
+
const cached = getCached(queryClient, contentKey);
|
|
440
|
+
if (cached) {
|
|
441
|
+
return { value: cached.value, isLoading: false, contentType: cached.contentType };
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return { value: defaultValue, isLoading: true, contentType: "TEXT" };
|
|
445
|
+
});
|
|
446
|
+
const contentKeyRef = useRef(contentKey);
|
|
447
|
+
contentKeyRef.current = contentKey;
|
|
448
|
+
useEffect6(() => {
|
|
449
|
+
if (!queryClient) {
|
|
450
|
+
setState((s) => ({ ...s, value: defaultValue, isLoading: false }));
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
const key = contentKeyRef.current;
|
|
454
|
+
const queryKey = [SITE_CONTENT_QUERY_KEY, key];
|
|
455
|
+
const queryFn = async () => {
|
|
456
|
+
try {
|
|
457
|
+
const content = await client.get(
|
|
458
|
+
`/api/site/content/${encodeURIComponent(key)}`
|
|
459
|
+
);
|
|
460
|
+
if (!content) return null;
|
|
461
|
+
return {
|
|
462
|
+
value: content.value ?? "",
|
|
463
|
+
contentType: content.contentType ?? "TEXT"
|
|
464
|
+
};
|
|
465
|
+
} catch (err) {
|
|
466
|
+
const status = err?.response?.status;
|
|
467
|
+
if (status === 404) return null;
|
|
468
|
+
throw err;
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
let cancelled = false;
|
|
472
|
+
queryClient.fetchQuery({
|
|
473
|
+
queryKey,
|
|
474
|
+
queryFn,
|
|
475
|
+
staleTime: 1e3 * 60 * 5,
|
|
476
|
+
retry: 1
|
|
477
|
+
}).then((data) => {
|
|
478
|
+
if (cancelled) return;
|
|
479
|
+
setState({
|
|
480
|
+
value: data?.value ?? defaultValue,
|
|
481
|
+
isLoading: false,
|
|
482
|
+
contentType: data?.contentType ?? "TEXT"
|
|
483
|
+
});
|
|
484
|
+
}).catch(() => {
|
|
485
|
+
if (cancelled) return;
|
|
486
|
+
setState((s) => ({ ...s, value: defaultValue, isLoading: false }));
|
|
487
|
+
});
|
|
488
|
+
const unsub = queryClient.getQueryCache().subscribe((event) => {
|
|
489
|
+
if (event?.type === "updated" && event?.query?.queryKey[1] === key) {
|
|
490
|
+
const cached = getCached(queryClient, key);
|
|
491
|
+
if (cached && !cancelled) {
|
|
492
|
+
setState({
|
|
493
|
+
value: cached.value,
|
|
494
|
+
isLoading: false,
|
|
495
|
+
contentType: cached.contentType
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
return () => {
|
|
501
|
+
cancelled = true;
|
|
502
|
+
unsub();
|
|
503
|
+
};
|
|
504
|
+
}, [queryClient, contentKey, defaultValue, client]);
|
|
505
|
+
return state;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/utils/sanitize.ts
|
|
509
|
+
import sanitizeHtmlLib from "sanitize-html";
|
|
510
|
+
var DEFAULT_ALLOWED_TAGS = [
|
|
511
|
+
"p",
|
|
512
|
+
"br",
|
|
513
|
+
"strong",
|
|
514
|
+
"em",
|
|
515
|
+
"u",
|
|
516
|
+
"s",
|
|
517
|
+
"a",
|
|
518
|
+
"ul",
|
|
519
|
+
"ol",
|
|
520
|
+
"li",
|
|
521
|
+
"h1",
|
|
522
|
+
"h2",
|
|
523
|
+
"h3",
|
|
524
|
+
"h4",
|
|
525
|
+
"h5",
|
|
526
|
+
"h6",
|
|
527
|
+
"blockquote",
|
|
528
|
+
"code",
|
|
529
|
+
"pre",
|
|
530
|
+
"span",
|
|
531
|
+
"div",
|
|
532
|
+
"img",
|
|
533
|
+
"table",
|
|
534
|
+
"thead",
|
|
535
|
+
"tbody",
|
|
536
|
+
"tr",
|
|
537
|
+
"th",
|
|
538
|
+
"td"
|
|
539
|
+
];
|
|
540
|
+
var DEFAULT_ALLOWED_ATTR = {
|
|
541
|
+
a: ["href", "target", "rel", "title"],
|
|
542
|
+
img: ["src", "alt", "title", "width", "height"],
|
|
543
|
+
"*": ["class"]
|
|
544
|
+
};
|
|
545
|
+
function sanitizeHtml(html) {
|
|
546
|
+
if (typeof html !== "string") return "";
|
|
547
|
+
return sanitizeHtmlLib(html, {
|
|
548
|
+
allowedTags: DEFAULT_ALLOWED_TAGS,
|
|
549
|
+
allowedAttributes: DEFAULT_ALLOWED_ATTR
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// src/utils/cn.ts
|
|
554
|
+
function cn(...args) {
|
|
555
|
+
return args.filter(Boolean).join(" ");
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// src/components/Editable.tsx
|
|
559
|
+
import { jsx as jsx6, jsxs } from "react/jsx-runtime";
|
|
560
|
+
var EDIT_MODE_TOOLTIP_STYLE = {
|
|
561
|
+
position: "absolute",
|
|
562
|
+
top: "-28px",
|
|
563
|
+
left: "50%",
|
|
564
|
+
transform: "translateX(-50%)",
|
|
565
|
+
fontSize: "10px",
|
|
566
|
+
fontFamily: "system-ui, sans-serif",
|
|
567
|
+
padding: "4px 8px",
|
|
568
|
+
backgroundColor: "rgb(37 99 235)",
|
|
569
|
+
color: "white",
|
|
570
|
+
borderRadius: "4px",
|
|
571
|
+
whiteSpace: "nowrap",
|
|
572
|
+
pointerEvents: "none",
|
|
573
|
+
zIndex: 100,
|
|
574
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.2)",
|
|
575
|
+
transition: "opacity 0.15s ease"
|
|
576
|
+
};
|
|
577
|
+
function Editable({
|
|
578
|
+
contentKey,
|
|
579
|
+
defaultValue,
|
|
580
|
+
as = "span",
|
|
581
|
+
multiline = false,
|
|
582
|
+
className
|
|
583
|
+
}) {
|
|
584
|
+
const [isHovered, setIsHovered] = useState7(false);
|
|
585
|
+
const isEditMode = useEditModeMessaging();
|
|
586
|
+
const sendEditRequest = useSendEditRequest();
|
|
587
|
+
const { value, isLoading, contentType } = useSiteContentQuery(contentKey, {
|
|
588
|
+
defaultValue
|
|
589
|
+
});
|
|
590
|
+
const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
|
|
591
|
+
const handleClick = useCallback3(
|
|
592
|
+
(e) => {
|
|
593
|
+
if (isEditMode) {
|
|
594
|
+
e.preventDefault();
|
|
595
|
+
e.stopPropagation();
|
|
596
|
+
sendEditRequest(
|
|
597
|
+
contentKey,
|
|
598
|
+
value,
|
|
599
|
+
contentType?.toLowerCase() || "text",
|
|
600
|
+
section
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
[isEditMode, contentKey, value, contentType, section, sendEditRequest]
|
|
605
|
+
);
|
|
606
|
+
if (isLoading) {
|
|
607
|
+
return createElement(as, {
|
|
608
|
+
className: cn(
|
|
609
|
+
"animate-pulse bg-muted rounded",
|
|
610
|
+
multiline ? "h-20" : "h-6",
|
|
611
|
+
"inline-block min-w-[100px]",
|
|
612
|
+
className
|
|
613
|
+
),
|
|
614
|
+
"aria-busy": true,
|
|
615
|
+
"aria-label": "Loading content..."
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
const editModeWrapperStyle = isEditMode ? {
|
|
619
|
+
position: "relative",
|
|
620
|
+
display: "inline",
|
|
621
|
+
cursor: "pointer",
|
|
622
|
+
borderRadius: "2px",
|
|
623
|
+
outline: isHovered ? "2px solid rgb(59 130 246)" : "none",
|
|
624
|
+
outlineOffset: "2px",
|
|
625
|
+
backgroundColor: isHovered ? "rgba(59 130 246 / 0.08)" : void 0
|
|
626
|
+
} : {};
|
|
627
|
+
const tooltipSpan = isEditMode ? /* @__PURE__ */ jsx6(
|
|
628
|
+
"span",
|
|
629
|
+
{
|
|
630
|
+
style: {
|
|
631
|
+
...EDIT_MODE_TOOLTIP_STYLE,
|
|
632
|
+
opacity: isHovered ? 1 : 0
|
|
633
|
+
},
|
|
634
|
+
"aria-hidden": true,
|
|
635
|
+
children: "Click to edit"
|
|
636
|
+
}
|
|
637
|
+
) : null;
|
|
638
|
+
const hoverHandlers = isEditMode ? {
|
|
639
|
+
onMouseEnter: () => setIsHovered(true),
|
|
640
|
+
onMouseLeave: () => setIsHovered(false)
|
|
641
|
+
} : {};
|
|
642
|
+
if (multiline && value.includes("\n")) {
|
|
643
|
+
const safeBr = sanitizeHtml(value.replace(/\n/g, "<br />"));
|
|
644
|
+
return createElement(
|
|
645
|
+
"span",
|
|
646
|
+
{ style: editModeWrapperStyle, ...hoverHandlers },
|
|
647
|
+
createElement(as, {
|
|
648
|
+
className,
|
|
649
|
+
"data-content-key": contentKey,
|
|
650
|
+
"data-editable": isEditMode ? "true" : void 0,
|
|
651
|
+
onClick: isEditMode ? handleClick : void 0,
|
|
652
|
+
dangerouslySetInnerHTML: { __html: safeBr }
|
|
653
|
+
}),
|
|
654
|
+
tooltipSpan
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
return createElement(
|
|
658
|
+
"span",
|
|
659
|
+
{ style: editModeWrapperStyle, ...hoverHandlers },
|
|
660
|
+
createElement(
|
|
661
|
+
as,
|
|
662
|
+
{
|
|
663
|
+
className,
|
|
664
|
+
"data-content-key": contentKey,
|
|
665
|
+
"data-editable": isEditMode ? "true" : void 0,
|
|
666
|
+
onClick: isEditMode ? handleClick : void 0
|
|
667
|
+
},
|
|
668
|
+
value
|
|
669
|
+
),
|
|
670
|
+
tooltipSpan
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
function EditableHTML({
|
|
674
|
+
contentKey,
|
|
675
|
+
defaultValue,
|
|
676
|
+
as = "div",
|
|
677
|
+
className
|
|
678
|
+
}) {
|
|
679
|
+
const [isHovered, setIsHovered] = useState7(false);
|
|
680
|
+
const isEditMode = useEditModeMessaging();
|
|
681
|
+
const sendEditRequest = useSendEditRequest();
|
|
682
|
+
const { value, isLoading } = useSiteContentQuery(contentKey, {
|
|
683
|
+
defaultValue
|
|
684
|
+
});
|
|
685
|
+
const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
|
|
686
|
+
const handleClick = useCallback3(
|
|
687
|
+
(e) => {
|
|
688
|
+
if (isEditMode) {
|
|
689
|
+
e.preventDefault();
|
|
690
|
+
e.stopPropagation();
|
|
691
|
+
sendEditRequest(contentKey, value, "html", section);
|
|
692
|
+
}
|
|
693
|
+
},
|
|
694
|
+
[isEditMode, contentKey, value, section, sendEditRequest]
|
|
695
|
+
);
|
|
696
|
+
if (isLoading) {
|
|
697
|
+
return createElement(as, {
|
|
698
|
+
className: cn("animate-pulse bg-muted rounded h-32", className),
|
|
699
|
+
"aria-busy": true
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
const wrapperStyle = isEditMode ? {
|
|
703
|
+
position: "relative",
|
|
704
|
+
cursor: "pointer",
|
|
705
|
+
borderRadius: "2px",
|
|
706
|
+
outline: isHovered ? "2px solid rgb(59 130 246)" : "none",
|
|
707
|
+
outlineOffset: "2px",
|
|
708
|
+
backgroundColor: isHovered ? "rgba(59 130 246 / 0.08)" : void 0
|
|
709
|
+
} : {};
|
|
710
|
+
const safeHtml = sanitizeHtml(value);
|
|
711
|
+
const hoverHandlers = isEditMode ? { onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false) } : {};
|
|
712
|
+
return createElement(
|
|
713
|
+
"div",
|
|
714
|
+
{ style: wrapperStyle, ...hoverHandlers },
|
|
715
|
+
createElement(as, {
|
|
716
|
+
className: cn("prose prose-slate dark:prose-invert", className),
|
|
717
|
+
"data-content-key": contentKey,
|
|
718
|
+
"data-editable": isEditMode ? "true" : void 0,
|
|
719
|
+
onClick: isEditMode ? handleClick : void 0,
|
|
720
|
+
dangerouslySetInnerHTML: { __html: safeHtml }
|
|
721
|
+
}),
|
|
722
|
+
isEditMode && /* @__PURE__ */ jsx6(
|
|
723
|
+
"span",
|
|
724
|
+
{
|
|
725
|
+
style: {
|
|
726
|
+
...EDIT_MODE_TOOLTIP_STYLE,
|
|
727
|
+
top: "-24px",
|
|
728
|
+
opacity: isHovered ? 1 : 0
|
|
729
|
+
},
|
|
730
|
+
"aria-hidden": true,
|
|
731
|
+
children: "Click to edit"
|
|
732
|
+
}
|
|
733
|
+
)
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
function EditableImage({
|
|
737
|
+
contentKey,
|
|
738
|
+
defaultValue,
|
|
739
|
+
alt,
|
|
740
|
+
className,
|
|
741
|
+
width,
|
|
742
|
+
height,
|
|
743
|
+
priority = false
|
|
744
|
+
}) {
|
|
745
|
+
const [isHovered, setIsHovered] = useState7(false);
|
|
746
|
+
const isEditMode = useEditModeMessaging();
|
|
747
|
+
const sendEditRequest = useSendEditRequest();
|
|
748
|
+
const { value: src, isLoading } = useSiteContentQuery(contentKey, {
|
|
749
|
+
defaultValue
|
|
750
|
+
});
|
|
751
|
+
const section = contentKey.includes(".") ? contentKey.split(".")[0] : void 0;
|
|
752
|
+
const handleClick = useCallback3(
|
|
753
|
+
(e) => {
|
|
754
|
+
if (isEditMode) {
|
|
755
|
+
e.preventDefault();
|
|
756
|
+
e.stopPropagation();
|
|
757
|
+
sendEditRequest(contentKey, src, "image", section);
|
|
758
|
+
}
|
|
759
|
+
},
|
|
760
|
+
[isEditMode, contentKey, src, section, sendEditRequest]
|
|
761
|
+
);
|
|
762
|
+
if (isLoading) {
|
|
763
|
+
return /* @__PURE__ */ jsx6(
|
|
764
|
+
"div",
|
|
765
|
+
{
|
|
766
|
+
className: cn("animate-pulse bg-muted rounded", className),
|
|
767
|
+
style: { width, height },
|
|
768
|
+
"aria-busy": "true"
|
|
769
|
+
}
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
const wrapperStyle = isEditMode ? {
|
|
773
|
+
position: "relative",
|
|
774
|
+
display: "inline-block",
|
|
775
|
+
cursor: "pointer",
|
|
776
|
+
borderRadius: "2px",
|
|
777
|
+
outline: isHovered ? "2px solid rgb(59 130 246)" : "none",
|
|
778
|
+
outlineOffset: "2px"
|
|
779
|
+
} : {};
|
|
780
|
+
const hoverHandlers = isEditMode ? { onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false) } : {};
|
|
781
|
+
return /* @__PURE__ */ jsxs("div", { style: wrapperStyle, ...hoverHandlers, children: [
|
|
782
|
+
/* @__PURE__ */ jsx6(
|
|
783
|
+
"img",
|
|
784
|
+
{
|
|
785
|
+
src,
|
|
786
|
+
alt,
|
|
787
|
+
className,
|
|
788
|
+
style: isEditMode && isHovered ? { opacity: 0.95 } : void 0,
|
|
789
|
+
width,
|
|
790
|
+
height,
|
|
791
|
+
loading: priority ? "eager" : "lazy",
|
|
792
|
+
"data-content-key": contentKey,
|
|
793
|
+
"data-editable": isEditMode ? "true" : void 0,
|
|
794
|
+
onClick: isEditMode ? handleClick : void 0
|
|
795
|
+
}
|
|
796
|
+
),
|
|
797
|
+
isEditMode && /* @__PURE__ */ jsx6(
|
|
798
|
+
"span",
|
|
799
|
+
{
|
|
800
|
+
style: {
|
|
801
|
+
...EDIT_MODE_TOOLTIP_STYLE,
|
|
802
|
+
top: "8px",
|
|
803
|
+
left: "8px",
|
|
804
|
+
transform: "none",
|
|
805
|
+
opacity: isHovered ? 1 : 0
|
|
806
|
+
},
|
|
807
|
+
"aria-hidden": true,
|
|
808
|
+
children: "Click to edit image"
|
|
809
|
+
}
|
|
810
|
+
)
|
|
811
|
+
] });
|
|
812
|
+
}
|
|
813
|
+
|
|
347
814
|
// src/hooks/useServices.ts
|
|
348
|
-
import { useState as
|
|
815
|
+
import { useState as useState8, useEffect as useEffect7 } from "react";
|
|
349
816
|
function useServices(options = {}) {
|
|
350
817
|
const { client } = useFoxPixelContext();
|
|
351
|
-
const [services, setServices] =
|
|
352
|
-
const [isLoading, setIsLoading] =
|
|
353
|
-
const [error, setError] =
|
|
818
|
+
const [services, setServices] = useState8(null);
|
|
819
|
+
const [isLoading, setIsLoading] = useState8(true);
|
|
820
|
+
const [error, setError] = useState8(null);
|
|
354
821
|
const fetchServices = async () => {
|
|
355
822
|
try {
|
|
356
823
|
setIsLoading(true);
|
|
@@ -368,7 +835,7 @@ function useServices(options = {}) {
|
|
|
368
835
|
setIsLoading(false);
|
|
369
836
|
}
|
|
370
837
|
};
|
|
371
|
-
|
|
838
|
+
useEffect7(() => {
|
|
372
839
|
fetchServices();
|
|
373
840
|
}, [options.category, options.active]);
|
|
374
841
|
return {
|
|
@@ -380,11 +847,11 @@ function useServices(options = {}) {
|
|
|
380
847
|
}
|
|
381
848
|
|
|
382
849
|
// src/hooks/useLeadCapture.ts
|
|
383
|
-
import { useState as
|
|
850
|
+
import { useState as useState9 } from "react";
|
|
384
851
|
function useLeadCapture() {
|
|
385
852
|
const { client } = useFoxPixelContext();
|
|
386
|
-
const [isLoading, setIsLoading] =
|
|
387
|
-
const [error, setError] =
|
|
853
|
+
const [isLoading, setIsLoading] = useState9(false);
|
|
854
|
+
const [error, setError] = useState9(null);
|
|
388
855
|
const captureLead = async (data) => {
|
|
389
856
|
try {
|
|
390
857
|
setIsLoading(true);
|
|
@@ -407,11 +874,11 @@ function useLeadCapture() {
|
|
|
407
874
|
}
|
|
408
875
|
|
|
409
876
|
// src/hooks/useContactCapture.ts
|
|
410
|
-
import { useState as
|
|
877
|
+
import { useState as useState10 } from "react";
|
|
411
878
|
function useContactCapture() {
|
|
412
879
|
const { client } = useFoxPixelContext();
|
|
413
|
-
const [isLoading, setIsLoading] =
|
|
414
|
-
const [error, setError] =
|
|
880
|
+
const [isLoading, setIsLoading] = useState10(false);
|
|
881
|
+
const [error, setError] = useState10(null);
|
|
415
882
|
const captureContact = async (data) => {
|
|
416
883
|
try {
|
|
417
884
|
setIsLoading(true);
|
|
@@ -433,13 +900,174 @@ function useContactCapture() {
|
|
|
433
900
|
};
|
|
434
901
|
}
|
|
435
902
|
|
|
903
|
+
// src/hooks/useSiteContent.ts
|
|
904
|
+
import { useState as useState11, useEffect as useEffect8, useCallback as useCallback4 } from "react";
|
|
905
|
+
function useSiteContent(contentKey, options = {}) {
|
|
906
|
+
const { defaultValue = "", fetchOnMount = true } = options;
|
|
907
|
+
const { client } = useFoxPixelContext();
|
|
908
|
+
const { user, hasPermission } = useAuth();
|
|
909
|
+
const [data, setData] = useState11(null);
|
|
910
|
+
const [isLoading, setIsLoading] = useState11(fetchOnMount);
|
|
911
|
+
const [error, setError] = useState11(null);
|
|
912
|
+
const canEdit = user !== null && hasPermission("site:content:update");
|
|
913
|
+
const fetchContent = useCallback4(async () => {
|
|
914
|
+
try {
|
|
915
|
+
setIsLoading(true);
|
|
916
|
+
setError(null);
|
|
917
|
+
const content = await client.get(
|
|
918
|
+
`/api/site/content/${encodeURIComponent(contentKey)}`
|
|
919
|
+
);
|
|
920
|
+
setData(content);
|
|
921
|
+
} catch (err) {
|
|
922
|
+
if (err?.status === 404) {
|
|
923
|
+
setData(null);
|
|
924
|
+
} else {
|
|
925
|
+
setError(err);
|
|
926
|
+
}
|
|
927
|
+
} finally {
|
|
928
|
+
setIsLoading(false);
|
|
929
|
+
}
|
|
930
|
+
}, [client, contentKey]);
|
|
931
|
+
const updateContent = useCallback4(async (newValue) => {
|
|
932
|
+
try {
|
|
933
|
+
setError(null);
|
|
934
|
+
const updated = await client.put(
|
|
935
|
+
`/api/site/content/${encodeURIComponent(contentKey)}`,
|
|
936
|
+
{ value: newValue }
|
|
937
|
+
);
|
|
938
|
+
setData(updated);
|
|
939
|
+
} catch (err) {
|
|
940
|
+
setError(err);
|
|
941
|
+
throw err;
|
|
942
|
+
}
|
|
943
|
+
}, [client, contentKey]);
|
|
944
|
+
useEffect8(() => {
|
|
945
|
+
if (fetchOnMount) {
|
|
946
|
+
fetchContent();
|
|
947
|
+
}
|
|
948
|
+
}, [contentKey, fetchOnMount]);
|
|
949
|
+
const value = data?.value ?? defaultValue;
|
|
950
|
+
return {
|
|
951
|
+
data,
|
|
952
|
+
value,
|
|
953
|
+
isLoading,
|
|
954
|
+
error,
|
|
955
|
+
canEdit,
|
|
956
|
+
update: updateContent,
|
|
957
|
+
refetch: fetchContent
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
function useSiteContents(contentKeys, options = {}) {
|
|
961
|
+
const { defaults = {} } = options;
|
|
962
|
+
const { client } = useFoxPixelContext();
|
|
963
|
+
const [data, setData] = useState11({});
|
|
964
|
+
const [isLoading, setIsLoading] = useState11(true);
|
|
965
|
+
const [error, setError] = useState11(null);
|
|
966
|
+
const fetchContents = useCallback4(async () => {
|
|
967
|
+
if (contentKeys.length === 0) {
|
|
968
|
+
setData({});
|
|
969
|
+
setIsLoading(false);
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
try {
|
|
973
|
+
setIsLoading(true);
|
|
974
|
+
setError(null);
|
|
975
|
+
const contents = await client.post(
|
|
976
|
+
"/api/site/content/batch",
|
|
977
|
+
contentKeys
|
|
978
|
+
);
|
|
979
|
+
setData(contents);
|
|
980
|
+
} catch (err) {
|
|
981
|
+
setError(err);
|
|
982
|
+
} finally {
|
|
983
|
+
setIsLoading(false);
|
|
984
|
+
}
|
|
985
|
+
}, [client, contentKeys.join(",")]);
|
|
986
|
+
useEffect8(() => {
|
|
987
|
+
fetchContents();
|
|
988
|
+
}, [fetchContents]);
|
|
989
|
+
const getValue = useCallback4((key, defaultValue) => {
|
|
990
|
+
const content = data[key];
|
|
991
|
+
if (content?.value) {
|
|
992
|
+
return content.value;
|
|
993
|
+
}
|
|
994
|
+
return defaultValue ?? defaults[key] ?? "";
|
|
995
|
+
}, [data, defaults]);
|
|
996
|
+
return {
|
|
997
|
+
data,
|
|
998
|
+
getValue,
|
|
999
|
+
isLoading,
|
|
1000
|
+
error,
|
|
1001
|
+
refetch: fetchContents
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
function useSiteContentSection(section) {
|
|
1005
|
+
const { client } = useFoxPixelContext();
|
|
1006
|
+
const [contents, setContents] = useState11([]);
|
|
1007
|
+
const [isLoading, setIsLoading] = useState11(true);
|
|
1008
|
+
const [error, setError] = useState11(null);
|
|
1009
|
+
const fetchContents = useCallback4(async () => {
|
|
1010
|
+
try {
|
|
1011
|
+
setIsLoading(true);
|
|
1012
|
+
setError(null);
|
|
1013
|
+
const data = await client.get(
|
|
1014
|
+
`/api/site/content/section/${encodeURIComponent(section)}`
|
|
1015
|
+
);
|
|
1016
|
+
setContents(data);
|
|
1017
|
+
} catch (err) {
|
|
1018
|
+
setError(err);
|
|
1019
|
+
} finally {
|
|
1020
|
+
setIsLoading(false);
|
|
1021
|
+
}
|
|
1022
|
+
}, [client, section]);
|
|
1023
|
+
useEffect8(() => {
|
|
1024
|
+
fetchContents();
|
|
1025
|
+
}, [fetchContents]);
|
|
1026
|
+
return {
|
|
1027
|
+
contents,
|
|
1028
|
+
isLoading,
|
|
1029
|
+
error,
|
|
1030
|
+
refetch: fetchContents
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// src/prefetchSiteContent.ts
|
|
1035
|
+
async function prefetchSiteContent(queryClient, options) {
|
|
1036
|
+
const { apiUrl, apiKey, tenantId, contentKeys } = options;
|
|
1037
|
+
const client = new FoxPixelHttpClient({ apiUrl, apiKey, tenantId });
|
|
1038
|
+
await Promise.all(
|
|
1039
|
+
contentKeys.map(async (contentKey) => {
|
|
1040
|
+
try {
|
|
1041
|
+
const content = await client.get(
|
|
1042
|
+
`/api/site/content/${encodeURIComponent(contentKey)}`
|
|
1043
|
+
);
|
|
1044
|
+
queryClient.setQueryData(
|
|
1045
|
+
[SITE_CONTENT_QUERY_KEY, contentKey],
|
|
1046
|
+
{
|
|
1047
|
+
value: content?.value ?? "",
|
|
1048
|
+
contentType: content?.contentType ?? "TEXT"
|
|
1049
|
+
}
|
|
1050
|
+
);
|
|
1051
|
+
} catch (err) {
|
|
1052
|
+
const status = err?.response?.status;
|
|
1053
|
+
if (status === 404) {
|
|
1054
|
+
queryClient.setQueryData([SITE_CONTENT_QUERY_KEY, contentKey], {
|
|
1055
|
+
value: "",
|
|
1056
|
+
contentType: "TEXT"
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
})
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
436
1064
|
// src/blog/hooks.ts
|
|
437
|
-
import { useState as
|
|
1065
|
+
import { useState as useState12, useEffect as useEffect9 } from "react";
|
|
438
1066
|
function useBlogPosts(options = {}) {
|
|
439
1067
|
const { client } = useFoxPixelContext();
|
|
440
|
-
const [data, setData] =
|
|
441
|
-
const [isLoading, setIsLoading] =
|
|
442
|
-
const [error, setError] =
|
|
1068
|
+
const [data, setData] = useState12(null);
|
|
1069
|
+
const [isLoading, setIsLoading] = useState12(true);
|
|
1070
|
+
const [error, setError] = useState12(null);
|
|
443
1071
|
const page = options.page ?? 0;
|
|
444
1072
|
const limit = options.limit ?? 10;
|
|
445
1073
|
const fetchPosts = async () => {
|
|
@@ -459,7 +1087,7 @@ function useBlogPosts(options = {}) {
|
|
|
459
1087
|
setIsLoading(false);
|
|
460
1088
|
}
|
|
461
1089
|
};
|
|
462
|
-
|
|
1090
|
+
useEffect9(() => {
|
|
463
1091
|
fetchPosts();
|
|
464
1092
|
}, [page, limit]);
|
|
465
1093
|
return {
|
|
@@ -471,9 +1099,9 @@ function useBlogPosts(options = {}) {
|
|
|
471
1099
|
}
|
|
472
1100
|
function useBlogPost(slug) {
|
|
473
1101
|
const { client } = useFoxPixelContext();
|
|
474
|
-
const [data, setData] =
|
|
475
|
-
const [isLoading, setIsLoading] =
|
|
476
|
-
const [error, setError] =
|
|
1102
|
+
const [data, setData] = useState12(null);
|
|
1103
|
+
const [isLoading, setIsLoading] = useState12(!!slug);
|
|
1104
|
+
const [error, setError] = useState12(null);
|
|
477
1105
|
const fetchPost = async () => {
|
|
478
1106
|
if (!slug) {
|
|
479
1107
|
setData(null);
|
|
@@ -492,7 +1120,7 @@ function useBlogPost(slug) {
|
|
|
492
1120
|
setIsLoading(false);
|
|
493
1121
|
}
|
|
494
1122
|
};
|
|
495
|
-
|
|
1123
|
+
useEffect9(() => {
|
|
496
1124
|
fetchPost();
|
|
497
1125
|
}, [slug]);
|
|
498
1126
|
return {
|
|
@@ -504,9 +1132,9 @@ function useBlogPost(slug) {
|
|
|
504
1132
|
}
|
|
505
1133
|
function useBlogCategories() {
|
|
506
1134
|
const { client } = useFoxPixelContext();
|
|
507
|
-
const [data, setData] =
|
|
508
|
-
const [isLoading, setIsLoading] =
|
|
509
|
-
const [error, setError] =
|
|
1135
|
+
const [data, setData] = useState12(null);
|
|
1136
|
+
const [isLoading, setIsLoading] = useState12(true);
|
|
1137
|
+
const [error, setError] = useState12(null);
|
|
510
1138
|
const fetchCategories = async () => {
|
|
511
1139
|
try {
|
|
512
1140
|
setIsLoading(true);
|
|
@@ -520,7 +1148,7 @@ function useBlogCategories() {
|
|
|
520
1148
|
setIsLoading(false);
|
|
521
1149
|
}
|
|
522
1150
|
};
|
|
523
|
-
|
|
1151
|
+
useEffect9(() => {
|
|
524
1152
|
fetchCategories();
|
|
525
1153
|
}, []);
|
|
526
1154
|
return {
|
|
@@ -532,9 +1160,9 @@ function useBlogCategories() {
|
|
|
532
1160
|
}
|
|
533
1161
|
function useBlogTags() {
|
|
534
1162
|
const { client } = useFoxPixelContext();
|
|
535
|
-
const [data, setData] =
|
|
536
|
-
const [isLoading, setIsLoading] =
|
|
537
|
-
const [error, setError] =
|
|
1163
|
+
const [data, setData] = useState12(null);
|
|
1164
|
+
const [isLoading, setIsLoading] = useState12(true);
|
|
1165
|
+
const [error, setError] = useState12(null);
|
|
538
1166
|
const fetchTags = async () => {
|
|
539
1167
|
try {
|
|
540
1168
|
setIsLoading(true);
|
|
@@ -548,7 +1176,7 @@ function useBlogTags() {
|
|
|
548
1176
|
setIsLoading(false);
|
|
549
1177
|
}
|
|
550
1178
|
};
|
|
551
|
-
|
|
1179
|
+
useEffect9(() => {
|
|
552
1180
|
fetchTags();
|
|
553
1181
|
}, []);
|
|
554
1182
|
return {
|
|
@@ -560,9 +1188,9 @@ function useBlogTags() {
|
|
|
560
1188
|
}
|
|
561
1189
|
function useBlogComments(slug) {
|
|
562
1190
|
const { client } = useFoxPixelContext();
|
|
563
|
-
const [data, setData] =
|
|
564
|
-
const [isLoading, setIsLoading] =
|
|
565
|
-
const [error, setError] =
|
|
1191
|
+
const [data, setData] = useState12(null);
|
|
1192
|
+
const [isLoading, setIsLoading] = useState12(!!slug);
|
|
1193
|
+
const [error, setError] = useState12(null);
|
|
566
1194
|
const fetchComments = async () => {
|
|
567
1195
|
if (!slug) {
|
|
568
1196
|
setData(null);
|
|
@@ -583,7 +1211,7 @@ function useBlogComments(slug) {
|
|
|
583
1211
|
setIsLoading(false);
|
|
584
1212
|
}
|
|
585
1213
|
};
|
|
586
|
-
|
|
1214
|
+
useEffect9(() => {
|
|
587
1215
|
fetchComments();
|
|
588
1216
|
}, [slug]);
|
|
589
1217
|
return {
|
|
@@ -595,8 +1223,8 @@ function useBlogComments(slug) {
|
|
|
595
1223
|
}
|
|
596
1224
|
function useBlogCommentSubmit(slug) {
|
|
597
1225
|
const { client } = useFoxPixelContext();
|
|
598
|
-
const [isSubmitting, setIsSubmitting] =
|
|
599
|
-
const [error, setError] =
|
|
1226
|
+
const [isSubmitting, setIsSubmitting] = useState12(false);
|
|
1227
|
+
const [error, setError] = useState12(null);
|
|
600
1228
|
const submit = async (payload) => {
|
|
601
1229
|
if (!slug) return null;
|
|
602
1230
|
try {
|
|
@@ -624,9 +1252,9 @@ function useBlogCommentSubmit(slug) {
|
|
|
624
1252
|
}
|
|
625
1253
|
function useBlogFeaturedPosts(limit = 6) {
|
|
626
1254
|
const { client } = useFoxPixelContext();
|
|
627
|
-
const [data, setData] =
|
|
628
|
-
const [isLoading, setIsLoading] =
|
|
629
|
-
const [error, setError] =
|
|
1255
|
+
const [data, setData] = useState12(null);
|
|
1256
|
+
const [isLoading, setIsLoading] = useState12(true);
|
|
1257
|
+
const [error, setError] = useState12(null);
|
|
630
1258
|
const fetchFeatured = async () => {
|
|
631
1259
|
try {
|
|
632
1260
|
setIsLoading(true);
|
|
@@ -644,7 +1272,7 @@ function useBlogFeaturedPosts(limit = 6) {
|
|
|
644
1272
|
setIsLoading(false);
|
|
645
1273
|
}
|
|
646
1274
|
};
|
|
647
|
-
|
|
1275
|
+
useEffect9(() => {
|
|
648
1276
|
fetchFeatured();
|
|
649
1277
|
}, [limit]);
|
|
650
1278
|
return {
|
|
@@ -656,9 +1284,9 @@ function useBlogFeaturedPosts(limit = 6) {
|
|
|
656
1284
|
}
|
|
657
1285
|
function useNewsletterSubscribe() {
|
|
658
1286
|
const { client } = useFoxPixelContext();
|
|
659
|
-
const [isSubmitting, setIsSubmitting] =
|
|
660
|
-
const [error, setError] =
|
|
661
|
-
const [success, setSuccess] =
|
|
1287
|
+
const [isSubmitting, setIsSubmitting] = useState12(false);
|
|
1288
|
+
const [error, setError] = useState12(null);
|
|
1289
|
+
const [success, setSuccess] = useState12(false);
|
|
662
1290
|
const subscribe = async (payload) => {
|
|
663
1291
|
try {
|
|
664
1292
|
setIsSubmitting(true);
|
|
@@ -691,9 +1319,9 @@ function useNewsletterSubscribe() {
|
|
|
691
1319
|
}
|
|
692
1320
|
function useNewsletterUnsubscribe() {
|
|
693
1321
|
const { client } = useFoxPixelContext();
|
|
694
|
-
const [isSubmitting, setIsSubmitting] =
|
|
695
|
-
const [error, setError] =
|
|
696
|
-
const [success, setSuccess] =
|
|
1322
|
+
const [isSubmitting, setIsSubmitting] = useState12(false);
|
|
1323
|
+
const [error, setError] = useState12(null);
|
|
1324
|
+
const [success, setSuccess] = useState12(false);
|
|
697
1325
|
const unsubscribe = async (email) => {
|
|
698
1326
|
try {
|
|
699
1327
|
setIsSubmitting(true);
|
|
@@ -711,8 +1339,26 @@ function useNewsletterUnsubscribe() {
|
|
|
711
1339
|
setIsSubmitting(false);
|
|
712
1340
|
}
|
|
713
1341
|
};
|
|
1342
|
+
const unsubscribeByToken = async (token) => {
|
|
1343
|
+
try {
|
|
1344
|
+
setIsSubmitting(true);
|
|
1345
|
+
setError(null);
|
|
1346
|
+
setSuccess(false);
|
|
1347
|
+
await client.get("/api/v1/blog/newsletter/unsubscribe", {
|
|
1348
|
+
params: { token }
|
|
1349
|
+
});
|
|
1350
|
+
setSuccess(true);
|
|
1351
|
+
return true;
|
|
1352
|
+
} catch (err) {
|
|
1353
|
+
setError(err);
|
|
1354
|
+
return false;
|
|
1355
|
+
} finally {
|
|
1356
|
+
setIsSubmitting(false);
|
|
1357
|
+
}
|
|
1358
|
+
};
|
|
714
1359
|
return {
|
|
715
1360
|
unsubscribe,
|
|
1361
|
+
unsubscribeByToken,
|
|
716
1362
|
isSubmitting,
|
|
717
1363
|
error,
|
|
718
1364
|
success
|
|
@@ -720,15 +1366,15 @@ function useNewsletterUnsubscribe() {
|
|
|
720
1366
|
}
|
|
721
1367
|
|
|
722
1368
|
// src/blog/admin-hooks.ts
|
|
723
|
-
import { useState as
|
|
1369
|
+
import { useState as useState13, useEffect as useEffect10, useCallback as useCallback5 } from "react";
|
|
724
1370
|
function useAdminBlogPosts(options = {}) {
|
|
725
1371
|
const { client } = useFoxPixelContext();
|
|
726
|
-
const [data, setData] =
|
|
727
|
-
const [isLoading, setIsLoading] =
|
|
728
|
-
const [error, setError] =
|
|
1372
|
+
const [data, setData] = useState13(null);
|
|
1373
|
+
const [isLoading, setIsLoading] = useState13(true);
|
|
1374
|
+
const [error, setError] = useState13(null);
|
|
729
1375
|
const page = options.page ?? 0;
|
|
730
1376
|
const size = options.size ?? 20;
|
|
731
|
-
const fetchPosts =
|
|
1377
|
+
const fetchPosts = useCallback5(async () => {
|
|
732
1378
|
try {
|
|
733
1379
|
setIsLoading(true);
|
|
734
1380
|
setError(null);
|
|
@@ -743,17 +1389,17 @@ function useAdminBlogPosts(options = {}) {
|
|
|
743
1389
|
setIsLoading(false);
|
|
744
1390
|
}
|
|
745
1391
|
}, [client, page, size]);
|
|
746
|
-
|
|
1392
|
+
useEffect10(() => {
|
|
747
1393
|
fetchPosts();
|
|
748
1394
|
}, [fetchPosts]);
|
|
749
1395
|
return { data, isLoading, error, refetch: fetchPosts };
|
|
750
1396
|
}
|
|
751
1397
|
function useAdminBlogPost(id) {
|
|
752
1398
|
const { client } = useFoxPixelContext();
|
|
753
|
-
const [data, setData] =
|
|
754
|
-
const [isLoading, setIsLoading] =
|
|
755
|
-
const [error, setError] =
|
|
756
|
-
const fetchPost =
|
|
1399
|
+
const [data, setData] = useState13(null);
|
|
1400
|
+
const [isLoading, setIsLoading] = useState13(!!id);
|
|
1401
|
+
const [error, setError] = useState13(null);
|
|
1402
|
+
const fetchPost = useCallback5(async () => {
|
|
757
1403
|
if (!id) {
|
|
758
1404
|
setData(null);
|
|
759
1405
|
setIsLoading(false);
|
|
@@ -770,15 +1416,15 @@ function useAdminBlogPost(id) {
|
|
|
770
1416
|
setIsLoading(false);
|
|
771
1417
|
}
|
|
772
1418
|
}, [client, id]);
|
|
773
|
-
|
|
1419
|
+
useEffect10(() => {
|
|
774
1420
|
fetchPost();
|
|
775
1421
|
}, [fetchPost]);
|
|
776
1422
|
return { data, isLoading, error, refetch: fetchPost };
|
|
777
1423
|
}
|
|
778
1424
|
function useAdminBlogPostMutations() {
|
|
779
1425
|
const { client } = useFoxPixelContext();
|
|
780
|
-
const [isLoading, setIsLoading] =
|
|
781
|
-
const [error, setError] =
|
|
1426
|
+
const [isLoading, setIsLoading] = useState13(false);
|
|
1427
|
+
const [error, setError] = useState13(null);
|
|
782
1428
|
const create = async (payload) => {
|
|
783
1429
|
try {
|
|
784
1430
|
setIsLoading(true);
|
|
@@ -822,10 +1468,10 @@ function useAdminBlogPostMutations() {
|
|
|
822
1468
|
}
|
|
823
1469
|
function useAdminBlogCategories() {
|
|
824
1470
|
const { client } = useFoxPixelContext();
|
|
825
|
-
const [data, setData] =
|
|
826
|
-
const [isLoading, setIsLoading] =
|
|
827
|
-
const [error, setError] =
|
|
828
|
-
const fetchCategories =
|
|
1471
|
+
const [data, setData] = useState13(null);
|
|
1472
|
+
const [isLoading, setIsLoading] = useState13(true);
|
|
1473
|
+
const [error, setError] = useState13(null);
|
|
1474
|
+
const fetchCategories = useCallback5(async () => {
|
|
829
1475
|
try {
|
|
830
1476
|
setIsLoading(true);
|
|
831
1477
|
setError(null);
|
|
@@ -837,7 +1483,7 @@ function useAdminBlogCategories() {
|
|
|
837
1483
|
setIsLoading(false);
|
|
838
1484
|
}
|
|
839
1485
|
}, [client]);
|
|
840
|
-
|
|
1486
|
+
useEffect10(() => {
|
|
841
1487
|
fetchCategories();
|
|
842
1488
|
}, [fetchCategories]);
|
|
843
1489
|
const create = async (payload) => {
|
|
@@ -874,10 +1520,10 @@ function useAdminBlogCategories() {
|
|
|
874
1520
|
}
|
|
875
1521
|
function useAdminBlogTags() {
|
|
876
1522
|
const { client } = useFoxPixelContext();
|
|
877
|
-
const [data, setData] =
|
|
878
|
-
const [isLoading, setIsLoading] =
|
|
879
|
-
const [error, setError] =
|
|
880
|
-
const fetchTags =
|
|
1523
|
+
const [data, setData] = useState13(null);
|
|
1524
|
+
const [isLoading, setIsLoading] = useState13(true);
|
|
1525
|
+
const [error, setError] = useState13(null);
|
|
1526
|
+
const fetchTags = useCallback5(async () => {
|
|
881
1527
|
try {
|
|
882
1528
|
setIsLoading(true);
|
|
883
1529
|
setError(null);
|
|
@@ -889,7 +1535,7 @@ function useAdminBlogTags() {
|
|
|
889
1535
|
setIsLoading(false);
|
|
890
1536
|
}
|
|
891
1537
|
}, [client]);
|
|
892
|
-
|
|
1538
|
+
useEffect10(() => {
|
|
893
1539
|
fetchTags();
|
|
894
1540
|
}, [fetchTags]);
|
|
895
1541
|
const create = async (payload) => {
|
|
@@ -926,11 +1572,11 @@ function useAdminBlogTags() {
|
|
|
926
1572
|
}
|
|
927
1573
|
function useAdminBlogComments(options = {}) {
|
|
928
1574
|
const { client } = useFoxPixelContext();
|
|
929
|
-
const [data, setData] =
|
|
930
|
-
const [isLoading, setIsLoading] =
|
|
931
|
-
const [error, setError] =
|
|
1575
|
+
const [data, setData] = useState13(null);
|
|
1576
|
+
const [isLoading, setIsLoading] = useState13(true);
|
|
1577
|
+
const [error, setError] = useState13(null);
|
|
932
1578
|
const { status, postId, page = 0, size = 20 } = options;
|
|
933
|
-
const fetchComments =
|
|
1579
|
+
const fetchComments = useCallback5(async () => {
|
|
934
1580
|
try {
|
|
935
1581
|
setIsLoading(true);
|
|
936
1582
|
setError(null);
|
|
@@ -947,7 +1593,7 @@ function useAdminBlogComments(options = {}) {
|
|
|
947
1593
|
setIsLoading(false);
|
|
948
1594
|
}
|
|
949
1595
|
}, [client, status, postId, page, size]);
|
|
950
|
-
|
|
1596
|
+
useEffect10(() => {
|
|
951
1597
|
fetchComments();
|
|
952
1598
|
}, [fetchComments]);
|
|
953
1599
|
const updateStatus = async (id, newStatus) => {
|
|
@@ -974,11 +1620,11 @@ function useAdminBlogComments(options = {}) {
|
|
|
974
1620
|
}
|
|
975
1621
|
function useAdminNewsletterSubscribers(options = {}) {
|
|
976
1622
|
const { client } = useFoxPixelContext();
|
|
977
|
-
const [data, setData] =
|
|
978
|
-
const [isLoading, setIsLoading] =
|
|
979
|
-
const [error, setError] =
|
|
1623
|
+
const [data, setData] = useState13(null);
|
|
1624
|
+
const [isLoading, setIsLoading] = useState13(true);
|
|
1625
|
+
const [error, setError] = useState13(null);
|
|
980
1626
|
const { status, page = 0, size = 20 } = options;
|
|
981
|
-
const fetchSubscribers =
|
|
1627
|
+
const fetchSubscribers = useCallback5(async () => {
|
|
982
1628
|
try {
|
|
983
1629
|
setIsLoading(true);
|
|
984
1630
|
setError(null);
|
|
@@ -994,7 +1640,7 @@ function useAdminNewsletterSubscribers(options = {}) {
|
|
|
994
1640
|
setIsLoading(false);
|
|
995
1641
|
}
|
|
996
1642
|
}, [client, status, page, size]);
|
|
997
|
-
|
|
1643
|
+
useEffect10(() => {
|
|
998
1644
|
fetchSubscribers();
|
|
999
1645
|
}, [fetchSubscribers]);
|
|
1000
1646
|
const remove = async (id) => {
|
|
@@ -1011,10 +1657,10 @@ function useAdminNewsletterSubscribers(options = {}) {
|
|
|
1011
1657
|
}
|
|
1012
1658
|
function useAdminNewsletterStats() {
|
|
1013
1659
|
const { client } = useFoxPixelContext();
|
|
1014
|
-
const [data, setData] =
|
|
1015
|
-
const [isLoading, setIsLoading] =
|
|
1016
|
-
const [error, setError] =
|
|
1017
|
-
const fetchStats =
|
|
1660
|
+
const [data, setData] = useState13(null);
|
|
1661
|
+
const [isLoading, setIsLoading] = useState13(true);
|
|
1662
|
+
const [error, setError] = useState13(null);
|
|
1663
|
+
const fetchStats = useCallback5(async () => {
|
|
1018
1664
|
try {
|
|
1019
1665
|
setIsLoading(true);
|
|
1020
1666
|
setError(null);
|
|
@@ -1026,17 +1672,17 @@ function useAdminNewsletterStats() {
|
|
|
1026
1672
|
setIsLoading(false);
|
|
1027
1673
|
}
|
|
1028
1674
|
}, [client]);
|
|
1029
|
-
|
|
1675
|
+
useEffect10(() => {
|
|
1030
1676
|
fetchStats();
|
|
1031
1677
|
}, [fetchStats]);
|
|
1032
1678
|
return { data, isLoading, error, refetch: fetchStats };
|
|
1033
1679
|
}
|
|
1034
1680
|
function useAdminBlogSettings() {
|
|
1035
1681
|
const { client } = useFoxPixelContext();
|
|
1036
|
-
const [data, setData] =
|
|
1037
|
-
const [isLoading, setIsLoading] =
|
|
1038
|
-
const [error, setError] =
|
|
1039
|
-
const fetchSettings =
|
|
1682
|
+
const [data, setData] = useState13(null);
|
|
1683
|
+
const [isLoading, setIsLoading] = useState13(true);
|
|
1684
|
+
const [error, setError] = useState13(null);
|
|
1685
|
+
const fetchSettings = useCallback5(async () => {
|
|
1040
1686
|
try {
|
|
1041
1687
|
setIsLoading(true);
|
|
1042
1688
|
setError(null);
|
|
@@ -1048,7 +1694,7 @@ function useAdminBlogSettings() {
|
|
|
1048
1694
|
setIsLoading(false);
|
|
1049
1695
|
}
|
|
1050
1696
|
}, [client]);
|
|
1051
|
-
|
|
1697
|
+
useEffect10(() => {
|
|
1052
1698
|
fetchSettings();
|
|
1053
1699
|
}, [fetchSettings]);
|
|
1054
1700
|
const update = async (settings) => {
|
|
@@ -1065,10 +1711,10 @@ function useAdminBlogSettings() {
|
|
|
1065
1711
|
}
|
|
1066
1712
|
function useAdminBlogAnalytics() {
|
|
1067
1713
|
const { client } = useFoxPixelContext();
|
|
1068
|
-
const [data, setData] =
|
|
1069
|
-
const [isLoading, setIsLoading] =
|
|
1070
|
-
const [error, setError] =
|
|
1071
|
-
const fetchAnalytics =
|
|
1714
|
+
const [data, setData] = useState13(null);
|
|
1715
|
+
const [isLoading, setIsLoading] = useState13(true);
|
|
1716
|
+
const [error, setError] = useState13(null);
|
|
1717
|
+
const fetchAnalytics = useCallback5(async () => {
|
|
1072
1718
|
try {
|
|
1073
1719
|
setIsLoading(true);
|
|
1074
1720
|
setError(null);
|
|
@@ -1080,7 +1726,7 @@ function useAdminBlogAnalytics() {
|
|
|
1080
1726
|
setIsLoading(false);
|
|
1081
1727
|
}
|
|
1082
1728
|
}, [client]);
|
|
1083
|
-
|
|
1729
|
+
useEffect10(() => {
|
|
1084
1730
|
fetchAnalytics();
|
|
1085
1731
|
}, [fetchAnalytics]);
|
|
1086
1732
|
return { data, isLoading, error, refetch: fetchAnalytics };
|
|
@@ -1119,11 +1765,16 @@ function getBlogPostSchemaLd(post, options) {
|
|
|
1119
1765
|
}
|
|
1120
1766
|
export {
|
|
1121
1767
|
AuthProvider,
|
|
1768
|
+
Editable,
|
|
1769
|
+
EditableHTML,
|
|
1770
|
+
EditableImage,
|
|
1122
1771
|
FoxPixelHttpClient,
|
|
1123
1772
|
FoxPixelProvider,
|
|
1124
1773
|
GuestOnlyRoute,
|
|
1125
1774
|
ProtectedRoute,
|
|
1775
|
+
SITE_CONTENT_QUERY_KEY,
|
|
1126
1776
|
getBlogPostSchemaLd,
|
|
1777
|
+
prefetchSiteContent,
|
|
1127
1778
|
useAdminBlogAnalytics,
|
|
1128
1779
|
useAdminBlogCategories,
|
|
1129
1780
|
useAdminBlogComments,
|
|
@@ -1143,11 +1794,18 @@ export {
|
|
|
1143
1794
|
useBlogPosts,
|
|
1144
1795
|
useBlogTags,
|
|
1145
1796
|
useContactCapture,
|
|
1797
|
+
useEditMode,
|
|
1798
|
+
useEditModeMessaging,
|
|
1146
1799
|
useFoxPixelContext,
|
|
1147
1800
|
useLeadCapture,
|
|
1148
1801
|
useNewsletterSubscribe,
|
|
1149
1802
|
useNewsletterUnsubscribe,
|
|
1803
|
+
useSendEditRequest,
|
|
1150
1804
|
useServices,
|
|
1805
|
+
useSiteContent,
|
|
1806
|
+
useSiteContentQuery,
|
|
1807
|
+
useSiteContentSection,
|
|
1808
|
+
useSiteContents,
|
|
1151
1809
|
withAuth
|
|
1152
1810
|
};
|
|
1153
1811
|
//# sourceMappingURL=index.mjs.map
|