@ketvietlab/ketsuite 0.1.5 → 0.1.6
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/cli.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modules/backend/design/HANDOFF.md +2 -2
- package/dist/modules/backend/design/auth.css +12 -0
- package/dist/modules/backend/design/client/table-selection.d.mts +3 -3
- package/dist/modules/backend/design/client/table-selection.d.mts.map +1 -1
- package/dist/modules/backend/design/client/table-selection.mjs +1 -1
- package/dist/modules/backend/design/client/table-selection.mjs.map +4 -4
- package/dist/modules/backend/design/design-system.css +1 -1
- package/dist/modules/backend/design/forms.css +62 -1
- package/dist/modules/backend/design/lists.css +26 -18
- package/dist/modules/backend/design/record.css +5 -2
- package/dist/modules/backend/design/responsive.css +5 -1
- package/dist/modules/backend/design/user-workflow.css +257 -0
- package/dist/modules/backend/index.d.ts.map +1 -1
- package/dist/modules/backend/index.js +1 -0
- package/dist/modules/backend/index.js.map +1 -1
- package/dist/modules/backend/messages.d.ts.map +1 -1
- package/dist/modules/backend/messages.js +2 -0
- package/dist/modules/backend/messages.js.map +1 -1
- package/dist/modules/crm/functions.d.ts +5 -0
- package/dist/modules/crm/functions.d.ts.map +1 -1
- package/dist/modules/crm/functions.js +105 -10
- package/dist/modules/crm/functions.js.map +1 -1
- package/dist/modules/crm/jobs.d.ts.map +1 -1
- package/dist/modules/crm/jobs.js +1 -0
- package/dist/modules/crm/jobs.js.map +1 -1
- package/dist/modules/crm/operations.d.ts.map +1 -1
- package/dist/modules/crm/operations.js +2 -1
- package/dist/modules/crm/operations.js.map +1 -1
- package/dist/modules/crm_backend/index.d.ts.map +1 -1
- package/dist/modules/crm_backend/index.js +5 -2
- package/dist/modules/crm_backend/index.js.map +1 -1
- package/dist/modules/crm_backend/messages.d.ts +116 -0
- package/dist/modules/crm_backend/messages.d.ts.map +1 -1
- package/dist/modules/crm_backend/messages.js +122 -6
- package/dist/modules/crm_backend/messages.js.map +1 -1
- package/dist/modules/crm_backend/routes.d.ts.map +1 -1
- package/dist/modules/crm_backend/routes.js +434 -174
- package/dist/modules/crm_backend/routes.js.map +1 -1
- package/dist/modules/crm_backend/screens/case-create.d.ts +7 -0
- package/dist/modules/crm_backend/screens/case-create.d.ts.map +1 -1
- package/dist/modules/crm_backend/screens/case-create.js +13 -4
- package/dist/modules/crm_backend/screens/case-create.js.map +1 -1
- package/dist/modules/crm_backend/screens/case-detail.d.ts +6 -0
- package/dist/modules/crm_backend/screens/case-detail.d.ts.map +1 -1
- package/dist/modules/crm_backend/screens/case-detail.js +73 -23
- package/dist/modules/crm_backend/screens/case-detail.js.map +1 -1
- package/dist/modules/crm_backend/screens/configuration.d.ts +21 -3
- package/dist/modules/crm_backend/screens/configuration.d.ts.map +1 -1
- package/dist/modules/crm_backend/screens/configuration.js +260 -55
- package/dist/modules/crm_backend/screens/configuration.js.map +1 -1
- package/dist/modules/crm_backend/screens/index.d.ts +3 -3
- package/dist/modules/crm_backend/screens/index.d.ts.map +1 -1
- package/dist/modules/crm_backend/screens/index.js +2 -2
- package/dist/modules/crm_backend/screens/index.js.map +1 -1
- package/dist/modules/loyalty/admin-functions.d.ts +2 -0
- package/dist/modules/loyalty/admin-functions.d.ts.map +1 -1
- package/dist/modules/loyalty/admin-functions.js +96 -20
- package/dist/modules/loyalty/admin-functions.js.map +1 -1
- package/dist/modules/loyalty/engine.d.ts +4 -1
- package/dist/modules/loyalty/engine.d.ts.map +1 -1
- package/dist/modules/loyalty/engine.js +125 -18
- package/dist/modules/loyalty/engine.js.map +1 -1
- package/dist/modules/loyalty/index.d.ts.map +1 -1
- package/dist/modules/loyalty/index.js +4 -3
- package/dist/modules/loyalty/index.js.map +1 -1
- package/dist/modules/loyalty/jobs.d.ts.map +1 -1
- package/dist/modules/loyalty/jobs.js +0 -1
- package/dist/modules/loyalty/jobs.js.map +1 -1
- package/dist/modules/loyalty/membership-functions.d.ts +5 -0
- package/dist/modules/loyalty/membership-functions.d.ts.map +1 -1
- package/dist/modules/loyalty/membership-functions.js +37 -23
- package/dist/modules/loyalty/membership-functions.js.map +1 -1
- package/dist/modules/loyalty/messages.d.ts +14 -0
- package/dist/modules/loyalty/messages.d.ts.map +1 -1
- package/dist/modules/loyalty/messages.js +14 -0
- package/dist/modules/loyalty/messages.js.map +1 -1
- package/dist/modules/loyalty/models.d.ts.map +1 -1
- package/dist/modules/loyalty/models.js +17 -0
- package/dist/modules/loyalty/models.js.map +1 -1
- package/dist/modules/loyalty/order-functions.d.ts.map +1 -1
- package/dist/modules/loyalty/order-functions.js +70 -17
- package/dist/modules/loyalty/order-functions.js.map +1 -1
- package/dist/modules/loyalty/program-design.d.ts +11 -0
- package/dist/modules/loyalty/program-design.d.ts.map +1 -0
- package/dist/modules/loyalty/program-design.js +356 -0
- package/dist/modules/loyalty/program-design.js.map +1 -0
- package/dist/modules/loyalty/stats.d.ts +0 -13
- package/dist/modules/loyalty/stats.d.ts.map +1 -1
- package/dist/modules/loyalty/stats.js +11 -6
- package/dist/modules/loyalty/stats.js.map +1 -1
- package/dist/modules/loyalty/stored-value.d.ts.map +1 -1
- package/dist/modules/loyalty/stored-value.js +7 -2
- package/dist/modules/loyalty/stored-value.js.map +1 -1
- package/dist/modules/loyalty/types.d.ts +1 -1
- package/dist/modules/loyalty/types.d.ts.map +1 -1
- package/dist/modules/loyalty_backend/design-messages.d.ts +221 -0
- package/dist/modules/loyalty_backend/design-messages.d.ts.map +1 -0
- package/dist/modules/loyalty_backend/design-messages.js +221 -0
- package/dist/modules/loyalty_backend/design-messages.js.map +1 -0
- package/dist/modules/loyalty_backend/index.js +224 -412
- package/dist/modules/loyalty_backend/index.js.map +1 -1
- package/dist/modules/loyalty_backend/messages.d.ts +642 -214
- package/dist/modules/loyalty_backend/messages.d.ts.map +1 -1
- package/dist/modules/loyalty_backend/messages.js +19 -13
- package/dist/modules/loyalty_backend/messages.js.map +1 -1
- package/dist/modules/loyalty_backend/program-workspace.d.ts +4 -0
- package/dist/modules/loyalty_backend/program-workspace.d.ts.map +1 -0
- package/dist/modules/loyalty_backend/program-workspace.js +600 -0
- package/dist/modules/loyalty_backend/program-workspace.js.map +1 -0
- package/dist/modules/loyalty_backend/screens/index.d.ts +12 -36
- package/dist/modules/loyalty_backend/screens/index.d.ts.map +1 -1
- package/dist/modules/loyalty_backend/screens/index.js +148 -292
- package/dist/modules/loyalty_backend/screens/index.js.map +1 -1
- package/dist/modules/loyalty_backend/screens/page-frame.d.ts.map +1 -1
- package/dist/modules/loyalty_backend/screens/page-frame.js +2 -2
- package/dist/modules/loyalty_backend/screens/page-frame.js.map +1 -1
- package/dist/modules/loyalty_pos/functions.d.ts.map +1 -1
- package/dist/modules/loyalty_pos/functions.js +1 -0
- package/dist/modules/loyalty_pos/functions.js.map +1 -1
- package/dist/modules/loyalty_pos/index.js +1 -1
- package/dist/modules/loyalty_pos/index.js.map +1 -1
- package/dist/modules/loyalty_sale/functions.d.ts +1 -0
- package/dist/modules/loyalty_sale/functions.d.ts.map +1 -1
- package/dist/modules/loyalty_sale/functions.js +1 -0
- package/dist/modules/loyalty_sale/functions.js.map +1 -1
- package/dist/modules/partner_backend/client/partner.css +3 -1
- package/dist/modules/partner_backend/index.d.ts.map +1 -1
- package/dist/modules/partner_backend/index.js +4 -0
- package/dist/modules/partner_backend/index.js.map +1 -1
- package/dist/modules/partner_backend/routes.d.ts.map +1 -1
- package/dist/modules/partner_backend/routes.js +6 -1
- package/dist/modules/partner_backend/routes.js.map +1 -1
- package/dist/modules/partner_backend/screens/form.d.ts +1 -0
- package/dist/modules/partner_backend/screens/form.d.ts.map +1 -1
- package/dist/modules/partner_backend/screens/form.js +1 -0
- package/dist/modules/partner_backend/screens/form.js.map +1 -1
- package/dist/modules/user/authorization.d.ts +64 -1
- package/dist/modules/user/authorization.d.ts.map +1 -1
- package/dist/modules/user/authorization.js +445 -53
- package/dist/modules/user/authorization.js.map +1 -1
- package/dist/modules/user/functions.d.ts.map +1 -1
- package/dist/modules/user/functions.js +45 -23
- package/dist/modules/user/functions.js.map +1 -1
- package/dist/modules/user/index.d.ts +2 -1
- package/dist/modules/user/index.d.ts.map +1 -1
- package/dist/modules/user/index.js +1 -1
- package/dist/modules/user/index.js.map +1 -1
- package/dist/modules/user/models.d.ts.map +1 -1
- package/dist/modules/user/models.js +5 -0
- package/dist/modules/user/models.js.map +1 -1
- package/dist/modules/user/roles.d.ts.map +1 -1
- package/dist/modules/user/roles.js +2 -1
- package/dist/modules/user/roles.js.map +1 -1
- package/dist/modules/user_backend/access-routes.d.ts +31 -0
- package/dist/modules/user_backend/access-routes.d.ts.map +1 -0
- package/dist/modules/user_backend/access-routes.js +447 -0
- package/dist/modules/user_backend/access-routes.js.map +1 -0
- package/dist/modules/user_backend/index.d.ts +1 -0
- package/dist/modules/user_backend/index.d.ts.map +1 -1
- package/dist/modules/user_backend/index.js +1 -0
- package/dist/modules/user_backend/index.js.map +1 -1
- package/dist/modules/user_backend/routes.d.ts.map +1 -1
- package/dist/modules/user_backend/routes.js +10 -2
- package/dist/modules/user_backend/routes.js.map +1 -1
- package/dist/permission-catalogue.d.ts.map +1 -1
- package/dist/permission-catalogue.js +7 -0
- package/dist/permission-catalogue.js.map +1 -1
- package/dist/scaffold/index.js +1 -1
- package/dist/ui/client/table-selection-view.d.ts.map +1 -1
- package/dist/ui/client/table-selection-view.js +95 -1
- package/dist/ui/client/table-selection-view.js.map +1 -1
- package/dist/ui/client/user-workflow.d.ts +2 -0
- package/dist/ui/client/user-workflow.d.ts.map +1 -0
- package/dist/ui/client/user-workflow.js +141 -0
- package/dist/ui/client/user-workflow.js.map +1 -0
- package/dist/ui/form.d.ts +7 -0
- package/dist/ui/form.d.ts.map +1 -1
- package/dist/ui/form.js +28 -15
- package/dist/ui/form.js.map +1 -1
- package/dist/ui/icons.d.ts.map +1 -1
- package/dist/ui/icons.js +2 -0
- package/dist/ui/icons.js.map +1 -1
- package/dist/ui/index.d.ts +5 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +4 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/layout.d.ts.map +1 -1
- package/dist/ui/layout.js +14 -4
- package/dist/ui/layout.js.map +1 -1
- package/dist/ui/nav.d.ts.map +1 -1
- package/dist/ui/nav.js +2 -1
- package/dist/ui/nav.js.map +1 -1
- package/dist/ui/table.js +1 -1
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/user-workflow.d.ts +72 -0
- package/dist/ui/user-workflow.d.ts.map +1 -0
- package/dist/ui/user-workflow.js +144 -0
- package/dist/ui/user-workflow.js.map +1 -0
- package/package.json +8 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "@ketvietlab/ketjs-view/jsx-runtime";
|
|
2
|
-
import { badge, CardGrid, code, actionGroup, ContentCard, dataTable, DashboardPage, DefinitionList, Delta, emptyState,
|
|
2
|
+
import { badge, CardGrid, code, actionGroup, ContentCard, dataTable, DashboardPage, DefinitionList, Delta, emptyState, icon, linkButton, Metric, ModalSheet, modalWorkspace, Notice, RecordForm, RecordWorkspace, RecordScreen, Section, shell, stack, Surface, Tabs, WorkspaceScreen, } from '../../../ui/index.js';
|
|
3
3
|
import { selectionLabel } from '../../backend/screen.js';
|
|
4
4
|
import { FormScreenFrame, ListScreenFrame } from './page-frame.js';
|
|
5
5
|
const empty = (_) => emptyState(_('loyalty_backend.empty.title'), _('loyalty_backend.empty.hint'));
|
|
@@ -63,6 +63,10 @@ const walletStateBadge = (_, wallet) => {
|
|
|
63
63
|
};
|
|
64
64
|
/** Where a program stands in its own calendar. */
|
|
65
65
|
const programStateBadge = (_, program) => {
|
|
66
|
+
if (program.phase === 'draft')
|
|
67
|
+
return badge(_('loyalty_backend.state.draft'), 'neutral');
|
|
68
|
+
if (program.state)
|
|
69
|
+
return badge(_(`loyalty_backend.state.${String(program.state)}`), program.state === 'running' ? 'positive' : 'neutral');
|
|
66
70
|
// is what this module's own archive action writes, so that is
|
|
67
71
|
// what the badge says. A program the operator paused and one they retired are
|
|
68
72
|
// the same row here, and inventing a second word for it would claim otherwise.
|
|
@@ -78,8 +82,8 @@ const programStateBadge = (_, program) => {
|
|
|
78
82
|
/** The window a program runs in, or that it never closes. */
|
|
79
83
|
const periodOf = (_, program) => {
|
|
80
84
|
const day = (value) => (value ? String(value).slice(0, 10) : null);
|
|
81
|
-
const start = day(program.dateFrom);
|
|
82
|
-
const end = day(program.dateTo);
|
|
85
|
+
const start = day(program.startDate ?? program.dateFrom);
|
|
86
|
+
const end = day(program.endDate ?? program.dateTo);
|
|
83
87
|
if (!start && !end)
|
|
84
88
|
return _('loyalty_backend.period.always');
|
|
85
89
|
if (start && !end)
|
|
@@ -114,7 +118,7 @@ export const dashboardScreen = (_, frame, stats) => shell(_, _('loyalty_backend.
|
|
|
114
118
|
id: 'members',
|
|
115
119
|
title: _('loyalty_backend.menu.memberships'),
|
|
116
120
|
value: stats.members,
|
|
117
|
-
href: '/admin/loyalty/
|
|
121
|
+
href: '/admin/loyalty/tiers',
|
|
118
122
|
},
|
|
119
123
|
{
|
|
120
124
|
id: 'ledger',
|
|
@@ -133,9 +137,28 @@ export const dashboardScreen = (_, frame, stats) => shell(_, _('loyalty_backend.
|
|
|
133
137
|
* figures above count them apart and the badge in the row says which is which
|
|
134
138
|
* without anyone opening it.
|
|
135
139
|
*/
|
|
136
|
-
export const programsScreen = (_, frame, programs, totals,
|
|
140
|
+
export const programsScreen = (_, frame, programs, totals, _createFields, _errors = []) => (_jsx(ListScreenFrame, { translator: _, title: _('loyalty_backend.programs.title'), subtitle: _('loyalty_backend.programs.hint'), frame: {
|
|
141
|
+
...frame,
|
|
142
|
+
extras: {
|
|
143
|
+
...frame.extras,
|
|
144
|
+
'topbar.end': linkButton({
|
|
145
|
+
label: _('loyalty_backend.action.createProgram'),
|
|
146
|
+
href: '/admin/loyalty/programs/new',
|
|
147
|
+
variant: 'primary',
|
|
148
|
+
}),
|
|
149
|
+
},
|
|
150
|
+
}, body: stack([
|
|
137
151
|
statRow([
|
|
138
|
-
{
|
|
152
|
+
{
|
|
153
|
+
id: 'total',
|
|
154
|
+
label: _('loyalty_backend.stat.programs'),
|
|
155
|
+
value: figure(totals.total),
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
id: 'draft',
|
|
159
|
+
label: _('loyalty_backend.state.draft'),
|
|
160
|
+
value: figure(totals.draft),
|
|
161
|
+
},
|
|
139
162
|
{
|
|
140
163
|
id: 'running',
|
|
141
164
|
label: _('loyalty_backend.stat.running'),
|
|
@@ -154,21 +177,23 @@ export const programsScreen = (_, frame, programs, totals, createFields, errors
|
|
|
154
177
|
value: figure(totals.archived),
|
|
155
178
|
detail: _('loyalty_backend.stat.archivedHint'),
|
|
156
179
|
},
|
|
157
|
-
{
|
|
180
|
+
{
|
|
181
|
+
id: 'ended',
|
|
182
|
+
label: _('loyalty_backend.stat.ended'),
|
|
183
|
+
value: figure(totals.ended),
|
|
184
|
+
},
|
|
158
185
|
]),
|
|
159
186
|
programs.length
|
|
160
187
|
? dataTable(_, {
|
|
161
188
|
rows: programs,
|
|
189
|
+
rowHref: (row) => `/admin/loyalty/programs/${encodeURIComponent(String(row.id))}`,
|
|
190
|
+
rowLink: false,
|
|
162
191
|
id: (row) => String(row.id),
|
|
163
192
|
columns: [
|
|
164
193
|
{
|
|
165
194
|
key: 'name',
|
|
166
195
|
label: _('loyalty_backend.field.name'),
|
|
167
|
-
cell: (row) =>
|
|
168
|
-
label: String(row.name),
|
|
169
|
-
href: `/admin/loyalty/programs/${String(row.id)}`,
|
|
170
|
-
variant: 'tertiary',
|
|
171
|
-
}),
|
|
196
|
+
cell: (row) => String(row.name),
|
|
172
197
|
priority: 'primary',
|
|
173
198
|
},
|
|
174
199
|
{
|
|
@@ -201,160 +226,19 @@ export const programsScreen = (_, frame, programs, totals, createFields, errors
|
|
|
201
226
|
],
|
|
202
227
|
})
|
|
203
228
|
: empty(_),
|
|
204
|
-
_jsx(Section, { title: _('loyalty_backend.action.createProgram'), body: _jsx(Surface, { body: _jsx(RecordForm, { action: "/admin/loyalty/programs", fields: createFields, errors: errors, submit: _('loyalty_backend.action.createProgram'), submitVariant: "primary" }) }) }),
|
|
205
229
|
]) }));
|
|
206
|
-
/**
|
|
207
|
-
* One program, in the three questions it is set up by.
|
|
208
|
-
*
|
|
209
|
-
* What it is, how points are earned, and what they buy — three tabs rather than
|
|
210
|
-
* three sections down one page, because they are edited on separate occasions
|
|
211
|
-
* and each carries a form. Stacked, adding a reward meant scrolling past every
|
|
212
|
-
* rule to reach the form for it.
|
|
213
|
-
*
|
|
214
|
-
* The settings form stays on the first tab with the identity strip above it, so
|
|
215
|
-
* the state of the program is visible while it is being changed.
|
|
216
|
-
*/
|
|
217
|
-
export const programDetailScreen = (_, frame, program, options) => {
|
|
218
|
-
const rules = program.rules ?? [];
|
|
219
|
-
const rewards = program.rewards ?? [];
|
|
220
|
-
const here = `/admin/loyalty/programs/${String(program.id)}`;
|
|
221
|
-
const tab = options.tab === 'rules' || options.tab === 'rewards' ? options.tab : 'overview';
|
|
222
|
-
const rulesPane = (_jsx(Section, { title: _('loyalty_backend.rules.title'), description: _('loyalty_backend.rules.hint'), body: stack([
|
|
223
|
-
...(rules.length
|
|
224
|
-
? [
|
|
225
|
-
dataTable(_, {
|
|
226
|
-
rows: rules,
|
|
227
|
-
id: (row) => String(row.id),
|
|
228
|
-
columns: [
|
|
229
|
-
{
|
|
230
|
-
key: 'priority',
|
|
231
|
-
label: _('loyalty_backend.field.priority'),
|
|
232
|
-
cell: (row) => String(row.priority),
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
key: 'mode',
|
|
236
|
-
label: _('loyalty_backend.field.mode'),
|
|
237
|
-
cell: (row) => labelOf(_, 'trigger', row.mode),
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
key: 'points',
|
|
241
|
-
label: _('loyalty_backend.field.pointAmount'),
|
|
242
|
-
cell: (row) => String(row.pointAmount),
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
key: 'basis',
|
|
246
|
-
label: _('loyalty_backend.field.pointMode'),
|
|
247
|
-
cell: (row) => labelOf(_, 'pointMode', row.pointMode),
|
|
248
|
-
},
|
|
249
|
-
{
|
|
250
|
-
key: 'code',
|
|
251
|
-
label: _('loyalty_backend.field.code'),
|
|
252
|
-
cell: (row) => code(row.code ? String(row.code) : '—'),
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
key: 'state',
|
|
256
|
-
label: _('loyalty_backend.field.state'),
|
|
257
|
-
cell: (row) => activeBadge(_, row.active),
|
|
258
|
-
},
|
|
259
|
-
],
|
|
260
|
-
}),
|
|
261
|
-
]
|
|
262
|
-
: []),
|
|
263
|
-
_jsx(Surface, { body: _jsx(RecordForm, { action: here, hidden: { action: 'add-rule' }, fields: options.ruleFields, submit: _('loyalty_backend.action.addRule'), submitVariant: "secondary" }) }),
|
|
264
|
-
]) }));
|
|
265
|
-
const rewardsPane = (_jsx(Section, { title: _('loyalty_backend.rewards.title'), description: _('loyalty_backend.rewards.hint'), body: stack([
|
|
266
|
-
...(rewards.length
|
|
267
|
-
? [
|
|
268
|
-
dataTable(_, {
|
|
269
|
-
rows: rewards,
|
|
270
|
-
id: (row) => String(row.id),
|
|
271
|
-
columns: [
|
|
272
|
-
{
|
|
273
|
-
key: 'description',
|
|
274
|
-
label: _('loyalty_backend.field.description'),
|
|
275
|
-
cell: (row) => String(row.description),
|
|
276
|
-
priority: 'primary',
|
|
277
|
-
},
|
|
278
|
-
{
|
|
279
|
-
key: 'type',
|
|
280
|
-
label: _('loyalty_backend.field.rewardType'),
|
|
281
|
-
cell: (row) => labelOf(_, 'rewardType', row.rewardType),
|
|
282
|
-
},
|
|
283
|
-
{
|
|
284
|
-
key: 'points',
|
|
285
|
-
label: _('loyalty_backend.field.requiredPoints'),
|
|
286
|
-
cell: (row) => String(row.requiredPoints),
|
|
287
|
-
},
|
|
288
|
-
{
|
|
289
|
-
key: 'discount',
|
|
290
|
-
label: _('loyalty_backend.field.discount'),
|
|
291
|
-
cell: (row) => String(row.discount),
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
key: 'state',
|
|
295
|
-
label: _('loyalty_backend.field.state'),
|
|
296
|
-
cell: (row) => activeBadge(_, row.active),
|
|
297
|
-
},
|
|
298
|
-
],
|
|
299
|
-
}),
|
|
300
|
-
]
|
|
301
|
-
: []),
|
|
302
|
-
_jsx(Surface, { body: _jsx(RecordForm, { action: here, hidden: { action: 'add-reward' }, fields: options.rewardFields, submit: _('loyalty_backend.action.addReward'), submitVariant: "secondary" }) }),
|
|
303
|
-
]) }));
|
|
304
|
-
return (_jsx(FormScreenFrame, { translator: _, title: String(program.name), frame: frame, body: _jsx(RecordWorkspace, { kicker: _('loyalty_backend.menu.programs'), title: String(program.name), subtitle: periodOf(_, program), imageFallback: icon('gift'), status: programStateBadge(_, program), badges: [
|
|
305
|
-
badge(labelOf(_, 'programType', program.programType), 'info', String(program.programType)),
|
|
306
|
-
badge(labelOf(_, 'trigger', program.trigger), 'neutral', String(program.trigger)),
|
|
307
|
-
], summary: [
|
|
308
|
-
{
|
|
309
|
-
id: 'points',
|
|
310
|
-
label: _('loyalty_backend.field.pointName'),
|
|
311
|
-
value: String(program.pointName ?? '—'),
|
|
312
|
-
},
|
|
313
|
-
{ id: 'rules', label: _('loyalty_backend.rules.title'), value: rules.length },
|
|
314
|
-
{ id: 'rewards', label: _('loyalty_backend.rewards.title'), value: rewards.length },
|
|
315
|
-
], navigation: _jsx(Tabs, { label: _('loyalty_backend.program.detail'), items: [
|
|
316
|
-
{
|
|
317
|
-
id: 'overview',
|
|
318
|
-
label: _('loyalty_backend.tab.overview'),
|
|
319
|
-
href: here,
|
|
320
|
-
active: tab === 'overview',
|
|
321
|
-
},
|
|
322
|
-
{
|
|
323
|
-
id: 'rules',
|
|
324
|
-
label: _('loyalty_backend.tab.rules'),
|
|
325
|
-
href: `${here}?tab=rules`,
|
|
326
|
-
active: tab === 'rules',
|
|
327
|
-
count: rules.length,
|
|
328
|
-
},
|
|
329
|
-
{
|
|
330
|
-
id: 'rewards',
|
|
331
|
-
label: _('loyalty_backend.tab.rewards'),
|
|
332
|
-
href: `${here}?tab=rewards`,
|
|
333
|
-
active: tab === 'rewards',
|
|
334
|
-
count: rewards.length,
|
|
335
|
-
},
|
|
336
|
-
] }), controller: _jsx(RecordActions, { action: here, actions: [
|
|
337
|
-
{
|
|
338
|
-
value: program.active ? 'archive' : 'restore',
|
|
339
|
-
label: program.active
|
|
340
|
-
? _('loyalty_backend.action.archive')
|
|
341
|
-
: _('loyalty_backend.action.restore'),
|
|
342
|
-
variant: program.active ? 'destructive' : 'secondary',
|
|
343
|
-
},
|
|
344
|
-
] }), body: tab === 'rules' ? (rulesPane) : tab === 'rewards' ? (rewardsPane) : (_jsx(Section, { title: _('loyalty_backend.program.detail'), body: _jsx(Surface, { body: _jsx(RecordForm, { action: here, hidden: { action: 'save-program' }, fields: options.programFields, errors: options.errors, submit: _('loyalty_backend.action.save'), submitVariant: "primary" }) }) })) }) }));
|
|
345
|
-
};
|
|
346
|
-
/**
|
|
347
|
-
* Every wallet, and how much is sitting in them.
|
|
348
|
-
*
|
|
349
|
-
* The balance total is the number a finance team asks for first — it is a
|
|
350
|
-
* liability, not a statistic — so it sits beside the count rather than under it.
|
|
351
|
-
* Locked and expired are counted apart because an operator undoes them
|
|
352
|
-
* differently.
|
|
353
|
-
*/
|
|
354
230
|
export const walletsScreen = (_, frame, wallets, totals, createFields, errors = []) => (_jsx(ListScreenFrame, { translator: _, title: _('loyalty_backend.wallets.title'), subtitle: _('loyalty_backend.wallets.hint'), frame: frame, body: stack([
|
|
355
231
|
statRow([
|
|
356
|
-
{
|
|
357
|
-
|
|
232
|
+
{
|
|
233
|
+
id: 'total',
|
|
234
|
+
label: _('loyalty_backend.stat.wallets'),
|
|
235
|
+
value: figure(totals.total),
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
id: 'balance',
|
|
239
|
+
label: _('loyalty_backend.stat.balance'),
|
|
240
|
+
value: figure(totals.balance),
|
|
241
|
+
},
|
|
358
242
|
{
|
|
359
243
|
id: 'active',
|
|
360
244
|
label: _('loyalty_backend.stat.walletsActive'),
|
|
@@ -470,13 +354,21 @@ export const walletDetailScreen = (_, frame, wallet, adjustFields, tab, errors =
|
|
|
470
354
|
badge(labelOf(_, 'walletUnit', wallet.unit), 'neutral', String(wallet.unit)),
|
|
471
355
|
...(wallet.programName ? [badge(String(wallet.programName), 'info')] : []),
|
|
472
356
|
], summary: [
|
|
473
|
-
{
|
|
357
|
+
{
|
|
358
|
+
id: 'balance',
|
|
359
|
+
label: _('loyalty_backend.field.balance'),
|
|
360
|
+
value: figure(wallet.balance),
|
|
361
|
+
},
|
|
474
362
|
{
|
|
475
363
|
id: 'available',
|
|
476
364
|
label: _('loyalty_backend.field.available'),
|
|
477
365
|
value: figure(wallet.available),
|
|
478
366
|
},
|
|
479
|
-
{
|
|
367
|
+
{
|
|
368
|
+
id: 'reserved',
|
|
369
|
+
label: _('loyalty_backend.field.reserved'),
|
|
370
|
+
value: figure(wallet.reserved),
|
|
371
|
+
},
|
|
480
372
|
], navigation: _jsx(Tabs, { label: _('loyalty_backend.wallets.title'), items: [
|
|
481
373
|
{
|
|
482
374
|
id: 'overview',
|
|
@@ -668,130 +560,79 @@ export const ledgerScreen = (_, frame, rows, totals) => (_jsx(ListScreenFrame, {
|
|
|
668
560
|
]),
|
|
669
561
|
rows.length ? ledgerTable(_, rows) : empty(_),
|
|
670
562
|
]) }));
|
|
671
|
-
/**
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
{
|
|
683
|
-
id: 'active',
|
|
684
|
-
label: _('loyalty_backend.stat.membersActive'),
|
|
685
|
-
value: figure(totals.active),
|
|
686
|
-
detail: percent(totals.active, totals.total),
|
|
687
|
-
tone: 'positive',
|
|
688
|
-
},
|
|
689
|
-
{
|
|
690
|
-
id: 'dormant',
|
|
691
|
-
label: _('loyalty_backend.stat.membersDormant'),
|
|
692
|
-
value: figure(totals.dormant),
|
|
693
|
-
detail: percent(totals.dormant, totals.total),
|
|
694
|
-
tone: 'warning',
|
|
563
|
+
/** Company-wide tiers with a rolling spend window on each threshold. */
|
|
564
|
+
export const tiersScreen = (_, frame, tiers, options) => {
|
|
565
|
+
const page = (_jsx(ListScreenFrame, { translator: _, title: _('loyalty_backend.memberships.title'), subtitle: _('loyalty_backend.memberships.hint'), frame: {
|
|
566
|
+
...frame,
|
|
567
|
+
extras: {
|
|
568
|
+
...frame.extras,
|
|
569
|
+
'topbar.end': linkButton({
|
|
570
|
+
label: _('loyalty_backend.action.addTier'),
|
|
571
|
+
href: options.createHref,
|
|
572
|
+
variant: 'primary',
|
|
573
|
+
}),
|
|
695
574
|
},
|
|
696
|
-
|
|
697
|
-
{
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
cell: (row) => String(row.partnerName ?? row.partnerId),
|
|
758
|
-
priority: 'primary',
|
|
759
|
-
kind: 'person',
|
|
760
|
-
},
|
|
761
|
-
{
|
|
762
|
-
key: 'tier',
|
|
763
|
-
label: _('loyalty_backend.field.tier'),
|
|
764
|
-
cell: (row) => row.tierName ? badge(String(row.tierName), 'info', String(row.tierCode ?? row.tierId ?? '')) : '—',
|
|
765
|
-
kind: 'status',
|
|
766
|
-
},
|
|
767
|
-
{
|
|
768
|
-
key: 'points',
|
|
769
|
-
label: _('loyalty_backend.field.points'),
|
|
770
|
-
cell: (row) => figure(row.points),
|
|
771
|
-
align: 'end',
|
|
772
|
-
kind: 'number',
|
|
773
|
-
},
|
|
774
|
-
{
|
|
775
|
-
key: 'spend',
|
|
776
|
-
label: _('loyalty_backend.field.rollingSpend'),
|
|
777
|
-
cell: (row) => figure(row.rollingSpend),
|
|
778
|
-
align: 'end',
|
|
779
|
-
kind: 'number',
|
|
780
|
-
},
|
|
781
|
-
{
|
|
782
|
-
key: 'window',
|
|
783
|
-
label: _('loyalty_backend.field.windowMonths'),
|
|
784
|
-
cell: (row) => _('loyalty_backend.value.months', { count: Number(row.windowMonths ?? 0) }),
|
|
785
|
-
priority: 'tertiary',
|
|
786
|
-
},
|
|
787
|
-
{
|
|
788
|
-
key: 'refreshed',
|
|
789
|
-
label: _('loyalty_backend.field.refreshedAt'),
|
|
790
|
-
cell: (row) => String(row.refreshedAt),
|
|
791
|
-
kind: 'date',
|
|
792
|
-
},
|
|
793
|
-
],
|
|
794
|
-
});
|
|
575
|
+
}, body: stack([
|
|
576
|
+
_jsx(Section, { title: _('loyalty_backend.tiers.title'), description: _('loyalty_backend.tiers.hint'), body: tiers.length
|
|
577
|
+
? dataTable(_, {
|
|
578
|
+
rows: tiers,
|
|
579
|
+
id: (row) => String(row.id),
|
|
580
|
+
rowHref: options.tierHref,
|
|
581
|
+
rowLink: false,
|
|
582
|
+
responsive: 'stack',
|
|
583
|
+
columns: [
|
|
584
|
+
{
|
|
585
|
+
key: 'name',
|
|
586
|
+
label: _('loyalty_backend.field.name'),
|
|
587
|
+
cell: (row) => String(row.name),
|
|
588
|
+
priority: 'primary',
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
key: 'code',
|
|
592
|
+
label: _('loyalty_backend.field.code'),
|
|
593
|
+
cell: (row) => code(String(row.code)),
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
key: 'minimum',
|
|
597
|
+
label: _('loyalty_backend.field.minimumSpend'),
|
|
598
|
+
cell: (row) => figure(row.minimumSpend),
|
|
599
|
+
align: 'end',
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
key: 'window',
|
|
603
|
+
label: _('loyalty_backend.field.windowMonths'),
|
|
604
|
+
cell: (row) => figure(row.windowMonths ?? 12),
|
|
605
|
+
align: 'end',
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
key: 'sequence',
|
|
609
|
+
label: _('loyalty_backend.field.sequence'),
|
|
610
|
+
cell: (row) => figure(row.sequence),
|
|
611
|
+
align: 'end',
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
key: 'state',
|
|
615
|
+
label: _('loyalty_backend.field.state'),
|
|
616
|
+
cell: (row) => activeBadge(_, row.active),
|
|
617
|
+
},
|
|
618
|
+
],
|
|
619
|
+
})
|
|
620
|
+
: empty(_) }),
|
|
621
|
+
]) }));
|
|
622
|
+
if (!options.modal || !options.tierFields)
|
|
623
|
+
return page;
|
|
624
|
+
return modalWorkspace(page, _jsx(ModalSheet, { title: _(options.tier ? 'loyalty_backend.action.editTier' : 'loyalty_backend.action.addTier'), closeHref: options.closeHref, closeLabel: _('loyalty_backend.action.cancel'), presentation: "dialog", body: stack([
|
|
625
|
+
_jsx(RecordForm, { action: options.action, hidden: {
|
|
626
|
+
action: 'tier',
|
|
627
|
+
...(options.tier ? { id: String(options.tier.id) } : {}),
|
|
628
|
+
}, fields: options.tierFields, errors: options.tierErrors, submit: _('loyalty_backend.action.save'), submitVariant: "primary", cancelHref: options.closeHref, cancelLabel: _('loyalty_backend.action.cancel') }),
|
|
629
|
+
...(options.tier
|
|
630
|
+
? [
|
|
631
|
+
_jsx(RecordForm, { action: options.action, hidden: { action: 'toggle', id: String(options.tier.id) }, fields: [], submit: _(options.tier.active ? 'loyalty_backend.action.archive' : 'loyalty_backend.action.restore'), submitVariant: "secondary" }),
|
|
632
|
+
]
|
|
633
|
+
: []),
|
|
634
|
+
]) }));
|
|
635
|
+
};
|
|
795
636
|
export const orderLoyaltyScreen = (_, frame, options) => {
|
|
796
637
|
const programs = options.result.programs ?? [];
|
|
797
638
|
const action = `/admin/loyalty/orders/${options.channel}/${options.orderId}`;
|
|
@@ -806,11 +647,19 @@ export const orderLoyaltyScreen = (_, frame, options) => {
|
|
|
806
647
|
_jsx(Notice, { title: _('loyalty_backend.validation.title'), message: options.errors.join(' · '), tone: "danger" }),
|
|
807
648
|
]
|
|
808
649
|
: []),
|
|
809
|
-
_jsx(Section, { title: _('loyalty_backend.order.code'), body: _jsx(Surface, { body: _jsx(RecordForm, { action: action, hidden: { action: 'code' }, fields: [
|
|
650
|
+
_jsx(Section, { title: _('loyalty_backend.order.code'), body: _jsx(Surface, { body: _jsx(RecordForm, { action: action, hidden: { action: 'code' }, fields: [
|
|
651
|
+
{
|
|
652
|
+
name: 'code',
|
|
653
|
+
label: _('loyalty_backend.field.code'),
|
|
654
|
+
required: true,
|
|
655
|
+
},
|
|
656
|
+
], submit: _('loyalty_backend.action.applyCode'), submitVariant: "primary" }) }) }),
|
|
810
657
|
...(programs.length
|
|
811
658
|
? programs.map((program) => {
|
|
812
659
|
const rewards = program.rewards ?? [];
|
|
813
|
-
return (_jsx(Section, { title: String(program.programName), description: _('loyalty_backend.order.pointsEarned', {
|
|
660
|
+
return (_jsx(Section, { title: String(program.programName), description: _('loyalty_backend.order.pointsEarned', {
|
|
661
|
+
points: String(program.points),
|
|
662
|
+
}), body: stack([
|
|
814
663
|
...(program.ineligibleReasons && program.ineligibleReasons.length
|
|
815
664
|
? [
|
|
816
665
|
_jsx(Notice, { title: _('loyalty_backend.order.ineligible'), message: program.ineligibleReasons.map(String).join(' · '), tone: "warning" }),
|
|
@@ -836,7 +685,10 @@ export const orderLoyaltyScreen = (_, frame, options) => {
|
|
|
836
685
|
}, fields: [], submit: _('loyalty_backend.action.applyReward'), submitVariant: "primary" }) })) }),
|
|
837
686
|
]
|
|
838
687
|
: [empty(_)]),
|
|
839
|
-
_jsx(RecordForm, { action: action, hidden: {
|
|
688
|
+
_jsx(RecordForm, { action: action, hidden: {
|
|
689
|
+
action: 'remove',
|
|
690
|
+
programId: String(program.programId),
|
|
691
|
+
}, fields: [], submit: _('loyalty_backend.action.removeReward'), submitVariant: "destructive" }),
|
|
840
692
|
]) }));
|
|
841
693
|
})
|
|
842
694
|
: [empty(_)]),
|
|
@@ -908,5 +760,9 @@ export const portalScreen = (_, frame, summary) => {
|
|
|
908
760
|
_jsx(Section, { title: _('loyalty_backend.portal.history'), body: ledger.length ? ledgerTable(_, ledger, { admin: false }) : empty(_) }),
|
|
909
761
|
]) }));
|
|
910
762
|
};
|
|
911
|
-
export const extensionLink = (_, href) => (_jsx(Surface, { tone: "subtle", body: linkButton({
|
|
763
|
+
export const extensionLink = (_, href) => (_jsx(Surface, { tone: "subtle", body: linkButton({
|
|
764
|
+
label: _('loyalty_backend.action.openOrderLoyalty'),
|
|
765
|
+
href,
|
|
766
|
+
variant: 'secondary',
|
|
767
|
+
}) }));
|
|
912
768
|
//# sourceMappingURL=index.js.map
|