@saasicat/ui-vue 0.19.0 → 0.22.0
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/{catalog-JXdKdIqG.d.cts → catalog-DJcfm5N2.d.cts} +21 -7
- package/dist/{catalog-JXdKdIqG.d.ts → catalog-DJcfm5N2.d.ts} +21 -7
- package/dist/{chunk-DPTIOQXX.js → chunk-F7NRM6KI.js} +56 -28
- package/dist/{chunk-RVG6LQHL.js → chunk-LY52T4N4.js} +21 -2
- package/dist/{chunk-ORX3ZG47.js → chunk-XMMFN2WJ.js} +74 -3
- package/dist/client/index.cjs +134 -29
- package/dist/client/index.d.cts +53 -3
- package/dist/client/index.d.ts +53 -3
- package/dist/client/index.js +14 -2
- package/dist/index.cjs +321 -162
- package/dist/index.d.cts +30 -8
- package/dist/index.d.ts +30 -8
- package/dist/index.js +176 -133
- package/dist/quasar/index.cjs +78 -29
- package/dist/quasar/index.d.cts +2 -2
- package/dist/quasar/index.d.ts +2 -2
- package/dist/quasar/index.js +6 -2
- package/dist/testing-e2e/admin-pages-suite.d.cts +37 -0
- package/dist/testing-e2e/admin-pages-suite.d.ts +37 -0
- package/dist/{use-super-admin-i18n-BlqcD0N7.d.ts → use-super-admin-i18n-CHNdsSlm.d.ts} +34 -7
- package/dist/{use-super-admin-i18n-1nCOkvgi.d.cts → use-super-admin-i18n-CgTuNi8h.d.cts} +34 -7
- package/package.json +18 -8
- package/src/client/i18n/messages/bundles.ts +0 -2
- package/src/client/i18n/messages/common.ts +24 -0
- package/src/client/i18n/messages/discovery.ts +2 -2
- package/src/client/i18n/messages/marketing.ts +2 -4
- package/src/client/i18n/messages/plan-detail.ts +0 -4
- package/src/client/i18n/messages/plans.ts +20 -8
- package/src/client/i18n/messages/tenants.ts +0 -2
- package/src/client/index.ts +1 -0
- package/src/client/manifest-loader.ts +1 -1
- package/src/client/resolve-plans.ts +144 -0
- package/src/components/BundleVersionPublishDialog.vue +6 -6
- package/src/components/KvBlock.vue +4 -4
- package/src/components/MarketingPromotionsTab.vue +34 -48
- package/src/components/MfaPromptDialog.vue +8 -2
- package/src/components/TenantActionConfirmDialog.vue +4 -4
- package/src/components/VersionDiffPreview.vue +7 -7
- package/src/components/admin-page/AdminBody.vue +40 -0
- package/src/components/admin-page/AdminFilters.vue +12 -0
- package/src/components/admin-page/AdminHero.vue +49 -0
- package/src/components/admin-page/AdminKpi.vue +84 -0
- package/src/components/admin-page/AdminPage.vue +16 -0
- package/src/components/admin-page/AdminPaginator.vue +195 -0
- package/src/components/admin-page/AdminRefreshBtn.vue +39 -0
- package/src/components/admin-page/AdminSection.vue +53 -0
- package/src/components/admin-page/AdminStatistics.vue +40 -0
- package/src/components/admin-page/AdminTable.vue +175 -0
- package/src/components/bundle-editor/BundleCreatePanel.vue +23 -23
- package/src/components/bundle-editor/BundleFeaturesEditor.vue +7 -7
- package/src/components/bundle-editor/BundlePlanCompatPicker.vue +9 -9
- package/src/components/bundle-editor/BundleQuotasEditor.vue +11 -11
- package/src/components/bundle-editor/BundleStatusBanner.vue +6 -6
- package/src/components/bundle-editor/BundleVersionInlineEditor.vue +18 -18
- package/src/components/bundle-editor/BundleVersionStrip.vue +12 -12
- package/src/components/dialogs/PilotCreateDialog.vue +12 -12
- package/src/components/dialogs/PilotEditDialog.vue +7 -7
- package/src/components/dialogs/PromoCodeCreateDialog.vue +8 -8
- package/src/components/dialogs/PromoCodeDialogFields.vue +33 -19
- package/src/components/dialogs/PromoCodeEditDialog.vue +10 -10
- package/src/components/plan/PlanGrid.vue +1 -1
- package/src/components/plan-create-dialog/PlanCreateDialog.vue +34 -46
- package/src/components/plan-detail/PlanAuditLog.vue +7 -8
- package/src/components/plan-detail/PlanDetail.vue +95 -292
- package/src/components/plan-detail/PlanDetailKpis.vue +22 -27
- package/src/components/plan-detail/PlanTitleEdit.vue +133 -0
- package/src/components/plan-detail/PlanVersionDiffPanel.vue +5 -8
- package/src/components/plan-detail/PlanVersionsPanel.vue +9 -11
- package/src/components/plan-list/PlanList.vue +206 -457
- package/src/components/plan-matrix/PlanMatrix.vue +66 -183
- package/src/components/plan-review/PlanReview.vue +191 -275
- package/src/components/plan-version-editor/PlanCatalogPreview.vue +7 -5
- package/src/components/plan-version-editor/PlanVersionEditor.vue +200 -295
- package/src/components/plan-version-editor/PlanVersionEditorHeader.vue +23 -55
- package/src/index.ts +1 -0
- package/src/pages-standard/AdminLayout.vue +38 -12
- package/src/pages-standard/AdminManifestErrorPage.vue +79 -9
- package/src/pages-standard/AuditPage.vue +65 -109
- package/src/pages-standard/BundlesPage.vue +146 -179
- package/src/pages-standard/DashboardPage.vue +59 -154
- package/src/pages-standard/DiscoveryPage.vue +172 -227
- package/src/pages-standard/EmailHistoryPage.vue +118 -159
- package/src/pages-standard/MarketingCatalogPage.vue +399 -440
- package/src/pages-standard/PilotsPage.vue +69 -117
- package/src/pages-standard/PlansPage.vue +240 -112
- package/src/pages-standard/PlatformEmailPage.vue +56 -91
- package/src/pages-standard/PromoCodeDetailPage.vue +49 -74
- package/src/pages-standard/PromoCodesPage.vue +95 -128
- package/src/pages-standard/SubscriptionsPage.vue +19 -52
- package/src/pages-standard/SuperAdminLoginPage.vue +12 -12
- package/src/pages-standard/SuperAdminSetupWizard.vue +22 -18
- package/src/pages-standard/TenantDetailPage.vue +100 -191
- package/src/pages-standard/TenantsPage.vue +190 -295
- package/src/pages-standard/UsersPage.vue +89 -157
- package/src/pages-standard/bundles-page/BundleAccordionList.vue +20 -17
- package/src/pages-standard/bundles-page/BundlesKpis.vue +13 -22
- package/src/pages-standard/bundles-page/BundlesToolbar.vue +63 -0
- package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +10 -10
- package/src/pages-standard/discovery-page/DiscoveryCapList.vue +5 -5
- package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +16 -16
- package/src/pages-standard/discovery-page/DiscoveryKpis.vue +31 -27
- package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +7 -7
- package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +111 -73
- package/src/pages-standard/marketing-catalog/MarketingCatalogHeader.vue +43 -62
- package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +53 -35
- package/src/pages-standard/marketing-catalog/MarketingCatalogToolbar.vue +7 -7
- package/src/pages-standard/plan-versions/PlanDiffCard.vue +6 -6
- package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +6 -6
- package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +16 -16
- package/src/pages-standard/plans-page/PlanBundleOverview.vue +14 -29
- package/src/pages-standard/plans-page/PlanPublishDialog.vue +1 -1
- package/src/pages-standard/plans-page/PlansPageToast.vue +6 -6
- package/src/pages-standard/sa-theme.css +552 -86
- package/src/pages-standard/tenant-detail/TenantMasterData.vue +28 -0
- package/src/pages-standard/tenant-detail/TenantUsage.vue +31 -0
- package/src/pages-standard/tenant-detail/TenantUsers.vue +15 -0
- package/src/pages-standard/tenant-detail/types.ts +38 -0
- package/src/pages-standard/tenants/StatusPill.vue +2 -2
- package/src/pages-tenant/MySubscriptionBundlesPage.vue +25 -25
- package/src/pages-tenant/OnboardingConfigurator.vue +1 -5
- package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
- package/src/pages-tenant/TenantPlanSection.vue +12 -20
- package/src/quasar/create-super-admin-app.ts +4 -0
- package/src/vue/entitlement-provider.ts +0 -1
- package/src/vue/feature-router-guard.ts +0 -1
- package/src/vue/super-admin-context.ts +106 -1
- package/src/vue/use-api-list.ts +2 -1
- package/src/vue/use-mfa-prompt.ts +72 -0
- package/src/vue/use-pagination.ts +63 -0
- package/src/vue/use-plans.ts +1 -2
- package/src/vue/use-sign-out.ts +90 -0
- package/src/vue/use-tenant-billing.ts +1 -1
- package/src/vue/use-tenant-manifest.ts +0 -1
- package/src/components/KpiCard.vue +0 -53
- package/src/components/plan-cockpit/PlanCockpit.vue +0 -1012
- package/src/components/plan-cockpit/PlanCockpitAuditLog.vue +0 -72
- package/src/components/plan-cockpit/PlanCockpitDiffPanel.vue +0 -100
- package/src/components/plan-cockpit/PlanCockpitHeader.vue +0 -101
- package/src/components/plan-cockpit/PlanCockpitImpactPanel.vue +0 -112
- package/src/components/plan-cockpit/PlanCockpitKpis.vue +0 -68
- package/src/components/plan-cockpit/PlanCockpitVersions.vue +0 -251
- package/src/components/plan-cockpit/types.ts +0 -72
- package/src/components/plan-detail/PlanDetailHeader.vue +0 -194
- package/src/pages-standard/bundles-page/BundlesHeader.vue +0 -68
- package/src/pages-standard/discovery-page/DiscoveryHeader.vue +0 -34
|
@@ -1,45 +1,41 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
<p class="sa-page-head__sub">{{ msg.provider.subtitle }}</p>
|
|
7
|
-
</div>
|
|
8
|
-
<div class="sa-page-head__actions">
|
|
9
|
-
<q-btn
|
|
2
|
+
<AdminPage class="sa-pemail">
|
|
3
|
+
<AdminHero :title="resolvedTitle" :subtitle="msg.provider.subtitle">
|
|
4
|
+
<template #actions>
|
|
5
|
+
<button
|
|
10
6
|
v-if="rows.length === 0"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
icon="add"
|
|
14
|
-
:label="msg.sender"
|
|
7
|
+
class="sa-btn sa-btn--primary"
|
|
8
|
+
type="button"
|
|
15
9
|
@click="openCreate"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
>
|
|
11
|
+
<q-icon name="add" size="16px" />
|
|
12
|
+
<span>{{ msg.sender }}</span>
|
|
13
|
+
</button>
|
|
14
|
+
<AdminRefreshBtn :loading="loading" @refresh="reload" />
|
|
15
|
+
</template>
|
|
16
|
+
</AdminHero>
|
|
20
17
|
|
|
21
|
-
<
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<q-td>
|
|
18
|
+
<AdminBody>
|
|
19
|
+
<AdminSection class="sa-pemail__card">
|
|
20
|
+
<AdminTable
|
|
21
|
+
:rows="rows"
|
|
22
|
+
:columns="columns"
|
|
23
|
+
:loading="loading"
|
|
24
|
+
storage-key="platform-email"
|
|
25
|
+
>
|
|
26
|
+
<template #body-cell-active="{ row }">
|
|
27
|
+
<q-td>
|
|
28
|
+
<q-badge
|
|
29
|
+
:color="row.active ? 'positive' : 'grey'"
|
|
30
|
+
:label="
|
|
31
|
+
row.active
|
|
32
|
+
? msg.provider.statusActive
|
|
33
|
+
: msg.provider.statusInactive
|
|
34
|
+
"
|
|
35
|
+
/>
|
|
36
|
+
</q-td>
|
|
37
|
+
</template>
|
|
38
|
+
<template #row-actions="{ row }">
|
|
43
39
|
<q-btn
|
|
44
40
|
flat
|
|
45
41
|
dense
|
|
@@ -64,10 +60,10 @@
|
|
|
64
60
|
:title="common.delete"
|
|
65
61
|
@click="onDelete(row)"
|
|
66
62
|
/>
|
|
67
|
-
</
|
|
68
|
-
</
|
|
69
|
-
</
|
|
70
|
-
</
|
|
63
|
+
</template>
|
|
64
|
+
</AdminTable>
|
|
65
|
+
</AdminSection>
|
|
66
|
+
</AdminBody>
|
|
71
67
|
|
|
72
68
|
<q-dialog v-model="showForm">
|
|
73
69
|
<q-card class="sa-pemail__dialog">
|
|
@@ -185,19 +181,26 @@
|
|
|
185
181
|
|
|
186
182
|
<MfaPromptDialog
|
|
187
183
|
v-if="requireMfaForWrite"
|
|
188
|
-
:model-value="
|
|
189
|
-
:description="
|
|
190
|
-
:error="
|
|
184
|
+
:model-value="mfa.show.value"
|
|
185
|
+
:description="mfa.description.value"
|
|
186
|
+
:error="mfa.error.value"
|
|
191
187
|
:setup-hint="mfaSetupHint"
|
|
192
|
-
@update:model-value="
|
|
193
|
-
@confirm="
|
|
188
|
+
@update:model-value="mfa.onVisibility"
|
|
189
|
+
@confirm="mfa.onConfirm"
|
|
194
190
|
/>
|
|
195
|
-
</
|
|
191
|
+
</AdminPage>
|
|
196
192
|
</template>
|
|
197
193
|
|
|
198
194
|
<script setup lang="ts">
|
|
195
|
+
import AdminTable from '../components/admin-page/AdminTable.vue';
|
|
199
196
|
import { computed, reactive, ref } from 'vue';
|
|
197
|
+
import { useMfaPrompt } from '../vue/use-mfa-prompt.js';
|
|
200
198
|
import { useQuasar } from 'quasar';
|
|
199
|
+
import AdminRefreshBtn from '../components/admin-page/AdminRefreshBtn.vue';
|
|
200
|
+
import AdminBody from '../components/admin-page/AdminBody.vue';
|
|
201
|
+
import AdminHero from '../components/admin-page/AdminHero.vue';
|
|
202
|
+
import AdminSection from '../components/admin-page/AdminSection.vue';
|
|
203
|
+
import AdminPage from '../components/admin-page/AdminPage.vue';
|
|
201
204
|
import { useSuperAdminNotify } from '../quasar/notify.js';
|
|
202
205
|
import MfaPromptDialog from '../components/MfaPromptDialog.vue';
|
|
203
206
|
import { formatMessage } from '../client/i18n/format.js';
|
|
@@ -265,7 +268,6 @@ const columns = computed(() => [
|
|
|
265
268
|
align: 'left' as const,
|
|
266
269
|
},
|
|
267
270
|
{ name: 'active', label: common.value.status, field: 'active', align: 'left' as const },
|
|
268
|
-
{ name: 'actions', label: '', field: 'id' as never, align: 'right' as 'left' },
|
|
269
271
|
]);
|
|
270
272
|
|
|
271
273
|
const showForm = ref(false);
|
|
@@ -279,10 +281,7 @@ const testResult = ref<PlatformEmailTestResult | null>(null);
|
|
|
279
281
|
const testing = ref(false);
|
|
280
282
|
|
|
281
283
|
// MFA loop analogous to UsersPage (promise-resolver pattern).
|
|
282
|
-
const
|
|
283
|
-
const mfaError = ref('');
|
|
284
|
-
const mfaDescription = ref('');
|
|
285
|
-
let pendingMfaResolve: ((code: string | null) => void) | null = null;
|
|
284
|
+
const mfa = useMfaPrompt();
|
|
286
285
|
|
|
287
286
|
function emptyForm(): PlatformEmailWriteInput {
|
|
288
287
|
return {
|
|
@@ -298,29 +297,6 @@ function emptyForm(): PlatformEmailWriteInput {
|
|
|
298
297
|
};
|
|
299
298
|
}
|
|
300
299
|
|
|
301
|
-
function promptMfa(description: string): Promise<string | null> {
|
|
302
|
-
return new Promise((resolve) => {
|
|
303
|
-
mfaDescription.value = description;
|
|
304
|
-
mfaError.value = '';
|
|
305
|
-
showMfa.value = true;
|
|
306
|
-
pendingMfaResolve = (code) => {
|
|
307
|
-
pendingMfaResolve = null;
|
|
308
|
-
resolve(code);
|
|
309
|
-
};
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function onMfaConfirm(code: string): void {
|
|
314
|
-
pendingMfaResolve?.(code);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function onMfaDialogVisibility(open: boolean): void {
|
|
318
|
-
showMfa.value = open;
|
|
319
|
-
if (!open && pendingMfaResolve) {
|
|
320
|
-
pendingMfaResolve(null);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
300
|
function errMsg(err: unknown): string {
|
|
325
301
|
return (
|
|
326
302
|
(err as { response?: { data?: { message?: string } } })?.response?.data?.message ??
|
|
@@ -381,19 +357,19 @@ async function runWrite(
|
|
|
381
357
|
}
|
|
382
358
|
}
|
|
383
359
|
for (;;) {
|
|
384
|
-
const code = await
|
|
360
|
+
const code = await mfa.prompt(label);
|
|
385
361
|
if (code === null) return false;
|
|
386
362
|
try {
|
|
387
363
|
await invoke(code);
|
|
388
|
-
|
|
364
|
+
mfa.show.value = false;
|
|
389
365
|
return true;
|
|
390
366
|
} catch (err) {
|
|
391
367
|
const status = (err as { response?: { status?: number } })?.response?.status;
|
|
392
368
|
if (status === 401) {
|
|
393
|
-
|
|
369
|
+
mfa.error.value = shell.value.mfa.invalidCode;
|
|
394
370
|
continue;
|
|
395
371
|
}
|
|
396
|
-
|
|
372
|
+
mfa.show.value = false;
|
|
397
373
|
notify('negative', errMsg(err));
|
|
398
374
|
return false;
|
|
399
375
|
}
|
|
@@ -484,17 +460,6 @@ async function onTest(): Promise<void> {
|
|
|
484
460
|
</script>
|
|
485
461
|
|
|
486
462
|
<style scoped>
|
|
487
|
-
.sa-pemail {
|
|
488
|
-
min-height: calc(100vh - 56px);
|
|
489
|
-
background: var(--sa-bg-app, #f1f5f9);
|
|
490
|
-
padding: 20px 28px 28px;
|
|
491
|
-
}
|
|
492
|
-
.sa-pemail__card {
|
|
493
|
-
background: #fff;
|
|
494
|
-
border: 1px solid var(--sa-border, #e2e8f0);
|
|
495
|
-
border-radius: 12px;
|
|
496
|
-
overflow: hidden;
|
|
497
|
-
}
|
|
498
463
|
.sa-pemail__dialog {
|
|
499
464
|
min-width: 420px;
|
|
500
465
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
<
|
|
2
|
+
<AdminPage class="sa-promo-detail">
|
|
3
|
+
<AdminHero :title="data?.promo.code ?? labels.promoCode">
|
|
4
|
+
<template #before-title>
|
|
5
5
|
<q-btn
|
|
6
6
|
flat
|
|
7
7
|
dense
|
|
@@ -10,73 +10,65 @@
|
|
|
10
10
|
:to="backRoute"
|
|
11
11
|
class="sa-promo-detail__back"
|
|
12
12
|
/>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<q-btn
|
|
13
|
+
</template>
|
|
14
|
+
<template #subtitle>
|
|
15
|
+
<template v-if="data">
|
|
16
|
+
{{ data.promo.valueType }} · {{ data.promo.value }} ·
|
|
17
|
+
<q-badge
|
|
18
|
+
:color="resolveStatusColor(String(data.promo.status))"
|
|
19
|
+
:label="String(data.promo.status)"
|
|
20
|
+
/>
|
|
21
|
+
</template>
|
|
22
|
+
<template v-else>—</template>
|
|
23
|
+
</template>
|
|
24
|
+
<template #actions>
|
|
25
|
+
<button
|
|
27
26
|
v-if="editSubmit && data"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
icon="edit"
|
|
31
|
-
:label="labels.edit"
|
|
27
|
+
class="sa-btn sa-btn--primary"
|
|
28
|
+
type="button"
|
|
32
29
|
@click="openEdit"
|
|
33
|
-
|
|
30
|
+
>
|
|
31
|
+
<q-icon name="edit" size="16px" />
|
|
32
|
+
<span>{{ labels.edit }}</span>
|
|
33
|
+
</button>
|
|
34
34
|
<slot name="header-actions" />
|
|
35
|
-
</
|
|
36
|
-
</
|
|
37
|
-
|
|
38
|
-
<div class="sa-promo-detail__body">
|
|
39
|
-
<div v-if="loading" class="sa-promo-detail__state">
|
|
40
|
-
<q-spinner size="32px" /> {{ msg.detail.loading }}
|
|
41
|
-
</div>
|
|
42
|
-
<div v-else-if="!data" class="sa-promo-detail__state">{{ labels.empty }}</div>
|
|
35
|
+
</template>
|
|
36
|
+
</AdminHero>
|
|
43
37
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
<AdminBody
|
|
39
|
+
:loading="loading"
|
|
40
|
+
:empty="!data"
|
|
41
|
+
:loading-text="msg.detail.loading"
|
|
42
|
+
:empty-text="labels.empty"
|
|
43
|
+
>
|
|
44
|
+
<template v-if="data">
|
|
45
|
+
<AdminSection :title="labels.config">
|
|
47
46
|
<slot name="config" :promo="data.promo">
|
|
48
47
|
<pre class="sa-promo-detail__kv">{{ resolveFormatPromo(data.promo) }}</pre>
|
|
49
48
|
</slot>
|
|
50
|
-
</
|
|
49
|
+
</AdminSection>
|
|
51
50
|
|
|
52
|
-
<
|
|
53
|
-
<div class="sa-promo-detail__section-head">{{ labels.stats }}</div>
|
|
51
|
+
<AdminSection :title="labels.stats">
|
|
54
52
|
<slot name="stats" :stats="data.stats">
|
|
55
53
|
<pre class="sa-promo-detail__kv">{{
|
|
56
54
|
JSON.stringify(data.stats, null, 2)
|
|
57
55
|
}}</pre>
|
|
58
56
|
</slot>
|
|
59
|
-
</
|
|
57
|
+
</AdminSection>
|
|
60
58
|
|
|
61
|
-
<
|
|
62
|
-
<div class="sa-promo-detail__section-head">
|
|
63
|
-
{{ labels.redemptions }} ({{ data.redemptions.length }})
|
|
64
|
-
</div>
|
|
59
|
+
<AdminSection :title="`${labels.redemptions} (${data.redemptions.length})`">
|
|
65
60
|
<slot name="redemptions" :redemptions="data.redemptions">
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
:rows="data.redemptions"
|
|
61
|
+
<AdminTable
|
|
62
|
+
:rows="redemptionRows"
|
|
69
63
|
:columns="redemptionsColumns ?? defaultColumns"
|
|
70
|
-
|
|
71
|
-
:pagination="{ rowsPerPage: 0 }"
|
|
72
|
-
hide-pagination
|
|
64
|
+
storage-key="promo-code-redemptions"
|
|
73
65
|
/>
|
|
74
66
|
</slot>
|
|
75
|
-
</
|
|
67
|
+
</AdminSection>
|
|
76
68
|
|
|
77
69
|
<slot name="extra-sections" :data="data" />
|
|
78
70
|
</template>
|
|
79
|
-
</
|
|
71
|
+
</AdminBody>
|
|
80
72
|
|
|
81
73
|
<PromoCodeEditDialog
|
|
82
74
|
v-if="editSubmit"
|
|
@@ -86,11 +78,16 @@
|
|
|
86
78
|
:submit="editSubmit"
|
|
87
79
|
@updated="onEditUpdated"
|
|
88
80
|
/>
|
|
89
|
-
</
|
|
81
|
+
</AdminPage>
|
|
90
82
|
</template>
|
|
91
83
|
|
|
92
84
|
<script setup lang="ts">
|
|
85
|
+
import AdminTable from '../components/admin-page/AdminTable.vue';
|
|
93
86
|
import { computed, onMounted, ref } from 'vue';
|
|
87
|
+
import AdminBody from '../components/admin-page/AdminBody.vue';
|
|
88
|
+
import AdminHero from '../components/admin-page/AdminHero.vue';
|
|
89
|
+
import AdminSection from '../components/admin-page/AdminSection.vue';
|
|
90
|
+
import AdminPage from '../components/admin-page/AdminPage.vue';
|
|
94
91
|
import type { RouteLocationRaw } from 'vue-router';
|
|
95
92
|
import type { QTableColumn } from 'quasar';
|
|
96
93
|
import PromoCodeEditDialog, {
|
|
@@ -280,13 +277,11 @@ const defaultColumns = computed<QTableColumn[]>(() => [
|
|
|
280
277
|
align: 'left',
|
|
281
278
|
},
|
|
282
279
|
]);
|
|
280
|
+
|
|
281
|
+
const redemptionRows = computed(() => data.value?.redemptions ?? []);
|
|
283
282
|
</script>
|
|
284
283
|
|
|
285
284
|
<style scoped>
|
|
286
|
-
.sa-promo-detail {
|
|
287
|
-
min-height: calc(100vh - 56px);
|
|
288
|
-
background: var(--sa-bg-app);
|
|
289
|
-
}
|
|
290
285
|
.sa-promo-detail__back {
|
|
291
286
|
margin-bottom: 6px;
|
|
292
287
|
}
|
|
@@ -297,23 +292,10 @@ const defaultColumns = computed<QTableColumn[]>(() => [
|
|
|
297
292
|
margin-left: auto;
|
|
298
293
|
}
|
|
299
294
|
.sa-promo-detail__body {
|
|
300
|
-
padding: 12px 28px 28px;
|
|
301
295
|
display: flex;
|
|
302
296
|
flex-direction: column;
|
|
303
297
|
gap: 14px;
|
|
304
298
|
}
|
|
305
|
-
.sa-promo-detail__section {
|
|
306
|
-
padding: 16px 18px;
|
|
307
|
-
}
|
|
308
|
-
.sa-promo-detail__section-head {
|
|
309
|
-
font-size: 11px;
|
|
310
|
-
font-weight: 700;
|
|
311
|
-
letter-spacing: 0.08em;
|
|
312
|
-
color: var(--sa-muted);
|
|
313
|
-
text-transform: uppercase;
|
|
314
|
-
margin-bottom: 10px;
|
|
315
|
-
font-family: var(--sa-font-head);
|
|
316
|
-
}
|
|
317
299
|
.sa-promo-detail__kv {
|
|
318
300
|
background: #fafbfc;
|
|
319
301
|
border: 1px solid var(--sa-border);
|
|
@@ -324,11 +306,4 @@ const defaultColumns = computed<QTableColumn[]>(() => [
|
|
|
324
306
|
overflow-x: auto;
|
|
325
307
|
font-family: var(--sa-font-mono);
|
|
326
308
|
}
|
|
327
|
-
.sa-promo-detail__state {
|
|
328
|
-
padding: 24px;
|
|
329
|
-
display: flex;
|
|
330
|
-
align-items: center;
|
|
331
|
-
gap: 12px;
|
|
332
|
-
color: var(--sa-muted);
|
|
333
|
-
}
|
|
334
309
|
</style>
|