@aglyn/plugins-email 1.0.0-beta.219 → 1.0.0-beta.220
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/package.json +18 -18
- package/src/lib/components/campaign-topic-options-widget.js +2 -2
- package/src/lib/components/campaign-topic-options-widget.js.map +1 -1
- package/src/lib/components/campaign-topic-select.js +3 -3
- package/src/lib/components/campaign-topic-select.js.map +1 -1
- package/src/lib/components/dynamic-list-rule-fields.d.ts +20 -4
- package/src/lib/components/dynamic-list-rule-fields.js +462 -411
- package/src/lib/components/dynamic-list-rule-fields.js.map +1 -1
- package/src/lib/components/email-topic-detail.d.ts +1 -1
- package/src/lib/components/email-topic-detail.js +5 -5
- package/src/lib/components/email-topic-detail.js.map +1 -1
- package/src/lib/components/email-topics-card.d.ts +1 -1
- package/src/lib/components/email-topics-card.js +6 -5
- package/src/lib/components/email-topics-card.js.map +1 -1
- package/src/lib/components/use-org-email-topics.d.ts +4 -4
- package/src/lib/components/use-org-email-topics.js +6 -5
- package/src/lib/components/use-org-email-topics.js.map +1 -1
- package/src/lib/list-import.js +2 -2
- package/src/lib/list-import.js.map +1 -1
- package/src/lib/model/email-topic-catalog.d.ts +36 -0
- package/src/lib/model/email-topic-catalog.js +36 -0
- package/src/lib/model/email-topic-catalog.js.map +1 -0
- package/src/lib/model/index.d.ts +0 -7
- package/src/lib/model/index.js +0 -6
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/server-console.js +6 -2
- package/src/lib/server-console.js.map +1 -1
- package/src/lib/server-list-import.js +1 -1
- package/src/lib/server-list-import.js.map +1 -1
- package/src/lib/server-topic-index.d.ts +52 -0
- package/src/lib/server-topic-index.js +92 -0
- package/src/lib/server-topic-index.js.map +1 -0
- package/src/lib/server.js +11 -11
- package/src/lib/server.js.map +1 -1
- package/src/lib/unsubscribe-link.d.ts +1 -1
- package/src/lib/unsubscribe-link.js +1 -1
- package/src/lib/unsubscribe-link.js.map +1 -1
|
@@ -59,8 +59,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
59
59
|
*/ import { CONTACT_LIFECYCLE_STAGES, CONTACT_LIFECYCLE_STAGE_LABELS, CONTACT_SOURCE_LABELS, DYNAMIC_LIST_CUSTOM_OPS, normalizeDynamicListRule } from "@aglyn/aglyn";
|
|
60
60
|
import { Autocomplete, Box, Button, Divider, MenuItem, Stack, TextField, Typography } from "@mui/material";
|
|
61
61
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
62
|
-
import {
|
|
63
|
-
import
|
|
62
|
+
import { useSiteContainerOptions, useOrgMemberOptions } from "@aglyn/tenant-feature-instance";
|
|
63
|
+
import ContainerPicker from "@aglyn/tenant-feature-instance/components/container-picker";
|
|
64
|
+
import { useContentStable } from "@aglyn/shared-ui-jsx/hooks/use-content-stable";
|
|
64
65
|
import { useOrgCompanyOptions } from "../hooks/use-org-company-options.js";
|
|
65
66
|
import { useOrgContactFields } from "../hooks/use-org-contact-fields.js";
|
|
66
67
|
import { useOrgContactSegments } from "../hooks/use-org-contact-segments.js";
|
|
@@ -632,7 +633,260 @@ const COMPANY_FIELD_SX = {
|
|
|
632
633
|
sx: COMPANY_FIELD_SX
|
|
633
634
|
});
|
|
634
635
|
});
|
|
635
|
-
|
|
636
|
+
/** A text field that redraws only when what it shows changes (AGL-3423). */ const MemoTextField = /*#__PURE__*/ memo(TextField);
|
|
637
|
+
const MemoContainerPicker = /*#__PURE__*/ memo(ContainerPicker);
|
|
638
|
+
/**
|
|
639
|
+
* One `{ minWidth }` object per width, so a memoized field's `sx` is the same
|
|
640
|
+
* object on every render.
|
|
641
|
+
*/ const MIN_WIDTHS = new Map();
|
|
642
|
+
const atLeast = (minWidth)=>{
|
|
643
|
+
let sx = MIN_WIDTHS.get(minWidth);
|
|
644
|
+
if (!sx) {
|
|
645
|
+
sx = {
|
|
646
|
+
minWidth
|
|
647
|
+
};
|
|
648
|
+
MIN_WIDTHS.set(minWidth, sx);
|
|
649
|
+
}
|
|
650
|
+
return sx;
|
|
651
|
+
};
|
|
652
|
+
const WRAP = {
|
|
653
|
+
flexWrap: 'wrap'
|
|
654
|
+
};
|
|
655
|
+
const WRAP_TOP = {
|
|
656
|
+
flexWrap: 'wrap',
|
|
657
|
+
alignItems: 'flex-start'
|
|
658
|
+
};
|
|
659
|
+
const SUMMARY_BOX = {
|
|
660
|
+
border: 1,
|
|
661
|
+
borderColor: 'divider',
|
|
662
|
+
borderRadius: 1,
|
|
663
|
+
p: 1.5
|
|
664
|
+
};
|
|
665
|
+
const CAMPAIGN_BOX = {
|
|
666
|
+
minWidth: 240,
|
|
667
|
+
flexGrow: 1,
|
|
668
|
+
maxWidth: 360
|
|
669
|
+
};
|
|
670
|
+
const CAPTION_BLOCK = {
|
|
671
|
+
display: 'block',
|
|
672
|
+
mt: 0.5
|
|
673
|
+
};
|
|
674
|
+
const MULTIPLE = {
|
|
675
|
+
select: {
|
|
676
|
+
multiple: true
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
const SHRUNK_LABEL = {
|
|
680
|
+
inputLabel: {
|
|
681
|
+
shrink: true
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
const STAGES_SELECT = {
|
|
685
|
+
select: {
|
|
686
|
+
multiple: true,
|
|
687
|
+
renderValue: (selected)=>selected.map((stage)=>{
|
|
688
|
+
var _CONTACT_LIFECYCLE_STAGE_LABELS_stage;
|
|
689
|
+
return (_CONTACT_LIFECYCLE_STAGE_LABELS_stage = CONTACT_LIFECYCLE_STAGE_LABELS[stage]) != null ? _CONTACT_LIFECYCLE_STAGE_LABELS_stage : stage;
|
|
690
|
+
}).join(', ')
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
/*
|
|
694
|
+
* The fixed menus, built once. A select's options are its children, and a
|
|
695
|
+
* child list built during render is a new prop on every render.
|
|
696
|
+
*/ const SOURCE_MENU = Object.entries(SOURCE_LABELS).map(([value, label])=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
697
|
+
value: value,
|
|
698
|
+
children: label
|
|
699
|
+
}, value));
|
|
700
|
+
const MATCH_MENU = [
|
|
701
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
702
|
+
value: "all",
|
|
703
|
+
children: 'All of the filters below'
|
|
704
|
+
}, "all"),
|
|
705
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
706
|
+
value: "any",
|
|
707
|
+
children: 'Any one of the filters below'
|
|
708
|
+
}, "any"),
|
|
709
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
710
|
+
value: "none",
|
|
711
|
+
children: 'Nobody matching all of them'
|
|
712
|
+
}, "none")
|
|
713
|
+
];
|
|
714
|
+
const CAPTURE_MENU = Object.entries(CONTACT_SOURCE_LABELS).map(([value, label])=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
715
|
+
value: value,
|
|
716
|
+
children: label
|
|
717
|
+
}, value));
|
|
718
|
+
const STAGE_MENU = CONTACT_LIFECYCLE_STAGES.map((stage)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
719
|
+
value: stage,
|
|
720
|
+
children: CONTACT_LIFECYCLE_STAGE_LABELS[stage]
|
|
721
|
+
}, stage));
|
|
722
|
+
const OP_MENU = DYNAMIC_LIST_CUSTOM_OPS.map((op)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
723
|
+
value: op,
|
|
724
|
+
children: CUSTOM_OP_LABELS[op]
|
|
725
|
+
}, op));
|
|
726
|
+
const CHECKED_MENU = [
|
|
727
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
728
|
+
value: "true",
|
|
729
|
+
children: 'Checked'
|
|
730
|
+
}, "true"),
|
|
731
|
+
/*#__PURE__*/ _jsx(MenuItem, {
|
|
732
|
+
value: "false",
|
|
733
|
+
children: 'Not checked'
|
|
734
|
+
}, "false")
|
|
735
|
+
];
|
|
736
|
+
/** A multi-select hands back a string when only one option is chosen. */ const asArray = (value)=>typeof value === 'string' ? [
|
|
737
|
+
value
|
|
738
|
+
] : value != null ? value : [];
|
|
739
|
+
/** Saved segments, views and audiences as menu items: a name, else the id. */ const menuOf = (rows)=>rows.map((row)=>{
|
|
740
|
+
var _row_name;
|
|
741
|
+
return /*#__PURE__*/ _jsx(MenuItem, {
|
|
742
|
+
value: row.$id,
|
|
743
|
+
children: (_row_name = row.name) != null ? _row_name : row.$id
|
|
744
|
+
}, row.$id);
|
|
745
|
+
});
|
|
746
|
+
/** The first choice of a saved segment or view: none. No stored id is empty. */ const NONE_ITEM = /*#__PURE__*/ _jsx(MenuItem, {
|
|
747
|
+
value: "",
|
|
748
|
+
children: 'None'
|
|
749
|
+
}, "");
|
|
750
|
+
/**
|
|
751
|
+
* One field condition: the field, how it compares, and the value — typed by
|
|
752
|
+
* the field's definition, so a number field hands the matcher a number and a
|
|
753
|
+
* choice field offers its own options, and a presence test asks for no value
|
|
754
|
+
* at all.
|
|
755
|
+
*
|
|
756
|
+
* Memoized, with handlers that write through the row's index, so a keystroke
|
|
757
|
+
* in one condition's value redraws that value and nothing else (AGL-3423).
|
|
758
|
+
*/ const CustomClauseRow = /*#__PURE__*/ memo(function CustomClauseRow(props) {
|
|
759
|
+
var _clause_value, _definition_options;
|
|
760
|
+
const { index, clause, definition, fieldMenu, onUpdate, onRemove } = props;
|
|
761
|
+
const valueText = String((_clause_value = clause.value) != null ? _clause_value : '');
|
|
762
|
+
const setKey = useCallback((event)=>onUpdate(index, {
|
|
763
|
+
key: event.target.value,
|
|
764
|
+
value: ''
|
|
765
|
+
}), [
|
|
766
|
+
index,
|
|
767
|
+
onUpdate
|
|
768
|
+
]);
|
|
769
|
+
const setOp = useCallback((event)=>onUpdate(index, {
|
|
770
|
+
op: event.target.value
|
|
771
|
+
}), [
|
|
772
|
+
index,
|
|
773
|
+
onUpdate
|
|
774
|
+
]);
|
|
775
|
+
const setValue = useCallback((event)=>onUpdate(index, {
|
|
776
|
+
value: event.target.value
|
|
777
|
+
}), [
|
|
778
|
+
index,
|
|
779
|
+
onUpdate
|
|
780
|
+
]);
|
|
781
|
+
const setChecked = useCallback((event)=>onUpdate(index, {
|
|
782
|
+
value: event.target.value === 'true'
|
|
783
|
+
}), [
|
|
784
|
+
index,
|
|
785
|
+
onUpdate
|
|
786
|
+
]);
|
|
787
|
+
const setNumber = useCallback((event)=>{
|
|
788
|
+
// A number field stores a NUMBER, so the matcher compares 10 with 9
|
|
789
|
+
// and not "10" with "9"; half-typed text stays text until it parses,
|
|
790
|
+
// rather than becoming NaN.
|
|
791
|
+
const text = event.target.value;
|
|
792
|
+
const parsed = Number(text);
|
|
793
|
+
onUpdate(index, {
|
|
794
|
+
value: text.trim() !== '' && Number.isFinite(parsed) ? parsed : text
|
|
795
|
+
});
|
|
796
|
+
}, [
|
|
797
|
+
index,
|
|
798
|
+
onUpdate
|
|
799
|
+
]);
|
|
800
|
+
const remove = useCallback(()=>onRemove(index), [
|
|
801
|
+
index,
|
|
802
|
+
onRemove
|
|
803
|
+
]);
|
|
804
|
+
return /*#__PURE__*/ _jsxs(Stack, {
|
|
805
|
+
direction: "row",
|
|
806
|
+
spacing: 1,
|
|
807
|
+
useFlexGap: true,
|
|
808
|
+
sx: WRAP_TOP,
|
|
809
|
+
children: [
|
|
810
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
811
|
+
select: true,
|
|
812
|
+
size: "small",
|
|
813
|
+
label: "Field",
|
|
814
|
+
value: clause.key,
|
|
815
|
+
onChange: setKey,
|
|
816
|
+
sx: atLeast(180),
|
|
817
|
+
children: fieldMenu
|
|
818
|
+
}),
|
|
819
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
820
|
+
select: true,
|
|
821
|
+
size: "small",
|
|
822
|
+
label: "Condition",
|
|
823
|
+
value: clause.op,
|
|
824
|
+
onChange: setOp,
|
|
825
|
+
sx: atLeast(160),
|
|
826
|
+
children: OP_MENU
|
|
827
|
+
}),
|
|
828
|
+
PRESENCE_OPS.has(clause.op) ? null : (definition == null ? void 0 : definition.type) === 'select' ? /*#__PURE__*/ _jsx(MemoTextField, {
|
|
829
|
+
select: true,
|
|
830
|
+
size: "small",
|
|
831
|
+
label: "Value",
|
|
832
|
+
value: valueText,
|
|
833
|
+
onChange: setValue,
|
|
834
|
+
sx: atLeast(180),
|
|
835
|
+
children: ((_definition_options = definition.options) != null ? _definition_options : []).map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
836
|
+
value: option,
|
|
837
|
+
children: option
|
|
838
|
+
}, option))
|
|
839
|
+
}) : (definition == null ? void 0 : definition.type) === 'checkbox' ? /*#__PURE__*/ _jsx(MemoTextField, {
|
|
840
|
+
select: true,
|
|
841
|
+
size: "small",
|
|
842
|
+
label: "Value",
|
|
843
|
+
value: clause.value === true ? 'true' : clause.value === false ? 'false' : '',
|
|
844
|
+
onChange: setChecked,
|
|
845
|
+
sx: atLeast(140),
|
|
846
|
+
children: CHECKED_MENU
|
|
847
|
+
}) : (definition == null ? void 0 : definition.type) === 'number' ? /*#__PURE__*/ _jsx(MemoTextField, {
|
|
848
|
+
type: "number",
|
|
849
|
+
size: "small",
|
|
850
|
+
label: "Value",
|
|
851
|
+
value: valueText,
|
|
852
|
+
onChange: setNumber,
|
|
853
|
+
sx: atLeast(140)
|
|
854
|
+
}) : /*#__PURE__*/ _jsx(MemoTextField, {
|
|
855
|
+
type: (definition == null ? void 0 : definition.type) === 'date' ? 'date' : 'text',
|
|
856
|
+
size: "small",
|
|
857
|
+
label: "Value",
|
|
858
|
+
value: valueText,
|
|
859
|
+
onChange: setValue,
|
|
860
|
+
slotProps: (definition == null ? void 0 : definition.type) === 'date' ? SHRUNK_LABEL : undefined,
|
|
861
|
+
sx: atLeast(180)
|
|
862
|
+
}),
|
|
863
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
864
|
+
size: "small",
|
|
865
|
+
onClick: remove,
|
|
866
|
+
children: 'Remove'
|
|
867
|
+
})
|
|
868
|
+
]
|
|
869
|
+
});
|
|
870
|
+
});
|
|
871
|
+
/**
|
|
872
|
+
* The rule's controls.
|
|
873
|
+
*
|
|
874
|
+
* ## A keystroke redraws the field it lands in (AGL-3423)
|
|
875
|
+
*
|
|
876
|
+
* Every control writes the same draft, and the draft is the parent's state,
|
|
877
|
+
* so each keystroke renders this component again. Drawn inline, that redrew
|
|
878
|
+
* every control on the form — 27 inputs and some thousand components for one
|
|
879
|
+
* letter — and a keystroke that costs that much lets typed input queue, which
|
|
880
|
+
* is what turns a chip field's per-commit update into React #185. So every
|
|
881
|
+
* control is memoized and handed only props that keep their identity while
|
|
882
|
+
* what it shows is unchanged: handlers that write through the latest draft,
|
|
883
|
+
* menus built once or from their own data, and `sx` objects that are
|
|
884
|
+
* constants. The sentences above the controls are the one part that is meant
|
|
885
|
+
* to change with every keystroke.
|
|
886
|
+
*
|
|
887
|
+
* The component is memoized as a whole as well, so a keystroke in the page's
|
|
888
|
+
* own fields — the list's name — does not draw the rule at all.
|
|
889
|
+
*/ export const DynamicListRuleFields = /*#__PURE__*/ memo(function DynamicListRuleFields(props) {
|
|
636
890
|
var _team_error;
|
|
637
891
|
const { scope, hostId, draft, onChange, listId } = props;
|
|
638
892
|
const segmentDocs = useOrgContactSegments(scope);
|
|
@@ -645,7 +899,7 @@ export function DynamicListRuleFields(props) {
|
|
|
645
899
|
* picker beside fields a reader came for; here the picker IS one of the
|
|
646
900
|
* fields the reader came for, and the same reasoning that opens the segment
|
|
647
901
|
* listen opens this one.
|
|
648
|
-
*/ const siteCampaigns =
|
|
902
|
+
*/ const siteCampaigns = useSiteContainerOptions('campaign', hostId, {
|
|
649
903
|
enabled: true
|
|
650
904
|
});
|
|
651
905
|
/*
|
|
@@ -717,6 +971,12 @@ export function DynamicListRuleFields(props) {
|
|
|
717
971
|
listDocs,
|
|
718
972
|
listId
|
|
719
973
|
]);
|
|
974
|
+
const memberNames = useMemo(()=>Object.fromEntries(team.options.map((option)=>[
|
|
975
|
+
option.uid,
|
|
976
|
+
option.label
|
|
977
|
+
])), [
|
|
978
|
+
team.options
|
|
979
|
+
]);
|
|
720
980
|
/** Ids the pickers can show, so a clause names an audience rather than a uid. */ const names = useMemo(()=>({
|
|
721
981
|
lists: Object.fromEntries(listDocs.map((row)=>{
|
|
722
982
|
var _row_name;
|
|
@@ -740,10 +1000,7 @@ export function DynamicListRuleFields(props) {
|
|
|
740
1000
|
option.value,
|
|
741
1001
|
option.label
|
|
742
1002
|
])),
|
|
743
|
-
members:
|
|
744
|
-
option.uid,
|
|
745
|
-
option.label
|
|
746
|
-
])),
|
|
1003
|
+
members: memberNames,
|
|
747
1004
|
companies: companies.names,
|
|
748
1005
|
fields: Object.fromEntries(fieldDefinitions.fields.map((field)=>[
|
|
749
1006
|
field.key,
|
|
@@ -754,7 +1011,7 @@ export function DynamicListRuleFields(props) {
|
|
|
754
1011
|
segments,
|
|
755
1012
|
crmViews,
|
|
756
1013
|
siteCampaigns.options,
|
|
757
|
-
|
|
1014
|
+
memberNames,
|
|
758
1015
|
companies.names,
|
|
759
1016
|
fieldDefinitions.fields
|
|
760
1017
|
]);
|
|
@@ -779,7 +1036,11 @@ export function DynamicListRuleFields(props) {
|
|
|
779
1036
|
team.options,
|
|
780
1037
|
draft.ownerUids
|
|
781
1038
|
]);
|
|
782
|
-
|
|
1039
|
+
/*
|
|
1040
|
+
* Held by content: the options are read from the clauses' KEYS, and a value
|
|
1041
|
+
* typed into a clause is a new clause list with the same keys — which would
|
|
1042
|
+
* otherwise redraw every row's field picker on each keystroke (AGL-3423).
|
|
1043
|
+
*/ const fieldOptions = useContentStable(useMemo(()=>{
|
|
783
1044
|
const known = new Set(fieldDefinitions.fields.map((field)=>field.key));
|
|
784
1045
|
return [
|
|
785
1046
|
...draft.custom.filter((clause)=>!known.has(clause.key)).map((clause)=>({
|
|
@@ -794,14 +1055,47 @@ export function DynamicListRuleFields(props) {
|
|
|
794
1055
|
}, [
|
|
795
1056
|
fieldDefinitions.fields,
|
|
796
1057
|
draft.custom
|
|
1058
|
+
]));
|
|
1059
|
+
/* The menus that come from data, rebuilt only when their data changes. */ const segmentMenu = useMemo(()=>[
|
|
1060
|
+
NONE_ITEM,
|
|
1061
|
+
...menuOf(segments)
|
|
1062
|
+
], [
|
|
1063
|
+
segments
|
|
1064
|
+
]);
|
|
1065
|
+
const viewMenu = useMemo(()=>[
|
|
1066
|
+
NONE_ITEM,
|
|
1067
|
+
...menuOf(crmViews)
|
|
1068
|
+
], [
|
|
1069
|
+
crmViews
|
|
1070
|
+
]);
|
|
1071
|
+
const listMenu = useMemo(()=>menuOf(lists), [
|
|
1072
|
+
lists
|
|
1073
|
+
]);
|
|
1074
|
+
const ownerMenu = useMemo(()=>ownerOptions.map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1075
|
+
value: option.uid,
|
|
1076
|
+
children: option.label
|
|
1077
|
+
}, option.uid)), [
|
|
1078
|
+
ownerOptions
|
|
1079
|
+
]);
|
|
1080
|
+
const ownerSelect = useMemo(()=>({
|
|
1081
|
+
select: {
|
|
1082
|
+
multiple: true,
|
|
1083
|
+
renderValue: (selected)=>selected.map((uid)=>named(uid, memberNames)).join(', ')
|
|
1084
|
+
}
|
|
1085
|
+
}), [
|
|
1086
|
+
memberNames
|
|
1087
|
+
]);
|
|
1088
|
+
const fieldMenu = useMemo(()=>fieldOptions.map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1089
|
+
value: option.key,
|
|
1090
|
+
children: option.label
|
|
1091
|
+
}, option.key)), [
|
|
1092
|
+
fieldOptions
|
|
797
1093
|
]);
|
|
798
|
-
/** The definition a clause's key names, when the org still has one. */ const definitionFor = (key)=>fieldDefinitions.fields.find((field)=>field.key === key);
|
|
799
|
-
const set = (key, value)=>onChange(_extends({}, draft, {
|
|
800
|
-
[key]: value
|
|
801
|
-
}));
|
|
802
1094
|
/*
|
|
803
|
-
*
|
|
804
|
-
*
|
|
1095
|
+
* Every control writes `{ ...draft, [key]: value }` from the last rendered
|
|
1096
|
+
* draft, through handlers that keep their identity from render to render —
|
|
1097
|
+
* a handler rebuilt per render is a changed prop, and a changed prop redraws
|
|
1098
|
+
* the field it is on.
|
|
805
1099
|
*/ const latest = useRef({
|
|
806
1100
|
draft,
|
|
807
1101
|
onChange
|
|
@@ -810,9 +1104,40 @@ export function DynamicListRuleFields(props) {
|
|
|
810
1104
|
draft,
|
|
811
1105
|
onChange
|
|
812
1106
|
};
|
|
813
|
-
const
|
|
814
|
-
|
|
1107
|
+
const set = useCallback((key, value)=>latest.current.onChange(_extends({}, latest.current.draft, {
|
|
1108
|
+
[key]: value
|
|
815
1109
|
})), []);
|
|
1110
|
+
const on = useMemo(()=>{
|
|
1111
|
+
const typed = (key)=>(event)=>set(key, event.target.value);
|
|
1112
|
+
return {
|
|
1113
|
+
sources: (event)=>set('sources', asArray(event.target.value)),
|
|
1114
|
+
match: (event)=>set('match', event.target.value),
|
|
1115
|
+
createdAfter: typed('createdAfter'),
|
|
1116
|
+
createdBefore: typed('createdBefore'),
|
|
1117
|
+
formNames: typed('formNames'),
|
|
1118
|
+
campaignIds: (next)=>set('campaignIds', next),
|
|
1119
|
+
segmentId: typed('segmentId'),
|
|
1120
|
+
viewId: typed('viewId'),
|
|
1121
|
+
tags: typed('tags'),
|
|
1122
|
+
captureSources: (event)=>set('captureSources', asArray(event.target.value)),
|
|
1123
|
+
ownerUids: (event)=>set('ownerUids', asArray(event.target.value)),
|
|
1124
|
+
lifecycleStages: (event)=>set('lifecycleStages', asArray(event.target.value)),
|
|
1125
|
+
companyIds: (companyIds)=>set('companyIds', companyIds),
|
|
1126
|
+
engagedWithinDays: typed('engagedWithinDays'),
|
|
1127
|
+
ordersCountAtLeast: typed('ordersCountAtLeast'),
|
|
1128
|
+
ltvAtLeast: typed('ltvAtLeast'),
|
|
1129
|
+
lastPurchaseWithinDays: typed('lastPurchaseWithinDays'),
|
|
1130
|
+
noPurchaseForDays: typed('noPurchaseForDays'),
|
|
1131
|
+
openedWithinDays: typed('openedWithinDays'),
|
|
1132
|
+
clickedWithinDays: typed('clickedWithinDays'),
|
|
1133
|
+
notOpenedForDays: typed('notOpenedForDays'),
|
|
1134
|
+
notClickedForDays: typed('notClickedForDays'),
|
|
1135
|
+
inListIds: (event)=>set('inListIds', asArray(event.target.value)),
|
|
1136
|
+
notInListIds: (event)=>set('notInListIds', asArray(event.target.value))
|
|
1137
|
+
};
|
|
1138
|
+
}, [
|
|
1139
|
+
set
|
|
1140
|
+
]);
|
|
816
1141
|
const companyIds = draft.companyIds;
|
|
817
1142
|
const companyNames = companies.names;
|
|
818
1143
|
const chosenCompanies = useMemo(()=>companyIds.map((id)=>{
|
|
@@ -833,39 +1158,39 @@ export function DynamicListRuleFields(props) {
|
|
|
833
1158
|
* a value typed for a number field is not a value for the select that
|
|
834
1159
|
* replaced it; changing the operator to a presence test removes it, so the
|
|
835
1160
|
* stored clause carries no value the sentence does not read.
|
|
836
|
-
*/ const addClause = ()=>{
|
|
1161
|
+
*/ const addClause = useCallback(()=>{
|
|
837
1162
|
const first = fieldOptions[0];
|
|
838
1163
|
if (!first) return;
|
|
839
1164
|
set('custom', [
|
|
840
|
-
...draft.custom,
|
|
1165
|
+
...latest.current.draft.custom,
|
|
841
1166
|
{
|
|
842
1167
|
key: first.key,
|
|
843
1168
|
op: 'eq',
|
|
844
1169
|
value: ''
|
|
845
1170
|
}
|
|
846
1171
|
]);
|
|
847
|
-
}
|
|
848
|
-
|
|
1172
|
+
}, [
|
|
1173
|
+
fieldOptions,
|
|
1174
|
+
set
|
|
1175
|
+
]);
|
|
1176
|
+
const updateClause = useCallback((index, patch)=>set('custom', latest.current.draft.custom.map((clause, at)=>{
|
|
849
1177
|
if (at !== index) return clause;
|
|
850
1178
|
const next = _extends({}, clause, patch);
|
|
851
1179
|
if (PRESENCE_OPS.has(next.op)) delete next.value;
|
|
852
1180
|
return next;
|
|
853
|
-
}))
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1181
|
+
})), [
|
|
1182
|
+
set
|
|
1183
|
+
]);
|
|
1184
|
+
const removeClause = useCallback((index)=>set('custom', latest.current.draft.custom.filter((_, at)=>at !== index)), [
|
|
1185
|
+
set
|
|
1186
|
+
]);
|
|
1187
|
+
/** The definition a clause's key names, when the org still has one. */ const definitionFor = (key)=>fieldDefinitions.fields.find((field)=>field.key === key);
|
|
858
1188
|
const contactsOnly = draft.sources.includes('contacts');
|
|
859
1189
|
return /*#__PURE__*/ _jsxs(Stack, {
|
|
860
1190
|
spacing: 1.5,
|
|
861
1191
|
children: [
|
|
862
1192
|
/*#__PURE__*/ _jsxs(Box, {
|
|
863
|
-
sx:
|
|
864
|
-
border: 1,
|
|
865
|
-
borderColor: 'divider',
|
|
866
|
-
borderRadius: 1,
|
|
867
|
-
p: 1.5
|
|
868
|
-
},
|
|
1193
|
+
sx: SUMMARY_BOX,
|
|
869
1194
|
children: [
|
|
870
1195
|
/*#__PURE__*/ _jsx(Typography, {
|
|
871
1196
|
variant: "overline",
|
|
@@ -882,105 +1207,62 @@ export function DynamicListRuleFields(props) {
|
|
|
882
1207
|
direction: "row",
|
|
883
1208
|
spacing: 1,
|
|
884
1209
|
useFlexGap: true,
|
|
885
|
-
sx:
|
|
886
|
-
flexWrap: 'wrap'
|
|
887
|
-
},
|
|
1210
|
+
sx: WRAP,
|
|
888
1211
|
children: [
|
|
889
|
-
/*#__PURE__*/ _jsx(
|
|
1212
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
890
1213
|
select: true,
|
|
891
1214
|
size: "small",
|
|
892
1215
|
label: "People from",
|
|
893
1216
|
value: draft.sources,
|
|
894
|
-
onChange:
|
|
895
|
-
slotProps:
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
}
|
|
899
|
-
},
|
|
900
|
-
sx: {
|
|
901
|
-
minWidth: 220
|
|
902
|
-
},
|
|
903
|
-
children: Object.entries(SOURCE_LABELS).map(([value, label])=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
904
|
-
value: value,
|
|
905
|
-
children: label
|
|
906
|
-
}, value))
|
|
1217
|
+
onChange: on.sources,
|
|
1218
|
+
slotProps: MULTIPLE,
|
|
1219
|
+
sx: atLeast(220),
|
|
1220
|
+
children: SOURCE_MENU
|
|
907
1221
|
}),
|
|
908
|
-
/*#__PURE__*/
|
|
1222
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
909
1223
|
select: true,
|
|
910
1224
|
size: "small",
|
|
911
1225
|
label: "Match",
|
|
912
1226
|
value: draft.match,
|
|
913
|
-
onChange:
|
|
1227
|
+
onChange: on.match,
|
|
914
1228
|
helperText: "A saved segment always applies",
|
|
915
|
-
sx:
|
|
916
|
-
|
|
917
|
-
},
|
|
918
|
-
children: [
|
|
919
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
920
|
-
value: "all",
|
|
921
|
-
children: 'All of the filters below'
|
|
922
|
-
}),
|
|
923
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
924
|
-
value: "any",
|
|
925
|
-
children: 'Any one of the filters below'
|
|
926
|
-
}),
|
|
927
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
928
|
-
value: "none",
|
|
929
|
-
children: 'Nobody matching all of them'
|
|
930
|
-
})
|
|
931
|
-
]
|
|
1229
|
+
sx: atLeast(210),
|
|
1230
|
+
children: MATCH_MENU
|
|
932
1231
|
}),
|
|
933
|
-
/*#__PURE__*/ _jsx(
|
|
1232
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
934
1233
|
type: "date",
|
|
935
1234
|
size: "small",
|
|
936
1235
|
label: "Created after",
|
|
937
1236
|
value: draft.createdAfter,
|
|
938
|
-
onChange:
|
|
939
|
-
slotProps:
|
|
940
|
-
|
|
941
|
-
shrink: true
|
|
942
|
-
}
|
|
943
|
-
},
|
|
944
|
-
sx: {
|
|
945
|
-
minWidth: 170
|
|
946
|
-
}
|
|
1237
|
+
onChange: on.createdAfter,
|
|
1238
|
+
slotProps: SHRUNK_LABEL,
|
|
1239
|
+
sx: atLeast(170)
|
|
947
1240
|
}),
|
|
948
|
-
/*#__PURE__*/ _jsx(
|
|
1241
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
949
1242
|
type: "date",
|
|
950
1243
|
size: "small",
|
|
951
1244
|
label: "Created before",
|
|
952
1245
|
value: draft.createdBefore,
|
|
953
|
-
onChange:
|
|
954
|
-
slotProps:
|
|
955
|
-
|
|
956
|
-
shrink: true
|
|
957
|
-
}
|
|
958
|
-
},
|
|
959
|
-
sx: {
|
|
960
|
-
minWidth: 170
|
|
961
|
-
}
|
|
1246
|
+
onChange: on.createdBefore,
|
|
1247
|
+
slotProps: SHRUNK_LABEL,
|
|
1248
|
+
sx: atLeast(170)
|
|
962
1249
|
}),
|
|
963
|
-
/*#__PURE__*/ _jsx(
|
|
1250
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
964
1251
|
size: "small",
|
|
965
1252
|
label: "Submitted form",
|
|
966
1253
|
placeholder: "Contact us",
|
|
967
1254
|
helperText: "Form submissions only",
|
|
968
1255
|
value: draft.formNames,
|
|
969
|
-
onChange:
|
|
970
|
-
sx:
|
|
971
|
-
minWidth: 180
|
|
972
|
-
}
|
|
1256
|
+
onChange: on.formNames,
|
|
1257
|
+
sx: atLeast(180)
|
|
973
1258
|
}),
|
|
974
1259
|
/*#__PURE__*/ _jsx(Box, {
|
|
975
|
-
sx:
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
maxWidth: 360
|
|
979
|
-
},
|
|
980
|
-
children: /*#__PURE__*/ _jsx(CampaignPicker, {
|
|
1260
|
+
sx: CAMPAIGN_BOX,
|
|
1261
|
+
children: /*#__PURE__*/ _jsx(MemoContainerPicker, {
|
|
1262
|
+
kind: "campaign",
|
|
981
1263
|
options: siteCampaigns.options,
|
|
982
1264
|
value: draft.campaignIds,
|
|
983
|
-
onChange:
|
|
1265
|
+
onChange: on.campaignIds,
|
|
984
1266
|
label: "In campaign",
|
|
985
1267
|
helperText: "Contacts and form submissions filed under any campaign picked. Being in a campaign is not consent to be emailed.",
|
|
986
1268
|
empty: siteCampaigns.ready && !siteCampaigns.options.length,
|
|
@@ -1004,84 +1286,46 @@ export function DynamicListRuleFields(props) {
|
|
|
1004
1286
|
direction: "row",
|
|
1005
1287
|
spacing: 1,
|
|
1006
1288
|
useFlexGap: true,
|
|
1007
|
-
sx:
|
|
1008
|
-
flexWrap: 'wrap'
|
|
1009
|
-
},
|
|
1289
|
+
sx: WRAP,
|
|
1010
1290
|
children: [
|
|
1011
|
-
/*#__PURE__*/
|
|
1291
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1012
1292
|
select: true,
|
|
1013
1293
|
size: "small",
|
|
1014
1294
|
label: "Saved segment",
|
|
1015
1295
|
value: draft.segmentId,
|
|
1016
|
-
onChange:
|
|
1296
|
+
onChange: on.segmentId,
|
|
1017
1297
|
helperText: "Reuses that segment's tags and sources",
|
|
1018
|
-
sx:
|
|
1019
|
-
|
|
1020
|
-
},
|
|
1021
|
-
children: [
|
|
1022
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1023
|
-
value: "",
|
|
1024
|
-
children: 'None'
|
|
1025
|
-
}),
|
|
1026
|
-
segments.map((segment)=>{
|
|
1027
|
-
var _segment_name;
|
|
1028
|
-
return /*#__PURE__*/ _jsx(MenuItem, {
|
|
1029
|
-
value: segment.$id,
|
|
1030
|
-
children: (_segment_name = segment.name) != null ? _segment_name : segment.$id
|
|
1031
|
-
}, segment.$id);
|
|
1032
|
-
})
|
|
1033
|
-
]
|
|
1298
|
+
sx: atLeast(200),
|
|
1299
|
+
children: segmentMenu
|
|
1034
1300
|
}),
|
|
1035
|
-
/*#__PURE__*/
|
|
1301
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1036
1302
|
select: true,
|
|
1037
1303
|
size: "small",
|
|
1038
1304
|
label: "Saved view",
|
|
1039
1305
|
value: draft.viewId,
|
|
1040
|
-
onChange:
|
|
1306
|
+
onChange: on.viewId,
|
|
1041
1307
|
helperText: "Reuses that Contacts view's filters",
|
|
1042
|
-
sx:
|
|
1043
|
-
|
|
1044
|
-
},
|
|
1045
|
-
children: [
|
|
1046
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1047
|
-
value: "",
|
|
1048
|
-
children: 'None'
|
|
1049
|
-
}),
|
|
1050
|
-
crmViews.map((view)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1051
|
-
value: view.$id,
|
|
1052
|
-
children: view.name
|
|
1053
|
-
}, view.$id))
|
|
1054
|
-
]
|
|
1308
|
+
sx: atLeast(200),
|
|
1309
|
+
children: viewMenu
|
|
1055
1310
|
}),
|
|
1056
|
-
/*#__PURE__*/ _jsx(
|
|
1311
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1057
1312
|
size: "small",
|
|
1058
1313
|
label: "Tagged",
|
|
1059
1314
|
placeholder: "vip, wholesale",
|
|
1060
1315
|
value: draft.tags,
|
|
1061
|
-
onChange:
|
|
1062
|
-
sx:
|
|
1063
|
-
minWidth: 180
|
|
1064
|
-
}
|
|
1316
|
+
onChange: on.tags,
|
|
1317
|
+
sx: atLeast(180)
|
|
1065
1318
|
}),
|
|
1066
|
-
/*#__PURE__*/ _jsx(
|
|
1319
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1067
1320
|
select: true,
|
|
1068
1321
|
size: "small",
|
|
1069
1322
|
label: "Captured by",
|
|
1070
1323
|
value: draft.captureSources,
|
|
1071
|
-
onChange:
|
|
1072
|
-
slotProps:
|
|
1073
|
-
select: {
|
|
1074
|
-
multiple: true
|
|
1075
|
-
}
|
|
1076
|
-
},
|
|
1324
|
+
onChange: on.captureSources,
|
|
1325
|
+
slotProps: MULTIPLE,
|
|
1077
1326
|
helperText: "How the contact reached you",
|
|
1078
|
-
sx:
|
|
1079
|
-
|
|
1080
|
-
},
|
|
1081
|
-
children: Object.entries(CONTACT_SOURCE_LABELS).map(([value, label])=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1082
|
-
value: value,
|
|
1083
|
-
children: label
|
|
1084
|
-
}, value))
|
|
1327
|
+
sx: atLeast(200),
|
|
1328
|
+
children: CAPTURE_MENU
|
|
1085
1329
|
})
|
|
1086
1330
|
]
|
|
1087
1331
|
}),
|
|
@@ -1089,55 +1333,30 @@ export function DynamicListRuleFields(props) {
|
|
|
1089
1333
|
direction: "row",
|
|
1090
1334
|
spacing: 1,
|
|
1091
1335
|
useFlexGap: true,
|
|
1092
|
-
sx:
|
|
1093
|
-
flexWrap: 'wrap'
|
|
1094
|
-
},
|
|
1336
|
+
sx: WRAP,
|
|
1095
1337
|
children: [
|
|
1096
|
-
/*#__PURE__*/ _jsx(
|
|
1338
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1097
1339
|
select: true,
|
|
1098
1340
|
size: "small",
|
|
1099
1341
|
label: "Owned by",
|
|
1100
1342
|
value: draft.ownerUids,
|
|
1101
|
-
onChange:
|
|
1102
|
-
slotProps:
|
|
1103
|
-
select: {
|
|
1104
|
-
multiple: true,
|
|
1105
|
-
renderValue: (selected)=>selected.map((uid)=>named(uid, names.members)).join(', ')
|
|
1106
|
-
}
|
|
1107
|
-
},
|
|
1343
|
+
onChange: on.ownerUids,
|
|
1344
|
+
slotProps: ownerSelect,
|
|
1108
1345
|
error: Boolean(team.error),
|
|
1109
1346
|
helperText: (_team_error = team.error) != null ? _team_error : 'Any of these team members. Unowned contacts are left out.',
|
|
1110
|
-
sx:
|
|
1111
|
-
|
|
1112
|
-
},
|
|
1113
|
-
children: ownerOptions.map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1114
|
-
value: option.uid,
|
|
1115
|
-
children: option.label
|
|
1116
|
-
}, option.uid))
|
|
1347
|
+
sx: atLeast(220),
|
|
1348
|
+
children: ownerMenu
|
|
1117
1349
|
}),
|
|
1118
|
-
/*#__PURE__*/ _jsx(
|
|
1350
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1119
1351
|
select: true,
|
|
1120
1352
|
size: "small",
|
|
1121
1353
|
label: "Lifecycle stage",
|
|
1122
1354
|
value: draft.lifecycleStages,
|
|
1123
|
-
onChange:
|
|
1124
|
-
slotProps:
|
|
1125
|
-
select: {
|
|
1126
|
-
multiple: true,
|
|
1127
|
-
renderValue: (selected)=>selected.map((stage)=>{
|
|
1128
|
-
var _CONTACT_LIFECYCLE_STAGE_LABELS_stage;
|
|
1129
|
-
return (_CONTACT_LIFECYCLE_STAGE_LABELS_stage = CONTACT_LIFECYCLE_STAGE_LABELS[stage]) != null ? _CONTACT_LIFECYCLE_STAGE_LABELS_stage : stage;
|
|
1130
|
-
}).join(', ')
|
|
1131
|
-
}
|
|
1132
|
-
},
|
|
1355
|
+
onChange: on.lifecycleStages,
|
|
1356
|
+
slotProps: STAGES_SELECT,
|
|
1133
1357
|
helperText: "Any of these stages",
|
|
1134
|
-
sx:
|
|
1135
|
-
|
|
1136
|
-
},
|
|
1137
|
-
children: CONTACT_LIFECYCLE_STAGES.map((stage)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1138
|
-
value: stage,
|
|
1139
|
-
children: CONTACT_LIFECYCLE_STAGE_LABELS[stage]
|
|
1140
|
-
}, stage))
|
|
1358
|
+
sx: atLeast(200),
|
|
1359
|
+
children: STAGE_MENU
|
|
1141
1360
|
}),
|
|
1142
1361
|
/*#__PURE__*/ _jsx(RuleCompaniesField, {
|
|
1143
1362
|
hits: companies.hits,
|
|
@@ -1145,146 +1364,27 @@ export function DynamicListRuleFields(props) {
|
|
|
1145
1364
|
search: companySearch,
|
|
1146
1365
|
searching: companies.searching,
|
|
1147
1366
|
onSearch: setCompanySearch,
|
|
1148
|
-
onChange:
|
|
1367
|
+
onChange: on.companyIds
|
|
1149
1368
|
}),
|
|
1150
|
-
/*#__PURE__*/ _jsx(
|
|
1369
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1151
1370
|
type: "number",
|
|
1152
1371
|
size: "small",
|
|
1153
1372
|
label: "Engaged with a campaign within (days)",
|
|
1154
1373
|
helperText: "Opened or clicked one of your campaigns. Never engaged is left out.",
|
|
1155
1374
|
value: draft.engagedWithinDays,
|
|
1156
|
-
onChange:
|
|
1157
|
-
sx:
|
|
1158
|
-
minWidth: 280
|
|
1159
|
-
}
|
|
1375
|
+
onChange: on.engagedWithinDays,
|
|
1376
|
+
sx: atLeast(280)
|
|
1160
1377
|
})
|
|
1161
1378
|
]
|
|
1162
1379
|
}),
|
|
1163
|
-
draft.custom.map((clause, index)
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
sx: {
|
|
1172
|
-
flexWrap: 'wrap',
|
|
1173
|
-
alignItems: 'flex-start'
|
|
1174
|
-
},
|
|
1175
|
-
children: [
|
|
1176
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1177
|
-
select: true,
|
|
1178
|
-
size: "small",
|
|
1179
|
-
label: "Field",
|
|
1180
|
-
value: clause.key,
|
|
1181
|
-
onChange: (event)=>updateClause(index, {
|
|
1182
|
-
key: event.target.value,
|
|
1183
|
-
value: ''
|
|
1184
|
-
}),
|
|
1185
|
-
sx: {
|
|
1186
|
-
minWidth: 180
|
|
1187
|
-
},
|
|
1188
|
-
children: fieldOptions.map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1189
|
-
value: option.key,
|
|
1190
|
-
children: option.label
|
|
1191
|
-
}, option.key))
|
|
1192
|
-
}),
|
|
1193
|
-
/*#__PURE__*/ _jsx(TextField, {
|
|
1194
|
-
select: true,
|
|
1195
|
-
size: "small",
|
|
1196
|
-
label: "Condition",
|
|
1197
|
-
value: clause.op,
|
|
1198
|
-
onChange: (event)=>updateClause(index, {
|
|
1199
|
-
op: event.target.value
|
|
1200
|
-
}),
|
|
1201
|
-
sx: {
|
|
1202
|
-
minWidth: 160
|
|
1203
|
-
},
|
|
1204
|
-
children: DYNAMIC_LIST_CUSTOM_OPS.map((op)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1205
|
-
value: op,
|
|
1206
|
-
children: CUSTOM_OP_LABELS[op]
|
|
1207
|
-
}, op))
|
|
1208
|
-
}),
|
|
1209
|
-
PRESENCE_OPS.has(clause.op) ? null : (definition == null ? void 0 : definition.type) === 'select' ? /*#__PURE__*/ _jsx(TextField, {
|
|
1210
|
-
select: true,
|
|
1211
|
-
size: "small",
|
|
1212
|
-
label: "Value",
|
|
1213
|
-
value: valueText,
|
|
1214
|
-
onChange: (event)=>updateClause(index, {
|
|
1215
|
-
value: event.target.value
|
|
1216
|
-
}),
|
|
1217
|
-
sx: {
|
|
1218
|
-
minWidth: 180
|
|
1219
|
-
},
|
|
1220
|
-
children: ((_definition_options = definition.options) != null ? _definition_options : []).map((option)=>/*#__PURE__*/ _jsx(MenuItem, {
|
|
1221
|
-
value: option,
|
|
1222
|
-
children: option
|
|
1223
|
-
}, option))
|
|
1224
|
-
}) : (definition == null ? void 0 : definition.type) === 'checkbox' ? /*#__PURE__*/ _jsxs(TextField, {
|
|
1225
|
-
select: true,
|
|
1226
|
-
size: "small",
|
|
1227
|
-
label: "Value",
|
|
1228
|
-
value: clause.value === true ? 'true' : clause.value === false ? 'false' : '',
|
|
1229
|
-
onChange: (event)=>updateClause(index, {
|
|
1230
|
-
value: event.target.value === 'true'
|
|
1231
|
-
}),
|
|
1232
|
-
sx: {
|
|
1233
|
-
minWidth: 140
|
|
1234
|
-
},
|
|
1235
|
-
children: [
|
|
1236
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1237
|
-
value: "true",
|
|
1238
|
-
children: 'Checked'
|
|
1239
|
-
}),
|
|
1240
|
-
/*#__PURE__*/ _jsx(MenuItem, {
|
|
1241
|
-
value: "false",
|
|
1242
|
-
children: 'Not checked'
|
|
1243
|
-
})
|
|
1244
|
-
]
|
|
1245
|
-
}) : (definition == null ? void 0 : definition.type) === 'number' ? /*#__PURE__*/ _jsx(TextField, {
|
|
1246
|
-
type: "number",
|
|
1247
|
-
size: "small",
|
|
1248
|
-
label: "Value",
|
|
1249
|
-
value: valueText,
|
|
1250
|
-
onChange: (event)=>{
|
|
1251
|
-
// A number field stores a NUMBER, so the matcher compares
|
|
1252
|
-
// 10 with 9 and not "10" with "9"; half-typed text stays
|
|
1253
|
-
// text until it parses, rather than becoming NaN.
|
|
1254
|
-
const text = event.target.value;
|
|
1255
|
-
const parsed = Number(text);
|
|
1256
|
-
updateClause(index, {
|
|
1257
|
-
value: text.trim() !== '' && Number.isFinite(parsed) ? parsed : text
|
|
1258
|
-
});
|
|
1259
|
-
},
|
|
1260
|
-
sx: {
|
|
1261
|
-
minWidth: 140
|
|
1262
|
-
}
|
|
1263
|
-
}) : /*#__PURE__*/ _jsx(TextField, {
|
|
1264
|
-
type: (definition == null ? void 0 : definition.type) === 'date' ? 'date' : 'text',
|
|
1265
|
-
size: "small",
|
|
1266
|
-
label: "Value",
|
|
1267
|
-
value: valueText,
|
|
1268
|
-
onChange: (event)=>updateClause(index, {
|
|
1269
|
-
value: event.target.value
|
|
1270
|
-
}),
|
|
1271
|
-
slotProps: (definition == null ? void 0 : definition.type) === 'date' ? {
|
|
1272
|
-
inputLabel: {
|
|
1273
|
-
shrink: true
|
|
1274
|
-
}
|
|
1275
|
-
} : undefined,
|
|
1276
|
-
sx: {
|
|
1277
|
-
minWidth: 180
|
|
1278
|
-
}
|
|
1279
|
-
}),
|
|
1280
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
1281
|
-
size: "small",
|
|
1282
|
-
onClick: ()=>removeClause(index),
|
|
1283
|
-
children: 'Remove'
|
|
1284
|
-
})
|
|
1285
|
-
]
|
|
1286
|
-
}, index);
|
|
1287
|
-
}),
|
|
1380
|
+
draft.custom.map((clause, index)=>/*#__PURE__*/ _jsx(CustomClauseRow, {
|
|
1381
|
+
index: index,
|
|
1382
|
+
clause: clause,
|
|
1383
|
+
definition: definitionFor(clause.key),
|
|
1384
|
+
fieldMenu: fieldMenu,
|
|
1385
|
+
onUpdate: updateClause,
|
|
1386
|
+
onRemove: removeClause
|
|
1387
|
+
}, index)),
|
|
1288
1388
|
/*#__PURE__*/ _jsxs(Box, {
|
|
1289
1389
|
children: [
|
|
1290
1390
|
/*#__PURE__*/ _jsx(Button, {
|
|
@@ -1297,10 +1397,7 @@ export function DynamicListRuleFields(props) {
|
|
|
1297
1397
|
fieldDefinitions.ready && !fieldDefinitions.fields.length ? /*#__PURE__*/ _jsx(Typography, {
|
|
1298
1398
|
variant: "caption",
|
|
1299
1399
|
color: "text.secondary",
|
|
1300
|
-
sx:
|
|
1301
|
-
display: 'block',
|
|
1302
|
-
mt: 0.5
|
|
1303
|
-
},
|
|
1400
|
+
sx: CAPTION_BLOCK,
|
|
1304
1401
|
children: 'This workspace has no custom contact fields yet. Define them ' + 'under CRM → Fields to filter on them here.'
|
|
1305
1402
|
}) : null
|
|
1306
1403
|
]
|
|
@@ -1314,51 +1411,41 @@ export function DynamicListRuleFields(props) {
|
|
|
1314
1411
|
direction: "row",
|
|
1315
1412
|
spacing: 1,
|
|
1316
1413
|
useFlexGap: true,
|
|
1317
|
-
sx:
|
|
1318
|
-
flexWrap: 'wrap'
|
|
1319
|
-
},
|
|
1414
|
+
sx: WRAP,
|
|
1320
1415
|
children: [
|
|
1321
|
-
/*#__PURE__*/ _jsx(
|
|
1416
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1322
1417
|
type: "number",
|
|
1323
1418
|
size: "small",
|
|
1324
1419
|
label: "Orders at least",
|
|
1325
1420
|
value: draft.ordersCountAtLeast,
|
|
1326
|
-
onChange:
|
|
1327
|
-
sx:
|
|
1328
|
-
minWidth: 160
|
|
1329
|
-
}
|
|
1421
|
+
onChange: on.ordersCountAtLeast,
|
|
1422
|
+
sx: atLeast(160)
|
|
1330
1423
|
}),
|
|
1331
|
-
/*#__PURE__*/ _jsx(
|
|
1424
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1332
1425
|
type: "number",
|
|
1333
1426
|
size: "small",
|
|
1334
1427
|
label: "Spent at least",
|
|
1335
1428
|
helperText: "Lifetime, in your store's currency",
|
|
1336
1429
|
value: draft.ltvAtLeast,
|
|
1337
|
-
onChange:
|
|
1338
|
-
sx:
|
|
1339
|
-
minWidth: 190
|
|
1340
|
-
}
|
|
1430
|
+
onChange: on.ltvAtLeast,
|
|
1431
|
+
sx: atLeast(190)
|
|
1341
1432
|
}),
|
|
1342
|
-
/*#__PURE__*/ _jsx(
|
|
1433
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1343
1434
|
type: "number",
|
|
1344
1435
|
size: "small",
|
|
1345
1436
|
label: "Bought within (days)",
|
|
1346
1437
|
value: draft.lastPurchaseWithinDays,
|
|
1347
|
-
onChange:
|
|
1348
|
-
sx:
|
|
1349
|
-
minWidth: 190
|
|
1350
|
-
}
|
|
1438
|
+
onChange: on.lastPurchaseWithinDays,
|
|
1439
|
+
sx: atLeast(190)
|
|
1351
1440
|
}),
|
|
1352
|
-
/*#__PURE__*/ _jsx(
|
|
1441
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1353
1442
|
type: "number",
|
|
1354
1443
|
size: "small",
|
|
1355
1444
|
label: "Nothing bought for (days)",
|
|
1356
1445
|
helperText: "Lapsed customers — never bought is not lapsed",
|
|
1357
1446
|
value: draft.noPurchaseForDays,
|
|
1358
|
-
onChange:
|
|
1359
|
-
sx:
|
|
1360
|
-
minWidth: 220
|
|
1361
|
-
}
|
|
1447
|
+
onChange: on.noPurchaseForDays,
|
|
1448
|
+
sx: atLeast(220)
|
|
1362
1449
|
})
|
|
1363
1450
|
]
|
|
1364
1451
|
}),
|
|
@@ -1377,51 +1464,41 @@ export function DynamicListRuleFields(props) {
|
|
|
1377
1464
|
direction: "row",
|
|
1378
1465
|
spacing: 1,
|
|
1379
1466
|
useFlexGap: true,
|
|
1380
|
-
sx:
|
|
1381
|
-
flexWrap: 'wrap'
|
|
1382
|
-
},
|
|
1467
|
+
sx: WRAP,
|
|
1383
1468
|
children: [
|
|
1384
|
-
/*#__PURE__*/ _jsx(
|
|
1469
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1385
1470
|
type: "number",
|
|
1386
1471
|
size: "small",
|
|
1387
1472
|
label: "Opened within (days)",
|
|
1388
1473
|
value: draft.openedWithinDays,
|
|
1389
|
-
onChange:
|
|
1390
|
-
sx:
|
|
1391
|
-
minWidth: 190
|
|
1392
|
-
}
|
|
1474
|
+
onChange: on.openedWithinDays,
|
|
1475
|
+
sx: atLeast(190)
|
|
1393
1476
|
}),
|
|
1394
|
-
/*#__PURE__*/ _jsx(
|
|
1477
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1395
1478
|
type: "number",
|
|
1396
1479
|
size: "small",
|
|
1397
1480
|
label: "Clicked within (days)",
|
|
1398
1481
|
value: draft.clickedWithinDays,
|
|
1399
|
-
onChange:
|
|
1400
|
-
sx:
|
|
1401
|
-
minWidth: 190
|
|
1402
|
-
}
|
|
1482
|
+
onChange: on.clickedWithinDays,
|
|
1483
|
+
sx: atLeast(190)
|
|
1403
1484
|
}),
|
|
1404
|
-
/*#__PURE__*/ _jsx(
|
|
1485
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1405
1486
|
type: "number",
|
|
1406
1487
|
size: "small",
|
|
1407
1488
|
label: "Nothing opened for (days)",
|
|
1408
1489
|
helperText: "Never opened counts",
|
|
1409
1490
|
value: draft.notOpenedForDays,
|
|
1410
|
-
onChange:
|
|
1411
|
-
sx:
|
|
1412
|
-
minWidth: 210
|
|
1413
|
-
}
|
|
1491
|
+
onChange: on.notOpenedForDays,
|
|
1492
|
+
sx: atLeast(210)
|
|
1414
1493
|
}),
|
|
1415
|
-
/*#__PURE__*/ _jsx(
|
|
1494
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1416
1495
|
type: "number",
|
|
1417
1496
|
size: "small",
|
|
1418
1497
|
label: "Nothing clicked for (days)",
|
|
1419
1498
|
helperText: "Never clicked counts",
|
|
1420
1499
|
value: draft.notClickedForDays,
|
|
1421
|
-
onChange:
|
|
1422
|
-
sx:
|
|
1423
|
-
minWidth: 210
|
|
1424
|
-
}
|
|
1500
|
+
onChange: on.notClickedForDays,
|
|
1501
|
+
sx: atLeast(210)
|
|
1425
1502
|
})
|
|
1426
1503
|
]
|
|
1427
1504
|
}),
|
|
@@ -1435,61 +1512,35 @@ export function DynamicListRuleFields(props) {
|
|
|
1435
1512
|
direction: "row",
|
|
1436
1513
|
spacing: 1,
|
|
1437
1514
|
useFlexGap: true,
|
|
1438
|
-
sx:
|
|
1439
|
-
flexWrap: 'wrap'
|
|
1440
|
-
},
|
|
1515
|
+
sx: WRAP,
|
|
1441
1516
|
children: [
|
|
1442
|
-
/*#__PURE__*/ _jsx(
|
|
1517
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1443
1518
|
select: true,
|
|
1444
1519
|
size: "small",
|
|
1445
1520
|
label: "Already on",
|
|
1446
1521
|
value: draft.inListIds,
|
|
1447
|
-
onChange:
|
|
1448
|
-
slotProps:
|
|
1449
|
-
select: {
|
|
1450
|
-
multiple: true
|
|
1451
|
-
}
|
|
1452
|
-
},
|
|
1522
|
+
onChange: on.inListIds,
|
|
1523
|
+
slotProps: MULTIPLE,
|
|
1453
1524
|
helperText: "Members of every audience picked",
|
|
1454
|
-
sx:
|
|
1455
|
-
|
|
1456
|
-
},
|
|
1457
|
-
children: lists.map((row)=>{
|
|
1458
|
-
var _row_name;
|
|
1459
|
-
return /*#__PURE__*/ _jsx(MenuItem, {
|
|
1460
|
-
value: row.$id,
|
|
1461
|
-
children: (_row_name = row.name) != null ? _row_name : row.$id
|
|
1462
|
-
}, row.$id);
|
|
1463
|
-
})
|
|
1525
|
+
sx: atLeast(220),
|
|
1526
|
+
children: listMenu
|
|
1464
1527
|
}),
|
|
1465
|
-
/*#__PURE__*/ _jsx(
|
|
1528
|
+
/*#__PURE__*/ _jsx(MemoTextField, {
|
|
1466
1529
|
select: true,
|
|
1467
1530
|
size: "small",
|
|
1468
1531
|
label: "Not on",
|
|
1469
1532
|
value: draft.notInListIds,
|
|
1470
|
-
onChange:
|
|
1471
|
-
slotProps:
|
|
1472
|
-
select: {
|
|
1473
|
-
multiple: true
|
|
1474
|
-
}
|
|
1475
|
-
},
|
|
1533
|
+
onChange: on.notInListIds,
|
|
1534
|
+
slotProps: MULTIPLE,
|
|
1476
1535
|
helperText: "Excludes members of any audience picked",
|
|
1477
|
-
sx:
|
|
1478
|
-
|
|
1479
|
-
},
|
|
1480
|
-
children: lists.map((row)=>{
|
|
1481
|
-
var _row_name;
|
|
1482
|
-
return /*#__PURE__*/ _jsx(MenuItem, {
|
|
1483
|
-
value: row.$id,
|
|
1484
|
-
children: (_row_name = row.name) != null ? _row_name : row.$id
|
|
1485
|
-
}, row.$id);
|
|
1486
|
-
})
|
|
1536
|
+
sx: atLeast(220),
|
|
1537
|
+
children: listMenu
|
|
1487
1538
|
})
|
|
1488
1539
|
]
|
|
1489
1540
|
})
|
|
1490
1541
|
]
|
|
1491
1542
|
});
|
|
1492
|
-
}
|
|
1543
|
+
});
|
|
1493
1544
|
DynamicListRuleFields.displayName = 'DynamicListRuleFields';
|
|
1494
1545
|
/**
|
|
1495
1546
|
* A draft seeded from a rule that arrives after the form does.
|