@aglyn/plugins-marketing 1.0.0-beta.229 → 1.0.0-beta.231
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/README.md +2 -2
- package/package.json +16 -15
- package/src/lib/components/campaign-conversions-card.js +23 -11
- package/src/lib/components/campaign-conversions-card.js.map +1 -1
- package/src/lib/components/campaign-list-zones.d.ts +33 -0
- package/src/lib/components/campaign-list-zones.js +30 -0
- package/src/lib/components/campaign-list-zones.js.map +1 -0
- package/src/lib/components/campaign-report-card.js +20 -3
- package/src/lib/components/campaign-report-card.js.map +1 -1
- package/src/lib/components/campaigns-card.js +42 -13
- package/src/lib/components/campaigns-card.js.map +1 -1
- package/src/lib/components/experiment-zones.d.ts +11 -0
- package/src/lib/components/experiment-zones.js.map +1 -1
- package/src/lib/components/host-experiments-card.component.js +5 -1
- package/src/lib/components/host-experiments-card.component.js.map +1 -1
- package/src/lib/components/host-overlays-card.component.js +139 -24
- package/src/lib/components/host-overlays-card.component.js.map +1 -1
- package/src/lib/components/marketing-insight-zones.d.ts +28 -0
- package/src/lib/components/marketing-insight-zones.js +30 -0
- package/src/lib/components/marketing-insight-zones.js.map +1 -0
- package/src/lib/components/overlay-zones.d.ts +84 -0
- package/src/lib/components/overlay-zones.js +38 -0
- package/src/lib/components/overlay-zones.js.map +1 -0
- package/src/lib/components/site-runtime.js +10 -1
- package/src/lib/components/site-runtime.js.map +1 -1
- package/src/lib/model/campaign-list-query.d.ts +2 -2
- package/src/lib/model/campaign-list-query.js.map +1 -1
- package/src/lib/model/index.d.ts +1 -0
- package/src/lib/model/index.js +1 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/overlay-drafts.d.ts +97 -0
- package/src/lib/model/overlay-drafts.js +192 -0
- package/src/lib/model/overlay-drafts.js.map +1 -0
- package/src/lib/plugin.js +12 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/email-events.js +8 -0
- package/src/lib/server/email-events.js.map +1 -1
- package/src/lib/server/marketing-ai-capabilities.d.ts +24 -0
- package/src/lib/server/marketing-ai-capabilities.js +225 -0
- package/src/lib/server/marketing-ai-capabilities.js.map +1 -0
- package/src/lib/server/marketing-drafts.d.ts +86 -0
- package/src/lib/server/marketing-drafts.js +354 -0
- package/src/lib/server/marketing-drafts.js.map +1 -0
- package/src/lib/server/marketing-figures.d.ts +18 -0
- package/src/lib/server/marketing-figures.js +259 -1
- package/src/lib/server/marketing-figures.js.map +1 -1
- package/src/lib/server/overlay-figures.d.ts +36 -0
- package/src/lib/server/overlay-figures.js +158 -0
- package/src/lib/server/overlay-figures.js.map +1 -0
- package/src/lib/server.js +10 -0
- package/src/lib/server.js.map +1 -1
|
@@ -18,7 +18,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
|
18
18
|
import { _ as _object_without_properties_loose } from "@swc/helpers/_/_object_without_properties_loose";
|
|
19
19
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
20
20
|
import { checkEntitlement, createResourceUid, pluginDocsHelp } from "@aglyn/aglyn";
|
|
21
|
-
import { compareOverlayPrecedence, overlayStatus } from "../model/index.js";
|
|
21
|
+
import { compareOverlayPrecedence, OVERLAY_COPY_LIMITS, OVERLAY_LIST_CEILING, OVERLAY_POPUP_TRIGGERS, overlayCopyFromProposal, overlayDraftFromProposal, overlayStatus } from "../model/index.js";
|
|
22
22
|
import { mdiChevronDown, mdiChevronUp } from "@aglyn/shared-data-mdi";
|
|
23
23
|
import { CardDisplay, MdiIcon, useConfirmationContext } from "@aglyn/shared-ui-jsx";
|
|
24
24
|
import { ScrollTable } from "@aglyn/shared-ui-jsx/components/scroll-table.component";
|
|
@@ -31,6 +31,7 @@ import { useFirestore, useFirestoreCollection, useHostActivityLogger, writeGuard
|
|
|
31
31
|
import { writeSiteWideChange } from "@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change";
|
|
32
32
|
import { overlayDisplayName, overlayEngagementLabel, overlayPagesLabel, overlayWindowLabel } from "./overlay-labels.js";
|
|
33
33
|
import { OVERLAY_COPY_HELPER_TEXT, shownAsTypedHelperText, useOverlayCopyEditor } from "./use-overlay-copy-editor.js";
|
|
34
|
+
import { HostOverlaysZone, OverlayEditorZone } from "./overlay-zones.js";
|
|
34
35
|
/**
|
|
35
36
|
* How many overlays the card reads.
|
|
36
37
|
*
|
|
@@ -38,7 +39,7 @@ import { OVERLAY_COPY_HELPER_TEXT, shownAsTypedHelperText, useOverlayCopyEditor
|
|
|
38
39
|
* one list is deliberately not paginated. Generous on purpose: a site runs a
|
|
39
40
|
* handful of banners and popups, and the number exists to bound a pathological
|
|
40
41
|
* collection rather than to bound a normal one.
|
|
41
|
-
*/ const CEILING =
|
|
42
|
+
*/ const CEILING = OVERLAY_LIST_CEILING;
|
|
42
43
|
const EMPTY_BAR = {
|
|
43
44
|
kind: 'bar',
|
|
44
45
|
enabled: true,
|
|
@@ -77,8 +78,8 @@ function parsePatterns(value) {
|
|
|
77
78
|
* text and a popup's headline and body are edited through
|
|
78
79
|
* `useOverlayCopyEditor`, like the single bar and popup cards (AGL-2885).
|
|
79
80
|
*/ export function HostOverlaysCard(props) {
|
|
80
|
-
var _ref, _editor_name,
|
|
81
|
-
var _editor_bar, _editor_popup, _editor_popup1, _editor_bar1, _editor_popup2, _editor_popup3, _editor_bar2,
|
|
81
|
+
var _ref, _editor_name, _editor_$id, _editor_name1, _ref1, _ref2, _ref3, _ref4, _shownAsTypedHelperText, _ref5, _ref6, _ref7, _shownAsTypedHelperText1, _ref8, _ref9, _ref10, _ref11, _ref12, _ref13, _editor_pathPatterns, _editor_excludePathPatterns;
|
|
82
|
+
var _editor_bar, _editor_popup, _editor_popup1, _editor_bar1, _editor_popup2, _editor_popup3, _editor_bar2, _editor_popup4, _editor_popup5, _editor_popup6, _editor_popup7, _editor_popup8, _editor_popup9, _editor_bar3, _editor_bar4, _editor_bar5, _editor_bar6, _editor_popup10, _editor_popup11, _editor_popup12, _editor_popup13, _editor_popup14, _editor_popup15, _editor_popup16, _editor_popup17, _editor_popup18, _editor_popup19, _editor_bar7, _editor_popup20, _editor_popup21;
|
|
82
83
|
const { hostId } = props;
|
|
83
84
|
const firestore = useFirestore();
|
|
84
85
|
const { data: user } = useUser();
|
|
@@ -259,6 +260,88 @@ function parsePatterns(value) {
|
|
|
259
260
|
});
|
|
260
261
|
}
|
|
261
262
|
};
|
|
263
|
+
/*
|
|
264
|
+
* What a widget in the list's zone asks for (AGL-3603): a new overlay from
|
|
265
|
+
* proposed copy, cut to the overlay's limits and written SWITCHED OFF —
|
|
266
|
+
* through the same site-wide write a typed overlay takes — then opened in
|
|
267
|
+
* the editor, where a person reads it, changes it and turns it on.
|
|
268
|
+
*/ const createOverlayDraft = async (kind, proposal)=>{
|
|
269
|
+
var _draft_name;
|
|
270
|
+
const draft = overlayDraftFromProposal(kind, proposal);
|
|
271
|
+
if (!draft) {
|
|
272
|
+
return {
|
|
273
|
+
ok: false,
|
|
274
|
+
error: kind === 'bar' ? 'There was no bar text to save.' : 'There was no popup body to save.'
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
const id = createResourceUid();
|
|
278
|
+
// The list orders on `name`, which every overlay carries, null or not.
|
|
279
|
+
const stored = _extends({}, draft, {
|
|
280
|
+
name: (_draft_name = draft.name) != null ? _draft_name : null
|
|
281
|
+
});
|
|
282
|
+
try {
|
|
283
|
+
await writeSiteWideChange({
|
|
284
|
+
firestore,
|
|
285
|
+
user,
|
|
286
|
+
hostId,
|
|
287
|
+
write: (batch)=>batch.set(doc(firestore, 'hosts', hostId, 'overlays', id), _extends({}, stored, {
|
|
288
|
+
createdAt: Timestamp.now(),
|
|
289
|
+
updatedAt: Timestamp.now()
|
|
290
|
+
}))
|
|
291
|
+
});
|
|
292
|
+
} catch (error) {
|
|
293
|
+
console.error(error);
|
|
294
|
+
return {
|
|
295
|
+
ok: false,
|
|
296
|
+
error: 'The overlay could not be saved. Try again.'
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
logActivity('Created overlay', _extends({
|
|
300
|
+
type: 'content',
|
|
301
|
+
id
|
|
302
|
+
}, draft.name ? {
|
|
303
|
+
name: draft.name
|
|
304
|
+
} : {}));
|
|
305
|
+
setEditor(_extends({}, draft, {
|
|
306
|
+
$id: id
|
|
307
|
+
}));
|
|
308
|
+
return {
|
|
309
|
+
ok: true,
|
|
310
|
+
id
|
|
311
|
+
};
|
|
312
|
+
};
|
|
313
|
+
/*
|
|
314
|
+
* What a widget in the editor's zone proposes (AGL-3603), put into the
|
|
315
|
+
* editor's own fields unsaved. Copy is stored as the editor stores typed
|
|
316
|
+
* copy, so a proposed variable name is kept the way a typed one is.
|
|
317
|
+
*/ const proposeOverlayCopy = (proposal)=>{
|
|
318
|
+
if (!editor) return;
|
|
319
|
+
const values = overlayCopyFromProposal(editor.kind, proposal);
|
|
320
|
+
if (values.name) patch({
|
|
321
|
+
name: values.name
|
|
322
|
+
});
|
|
323
|
+
if (editor.kind === 'bar') {
|
|
324
|
+
if (values.text) patchBar({
|
|
325
|
+
text: copy.stored(values.text)
|
|
326
|
+
});
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
patchPopup(_extends({}, values.headline ? {
|
|
330
|
+
headline: copy.stored(values.headline)
|
|
331
|
+
} : {}, values.body ? {
|
|
332
|
+
body: copy.stored(values.body)
|
|
333
|
+
} : {}, values.ctaLabel ? {
|
|
334
|
+
ctaLabel: values.ctaLabel
|
|
335
|
+
} : {}, values.trigger ? {
|
|
336
|
+
trigger: values.trigger
|
|
337
|
+
} : {}, values.triggerValue !== undefined ? {
|
|
338
|
+
triggerValue: values.triggerValue
|
|
339
|
+
} : {}));
|
|
340
|
+
};
|
|
341
|
+
const overlayRules = {
|
|
342
|
+
limits: OVERLAY_COPY_LIMITS,
|
|
343
|
+
triggers: OVERLAY_POPUP_TRIGGERS
|
|
344
|
+
};
|
|
262
345
|
const handleDelete = async (overlay)=>{
|
|
263
346
|
var _overlay_name;
|
|
264
347
|
if (!overlay.$id) return;
|
|
@@ -389,17 +472,33 @@ function parsePatterns(value) {
|
|
|
389
472
|
variant: "contained",
|
|
390
473
|
onClick: ()=>setEditor(_extends({}, EMPTY_POPUP)),
|
|
391
474
|
children: 'New popup'
|
|
392
|
-
})
|
|
475
|
+
}),
|
|
476
|
+
/*#__PURE__*/ _jsx(HostOverlaysZone, _extends({
|
|
477
|
+
hostId: hostId,
|
|
478
|
+
createOverlayDraft: createOverlayDraft
|
|
479
|
+
}, overlayRules))
|
|
393
480
|
]
|
|
394
481
|
}),
|
|
395
482
|
truncated ? /*#__PURE__*/ _jsx(Alert, {
|
|
396
483
|
severity: "info",
|
|
397
484
|
children: `Showing ${CEILING} overlays, ordered by name. This site has ` + 'more than that — delete the ones you have finished with, or ' + 'the ones below the ceiling cannot be reordered against them.'
|
|
398
485
|
}) : null,
|
|
399
|
-
overlays.length === 0 ? /*#__PURE__*/
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
486
|
+
overlays.length === 0 ? /*#__PURE__*/ _jsxs(Stack, {
|
|
487
|
+
spacing: 1,
|
|
488
|
+
sx: {
|
|
489
|
+
alignItems: 'flex-start'
|
|
490
|
+
},
|
|
491
|
+
children: [
|
|
492
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
493
|
+
variant: "body2",
|
|
494
|
+
color: "text.secondary",
|
|
495
|
+
children: 'No overlays yet — the single announcement bar and popup ' + 'below keep working as your default surfaces.'
|
|
496
|
+
}),
|
|
497
|
+
/*#__PURE__*/ _jsx(HostOverlaysZone, _extends({
|
|
498
|
+
hostId: hostId,
|
|
499
|
+
createOverlayDraft: createOverlayDraft
|
|
500
|
+
}, overlayRules))
|
|
501
|
+
]
|
|
403
502
|
}) : /*#__PURE__*/ _jsxs(ScrollTable, {
|
|
404
503
|
size: "small",
|
|
405
504
|
children: [
|
|
@@ -539,13 +638,29 @@ function parsePatterns(value) {
|
|
|
539
638
|
}),
|
|
540
639
|
helperText: "Internal label shown in this list"
|
|
541
640
|
}),
|
|
641
|
+
/*#__PURE__*/ _jsx(OverlayEditorZone, _extends({
|
|
642
|
+
hostId: hostId,
|
|
643
|
+
overlayId: (_editor_$id = editor.$id) != null ? _editor_$id : '',
|
|
644
|
+
kind: editor.kind,
|
|
645
|
+
copy: {
|
|
646
|
+
name: (_editor_name1 = editor.name) != null ? _editor_name1 : '',
|
|
647
|
+
text: copy.editable((_editor_bar2 = editor.bar) == null ? void 0 : _editor_bar2.text),
|
|
648
|
+
headline: copy.editable((_editor_popup4 = editor.popup) == null ? void 0 : _editor_popup4.headline),
|
|
649
|
+
body: copy.editable((_editor_popup5 = editor.popup) == null ? void 0 : _editor_popup5.body),
|
|
650
|
+
ctaLabel: (_ref1 = (_editor_popup6 = editor.popup) == null ? void 0 : _editor_popup6.ctaLabel) != null ? _ref1 : '',
|
|
651
|
+
ctaHref: (_ref2 = (_editor_popup7 = editor.popup) == null ? void 0 : _editor_popup7.ctaHref) != null ? _ref2 : '',
|
|
652
|
+
trigger: (_ref3 = (_editor_popup8 = editor.popup) == null ? void 0 : _editor_popup8.trigger) != null ? _ref3 : 'delay',
|
|
653
|
+
triggerValue: (_ref4 = (_editor_popup9 = editor.popup) == null ? void 0 : _editor_popup9.triggerValue) != null ? _ref4 : null
|
|
654
|
+
},
|
|
655
|
+
proposeValues: proposeOverlayCopy
|
|
656
|
+
}, overlayRules)),
|
|
542
657
|
editor.kind === 'bar' ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
543
658
|
children: [
|
|
544
659
|
/*#__PURE__*/ _jsx(TextField, {
|
|
545
660
|
size: "small",
|
|
546
661
|
label: "Text",
|
|
547
662
|
required: true,
|
|
548
|
-
value: copy.editable((
|
|
663
|
+
value: copy.editable((_editor_bar3 = editor.bar) == null ? void 0 : _editor_bar3.text),
|
|
549
664
|
onChange: (event)=>patchBar({
|
|
550
665
|
text: copy.stored(event.target.value)
|
|
551
666
|
}),
|
|
@@ -555,7 +670,7 @@ function parsePatterns(value) {
|
|
|
555
670
|
/*#__PURE__*/ _jsx(TextField, {
|
|
556
671
|
size: "small",
|
|
557
672
|
label: "Link (optional)",
|
|
558
|
-
value: (
|
|
673
|
+
value: (_ref5 = (_editor_bar4 = editor.bar) == null ? void 0 : _editor_bar4.href) != null ? _ref5 : '',
|
|
559
674
|
onChange: (event)=>patchBar({
|
|
560
675
|
href: event.target.value
|
|
561
676
|
})
|
|
@@ -567,7 +682,7 @@ function parsePatterns(value) {
|
|
|
567
682
|
/*#__PURE__*/ _jsx(TextField, {
|
|
568
683
|
size: "small",
|
|
569
684
|
label: "Background color",
|
|
570
|
-
value: (
|
|
685
|
+
value: (_ref6 = (_editor_bar5 = editor.bar) == null ? void 0 : _editor_bar5.backgroundColor) != null ? _ref6 : '',
|
|
571
686
|
onChange: (event)=>patchBar({
|
|
572
687
|
backgroundColor: event.target.value
|
|
573
688
|
})
|
|
@@ -575,7 +690,7 @@ function parsePatterns(value) {
|
|
|
575
690
|
/*#__PURE__*/ _jsx(TextField, {
|
|
576
691
|
size: "small",
|
|
577
692
|
label: "Text color",
|
|
578
|
-
value: (
|
|
693
|
+
value: (_ref7 = (_editor_bar6 = editor.bar) == null ? void 0 : _editor_bar6.textColor) != null ? _ref7 : '',
|
|
579
694
|
onChange: (event)=>patchBar({
|
|
580
695
|
textColor: event.target.value
|
|
581
696
|
})
|
|
@@ -588,7 +703,7 @@ function parsePatterns(value) {
|
|
|
588
703
|
/*#__PURE__*/ _jsx(TextField, {
|
|
589
704
|
size: "small",
|
|
590
705
|
label: "Headline",
|
|
591
|
-
value: copy.editable((
|
|
706
|
+
value: copy.editable((_editor_popup10 = editor.popup) == null ? void 0 : _editor_popup10.headline),
|
|
592
707
|
onChange: (event)=>patchPopup({
|
|
593
708
|
headline: copy.stored(event.target.value)
|
|
594
709
|
}),
|
|
@@ -601,7 +716,7 @@ function parsePatterns(value) {
|
|
|
601
716
|
required: true,
|
|
602
717
|
multiline: true,
|
|
603
718
|
minRows: 2,
|
|
604
|
-
value: copy.editable((
|
|
719
|
+
value: copy.editable((_editor_popup11 = editor.popup) == null ? void 0 : _editor_popup11.body),
|
|
605
720
|
onChange: (event)=>patchPopup({
|
|
606
721
|
body: copy.stored(event.target.value)
|
|
607
722
|
}),
|
|
@@ -615,7 +730,7 @@ function parsePatterns(value) {
|
|
|
615
730
|
/*#__PURE__*/ _jsx(TextField, {
|
|
616
731
|
size: "small",
|
|
617
732
|
label: "CTA label",
|
|
618
|
-
value: (
|
|
733
|
+
value: (_ref8 = (_editor_popup12 = editor.popup) == null ? void 0 : _editor_popup12.ctaLabel) != null ? _ref8 : '',
|
|
619
734
|
onChange: (event)=>patchPopup({
|
|
620
735
|
ctaLabel: event.target.value
|
|
621
736
|
})
|
|
@@ -623,7 +738,7 @@ function parsePatterns(value) {
|
|
|
623
738
|
/*#__PURE__*/ _jsx(TextField, {
|
|
624
739
|
size: "small",
|
|
625
740
|
label: "CTA link",
|
|
626
|
-
value: (
|
|
741
|
+
value: (_ref9 = (_editor_popup13 = editor.popup) == null ? void 0 : _editor_popup13.ctaHref) != null ? _ref9 : '',
|
|
627
742
|
onChange: (event)=>patchPopup({
|
|
628
743
|
ctaHref: event.target.value
|
|
629
744
|
})
|
|
@@ -641,7 +756,7 @@ function parsePatterns(value) {
|
|
|
641
756
|
sx: {
|
|
642
757
|
minWidth: 140
|
|
643
758
|
},
|
|
644
|
-
value: (
|
|
759
|
+
value: (_ref10 = (_editor_popup14 = editor.popup) == null ? void 0 : _editor_popup14.trigger) != null ? _ref10 : 'delay',
|
|
645
760
|
onChange: (event)=>patchPopup({
|
|
646
761
|
trigger: event.target.value
|
|
647
762
|
}),
|
|
@@ -663,8 +778,8 @@ function parsePatterns(value) {
|
|
|
663
778
|
/*#__PURE__*/ _jsx(TextField, {
|
|
664
779
|
size: "small",
|
|
665
780
|
type: "number",
|
|
666
|
-
label: ((
|
|
667
|
-
value: (
|
|
781
|
+
label: ((_ref11 = (_editor_popup15 = editor.popup) == null ? void 0 : _editor_popup15.trigger) != null ? _ref11 : 'delay') === 'scroll' ? 'Scroll %' : 'Seconds',
|
|
782
|
+
value: (_ref12 = (_editor_popup16 = editor.popup) == null ? void 0 : _editor_popup16.triggerValue) != null ? _ref12 : 3,
|
|
668
783
|
onChange: (event)=>patchPopup({
|
|
669
784
|
triggerValue: Number(event.target.value)
|
|
670
785
|
})
|
|
@@ -673,7 +788,7 @@ function parsePatterns(value) {
|
|
|
673
788
|
select: true,
|
|
674
789
|
size: "small",
|
|
675
790
|
label: "Frequency",
|
|
676
|
-
value: ((
|
|
791
|
+
value: ((_editor_popup17 = editor.popup) == null ? void 0 : _editor_popup17.oncePerSession) ? 'session' : 'days',
|
|
677
792
|
onChange: (event)=>patchPopup({
|
|
678
793
|
oncePerSession: event.target.value === 'session'
|
|
679
794
|
}),
|
|
@@ -691,11 +806,11 @@ function parsePatterns(value) {
|
|
|
691
806
|
})
|
|
692
807
|
]
|
|
693
808
|
}),
|
|
694
|
-
((
|
|
809
|
+
((_editor_popup18 = editor.popup) == null ? void 0 : _editor_popup18.oncePerSession) ? null : /*#__PURE__*/ _jsx(TextField, {
|
|
695
810
|
size: "small",
|
|
696
811
|
type: "number",
|
|
697
812
|
label: "Re-show after (days)",
|
|
698
|
-
value: (
|
|
813
|
+
value: (_ref13 = (_editor_popup19 = editor.popup) == null ? void 0 : _editor_popup19.frequencyDays) != null ? _ref13 : 7,
|
|
699
814
|
onChange: (event)=>patchPopup({
|
|
700
815
|
frequencyDays: Number(event.target.value)
|
|
701
816
|
})
|
|
@@ -769,7 +884,7 @@ function parsePatterns(value) {
|
|
|
769
884
|
variant: "contained",
|
|
770
885
|
color: "primary",
|
|
771
886
|
onClick: handleSave,
|
|
772
|
-
disabled: copy.pending(editor == null ? void 0 : (
|
|
887
|
+
disabled: copy.pending(editor == null ? void 0 : (_editor_bar7 = editor.bar) == null ? void 0 : _editor_bar7.text, editor == null ? void 0 : (_editor_popup20 = editor.popup) == null ? void 0 : _editor_popup20.headline, editor == null ? void 0 : (_editor_popup21 = editor.popup) == null ? void 0 : _editor_popup21.body),
|
|
773
888
|
children: 'Save'
|
|
774
889
|
})
|
|
775
890
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/marketing/src/lib/components/host-overlays-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n type AglynOrgBilling,\n checkEntitlement,\n createResourceUid,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport {\n compareOverlayPrecedence,\n overlayStatus,\n type HostOverlay,\n} from '../model'\nimport { mdiChevronDown, mdiChevronUp } from '@aglyn/shared-data-mdi'\nimport {\n CardDisplay,\n MdiIcon,\n useConfirmationContext,\n} from '@aglyn/shared-ui-jsx'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { Timestamp } from '@aglyn/shared-util-timestamp'\nimport {\n Alert,\n Button,\n Chip,\n IconButton,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n Switch,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection, doc, limit, orderBy, query } from 'firebase/firestore'\nimport { useState } from 'react'\nimport {\n useFirestore,\n useFirestoreCollection,\n useHostActivityLogger,\n writeGuardedBySeed,\n useUser,\n} from '@aglyn/tenant-feature-instance'\nimport { writeSiteWideChange } from '@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change'\nimport {\n overlayDisplayName,\n overlayEngagementLabel,\n overlayPagesLabel,\n overlayWindowLabel,\n} from './overlay-labels'\nimport {\n OVERLAY_COPY_HELPER_TEXT,\n shownAsTypedHelperText,\n useOverlayCopyEditor,\n} from './use-overlay-copy-editor'\n\nexport interface HostOverlaysCardProps {\n hostId: string\n /** Resolved entitlement source (AGL-395). */\n org?: Partial<AglynOrgBilling>\n}\n\ntype OverlayDraft = HostOverlay & { $id?: string }\n\n/**\n * How many overlays the card reads.\n *\n * A ceiling rather than a page size — see the query, which explains why this\n * one list is deliberately not paginated. Generous on purpose: a site runs a\n * handful of banners and popups, and the number exists to bound a pathological\n * collection rather than to bound a normal one.\n */\nconst CEILING = 50\n\nconst EMPTY_BAR: OverlayDraft = {\n kind: 'bar',\n enabled: true,\n bar: { dismissible: true },\n}\nconst EMPTY_POPUP: OverlayDraft = {\n kind: 'popup',\n enabled: true,\n popup: { trigger: 'delay', triggerValue: 3, frequencyDays: 7 },\n}\n\nfunction toDatetimeLocal(ms?: number): string {\n if (!ms) return ''\n const date = new Date(ms)\n const pad = (value: number) => String(value).padStart(2, '0')\n return (\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-` +\n `${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`\n )\n}\n\nfunction fromDatetimeLocal(value: string): number | undefined {\n if (!value) return undefined\n const ms = new Date(value).getTime()\n return Number.isFinite(ms) ? ms : undefined\n}\n\nfunction parsePatterns(value: string): string[] {\n return value\n .split(',')\n .map((pattern) => pattern.trim())\n .filter(Boolean)\n}\n\n/**\n * Marketing hub overlays manager (AGL-251): multiple announcement bars\n * and popups at `hosts/{hostId}/overlays`, each with a schedule window\n * and page targeting; the tenant render shows the first active match per\n * kind (overlay docs win over the legacy single bar/popup fields). A bar's\n * text and a popup's headline and body are edited through\n * `useOverlayCopyEditor`, like the single bar and popup cards (AGL-2885).\n */\nexport function HostOverlaysCard(props: HostOverlaysCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { org } = props\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const logActivity = useHostActivityLogger(hostId)\n const entitled = checkEntitlement(org, 'marketingOverlays')\n\n const {\n data: overlayDocs,\n status: overlaysStatus,\n /**\n * The overlay rows the editor is seeded from are unconfirmed by the\n * server (AGL-1358). Editing one spreads the whole stored row into\n * `editor` and writes it back with NO options argument at all — a full\n * document replace — so a cached seed reverts every field nobody\n * touched. Including `stats`, the lifetime impression/click/dismissal\n * counters the org beacon increments: a save here would roll live\n * engagement numbers back to whenever the snapshot was taken.\n */\n fromCache: overlaysFromCache,\n } = useFirestoreCollection<any>(\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'overlays'),\n /*\n * ORDERED AND CEILINGED, deliberately not paged (AGL-2501).\n *\n * ## Why the read is ordered\n *\n * `limit(50)` alone is answered in DOCUMENT-ID order over ids from\n * `createResourceUid()`, so the window was a pseudo-random fifty that\n * the client sort below arranged into a believable precedence list.\n * `name` is the one field every overlay carries: `handleSave` writes\n * `name: (…).trim() || null` on every save, and it is the only writer\n * that CREATES one — the analytics beacon uses `update()` precisely so\n * a stale page cannot mint a stats-only stray, and `overlays` is not\n * in `IMPORTABLE_FIELDS`, so no restore path makes one either. A null\n * name still matches an `orderBy`; an ABSENT field would not.\n *\n * ## Why this list is not paged\n *\n * The row order IS the feature: the first enabled overlay of each kind\n * is the one a visitor sees (AGL-270), and the arrows reorder by\n * swapping `order` with the ADJACENT row. A page boundary separates a\n * row from the neighbor it would swap with, so the eleventh overlay\n * could never be moved into tenth place — the same reason the console's\n * screen tree and starter bundles are ceilinged rather than paged.\n *\n * `orderBy('order')` is not an option either, and that is what makes\n * the precedence sort a client-side one: `EMPTY_BAR` and `EMPTY_POPUP`\n * carry no `order`, and only `handleMove` ever writes one, so ordering\n * the query on it would hide every overlay nobody has reordered rather\n * than mis-sorting it. The client sort holds the WHOLE window, which is\n * what makes sorting it here honest.\n */\n orderBy('name'),\n // One past the ceiling, so \"there are more overlays than these\" is a\n // fact rather than a guess from `length === 50`.\n limit(CEILING + 1),\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const truncated = (overlayDocs?.length ?? 0) > CEILING\n const overlays: OverlayDraft[] = [...(overlayDocs ?? [])]\n .slice(0, CEILING)\n .sort(compareOverlayPrecedence)\n\n const [editor, setEditor] = useState<OverlayDraft | null>(null)\n // The editor's copy is held in its stored form; the fields show it as typed.\n const copy = useOverlayCopyEditor({\n hostId,\n usesTokens:\n entitled &&\n [editor?.bar?.text, editor?.popup?.headline, editor?.popup?.body].some(\n (text) => text?.includes('{{'),\n ),\n })\n const barTextShownAsTyped = copy.shownAsTyped(editor?.bar?.text)\n const headlineShownAsTyped = copy.shownAsTyped(editor?.popup?.headline)\n const bodyShownAsTyped = copy.shownAsTyped(editor?.popup?.body)\n const patch = (partial: Partial<OverlayDraft>) =>\n setEditor((previous) => (previous ? { ...previous, ...partial } : previous))\n const patchBar = (partial: Partial<NonNullable<OverlayDraft['bar']>>) =>\n setEditor((previous) =>\n previous\n ? { ...previous, bar: { ...(previous.bar ?? {}), ...partial } }\n : previous,\n )\n const patchPopup = (partial: Partial<NonNullable<OverlayDraft['popup']>>) =>\n setEditor((previous) =>\n previous\n ? { ...previous, popup: { ...(previous.popup ?? {}), ...partial } }\n : previous,\n )\n\n const handleSave = async () => {\n if (!editor) return\n if (editor.kind === 'bar' && !editor.bar?.text?.trim()) {\n return void enqueueSnackbar('Enter the bar text', {\n variant: 'warning',\n persist: false,\n })\n }\n if (editor.kind === 'popup' && !editor.popup?.body?.trim()) {\n return void enqueueSnackbar('Enter the popup body', {\n variant: 'warning',\n persist: false,\n })\n }\n const id = editor.$id ?? createResourceUid()\n const {\n $id: _ignored,\n createdAt: _createdAt,\n updatedAt: _updatedAt,\n ...payload\n } = editor as OverlayDraft & { createdAt?: unknown; updatedAt?: unknown }\n try {\n // JSON round-trip strips undefined values Firestore rejects. The copy\n // is stored again here, for a name typed before the variables arrived.\n const cleaned = JSON.parse(\n JSON.stringify({\n ...payload,\n ...(payload.bar\n ? { bar: { ...payload.bar, text: copy.stored(payload.bar.text) } }\n : {}),\n ...(payload.popup\n ? {\n popup: {\n ...payload.popup,\n headline: copy.stored(payload.popup.headline),\n body: copy.stored(payload.popup.body),\n },\n }\n : {}),\n name: (editor.name ?? '').trim() || null,\n }),\n )\n /**\n * Refuse an EDIT whose seed the server never confirmed (AGL-1358).\n *\n * This write has no options argument, so it is a full document replace\n * of a payload copied wholesale off the listener — `merge` would not\n * have helped anyway, since every field is present. The activity log\n * is inside the guard too: a logged \"Updated overlay\" whose write never\n * happened is worse than neither, because the history then disagrees\n * with the overlay it claims to explain.\n *\n * Only the edit path. A NEW overlay starts from `EMPTY_BAR`/\n * `EMPTY_POPUP` at a fresh uid and can overwrite nothing, and the first\n * snapshot of any listener is `fromCache: true`, so guarding a create\n * would refuse a save that was never unsafe.\n *\n * The guard WRAPS the write: an early return is a shape you can keep\n * while losing the protection.\n */\n const verdict = await writeGuardedBySeed(\n {\n subject: 'overlay',\n unreadable: Boolean(editor.$id) && overlaysStatus === 'error',\n fromCache: Boolean(editor.$id) && overlaysFromCache,\n },\n async () => {\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.set(doc(firestore, 'hosts', hostId, 'overlays', id), {\n ...cleaned,\n updatedAt: Timestamp.now(),\n ...(editor.$id ? {} : { createdAt: Timestamp.now() }),\n }),\n })\n logActivity(editor.$id ? 'Updated overlay' : 'Created overlay', {\n type: 'content',\n id,\n ...(editor.name ? { name: editor.name } : {}),\n })\n },\n )\n // A refusal keeps the editor open with everything that was typed.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n enqueueSnackbar('Overlay saved', { variant: 'success', persist: false })\n setEditor(null)\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', { variant: 'error' })\n }\n }\n\n const handleDelete = async (overlay: OverlayDraft) => {\n if (!overlay.$id) return\n const confirmed = await confirm({\n title: 'Delete overlay?',\n description: `\"${overlay.name ?? overlay.$id}\" stops showing immediately.`,\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n // Resolves with no value and rejects on cancel — gating on the\n // resolved value alone made this always return (AGL-950).\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.delete(doc(firestore, 'hosts', hostId, 'overlays', overlay.$id)),\n })\n enqueueSnackbar('Overlay deleted', { variant: 'success', persist: false })\n logActivity('Deleted overlay', {\n type: 'content',\n id: overlay.$id,\n ...(overlay.name ? { name: overlay.name } : {}),\n })\n }\n\n // Ordering (AGL-270): the first active overlay per kind wins, so the\n // list order is meaningful — swap `order` with the neighbor.\n const handleMove = async (index: number, direction: -1 | 1) => {\n const neighbor = overlays[index + direction]\n const current = overlays[index]\n if (!neighbor?.$id || !current?.$id) return\n const currentOrder = current.order ?? index\n const neighborOrder = neighbor.order ?? index + direction\n // One batch, so the swap lands whole — and the order decides which\n // overlay a visitor sees, so it carries the site's cache drop.\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) => {\n batch.set(\n doc(firestore, 'hosts', hostId, 'overlays', current.$id as string),\n { order: neighborOrder === currentOrder ? neighborOrder + direction : neighborOrder },\n { merge: true },\n )\n batch.set(\n doc(firestore, 'hosts', hostId, 'overlays', neighbor.$id as string),\n { order: currentOrder },\n { merge: true },\n )\n },\n }).catch(console.error)\n }\n\n const handleToggle = async (overlay: OverlayDraft) => {\n if (!overlay.$id) return\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.set(\n doc(firestore, 'hosts', hostId, 'overlays', overlay.$id),\n { enabled: overlay.enabled === false },\n { merge: true },\n ),\n })\n }\n\n const statusChip = (overlay: OverlayDraft) => {\n const status = overlayStatus(overlay, Date.now())\n if (status === 'off') return <Chip size=\"small\" label=\"Off\" />\n if (status === 'scheduled') {\n return <Chip size=\"small\" color=\"info\" label=\"Scheduled\" />\n }\n return <Chip size=\"small\" color=\"success\" label=\"Live\" />\n }\n\n return (\n <CardDisplay\n header=\"Announcement bars & popups\"\n help={pluginDocsHelp('marketingOverlays', {\n anchor: '#frequency',\n excerpt:\n 'Every bar and popup on this site, with its schedule, page ' +\n 'targeting, and how often a visitor sees it again.',\n })}\n contentGutterX\n contentGutterY\n contentBordered=\"all\"\n >\n {!entitled ? (\n <Alert severity=\"info\">\n {'Announcement bars and popups are included from the Starter ' +\n 'plan — see Billing to upgrade.'}\n </Alert>\n ) : (\n <Stack spacing={2}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Configure as many bars and popups as you need, each with its ' +\n 'own schedule and page targeting. When several match a page, ' +\n 'the first per kind shows.'}\n </Typography>\n <Stack direction=\"row\" spacing={1}>\n <Button\n size=\"small\"\n color=\"primary\"\n variant=\"contained\"\n onClick={() => setEditor({ ...EMPTY_BAR })}\n >\n {'New bar'}\n </Button>\n <Button\n size=\"small\"\n color=\"primary\"\n variant=\"contained\"\n onClick={() => setEditor({ ...EMPTY_POPUP })}\n >\n {'New popup'}\n </Button>\n </Stack>\n {truncated ? (\n <Alert severity=\"info\">\n {`Showing ${CEILING} overlays, ordered by name. This site has ` +\n 'more than that — delete the ones you have finished with, or ' +\n 'the ones below the ceiling cannot be reordered against them.'}\n </Alert>\n ) : null}\n {overlays.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No overlays yet — the single announcement bar and popup ' +\n 'below keep working as your default surfaces.'}\n </Typography>\n ) : (\n <ScrollTable size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>{'Name'}</TableCell>\n <TableCell>{'Kind'}</TableCell>\n <TableCell>{'Status'}</TableCell>\n <TableCell>{'Window'}</TableCell>\n <TableCell>{'Pages'}</TableCell>\n <TableCell>{'Engagement'}</TableCell>\n <TableCell align=\"right\">{'Actions'}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {overlays.map((overlay) => (\n <TableRow key={overlay.$id}>\n <TableCell>{overlayDisplayName(overlay)}</TableCell>\n <TableCell>\n {overlay.kind === 'bar' ? 'Bar' : 'Popup'}\n </TableCell>\n <TableCell>{statusChip(overlay)}</TableCell>\n <TableCell>{overlayWindowLabel(overlay)}</TableCell>\n <TableCell>{overlayPagesLabel(overlay)}</TableCell>\n <TableCell>\n {/* Engagement (AGL-271): lifetime counters the org beacon increments. */}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {overlayEngagementLabel(overlay.stats)}\n </Typography>\n </TableCell>\n <TableCell align=\"right\">\n <IconButton\n size=\"small\"\n aria-label=\"move up\"\n disabled={overlays.indexOf(overlay) === 0}\n onClick={() =>\n void handleMove(overlays.indexOf(overlay), -1)\n }\n >\n <MdiIcon path={mdiChevronUp.path} sx={{ fontSize: '1rem' }} />\n </IconButton>\n <IconButton\n size=\"small\"\n aria-label=\"move down\"\n disabled={\n overlays.indexOf(overlay) === overlays.length - 1\n }\n onClick={() =>\n void handleMove(overlays.indexOf(overlay), 1)\n }\n >\n <MdiIcon\n path={mdiChevronDown.path}\n sx={{ fontSize: '1rem' }}\n />\n </IconButton>\n <Switch\n size=\"small\"\n checked={overlay.enabled !== false}\n onChange={() => handleToggle(overlay)}\n slotProps={{ input: { 'aria-label': 'Enabled' } }}\n />\n <Button\n size=\"small\"\n color=\"primary\"\n onClick={() => setEditor({ ...overlay })}\n >\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={() => handleDelete(overlay)}\n >\n {'Delete'}\n </Button>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n )}\n </Stack>\n )}\n\n <Dialog\n open={Boolean(editor)}\n onClose={() => setEditor(null)}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>\n {editor?.$id\n ? 'Edit overlay'\n : editor?.kind === 'bar'\n ? 'New announcement bar'\n : 'New popup'}\n </DialogTitle>\n <DialogContent>\n {editor ? (\n <Stack spacing={2} sx={{ mt: 1 }}>\n <TextField\n size=\"small\"\n label=\"Name\"\n value={editor.name ?? ''}\n onChange={(event) => patch({ name: event.target.value })}\n helperText=\"Internal label shown in this list\"\n />\n {editor.kind === 'bar' ? (\n <>\n <TextField\n size=\"small\"\n label=\"Text\"\n required\n value={copy.editable(editor.bar?.text)}\n onChange={(event) =>\n patchBar({ text: copy.stored(event.target.value) })\n }\n error={barTextShownAsTyped.length > 0}\n helperText={\n shownAsTypedHelperText(barTextShownAsTyped) ??\n OVERLAY_COPY_HELPER_TEXT\n }\n />\n <TextField\n size=\"small\"\n label=\"Link (optional)\"\n value={editor.bar?.href ?? ''}\n onChange={(event) => patchBar({ href: event.target.value })}\n />\n <Stack direction=\"row\" spacing={1}>\n <TextField\n size=\"small\"\n label=\"Background color\"\n value={editor.bar?.backgroundColor ?? ''}\n onChange={(event) =>\n patchBar({ backgroundColor: event.target.value })\n }\n />\n <TextField\n size=\"small\"\n label=\"Text color\"\n value={editor.bar?.textColor ?? ''}\n onChange={(event) =>\n patchBar({ textColor: event.target.value })\n }\n />\n </Stack>\n </>\n ) : (\n <>\n <TextField\n size=\"small\"\n label=\"Headline\"\n value={copy.editable(editor.popup?.headline)}\n onChange={(event) =>\n patchPopup({ headline: copy.stored(event.target.value) })\n }\n error={headlineShownAsTyped.length > 0}\n helperText={shownAsTypedHelperText(headlineShownAsTyped)}\n />\n <TextField\n size=\"small\"\n label=\"Body\"\n required\n multiline\n minRows={2}\n value={copy.editable(editor.popup?.body)}\n onChange={(event) =>\n patchPopup({ body: copy.stored(event.target.value) })\n }\n error={bodyShownAsTyped.length > 0}\n helperText={\n shownAsTypedHelperText(bodyShownAsTyped) ??\n OVERLAY_COPY_HELPER_TEXT\n }\n />\n <Stack direction=\"row\" spacing={1}>\n <TextField\n size=\"small\"\n label=\"CTA label\"\n value={editor.popup?.ctaLabel ?? ''}\n onChange={(event) =>\n patchPopup({ ctaLabel: event.target.value })\n }\n />\n <TextField\n size=\"small\"\n label=\"CTA link\"\n value={editor.popup?.ctaHref ?? ''}\n onChange={(event) =>\n patchPopup({ ctaHref: event.target.value })\n }\n />\n </Stack>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n select\n size=\"small\"\n label=\"Trigger\"\n sx={{ minWidth: 140 }}\n value={editor.popup?.trigger ?? 'delay'}\n onChange={(event) =>\n patchPopup({\n trigger: event.target\n .value as NonNullable<\n OverlayDraft['popup']\n >['trigger'],\n })\n }\n >\n <MenuItem value=\"delay\">{'After a delay'}</MenuItem>\n <MenuItem value=\"scroll\">{'On scroll'}</MenuItem>\n <MenuItem value=\"exit\">{'On exit intent'}</MenuItem>\n </TextField>\n <TextField\n size=\"small\"\n type=\"number\"\n label={\n (editor.popup?.trigger ?? 'delay') === 'scroll'\n ? 'Scroll %'\n : 'Seconds'\n }\n value={editor.popup?.triggerValue ?? 3}\n onChange={(event) =>\n patchPopup({\n triggerValue: Number(event.target.value),\n })\n }\n />\n {/*\n `Once per session` (AGL-2174). `/product/marketing`\n sells \"per-session frequency caps\" in as many words\n and the only cap that existed was day-based — a\n visitor who dismissed a popup did not see it again\n for a week, which is a different promise. The two are\n alternatives, so the day field goes away when the\n session cap is on rather than sitting there ignored.\n */}\n <TextField\n select\n size=\"small\"\n label=\"Frequency\"\n value={editor.popup?.oncePerSession ? 'session' : 'days'}\n onChange={(event) =>\n patchPopup({\n oncePerSession: event.target.value === 'session',\n })\n }\n sx={{ minWidth: 170 }}\n >\n <MenuItem value=\"session\">\n {'Once per session'}\n </MenuItem>\n <MenuItem value=\"days\">{'Re-show after a while'}</MenuItem>\n </TextField>\n {editor.popup?.oncePerSession ? null : (\n <TextField\n size=\"small\"\n type=\"number\"\n label=\"Re-show after (days)\"\n value={editor.popup?.frequencyDays ?? 7}\n onChange={(event) =>\n patchPopup({\n frequencyDays: Number(event.target.value),\n })\n }\n />\n )}\n </Stack>\n </>\n )}\n <Stack direction=\"row\" spacing={1}>\n <TextField\n size=\"small\"\n type=\"datetime-local\"\n label=\"Show from\"\n slotProps={{ inputLabel: { shrink: true } }}\n value={toDatetimeLocal(editor.startAtMs)}\n onChange={(event) =>\n patch({ startAtMs: fromDatetimeLocal(event.target.value) })\n }\n />\n <TextField\n size=\"small\"\n type=\"datetime-local\"\n label=\"Show until\"\n slotProps={{ inputLabel: { shrink: true } }}\n value={toDatetimeLocal(editor.endAtMs)}\n onChange={(event) =>\n patch({ endAtMs: fromDatetimeLocal(event.target.value) })\n }\n />\n </Stack>\n <TextField\n size=\"small\"\n label=\"Show on pages\"\n value={(editor.pathPatterns ?? []).join(', ')}\n onChange={(event) =>\n patch({ pathPatterns: parsePatterns(event.target.value) })\n }\n helperText={\n 'Comma-separated paths; /blog/* matches a section. ' +\n 'Empty = every page.'\n }\n />\n <TextField\n size=\"small\"\n label=\"Never show on\"\n value={(editor.excludePathPatterns ?? []).join(', ')}\n onChange={(event) =>\n patch({\n excludePathPatterns: parsePatterns(event.target.value),\n })\n }\n />\n </Stack>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button color=\"inherit\" onClick={() => setEditor(null)}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={handleSave}\n disabled={copy.pending(\n editor?.bar?.text,\n editor?.popup?.headline,\n editor?.popup?.body,\n )}\n >\n {'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nHostOverlaysCard.displayName = 'HostOverlaysCard'\n\nexport default HostOverlaysCard\n"],"names":["checkEntitlement","createResourceUid","pluginDocsHelp","compareOverlayPrecedence","overlayStatus","mdiChevronDown","mdiChevronUp","CardDisplay","MdiIcon","useConfirmationContext","ScrollTable","useSnackbar","Timestamp","Alert","Button","Chip","IconButton","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","Switch","TableBody","TableCell","TableHead","TableRow","TextField","Typography","collection","doc","limit","orderBy","query","useState","useFirestore","useFirestoreCollection","useHostActivityLogger","writeGuardedBySeed","useUser","writeSiteWideChange","overlayDisplayName","overlayEngagementLabel","overlayPagesLabel","overlayWindowLabel","OVERLAY_COPY_HELPER_TEXT","shownAsTypedHelperText","useOverlayCopyEditor","CEILING","EMPTY_BAR","kind","enabled","bar","dismissible","EMPTY_POPUP","popup","trigger","triggerValue","frequencyDays","toDatetimeLocal","ms","date","Date","pad","value","String","padStart","getFullYear","getMonth","getDate","getHours","getMinutes","fromDatetimeLocal","undefined","getTime","Number","isFinite","parsePatterns","split","map","pattern","trim","filter","Boolean","HostOverlaysCard","props","editor","hostId","firestore","data","user","org","enqueueSnackbar","confirm","logActivity","entitled","overlayDocs","status","overlaysStatus","fromCache","overlaysFromCache","idField","truncated","length","overlays","slice","sort","setEditor","copy","usesTokens","text","headline","body","some","includes","barTextShownAsTyped","shownAsTyped","headlineShownAsTyped","bodyShownAsTyped","patch","partial","previous","patchBar","patchPopup","handleSave","variant","persist","id","$id","_ignored","createdAt","_createdAt","updatedAt","_updatedAt","payload","cleaned","JSON","parse","stringify","stored","name","verdict","subject","unreadable","write","batch","set","now","type","ok","message","error","console","handleDelete","overlay","confirmed","title","description","confirmationText","confirmationButtonProps","color","then","catch","delete","handleMove","index","direction","current","neighbor","currentOrder","order","neighborOrder","merge","handleToggle","statusChip","size","label","header","help","anchor","excerpt","contentGutterX","contentGutterY","contentBordered","severity","spacing","onClick","align","stats","aria-label","disabled","indexOf","path","sx","fontSize","checked","onChange","slotProps","input","open","onClose","maxWidth","fullWidth","mt","event","target","helperText","required","editable","href","backgroundColor","textColor","multiline","minRows","ctaLabel","ctaHref","select","minWidth","oncePerSession","inputLabel","shrink","startAtMs","endAtMs","pathPatterns","join","excludePathPatterns","pending","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/marketing/src/lib/components/host-overlays-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n type AglynOrgBilling,\n checkEntitlement,\n createResourceUid,\n pluginDocsHelp,\n} from '@aglyn/aglyn'\nimport {\n compareOverlayPrecedence,\n OVERLAY_COPY_LIMITS,\n OVERLAY_LIST_CEILING,\n OVERLAY_POPUP_TRIGGERS,\n overlayCopyFromProposal,\n overlayDraftFromProposal,\n overlayStatus,\n type HostOverlay,\n type OverlayCopyProposal,\n} from '../model'\nimport { mdiChevronDown, mdiChevronUp } from '@aglyn/shared-data-mdi'\nimport {\n CardDisplay,\n MdiIcon,\n useConfirmationContext,\n} from '@aglyn/shared-ui-jsx'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { Timestamp } from '@aglyn/shared-util-timestamp'\nimport {\n Alert,\n Button,\n Chip,\n IconButton,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n MenuItem,\n Stack,\n Switch,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection, doc, limit, orderBy, query } from 'firebase/firestore'\nimport { useState } from 'react'\nimport {\n useFirestore,\n useFirestoreCollection,\n useHostActivityLogger,\n writeGuardedBySeed,\n useUser,\n} from '@aglyn/tenant-feature-instance'\nimport { writeSiteWideChange } from '@aglyn/tenant-feature-instance/hooks/helpers/site-wide-change'\nimport {\n overlayDisplayName,\n overlayEngagementLabel,\n overlayPagesLabel,\n overlayWindowLabel,\n} from './overlay-labels'\nimport {\n OVERLAY_COPY_HELPER_TEXT,\n shownAsTypedHelperText,\n useOverlayCopyEditor,\n} from './use-overlay-copy-editor'\nimport {\n HostOverlaysZone,\n OverlayEditorZone,\n type MarketingOverlayDraftResult,\n} from './overlay-zones'\n\nexport interface HostOverlaysCardProps {\n hostId: string\n /** Resolved entitlement source (AGL-395). */\n org?: Partial<AglynOrgBilling>\n}\n\ntype OverlayDraft = HostOverlay & { $id?: string }\n\n/**\n * How many overlays the card reads.\n *\n * A ceiling rather than a page size — see the query, which explains why this\n * one list is deliberately not paginated. Generous on purpose: a site runs a\n * handful of banners and popups, and the number exists to bound a pathological\n * collection rather than to bound a normal one.\n */\nconst CEILING = OVERLAY_LIST_CEILING\n\nconst EMPTY_BAR: OverlayDraft = {\n kind: 'bar',\n enabled: true,\n bar: { dismissible: true },\n}\nconst EMPTY_POPUP: OverlayDraft = {\n kind: 'popup',\n enabled: true,\n popup: { trigger: 'delay', triggerValue: 3, frequencyDays: 7 },\n}\n\nfunction toDatetimeLocal(ms?: number): string {\n if (!ms) return ''\n const date = new Date(ms)\n const pad = (value: number) => String(value).padStart(2, '0')\n return (\n `${date.getFullYear()}-${pad(date.getMonth() + 1)}-` +\n `${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`\n )\n}\n\nfunction fromDatetimeLocal(value: string): number | undefined {\n if (!value) return undefined\n const ms = new Date(value).getTime()\n return Number.isFinite(ms) ? ms : undefined\n}\n\nfunction parsePatterns(value: string): string[] {\n return value\n .split(',')\n .map((pattern) => pattern.trim())\n .filter(Boolean)\n}\n\n/**\n * Marketing hub overlays manager (AGL-251): multiple announcement bars\n * and popups at `hosts/{hostId}/overlays`, each with a schedule window\n * and page targeting; the tenant render shows the first active match per\n * kind (overlay docs win over the legacy single bar/popup fields). A bar's\n * text and a popup's headline and body are edited through\n * `useOverlayCopyEditor`, like the single bar and popup cards (AGL-2885).\n */\nexport function HostOverlaysCard(props: HostOverlaysCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { org } = props\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const logActivity = useHostActivityLogger(hostId)\n const entitled = checkEntitlement(org, 'marketingOverlays')\n\n const {\n data: overlayDocs,\n status: overlaysStatus,\n /**\n * The overlay rows the editor is seeded from are unconfirmed by the\n * server (AGL-1358). Editing one spreads the whole stored row into\n * `editor` and writes it back with NO options argument at all — a full\n * document replace — so a cached seed reverts every field nobody\n * touched. Including `stats`, the lifetime impression/click/dismissal\n * counters the org beacon increments: a save here would roll live\n * engagement numbers back to whenever the snapshot was taken.\n */\n fromCache: overlaysFromCache,\n } = useFirestoreCollection<any>(\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'overlays'),\n /*\n * ORDERED AND CEILINGED, deliberately not paged (AGL-2501).\n *\n * ## Why the read is ordered\n *\n * `limit(50)` alone is answered in DOCUMENT-ID order over ids from\n * `createResourceUid()`, so the window was a pseudo-random fifty that\n * the client sort below arranged into a believable precedence list.\n * `name` is the one field every overlay carries: `handleSave` writes\n * `name: (…).trim() || null` on every save, and it is the only writer\n * that CREATES one — the analytics beacon uses `update()` precisely so\n * a stale page cannot mint a stats-only stray, and `overlays` is not\n * in `IMPORTABLE_FIELDS`, so no restore path makes one either. A null\n * name still matches an `orderBy`; an ABSENT field would not.\n *\n * ## Why this list is not paged\n *\n * The row order IS the feature: the first enabled overlay of each kind\n * is the one a visitor sees (AGL-270), and the arrows reorder by\n * swapping `order` with the ADJACENT row. A page boundary separates a\n * row from the neighbor it would swap with, so the eleventh overlay\n * could never be moved into tenth place — the same reason the console's\n * screen tree and starter bundles are ceilinged rather than paged.\n *\n * `orderBy('order')` is not an option either, and that is what makes\n * the precedence sort a client-side one: `EMPTY_BAR` and `EMPTY_POPUP`\n * carry no `order`, and only `handleMove` ever writes one, so ordering\n * the query on it would hide every overlay nobody has reordered rather\n * than mis-sorting it. The client sort holds the WHOLE window, which is\n * what makes sorting it here honest.\n */\n orderBy('name'),\n // One past the ceiling, so \"there are more overlays than these\" is a\n // fact rather than a guess from `length === 50`.\n limit(CEILING + 1),\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const truncated = (overlayDocs?.length ?? 0) > CEILING\n const overlays: OverlayDraft[] = [...(overlayDocs ?? [])]\n .slice(0, CEILING)\n .sort(compareOverlayPrecedence)\n\n const [editor, setEditor] = useState<OverlayDraft | null>(null)\n // The editor's copy is held in its stored form; the fields show it as typed.\n const copy = useOverlayCopyEditor({\n hostId,\n usesTokens:\n entitled &&\n [editor?.bar?.text, editor?.popup?.headline, editor?.popup?.body].some(\n (text) => text?.includes('{{'),\n ),\n })\n const barTextShownAsTyped = copy.shownAsTyped(editor?.bar?.text)\n const headlineShownAsTyped = copy.shownAsTyped(editor?.popup?.headline)\n const bodyShownAsTyped = copy.shownAsTyped(editor?.popup?.body)\n const patch = (partial: Partial<OverlayDraft>) =>\n setEditor((previous) => (previous ? { ...previous, ...partial } : previous))\n const patchBar = (partial: Partial<NonNullable<OverlayDraft['bar']>>) =>\n setEditor((previous) =>\n previous\n ? { ...previous, bar: { ...(previous.bar ?? {}), ...partial } }\n : previous,\n )\n const patchPopup = (partial: Partial<NonNullable<OverlayDraft['popup']>>) =>\n setEditor((previous) =>\n previous\n ? { ...previous, popup: { ...(previous.popup ?? {}), ...partial } }\n : previous,\n )\n\n const handleSave = async () => {\n if (!editor) return\n if (editor.kind === 'bar' && !editor.bar?.text?.trim()) {\n return void enqueueSnackbar('Enter the bar text', {\n variant: 'warning',\n persist: false,\n })\n }\n if (editor.kind === 'popup' && !editor.popup?.body?.trim()) {\n return void enqueueSnackbar('Enter the popup body', {\n variant: 'warning',\n persist: false,\n })\n }\n const id = editor.$id ?? createResourceUid()\n const {\n $id: _ignored,\n createdAt: _createdAt,\n updatedAt: _updatedAt,\n ...payload\n } = editor as OverlayDraft & { createdAt?: unknown; updatedAt?: unknown }\n try {\n // JSON round-trip strips undefined values Firestore rejects. The copy\n // is stored again here, for a name typed before the variables arrived.\n const cleaned = JSON.parse(\n JSON.stringify({\n ...payload,\n ...(payload.bar\n ? { bar: { ...payload.bar, text: copy.stored(payload.bar.text) } }\n : {}),\n ...(payload.popup\n ? {\n popup: {\n ...payload.popup,\n headline: copy.stored(payload.popup.headline),\n body: copy.stored(payload.popup.body),\n },\n }\n : {}),\n name: (editor.name ?? '').trim() || null,\n }),\n )\n /**\n * Refuse an EDIT whose seed the server never confirmed (AGL-1358).\n *\n * This write has no options argument, so it is a full document replace\n * of a payload copied wholesale off the listener — `merge` would not\n * have helped anyway, since every field is present. The activity log\n * is inside the guard too: a logged \"Updated overlay\" whose write never\n * happened is worse than neither, because the history then disagrees\n * with the overlay it claims to explain.\n *\n * Only the edit path. A NEW overlay starts from `EMPTY_BAR`/\n * `EMPTY_POPUP` at a fresh uid and can overwrite nothing, and the first\n * snapshot of any listener is `fromCache: true`, so guarding a create\n * would refuse a save that was never unsafe.\n *\n * The guard WRAPS the write: an early return is a shape you can keep\n * while losing the protection.\n */\n const verdict = await writeGuardedBySeed(\n {\n subject: 'overlay',\n unreadable: Boolean(editor.$id) && overlaysStatus === 'error',\n fromCache: Boolean(editor.$id) && overlaysFromCache,\n },\n async () => {\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.set(doc(firestore, 'hosts', hostId, 'overlays', id), {\n ...cleaned,\n updatedAt: Timestamp.now(),\n ...(editor.$id ? {} : { createdAt: Timestamp.now() }),\n }),\n })\n logActivity(editor.$id ? 'Updated overlay' : 'Created overlay', {\n type: 'content',\n id,\n ...(editor.name ? { name: editor.name } : {}),\n })\n },\n )\n // A refusal keeps the editor open with everything that was typed.\n if (!verdict.ok) {\n return void enqueueSnackbar(verdict.message, {\n variant: 'warning',\n persist: false,\n })\n }\n enqueueSnackbar('Overlay saved', { variant: 'success', persist: false })\n setEditor(null)\n } catch (error) {\n console.error(error)\n enqueueSnackbar('An error has occurred', { variant: 'error' })\n }\n }\n\n /*\n * What a widget in the list's zone asks for (AGL-3603): a new overlay from\n * proposed copy, cut to the overlay's limits and written SWITCHED OFF —\n * through the same site-wide write a typed overlay takes — then opened in\n * the editor, where a person reads it, changes it and turns it on.\n */\n const createOverlayDraft = async (\n kind: HostOverlay['kind'],\n proposal: OverlayCopyProposal,\n ): Promise<MarketingOverlayDraftResult> => {\n const draft = overlayDraftFromProposal(kind, proposal)\n if (!draft) {\n return {\n ok: false,\n error:\n kind === 'bar'\n ? 'There was no bar text to save.'\n : 'There was no popup body to save.',\n }\n }\n const id = createResourceUid()\n // The list orders on `name`, which every overlay carries, null or not.\n const stored = { ...draft, name: draft.name ?? null }\n try {\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.set(doc(firestore, 'hosts', hostId, 'overlays', id), {\n ...stored,\n createdAt: Timestamp.now(),\n updatedAt: Timestamp.now(),\n }),\n })\n } catch (error) {\n console.error(error)\n return { ok: false, error: 'The overlay could not be saved. Try again.' }\n }\n logActivity('Created overlay', {\n type: 'content',\n id,\n ...(draft.name ? { name: draft.name } : {}),\n })\n setEditor({ ...draft, $id: id })\n return { ok: true, id }\n }\n\n /*\n * What a widget in the editor's zone proposes (AGL-3603), put into the\n * editor's own fields unsaved. Copy is stored as the editor stores typed\n * copy, so a proposed variable name is kept the way a typed one is.\n */\n const proposeOverlayCopy = (proposal: OverlayCopyProposal) => {\n if (!editor) return\n const values = overlayCopyFromProposal(editor.kind, proposal)\n if (values.name) patch({ name: values.name })\n if (editor.kind === 'bar') {\n if (values.text) patchBar({ text: copy.stored(values.text) })\n return\n }\n patchPopup({\n ...(values.headline ? { headline: copy.stored(values.headline) } : {}),\n ...(values.body ? { body: copy.stored(values.body) } : {}),\n ...(values.ctaLabel ? { ctaLabel: values.ctaLabel } : {}),\n ...(values.trigger ? { trigger: values.trigger } : {}),\n ...(values.triggerValue !== undefined ? { triggerValue: values.triggerValue } : {}),\n })\n }\n\n const overlayRules = { limits: OVERLAY_COPY_LIMITS, triggers: OVERLAY_POPUP_TRIGGERS }\n\n const handleDelete = async (overlay: OverlayDraft) => {\n if (!overlay.$id) return\n const confirmed = await confirm({\n title: 'Delete overlay?',\n description: `\"${overlay.name ?? overlay.$id}\" stops showing immediately.`,\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n // Resolves with no value and rejects on cancel — gating on the\n // resolved value alone made this always return (AGL-950).\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.delete(doc(firestore, 'hosts', hostId, 'overlays', overlay.$id)),\n })\n enqueueSnackbar('Overlay deleted', { variant: 'success', persist: false })\n logActivity('Deleted overlay', {\n type: 'content',\n id: overlay.$id,\n ...(overlay.name ? { name: overlay.name } : {}),\n })\n }\n\n // Ordering (AGL-270): the first active overlay per kind wins, so the\n // list order is meaningful — swap `order` with the neighbor.\n const handleMove = async (index: number, direction: -1 | 1) => {\n const neighbor = overlays[index + direction]\n const current = overlays[index]\n if (!neighbor?.$id || !current?.$id) return\n const currentOrder = current.order ?? index\n const neighborOrder = neighbor.order ?? index + direction\n // One batch, so the swap lands whole — and the order decides which\n // overlay a visitor sees, so it carries the site's cache drop.\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) => {\n batch.set(\n doc(firestore, 'hosts', hostId, 'overlays', current.$id as string),\n { order: neighborOrder === currentOrder ? neighborOrder + direction : neighborOrder },\n { merge: true },\n )\n batch.set(\n doc(firestore, 'hosts', hostId, 'overlays', neighbor.$id as string),\n { order: currentOrder },\n { merge: true },\n )\n },\n }).catch(console.error)\n }\n\n const handleToggle = async (overlay: OverlayDraft) => {\n if (!overlay.$id) return\n await writeSiteWideChange({\n firestore,\n user,\n hostId,\n write: (batch) =>\n batch.set(\n doc(firestore, 'hosts', hostId, 'overlays', overlay.$id),\n { enabled: overlay.enabled === false },\n { merge: true },\n ),\n })\n }\n\n const statusChip = (overlay: OverlayDraft) => {\n const status = overlayStatus(overlay, Date.now())\n if (status === 'off') return <Chip size=\"small\" label=\"Off\" />\n if (status === 'scheduled') {\n return <Chip size=\"small\" color=\"info\" label=\"Scheduled\" />\n }\n return <Chip size=\"small\" color=\"success\" label=\"Live\" />\n }\n\n return (\n <CardDisplay\n header=\"Announcement bars & popups\"\n help={pluginDocsHelp('marketingOverlays', {\n anchor: '#frequency',\n excerpt:\n 'Every bar and popup on this site, with its schedule, page ' +\n 'targeting, and how often a visitor sees it again.',\n })}\n contentGutterX\n contentGutterY\n contentBordered=\"all\"\n >\n {!entitled ? (\n <Alert severity=\"info\">\n {'Announcement bars and popups are included from the Starter ' +\n 'plan — see Billing to upgrade.'}\n </Alert>\n ) : (\n <Stack spacing={2}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Configure as many bars and popups as you need, each with its ' +\n 'own schedule and page targeting. When several match a page, ' +\n 'the first per kind shows.'}\n </Typography>\n <Stack direction=\"row\" spacing={1}>\n <Button\n size=\"small\"\n color=\"primary\"\n variant=\"contained\"\n onClick={() => setEditor({ ...EMPTY_BAR })}\n >\n {'New bar'}\n </Button>\n <Button\n size=\"small\"\n color=\"primary\"\n variant=\"contained\"\n onClick={() => setEditor({ ...EMPTY_POPUP })}\n >\n {'New popup'}\n </Button>\n {/*\n Other ways to start an overlay, from plugins (AGL-3603): the\n `hostOverlays` zone this plugin declares, drawn through the\n shell's own gated slot.\n */}\n <HostOverlaysZone\n hostId={hostId}\n createOverlayDraft={createOverlayDraft}\n {...overlayRules}\n />\n </Stack>\n {truncated ? (\n <Alert severity=\"info\">\n {`Showing ${CEILING} overlays, ordered by name. This site has ` +\n 'more than that — delete the ones you have finished with, or ' +\n 'the ones below the ceiling cannot be reordered against them.'}\n </Alert>\n ) : null}\n {overlays.length === 0 ? (\n <Stack spacing={1} sx={{ alignItems: 'flex-start' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No overlays yet — the single announcement bar and popup ' +\n 'below keep working as your default surfaces.'}\n </Typography>\n {/* Other ways to start an overlay, the row's zone again. */}\n <HostOverlaysZone\n hostId={hostId}\n createOverlayDraft={createOverlayDraft}\n {...overlayRules}\n />\n </Stack>\n ) : (\n <ScrollTable size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>{'Name'}</TableCell>\n <TableCell>{'Kind'}</TableCell>\n <TableCell>{'Status'}</TableCell>\n <TableCell>{'Window'}</TableCell>\n <TableCell>{'Pages'}</TableCell>\n <TableCell>{'Engagement'}</TableCell>\n <TableCell align=\"right\">{'Actions'}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {overlays.map((overlay) => (\n <TableRow key={overlay.$id}>\n <TableCell>{overlayDisplayName(overlay)}</TableCell>\n <TableCell>\n {overlay.kind === 'bar' ? 'Bar' : 'Popup'}\n </TableCell>\n <TableCell>{statusChip(overlay)}</TableCell>\n <TableCell>{overlayWindowLabel(overlay)}</TableCell>\n <TableCell>{overlayPagesLabel(overlay)}</TableCell>\n <TableCell>\n {/* Engagement (AGL-271): lifetime counters the org beacon increments. */}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {overlayEngagementLabel(overlay.stats)}\n </Typography>\n </TableCell>\n <TableCell align=\"right\">\n <IconButton\n size=\"small\"\n aria-label=\"move up\"\n disabled={overlays.indexOf(overlay) === 0}\n onClick={() =>\n void handleMove(overlays.indexOf(overlay), -1)\n }\n >\n <MdiIcon path={mdiChevronUp.path} sx={{ fontSize: '1rem' }} />\n </IconButton>\n <IconButton\n size=\"small\"\n aria-label=\"move down\"\n disabled={\n overlays.indexOf(overlay) === overlays.length - 1\n }\n onClick={() =>\n void handleMove(overlays.indexOf(overlay), 1)\n }\n >\n <MdiIcon\n path={mdiChevronDown.path}\n sx={{ fontSize: '1rem' }}\n />\n </IconButton>\n <Switch\n size=\"small\"\n checked={overlay.enabled !== false}\n onChange={() => handleToggle(overlay)}\n slotProps={{ input: { 'aria-label': 'Enabled' } }}\n />\n <Button\n size=\"small\"\n color=\"primary\"\n onClick={() => setEditor({ ...overlay })}\n >\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n color=\"error\"\n onClick={() => handleDelete(overlay)}\n >\n {'Delete'}\n </Button>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n )}\n </Stack>\n )}\n\n <Dialog\n open={Boolean(editor)}\n onClose={() => setEditor(null)}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>\n {editor?.$id\n ? 'Edit overlay'\n : editor?.kind === 'bar'\n ? 'New announcement bar'\n : 'New popup'}\n </DialogTitle>\n <DialogContent>\n {editor ? (\n <Stack spacing={2} sx={{ mt: 1 }}>\n <TextField\n size=\"small\"\n label=\"Name\"\n value={editor.name ?? ''}\n onChange={(event) => patch({ name: event.target.value })}\n helperText=\"Internal label shown in this list\"\n />\n {/*\n Copy proposed by a plugin (AGL-3603): the `overlayEditor`\n zone this plugin declares. A widget fills these fields\n unsaved; Save below is the only write.\n */}\n <OverlayEditorZone\n hostId={hostId}\n overlayId={editor.$id ?? ''}\n kind={editor.kind}\n copy={{\n name: editor.name ?? '',\n text: copy.editable(editor.bar?.text),\n headline: copy.editable(editor.popup?.headline),\n body: copy.editable(editor.popup?.body),\n ctaLabel: editor.popup?.ctaLabel ?? '',\n ctaHref: editor.popup?.ctaHref ?? '',\n trigger: editor.popup?.trigger ?? 'delay',\n triggerValue: editor.popup?.triggerValue ?? null,\n }}\n proposeValues={proposeOverlayCopy}\n {...overlayRules}\n />\n {editor.kind === 'bar' ? (\n <>\n <TextField\n size=\"small\"\n label=\"Text\"\n required\n value={copy.editable(editor.bar?.text)}\n onChange={(event) =>\n patchBar({ text: copy.stored(event.target.value) })\n }\n error={barTextShownAsTyped.length > 0}\n helperText={\n shownAsTypedHelperText(barTextShownAsTyped) ??\n OVERLAY_COPY_HELPER_TEXT\n }\n />\n <TextField\n size=\"small\"\n label=\"Link (optional)\"\n value={editor.bar?.href ?? ''}\n onChange={(event) => patchBar({ href: event.target.value })}\n />\n <Stack direction=\"row\" spacing={1}>\n <TextField\n size=\"small\"\n label=\"Background color\"\n value={editor.bar?.backgroundColor ?? ''}\n onChange={(event) =>\n patchBar({ backgroundColor: event.target.value })\n }\n />\n <TextField\n size=\"small\"\n label=\"Text color\"\n value={editor.bar?.textColor ?? ''}\n onChange={(event) =>\n patchBar({ textColor: event.target.value })\n }\n />\n </Stack>\n </>\n ) : (\n <>\n <TextField\n size=\"small\"\n label=\"Headline\"\n value={copy.editable(editor.popup?.headline)}\n onChange={(event) =>\n patchPopup({ headline: copy.stored(event.target.value) })\n }\n error={headlineShownAsTyped.length > 0}\n helperText={shownAsTypedHelperText(headlineShownAsTyped)}\n />\n <TextField\n size=\"small\"\n label=\"Body\"\n required\n multiline\n minRows={2}\n value={copy.editable(editor.popup?.body)}\n onChange={(event) =>\n patchPopup({ body: copy.stored(event.target.value) })\n }\n error={bodyShownAsTyped.length > 0}\n helperText={\n shownAsTypedHelperText(bodyShownAsTyped) ??\n OVERLAY_COPY_HELPER_TEXT\n }\n />\n <Stack direction=\"row\" spacing={1}>\n <TextField\n size=\"small\"\n label=\"CTA label\"\n value={editor.popup?.ctaLabel ?? ''}\n onChange={(event) =>\n patchPopup({ ctaLabel: event.target.value })\n }\n />\n <TextField\n size=\"small\"\n label=\"CTA link\"\n value={editor.popup?.ctaHref ?? ''}\n onChange={(event) =>\n patchPopup({ ctaHref: event.target.value })\n }\n />\n </Stack>\n <Stack direction=\"row\" spacing={1}>\n <TextField\n select\n size=\"small\"\n label=\"Trigger\"\n sx={{ minWidth: 140 }}\n value={editor.popup?.trigger ?? 'delay'}\n onChange={(event) =>\n patchPopup({\n trigger: event.target\n .value as NonNullable<\n OverlayDraft['popup']\n >['trigger'],\n })\n }\n >\n <MenuItem value=\"delay\">{'After a delay'}</MenuItem>\n <MenuItem value=\"scroll\">{'On scroll'}</MenuItem>\n <MenuItem value=\"exit\">{'On exit intent'}</MenuItem>\n </TextField>\n <TextField\n size=\"small\"\n type=\"number\"\n label={\n (editor.popup?.trigger ?? 'delay') === 'scroll'\n ? 'Scroll %'\n : 'Seconds'\n }\n value={editor.popup?.triggerValue ?? 3}\n onChange={(event) =>\n patchPopup({\n triggerValue: Number(event.target.value),\n })\n }\n />\n {/*\n `Once per session` (AGL-2174). `/product/marketing`\n sells \"per-session frequency caps\" in as many words\n and the only cap that existed was day-based — a\n visitor who dismissed a popup did not see it again\n for a week, which is a different promise. The two are\n alternatives, so the day field goes away when the\n session cap is on rather than sitting there ignored.\n */}\n <TextField\n select\n size=\"small\"\n label=\"Frequency\"\n value={editor.popup?.oncePerSession ? 'session' : 'days'}\n onChange={(event) =>\n patchPopup({\n oncePerSession: event.target.value === 'session',\n })\n }\n sx={{ minWidth: 170 }}\n >\n <MenuItem value=\"session\">\n {'Once per session'}\n </MenuItem>\n <MenuItem value=\"days\">{'Re-show after a while'}</MenuItem>\n </TextField>\n {editor.popup?.oncePerSession ? null : (\n <TextField\n size=\"small\"\n type=\"number\"\n label=\"Re-show after (days)\"\n value={editor.popup?.frequencyDays ?? 7}\n onChange={(event) =>\n patchPopup({\n frequencyDays: Number(event.target.value),\n })\n }\n />\n )}\n </Stack>\n </>\n )}\n <Stack direction=\"row\" spacing={1}>\n <TextField\n size=\"small\"\n type=\"datetime-local\"\n label=\"Show from\"\n slotProps={{ inputLabel: { shrink: true } }}\n value={toDatetimeLocal(editor.startAtMs)}\n onChange={(event) =>\n patch({ startAtMs: fromDatetimeLocal(event.target.value) })\n }\n />\n <TextField\n size=\"small\"\n type=\"datetime-local\"\n label=\"Show until\"\n slotProps={{ inputLabel: { shrink: true } }}\n value={toDatetimeLocal(editor.endAtMs)}\n onChange={(event) =>\n patch({ endAtMs: fromDatetimeLocal(event.target.value) })\n }\n />\n </Stack>\n <TextField\n size=\"small\"\n label=\"Show on pages\"\n value={(editor.pathPatterns ?? []).join(', ')}\n onChange={(event) =>\n patch({ pathPatterns: parsePatterns(event.target.value) })\n }\n helperText={\n 'Comma-separated paths; /blog/* matches a section. ' +\n 'Empty = every page.'\n }\n />\n <TextField\n size=\"small\"\n label=\"Never show on\"\n value={(editor.excludePathPatterns ?? []).join(', ')}\n onChange={(event) =>\n patch({\n excludePathPatterns: parsePatterns(event.target.value),\n })\n }\n />\n </Stack>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button color=\"inherit\" onClick={() => setEditor(null)}>\n {'Cancel'}\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={handleSave}\n disabled={copy.pending(\n editor?.bar?.text,\n editor?.popup?.headline,\n editor?.popup?.body,\n )}\n >\n {'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n </CardDisplay>\n )\n}\nHostOverlaysCard.displayName = 'HostOverlaysCard'\n\nexport default HostOverlaysCard\n"],"names":["checkEntitlement","createResourceUid","pluginDocsHelp","compareOverlayPrecedence","OVERLAY_COPY_LIMITS","OVERLAY_LIST_CEILING","OVERLAY_POPUP_TRIGGERS","overlayCopyFromProposal","overlayDraftFromProposal","overlayStatus","mdiChevronDown","mdiChevronUp","CardDisplay","MdiIcon","useConfirmationContext","ScrollTable","useSnackbar","Timestamp","Alert","Button","Chip","IconButton","Dialog","DialogActions","DialogContent","DialogTitle","MenuItem","Stack","Switch","TableBody","TableCell","TableHead","TableRow","TextField","Typography","collection","doc","limit","orderBy","query","useState","useFirestore","useFirestoreCollection","useHostActivityLogger","writeGuardedBySeed","useUser","writeSiteWideChange","overlayDisplayName","overlayEngagementLabel","overlayPagesLabel","overlayWindowLabel","OVERLAY_COPY_HELPER_TEXT","shownAsTypedHelperText","useOverlayCopyEditor","HostOverlaysZone","OverlayEditorZone","CEILING","EMPTY_BAR","kind","enabled","bar","dismissible","EMPTY_POPUP","popup","trigger","triggerValue","frequencyDays","toDatetimeLocal","ms","date","Date","pad","value","String","padStart","getFullYear","getMonth","getDate","getHours","getMinutes","fromDatetimeLocal","undefined","getTime","Number","isFinite","parsePatterns","split","map","pattern","trim","filter","Boolean","HostOverlaysCard","props","editor","hostId","firestore","data","user","org","enqueueSnackbar","confirm","logActivity","entitled","overlayDocs","status","overlaysStatus","fromCache","overlaysFromCache","idField","truncated","length","overlays","slice","sort","setEditor","copy","usesTokens","text","headline","body","some","includes","barTextShownAsTyped","shownAsTyped","headlineShownAsTyped","bodyShownAsTyped","patch","partial","previous","patchBar","patchPopup","handleSave","variant","persist","id","$id","_ignored","createdAt","_createdAt","updatedAt","_updatedAt","payload","cleaned","JSON","parse","stringify","stored","name","verdict","subject","unreadable","write","batch","set","now","type","ok","message","error","console","createOverlayDraft","proposal","draft","proposeOverlayCopy","values","ctaLabel","overlayRules","limits","triggers","handleDelete","overlay","confirmed","title","description","confirmationText","confirmationButtonProps","color","then","catch","delete","handleMove","index","direction","current","neighbor","currentOrder","order","neighborOrder","merge","handleToggle","statusChip","size","label","header","help","anchor","excerpt","contentGutterX","contentGutterY","contentBordered","severity","spacing","onClick","sx","alignItems","align","stats","aria-label","disabled","indexOf","path","fontSize","checked","onChange","slotProps","input","open","onClose","maxWidth","fullWidth","mt","event","target","helperText","overlayId","editable","ctaHref","proposeValues","required","href","backgroundColor","textColor","multiline","minRows","select","minWidth","oncePerSession","inputLabel","shrink","startAtMs","endAtMs","pathPatterns","join","excludePathPatterns","pending","displayName"],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The zone a marketing report hosts in its header (AGL-3603): the
|
|
3
|
+
* Conversions section and one campaign's report.
|
|
4
|
+
*
|
|
5
|
+
* A widget here explains the figures the page shows, in words. It is handed
|
|
6
|
+
* the site the figures are one site's — the site picked on the
|
|
7
|
+
* organization's Conversions section, the site a campaign email was sent as —
|
|
8
|
+
* and what the page is about, and nothing else: the figures it reads are the
|
|
9
|
+
* ones this plugin publishes to other plugins as figure readers
|
|
10
|
+
* (`server/marketing-figures.ts`), never this page's documents. There is
|
|
11
|
+
* nothing to apply and nothing a widget may write.
|
|
12
|
+
*/
|
|
13
|
+
/** What the report a widget sits on is about. */
|
|
14
|
+
export type MarketingInsightSubject = 'conversions' | 'campaign';
|
|
15
|
+
/** What {@link MARKETING_INSIGHTS_ZONE} hands each widget. */
|
|
16
|
+
export interface MarketingInsightsZoneProps {
|
|
17
|
+
/** The site the figures are one site's; `null` when the page has none to name yet. */
|
|
18
|
+
hostId: string | null;
|
|
19
|
+
subject: MarketingInsightSubject;
|
|
20
|
+
/** One campaign's report: the subject line it is known by. `null` elsewhere. */
|
|
21
|
+
campaign: string | null;
|
|
22
|
+
}
|
|
23
|
+
export declare const MARKETING_INSIGHTS_ZONE: import("@aglyn/aglyn/plugin-manager/plugin-zones").PluginZone<MarketingInsightsZoneProps>;
|
|
24
|
+
/** The report's zone, drawn through the shell's renderer, or nothing outside the shell. */
|
|
25
|
+
export declare function MarketingInsightsZone(props: MarketingInsightsZoneProps): import("react").JSX.Element;
|
|
26
|
+
export declare namespace MarketingInsightsZone {
|
|
27
|
+
var displayName: string;
|
|
28
|
+
}
|