@feedmepos/mf-connect 0.1.98-beta.21 → 0.1.98-beta.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{App-B3f8GWoR.js → App-DkvPrOD_.js} +10 -9
- package/dist/{AuditLogs-LRHzzpqj.js → AuditLogs-CWYsiJmS.js} +9 -9
- package/dist/{Bin-Y761Ua4-.js → Bin-BeuBpKQM.js} +8 -8
- package/dist/{Broadcast-CdRuG42N.js → Broadcast-Dm-HdR4q.js} +13 -12
- package/dist/CampaignAnalytic-DipDONF1.js +1656 -0
- package/dist/{CampaignTypeDialog.vue_vue_type_script_setup_true_lang-CsULDH9l.js → CampaignTypeDialog.vue_vue_type_script_setup_true_lang-D4wbIGp6.js} +6 -5
- package/dist/{Card-GZ3ZLnBl.js → Card-i5EhYfDp.js} +18 -18
- package/dist/{Collections-B59fL-oS.js → Collections-B4lpotjz.js} +14 -13
- package/dist/{Credit-DJxzXBam.js → Credit-DbK_BdJJ.js} +119 -93
- package/dist/{EditCampaignSheet.vue_vue_type_script_setup_true_lang-C3d8frgZ.js → EditCampaignSheet.vue_vue_type_script_setup_true_lang-B8Soqc5E.js} +34 -30
- package/dist/{EffectSheet.vue_vue_type_style_index_0_lang-DKUFvacX.js → EffectSheet.vue_vue_type_style_index_0_lang-DzdJH_eS.js} +6 -6
- package/dist/{Experience-lzpvYFPP.js → Experience-W3vkkzi6.js} +112 -86
- package/dist/{FileSaver.min-BXoEv5ve.js → FileSaver.min-BI4NzqgX.js} +1 -1
- package/dist/Game-fftjNIOx.js +356 -0
- package/dist/{Grab-BQgS104D.js → Grab-CMQ8P4g9.js} +32 -31
- package/dist/{ImageInput.vue_vue_type_script_setup_true_lang-Cz9iB9ox.js → ImageInput.vue_vue_type_script_setup_true_lang-DUi11pWY.js} +1 -1
- package/dist/{Index-B5UTBbUy.js → Index-Cnztjepd.js} +10 -10
- package/dist/{LocationPicker.vue_vue_type_script_setup_true_lang-CLLhy4-v.js → LocationPicker.vue_vue_type_script_setup_true_lang-Dy8WW9eT.js} +1 -1
- package/dist/{LottieAnimation.vue_vue_type_script_setup_true_lang-BiIqs4zW.js → LottieAnimation.vue_vue_type_script_setup_true_lang-DTHvv2lB.js} +1 -1
- package/dist/LoyaltyDashboard-1gKZWq0g.js +1339 -0
- package/dist/{MainLayout-AvQ4_-oT.js → MainLayout-CfKJ6l-r.js} +1 -1
- package/dist/{Marketing-Bn1ygF8d.js → Marketing-Dk_nSJuC.js} +4 -4
- package/dist/{MarketingMaterialEdit-Cw-VPVqE.js → MarketingMaterialEdit-DnO9DNuB.js} +6 -6
- package/dist/{Member-CpEXFHIF.js → Member-CpXKw34e.js} +11 -11
- package/dist/{MemberList-gSEw_idJ.js → MemberList-8ppDIsaQ.js} +36 -35
- package/dist/{MemberTransactions-DEMzj9-y.js → MemberTransactions-B52DV6hR.js} +1 -1
- package/dist/{MessageInput.vue_vue_type_script_setup_true_lang-B4Y5KPpw.js → MessageInput.vue_vue_type_script_setup_true_lang-Di0tBK7t.js} +4400 -4431
- package/dist/MetricInfoTooltip.vue_vue_type_script_setup_true_lang-B1Yj3odA.js +38 -0
- package/dist/Mission-dT284_xH.js +360 -0
- package/dist/{Overview-CMudFYOc.js → Overview-CUXmQ5AN.js} +3 -3
- package/dist/{Overview-DjNcF88f.js → Overview-CePgs6nV.js} +18 -18
- package/dist/Point-BLr01-Fi.js +288 -0
- package/dist/Promotion-BJUWwJir.js +423 -0
- package/dist/{Queue-BjoAJoVe.js → Queue-DpjzPA9X.js} +16 -16
- package/dist/{Record-CfZFuwy_.js → Record-D5iz3VhQ.js} +9 -9
- package/dist/{Review-pIAxbjVU.js → Review-BIDSfZ-d.js} +2 -2
- package/dist/{ReviewFacebookCallback-BRW4T-5-.js → ReviewFacebookCallback-Cl4apd5U.js} +5 -5
- package/dist/{ReviewGoogleCallback-B-6EojXR.js → ReviewGoogleCallback-CxQ3jv5Z.js} +5 -5
- package/dist/{Reward-_pdE2XZp.js → Reward-FhUo0v2c.js} +16 -16
- package/dist/{RewardGroup.vue_vue_type_script_setup_true_lang-S5dh0IGc.js → RewardGroup.vue_vue_type_script_setup_true_lang-9Fdl4-Zk.js} +11 -11
- package/dist/{RuleGroup.vue_vue_type_script_setup_true_lang-C9B7NmF0.js → RuleGroup.vue_vue_type_script_setup_true_lang-Bh1rez91.js} +16 -15
- package/dist/{Segment-B1EMe-LZ.js → Segment-XrwahyNZ.js} +39 -37
- package/dist/{SelectItems.vue_vue_type_script_setup_true_lang-DAmjk8b3.js → SelectItems.vue_vue_type_script_setup_true_lang-Bd_O16Eo.js} +2 -2
- package/dist/{SendCollectionSheet.vue_vue_type_script_setup_true_lang-C7sgPf8l.js → SendCollectionSheet.vue_vue_type_script_setup_true_lang-CB0bY0pg.js} +12 -12
- package/dist/{SendVoucherSheet.vue_vue_type_script_setup_true_lang-DVYTZr_E.js → SendVoucherSheet.vue_vue_type_script_setup_true_lang-B1-fwLJq.js} +4 -4
- package/dist/{Setting-CQQ6zacB.js → Setting-Cs5abyWq.js} +40 -40
- package/dist/{SettingAdvertisements-9Wl9VWbM.js → SettingAdvertisements-C0NbeiB9.js} +12 -12
- package/dist/{Settings-Bvj2ChDR.js → Settings-xdy_sV8_.js} +5 -5
- package/dist/{Store-BdUZ22g6.js → Store-BVn4DGJN.js} +21 -21
- package/dist/{StoreRewards-DsUS_Lu1.js → StoreRewards-BnEDugiP.js} +15 -15
- package/dist/{StoreTransactions.vue_vue_type_script_setup_true_lang-Zw-lIDCN.js → StoreTransactions.vue_vue_type_script_setup_true_lang-B63UqQ0d.js} +21 -21
- package/dist/{TargetLocationInput.vue_vue_type_script_setup_true_lang-BECp3eqQ.js → TargetLocationInput.vue_vue_type_script_setup_true_lang-BOIUqr5c.js} +2 -2
- package/dist/{Tier-2-mJ3SNK.js → Tier-BdyyZ6S8.js} +36 -34
- package/dist/{Title-BjeEDjxl.js → Title-Y7GfS9n5.js} +39 -37
- package/dist/{Transaction--U_kJKec.js → Transaction-DF217QY1.js} +2 -2
- package/dist/{UserRuleGroup.vue_vue_type_script_setup_true_lang-BkLyvjA5.js → UserRuleGroup.vue_vue_type_script_setup_true_lang-QrbU0JEl.js} +6 -6
- package/dist/{Voucher-INa3N_6V.js → Voucher-q9JMtbmK.js} +156 -133
- package/dist/{VoucherEditor.vue_vue_type_script_setup_true_lang-4Quzmc7-.js → VoucherEditor.vue_vue_type_script_setup_true_lang-Cm040eE9.js} +12 -12
- package/dist/{ZodTextField.vue_vue_type_script_setup_true_lang-CPCnBExY.js → ZodTextField.vue_vue_type_script_setup_true_lang-DibJzz40.js} +2 -2
- package/dist/{app-Dlqr-LX4.js → app-BZJkvDm7.js} +3279 -3135
- package/dist/app.js +1 -1
- package/dist/{business-DWrfGEe_.js → business-akMhlJ-M.js} +1 -1
- package/dist/{campaign-DtNt-BqN.js → campaign-BDXIKhhi.js} +74 -96
- package/dist/campaign-hm_reShF.js +100 -0
- package/dist/{campaign.enum-B9-ZpK0C.js → campaign.enum-Dx-Zo68Q.js} +1 -1
- package/dist/{campaign.fn-COxaWmi_.js → campaign.fn-BFI2Flc_.js} +126 -126
- package/dist/{collectible.enum-CF0VF-r7.js → collectible.enum-Liy2wH3s.js} +1 -1
- package/dist/collection.fn-RUGxb2Zd.js +26 -0
- package/dist/{duplicateCampaign-8ciT68QF.js → duplicateCampaign-DsGtbLbP.js} +2 -2
- package/dist/{effect-CaSn-84h.js → effect-8iyz8Uq4.js} +1 -1
- package/dist/{email-addresses-BiMQ8xIx.js → email-addresses-gyl-C-R_.js} +2 -2
- package/dist/{export-BwBNgCo5.js → export-wupBk3du.js} +3 -3
- package/dist/{helper-CajV_0CM.js → helper-CaxDAXPt.js} +1 -1
- package/dist/{index-CQIciFrH.js → index-BMin5EVt.js} +1 -1
- package/dist/{index-CQj9BQlQ.js → index-BO9SkdZr.js} +105 -123
- package/dist/index-BOcaalDh.js +146 -0
- package/dist/{index-B6ldAC8Y.js → index-BQmxPtoj.js} +1 -1
- package/dist/{index-B6tm_U_M.js → index-Bic6MeUk.js} +18 -17
- package/dist/{index-D1vhLY7l.js → index-C4drX0Ls.js} +1 -1
- package/dist/index-C8cXXcLk.js +45 -0
- package/dist/{index-DBUTFa2h.js → index-CG66mIC4.js} +2 -2
- package/dist/index-C_H8jFYf.js +2743 -0
- package/dist/{index-Bqcfsd4p.js → index-Cw-UC5sx.js} +8 -7
- package/dist/{index-D1--K-QL.js → index-D4BfoKjK.js} +1 -1
- package/dist/{index-DWBKko92.js → index-DhQlBP7P.js} +6 -6
- package/dist/{index-J8pSZ3WO.js → index-Dvf0YXyw.js} +1 -1
- package/dist/{index-BP5rdioN.js → index-J3y4ZPL5.js} +8027 -10766
- package/dist/{index-CjW6Mj-1.js → index-bZhlsMWI.js} +1 -1
- package/dist/{index-B0ohh62P.js → index-xGCLj50g.js} +230 -351
- package/dist/{index-D90p28Hr.js → index-yYZu6iPh.js} +205 -229
- package/dist/{index.esm2017-QlPanYiW.js → index.esm2017-DgAjf49-.js} +1 -1
- package/dist/{loading-CqqkzWSm.js → loading-DIme5B41.js} +1 -1
- package/dist/{lodash-DmbW2QhA.js → lodash-ssnk3xgl.js} +1 -1
- package/dist/{membership-Dcwyu-rr.js → membership-CNHGvM-v.js} +3 -3
- package/dist/{money-DWr1gi--.js → money-CxE1yyP-.js} +1 -1
- package/dist/{number-CHhHAd1q.js → number-MuiSu5EH.js} +1 -1
- package/dist/{objectid-BsiuHVH8.js → objectid-BKst2tcL.js} +9 -9
- package/dist/{plugins-BxmMI8fo.js → plugins-J8P61v6q.js} +3 -3
- package/dist/{reward-DX0FjsNT.js → reward-CvyDLx6u.js} +1 -1
- package/dist/{rule-DDLcqiHH.js → rule-CidUfHRV.js} +3 -3
- package/dist/rule-builder-CzSwZHFX.js +126 -0
- package/dist/{template-C0lF82yv.js → template-DDFGgRca.js} +6 -6
- package/dist/timezone-C55-EXUa.js +20 -0
- package/dist/{trigger-CsJcg_RY.js → trigger-BHmznST2.js} +5 -5
- package/dist/{useMarketingMaterialActions-B0iV6YzB.js → useMarketingMaterialActions-CRGy07Kl.js} +3 -3
- package/dist/{usePagination-4EISkyGW.js → usePagination-nKd3ToBL.js} +1 -1
- package/dist/{user-DZuSeqRY.js → user-CxxLM4oI.js} +1 -1
- package/dist/{vue-i18n-BKcwYlp1.js → vue-i18n-BIqCnVyc.js} +300 -300
- package/dist/{xlsx-C-7dia55.js → xlsx-CUqEhJg1.js} +1 -1
- package/dist/{zod-DPxXVSRw.js → zod-B3g-tD-1.js} +1 -1
- package/package.json +1 -1
- package/dist/Game-KCxIpXEC.js +0 -330
- package/dist/LoyaltyDashboard-DPHWpaNJ.js +0 -1082
- package/dist/Mission-DMtpauNQ.js +0 -334
- package/dist/Point-CgdTrgXc.js +0 -262
- package/dist/Promotion-DDQodFDb.js +0 -397
- package/dist/campaign-un9Ji1KF.js +0 -219
|
@@ -0,0 +1,1339 @@
|
|
|
1
|
+
import { defineComponent as L, resolveComponent as _, openBlock as l, createBlock as A, withCtx as D, createElementVNode as t, createVNode as p, unref as f, createTextVNode as te, createElementBlock as u, Fragment as F, renderList as B, normalizeClass as I, toDisplayString as d, createCommentVNode as U, normalizeStyle as ze, computed as w, ref as x, watch as ge, onMounted as qe, nextTick as Ye } from "vue";
|
|
2
|
+
import { h as he } from "./moment-D7p2TMB-.js";
|
|
3
|
+
import { g as R, S as je, b as Ge, c as Je } from "./index-CG66mIC4.js";
|
|
4
|
+
import { RouterLink as Me, useRouter as Ke } from "vue-router";
|
|
5
|
+
import { c as We } from "./index-BOcaalDh.js";
|
|
6
|
+
import { _ as T } from "./MetricInfoTooltip.vue_vue_type_script_setup_true_lang-B1Yj3odA.js";
|
|
7
|
+
import { _ as Qe } from "./FilterChip.vue_vue_type_script_setup_true_lang-DaU-9GzO.js";
|
|
8
|
+
import { _ as xe } from "./DateRangeChip.vue_vue_type_script_setup_true_lang-eIoPtgO5.js";
|
|
9
|
+
import { u as Xe } from "./loading-DIme5B41.js";
|
|
10
|
+
import { u as Ze } from "./business-akMhlJ-M.js";
|
|
11
|
+
import { C as _e } from "./timezone-C55-EXUa.js";
|
|
12
|
+
import { useCoreStore as et } from "@feedmepos/mf-common";
|
|
13
|
+
import { m as V } from "./index-BO9SkdZr.js";
|
|
14
|
+
import { t as tt } from "./money-CxE1yyP-.js";
|
|
15
|
+
const rt = { class: "flex items-center mb-14" }, st = {
|
|
16
|
+
key: 0,
|
|
17
|
+
class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary py-10"
|
|
18
|
+
}, ot = {
|
|
19
|
+
key: 1,
|
|
20
|
+
class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary py-10"
|
|
21
|
+
}, at = {
|
|
22
|
+
key: 2,
|
|
23
|
+
class: "flex flex-col"
|
|
24
|
+
}, nt = { class: "flex-1 min-w-0" }, it = { class: "fm-typo-en-body-sm-600 whitespace-nowrap overflow-hidden text-ellipsis" }, lt = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary mt-2" }, dt = { class: "text-right flex-shrink-0" }, ct = { class: "fm-typo-en-body-lg-600" }, mt = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary mt-2" }, ut = {
|
|
25
|
+
key: 3,
|
|
26
|
+
class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary py-10"
|
|
27
|
+
}, pt = /* @__PURE__ */ L({
|
|
28
|
+
__name: "CampaignActivityList",
|
|
29
|
+
props: {
|
|
30
|
+
campaigns: {},
|
|
31
|
+
loading: { type: Boolean },
|
|
32
|
+
error: { type: Boolean }
|
|
33
|
+
},
|
|
34
|
+
setup(e) {
|
|
35
|
+
return (o, r) => {
|
|
36
|
+
const n = _("FmCard");
|
|
37
|
+
return l(), A(n, {
|
|
38
|
+
variant: "outlined",
|
|
39
|
+
class: "p-24"
|
|
40
|
+
}, {
|
|
41
|
+
default: D(() => [
|
|
42
|
+
t("div", rt, [
|
|
43
|
+
r[1] || (r[1] = t("div", { class: "flex-1 fm-typo-en-body-md-600" }, "Recent campaigns", -1)),
|
|
44
|
+
p(f(Me), {
|
|
45
|
+
to: "/campaign",
|
|
46
|
+
class: "fm-typo-en-body-sm-600 text-fm-color-primary no-underline"
|
|
47
|
+
}, {
|
|
48
|
+
default: D(() => [...r[0] || (r[0] = [
|
|
49
|
+
te(" All campaigns ", -1)
|
|
50
|
+
])]),
|
|
51
|
+
_: 1
|
|
52
|
+
})
|
|
53
|
+
]),
|
|
54
|
+
e.loading ? (l(), u("div", st, " Loading campaigns. ")) : e.error ? (l(), u("div", ot, " Unable to load campaigns. ")) : e.campaigns.length ? (l(), u("div", at, [
|
|
55
|
+
(l(!0), u(F, null, B(e.campaigns, (s) => (l(), u("div", {
|
|
56
|
+
key: s.id,
|
|
57
|
+
class: "flex items-start gap-10 py-10 border-b border-fm-color-neutral-gray-100 last:border-b-0"
|
|
58
|
+
}, [
|
|
59
|
+
t("div", {
|
|
60
|
+
class: I(["w-7 h-7 rounded-full bg-current flex-shrink-0 mt-5", s.statusClass])
|
|
61
|
+
}, null, 2),
|
|
62
|
+
t("div", nt, [
|
|
63
|
+
t("div", it, d(s.name), 1),
|
|
64
|
+
t("div", lt, d(s.type), 1)
|
|
65
|
+
]),
|
|
66
|
+
t("div", dt, [
|
|
67
|
+
t("div", ct, d(s.metric), 1),
|
|
68
|
+
t("div", mt, d(s.metricLabel), 1)
|
|
69
|
+
])
|
|
70
|
+
]))), 128))
|
|
71
|
+
])) : (l(), u("div", ut, " No campaigns are available for this location. "))
|
|
72
|
+
]),
|
|
73
|
+
_: 1
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}), ft = { class: "flex items-center gap-8" }, bt = { class: "w-[30px] h-[30px] bg-fm-color-primary-oats flex items-center justify-center flex-shrink-0 fm-corner-radius-md" }, yt = { class: "bg-fm-color-primary-oats p-14 fm-corner-radius-md" }, vt = { class: "fm-typo-en-body-md-600 mb-6" }, gt = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary" }, ht = { class: "flex flex-col gap-6" }, xt = { class: "border-t border-fm-color-neutral-gray-100 pt-12 flex flex-col gap-3" }, _t = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary" }, wt = {
|
|
78
|
+
key: 1,
|
|
79
|
+
class: "bg-fm-color-neutral-gray-100 rounded-10 p-14 fm-typo-en-body-sm-400 text-fm-color-typo-secondary"
|
|
80
|
+
}, Mt = /* @__PURE__ */ L({
|
|
81
|
+
__name: "InsightPanel",
|
|
82
|
+
props: {
|
|
83
|
+
insight: {}
|
|
84
|
+
},
|
|
85
|
+
emits: ["navigate"],
|
|
86
|
+
setup(e, { emit: o }) {
|
|
87
|
+
const r = o;
|
|
88
|
+
return (n, s) => {
|
|
89
|
+
const i = _("FmIcon"), m = _("FmButton"), b = _("FmCard");
|
|
90
|
+
return l(), A(b, {
|
|
91
|
+
variant: "outlined",
|
|
92
|
+
class: "p-24 flex flex-col gap-14"
|
|
93
|
+
}, {
|
|
94
|
+
default: D(() => [
|
|
95
|
+
t("div", ft, [
|
|
96
|
+
t("div", bt, [
|
|
97
|
+
p(i, {
|
|
98
|
+
name: "info",
|
|
99
|
+
outline: "",
|
|
100
|
+
size: "sm",
|
|
101
|
+
class: "!text-fm-color-primary"
|
|
102
|
+
})
|
|
103
|
+
]),
|
|
104
|
+
s[1] || (s[1] = t("div", { class: "fm-typo-en-body-md-600" }, "Action insight", -1))
|
|
105
|
+
]),
|
|
106
|
+
e.insight ? (l(), u(F, { key: 0 }, [
|
|
107
|
+
t("div", yt, [
|
|
108
|
+
t("div", vt, d(e.insight.title), 1),
|
|
109
|
+
t("div", gt, d(e.insight.body), 1)
|
|
110
|
+
]),
|
|
111
|
+
t("div", ht, [
|
|
112
|
+
s[2] || (s[2] = t("div", { class: "fm-typo-en-body-sm-600 text-fm-color-typo-tertiary uppercase tracking-wide mb-1" }, " Suggested action ", -1)),
|
|
113
|
+
p(m, {
|
|
114
|
+
label: e.insight.action.label,
|
|
115
|
+
"append-icon": "arrow_forward",
|
|
116
|
+
class: "!justify-between",
|
|
117
|
+
onClick: s[0] || (s[0] = (y) => r("navigate", e.insight.action.path))
|
|
118
|
+
}, null, 8, ["label"])
|
|
119
|
+
]),
|
|
120
|
+
t("div", xt, [
|
|
121
|
+
s[3] || (s[3] = t("div", { class: "fm-typo-en-body-sm-600 text-fm-color-typo-tertiary uppercase tracking-wide mb-1" }, " Supporting signal ", -1)),
|
|
122
|
+
(l(!0), u(F, null, B(e.insight.signals, (y) => (l(), u("li", {
|
|
123
|
+
key: y.text,
|
|
124
|
+
class: "flex items-start gap-7"
|
|
125
|
+
}, [
|
|
126
|
+
t("ul", _t, d(y.text), 1)
|
|
127
|
+
]))), 128))
|
|
128
|
+
])
|
|
129
|
+
], 64)) : (l(), u("div", wt, " More member activity is needed before a clear action can be suggested. "))
|
|
130
|
+
]),
|
|
131
|
+
_: 1
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}), St = { class: "grid grid-cols-5 xs:grid-cols-2 gap-12" }, Rt = { class: "flex items-center gap-8" }, Ct = { class: "w-[30px] h-[30px] rounded-8 bg-[#FFF6EE] flex items-center justify-center flex-shrink-0" }, $t = { class: "fm-typo-en-body-sm-600 text-fm-color-typo-secondary flex-1 min-w-0" }, Ft = { class: "fm-typo-en-title-sm-800 text-fm-color-typo-primary whitespace-nowrap overflow-hidden text-ellipsis" }, Dt = {
|
|
136
|
+
key: 0,
|
|
137
|
+
class: "text-fm-color-typo-success fm-typo-en-body-sm-600 -mt-4"
|
|
138
|
+
}, kt = { class: "flex items-center gap-4 flex-wrap" }, Pt = /* @__PURE__ */ L({
|
|
139
|
+
__name: "KpiStrip",
|
|
140
|
+
props: {
|
|
141
|
+
kpis: {}
|
|
142
|
+
},
|
|
143
|
+
setup(e) {
|
|
144
|
+
return (o, r) => {
|
|
145
|
+
const n = _("FmIcon"), s = _("FmCard");
|
|
146
|
+
return l(), u("section", St, [
|
|
147
|
+
(l(!0), u(F, null, B(e.kpis, (i) => (l(), A(s, {
|
|
148
|
+
key: i.label,
|
|
149
|
+
variant: "outlined",
|
|
150
|
+
class: "flex flex-col gap-8 p-16 min-w-0 overflow-hidden"
|
|
151
|
+
}, {
|
|
152
|
+
default: D(() => [
|
|
153
|
+
t("div", Rt, [
|
|
154
|
+
t("div", Ct, [
|
|
155
|
+
p(n, {
|
|
156
|
+
name: i.icon,
|
|
157
|
+
outline: "",
|
|
158
|
+
size: "sm",
|
|
159
|
+
class: "!text-fm-color-primary"
|
|
160
|
+
}, null, 8, ["name"])
|
|
161
|
+
]),
|
|
162
|
+
t("span", $t, d(i.label), 1),
|
|
163
|
+
p(T, {
|
|
164
|
+
description: i.description
|
|
165
|
+
}, null, 8, ["description"])
|
|
166
|
+
]),
|
|
167
|
+
t("div", Ft, d(i.value), 1),
|
|
168
|
+
i.sub ? (l(), u("div", Dt, d(i.sub), 1)) : U("", !0),
|
|
169
|
+
t("div", kt, [
|
|
170
|
+
i.delta !== "0%" && i.delta !== "0pp" ? (l(), A(n, {
|
|
171
|
+
key: 0,
|
|
172
|
+
name: i.trendUp ? "trending_up" : "trending_down",
|
|
173
|
+
size: "xs",
|
|
174
|
+
class: I(i.deltaClass)
|
|
175
|
+
}, null, 8, ["name", "class"])) : U("", !0),
|
|
176
|
+
t("span", {
|
|
177
|
+
class: I(["fm-typo-en-body-sm-600", i.deltaClass])
|
|
178
|
+
}, d(i.delta), 3),
|
|
179
|
+
r[0] || (r[0] = t("span", { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary" }, "vs prev", -1))
|
|
180
|
+
])
|
|
181
|
+
]),
|
|
182
|
+
_: 2
|
|
183
|
+
}, 1024))), 128))
|
|
184
|
+
]);
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}), At = { class: "flex flex-col gap-4" }, It = ["onClick"], Lt = { class: "fm-typo-en-body-sm-600" }, Ot = { class: "fm-typo-en-body-md-600 min-w-[38px] text-right" }, Bt = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary min-w-[34px] text-right" }, Tt = { class: "mt-14 pt-12 border-t border-fm-color-neutral-gray-100 fm-typo-en-body-sm-400 text-fm-color-typo-secondary" }, Nt = /* @__PURE__ */ L({
|
|
188
|
+
__name: "LifecycleSegments",
|
|
189
|
+
props: {
|
|
190
|
+
segments: {},
|
|
191
|
+
summary: {},
|
|
192
|
+
interactive: { type: Boolean, default: !0 }
|
|
193
|
+
},
|
|
194
|
+
emits: ["select"],
|
|
195
|
+
setup(e, { emit: o }) {
|
|
196
|
+
const r = e, n = o;
|
|
197
|
+
return (s, i) => {
|
|
198
|
+
const m = _("FmProgressBar"), b = _("FmCard");
|
|
199
|
+
return l(), A(b, {
|
|
200
|
+
variant: "outlined",
|
|
201
|
+
class: "p-24"
|
|
202
|
+
}, {
|
|
203
|
+
default: D(() => [
|
|
204
|
+
i[0] || (i[0] = t("div", { class: "flex items-center mb-16" }, [
|
|
205
|
+
t("div", { class: "flex-1 fm-typo-en-body-md-600" }, "Member lifecycle")
|
|
206
|
+
], -1)),
|
|
207
|
+
t("div", At, [
|
|
208
|
+
(l(!0), u(F, null, B(r.segments, (y) => (l(), u("div", {
|
|
209
|
+
key: y.id,
|
|
210
|
+
class: I([
|
|
211
|
+
"flex items-center gap-9 px-6 py-3 -mx-6 rounded-8",
|
|
212
|
+
r.interactive ? "cursor-pointer hover:bg-fm-color-neutral-gray-100/50" : "cursor-default"
|
|
213
|
+
]),
|
|
214
|
+
onClick: (v) => r.interactive && n("select", y.id)
|
|
215
|
+
}, [
|
|
216
|
+
t("div", {
|
|
217
|
+
class: I(["flex w-[90px] flex-shrink-0 items-center gap-3", y.labelClass])
|
|
218
|
+
}, [
|
|
219
|
+
t("span", Lt, d(y.label), 1),
|
|
220
|
+
p(T, {
|
|
221
|
+
description: y.description
|
|
222
|
+
}, null, 8, ["description"])
|
|
223
|
+
], 2),
|
|
224
|
+
p(m, {
|
|
225
|
+
class: "flex-1",
|
|
226
|
+
value: y.barPct,
|
|
227
|
+
color: y.barColor,
|
|
228
|
+
size: "lg"
|
|
229
|
+
}, null, 8, ["value", "color"]),
|
|
230
|
+
t("span", Ot, d(y.countStr), 1),
|
|
231
|
+
t("span", Bt, d(y.pctStr), 1)
|
|
232
|
+
], 10, It))), 128))
|
|
233
|
+
]),
|
|
234
|
+
t("div", Tt, d(r.summary), 1)
|
|
235
|
+
]),
|
|
236
|
+
_: 1
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}), Et = { class: "flex items-start gap-8 mb-12" }, Ut = { class: "flex-1" }, Vt = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary mt-4" }, Ht = {
|
|
241
|
+
key: 0,
|
|
242
|
+
class: "flex items-start pl-[152px] xs:pl-0 xs:justify-center"
|
|
243
|
+
}, zt = { class: "flex flex-col items-start" }, qt = { class: "flex items-center gap-8" }, Yt = {
|
|
244
|
+
key: 0,
|
|
245
|
+
class: "fm-typo-en-body-sm-600 text-fm-color-typo-warning bg-fm-color-system-warning-100 px-8 py-[2px] rounded-xxxl whitespace-nowrap"
|
|
246
|
+
}, jt = ["onClick"], Gt = { class: "min-w-0" }, Jt = { class: "flex items-center gap-3 fm-typo-en-body-sm-600" }, Kt = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary mt-4" }, Wt = { class: "min-w-0 text-right" }, Qt = { class: "fm-typo-en-body-lg-600" }, Xt = {
|
|
247
|
+
key: 0,
|
|
248
|
+
class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary"
|
|
249
|
+
}, Zt = { class: "mt-12 pt-12 border-t border-fm-color-neutral-gray-100" }, er = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary text-right" }, tr = /* @__PURE__ */ L({
|
|
250
|
+
__name: "MemberFunnel",
|
|
251
|
+
props: {
|
|
252
|
+
stages: {},
|
|
253
|
+
footnote: {},
|
|
254
|
+
interactive: { type: Boolean, default: !0 }
|
|
255
|
+
},
|
|
256
|
+
emits: ["select"],
|
|
257
|
+
setup(e, { emit: o }) {
|
|
258
|
+
const r = e, n = o;
|
|
259
|
+
function s(i) {
|
|
260
|
+
r.interactive && n("select", i);
|
|
261
|
+
}
|
|
262
|
+
return (i, m) => {
|
|
263
|
+
const b = _("FmProgressBar"), y = _("FmCard");
|
|
264
|
+
return l(), A(y, {
|
|
265
|
+
variant: "outlined",
|
|
266
|
+
class: "p-24"
|
|
267
|
+
}, {
|
|
268
|
+
default: D(() => [
|
|
269
|
+
t("div", Et, [
|
|
270
|
+
t("div", Ut, [
|
|
271
|
+
m[0] || (m[0] = t("div", { class: "fm-typo-en-body-md-600" }, "Member funnel", -1)),
|
|
272
|
+
t("div", Vt, d(r.interactive ? "Strict member-only · visitors excluded · click any stage to drill down" : "Strict member-only · visitors excluded"), 1)
|
|
273
|
+
])
|
|
274
|
+
]),
|
|
275
|
+
(l(!0), u(F, null, B(e.stages, (v, M) => (l(), u("div", {
|
|
276
|
+
key: v.id
|
|
277
|
+
}, [
|
|
278
|
+
v.hasDropLine ? (l(), u("div", Ht, [
|
|
279
|
+
t("div", zt, [
|
|
280
|
+
m[1] || (m[1] = t("div", { class: "w-[1px] h-[4px] bg-fm-color-neutral-gray-100 ml-[9px]" }, null, -1)),
|
|
281
|
+
t("div", qt, [
|
|
282
|
+
t("span", {
|
|
283
|
+
class: I(["fm-typo-en-body-sm-600 px-8 py-[2px] rounded-xxxl whitespace-nowrap", v.dropClass])
|
|
284
|
+
}, d(v.conversionStr), 3),
|
|
285
|
+
v.isBiggestDrop ? (l(), u("span", Yt, " biggest drop ")) : U("", !0)
|
|
286
|
+
]),
|
|
287
|
+
m[2] || (m[2] = t("div", { class: "w-[1px] h-[4px] bg-fm-color-neutral-gray-100 ml-[9px]" }, null, -1))
|
|
288
|
+
])
|
|
289
|
+
])) : U("", !0),
|
|
290
|
+
t("div", {
|
|
291
|
+
class: I([
|
|
292
|
+
"grid grid-cols-[140px_minmax(0,1fr)_72px] xs:grid-cols-[minmax(0,1fr)_auto] items-center gap-x-12 gap-y-8 py-4 px-8 -mx-8 rounded-md",
|
|
293
|
+
r.interactive ? "cursor-pointer hover:bg-fm-color-neutral-gray-100/50" : ""
|
|
294
|
+
]),
|
|
295
|
+
onClick: (S) => s(v.id)
|
|
296
|
+
}, [
|
|
297
|
+
t("div", Gt, [
|
|
298
|
+
t("div", Jt, [
|
|
299
|
+
t("span", null, d(v.label), 1),
|
|
300
|
+
p(T, {
|
|
301
|
+
description: v.description
|
|
302
|
+
}, null, 8, ["description"])
|
|
303
|
+
]),
|
|
304
|
+
t("div", Kt, d(v.desc), 1)
|
|
305
|
+
]),
|
|
306
|
+
p(b, {
|
|
307
|
+
class: "min-w-0 xs:col-span-2 xs:row-start-2",
|
|
308
|
+
value: v.barWidthPct,
|
|
309
|
+
color: v.barColor,
|
|
310
|
+
size: "lg"
|
|
311
|
+
}, null, 8, ["value", "color"]),
|
|
312
|
+
t("div", Wt, [
|
|
313
|
+
t("div", Qt, d(v.countStr), 1),
|
|
314
|
+
v.hasConvRate ? (l(), u("div", Xt, d(v.convRateLabel), 1)) : U("", !0)
|
|
315
|
+
])
|
|
316
|
+
], 10, jt)
|
|
317
|
+
]))), 128)),
|
|
318
|
+
t("div", Zt, [
|
|
319
|
+
t("div", er, d(e.footnote), 1)
|
|
320
|
+
])
|
|
321
|
+
]),
|
|
322
|
+
_: 1
|
|
323
|
+
});
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}), rr = { class: "flex items-center gap-3 fm-typo-en-body-md-600 mb-4" }, sr = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary mb-16" }, or = { class: "grid grid-cols-2 xs:grid-cols-1 gap-16" }, ar = { class: "fm-typo-en-title-sm-800" }, nr = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary mt-4" }, ir = { class: "fm-typo-en-title-sm-800" }, lr = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary mt-4" }, dr = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary mt-8" }, cr = { class: "mt-16 pt-12 border-t border-fm-color-neutral-gray-100 fm-typo-en-body-sm-400" }, mr = /* @__PURE__ */ L({
|
|
327
|
+
__name: "MemberSpendComparison",
|
|
328
|
+
props: {
|
|
329
|
+
spend: {}
|
|
330
|
+
},
|
|
331
|
+
setup(e) {
|
|
332
|
+
return (o, r) => {
|
|
333
|
+
const n = _("FmProgressBar"), s = _("FmCard");
|
|
334
|
+
return l(), A(s, {
|
|
335
|
+
variant: "outlined",
|
|
336
|
+
class: "p-24"
|
|
337
|
+
}, {
|
|
338
|
+
default: D(() => [
|
|
339
|
+
t("div", rr, [
|
|
340
|
+
r[0] || (r[0] = t("span", null, "Member vs. non-member spend", -1)),
|
|
341
|
+
p(T, {
|
|
342
|
+
description: e.spend.description
|
|
343
|
+
}, null, 8, ["description"])
|
|
344
|
+
]),
|
|
345
|
+
t("div", sr, d(e.spend.description), 1),
|
|
346
|
+
t("div", or, [
|
|
347
|
+
t("div", null, [
|
|
348
|
+
r[1] || (r[1] = t("div", { class: "flex items-center gap-8 mb-8" }, [
|
|
349
|
+
t("div", { class: "w-8 h-8 rounded-sm bg-fm-color-primary" }),
|
|
350
|
+
t("span", { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary" }, "Member sales")
|
|
351
|
+
], -1)),
|
|
352
|
+
t("div", ar, d(e.spend.memberSalesFmt), 1),
|
|
353
|
+
t("div", nr, " avg " + d(e.spend.avgMemberSaleFmt) + " / order ", 1)
|
|
354
|
+
]),
|
|
355
|
+
t("div", null, [
|
|
356
|
+
r[2] || (r[2] = t("div", { class: "flex items-center gap-8 mb-8" }, [
|
|
357
|
+
t("div", { class: "w-8 h-8 rounded-sm bg-fm-color-neutral-gray-200" }),
|
|
358
|
+
t("span", { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary" }, "Non-member sales")
|
|
359
|
+
], -1)),
|
|
360
|
+
t("div", ir, d(e.spend.nonMemberSalesFmt), 1),
|
|
361
|
+
t("div", lr, " avg " + d(e.spend.avgNonMemberSaleFmt) + " / order ", 1)
|
|
362
|
+
])
|
|
363
|
+
]),
|
|
364
|
+
p(n, {
|
|
365
|
+
class: "mt-16",
|
|
366
|
+
value: e.spend.memberSharePct,
|
|
367
|
+
color: "primary",
|
|
368
|
+
size: "md"
|
|
369
|
+
}, null, 8, ["value"]),
|
|
370
|
+
t("div", dr, " Members drive " + d(e.spend.memberSharePct) + "% of tracked sales ", 1),
|
|
371
|
+
t("div", cr, d(e.spend.summary), 1)
|
|
372
|
+
]),
|
|
373
|
+
_: 1
|
|
374
|
+
});
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
}), ur = { class: "flex items-center mb-16" }, pr = {
|
|
378
|
+
key: 0,
|
|
379
|
+
class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary"
|
|
380
|
+
}, fr = {
|
|
381
|
+
key: 1,
|
|
382
|
+
class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary"
|
|
383
|
+
}, br = { class: "grid grid-cols-3 gap-10 mb-16" }, yr = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary mb-4 flex items-center gap-3" }, vr = { class: "fm-typo-en-title-sm-800" }, gr = { class: "flex flex-col gap-9" }, hr = { class: "flex-1 fm-typo-en-body-sm-400 whitespace-nowrap overflow-hidden text-ellipsis" }, xr = { class: "flex flex-shrink-0 items-center gap-3 fm-typo-en-body-sm-600 text-fm-color-typo-secondary" }, _r = { class: "w-[48px] h-4 bg-fm-color-neutral-gray-100 rounded-2 overflow-hidden flex-shrink-0" }, wr = {
|
|
384
|
+
key: 3,
|
|
385
|
+
class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary"
|
|
386
|
+
}, Mr = /* @__PURE__ */ L({
|
|
387
|
+
__name: "RewardPerformance",
|
|
388
|
+
props: {
|
|
389
|
+
kpis: {},
|
|
390
|
+
topRewards: {},
|
|
391
|
+
hasData: { type: Boolean },
|
|
392
|
+
loading: { type: Boolean },
|
|
393
|
+
error: { type: Boolean }
|
|
394
|
+
},
|
|
395
|
+
setup(e) {
|
|
396
|
+
return (o, r) => {
|
|
397
|
+
const n = _("FmCard");
|
|
398
|
+
return l(), A(n, {
|
|
399
|
+
variant: "outlined",
|
|
400
|
+
class: "p-24"
|
|
401
|
+
}, {
|
|
402
|
+
default: D(() => [
|
|
403
|
+
t("div", ur, [
|
|
404
|
+
r[1] || (r[1] = t("div", { class: "flex-1 fm-typo-en-body-md-600" }, "Reward usage health", -1)),
|
|
405
|
+
p(f(Me), {
|
|
406
|
+
to: "/reward",
|
|
407
|
+
class: "fm-typo-en-body-sm-600 text-fm-color-primary no-underline"
|
|
408
|
+
}, {
|
|
409
|
+
default: D(() => [...r[0] || (r[0] = [
|
|
410
|
+
te(" All rewards ", -1)
|
|
411
|
+
])]),
|
|
412
|
+
_: 1
|
|
413
|
+
})
|
|
414
|
+
]),
|
|
415
|
+
e.loading ? (l(), u("div", pr, " Loading reward usage data. ")) : e.error ? (l(), u("div", fr, " Unable to load reward usage data. ")) : e.hasData ? (l(), u(F, { key: 2 }, [
|
|
416
|
+
t("div", br, [
|
|
417
|
+
(l(!0), u(F, null, B(e.kpis, (s) => (l(), u("div", {
|
|
418
|
+
key: s.label,
|
|
419
|
+
class: "bg-[#FAFAFA] rounded-10 p-12"
|
|
420
|
+
}, [
|
|
421
|
+
t("div", yr, [
|
|
422
|
+
t("span", null, d(s.label), 1),
|
|
423
|
+
p(T, {
|
|
424
|
+
description: s.description
|
|
425
|
+
}, null, 8, ["description"])
|
|
426
|
+
]),
|
|
427
|
+
t("div", vr, d(s.value), 1),
|
|
428
|
+
s.delta ? (l(), u("div", {
|
|
429
|
+
key: 0,
|
|
430
|
+
class: I(["fm-typo-en-body-sm-600 mt-3", s.deltaClass])
|
|
431
|
+
}, d(s.delta), 3)) : U("", !0)
|
|
432
|
+
]))), 128))
|
|
433
|
+
]),
|
|
434
|
+
r[3] || (r[3] = t("div", { class: "fm-typo-en-body-sm-600 text-fm-color-typo-tertiary uppercase tracking-wide mb-10" }, " Top used rewards ", -1)),
|
|
435
|
+
t("div", gr, [
|
|
436
|
+
(l(!0), u(F, null, B(e.topRewards, (s) => (l(), u("div", {
|
|
437
|
+
key: s.name,
|
|
438
|
+
class: "flex items-center gap-9"
|
|
439
|
+
}, [
|
|
440
|
+
r[2] || (r[2] = t("div", { class: "w-6 h-6 rounded-2 bg-fm-color-primary flex-shrink-0" }, null, -1)),
|
|
441
|
+
t("span", hr, d(s.name), 1),
|
|
442
|
+
t("span", xr, [
|
|
443
|
+
te(d(s.count) + " ", 1),
|
|
444
|
+
p(T, {
|
|
445
|
+
description: s.description
|
|
446
|
+
}, null, 8, ["description"])
|
|
447
|
+
]),
|
|
448
|
+
t("div", _r, [
|
|
449
|
+
t("div", {
|
|
450
|
+
class: "h-full bg-fm-color-primary rounded-2",
|
|
451
|
+
style: ze({ width: s.barPct + "%" })
|
|
452
|
+
}, null, 4)
|
|
453
|
+
])
|
|
454
|
+
]))), 128))
|
|
455
|
+
])
|
|
456
|
+
], 64)) : (l(), u("div", wr, " No reward usage data is available for this period. "))
|
|
457
|
+
]),
|
|
458
|
+
_: 1
|
|
459
|
+
});
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
}), Sr = { class: "mb-6 flex items-center gap-3 fm-typo-en-body-md-600" }, Rr = { class: "flex items-baseline gap-10 mb-14 flex-wrap" }, Cr = { class: "fm-typo-en-title-lg-800" }, $r = /* @__PURE__ */ L({
|
|
463
|
+
__name: "SalesTrendChart",
|
|
464
|
+
props: {
|
|
465
|
+
sales: {}
|
|
466
|
+
},
|
|
467
|
+
setup(e) {
|
|
468
|
+
const o = e, r = w(() => [
|
|
469
|
+
{
|
|
470
|
+
label: "This period",
|
|
471
|
+
data: o.sales.series,
|
|
472
|
+
color: "#FF7823",
|
|
473
|
+
fill: !0
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
label: "Prev. period",
|
|
477
|
+
data: o.sales.prevSeries,
|
|
478
|
+
color: "#B2B3B6",
|
|
479
|
+
dash: !0
|
|
480
|
+
}
|
|
481
|
+
]), n = { display: !1 };
|
|
482
|
+
return (s, i) => {
|
|
483
|
+
const m = _("FmLineChart"), b = _("FmCard");
|
|
484
|
+
return l(), A(b, {
|
|
485
|
+
variant: "outlined",
|
|
486
|
+
class: "p-24"
|
|
487
|
+
}, {
|
|
488
|
+
default: D(() => [
|
|
489
|
+
t("div", Sr, [
|
|
490
|
+
i[0] || (i[0] = t("span", null, "Member sales trend", -1)),
|
|
491
|
+
p(T, {
|
|
492
|
+
description: e.sales.description
|
|
493
|
+
}, null, 8, ["description"])
|
|
494
|
+
]),
|
|
495
|
+
t("div", Rr, [
|
|
496
|
+
t("span", Cr, d(e.sales.totalFmt), 1),
|
|
497
|
+
t("span", {
|
|
498
|
+
class: I(["fm-typo-en-body-sm-600 px-9 py-3 rounded-full whitespace-nowrap", e.sales.deltaClass])
|
|
499
|
+
}, d(e.sales.deltaStr), 3),
|
|
500
|
+
i[1] || (i[1] = t("span", { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary" }, "vs prev. period", -1))
|
|
501
|
+
]),
|
|
502
|
+
p(m, {
|
|
503
|
+
datasets: f(r),
|
|
504
|
+
"x-axis": { categories: e.sales.comparisonCategories },
|
|
505
|
+
"x-cfg": n,
|
|
506
|
+
"y-cfg": n,
|
|
507
|
+
legend: { display: !1 },
|
|
508
|
+
height: "80px"
|
|
509
|
+
}, null, 8, ["datasets", "x-axis"]),
|
|
510
|
+
i[2] || (i[2] = t("div", { class: "flex items-center gap-14 mt-10" }, [
|
|
511
|
+
t("div", { class: "flex items-center gap-5" }, [
|
|
512
|
+
t("div", { class: "w-14 h-2 bg-fm-color-primary rounded-1" }),
|
|
513
|
+
t("span", { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary" }, "This period")
|
|
514
|
+
]),
|
|
515
|
+
t("div", { class: "flex items-center gap-5" }, [
|
|
516
|
+
t("div", { class: "w-14 border-t-[1.5px] border-dashed border-fm-color-neutral-gray-200" }),
|
|
517
|
+
t("span", { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary" }, "Prev. period")
|
|
518
|
+
])
|
|
519
|
+
], -1))
|
|
520
|
+
]),
|
|
521
|
+
_: 1
|
|
522
|
+
});
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
}), C = () => {
|
|
526
|
+
const e = je.getBusinessId();
|
|
527
|
+
if (!e) throw new Error("Invalid business ID");
|
|
528
|
+
return Ge(`businesses/${e}/loyalty-dashboard`, {
|
|
529
|
+
noIdRequired: !0
|
|
530
|
+
});
|
|
531
|
+
}, $ = {
|
|
532
|
+
async readTotalMembers(e) {
|
|
533
|
+
return R(
|
|
534
|
+
await C().post(
|
|
535
|
+
"metrics/total-members",
|
|
536
|
+
e
|
|
537
|
+
)
|
|
538
|
+
);
|
|
539
|
+
},
|
|
540
|
+
async readActiveMembers(e) {
|
|
541
|
+
return R(
|
|
542
|
+
await C().post(
|
|
543
|
+
"metrics/active-members",
|
|
544
|
+
e
|
|
545
|
+
)
|
|
546
|
+
);
|
|
547
|
+
},
|
|
548
|
+
async readMemberSales(e) {
|
|
549
|
+
return R(
|
|
550
|
+
await C().post("metrics/member-sales", e)
|
|
551
|
+
);
|
|
552
|
+
},
|
|
553
|
+
async readMemberSpendComparison(e) {
|
|
554
|
+
return R(
|
|
555
|
+
await C().post(
|
|
556
|
+
"metrics/member-spend-comparison",
|
|
557
|
+
e
|
|
558
|
+
)
|
|
559
|
+
);
|
|
560
|
+
},
|
|
561
|
+
async readMemberSalesTrend(e) {
|
|
562
|
+
return R(
|
|
563
|
+
await C().post(
|
|
564
|
+
"metrics/member-sales-trend",
|
|
565
|
+
e
|
|
566
|
+
)
|
|
567
|
+
);
|
|
568
|
+
},
|
|
569
|
+
async readRepeatRate(e) {
|
|
570
|
+
return R(
|
|
571
|
+
await C().post("metrics/repeat-rate", e)
|
|
572
|
+
);
|
|
573
|
+
},
|
|
574
|
+
async readVoucherRedemptionRate(e) {
|
|
575
|
+
return R(
|
|
576
|
+
await C().post(
|
|
577
|
+
"metrics/voucher-redemption-rate",
|
|
578
|
+
e
|
|
579
|
+
)
|
|
580
|
+
);
|
|
581
|
+
},
|
|
582
|
+
async readMemberFunnel(e) {
|
|
583
|
+
return R(
|
|
584
|
+
await C().post(
|
|
585
|
+
"metrics/member-funnel",
|
|
586
|
+
e
|
|
587
|
+
)
|
|
588
|
+
);
|
|
589
|
+
},
|
|
590
|
+
async readMemberLifecycle(e) {
|
|
591
|
+
return R(
|
|
592
|
+
await C().post(
|
|
593
|
+
"metrics/member-lifecycle",
|
|
594
|
+
e
|
|
595
|
+
)
|
|
596
|
+
);
|
|
597
|
+
},
|
|
598
|
+
async readRewardUsageHealth(e) {
|
|
599
|
+
return R(
|
|
600
|
+
await C().post(
|
|
601
|
+
"metrics/reward-usage-health",
|
|
602
|
+
e
|
|
603
|
+
)
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
}, g = {
|
|
607
|
+
totalMembers: "Distinct members recorded through the end of the selected period; the start date does not reduce this total.",
|
|
608
|
+
activeMembers: "Distinct members with a completed member purchase or voucher redemption during the selected period.",
|
|
609
|
+
memberSales: "Sum of nettTotal from member-linked bills included in the selected period.",
|
|
610
|
+
repeatRate: "Repeat members divided by purchase members. Repeat members have purchase history before the selected period.",
|
|
611
|
+
voucherRedemptionRate: "Repeat members who redeemed a voucher divided by repeat members.",
|
|
612
|
+
purchasingMembers: "Distinct members with at least one completed member bill in the selected period.",
|
|
613
|
+
repeatMembers: "Purchase members who also had purchase history before the selected period.",
|
|
614
|
+
funnelRewardRedeemers: "Repeat members with counted reward activity in the selected period.",
|
|
615
|
+
newlyJoined: "Members whose join date falls within the selected period.",
|
|
616
|
+
frequent: "Existing members with at least two completed member bills in the selected period.",
|
|
617
|
+
infrequent: "Existing members with exactly one completed member bill in the selected period.",
|
|
618
|
+
atRisk: "Existing members with no selected-period purchase but a completed purchase in the prior 60 calendar days.",
|
|
619
|
+
dormant: "Existing members with no selected-period purchase and no completed purchase in the prior 60 calendar days.",
|
|
620
|
+
memberSalesTrend: "Daily member nett sales for the selected period compared with the selected comparison period.",
|
|
621
|
+
rewardRedeemers: "Distinct members who used a counted VOUCHER, CREDIT, or COIN reward during the selected period; anonymous usage is excluded from the member count.",
|
|
622
|
+
redemptionRate: "Reward redeemers divided by active members, where active members are members with purchase or reward activity during the selected period.",
|
|
623
|
+
averageRewardUses: "Counted reward-use transactions divided by distinct reward redeemers.",
|
|
624
|
+
memberSpendComparison: "Shows the value members bring — use it to make the case for growing membership"
|
|
625
|
+
};
|
|
626
|
+
function Fr(e, o, r = /* @__PURE__ */ new Date()) {
|
|
627
|
+
const n = V.tz(r, o).endOf("day"), s = n.clone().startOf("day");
|
|
628
|
+
return s.startOf("month"), [s.toISOString(), n.toISOString()];
|
|
629
|
+
}
|
|
630
|
+
function Dr(e, o) {
|
|
631
|
+
return e.length ? e : o;
|
|
632
|
+
}
|
|
633
|
+
function kr(e) {
|
|
634
|
+
return {
|
|
635
|
+
dateRange: e.dateRange,
|
|
636
|
+
compareDateRange: e.compareDateRange,
|
|
637
|
+
restaurantIds: Dr(
|
|
638
|
+
e.selectedLocationIds,
|
|
639
|
+
e.locationIds
|
|
640
|
+
),
|
|
641
|
+
timezone: e.timezone
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
function we(e) {
|
|
645
|
+
const [o, r] = e, n = V(r).diff(V(o)), s = V(o).subtract(1, "millisecond");
|
|
646
|
+
return [s.clone().subtract(n, "milliseconds").toISOString(), s.toISOString()];
|
|
647
|
+
}
|
|
648
|
+
const J = (e) => ({
|
|
649
|
+
total: 0,
|
|
650
|
+
totalNew: 0,
|
|
651
|
+
totalPrev: 0,
|
|
652
|
+
active: 0,
|
|
653
|
+
activePrev: 0,
|
|
654
|
+
purchasing: 0,
|
|
655
|
+
purchasingPrev: 0,
|
|
656
|
+
repeat: 0,
|
|
657
|
+
repeatPrev: 0,
|
|
658
|
+
redeemers: 0,
|
|
659
|
+
redeemersPrev: 0,
|
|
660
|
+
memberSales: 0,
|
|
661
|
+
memberSalesPrev: 0,
|
|
662
|
+
series: Array(e).fill(0),
|
|
663
|
+
prev: Array(e).fill(0)
|
|
664
|
+
});
|
|
665
|
+
J(20), J(7), J(30), J(12);
|
|
666
|
+
const re = (e, o) => o ? Math.round(e / o * 1e3) / 10 : 0, Pr = (e, o) => o ? Math.round((e - o) / o * 1e3) / 10 : 0, H = (e) => e >= 1e3 ? (e / 1e3).toFixed(1).replace(/\.0$/, "") + "k" : String(e), O = (e, o) => tt(e).set({ currency: o }).toFormat(!0), Ar = [
|
|
667
|
+
"neutral-black",
|
|
668
|
+
"primary",
|
|
669
|
+
"#FF9C52",
|
|
670
|
+
"#FFB577",
|
|
671
|
+
"#FFD0A3"
|
|
672
|
+
], se = {
|
|
673
|
+
text: "text-fm-color-typo-success",
|
|
674
|
+
bg: "bg-fm-color-system-success-100"
|
|
675
|
+
}, Se = {
|
|
676
|
+
text: "text-fm-color-typo-error",
|
|
677
|
+
bg: "bg-fm-color-system-error-100"
|
|
678
|
+
}, oe = {
|
|
679
|
+
text: "text-fm-color-typo-warning",
|
|
680
|
+
bg: "bg-fm-color-system-warning-100"
|
|
681
|
+
};
|
|
682
|
+
function Ir(e) {
|
|
683
|
+
return e === 0 ? "text-fm-color-typo-secondary" : e > 0 ? se.text : Se.text;
|
|
684
|
+
}
|
|
685
|
+
function Lr(e) {
|
|
686
|
+
const o = [
|
|
687
|
+
{
|
|
688
|
+
id: "total",
|
|
689
|
+
label: "Total members",
|
|
690
|
+
count: e.totalMembers,
|
|
691
|
+
desc: "All members through period end",
|
|
692
|
+
description: g.totalMembers,
|
|
693
|
+
denom: null
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
id: "active",
|
|
697
|
+
label: "Active members",
|
|
698
|
+
count: e.activeMembers,
|
|
699
|
+
desc: "Purchase or reward activity",
|
|
700
|
+
description: g.activeMembers,
|
|
701
|
+
denom: e.totalMembers
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
id: "purchasing",
|
|
705
|
+
label: "Purchase members",
|
|
706
|
+
count: e.purchasingMembers,
|
|
707
|
+
desc: "At least 1 completed order",
|
|
708
|
+
description: g.purchasingMembers,
|
|
709
|
+
denom: e.activeMembers
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
id: "repeat",
|
|
713
|
+
label: "Repeat members",
|
|
714
|
+
count: e.repeatMembers,
|
|
715
|
+
desc: "Had prior order history",
|
|
716
|
+
description: g.repeatMembers,
|
|
717
|
+
denom: e.purchasingMembers
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
id: "redeemers",
|
|
721
|
+
label: "Reward redeemers",
|
|
722
|
+
count: e.rewardRedeemers,
|
|
723
|
+
desc: "Repeat member used reward",
|
|
724
|
+
description: g.funnelRewardRedeemers,
|
|
725
|
+
denom: e.repeatMembers
|
|
726
|
+
}
|
|
727
|
+
], r = o.map(
|
|
728
|
+
(m, b) => b === 0 || !m.denom ? null : re(m.count, m.denom)
|
|
729
|
+
);
|
|
730
|
+
let n = null, s = 100;
|
|
731
|
+
return e.totalMembers > 0 && r.forEach((m, b) => {
|
|
732
|
+
b > 0 && m !== null && m < s && (s = m, n = b);
|
|
733
|
+
}), {
|
|
734
|
+
funnelStages: o.map((m, b) => {
|
|
735
|
+
const y = r[b], v = b === n;
|
|
736
|
+
return {
|
|
737
|
+
id: m.id,
|
|
738
|
+
label: m.label,
|
|
739
|
+
desc: m.desc,
|
|
740
|
+
description: m.description,
|
|
741
|
+
countStr: H(m.count),
|
|
742
|
+
conversionStr: y != null ? `${y}% convert` : "",
|
|
743
|
+
convRateLabel: y != null ? `${y}% of prev` : "",
|
|
744
|
+
hasConvRate: b > 0,
|
|
745
|
+
hasDropLine: b > 0,
|
|
746
|
+
isBiggestDrop: v,
|
|
747
|
+
barColor: Ar[b] ?? "#FFD0A3",
|
|
748
|
+
barWidthPct: e.totalMembers > 0 && m.count > 0 ? Math.max(re(m.count, e.totalMembers), 1) : 0,
|
|
749
|
+
dropClass: v ? `${oe.text} bg-[#FFF0E2]` : "text-fm-color-typo-secondary bg-fm-color-neutral-gray-100"
|
|
750
|
+
};
|
|
751
|
+
}),
|
|
752
|
+
funnelFootnote: `${e.totalMembers.toLocaleString()} total members`,
|
|
753
|
+
convRates: r,
|
|
754
|
+
biggestDropIdx: n
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
function Or(e) {
|
|
758
|
+
const { funnelStages: o, funnelFootnote: r } = Lr(e);
|
|
759
|
+
return { funnelStages: o, funnelFootnote: r };
|
|
760
|
+
}
|
|
761
|
+
const Br = 10;
|
|
762
|
+
function Tr(e) {
|
|
763
|
+
const o = [
|
|
764
|
+
{
|
|
765
|
+
source: e.totalMembers,
|
|
766
|
+
target: e.activeMembers,
|
|
767
|
+
title: "Many members are not active",
|
|
768
|
+
body: "Members who joined may benefit from a reactivation campaign.",
|
|
769
|
+
action: {
|
|
770
|
+
label: "Create reactivation campaign",
|
|
771
|
+
path: "/campaign/promotion"
|
|
772
|
+
}
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
source: e.activeMembers,
|
|
776
|
+
target: e.purchasingMembers,
|
|
777
|
+
title: "Active members are not purchasing",
|
|
778
|
+
body: "Active members may benefit from a review of purchase incentives.",
|
|
779
|
+
action: {
|
|
780
|
+
label: "Review purchase incentives",
|
|
781
|
+
path: "/campaign/promotion"
|
|
782
|
+
}
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
source: e.purchasingMembers,
|
|
786
|
+
target: e.repeatMembers,
|
|
787
|
+
title: "Members are not returning after a purchase",
|
|
788
|
+
body: "Members who purchase once may benefit from a retention campaign.",
|
|
789
|
+
action: {
|
|
790
|
+
label: "Create retention campaign",
|
|
791
|
+
path: "/campaign/promotion"
|
|
792
|
+
}
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
source: e.repeatMembers,
|
|
796
|
+
target: e.rewardRedeemers,
|
|
797
|
+
title: "Repeat members are not using rewards",
|
|
798
|
+
body: "Repeat members may benefit from a review of reward setup.",
|
|
799
|
+
action: {
|
|
800
|
+
label: "Review reward setup",
|
|
801
|
+
path: "/reward"
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
];
|
|
805
|
+
let r = null;
|
|
806
|
+
for (const s of o)
|
|
807
|
+
s.source < Br || s.target >= s.source || (!r || s.target / s.source < r.target / r.source) && (r = s);
|
|
808
|
+
if (!r) return null;
|
|
809
|
+
const n = Math.round(r.target / r.source * 1e3) / 10;
|
|
810
|
+
return {
|
|
811
|
+
title: r.title,
|
|
812
|
+
body: `${n}% of this stage progressed in the selected period. ${r.body}`,
|
|
813
|
+
action: r.action,
|
|
814
|
+
signals: [
|
|
815
|
+
{
|
|
816
|
+
text: `${r.target.toLocaleString()} of ${r.source.toLocaleString()} members progressed`
|
|
817
|
+
}
|
|
818
|
+
]
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
const Nr = {
|
|
822
|
+
VOUCHER: "Voucher",
|
|
823
|
+
PROMOTION: "Promotion",
|
|
824
|
+
POINT: "Experience",
|
|
825
|
+
CREDIT: "Credit",
|
|
826
|
+
BROADCAST: "Broadcast",
|
|
827
|
+
COIN: "Point",
|
|
828
|
+
REWARD_POOL: "Reward pool",
|
|
829
|
+
GAME: "Game",
|
|
830
|
+
MISSION: "Mission"
|
|
831
|
+
}, Er = {
|
|
832
|
+
active: { label: "Active", class: se.text },
|
|
833
|
+
expired: { label: "Ended", class: "text-fm-color-typo-tertiary" },
|
|
834
|
+
upcoming: { label: "Upcoming", class: oe.text }
|
|
835
|
+
};
|
|
836
|
+
function Ur(e) {
|
|
837
|
+
return e.type !== "MEMBERSHIP";
|
|
838
|
+
}
|
|
839
|
+
function Vr(e, o) {
|
|
840
|
+
var r;
|
|
841
|
+
return !o.length || !((r = e.targetLocation) != null && r.length) ? !0 : e.targetLocation.some(
|
|
842
|
+
(n) => o.includes(n.toString())
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
function Hr(e) {
|
|
846
|
+
var o;
|
|
847
|
+
if (((o = e.timeframeOptions) == null ? void 0 : o.type) === "timeframe") {
|
|
848
|
+
const r = V();
|
|
849
|
+
return r.isBetween(
|
|
850
|
+
e.timeframeOptions.start ?? r.clone().subtract(1, "d"),
|
|
851
|
+
e.timeframeOptions.end ?? r.clone().add(1, "d")
|
|
852
|
+
) ? "active" : r.isAfter(e.timeframeOptions.end) ? "expired" : "upcoming";
|
|
853
|
+
}
|
|
854
|
+
return "active";
|
|
855
|
+
}
|
|
856
|
+
function zr(e, o) {
|
|
857
|
+
return e.filter(Ur).filter(
|
|
858
|
+
(r) => Vr(r, o)
|
|
859
|
+
).map((r) => {
|
|
860
|
+
const n = Hr(r), s = Er[n], i = r.type === "BROADCAST";
|
|
861
|
+
return {
|
|
862
|
+
id: r._id.toString(),
|
|
863
|
+
name: r.name,
|
|
864
|
+
type: Nr[r.type] ?? r.type,
|
|
865
|
+
status: s.label,
|
|
866
|
+
metric: i ? String(r.currentReceive ?? 0) : s.label,
|
|
867
|
+
metricLabel: i ? "Messages sent" : "Status",
|
|
868
|
+
statusClass: s.class
|
|
869
|
+
};
|
|
870
|
+
}).sort(
|
|
871
|
+
(r, n) => +(n.status === "Active") - +(r.status === "Active")
|
|
872
|
+
).slice(0, 4);
|
|
873
|
+
}
|
|
874
|
+
function qr(e, o) {
|
|
875
|
+
return {
|
|
876
|
+
categories: e.categories,
|
|
877
|
+
prevCategories: e.prevCategories,
|
|
878
|
+
comparisonCategories: e.categories.map(
|
|
879
|
+
(r, n) => [r, e.prevCategories[n]].filter(Boolean).map((s) => V(s).format("DD/MM/YYYY")).join(" vs ")
|
|
880
|
+
),
|
|
881
|
+
series: e.series,
|
|
882
|
+
prevSeries: e.prevSeries,
|
|
883
|
+
description: g.memberSalesTrend,
|
|
884
|
+
totalFmt: O(e.memberSales, o),
|
|
885
|
+
deltaStr: `${e.deltaPct > 0 ? "+" : ""}${e.deltaPct}%`,
|
|
886
|
+
deltaClass: Ir(e.deltaPct)
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
function Yr(e, o, r, n) {
|
|
890
|
+
return !e.memberOrders && !e.nonMemberOrders ? "No completed orders were recorded in this period." : r === 0 && o > 0 ? "Members account for all tracked spend in this period." : o === 0 && r > 0 ? "Non-members account for all tracked spend in this period." : n > 0 ? `Members spend ${n}% more per order than non-members. Converting more walk-ins to members is a direct lever on sales.` : n < 0 ? `Non-members spend ${Math.abs(n)}% more per order than members. Converting more walk-ins to members can increase member-linked sales.` : "Members and non-members have the same average order value in this period.";
|
|
891
|
+
}
|
|
892
|
+
function jr(e, o) {
|
|
893
|
+
const r = e.memberOrders ? e.memberSales / e.memberOrders : 0, n = e.nonMemberOrders ? e.nonMemberSales / e.nonMemberOrders : 0, s = e.memberSales + e.nonMemberSales, i = Pr(r, n);
|
|
894
|
+
return {
|
|
895
|
+
description: g.memberSpendComparison,
|
|
896
|
+
memberSalesFmt: O(e.memberSales, o),
|
|
897
|
+
nonMemberSalesFmt: O(e.nonMemberSales, o),
|
|
898
|
+
avgMemberSaleFmt: O(r, o),
|
|
899
|
+
avgNonMemberSaleFmt: O(n, o),
|
|
900
|
+
memberSharePct: re(e.memberSales, s),
|
|
901
|
+
avgGapPct: i,
|
|
902
|
+
summary: Yr(
|
|
903
|
+
e,
|
|
904
|
+
r,
|
|
905
|
+
n,
|
|
906
|
+
i
|
|
907
|
+
)
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
function Gr(e) {
|
|
911
|
+
const o = [
|
|
912
|
+
{
|
|
913
|
+
id: "new",
|
|
914
|
+
label: "Newly joined",
|
|
915
|
+
count: e.newlyJoined,
|
|
916
|
+
description: g.newlyJoined,
|
|
917
|
+
labelClass: se.text,
|
|
918
|
+
barColor: "typo-success"
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
id: "frequent",
|
|
922
|
+
label: "Frequent",
|
|
923
|
+
count: e.frequent,
|
|
924
|
+
description: g.frequent,
|
|
925
|
+
labelClass: "text-fm-color-primary",
|
|
926
|
+
barColor: "primary"
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
id: "infrequent",
|
|
930
|
+
label: "Infrequent",
|
|
931
|
+
count: e.infrequent,
|
|
932
|
+
description: g.infrequent,
|
|
933
|
+
labelClass: "text-fm-color-typo-secondary",
|
|
934
|
+
barColor: "neutral-gray-300"
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
id: "at-risk",
|
|
938
|
+
label: "At-risk",
|
|
939
|
+
count: e.atRisk,
|
|
940
|
+
description: g.atRisk,
|
|
941
|
+
labelClass: oe.text,
|
|
942
|
+
barColor: "#FFC746"
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
id: "dormant",
|
|
946
|
+
label: "Dormant",
|
|
947
|
+
count: e.dormant,
|
|
948
|
+
description: g.dormant,
|
|
949
|
+
labelClass: Se.text,
|
|
950
|
+
barColor: "#FFCFCC"
|
|
951
|
+
}
|
|
952
|
+
], r = Math.max(...o.map((s) => s.count), 1);
|
|
953
|
+
return {
|
|
954
|
+
lifecycleSegs: o.map((s) => ({
|
|
955
|
+
...s,
|
|
956
|
+
barPct: Math.round(s.count / r * 100),
|
|
957
|
+
pctStr: `${e.totalMembers ? Math.round(s.count / e.totalMembers * 100) : 0}%`,
|
|
958
|
+
countStr: H(s.count)
|
|
959
|
+
})),
|
|
960
|
+
lifecycleSummary: `${H(
|
|
961
|
+
e.atRisk + e.dormant
|
|
962
|
+
)} members are at-risk or dormant`
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
function Jr(e) {
|
|
966
|
+
return Gr(e);
|
|
967
|
+
}
|
|
968
|
+
function Kr(e, o) {
|
|
969
|
+
return e.displayUnit === "uses" ? `${H(e.displayValue)} ${e.displayValue === 1 ? "use" : "uses"}` : e.type === "COIN" ? `${H(e.displayValue)} pts` : O(e.displayValue, o);
|
|
970
|
+
}
|
|
971
|
+
function Wr(e) {
|
|
972
|
+
return e.displayUnit === "uses" ? "Counted voucher-use transactions for this reward during the selected period." : `Total ${e.type.toLowerCase()} amount used for this reward during the selected period.`;
|
|
973
|
+
}
|
|
974
|
+
function Qr(e, o) {
|
|
975
|
+
const r = Math.max(
|
|
976
|
+
...e.topRewards.map((n) => n.usageCount),
|
|
977
|
+
1
|
|
978
|
+
);
|
|
979
|
+
return {
|
|
980
|
+
rewardKpis: [
|
|
981
|
+
{
|
|
982
|
+
label: "Reward redeemers",
|
|
983
|
+
value: H(e.rewardRedeemers),
|
|
984
|
+
description: g.rewardRedeemers
|
|
985
|
+
},
|
|
986
|
+
{
|
|
987
|
+
label: "Redemption rate",
|
|
988
|
+
value: `${e.redemptionRatePct}%`,
|
|
989
|
+
description: g.redemptionRate
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
label: "Avg reward uses",
|
|
993
|
+
value: `${e.averageRewardUsesPerRedeemer}x`,
|
|
994
|
+
description: g.averageRewardUses
|
|
995
|
+
}
|
|
996
|
+
],
|
|
997
|
+
topRewards: e.topRewards.map((n) => ({
|
|
998
|
+
name: n.name,
|
|
999
|
+
count: Kr(n, o),
|
|
1000
|
+
description: Wr(n),
|
|
1001
|
+
barPct: n.usageCount ? Math.round(n.usageCount / r * 100) : 0
|
|
1002
|
+
}))
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
const Xr = { class: "px-24 flex flex-col gap-16 pb-24" }, Zr = { class: "flex items-center justify-between gap-8 flex-wrap" }, es = { class: "flex items-center gap-8 flex-wrap" }, ts = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary -mt-8 text-right" }, rs = { class: "grid grid-cols-[3fr_2fr] xs:grid-cols-1 gap-16 items-start" }, ss = { class: "grid grid-cols-2 xs:grid-cols-1 gap-16" }, gs = /* @__PURE__ */ L({
|
|
1006
|
+
__name: "LoyaltyDashboard",
|
|
1007
|
+
setup(e) {
|
|
1008
|
+
const o = Ze(), r = et(), n = Ke(), { global: s, minor: i } = Xe, m = w(
|
|
1009
|
+
() => _e[r.currentCountry.value || "MY"] ?? _e.MY
|
|
1010
|
+
), b = w(
|
|
1011
|
+
() => Je.Country.getCountry(r.currentCountry.value || "MY").currency.code
|
|
1012
|
+
), [y, v] = Fr(
|
|
1013
|
+
"this-month",
|
|
1014
|
+
m.value
|
|
1015
|
+
), M = x({
|
|
1016
|
+
startDate: y,
|
|
1017
|
+
endDate: v
|
|
1018
|
+
}), S = x(
|
|
1019
|
+
me(we([y, v]))
|
|
1020
|
+
), z = x({ location: [] }), K = x(o.locations.length > 0), ae = x(!1), ne = x(0), ie = x({}), q = x(null), le = x(null), de = x(null), ce = x(null), W = x(null), Y = x(!1), j = x(!1), Q = x([]), X = x(!1), Z = x(!1);
|
|
1021
|
+
function me([a, c]) {
|
|
1022
|
+
return { startDate: a, endDate: c };
|
|
1023
|
+
}
|
|
1024
|
+
ge(M, (a) => {
|
|
1025
|
+
a.startDate && a.endDate && (S.value = me(
|
|
1026
|
+
we([a.startDate, a.endDate])
|
|
1027
|
+
));
|
|
1028
|
+
});
|
|
1029
|
+
const ue = w(
|
|
1030
|
+
() => Or(
|
|
1031
|
+
q.value ?? {
|
|
1032
|
+
totalMembers: 0,
|
|
1033
|
+
activeMembers: 0,
|
|
1034
|
+
purchasingMembers: 0,
|
|
1035
|
+
repeatMembers: 0,
|
|
1036
|
+
rewardRedeemers: 0
|
|
1037
|
+
}
|
|
1038
|
+
)
|
|
1039
|
+
), pe = w(
|
|
1040
|
+
() => Jr(
|
|
1041
|
+
le.value ?? {
|
|
1042
|
+
totalMembers: 0,
|
|
1043
|
+
newlyJoined: 0,
|
|
1044
|
+
frequent: 0,
|
|
1045
|
+
infrequent: 0,
|
|
1046
|
+
atRisk: 0,
|
|
1047
|
+
dormant: 0
|
|
1048
|
+
}
|
|
1049
|
+
)
|
|
1050
|
+
), Re = w(
|
|
1051
|
+
() => qr(
|
|
1052
|
+
de.value ?? {
|
|
1053
|
+
categories: [""],
|
|
1054
|
+
prevCategories: [""],
|
|
1055
|
+
series: [0],
|
|
1056
|
+
prevSeries: [0],
|
|
1057
|
+
description: g.memberSalesTrend,
|
|
1058
|
+
memberSales: 0,
|
|
1059
|
+
deltaPct: 0
|
|
1060
|
+
},
|
|
1061
|
+
b.value
|
|
1062
|
+
)
|
|
1063
|
+
), Ce = w(
|
|
1064
|
+
() => q.value ? Tr(q.value) : null
|
|
1065
|
+
), ee = w(
|
|
1066
|
+
() => W.value ? Qr(W.value, b.value) : null
|
|
1067
|
+
), $e = w(
|
|
1068
|
+
() => jr(
|
|
1069
|
+
ce.value ?? {
|
|
1070
|
+
memberSales: 0,
|
|
1071
|
+
memberOrders: 0,
|
|
1072
|
+
nonMemberSales: 0,
|
|
1073
|
+
nonMemberOrders: 0
|
|
1074
|
+
},
|
|
1075
|
+
b.value
|
|
1076
|
+
)
|
|
1077
|
+
), Fe = w(
|
|
1078
|
+
() => zr(Q.value, z.value.location)
|
|
1079
|
+
), De = w(() => {
|
|
1080
|
+
const a = ie.value;
|
|
1081
|
+
return [
|
|
1082
|
+
{
|
|
1083
|
+
label: "Total members",
|
|
1084
|
+
value: be(a.totalMembers ?? 0),
|
|
1085
|
+
description: g.totalMembers,
|
|
1086
|
+
icon: "group",
|
|
1087
|
+
delta: "0%"
|
|
1088
|
+
},
|
|
1089
|
+
{
|
|
1090
|
+
label: "Active members",
|
|
1091
|
+
value: be(a.activeMembers ?? 0),
|
|
1092
|
+
description: g.activeMembers,
|
|
1093
|
+
icon: "bolt",
|
|
1094
|
+
delta: "0%"
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
label: "Member sales",
|
|
1098
|
+
value: O(a.memberSales ?? 0, b.value),
|
|
1099
|
+
description: g.memberSales,
|
|
1100
|
+
icon: "payments",
|
|
1101
|
+
delta: "0%"
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
label: "Repeat rate",
|
|
1105
|
+
value: ye(a.repeatRatePct ?? 0),
|
|
1106
|
+
description: g.repeatRate,
|
|
1107
|
+
icon: "repeat",
|
|
1108
|
+
delta: "0pp"
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
label: "Voucher redemption rate",
|
|
1112
|
+
value: ye(a.voucherRedemptionRatePct ?? 0),
|
|
1113
|
+
description: g.voucherRedemptionRate,
|
|
1114
|
+
icon: "redeem",
|
|
1115
|
+
delta: "0pp"
|
|
1116
|
+
}
|
|
1117
|
+
].map(
|
|
1118
|
+
(h) => ({
|
|
1119
|
+
...h,
|
|
1120
|
+
sub: null,
|
|
1121
|
+
deltaClass: "text-fm-color-typo-secondary",
|
|
1122
|
+
trendUp: !0
|
|
1123
|
+
})
|
|
1124
|
+
);
|
|
1125
|
+
}), ke = w(
|
|
1126
|
+
() => o.locations.map((a) => a._id.toString())
|
|
1127
|
+
);
|
|
1128
|
+
function fe(a) {
|
|
1129
|
+
return !a.startDate || !a.endDate ? "" : `${he(a.startDate).format("D MMM")} – ${he(a.endDate).format("D MMM YYYY")}`;
|
|
1130
|
+
}
|
|
1131
|
+
const Pe = w(() => fe(M.value)), Ae = w(
|
|
1132
|
+
() => fe(S.value)
|
|
1133
|
+
);
|
|
1134
|
+
function be(a) {
|
|
1135
|
+
return a >= 1e3 ? `${(a / 1e3).toFixed(1).replace(/\.0$/, "")}k` : String(a);
|
|
1136
|
+
}
|
|
1137
|
+
function ye(a) {
|
|
1138
|
+
return `${Math.round(a * 10) / 10}%`;
|
|
1139
|
+
}
|
|
1140
|
+
function Ie(a) {
|
|
1141
|
+
if (a && typeof a == "object" && "value" in a && Number.isFinite(Number(a.value)))
|
|
1142
|
+
return Number(a.value);
|
|
1143
|
+
}
|
|
1144
|
+
function Le() {
|
|
1145
|
+
return !M.value.startDate || !M.value.endDate || !S.value.startDate || !S.value.endDate || !K.value ? null : kr({
|
|
1146
|
+
dateRange: [M.value.startDate, M.value.endDate],
|
|
1147
|
+
compareDateRange: [
|
|
1148
|
+
S.value.startDate,
|
|
1149
|
+
S.value.endDate
|
|
1150
|
+
],
|
|
1151
|
+
selectedLocationIds: z.value.location,
|
|
1152
|
+
locationIds: ke.value,
|
|
1153
|
+
timezone: m.value
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
function k(a) {
|
|
1157
|
+
return a === ne.value;
|
|
1158
|
+
}
|
|
1159
|
+
async function N(a, c, h) {
|
|
1160
|
+
try {
|
|
1161
|
+
await a(c, h);
|
|
1162
|
+
} catch (E) {
|
|
1163
|
+
if (k(h)) throw E;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
async function Oe(a, c) {
|
|
1167
|
+
const [
|
|
1168
|
+
h,
|
|
1169
|
+
E,
|
|
1170
|
+
G,
|
|
1171
|
+
P,
|
|
1172
|
+
He
|
|
1173
|
+
] = await Promise.all([
|
|
1174
|
+
$.readTotalMembers(a),
|
|
1175
|
+
$.readActiveMembers(a),
|
|
1176
|
+
$.readMemberSales(a),
|
|
1177
|
+
$.readRepeatRate(a),
|
|
1178
|
+
$.readVoucherRedemptionRate(a)
|
|
1179
|
+
]);
|
|
1180
|
+
k(c) && (ie.value = {
|
|
1181
|
+
totalMembers: Ie(h),
|
|
1182
|
+
activeMembers: E.activeMembers,
|
|
1183
|
+
memberSales: G.memberSales,
|
|
1184
|
+
repeatRatePct: P.repeatRatePct,
|
|
1185
|
+
voucherRedemptionRatePct: He.voucherRedemptionRatePct
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
async function Be(a, c) {
|
|
1189
|
+
const h = await $.readMemberFunnel(a);
|
|
1190
|
+
k(c) && (q.value = h);
|
|
1191
|
+
}
|
|
1192
|
+
async function Te(a, c) {
|
|
1193
|
+
const h = await $.readMemberLifecycle(a);
|
|
1194
|
+
k(c) && (le.value = h);
|
|
1195
|
+
}
|
|
1196
|
+
async function Ne(a, c) {
|
|
1197
|
+
const h = await $.readMemberSalesTrend(a);
|
|
1198
|
+
k(c) && (de.value = h);
|
|
1199
|
+
}
|
|
1200
|
+
async function Ee(a, c) {
|
|
1201
|
+
const h = await $.readMemberSpendComparison(a);
|
|
1202
|
+
k(c) && (ce.value = h);
|
|
1203
|
+
}
|
|
1204
|
+
async function Ue(a, c) {
|
|
1205
|
+
Y.value = !0, j.value = !1;
|
|
1206
|
+
try {
|
|
1207
|
+
const h = await $.readRewardUsageHealth(a);
|
|
1208
|
+
if (!k(c)) return;
|
|
1209
|
+
W.value = h;
|
|
1210
|
+
} catch (h) {
|
|
1211
|
+
throw k(c) && (j.value = !0), h;
|
|
1212
|
+
} finally {
|
|
1213
|
+
k(c) && (Y.value = !1);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
async function Ve() {
|
|
1217
|
+
X.value = !0, Z.value = !1;
|
|
1218
|
+
try {
|
|
1219
|
+
const { resources: a } = await We.readAll({
|
|
1220
|
+
limit: 1e3,
|
|
1221
|
+
skip: 0,
|
|
1222
|
+
sortBy: "_id",
|
|
1223
|
+
descending: !0
|
|
1224
|
+
});
|
|
1225
|
+
Q.value = a;
|
|
1226
|
+
} catch (a) {
|
|
1227
|
+
throw Z.value = !0, a;
|
|
1228
|
+
} finally {
|
|
1229
|
+
X.value = !1;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
function ve() {
|
|
1233
|
+
const a = ++ne.value, c = Le();
|
|
1234
|
+
if (!c) {
|
|
1235
|
+
Y.value = !1, j.value = !1;
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
i(
|
|
1239
|
+
() => N(Oe, c, a)
|
|
1240
|
+
).catch(() => {
|
|
1241
|
+
}), i(
|
|
1242
|
+
() => N(Be, c, a)
|
|
1243
|
+
).catch(() => {
|
|
1244
|
+
}), i(
|
|
1245
|
+
() => N(Te, c, a)
|
|
1246
|
+
).catch(() => {
|
|
1247
|
+
}), i(
|
|
1248
|
+
() => N(Ne, c, a)
|
|
1249
|
+
).catch(() => {
|
|
1250
|
+
}), i(
|
|
1251
|
+
() => N(
|
|
1252
|
+
Ee,
|
|
1253
|
+
c,
|
|
1254
|
+
a
|
|
1255
|
+
)
|
|
1256
|
+
).catch(() => {
|
|
1257
|
+
}), i(
|
|
1258
|
+
() => N(Ue, c, a)
|
|
1259
|
+
).catch(() => {
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
return ge([M, S, () => z.value.location], () => {
|
|
1263
|
+
ae.value && ve();
|
|
1264
|
+
}), qe(async () => {
|
|
1265
|
+
await s(async () => {
|
|
1266
|
+
K.value || await o.readLocations(), K.value = !0;
|
|
1267
|
+
}), await Ye(), ae.value = !0, ve(), Ve().catch(() => {
|
|
1268
|
+
Q.value = [];
|
|
1269
|
+
});
|
|
1270
|
+
}), (a, c) => {
|
|
1271
|
+
var E, G;
|
|
1272
|
+
const h = _("FmPageHead");
|
|
1273
|
+
return l(), u(F, null, [
|
|
1274
|
+
p(h, { title: "Analytic" }),
|
|
1275
|
+
t("div", Xr, [
|
|
1276
|
+
t("div", Zr, [
|
|
1277
|
+
p(Qe, {
|
|
1278
|
+
label: "Location: ",
|
|
1279
|
+
"right-icon": "keyboard_arrow_down",
|
|
1280
|
+
modelValue: f(z).location,
|
|
1281
|
+
"onUpdate:modelValue": c[0] || (c[0] = (P) => f(z).location = P),
|
|
1282
|
+
icon: "storefront",
|
|
1283
|
+
"show-item-label": !0,
|
|
1284
|
+
items: f(o).locationOptions
|
|
1285
|
+
}, null, 8, ["modelValue", "items"]),
|
|
1286
|
+
t("div", es, [
|
|
1287
|
+
p(xe, {
|
|
1288
|
+
"model-value": f(M),
|
|
1289
|
+
"onUpdate:modelValue": c[1] || (c[1] = (P) => M.value = P)
|
|
1290
|
+
}, null, 8, ["model-value"]),
|
|
1291
|
+
c[4] || (c[4] = t("span", { class: "fm-typo-en-body-sm-600 text-fm-color-typo-tertiary" }, "vs", -1)),
|
|
1292
|
+
p(xe, {
|
|
1293
|
+
"model-value": f(S),
|
|
1294
|
+
"onUpdate:modelValue": c[2] || (c[2] = (P) => S.value = P)
|
|
1295
|
+
}, null, 8, ["model-value"])
|
|
1296
|
+
])
|
|
1297
|
+
]),
|
|
1298
|
+
t("div", ts, d(f(Pe)) + " · vs. " + d(f(Ae)), 1),
|
|
1299
|
+
p(Pt, { kpis: f(De) }, null, 8, ["kpis"]),
|
|
1300
|
+
t("section", rs, [
|
|
1301
|
+
p(tr, {
|
|
1302
|
+
stages: f(ue).funnelStages,
|
|
1303
|
+
footnote: f(ue).funnelFootnote,
|
|
1304
|
+
interactive: !1
|
|
1305
|
+
}, null, 8, ["stages", "footnote"]),
|
|
1306
|
+
p(Mt, {
|
|
1307
|
+
insight: f(Ce),
|
|
1308
|
+
onNavigate: c[3] || (c[3] = (P) => f(n).push(P))
|
|
1309
|
+
}, null, 8, ["insight"])
|
|
1310
|
+
]),
|
|
1311
|
+
t("section", ss, [
|
|
1312
|
+
p(Nt, {
|
|
1313
|
+
segments: f(pe).lifecycleSegs,
|
|
1314
|
+
summary: f(pe).lifecycleSummary,
|
|
1315
|
+
interactive: !1
|
|
1316
|
+
}, null, 8, ["segments", "summary"]),
|
|
1317
|
+
p(Mr, {
|
|
1318
|
+
kpis: ((E = f(ee)) == null ? void 0 : E.rewardKpis) ?? [],
|
|
1319
|
+
"top-rewards": ((G = f(ee)) == null ? void 0 : G.topRewards) ?? [],
|
|
1320
|
+
"has-data": !!f(ee),
|
|
1321
|
+
loading: f(Y),
|
|
1322
|
+
error: f(j)
|
|
1323
|
+
}, null, 8, ["kpis", "top-rewards", "has-data", "loading", "error"]),
|
|
1324
|
+
p($r, { sales: f(Re) }, null, 8, ["sales"]),
|
|
1325
|
+
p(pt, {
|
|
1326
|
+
campaigns: f(Fe),
|
|
1327
|
+
loading: f(X),
|
|
1328
|
+
error: f(Z)
|
|
1329
|
+
}, null, 8, ["campaigns", "loading", "error"]),
|
|
1330
|
+
p(mr, { spend: f($e) }, null, 8, ["spend"])
|
|
1331
|
+
])
|
|
1332
|
+
])
|
|
1333
|
+
], 64);
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
});
|
|
1337
|
+
export {
|
|
1338
|
+
gs as default
|
|
1339
|
+
};
|