@feedmepos/mf-connect 0.1.98-beta.13 → 0.1.98-beta.15
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 +1 -1
- package/dist/App-DQqZfak3.js +0 -4782
- package/dist/AuditLogs-C19m85wp.js +0 -2013
- package/dist/Bin-GjJ5Q2ae.js +0 -166
- package/dist/Broadcast-CVTBL0T0.js +0 -266
- package/dist/CampaignTypeDialog.vue_vue_type_script_setup_true_lang-B6BYvVmq.js +0 -120
- package/dist/Card-DzYit3v6.js +0 -910
- package/dist/ChipMenu.vue_vue_type_script_setup_true_lang-BPpZZNkr.js +0 -97
- package/dist/Collections-CaU7auvn.js +0 -540
- package/dist/Credit-B_eUMV0R.js +0 -260
- package/dist/CustomSelect.vue_vue_type_script_setup_true_lang-Du7fRSZC.js +0 -128
- package/dist/DateRangeChip.vue_vue_type_script_setup_true_lang-eIoPtgO5.js +0 -58
- package/dist/EditCampaignSheet.vue_vue_type_script_setup_true_lang-Bgcm1S_g.js +0 -3377
- package/dist/EffectSheet.vue_vue_type_style_index_0_lang-CZLoCJM4.js +0 -351
- package/dist/Experience-B7kxE07l.js +0 -259
- package/dist/FileSaver.min-BBvy4uPh.js +0 -74
- package/dist/FilterChip.vue_vue_type_script_setup_true_lang-DaU-9GzO.js +0 -129
- package/dist/FmTableSelection.vue_vue_type_script_setup_true_lang-DzcUc0_w.js +0 -52
- package/dist/Game-B98hcWvR.js +0 -330
- package/dist/Grab-RdxV7xhM.js +0 -300
- package/dist/ImageInput.vue_vue_type_script_setup_true_lang-BBYekrJp.js +0 -145
- package/dist/Index-CvMVxCY5.js +0 -259
- package/dist/JsonViewer-v8_C7l5N.js +0 -87
- package/dist/LocationPicker.vue_vue_type_script_setup_true_lang-D4-wjMg6.js +0 -48
- package/dist/LottieAnimation.vue_vue_type_script_setup_true_lang-Jir8zY8e.js +0 -18737
- package/dist/LoyaltyDashboard-B1OzFT4q.js +0 -1082
- package/dist/MainLayout-De_edc-D.js +0 -41
- package/dist/Marketing-B7-To3XF.js +0 -235
- package/dist/MarketingMaterialEdit-DGONncxn.js +0 -1035
- package/dist/Member-DEGCrqnh.js +0 -280
- package/dist/MemberList-vKYbpLVu.js +0 -1601
- package/dist/MemberOverview-wL_ailso.js +0 -58
- package/dist/MemberTransactions-CGC3vYKC.js +0 -45
- package/dist/MessageInput.vue_vue_type_script_setup_true_lang-BP9YtuPA.js +0 -60802
- package/dist/Mission-hxf_AIGL.js +0 -334
- package/dist/Overview-NvgUuMYp.js +0 -949
- package/dist/Overview-iRLMLoAo.js +0 -1079
- package/dist/Point-tkUTXOCe.js +0 -262
- package/dist/Promotion-DNUcMKJQ.js +0 -397
- package/dist/Queue-5XYiIuG8.js +0 -260
- package/dist/Record-B5aYp7eF.js +0 -342
- package/dist/Review-BqaHlzXV.js +0 -45
- package/dist/ReviewFacebookCallback-BqlFkSB7.js +0 -248
- package/dist/ReviewGoogleCallback-ssKL4jh4.js +0 -213
- package/dist/Reward-1xOMowTW.js +0 -442
- package/dist/RewardGroup.vue_vue_type_script_setup_true_lang-Db3FSfIc.js +0 -149
- package/dist/RuleGroup.vue_vue_type_script_setup_true_lang-Cmrp2Tia.js +0 -1911
- package/dist/Segment-BMBwsUug.js +0 -1014
- package/dist/SelectItems.vue_vue_type_script_setup_true_lang-DSfdei-h.js +0 -181
- package/dist/SendCollectionSheet.vue_vue_type_script_setup_true_lang-BJVeGJ5J.js +0 -188
- package/dist/SendVoucherSheet.vue_vue_type_script_setup_true_lang-OBZubKUy.js +0 -226
- package/dist/Setting-DWygYkHW.js +0 -2047
- package/dist/SettingAdvertisements-TYB1b7dB.js +0 -264
- package/dist/Settings-DynjmCPL.js +0 -220
- package/dist/Store-DRYkmigC.js +0 -1996
- package/dist/StoreRewards-DU8eWbXE.js +0 -540
- package/dist/StoreTransactions.vue_vue_type_script_setup_true_lang-BkqBjEFm.js +0 -1130
- package/dist/TargetLocationInput.vue_vue_type_script_setup_true_lang-l6KmXVBZ.js +0 -7007
- package/dist/Tier-4k8SxKtl.js +0 -969
- package/dist/Title-B9lWQ_jl.js +0 -566
- package/dist/Transaction-C38Yd0tf.js +0 -39
- package/dist/UserRuleGroup.vue_vue_type_script_setup_true_lang-D6tgpKpc.js +0 -130
- package/dist/Voucher-BQbqC7RV.js +0 -421
- package/dist/VoucherEditor.vue_vue_type_script_setup_true_lang-erwpbvYi.js +0 -421
- package/dist/ZodTextField.vue_vue_type_script_setup_true_lang-Dt05b7fU.js +0 -56
- package/dist/_plugin-vue_export-helper-CHgC5LLL.js +0 -9
- package/dist/app-BTm9mz0r.js +0 -59940
- package/dist/app-wDQR6dpb.js +0 -39
- package/dist/app.js +0 -7
- package/dist/business-B7GwHLce.js +0 -82
- package/dist/campaign-BCdKDHgz.js +0 -277
- package/dist/campaign-CpzFl8Vr.js +0 -4
- package/dist/campaign-DWlsbsKQ.js +0 -219
- package/dist/campaign.enum-BgK4maXz.js +0 -26
- package/dist/campaign.fn-DxnwGCB2.js +0 -776
- package/dist/collectible.enum-CdOSUDwG.js +0 -19
- package/dist/duplicateCampaign-BSHe0P-g.js +0 -51
- package/dist/effect-C7wkN_13.js +0 -89
- package/dist/email-addresses-DJycNI7L.js +0 -705
- package/dist/export-uIHWDxuh.js +0 -97
- package/dist/feedme.ico +0 -0
- package/dist/google-BQK68wbe.js +0 -5
- package/dist/helper-czpAhAIw.js +0 -86
- package/dist/index-5Sa4xS2m.js +0 -151
- package/dist/index-5WGEWCcI.js +0 -3
- package/dist/index-B2C7kc4z.js +0 -31
- package/dist/index-B5eb6_bi.js +0 -3678
- package/dist/index-B7nE1Pb2.js +0 -67
- package/dist/index-BFAHLexA.js +0 -32
- package/dist/index-BanxlNli.js +0 -8910
- package/dist/index-ByHoFriu.js +0 -85
- package/dist/index-Ca2bBJuR.js +0 -54
- package/dist/index-CuvNtC_M.js +0 -61
- package/dist/index-D-kYrDAi.js +0 -30289
- package/dist/index-D2gAYMIp.js +0 -28900
- package/dist/index-DWxmK2NJ.js +0 -61
- package/dist/index-U_rwkNKU.js +0 -2819
- package/dist/index-knizSLfz.js +0 -1157
- package/dist/index-vh86FiIQ.js +0 -10
- package/dist/index.esm2017-DFVkiPjd.js +0 -3069
- package/dist/loading-B3OgwEC8.js +0 -72
- package/dist/lodash-CiRTkvui.js +0 -3678
- package/dist/membership-s2VKnu_8.js +0 -255
- package/dist/moment-D7p2TMB-.js +0 -2583
- package/dist/money-DqxOXYd0.js +0 -15
- package/dist/number-Bt4sacaM.js +0 -12
- package/dist/object-BYyQ0PZp.js +0 -18
- package/dist/objectId-dwaoBfJX.js +0 -7
- package/dist/objectid-CxCupSWP.js +0 -145
- package/dist/plugins-CQ1JAqJB.js +0 -1788
- package/dist/reward-pjbal-XX.js +0 -36
- package/dist/rule-CzU2GAur.js +0 -1969
- package/dist/string-Gcy5IM_H.js +0 -32
- package/dist/style.css +0 -4
- package/dist/template-7yiMSL1f.js +0 -188
- package/dist/tier-BJDhpH6X.js +0 -4
- package/dist/tiers/tier=1.png +0 -0
- package/dist/tiers/tier=2.png +0 -0
- package/dist/tiers/tier=3.png +0 -0
- package/dist/tiers/tier=4.png +0 -0
- package/dist/titles/type=diamond.png +0 -0
- package/dist/titles/type=drinks.png +0 -0
- package/dist/titles/type=food.png +0 -0
- package/dist/titles/type=heart.png +0 -0
- package/dist/titles/type=medal.png +0 -0
- package/dist/titles/type=spend.png +0 -0
- package/dist/titles/type=thank-you.png +0 -0
- package/dist/titles/type=thumbs-up.png +0 -0
- package/dist/titles/type=years.png +0 -0
- package/dist/trigger-C5bqlYHn.js +0 -213
- package/dist/tslib.es6-BCqqvLQ_.js +0 -44
- package/dist/type_drinks-D6jnpvwV.js +0 -4
- package/dist/useMarketingMaterialActions-CW_QRtQb.js +0 -107
- package/dist/usePagination-D2pke4vy.js +0 -220
- package/dist/user-BcXrT_t5.js +0 -55
- package/dist/vue-i18n-CFNkj6JK.js +0 -2365
- package/dist/xlsx-DyVY5_Qx.js +0 -15491
- package/dist/zod-BD_8DRqQ.js +0 -91
|
@@ -1,1082 +0,0 @@
|
|
|
1
|
-
import { defineComponent as M, resolveComponent as g, openBlock as u, createBlock as C, withCtx as N, createElementVNode as t, createElementBlock as v, Fragment as F, renderList as B, normalizeClass as w, toDisplayString as n, createVNode as b, createCommentVNode as H, createTextVNode as ke, normalizeStyle as Ae, computed as _, unref as y, ref as $, watch as fe, onMounted as Ie } from "vue";
|
|
2
|
-
import { h as ye } from "./moment-D7p2TMB-.js";
|
|
3
|
-
import { _ as Be } from "./FilterChip.vue_vue_type_script_setup_true_lang-DaU-9GzO.js";
|
|
4
|
-
import { _ as be } from "./DateRangeChip.vue_vue_type_script_setup_true_lang-eIoPtgO5.js";
|
|
5
|
-
import { u as Ne } from "./loading-B3OgwEC8.js";
|
|
6
|
-
import { g as k, S as Te, b as je } from "./index-D2gAYMIp.js";
|
|
7
|
-
import { u as Ee } from "./business-B7GwHLce.js";
|
|
8
|
-
import { m as z, C as ve } from "./index-knizSLfz.js";
|
|
9
|
-
import { useCoreStore as Ve } from "@feedmepos/mf-common";
|
|
10
|
-
const Je = { class: "flex flex-col" }, qe = { class: "flex-1 min-w-0" }, Oe = { class: "fm-typo-en-body-sm-600 whitespace-nowrap overflow-hidden text-ellipsis" }, ze = { class: "fm-typo-en-body-xs-400 text-fm-color-typo-tertiary mt-2" }, Ke = { class: "text-right flex-shrink-0" }, Ue = { class: "fm-typo-en-title-xs-800" }, We = { class: "fm-typo-en-body-xs-400 text-fm-color-typo-tertiary mt-2" }, Ye = /* @__PURE__ */ M({
|
|
11
|
-
__name: "CampaignActivityList",
|
|
12
|
-
props: {
|
|
13
|
-
campaigns: {}
|
|
14
|
-
},
|
|
15
|
-
setup(e) {
|
|
16
|
-
return (s, o) => {
|
|
17
|
-
const d = g("FmCard");
|
|
18
|
-
return u(), C(d, {
|
|
19
|
-
variant: "outlined",
|
|
20
|
-
class: "p-24"
|
|
21
|
-
}, {
|
|
22
|
-
default: N(() => [
|
|
23
|
-
o[0] || (o[0] = t("div", { class: "flex items-center mb-14" }, [
|
|
24
|
-
t("div", { class: "flex-1 fm-typo-en-body-md-600" }, "Recent campaigns"),
|
|
25
|
-
t("a", {
|
|
26
|
-
href: "#",
|
|
27
|
-
class: "fm-typo-en-body-xs-600 text-fm-color-primary no-underline"
|
|
28
|
-
}, "All campaigns")
|
|
29
|
-
], -1)),
|
|
30
|
-
t("div", Je, [
|
|
31
|
-
(u(!0), v(F, null, B(e.campaigns, (a) => (u(), v("div", {
|
|
32
|
-
key: a.name,
|
|
33
|
-
class: "flex items-start gap-10 py-10 border-b border-fm-color-neutral-gray-100 last:border-b-0 cursor-pointer"
|
|
34
|
-
}, [
|
|
35
|
-
t("div", {
|
|
36
|
-
class: w(["w-7 h-7 rounded-full bg-current flex-shrink-0 mt-5", a.statusClass])
|
|
37
|
-
}, null, 2),
|
|
38
|
-
t("div", qe, [
|
|
39
|
-
t("div", Oe, n(a.name), 1),
|
|
40
|
-
t("div", ze, n(a.date) + " · " + n(a.type), 1)
|
|
41
|
-
]),
|
|
42
|
-
t("div", Ke, [
|
|
43
|
-
t("div", Ue, n(a.metric), 1),
|
|
44
|
-
t("div", We, n(a.metricLabel), 1)
|
|
45
|
-
])
|
|
46
|
-
]))), 128))
|
|
47
|
-
])
|
|
48
|
-
]),
|
|
49
|
-
_: 1
|
|
50
|
-
});
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
}), He = { class: "flex items-center gap-8" }, Ge = { class: "w-[30px] h-[30px] rounded-8 bg-[#FFF0E2] flex items-center justify-center flex-shrink-0" }, Qe = { class: "bg-[#FFF6EE] rounded-10 p-14" }, Xe = { class: "fm-typo-en-body-sm-700 mb-6" }, Ze = { class: "fm-typo-en-body-xs-400 text-fm-color-typo-secondary" }, et = { class: "flex flex-col gap-6" }, tt = { class: "border-t border-fm-color-neutral-gray-100 pt-12 flex flex-col gap-7" }, st = { class: "fm-typo-en-body-xs-400 text-fm-color-typo-secondary" }, at = /* @__PURE__ */ M({
|
|
54
|
-
__name: "InsightPanel",
|
|
55
|
-
props: {
|
|
56
|
-
insight: {}
|
|
57
|
-
},
|
|
58
|
-
emits: ["view-segment"],
|
|
59
|
-
setup(e, { emit: s }) {
|
|
60
|
-
const o = s;
|
|
61
|
-
return (d, a) => {
|
|
62
|
-
const l = g("FmIcon"), i = g("FmButton"), c = g("FmCard");
|
|
63
|
-
return u(), C(c, {
|
|
64
|
-
variant: "outlined",
|
|
65
|
-
class: "p-24 flex flex-col gap-14"
|
|
66
|
-
}, {
|
|
67
|
-
default: N(() => [
|
|
68
|
-
t("div", He, [
|
|
69
|
-
t("div", Ge, [
|
|
70
|
-
b(l, {
|
|
71
|
-
name: "info",
|
|
72
|
-
outline: "",
|
|
73
|
-
size: "sm",
|
|
74
|
-
class: "!text-fm-color-primary"
|
|
75
|
-
})
|
|
76
|
-
]),
|
|
77
|
-
a[1] || (a[1] = t("div", { class: "fm-typo-en-body-md-600" }, "Action insight", -1))
|
|
78
|
-
]),
|
|
79
|
-
t("div", Qe, [
|
|
80
|
-
t("div", Xe, n(e.insight.title), 1),
|
|
81
|
-
t("div", Ze, n(e.insight.body), 1)
|
|
82
|
-
]),
|
|
83
|
-
t("div", et, [
|
|
84
|
-
a[2] || (a[2] = t("div", { class: "fm-typo-en-body-xs-600 text-fm-color-typo-tertiary uppercase tracking-wide mb-1" }, " Suggested actions ", -1)),
|
|
85
|
-
b(i, {
|
|
86
|
-
label: e.insight.primaryLabel,
|
|
87
|
-
"append-icon": "arrow_forward",
|
|
88
|
-
class: "!justify-between"
|
|
89
|
-
}, null, 8, ["label"]),
|
|
90
|
-
b(i, {
|
|
91
|
-
variant: "secondary",
|
|
92
|
-
label: e.insight.secondaryLabel,
|
|
93
|
-
"append-icon": "arrow_forward",
|
|
94
|
-
class: "!justify-between",
|
|
95
|
-
onClick: a[0] || (a[0] = (p) => o("view-segment", e.insight.secondaryStage))
|
|
96
|
-
}, null, 8, ["label"])
|
|
97
|
-
]),
|
|
98
|
-
t("div", tt, [
|
|
99
|
-
a[4] || (a[4] = t("div", { class: "fm-typo-en-body-xs-600 text-fm-color-typo-tertiary uppercase tracking-wide mb-1" }, " Other signals ", -1)),
|
|
100
|
-
(u(!0), v(F, null, B(e.insight.signals, (p) => (u(), v("div", {
|
|
101
|
-
key: p.text,
|
|
102
|
-
class: "flex items-start gap-7"
|
|
103
|
-
}, [
|
|
104
|
-
a[3] || (a[3] = t("div", { class: "w-4 h-4 rounded-full bg-fm-color-neutral-gray-200 flex-shrink-0 mt-6" }, null, -1)),
|
|
105
|
-
t("div", st, n(p.text), 1)
|
|
106
|
-
]))), 128))
|
|
107
|
-
])
|
|
108
|
-
]),
|
|
109
|
-
_: 1
|
|
110
|
-
});
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
}), rt = { class: "grid grid-cols-5 xs:grid-cols-2 gap-12" }, ot = { class: "flex items-center gap-8" }, nt = { class: "w-[30px] h-[30px] rounded-8 bg-[#FFF6EE] flex items-center justify-center flex-shrink-0" }, lt = { class: "fm-typo-en-body-lg-600 text-fm-color-typo-secondary flex-1 min-w-0" }, it = { class: "fm-typo-en-title-sm-800 text-fm-color-typo-primary whitespace-nowrap overflow-hidden text-ellipsis" }, ct = {
|
|
114
|
-
key: 0,
|
|
115
|
-
class: "text-fm-color-typo-success fm-typo-en-body-xs-600 -mt-4"
|
|
116
|
-
}, mt = { class: "flex items-center gap-4 flex-wrap" }, dt = /* @__PURE__ */ M({
|
|
117
|
-
__name: "KpiStrip",
|
|
118
|
-
props: {
|
|
119
|
-
kpis: {}
|
|
120
|
-
},
|
|
121
|
-
setup(e) {
|
|
122
|
-
return (s, o) => {
|
|
123
|
-
const d = g("FmIcon"), a = g("FmCard");
|
|
124
|
-
return u(), v("section", rt, [
|
|
125
|
-
(u(!0), v(F, null, B(e.kpis, (l) => (u(), C(a, {
|
|
126
|
-
key: l.label,
|
|
127
|
-
variant: "outlined",
|
|
128
|
-
class: "flex flex-col gap-8 p-16 min-w-0 overflow-hidden"
|
|
129
|
-
}, {
|
|
130
|
-
default: N(() => [
|
|
131
|
-
t("div", ot, [
|
|
132
|
-
t("div", nt, [
|
|
133
|
-
b(d, {
|
|
134
|
-
name: l.icon,
|
|
135
|
-
outline: "",
|
|
136
|
-
size: "sm",
|
|
137
|
-
class: "!text-fm-color-primary"
|
|
138
|
-
}, null, 8, ["name"])
|
|
139
|
-
]),
|
|
140
|
-
t("span", lt, n(l.label), 1)
|
|
141
|
-
]),
|
|
142
|
-
t("div", it, n(l.value), 1),
|
|
143
|
-
l.sub ? (u(), v("div", ct, n(l.sub), 1)) : H("", !0),
|
|
144
|
-
t("div", mt, [
|
|
145
|
-
b(d, {
|
|
146
|
-
name: l.trendUp ? "trending_up" : "trending_down",
|
|
147
|
-
size: "xs",
|
|
148
|
-
class: w(l.deltaClass)
|
|
149
|
-
}, null, 8, ["name", "class"]),
|
|
150
|
-
t("span", {
|
|
151
|
-
class: w(["fm-typo-en-body-xs-600", l.deltaClass])
|
|
152
|
-
}, n(l.delta), 3),
|
|
153
|
-
o[0] || (o[0] = t("span", { class: "fm-typo-en-body-xs-400 text-fm-color-typo-tertiary" }, "vs prev", -1))
|
|
154
|
-
])
|
|
155
|
-
]),
|
|
156
|
-
_: 2
|
|
157
|
-
}, 1024))), 128))
|
|
158
|
-
]);
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
}), ut = { class: "flex items-center mb-16" }, pt = { class: "flex flex-col gap-9" }, ft = ["onClick"], yt = { class: "fm-typo-en-title-xs-800 min-w-[38px] text-right" }, bt = { class: "fm-typo-en-body-xs-500 text-fm-color-typo-tertiary min-w-[34px] text-right" }, vt = { class: "mt-14 pt-12 border-t border-fm-color-neutral-gray-100 fm-typo-en-body-xs-400 text-fm-color-typo-secondary" }, gt = /* @__PURE__ */ M({
|
|
162
|
-
__name: "LifecycleSegments",
|
|
163
|
-
props: {
|
|
164
|
-
segments: {},
|
|
165
|
-
summary: {},
|
|
166
|
-
interactive: { type: Boolean, default: !0 }
|
|
167
|
-
},
|
|
168
|
-
emits: ["select"],
|
|
169
|
-
setup(e, { emit: s }) {
|
|
170
|
-
const o = e, d = s;
|
|
171
|
-
return (a, l) => {
|
|
172
|
-
const i = g("FmButton"), c = g("FmProgressBar"), p = g("FmCard");
|
|
173
|
-
return u(), C(p, {
|
|
174
|
-
variant: "outlined",
|
|
175
|
-
class: "p-24"
|
|
176
|
-
}, {
|
|
177
|
-
default: N(() => [
|
|
178
|
-
t("div", ut, [
|
|
179
|
-
l[0] || (l[0] = t("div", { class: "flex-1 fm-typo-en-body-md-600" }, "Member lifecycle", -1)),
|
|
180
|
-
b(i, {
|
|
181
|
-
variant: "secondary",
|
|
182
|
-
size: "sm",
|
|
183
|
-
label: "Create campaign"
|
|
184
|
-
})
|
|
185
|
-
]),
|
|
186
|
-
t("div", pt, [
|
|
187
|
-
(u(!0), v(F, null, B(o.segments, (m) => (u(), v("div", {
|
|
188
|
-
key: m.id,
|
|
189
|
-
class: w(["flex items-center gap-9 px-6 py-3 -mx-6 rounded-8", o.interactive ? "cursor-pointer hover:bg-fm-color-neutral-gray-100/50" : "cursor-default"]),
|
|
190
|
-
onClick: (S) => o.interactive && d("select", m.id)
|
|
191
|
-
}, [
|
|
192
|
-
t("span", {
|
|
193
|
-
class: w(["fm-typo-en-body-xs-600 w-[90px] flex-shrink-0", m.labelClass])
|
|
194
|
-
}, n(m.label), 3),
|
|
195
|
-
b(c, {
|
|
196
|
-
class: "flex-1",
|
|
197
|
-
value: m.barPct,
|
|
198
|
-
color: m.barColor,
|
|
199
|
-
size: "md"
|
|
200
|
-
}, null, 8, ["value", "color"]),
|
|
201
|
-
t("span", yt, n(m.countStr), 1),
|
|
202
|
-
t("span", bt, n(m.pctStr), 1)
|
|
203
|
-
], 10, ft))), 128))
|
|
204
|
-
]),
|
|
205
|
-
t("div", vt, n(o.summary), 1)
|
|
206
|
-
]),
|
|
207
|
-
_: 1
|
|
208
|
-
});
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
}), xt = { class: "flex items-center gap-12 mb-16" }, ht = { class: "flex-1" }, _t = { class: "fm-typo-en-body-md-600" }, wt = { class: "fm-typo-en-body-xs-400 text-fm-color-typo-tertiary mt-1" }, $t = { class: "flex items-center gap-8 min-w-0" }, St = { class: "w-[28px] h-[28px] rounded-full bg-[#FFF0E2] flex items-center justify-center fm-typo-en-body-xs-700 text-fm-color-primary flex-shrink-0" }, Ft = { class: "min-w-0" }, Mt = { class: "fm-typo-en-body-sm-600 whitespace-nowrap overflow-hidden text-ellipsis" }, Ct = { class: "fm-typo-en-body-xs-400 text-fm-color-typo-tertiary whitespace-nowrap overflow-hidden text-ellipsis" }, Rt = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary" }, Pt = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary" }, Lt = { class: "fm-typo-en-body-sm-600" }, Dt = { class: "pt-14 flex items-center justify-center gap-4 fm-typo-en-body-xs-400 text-fm-color-typo-tertiary" }, ge = "grid-cols-[1fr_108px_130px_76px_88px]", kt = /* @__PURE__ */ M({
|
|
212
|
-
__name: "MemberDrillDownTable",
|
|
213
|
-
props: {
|
|
214
|
-
title: {},
|
|
215
|
-
countLabel: {},
|
|
216
|
-
members: {}
|
|
217
|
-
},
|
|
218
|
-
emits: ["close"],
|
|
219
|
-
setup(e, { emit: s }) {
|
|
220
|
-
const o = s;
|
|
221
|
-
return (d, a) => {
|
|
222
|
-
const l = g("FmButton"), i = g("FmCard");
|
|
223
|
-
return u(), C(i, {
|
|
224
|
-
variant: "outlined",
|
|
225
|
-
class: "p-24"
|
|
226
|
-
}, {
|
|
227
|
-
default: N(() => [
|
|
228
|
-
t("div", xt, [
|
|
229
|
-
t("div", ht, [
|
|
230
|
-
t("div", _t, n(e.title), 1),
|
|
231
|
-
t("div", wt, n(e.countLabel), 1)
|
|
232
|
-
]),
|
|
233
|
-
b(l, {
|
|
234
|
-
variant: "secondary",
|
|
235
|
-
size: "sm",
|
|
236
|
-
"prepend-icon": "close",
|
|
237
|
-
label: "Close",
|
|
238
|
-
onClick: a[0] || (a[0] = (c) => o("close"))
|
|
239
|
-
})
|
|
240
|
-
]),
|
|
241
|
-
t("div", {
|
|
242
|
-
class: w(["grid gap-8 p-8 bg-[#FAFAFA] rounded-8 mb-2", ge])
|
|
243
|
-
}, [...a[1] || (a[1] = [
|
|
244
|
-
t("span", { class: "fm-typo-en-body-xs-600 text-fm-color-typo-tertiary uppercase tracking-wide" }, "Member", -1),
|
|
245
|
-
t("span", { class: "fm-typo-en-body-xs-600 text-fm-color-typo-tertiary uppercase tracking-wide" }, "Joined", -1),
|
|
246
|
-
t("span", { class: "fm-typo-en-body-xs-600 text-fm-color-typo-tertiary uppercase tracking-wide" }, "Last active", -1),
|
|
247
|
-
t("span", { class: "fm-typo-en-body-xs-600 text-fm-color-typo-tertiary uppercase tracking-wide" }, "Points", -1),
|
|
248
|
-
t("span", { class: "fm-typo-en-body-xs-600 text-fm-color-typo-tertiary uppercase tracking-wide" }, "Status", -1)
|
|
249
|
-
])], 2),
|
|
250
|
-
(u(!0), v(F, null, B(e.members, (c) => (u(), v("div", {
|
|
251
|
-
key: c.email,
|
|
252
|
-
class: w(["grid gap-8 py-12 px-8 border-b border-fm-color-neutral-gray-100 items-center", ge])
|
|
253
|
-
}, [
|
|
254
|
-
t("div", $t, [
|
|
255
|
-
t("div", St, n(c.initials), 1),
|
|
256
|
-
t("div", Ft, [
|
|
257
|
-
t("div", Mt, n(c.name), 1),
|
|
258
|
-
t("div", Ct, n(c.email), 1)
|
|
259
|
-
])
|
|
260
|
-
]),
|
|
261
|
-
t("span", Rt, n(c.joined), 1),
|
|
262
|
-
t("span", Pt, n(c.lastActive), 1),
|
|
263
|
-
t("span", Lt, n(c.points), 1),
|
|
264
|
-
t("span", {
|
|
265
|
-
class: w(["fm-typo-en-body-xs-600 px-9 py-3 rounded-full inline-block whitespace-nowrap w-fit", c.statusClass])
|
|
266
|
-
}, n(c.status), 3)
|
|
267
|
-
], 2))), 128)),
|
|
268
|
-
t("div", Dt, [
|
|
269
|
-
ke(n(e.countLabel) + " · ", 1),
|
|
270
|
-
a[2] || (a[2] = t("a", {
|
|
271
|
-
href: "#",
|
|
272
|
-
class: "text-fm-color-primary fm-typo-en-body-xs-600 no-underline ml-4"
|
|
273
|
-
}, "View all in Members", -1))
|
|
274
|
-
])
|
|
275
|
-
]),
|
|
276
|
-
_: 1
|
|
277
|
-
});
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
}), At = { class: "flex items-start gap-8 mb-20" }, It = { class: "flex-1" }, Bt = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary mt-2" }, Nt = {
|
|
281
|
-
key: 0,
|
|
282
|
-
class: "flex items-start pl-[150px] ml-12"
|
|
283
|
-
}, Tt = { class: "flex flex-col items-start gap-3 py-1" }, jt = { class: "flex items-center gap-6" }, Et = {
|
|
284
|
-
key: 0,
|
|
285
|
-
class: "fm-typo-en-body-xs-600 text-fm-color-typo-warning bg-[#FFF0E2] px-10 py-3 rounded-full whitespace-nowrap"
|
|
286
|
-
}, Vt = ["onClick"], Jt = { class: "w-[140px] flex-shrink-0" }, qt = { class: "fm-typo-en-body-sm-600" }, Ot = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-secondary mt-1" }, zt = { class: "w-[72px] text-right flex-shrink-0" }, Kt = { class: "fm-typo-en-title-xs-800" }, Ut = {
|
|
287
|
-
key: 0,
|
|
288
|
-
class: "fm-typo-en-body-xs-500 text-fm-color-typo-tertiary"
|
|
289
|
-
}, Wt = { class: "mt-14 pt-12 border-t border-fm-color-neutral-gray-100" }, Yt = { class: "fm-typo-en-body-sm-400 text-fm-color-typo-tertiary text-right" }, Ht = /* @__PURE__ */ M({
|
|
290
|
-
__name: "MemberFunnel",
|
|
291
|
-
props: {
|
|
292
|
-
stages: {},
|
|
293
|
-
footnote: {},
|
|
294
|
-
interactive: { type: Boolean, default: !0 }
|
|
295
|
-
},
|
|
296
|
-
emits: ["select"],
|
|
297
|
-
setup(e, { emit: s }) {
|
|
298
|
-
const o = e, d = s;
|
|
299
|
-
function a(l) {
|
|
300
|
-
o.interactive && d("select", l);
|
|
301
|
-
}
|
|
302
|
-
return (l, i) => {
|
|
303
|
-
const c = g("FmProgressBar"), p = g("FmCard");
|
|
304
|
-
return u(), C(p, {
|
|
305
|
-
variant: "outlined",
|
|
306
|
-
class: "p-24"
|
|
307
|
-
}, {
|
|
308
|
-
default: N(() => [
|
|
309
|
-
t("div", At, [
|
|
310
|
-
t("div", It, [
|
|
311
|
-
i[0] || (i[0] = t("div", { class: "fm-typo-en-body-md-600" }, "Member funnel", -1)),
|
|
312
|
-
t("div", Bt, n(o.interactive ? "Strict member-only · visitors excluded · click any stage to drill down" : "Strict member-only · visitors excluded"), 1)
|
|
313
|
-
])
|
|
314
|
-
]),
|
|
315
|
-
(u(!0), v(F, null, B(e.stages, (m, S) => (u(), v("div", {
|
|
316
|
-
key: m.id
|
|
317
|
-
}, [
|
|
318
|
-
m.hasDropLine ? (u(), v("div", Nt, [
|
|
319
|
-
t("div", Tt, [
|
|
320
|
-
i[1] || (i[1] = t("div", { class: "w-[1px] h-[10px] bg-fm-color-neutral-gray-100 ml-[9px]" }, null, -1)),
|
|
321
|
-
t("div", jt, [
|
|
322
|
-
t("span", {
|
|
323
|
-
class: w(["fm-typo-en-body-xs-600 px-10 py-3 rounded-full whitespace-nowrap", m.dropClass])
|
|
324
|
-
}, n(m.conversionStr), 3),
|
|
325
|
-
m.isBiggestDrop ? (u(), v("span", Et, " biggest drop ")) : H("", !0)
|
|
326
|
-
]),
|
|
327
|
-
i[2] || (i[2] = t("div", { class: "w-[1px] h-[10px] bg-fm-color-neutral-gray-100 ml-[9px]" }, null, -1))
|
|
328
|
-
])
|
|
329
|
-
])) : H("", !0),
|
|
330
|
-
t("div", {
|
|
331
|
-
class: w(["flex items-center gap-10 py-7 px-10 -mx-10 rounded-10", o.interactive ? "cursor-pointer hover:bg-fm-color-neutral-gray-100/50" : ""]),
|
|
332
|
-
onClick: (R) => a(m.id)
|
|
333
|
-
}, [
|
|
334
|
-
t("div", Jt, [
|
|
335
|
-
t("div", qt, n(m.label), 1),
|
|
336
|
-
t("div", Ot, n(m.desc), 1)
|
|
337
|
-
]),
|
|
338
|
-
b(c, {
|
|
339
|
-
class: "flex-1",
|
|
340
|
-
value: m.barWidthPct,
|
|
341
|
-
color: m.barColor,
|
|
342
|
-
size: "lg"
|
|
343
|
-
}, null, 8, ["value", "color"]),
|
|
344
|
-
t("div", zt, [
|
|
345
|
-
t("div", Kt, n(m.countStr), 1),
|
|
346
|
-
m.hasConvRate ? (u(), v("div", Ut, n(m.convRateLabel), 1)) : H("", !0)
|
|
347
|
-
])
|
|
348
|
-
], 10, Vt)
|
|
349
|
-
]))), 128)),
|
|
350
|
-
t("div", Wt, [
|
|
351
|
-
t("div", Yt, n(e.footnote), 1)
|
|
352
|
-
])
|
|
353
|
-
]),
|
|
354
|
-
_: 1
|
|
355
|
-
});
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
}), Gt = { class: "grid grid-cols-3 gap-10 mb-16" }, Qt = { class: "fm-typo-en-body-xs-500 text-fm-color-typo-secondary mb-4" }, Xt = { class: "fm-typo-en-title-xs-800" }, Zt = { class: "flex flex-col gap-9" }, es = { class: "flex-1 fm-typo-en-body-sm-400 whitespace-nowrap overflow-hidden text-ellipsis" }, ts = { class: "fm-typo-en-body-xs-600 text-fm-color-typo-secondary flex-shrink-0" }, ss = { class: "w-[48px] h-4 bg-fm-color-neutral-gray-100 rounded-2 overflow-hidden flex-shrink-0" }, as = /* @__PURE__ */ M({
|
|
359
|
-
__name: "RewardPerformance",
|
|
360
|
-
props: {
|
|
361
|
-
kpis: {},
|
|
362
|
-
topRewards: {}
|
|
363
|
-
},
|
|
364
|
-
setup(e) {
|
|
365
|
-
return (s, o) => {
|
|
366
|
-
const d = g("FmCard");
|
|
367
|
-
return u(), C(d, {
|
|
368
|
-
variant: "outlined",
|
|
369
|
-
class: "p-24"
|
|
370
|
-
}, {
|
|
371
|
-
default: N(() => [
|
|
372
|
-
o[1] || (o[1] = t("div", { class: "flex items-center mb-16" }, [
|
|
373
|
-
t("div", { class: "flex-1 fm-typo-en-body-md-600" }, "Reward performance"),
|
|
374
|
-
t("a", {
|
|
375
|
-
href: "#",
|
|
376
|
-
class: "fm-typo-en-body-xs-600 text-fm-color-primary no-underline"
|
|
377
|
-
}, "All rewards")
|
|
378
|
-
], -1)),
|
|
379
|
-
t("div", Gt, [
|
|
380
|
-
(u(!0), v(F, null, B(e.kpis, (a) => (u(), v("div", {
|
|
381
|
-
key: a.label,
|
|
382
|
-
class: "bg-[#FAFAFA] rounded-10 p-12"
|
|
383
|
-
}, [
|
|
384
|
-
t("div", Qt, n(a.label), 1),
|
|
385
|
-
t("div", Xt, n(a.value), 1),
|
|
386
|
-
t("div", {
|
|
387
|
-
class: w(["fm-typo-en-body-xs-600 mt-3", a.deltaClass])
|
|
388
|
-
}, n(a.delta), 3)
|
|
389
|
-
]))), 128))
|
|
390
|
-
]),
|
|
391
|
-
o[2] || (o[2] = t("div", { class: "fm-typo-en-body-xs-600 text-fm-color-typo-tertiary uppercase tracking-wide mb-10" }, " Top redeemed ", -1)),
|
|
392
|
-
t("div", Zt, [
|
|
393
|
-
(u(!0), v(F, null, B(e.topRewards, (a) => (u(), v("div", {
|
|
394
|
-
key: a.name,
|
|
395
|
-
class: "flex items-center gap-9"
|
|
396
|
-
}, [
|
|
397
|
-
o[0] || (o[0] = t("div", { class: "w-6 h-6 rounded-2 bg-fm-color-primary flex-shrink-0" }, null, -1)),
|
|
398
|
-
t("span", es, n(a.name), 1),
|
|
399
|
-
t("span", ts, n(a.count), 1),
|
|
400
|
-
t("div", ss, [
|
|
401
|
-
t("div", {
|
|
402
|
-
class: "h-full bg-fm-color-primary rounded-2",
|
|
403
|
-
style: Ae({ width: a.barPct + "%" })
|
|
404
|
-
}, null, 4)
|
|
405
|
-
])
|
|
406
|
-
]))), 128))
|
|
407
|
-
])
|
|
408
|
-
]),
|
|
409
|
-
_: 1
|
|
410
|
-
});
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
}), rs = { class: "flex items-baseline gap-10 mb-14 flex-wrap" }, os = { class: "fm-typo-en-title-lg-800" }, ns = /* @__PURE__ */ M({
|
|
414
|
-
__name: "SalesTrendChart",
|
|
415
|
-
props: {
|
|
416
|
-
sales: {}
|
|
417
|
-
},
|
|
418
|
-
setup(e) {
|
|
419
|
-
const s = e, o = _(() => [
|
|
420
|
-
{
|
|
421
|
-
label: "This period",
|
|
422
|
-
data: s.sales.series,
|
|
423
|
-
color: "#FF7823",
|
|
424
|
-
fill: !0
|
|
425
|
-
},
|
|
426
|
-
{
|
|
427
|
-
label: "Prev. period",
|
|
428
|
-
data: s.sales.prevSeries,
|
|
429
|
-
color: "#B2B3B6",
|
|
430
|
-
dash: !0
|
|
431
|
-
}
|
|
432
|
-
]), d = { display: !1 };
|
|
433
|
-
return (a, l) => {
|
|
434
|
-
const i = g("FmLineChart"), c = g("FmCard");
|
|
435
|
-
return u(), C(c, {
|
|
436
|
-
variant: "outlined",
|
|
437
|
-
class: "p-24"
|
|
438
|
-
}, {
|
|
439
|
-
default: N(() => [
|
|
440
|
-
l[1] || (l[1] = t("div", { class: "fm-typo-en-body-md-600 mb-6" }, "Member sales trend", -1)),
|
|
441
|
-
t("div", rs, [
|
|
442
|
-
t("span", os, n(e.sales.totalFmt), 1),
|
|
443
|
-
t("span", {
|
|
444
|
-
class: w(["fm-typo-en-body-xs-600 px-9 py-3 rounded-full whitespace-nowrap", e.sales.deltaClass])
|
|
445
|
-
}, n(e.sales.deltaStr), 3),
|
|
446
|
-
l[0] || (l[0] = t("span", { class: "fm-typo-en-body-xs-400 text-fm-color-typo-tertiary" }, "vs prev. period", -1))
|
|
447
|
-
]),
|
|
448
|
-
b(i, {
|
|
449
|
-
datasets: y(o),
|
|
450
|
-
"x-axis": { categories: e.sales.categories },
|
|
451
|
-
"x-cfg": d,
|
|
452
|
-
"y-cfg": d,
|
|
453
|
-
legend: { display: !1 },
|
|
454
|
-
height: "80px"
|
|
455
|
-
}, null, 8, ["datasets", "x-axis"]),
|
|
456
|
-
l[2] || (l[2] = t("div", { class: "flex items-center gap-14 mt-10" }, [
|
|
457
|
-
t("div", { class: "flex items-center gap-5" }, [
|
|
458
|
-
t("div", { class: "w-14 h-2 bg-fm-color-primary rounded-1" }),
|
|
459
|
-
t("span", { class: "fm-typo-en-body-xs-400 text-fm-color-typo-secondary" }, "This period")
|
|
460
|
-
]),
|
|
461
|
-
t("div", { class: "flex items-center gap-5" }, [
|
|
462
|
-
t("div", { class: "w-14 border-t-[1.5px] border-dashed border-fm-color-neutral-gray-200" }),
|
|
463
|
-
t("span", { class: "fm-typo-en-body-xs-400 text-fm-color-typo-secondary" }, "Prev. period")
|
|
464
|
-
])
|
|
465
|
-
], -1))
|
|
466
|
-
]),
|
|
467
|
-
_: 1
|
|
468
|
-
});
|
|
469
|
-
};
|
|
470
|
-
}
|
|
471
|
-
}), A = () => {
|
|
472
|
-
const e = Te.getBusinessId();
|
|
473
|
-
if (!e) throw new Error("Invalid business ID");
|
|
474
|
-
return je(`businesses/${e}/loyalty-dashboard`, {
|
|
475
|
-
noIdRequired: !0
|
|
476
|
-
});
|
|
477
|
-
}, I = {
|
|
478
|
-
async readTotalMembers(e) {
|
|
479
|
-
return k(
|
|
480
|
-
await A().post(
|
|
481
|
-
"metrics/total-members",
|
|
482
|
-
e
|
|
483
|
-
)
|
|
484
|
-
);
|
|
485
|
-
},
|
|
486
|
-
async readActiveMembers(e) {
|
|
487
|
-
return k(
|
|
488
|
-
await A().post(
|
|
489
|
-
"metrics/active-members",
|
|
490
|
-
e
|
|
491
|
-
)
|
|
492
|
-
);
|
|
493
|
-
},
|
|
494
|
-
async readMemberSales(e) {
|
|
495
|
-
return k(
|
|
496
|
-
await A().post("metrics/member-sales", e)
|
|
497
|
-
);
|
|
498
|
-
},
|
|
499
|
-
async readMemberSalesTrend(e) {
|
|
500
|
-
return k(
|
|
501
|
-
await A().post(
|
|
502
|
-
"metrics/member-sales-trend",
|
|
503
|
-
e
|
|
504
|
-
)
|
|
505
|
-
);
|
|
506
|
-
},
|
|
507
|
-
async readRepeatRate(e) {
|
|
508
|
-
return k(
|
|
509
|
-
await A().post("metrics/repeat-rate", e)
|
|
510
|
-
);
|
|
511
|
-
},
|
|
512
|
-
async readVoucherRedemptionRate(e) {
|
|
513
|
-
return k(
|
|
514
|
-
await A().post(
|
|
515
|
-
"metrics/voucher-redemption-rate",
|
|
516
|
-
e
|
|
517
|
-
)
|
|
518
|
-
);
|
|
519
|
-
},
|
|
520
|
-
async readMemberFunnel(e) {
|
|
521
|
-
return k(
|
|
522
|
-
await A().post(
|
|
523
|
-
"metrics/member-funnel",
|
|
524
|
-
e
|
|
525
|
-
)
|
|
526
|
-
);
|
|
527
|
-
},
|
|
528
|
-
async readMemberLifecycle(e) {
|
|
529
|
-
return k(
|
|
530
|
-
await A().post(
|
|
531
|
-
"metrics/member-lifecycle",
|
|
532
|
-
e
|
|
533
|
-
)
|
|
534
|
-
);
|
|
535
|
-
}
|
|
536
|
-
};
|
|
537
|
-
function ls(e, s, o = /* @__PURE__ */ new Date()) {
|
|
538
|
-
const d = z.tz(o, s).endOf("day"), a = d.clone().startOf("day");
|
|
539
|
-
return a.startOf("month"), [a.toISOString(), d.toISOString()];
|
|
540
|
-
}
|
|
541
|
-
function is(e, s) {
|
|
542
|
-
return e.length ? e : s;
|
|
543
|
-
}
|
|
544
|
-
function cs(e) {
|
|
545
|
-
return {
|
|
546
|
-
dateRange: e.dateRange,
|
|
547
|
-
restaurantIds: is(
|
|
548
|
-
e.selectedLocationIds,
|
|
549
|
-
e.locationIds
|
|
550
|
-
),
|
|
551
|
-
timezone: e.timezone
|
|
552
|
-
};
|
|
553
|
-
}
|
|
554
|
-
function ms(e) {
|
|
555
|
-
if (!e.startDate || !e.endDate) return "this-month";
|
|
556
|
-
const s = z(e.endDate).diff(z(e.startDate), "days") + 1;
|
|
557
|
-
return s <= 10 ? "last-7" : s <= 35 ? "this-month" : s <= 100 ? "last-30" : "last-quarter";
|
|
558
|
-
}
|
|
559
|
-
function xe(e) {
|
|
560
|
-
const [s, o] = e, d = z(o).diff(z(s)), a = z(s).subtract(1, "millisecond");
|
|
561
|
-
return [a.clone().subtract(d, "milliseconds").toISOString(), a.toISOString()];
|
|
562
|
-
}
|
|
563
|
-
const ae = {
|
|
564
|
-
"this-month": {
|
|
565
|
-
total: 12847,
|
|
566
|
-
totalNew: 234,
|
|
567
|
-
totalPrev: 12613,
|
|
568
|
-
active: 4621,
|
|
569
|
-
activePrev: 4789,
|
|
570
|
-
purchasing: 2941,
|
|
571
|
-
purchasingPrev: 2841,
|
|
572
|
-
repeat: 1176,
|
|
573
|
-
repeatPrev: 1089,
|
|
574
|
-
redeemers: 353,
|
|
575
|
-
redeemersPrev: 420,
|
|
576
|
-
memberSales: 84320,
|
|
577
|
-
memberSalesPrev: 77814,
|
|
578
|
-
series: [2100, 2400, 2200, 2800, 3100, 2700, 3200, 3600, 3100, 3900, 4200, 3800, 4100, 4600, 4300, 4800, 5200, 4900, 5400, 5100],
|
|
579
|
-
prev: [1800, 2100, 1900, 2400, 2700, 2300, 2800, 3100, 2700, 3400, 3700, 3300, 3600, 4100, 3800, 4300, 4600, 4200, 4800, 4500]
|
|
580
|
-
},
|
|
581
|
-
"last-7": {
|
|
582
|
-
total: 12847,
|
|
583
|
-
totalNew: 52,
|
|
584
|
-
totalPrev: 12795,
|
|
585
|
-
active: 1840,
|
|
586
|
-
activePrev: 1910,
|
|
587
|
-
purchasing: 1102,
|
|
588
|
-
purchasingPrev: 1089,
|
|
589
|
-
repeat: 441,
|
|
590
|
-
repeatPrev: 412,
|
|
591
|
-
redeemers: 128,
|
|
592
|
-
redeemersPrev: 152,
|
|
593
|
-
memberSales: 19240,
|
|
594
|
-
memberSalesPrev: 21300,
|
|
595
|
-
series: [2600, 2400, 2800, 2200, 3100, 2900, 3200],
|
|
596
|
-
prev: [2900, 2700, 3100, 2500, 3300, 3100, 3500]
|
|
597
|
-
},
|
|
598
|
-
"last-30": {
|
|
599
|
-
total: 12847,
|
|
600
|
-
totalNew: 680,
|
|
601
|
-
totalPrev: 12167,
|
|
602
|
-
active: 5840,
|
|
603
|
-
activePrev: 5420,
|
|
604
|
-
purchasing: 3610,
|
|
605
|
-
purchasingPrev: 3240,
|
|
606
|
-
repeat: 1446,
|
|
607
|
-
repeatPrev: 1296,
|
|
608
|
-
redeemers: 462,
|
|
609
|
-
redeemersPrev: 480,
|
|
610
|
-
memberSales: 112400,
|
|
611
|
-
memberSalesPrev: 98600,
|
|
612
|
-
series: [2100, 2400, 2200, 2800, 3100, 2700, 3200, 3600, 3100, 3900, 4200, 3800, 4100, 4600, 4300, 4800, 5200, 4900, 5400, 5100, 4800, 5300, 5600, 5100, 5800, 5500, 5900, 6200, 5800, 6400],
|
|
613
|
-
prev: [1800, 2100, 1900, 2400, 2700, 2300, 2800, 3100, 2700, 3400, 3700, 3300, 3600, 4100, 3800, 4300, 4600, 4200, 4800, 4500, 4200, 4700, 5e3, 4600, 5200, 4900, 5300, 5600, 5200, 5800]
|
|
614
|
-
},
|
|
615
|
-
"last-quarter": {
|
|
616
|
-
total: 12847,
|
|
617
|
-
totalNew: 1840,
|
|
618
|
-
totalPrev: 11007,
|
|
619
|
-
active: 6920,
|
|
620
|
-
activePrev: 5840,
|
|
621
|
-
purchasing: 4290,
|
|
622
|
-
purchasingPrev: 3520,
|
|
623
|
-
repeat: 1802,
|
|
624
|
-
repeatPrev: 1408,
|
|
625
|
-
redeemers: 612,
|
|
626
|
-
redeemersPrev: 504,
|
|
627
|
-
memberSales: 311600,
|
|
628
|
-
memberSalesPrev: 256800,
|
|
629
|
-
series: [35e3, 38e3, 36e3, 42e3, 45e3, 43e3, 48e3, 52e3, 49e3, 55e3, 58e3, 56e3],
|
|
630
|
-
prev: [28e3, 3e4, 29e3, 34e3, 36e3, 34e3, 38e3, 42e3, 4e4, 44e3, 47e3, 46e3]
|
|
631
|
-
}
|
|
632
|
-
}, O = (e, s) => s ? Math.round(e / s * 1e3) / 10 : 0, se = (e, s) => s ? Math.round((e - s) / s * 1e3) / 10 : 0, K = (e) => e >= 1e3 ? (e / 1e3).toFixed(1).replace(/\.0$/, "") + "k" : String(e), ce = (e) => "$" + e.toLocaleString("en-US", {
|
|
633
|
-
minimumFractionDigits: 2,
|
|
634
|
-
maximumFractionDigits: 2
|
|
635
|
-
}), ds = ["neutral-black", "primary", "#FF9C52", "#FFB577", "#FFD0A3"], x = { text: "text-fm-color-typo-success", bg: "bg-fm-color-system-success-100" }, me = { text: "text-fm-color-typo-error", bg: "bg-fm-color-system-error-100" }, G = { text: "text-fm-color-typo-warning", bg: "bg-fm-color-system-warning-100" };
|
|
636
|
-
function Y(e) {
|
|
637
|
-
return e ? x.text : me.text;
|
|
638
|
-
}
|
|
639
|
-
function _e(e) {
|
|
640
|
-
const s = [
|
|
641
|
-
{
|
|
642
|
-
id: "total",
|
|
643
|
-
label: "Total members",
|
|
644
|
-
count: e.totalMembers,
|
|
645
|
-
desc: "All members through period end",
|
|
646
|
-
denom: null
|
|
647
|
-
},
|
|
648
|
-
{
|
|
649
|
-
id: "active",
|
|
650
|
-
label: "Active members",
|
|
651
|
-
count: e.activeMembers,
|
|
652
|
-
desc: "Purchase or reward activity",
|
|
653
|
-
denom: e.totalMembers
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
id: "purchasing",
|
|
657
|
-
label: "Purchase members",
|
|
658
|
-
count: e.purchasingMembers,
|
|
659
|
-
desc: "At least 1 completed order",
|
|
660
|
-
denom: e.activeMembers
|
|
661
|
-
},
|
|
662
|
-
{
|
|
663
|
-
id: "repeat",
|
|
664
|
-
label: "Repeat members",
|
|
665
|
-
count: e.repeatMembers,
|
|
666
|
-
desc: "Had prior order history",
|
|
667
|
-
denom: e.purchasingMembers
|
|
668
|
-
},
|
|
669
|
-
{
|
|
670
|
-
id: "redeemers",
|
|
671
|
-
label: "Reward redeemers",
|
|
672
|
-
count: e.rewardRedeemers,
|
|
673
|
-
desc: "Repeat member used reward",
|
|
674
|
-
denom: e.repeatMembers
|
|
675
|
-
}
|
|
676
|
-
], o = s.map(
|
|
677
|
-
(i, c) => c === 0 || !i.denom ? null : O(i.count, i.denom)
|
|
678
|
-
);
|
|
679
|
-
let d = 1, a = 100;
|
|
680
|
-
return o.forEach((i, c) => {
|
|
681
|
-
c > 0 && i !== null && i < a && (a = i, d = c);
|
|
682
|
-
}), {
|
|
683
|
-
funnelStages: s.map((i, c) => {
|
|
684
|
-
const p = o[c], m = c === d;
|
|
685
|
-
return {
|
|
686
|
-
id: i.id,
|
|
687
|
-
label: i.label,
|
|
688
|
-
desc: i.desc,
|
|
689
|
-
countStr: K(i.count),
|
|
690
|
-
conversionStr: p != null ? `${p}% convert` : "",
|
|
691
|
-
convRateLabel: p != null ? `${p}% of prev` : "",
|
|
692
|
-
hasConvRate: c > 0,
|
|
693
|
-
hasDropLine: c > 0,
|
|
694
|
-
isBiggestDrop: m,
|
|
695
|
-
barColor: ds[c] ?? "#FFD0A3",
|
|
696
|
-
barWidthPct: e.totalMembers > 0 && i.count > 0 ? Math.max(O(i.count, e.totalMembers), 1) : 0,
|
|
697
|
-
dropClass: m ? `${G.text} bg-[#FFF0E2]` : "text-fm-color-typo-secondary bg-fm-color-neutral-gray-100"
|
|
698
|
-
};
|
|
699
|
-
}),
|
|
700
|
-
funnelFootnote: `${e.totalMembers.toLocaleString()} total members`,
|
|
701
|
-
convRates: o,
|
|
702
|
-
biggestDropIdx: d
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
function us(e) {
|
|
706
|
-
const { funnelStages: s, funnelFootnote: o } = _e(e);
|
|
707
|
-
return { funnelStages: s, funnelFootnote: o };
|
|
708
|
-
}
|
|
709
|
-
function ps(e) {
|
|
710
|
-
return {
|
|
711
|
-
categories: e.categories,
|
|
712
|
-
series: e.series,
|
|
713
|
-
prevSeries: e.prevSeries,
|
|
714
|
-
totalFmt: ce(e.memberSales),
|
|
715
|
-
deltaStr: `${e.deltaPct >= 0 ? "+" : ""}${e.deltaPct}%`,
|
|
716
|
-
deltaClass: Y(e.deltaPct >= 0)
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
function we(e) {
|
|
720
|
-
const s = [
|
|
721
|
-
{
|
|
722
|
-
id: "new",
|
|
723
|
-
label: "Newly joined",
|
|
724
|
-
count: e.newlyJoined,
|
|
725
|
-
labelClass: x.text,
|
|
726
|
-
barColor: "typo-success"
|
|
727
|
-
},
|
|
728
|
-
{
|
|
729
|
-
id: "frequent",
|
|
730
|
-
label: "Frequent",
|
|
731
|
-
count: e.frequent,
|
|
732
|
-
labelClass: "text-fm-color-primary",
|
|
733
|
-
barColor: "primary"
|
|
734
|
-
},
|
|
735
|
-
{
|
|
736
|
-
id: "infrequent",
|
|
737
|
-
label: "Infrequent",
|
|
738
|
-
count: e.infrequent,
|
|
739
|
-
labelClass: "text-fm-color-typo-secondary",
|
|
740
|
-
barColor: "neutral-gray-300"
|
|
741
|
-
},
|
|
742
|
-
{
|
|
743
|
-
id: "at-risk",
|
|
744
|
-
label: "At-risk",
|
|
745
|
-
count: e.atRisk,
|
|
746
|
-
labelClass: G.text,
|
|
747
|
-
barColor: "#FFC746"
|
|
748
|
-
},
|
|
749
|
-
{
|
|
750
|
-
id: "dormant",
|
|
751
|
-
label: "Dormant",
|
|
752
|
-
count: e.dormant,
|
|
753
|
-
labelClass: me.text,
|
|
754
|
-
barColor: "#FFCFCC"
|
|
755
|
-
}
|
|
756
|
-
], o = Math.max(...s.map((a) => a.count), 1);
|
|
757
|
-
return {
|
|
758
|
-
lifecycleSegs: s.map((a) => ({
|
|
759
|
-
...a,
|
|
760
|
-
barPct: Math.round(a.count / o * 100),
|
|
761
|
-
pctStr: `${e.totalMembers ? Math.round(a.count / e.totalMembers * 100) : 0}%`,
|
|
762
|
-
countStr: K(a.count)
|
|
763
|
-
})),
|
|
764
|
-
lifecycleSummary: `${K(
|
|
765
|
-
e.atRisk + e.dormant
|
|
766
|
-
)} members are at-risk or dormant`
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
function fs(e) {
|
|
770
|
-
return we(e);
|
|
771
|
-
}
|
|
772
|
-
function ys(e) {
|
|
773
|
-
const s = ae[e] ?? ae["this-month"], o = se(s.memberSales, s.memberSalesPrev), { funnelStages: d, funnelFootnote: a, convRates: l, biggestDropIdx: i } = _e({
|
|
774
|
-
totalMembers: s.total,
|
|
775
|
-
activeMembers: s.active,
|
|
776
|
-
purchasingMembers: s.purchasing,
|
|
777
|
-
repeatMembers: s.repeat,
|
|
778
|
-
rewardRedeemers: s.redeemers
|
|
779
|
-
}), c = {
|
|
780
|
-
1: { title: "Many members are not active", body: `Only ${l[1]}% of members took any action this period. Most who joined have gone quiet — an onboarding or reactivation campaign could help.`, primaryLabel: "Create reactivation campaign", secondaryLabel: "View inactive members", secondaryStage: "total" },
|
|
781
|
-
2: { title: "Active members aren't purchasing", body: `${l[2]}% of active members completed an order. Members are engaging but not buying — review purchase incentives or point triggers.`, primaryLabel: "Review purchase incentives", secondaryLabel: "View non-purchasing members", secondaryStage: "active" },
|
|
782
|
-
3: { title: "Members aren't returning after first purchase", body: `${l[3]}% of purchasing members have repeat history. Most buy once and don't come back — a retention campaign could help.`, primaryLabel: "Create retention campaign", secondaryLabel: "View one-time buyers", secondaryStage: "purchasing" },
|
|
783
|
-
4: { title: "Repeat members aren't using rewards", body: `Only ${l[4]}% of repeat members redeemed a reward. Your most loyal members may not be aware of rewards or find redemption unclear.`, primaryLabel: "Review reward setup", secondaryLabel: "View non-redeeming members", secondaryStage: "repeat" }
|
|
784
|
-
}, m = {
|
|
785
|
-
...c[i] ?? c[4],
|
|
786
|
-
signals: [
|
|
787
|
-
{ text: `${s.active.toLocaleString()} active members — ${l[1]}% of total base this period` },
|
|
788
|
-
{ text: `Member sales ${o >= 0 ? "+" : ""}${o}% — loyalty is ${o >= 0 ? "driving revenue growth" : "lagging behind revenue"}` },
|
|
789
|
-
{ text: `${s.totalNew} new members joined, ${K(s.total - s.totalNew)} are existing base` }
|
|
790
|
-
]
|
|
791
|
-
}, S = O(s.repeat, s.purchasing), R = O(s.repeatPrev, s.purchasingPrev), P = O(s.redeemers, s.repeat), U = O(s.redeemersPrev, s.repeatPrev), L = (Z, D, T, ee, oe, ne = !1) => ({
|
|
792
|
-
label: Z,
|
|
793
|
-
value: D,
|
|
794
|
-
sub: ee,
|
|
795
|
-
delta: `${T >= 0 ? "+" : ""}${T}${ne ? "pp" : "%"}`,
|
|
796
|
-
deltaClass: Y(T >= 0),
|
|
797
|
-
trendUp: T >= 0,
|
|
798
|
-
icon: oe
|
|
799
|
-
}), E = [
|
|
800
|
-
L("Total members", K(s.total), se(s.total, s.totalPrev), `+${s.totalNew} new`, "group"),
|
|
801
|
-
L("Active members", K(s.active), se(s.active, s.activePrev), null, "bolt"),
|
|
802
|
-
L("Member sales", ce(s.memberSales), o, null, "payments"),
|
|
803
|
-
L("Repeat rate", `${S}%`, Math.round((S - R) * 10) / 10, null, "repeat", !0),
|
|
804
|
-
L("Voucher redemption rate", `${P}%`, Math.round((P - U) * 10) / 10, null, "redeem", !0)
|
|
805
|
-
], { lifecycleSegs: V, lifecycleSummary: W } = we({
|
|
806
|
-
totalMembers: s.total,
|
|
807
|
-
newlyJoined: s.totalNew,
|
|
808
|
-
frequent: Math.round(s.active * 0.4),
|
|
809
|
-
infrequent: Math.round(s.active * 0.6),
|
|
810
|
-
atRisk: Math.round((s.total - s.active) * 0.4),
|
|
811
|
-
dormant: Math.round((s.total - s.active) * 0.6)
|
|
812
|
-
}), J = se(s.redeemers, s.redeemersPrev), q = Math.round((P - U) * 10) / 10, h = [
|
|
813
|
-
{ label: "Total redeemed", value: String(s.redeemers), delta: `${J >= 0 ? "+" : ""}${J}%`, deltaClass: Y(J >= 0) },
|
|
814
|
-
{ label: "Redemption rate", value: `${P}%`, delta: `${q >= 0 ? "+" : ""}${q}pp`, deltaClass: Y(q >= 0) },
|
|
815
|
-
{ label: "Avg per member", value: `${(Math.round(s.redeemers / Math.max(s.repeat, 1) * 100) / 100).toFixed(2)}x`, delta: "+0.1x", deltaClass: x.text }
|
|
816
|
-
], Q = [
|
|
817
|
-
{ name: "Flat white freebie", count: "142", barPct: 100 },
|
|
818
|
-
{ name: "$5 cashback voucher", count: "98", barPct: 69 },
|
|
819
|
-
{ name: "50 bonus points", count: "73", barPct: 51 },
|
|
820
|
-
{ name: "Free size upgrade", count: "40", barPct: 28 }
|
|
821
|
-
], X = {
|
|
822
|
-
categories: s.series.map((Z, D) => String(D + 1)),
|
|
823
|
-
series: s.series,
|
|
824
|
-
prevSeries: s.prev,
|
|
825
|
-
totalFmt: ce(s.memberSales),
|
|
826
|
-
deltaStr: `${o >= 0 ? "+" : ""}${o}%`,
|
|
827
|
-
deltaClass: Y(o >= 0)
|
|
828
|
-
}, re = [
|
|
829
|
-
{ name: "Re-engage at-risk members", date: "14 Jun", type: "SMS", metric: "18.4%", metricLabel: "click rate", statusClass: x.text },
|
|
830
|
-
{ name: "Reward push — loyal members", date: "10 Jun", type: "Email", metric: "32.1%", metricLabel: "redemption", statusClass: x.text },
|
|
831
|
-
{ name: "First purchase reward", date: "5 Jun", type: "Push", metric: "8.9%", metricLabel: "conversion", statusClass: G.text },
|
|
832
|
-
{ name: "Dormant win-back offer", date: "1 Jun", type: "Email", metric: "4.2%", metricLabel: "open rate", statusClass: me.text }
|
|
833
|
-
];
|
|
834
|
-
return {
|
|
835
|
-
kpis: E,
|
|
836
|
-
funnelStages: d,
|
|
837
|
-
funnelFootnote: a,
|
|
838
|
-
insight: m,
|
|
839
|
-
lifecycleSegs: V,
|
|
840
|
-
lifecycleSummary: W,
|
|
841
|
-
rewardKpis: h,
|
|
842
|
-
topRewards: Q,
|
|
843
|
-
sales: X,
|
|
844
|
-
campaigns: re
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
|
-
const bs = {
|
|
848
|
-
total: "All members",
|
|
849
|
-
active: "Active members",
|
|
850
|
-
purchasing: "Purchase members",
|
|
851
|
-
repeat: "Repeat members",
|
|
852
|
-
redeemers: "Reward redeemers",
|
|
853
|
-
new: "Newly joined members",
|
|
854
|
-
frequent: "Frequent members",
|
|
855
|
-
infrequent: "Infrequent members",
|
|
856
|
-
"at-risk": "At-risk members",
|
|
857
|
-
dormant: "Dormant members"
|
|
858
|
-
}, he = [
|
|
859
|
-
{ initials: "AT", name: "Aisha Tan", email: "aisha.tan@gmail.com", joined: "12 Jan 2024", lastActive: "15 Jun 2026", points: "1,840", status: "Regular", statusClass: `${x.text} ${x.bg}` },
|
|
860
|
-
{ initials: "WL", name: "Wei Ming Lim", email: "weiming.lim@yahoo.com", joined: "3 Mar 2024", lastActive: "14 Jun 2026", points: "920", status: "Frequent", statusClass: "text-fm-color-primary bg-[#FFF0E2]" },
|
|
861
|
-
{ initials: "FB", name: "Farah Binte Ali", email: "farah.ali@hotmail.com", joined: "21 Apr 2023", lastActive: "13 Jun 2026", points: "3,210", status: "Regular", statusClass: `${x.text} ${x.bg}` },
|
|
862
|
-
{ initials: "RK", name: "Raj Kumar", email: "raj.kumar@gmail.com", joined: "8 Nov 2023", lastActive: "12 Jun 2026", points: "560", status: "Active", statusClass: `${x.text} ${x.bg}` },
|
|
863
|
-
{ initials: "JW", name: "Jennifer Wong", email: "jwong@outlook.com", joined: "15 Jul 2024", lastActive: "10 Jun 2026", points: "240", status: "Active", statusClass: `${x.text} ${x.bg}` },
|
|
864
|
-
{ initials: "AF", name: "Ahmad Faris", email: "ahmad.faris@gmail.com", joined: "2 Feb 2023", lastActive: "8 Jun 2026", points: "4,102", status: "Frequent", statusClass: "text-fm-color-primary bg-[#FFF0E2]" },
|
|
865
|
-
{ initials: "LC", name: "Lily Chen", email: "lily.chen@gmail.com", joined: "19 May 2024", lastActive: "5 Jun 2026", points: "120", status: "New", statusClass: `${x.text} ${x.bg}` },
|
|
866
|
-
{ initials: "MN", name: "Marcus Ng", email: "marcus.ng@yahoo.com", joined: "7 Aug 2023", lastActive: "1 Jun 2026", points: "780", status: "At-risk", statusClass: `${G.text} ${G.bg}` }
|
|
867
|
-
];
|
|
868
|
-
function vs(e, s) {
|
|
869
|
-
const o = ae[s] ?? ae["this-month"], a = {
|
|
870
|
-
total: o.total,
|
|
871
|
-
active: o.active,
|
|
872
|
-
purchasing: o.purchasing,
|
|
873
|
-
repeat: o.repeat,
|
|
874
|
-
redeemers: o.redeemers
|
|
875
|
-
}[e] ?? 0;
|
|
876
|
-
return {
|
|
877
|
-
title: bs[e] ?? "Members",
|
|
878
|
-
countLabel: `Showing ${he.length} of ${a.toLocaleString()} members`,
|
|
879
|
-
members: he
|
|
880
|
-
};
|
|
881
|
-
}
|
|
882
|
-
const gs = { class: "px-24 flex flex-col gap-16 pb-24" }, xs = { class: "flex items-center justify-between gap-8 flex-wrap" }, hs = { class: "flex items-center gap-8 flex-wrap" }, _s = { class: "fm-typo-en-body-xs-400 text-fm-color-typo-tertiary -mt-8 text-right" }, ws = { class: "grid grid-cols-[3fr_2fr] xs:grid-cols-1 gap-16 items-start" }, $s = { class: "grid grid-cols-2 xs:grid-cols-1 gap-16" }, As = /* @__PURE__ */ M({
|
|
883
|
-
__name: "LoyaltyDashboard",
|
|
884
|
-
setup(e) {
|
|
885
|
-
const s = Ee(), o = Ve(), { global: d, minor: a } = Ne, l = _(
|
|
886
|
-
() => ve[o.currentCountry.value || "MY"] ?? ve.MY
|
|
887
|
-
), [i, c] = ls(
|
|
888
|
-
"this-month",
|
|
889
|
-
l.value
|
|
890
|
-
), p = $({
|
|
891
|
-
startDate: i,
|
|
892
|
-
endDate: c
|
|
893
|
-
}), m = $(J(xe([i, c]))), S = $({ location: [] }), R = $(null), P = $(s.locations.length > 0), U = $(!1), L = $({}), E = $(null), V = $(null), W = $(null);
|
|
894
|
-
function J([r, f]) {
|
|
895
|
-
return { startDate: r, endDate: f };
|
|
896
|
-
}
|
|
897
|
-
fe(p, (r) => {
|
|
898
|
-
R.value = null, r.startDate && r.endDate && (m.value = J(
|
|
899
|
-
xe([r.startDate, r.endDate])
|
|
900
|
-
));
|
|
901
|
-
});
|
|
902
|
-
const q = _(() => ms(p.value)), h = _(() => ys(q.value)), Q = _(
|
|
903
|
-
() => E.value ? us(E.value) : {
|
|
904
|
-
funnelStages: h.value.funnelStages,
|
|
905
|
-
funnelFootnote: h.value.funnelFootnote
|
|
906
|
-
}
|
|
907
|
-
), X = _(
|
|
908
|
-
() => V.value ? fs(V.value) : {
|
|
909
|
-
lifecycleSegs: h.value.lifecycleSegs,
|
|
910
|
-
lifecycleSummary: h.value.lifecycleSummary
|
|
911
|
-
}
|
|
912
|
-
), re = _(
|
|
913
|
-
() => W.value ? ps(W.value) : h.value.sales
|
|
914
|
-
), Z = _(() => {
|
|
915
|
-
const r = L.value;
|
|
916
|
-
return h.value.kpis.map((f) => f.label === "Total members" && r.totalMembers != null ? { ...f, value: de(r.totalMembers) } : f.label === "Active members" && r.activeMembers != null ? { ...f, value: de(r.activeMembers) } : f.label === "Member sales" && r.memberSales != null ? { ...f, value: $e(r.memberSales) } : f.label === "Repeat rate" && r.repeatRatePct != null ? { ...f, value: ue(r.repeatRatePct) } : f.label === "Voucher redemption rate" && r.voucherRedemptionRatePct != null ? { ...f, value: ue(r.voucherRedemptionRatePct) } : f);
|
|
917
|
-
}), D = _(
|
|
918
|
-
() => R.value ? vs(R.value, q.value) : null
|
|
919
|
-
), T = _(
|
|
920
|
-
() => s.locations.map((r) => r._id.toString())
|
|
921
|
-
);
|
|
922
|
-
function ee(r) {
|
|
923
|
-
return !r.startDate || !r.endDate ? "" : `${ye(r.startDate).format("D MMM")} – ${ye(r.endDate).format("D MMM YYYY")}`;
|
|
924
|
-
}
|
|
925
|
-
const oe = _(() => ee(p.value)), ne = _(() => ee(m.value));
|
|
926
|
-
function de(r) {
|
|
927
|
-
return r >= 1e3 ? `${(r / 1e3).toFixed(1).replace(/\.0$/, "")}k` : String(r);
|
|
928
|
-
}
|
|
929
|
-
function $e(r) {
|
|
930
|
-
return "$" + r.toLocaleString("en-US", {
|
|
931
|
-
minimumFractionDigits: 2,
|
|
932
|
-
maximumFractionDigits: 2
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
function ue(r) {
|
|
936
|
-
return `${Math.round(r * 10) / 10}%`;
|
|
937
|
-
}
|
|
938
|
-
function Se(r) {
|
|
939
|
-
if (r && typeof r == "object" && "value" in r && Number.isFinite(Number(r.value)))
|
|
940
|
-
return Number(r.value);
|
|
941
|
-
}
|
|
942
|
-
function te() {
|
|
943
|
-
return !p.value.startDate || !p.value.endDate || !P.value || T.value.length === 0 ? null : cs({
|
|
944
|
-
dateRange: [p.value.startDate, p.value.endDate],
|
|
945
|
-
selectedLocationIds: S.value.location,
|
|
946
|
-
locationIds: T.value,
|
|
947
|
-
timezone: l.value
|
|
948
|
-
});
|
|
949
|
-
}
|
|
950
|
-
async function Fe() {
|
|
951
|
-
const r = te();
|
|
952
|
-
if (!r) return;
|
|
953
|
-
const [
|
|
954
|
-
f,
|
|
955
|
-
ie,
|
|
956
|
-
j,
|
|
957
|
-
Le,
|
|
958
|
-
De
|
|
959
|
-
] = await Promise.all([
|
|
960
|
-
I.readTotalMembers(r),
|
|
961
|
-
I.readActiveMembers(r),
|
|
962
|
-
I.readMemberSales(r),
|
|
963
|
-
I.readRepeatRate(r),
|
|
964
|
-
I.readVoucherRedemptionRate(r)
|
|
965
|
-
]);
|
|
966
|
-
L.value = {
|
|
967
|
-
totalMembers: Se(f),
|
|
968
|
-
activeMembers: ie.activeMembers,
|
|
969
|
-
memberSales: j.memberSales,
|
|
970
|
-
repeatRatePct: Le.repeatRatePct,
|
|
971
|
-
voucherRedemptionRatePct: De.voucherRedemptionRatePct
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
async function Me() {
|
|
975
|
-
const r = te();
|
|
976
|
-
r && (E.value = await I.readMemberFunnel(
|
|
977
|
-
r
|
|
978
|
-
));
|
|
979
|
-
}
|
|
980
|
-
async function Ce() {
|
|
981
|
-
const r = te();
|
|
982
|
-
r && (V.value = await I.readMemberLifecycle(
|
|
983
|
-
r
|
|
984
|
-
));
|
|
985
|
-
}
|
|
986
|
-
async function Re() {
|
|
987
|
-
const r = te();
|
|
988
|
-
r && (W.value = await I.readMemberSalesTrend(r));
|
|
989
|
-
}
|
|
990
|
-
async function pe() {
|
|
991
|
-
await Promise.all([
|
|
992
|
-
Fe(),
|
|
993
|
-
Me(),
|
|
994
|
-
Ce(),
|
|
995
|
-
Re()
|
|
996
|
-
]);
|
|
997
|
-
}
|
|
998
|
-
fe([p, () => S.value.location], async () => {
|
|
999
|
-
U.value && await a(pe);
|
|
1000
|
-
}), Ie(async () => {
|
|
1001
|
-
await d(async () => {
|
|
1002
|
-
P.value || await s.readLocations(), P.value = !0, await pe(), U.value = !0;
|
|
1003
|
-
});
|
|
1004
|
-
});
|
|
1005
|
-
function le(r) {
|
|
1006
|
-
R.value = r;
|
|
1007
|
-
}
|
|
1008
|
-
function Pe() {
|
|
1009
|
-
R.value = null;
|
|
1010
|
-
}
|
|
1011
|
-
return (r, f) => {
|
|
1012
|
-
const ie = g("FmPageHead");
|
|
1013
|
-
return u(), v(F, null, [
|
|
1014
|
-
b(ie, { title: "Analytic" }),
|
|
1015
|
-
t("div", gs, [
|
|
1016
|
-
t("div", xs, [
|
|
1017
|
-
b(Be, {
|
|
1018
|
-
label: "Location: ",
|
|
1019
|
-
"right-icon": "keyboard_arrow_down",
|
|
1020
|
-
modelValue: y(S).location,
|
|
1021
|
-
"onUpdate:modelValue": f[0] || (f[0] = (j) => y(S).location = j),
|
|
1022
|
-
icon: "storefront",
|
|
1023
|
-
"show-item-label": !0,
|
|
1024
|
-
items: y(s).locationOptions
|
|
1025
|
-
}, null, 8, ["modelValue", "items"]),
|
|
1026
|
-
t("div", hs, [
|
|
1027
|
-
b(be, {
|
|
1028
|
-
"model-value": y(p),
|
|
1029
|
-
"onUpdate:modelValue": f[1] || (f[1] = (j) => p.value = j)
|
|
1030
|
-
}, null, 8, ["model-value"]),
|
|
1031
|
-
f[3] || (f[3] = t("span", { class: "fm-typo-en-body-xs-600 text-fm-color-typo-tertiary" }, "vs", -1)),
|
|
1032
|
-
b(be, {
|
|
1033
|
-
"model-value": y(m),
|
|
1034
|
-
"onUpdate:modelValue": f[2] || (f[2] = (j) => m.value = j)
|
|
1035
|
-
}, null, 8, ["model-value"])
|
|
1036
|
-
])
|
|
1037
|
-
]),
|
|
1038
|
-
t("div", _s, n(y(oe)) + " · vs. " + n(y(ne)), 1),
|
|
1039
|
-
b(dt, { kpis: y(Z) }, null, 8, ["kpis"]),
|
|
1040
|
-
t("section", ws, [
|
|
1041
|
-
b(Ht, {
|
|
1042
|
-
stages: y(Q).funnelStages,
|
|
1043
|
-
footnote: y(Q).funnelFootnote,
|
|
1044
|
-
interactive: !y(E),
|
|
1045
|
-
onSelect: le
|
|
1046
|
-
}, null, 8, ["stages", "footnote", "interactive"]),
|
|
1047
|
-
b(at, {
|
|
1048
|
-
insight: y(h).insight,
|
|
1049
|
-
onViewSegment: le
|
|
1050
|
-
}, null, 8, ["insight"])
|
|
1051
|
-
]),
|
|
1052
|
-
t("section", $s, [
|
|
1053
|
-
b(gt, {
|
|
1054
|
-
segments: y(X).lifecycleSegs,
|
|
1055
|
-
summary: y(X).lifecycleSummary,
|
|
1056
|
-
interactive: !y(V),
|
|
1057
|
-
onSelect: le
|
|
1058
|
-
}, null, 8, ["segments", "summary", "interactive"]),
|
|
1059
|
-
b(as, {
|
|
1060
|
-
kpis: y(h).rewardKpis,
|
|
1061
|
-
"top-rewards": y(h).topRewards
|
|
1062
|
-
}, null, 8, ["kpis", "top-rewards"]),
|
|
1063
|
-
b(ns, { sales: y(re) }, null, 8, ["sales"]),
|
|
1064
|
-
b(Ye, {
|
|
1065
|
-
campaigns: y(h).campaigns
|
|
1066
|
-
}, null, 8, ["campaigns"])
|
|
1067
|
-
]),
|
|
1068
|
-
y(D) ? (u(), C(kt, {
|
|
1069
|
-
key: 0,
|
|
1070
|
-
title: y(D).title,
|
|
1071
|
-
"count-label": y(D).countLabel,
|
|
1072
|
-
members: y(D).members,
|
|
1073
|
-
onClose: Pe
|
|
1074
|
-
}, null, 8, ["title", "count-label", "members"])) : H("", !0)
|
|
1075
|
-
])
|
|
1076
|
-
], 64);
|
|
1077
|
-
};
|
|
1078
|
-
}
|
|
1079
|
-
});
|
|
1080
|
-
export {
|
|
1081
|
-
As as default
|
|
1082
|
-
};
|