@saasicat/ui-vue 0.4.0 → 0.6.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/README.md +64 -4
- package/dist/chunk-A3W2N26K.js +714 -0
- package/dist/chunk-QZOSDCNP.js +98 -0
- package/dist/chunk-X5SQ5HMB.js +3231 -0
- package/dist/client/index.cjs +3988 -0
- package/dist/client/index.d.cts +321 -0
- package/dist/client/index.d.ts +321 -0
- package/dist/client/index.js +70 -0
- package/dist/index.cjs +4446 -1249
- package/dist/index.d.cts +297 -888
- package/dist/index.d.ts +297 -888
- package/dist/index.js +609 -1348
- package/dist/messages-7b0P8W75.d.cts +1652 -0
- package/dist/messages-7b0P8W75.d.ts +1652 -0
- package/dist/quasar/index.cjs +3340 -0
- package/dist/quasar/index.d.cts +95 -0
- package/dist/quasar/index.d.ts +95 -0
- package/dist/quasar/index.js +96 -0
- package/dist/testing-e2e/admin-pages-suite.cjs +14 -11
- package/dist/testing-e2e/admin-pages-suite.js +14 -11
- package/dist/use-super-admin-i18n-B3v3-SWZ.d.ts +210 -0
- package/dist/use-super-admin-i18n-DMktRVEt.d.cts +210 -0
- package/package.json +23 -3
- package/src/{action-registry.ts → client/action-registry.ts} +4 -4
- package/src/{batch-column-fetcher.ts → client/batch-column-fetcher.ts} +4 -4
- package/src/{boot-loader.ts → client/boot-loader.ts} +3 -3
- package/src/client/i18n/currency.ts +42 -0
- package/src/client/i18n/define.ts +59 -0
- package/src/client/i18n/format.ts +12 -0
- package/src/client/i18n/index.ts +14 -0
- package/src/client/i18n/locale.ts +15 -0
- package/src/client/i18n/messages/audit.ts +42 -0
- package/src/client/i18n/messages/bundles.ts +459 -0
- package/src/client/i18n/messages/common.ts +147 -0
- package/src/client/i18n/messages/dashboard.ts +16 -0
- package/src/client/i18n/messages/discovery.ts +229 -0
- package/src/client/i18n/messages/email.ts +125 -0
- package/src/client/i18n/messages/marketing.ts +270 -0
- package/src/client/i18n/messages/nav.ts +72 -0
- package/src/client/i18n/messages/pilots.ts +192 -0
- package/src/client/i18n/messages/plan-detail.ts +266 -0
- package/src/client/i18n/messages/plan-editor.ts +177 -0
- package/src/client/i18n/messages/plan-versions.ts +251 -0
- package/src/client/i18n/messages/plans.ts +503 -0
- package/src/client/i18n/messages/promos.ts +202 -0
- package/src/client/i18n/messages/shell.ts +145 -0
- package/src/client/i18n/messages/tenants.ts +104 -0
- package/src/client/i18n/messages/users.ts +78 -0
- package/src/client/i18n/messages.ts +84 -0
- package/src/client/index.ts +27 -0
- package/src/{manifest-loader.ts → client/manifest-loader.ts} +4 -4
- package/src/{nav-builder.ts → client/nav-builder.ts} +44 -51
- package/src/{plan-versions-catalog.ts → client/plan-versions-catalog.ts} +42 -30
- package/src/components/BundleVersionPublishDialog.vue +35 -24
- package/src/components/FeatureGate.vue +1 -1
- package/src/components/MarketingPromotionsTab.vue +112 -59
- package/src/components/MfaPromptDialog.vue +11 -11
- package/src/components/TenantActionConfirmDialog.vue +19 -17
- package/src/components/VersionDiffPreview.vue +72 -43
- package/src/components/bundle-editor/BundleCreatePanel.vue +76 -63
- package/src/components/bundle-editor/BundleFeaturesEditor.vue +13 -6
- package/src/components/bundle-editor/BundlePlanCompatPicker.vue +19 -14
- package/src/components/bundle-editor/BundleQuotasEditor.vue +7 -4
- package/src/components/bundle-editor/BundleStatusBanner.vue +36 -19
- package/src/components/bundle-editor/BundleVersionInlineEditor.vue +51 -35
- package/src/components/bundle-editor/BundleVersionStrip.vue +24 -12
- package/src/components/bundle-editor/bundle-version-status.ts +29 -29
- package/src/components/dialogs/PilotCreateDialog.vue +58 -63
- package/src/components/dialogs/PilotEditDialog.vue +40 -34
- package/src/components/dialogs/PromoCodeCreateDialog.vue +89 -63
- package/src/components/dialogs/PromoCodeEditDialog.vue +98 -66
- package/src/components/dialogs/types.ts +3 -13
- package/src/components/plan/PlanCycleToggle.vue +21 -10
- package/src/components/plan/PlanGrid.vue +2 -2
- package/src/components/plan/PriceSummary.vue +1 -1
- package/src/components/plan/PromoCodeInput.vue +1 -1
- package/src/components/plan/PublicBundleGrid.vue +1 -1
- package/src/components/plan-cockpit/PlanCockpit.vue +34 -15
- package/src/components/plan-cockpit/PlanCockpitAuditLog.vue +13 -6
- package/src/components/plan-cockpit/PlanCockpitDiffPanel.vue +18 -9
- package/src/components/plan-cockpit/PlanCockpitHeader.vue +9 -6
- package/src/components/plan-cockpit/PlanCockpitImpactPanel.vue +24 -11
- package/src/components/plan-cockpit/PlanCockpitKpis.vue +28 -17
- package/src/components/plan-cockpit/PlanCockpitVersions.vue +50 -25
- package/src/components/plan-create-dialog/PlanCreateDialog.vue +45 -35
- package/src/components/plan-detail/PlanAuditLog.vue +11 -6
- package/src/components/plan-detail/PlanDetail.vue +21 -23
- package/src/components/plan-detail/PlanDetailHeader.vue +20 -11
- package/src/components/plan-detail/PlanDetailKpis.vue +30 -17
- package/src/components/plan-detail/PlanTerminateDialog.vue +22 -9
- package/src/components/plan-detail/PlanVersionDiffPanel.vue +61 -27
- package/src/components/plan-detail/PlanVersionsPanel.vue +71 -36
- package/src/components/plan-list/PlanList.vue +99 -57
- package/src/components/plan-matrix/PlanMatrix.vue +85 -38
- package/src/components/plan-review/PlanReview.vue +105 -80
- package/src/components/plan-version-editor/PlanCatalogPreview.vue +43 -20
- package/src/components/plan-version-editor/PlanComponentPool.vue +15 -7
- package/src/components/plan-version-editor/PlanVersionBasket.vue +45 -24
- package/src/components/plan-version-editor/PlanVersionDiffDialog.vue +8 -7
- package/src/components/plan-version-editor/PlanVersionEditor.vue +74 -40
- package/src/components/plan-version-editor/PlanVersionEditorHeader.vue +24 -12
- package/src/index.ts +82 -79
- package/src/pages-standard/AdminLayout.vue +43 -18
- package/src/pages-standard/AdminManifestErrorPage.vue +10 -10
- package/src/pages-standard/AuditPage.vue +58 -19
- package/src/pages-standard/BundlesPage.vue +29 -18
- package/src/pages-standard/DashboardPage.vue +31 -17
- package/src/pages-standard/DiscoveryPage.vue +40 -28
- package/src/pages-standard/EmailHistoryPage.vue +98 -69
- package/src/pages-standard/MarketingCatalogPage.vue +40 -21
- package/src/pages-standard/PilotsPage.vue +64 -52
- package/src/pages-standard/PlanVersionsPage.vue +9 -5
- package/src/pages-standard/PlansPage.vue +91 -59
- package/src/pages-standard/PlatformEmailPage.vue +120 -53
- package/src/pages-standard/PromoCodeDetailPage.vue +66 -63
- package/src/pages-standard/PromoCodesPage.vue +51 -54
- package/src/pages-standard/SubscriptionsPage.vue +14 -9
- package/src/pages-standard/SuperAdminLoginPage.vue +19 -16
- package/src/pages-standard/SuperAdminSetupWizard.vue +53 -49
- package/src/pages-standard/TenantDetailPage.vue +54 -40
- package/src/pages-standard/TenantsPage.vue +57 -44
- package/src/pages-standard/UsersPage.vue +70 -52
- package/src/pages-standard/bundles-page/BundleAccordionList.vue +20 -8
- package/src/pages-standard/bundles-page/BundleDetailPanel.vue +28 -18
- package/src/pages-standard/bundles-page/BundlesFilterBar.vue +4 -1
- package/src/pages-standard/bundles-page/BundlesHeader.vue +9 -8
- package/src/pages-standard/bundles-page/BundlesKpis.vue +29 -11
- package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +20 -8
- package/src/pages-standard/discovery-page/DiscoveryCapList.vue +5 -3
- package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +43 -24
- package/src/pages-standard/discovery-page/DiscoveryHeader.vue +7 -4
- package/src/pages-standard/discovery-page/DiscoveryKpis.vue +28 -15
- package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +20 -10
- package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +9 -6
- package/src/pages-standard/discovery-page/discovery-ui.ts +40 -52
- package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +81 -49
- package/src/pages-standard/marketing-catalog/MarketingCatalogHeader.vue +13 -10
- package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +24 -20
- package/src/pages-standard/marketing-catalog/MarketingCatalogToolbar.vue +6 -3
- package/src/pages-standard/plan-versions/PlanDiffCard.vue +16 -6
- package/src/pages-standard/plan-versions/PlanVersionHeader.vue +42 -26
- package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +46 -27
- package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +8 -6
- package/src/pages-standard/plan-versions/PlanVersionsList.vue +40 -17
- package/src/pages-standard/plan-versions/PlanVersionsMatrix.vue +1 -1
- package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +25 -13
- package/src/pages-standard/plan-versions/format.ts +33 -17
- package/src/pages-standard/plans-page/PlanArchiveDialog.vue +12 -8
- package/src/pages-standard/plans-page/PlanBundleOverview.vue +15 -6
- package/src/pages-standard/plans-page/PlanDiscardDraftDialog.vue +18 -7
- package/src/pages-standard/plans-page/PlanPublishDialog.vue +23 -12
- package/src/pages-standard/tenants/format.ts +3 -2
- package/src/pages-tenant/MySubscriptionBundlesPage.vue +73 -38
- package/src/pages-tenant/OnboardingConfigurator.vue +3 -3
- package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
- package/src/pages-tenant/PlanChangeWizard.vue +10 -6
- package/src/pages-tenant/TenantPlanSection.vue +20 -16
- package/src/pages-tenant/default-i18n.ts +217 -1
- package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +9 -7
- package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +11 -12
- package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +4 -1
- package/src/pages-tenant/tenant-plan-section/TenantPlanCardHeader.vue +1 -1
- package/src/pages-tenant/tenant-plan-section/TenantUsageGrid.vue +1 -1
- package/src/quasar/create-super-admin-app.ts +192 -0
- package/src/quasar/index.ts +11 -0
- package/src/quasar/notify.ts +30 -0
- package/src/testing-e2e/admin-pages-suite.ts +14 -11
- package/src/{manifest-store-factory.ts → vue/manifest-store-factory.ts} +1 -1
- package/src/{platform-loaders.ts → vue/platform-loaders.ts} +4 -4
- package/src/{project-page-host.ts → vue/project-page-host.ts} +6 -4
- package/src/{create-super-admin-app.ts → vue/super-admin-context.ts} +20 -139
- package/src/vue/ui-notify.ts +30 -0
- package/src/{use-actions.ts → vue/use-actions.ts} +1 -1
- package/src/{use-api-list.ts → vue/use-api-list.ts} +1 -1
- package/src/{use-audit-entries.ts → vue/use-audit-entries.ts} +3 -3
- package/src/{use-batch-columns.ts → vue/use-batch-columns.ts} +1 -1
- package/src/{use-bulk-publish.ts → vue/use-bulk-publish.ts} +7 -5
- package/src/{use-bundle-versions-map.ts → vue/use-bundle-versions-map.ts} +7 -5
- package/src/{use-bundles.ts → vue/use-bundles.ts} +14 -14
- package/src/{use-catalog-entries.ts → vue/use-catalog-entries.ts} +14 -11
- package/src/{use-discovery.ts → vue/use-discovery.ts} +9 -6
- package/src/{use-entitlement.ts → vue/use-entitlement.ts} +4 -4
- package/src/{use-live-plan-versions.ts → vue/use-live-plan-versions.ts} +5 -5
- package/src/{use-manifest.ts → vue/use-manifest.ts} +1 -1
- package/src/{use-marketing-projections.ts → vue/use-marketing-projections.ts} +10 -7
- package/src/{use-nav.ts → vue/use-nav.ts} +9 -3
- package/src/{use-plan-editor.ts → vue/use-plan-editor.ts} +2 -2
- package/src/{use-plan-versions.ts → vue/use-plan-versions.ts} +3 -3
- package/src/{use-plans.ts → vue/use-plans.ts} +13 -13
- package/src/{use-platform-tenant-actions.ts → vue/use-platform-tenant-actions.ts} +9 -6
- package/src/{use-promotions.ts → vue/use-promotions.ts} +10 -11
- package/src/{use-public-boot.ts → vue/use-public-boot.ts} +1 -1
- package/src/{use-subscription-draft.ts → vue/use-subscription-draft.ts} +2 -3
- package/src/{use-super-admin-context.ts → vue/use-super-admin-context.ts} +5 -5
- package/src/vue/use-super-admin-i18n.ts +82 -0
- package/src/{use-tenant-action-flow.ts → vue/use-tenant-action-flow.ts} +12 -7
- package/src/{use-tenant-billing-catalog.ts → vue/use-tenant-billing-catalog.ts} +2 -2
- package/src/{use-tenant-billing.ts → vue/use-tenant-billing.ts} +2 -2
- package/src/{use-tenant-manifest.ts → vue/use-tenant-manifest.ts} +2 -4
- package/src/{use-tenant-subscription-bundles.ts → vue/use-tenant-subscription-bundles.ts} +5 -5
- package/src/{use-tenants.ts → vue/use-tenants.ts} +3 -3
- package/dist/testing-e2e/admin-pages-suite.d.cts +0 -37
- package/dist/testing-e2e/admin-pages-suite.d.ts +0 -37
- package/src/components/BusinessTypeVersionEditorDialog.vue +0 -417
- package/src/components/BusinessTypeVersionPublishDialog.vue +0 -258
- package/src/pages-standard/BusinessTypesPage.vue +0 -662
- package/src/pages-standard/plan-versions/VersionDiffPreview.vue +0 -167
- package/src/use-business-types.ts +0 -269
- /package/src/{http-json.ts → client/http-json.ts} +0 -0
- /package/src/{types.ts → client/types.ts} +0 -0
- /package/src/{version.ts → client/version.ts} +0 -0
- /package/src/{create-admin-routes.ts → vue/create-admin-routes.ts} +0 -0
- /package/src/{entitlement-provider.ts → vue/entitlement-provider.ts} +0 -0
- /package/src/{feature-router-guard.ts → vue/feature-router-guard.ts} +0 -0
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
<div class="sa-emh">
|
|
3
3
|
<header class="sa-emh__head">
|
|
4
4
|
<div>
|
|
5
|
-
<h1 class="sa-emh__title">{{
|
|
6
|
-
<p class="sa-emh__sub">
|
|
7
|
-
Über den Plattform-Absender versendete System-Mails — Empfänger, Status und
|
|
8
|
-
Fehler.
|
|
9
|
-
</p>
|
|
5
|
+
<h1 class="sa-emh__title">{{ resolvedTitle }}</h1>
|
|
6
|
+
<p class="sa-emh__sub">{{ msg.history.subtitle }}</p>
|
|
10
7
|
</div>
|
|
11
|
-
<q-btn flat icon="refresh" label="
|
|
8
|
+
<q-btn flat icon="refresh" :label="common.reload" @click="applyFilter" />
|
|
12
9
|
</header>
|
|
13
10
|
|
|
14
11
|
<div class="sa-emh__body">
|
|
@@ -18,7 +15,7 @@
|
|
|
18
15
|
outlined
|
|
19
16
|
dense
|
|
20
17
|
clearable
|
|
21
|
-
label="
|
|
18
|
+
:label="msg.history.searchLabel"
|
|
22
19
|
debounce="350"
|
|
23
20
|
@keyup.enter="applyFilter"
|
|
24
21
|
@update:model-value="applyFilter"
|
|
@@ -32,7 +29,7 @@
|
|
|
32
29
|
clearable
|
|
33
30
|
emit-value
|
|
34
31
|
map-options
|
|
35
|
-
label="
|
|
32
|
+
:label="common.status"
|
|
36
33
|
:options="statusOptions"
|
|
37
34
|
@update:model-value="applyFilter"
|
|
38
35
|
/>
|
|
@@ -42,7 +39,7 @@
|
|
|
42
39
|
dense
|
|
43
40
|
clearable
|
|
44
41
|
type="date"
|
|
45
|
-
label="
|
|
42
|
+
:label="common.from"
|
|
46
43
|
@update:model-value="applyFilter"
|
|
47
44
|
/>
|
|
48
45
|
<q-input
|
|
@@ -51,7 +48,7 @@
|
|
|
51
48
|
dense
|
|
52
49
|
clearable
|
|
53
50
|
type="date"
|
|
54
|
-
label="
|
|
51
|
+
:label="common.to"
|
|
55
52
|
@update:model-value="applyFilter"
|
|
56
53
|
/>
|
|
57
54
|
</div>
|
|
@@ -70,7 +67,10 @@
|
|
|
70
67
|
>
|
|
71
68
|
<template #body-cell-status="{ row }">
|
|
72
69
|
<q-td>
|
|
73
|
-
<q-badge
|
|
70
|
+
<q-badge
|
|
71
|
+
:color="statusColor(row.status)"
|
|
72
|
+
:label="statusLabel(row.status)"
|
|
73
|
+
/>
|
|
74
74
|
</q-td>
|
|
75
75
|
</template>
|
|
76
76
|
<template #body-cell-actions="{ row }">
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
dense
|
|
81
81
|
icon="send"
|
|
82
82
|
color="primary"
|
|
83
|
-
title="
|
|
83
|
+
:title="msg.history.resend"
|
|
84
84
|
@click.stop="onResend(row.id)"
|
|
85
85
|
/>
|
|
86
86
|
<q-btn
|
|
@@ -88,13 +88,13 @@
|
|
|
88
88
|
dense
|
|
89
89
|
icon="delete"
|
|
90
90
|
color="negative"
|
|
91
|
-
title="
|
|
91
|
+
:title="msg.history.removeFromHistory"
|
|
92
92
|
@click.stop="askDelete(row.id)"
|
|
93
93
|
/>
|
|
94
94
|
</q-td>
|
|
95
95
|
</template>
|
|
96
96
|
<template #no-data>
|
|
97
|
-
<div class="sa-emh__empty">
|
|
97
|
+
<div class="sa-emh__empty">{{ msg.history.empty }}</div>
|
|
98
98
|
</template>
|
|
99
99
|
</q-table>
|
|
100
100
|
</div>
|
|
@@ -106,21 +106,36 @@
|
|
|
106
106
|
<template v-if="detail">
|
|
107
107
|
<q-card-section>
|
|
108
108
|
<div class="row items-center no-wrap q-gutter-sm">
|
|
109
|
-
<q-badge
|
|
109
|
+
<q-badge
|
|
110
|
+
:color="statusColor(detail.status)"
|
|
111
|
+
:label="statusLabel(detail.status)"
|
|
112
|
+
/>
|
|
110
113
|
<div class="text-h6 ellipsis">{{ detail.subject }}</div>
|
|
111
114
|
</div>
|
|
112
115
|
<div class="text-caption text-grey-7 q-mt-xs">
|
|
113
|
-
|
|
116
|
+
{{
|
|
117
|
+
formatMessage(msg.history.detailFromTo, {
|
|
118
|
+
from: detail.fromEmail,
|
|
119
|
+
to: detail.toEmail,
|
|
120
|
+
})
|
|
121
|
+
}}
|
|
114
122
|
<span v-if="detail.ccEmail"> · Cc {{ detail.ccEmail }}</span>
|
|
115
123
|
<span v-if="detail.bccEmail"> · Bcc {{ detail.bccEmail }}</span>
|
|
116
124
|
</div>
|
|
117
125
|
<div class="text-caption text-grey-7">
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
{{
|
|
127
|
+
formatMessage(msg.history.detailTimestamps, {
|
|
128
|
+
created: formatTs(detail.createdAt),
|
|
129
|
+
sent: formatTs(detail.sentAt),
|
|
130
|
+
})
|
|
131
|
+
}}
|
|
120
132
|
</div>
|
|
121
133
|
</q-card-section>
|
|
122
134
|
|
|
123
|
-
<q-card-section
|
|
135
|
+
<q-card-section
|
|
136
|
+
v-if="detail.status === 'FAILED' && detail.errorMessage"
|
|
137
|
+
class="q-pt-none"
|
|
138
|
+
>
|
|
124
139
|
<q-banner dense class="bg-red-1 text-red-9 sa-emh__error">
|
|
125
140
|
<template #avatar><q-icon name="error" color="negative" /></template>
|
|
126
141
|
{{ detail.errorMessage }}
|
|
@@ -137,12 +152,14 @@
|
|
|
137
152
|
referrerpolicy="no-referrer"
|
|
138
153
|
class="sa-emh__frame"
|
|
139
154
|
/>
|
|
140
|
-
<pre v-else-if="detail.bodyText" class="sa-emh__text">{{
|
|
141
|
-
|
|
155
|
+
<pre v-else-if="detail.bodyText" class="sa-emh__text">{{
|
|
156
|
+
detail.bodyText
|
|
157
|
+
}}</pre>
|
|
158
|
+
<div v-else class="text-grey-6">{{ msg.history.noContent }}</div>
|
|
142
159
|
</q-card-section>
|
|
143
160
|
|
|
144
161
|
<q-card-section v-if="detail.smtpResponse" class="q-pt-none">
|
|
145
|
-
<div class="text-caption text-grey-7">
|
|
162
|
+
<div class="text-caption text-grey-7">{{ msg.history.smtpResponse }}</div>
|
|
146
163
|
<pre class="sa-emh__smtp">{{ detail.smtpResponse }}</pre>
|
|
147
164
|
</q-card-section>
|
|
148
165
|
|
|
@@ -151,17 +168,17 @@
|
|
|
151
168
|
flat
|
|
152
169
|
color="negative"
|
|
153
170
|
icon="delete"
|
|
154
|
-
label="
|
|
171
|
+
:label="common.remove"
|
|
155
172
|
@click="askDelete(detail.id)"
|
|
156
173
|
/>
|
|
157
174
|
<q-btn
|
|
158
175
|
unelevated
|
|
159
176
|
color="primary"
|
|
160
177
|
icon="send"
|
|
161
|
-
label="
|
|
178
|
+
:label="msg.history.resend"
|
|
162
179
|
@click="onResend(detail.id)"
|
|
163
180
|
/>
|
|
164
|
-
<q-btn v-close-popup flat label="
|
|
181
|
+
<q-btn v-close-popup flat :label="common.close" />
|
|
165
182
|
</q-card-actions>
|
|
166
183
|
</template>
|
|
167
184
|
</q-card>
|
|
@@ -170,15 +187,19 @@
|
|
|
170
187
|
<q-dialog v-model="confirmDeleteOpen">
|
|
171
188
|
<q-card class="sa-emh__confirm">
|
|
172
189
|
<q-card-section>
|
|
173
|
-
<div class="text-h6">
|
|
190
|
+
<div class="text-h6">{{ msg.history.confirmRemoveTitle }}</div>
|
|
174
191
|
</q-card-section>
|
|
175
192
|
<q-card-section class="q-pt-none">
|
|
176
|
-
|
|
177
|
-
aber für das Audit erhalten.
|
|
193
|
+
{{ msg.history.confirmRemoveMessage }}
|
|
178
194
|
</q-card-section>
|
|
179
195
|
<q-card-actions align="right">
|
|
180
|
-
<q-btn v-close-popup flat label="
|
|
181
|
-
<q-btn
|
|
196
|
+
<q-btn v-close-popup flat :label="common.cancel" />
|
|
197
|
+
<q-btn
|
|
198
|
+
unelevated
|
|
199
|
+
color="negative"
|
|
200
|
+
:label="common.remove"
|
|
201
|
+
@click="confirmDelete"
|
|
202
|
+
/>
|
|
182
203
|
</q-card-actions>
|
|
183
204
|
</q-card>
|
|
184
205
|
</q-dialog>
|
|
@@ -196,9 +217,11 @@
|
|
|
196
217
|
</template>
|
|
197
218
|
|
|
198
219
|
<script setup lang="ts">
|
|
199
|
-
import { reactive, ref } from 'vue';
|
|
200
|
-
import {
|
|
220
|
+
import { computed, reactive, ref } from 'vue';
|
|
221
|
+
import { useSuperAdminNotify } from '../quasar/notify.js';
|
|
201
222
|
import MfaPromptDialog from '../components/MfaPromptDialog.vue';
|
|
223
|
+
import { formatMessage } from '../client/i18n/format.js';
|
|
224
|
+
import { useSaMessages, useSuperAdminI18n } from '../vue/use-super-admin-i18n.js';
|
|
202
225
|
import type {
|
|
203
226
|
EmailHistoryRow,
|
|
204
227
|
EmailHistoryDetail,
|
|
@@ -225,13 +248,18 @@ const props = withDefaults(
|
|
|
225
248
|
mfaSetupHint?: string;
|
|
226
249
|
}>(),
|
|
227
250
|
{
|
|
228
|
-
title: 'Plattform-E-Mail-Verlauf',
|
|
229
251
|
pageSize: 25,
|
|
230
252
|
requireMfaForWrite: false,
|
|
231
253
|
},
|
|
232
254
|
);
|
|
233
255
|
|
|
234
|
-
const
|
|
256
|
+
const notify = useSuperAdminNotify();
|
|
257
|
+
const msg = useSaMessages('email');
|
|
258
|
+
const common = useSaMessages('common');
|
|
259
|
+
const shell = useSaMessages('shell');
|
|
260
|
+
const { intlLocale } = useSuperAdminI18n();
|
|
261
|
+
|
|
262
|
+
const resolvedTitle = computed(() => props.title ?? msg.value.history.title);
|
|
235
263
|
|
|
236
264
|
const rows = ref<EmailHistoryRow[]>([]);
|
|
237
265
|
const loading = ref(false);
|
|
@@ -249,32 +277,37 @@ const pagination = ref({
|
|
|
249
277
|
rowsNumber: 0,
|
|
250
278
|
});
|
|
251
279
|
|
|
252
|
-
const statusOptions = [
|
|
253
|
-
{ label:
|
|
254
|
-
{ label:
|
|
255
|
-
{ label:
|
|
256
|
-
{ label:
|
|
257
|
-
];
|
|
258
|
-
|
|
259
|
-
const columns = [
|
|
260
|
-
{ name: 'status', label:
|
|
261
|
-
{ name: 'toEmail', label:
|
|
262
|
-
{
|
|
263
|
-
|
|
280
|
+
const statusOptions = computed(() => [
|
|
281
|
+
{ label: msg.value.history.statusSent, value: 'SENT' },
|
|
282
|
+
{ label: msg.value.history.statusFailed, value: 'FAILED' },
|
|
283
|
+
{ label: msg.value.history.statusPending, value: 'PENDING' },
|
|
284
|
+
{ label: msg.value.history.statusBounced, value: 'BOUNCED' },
|
|
285
|
+
]);
|
|
286
|
+
|
|
287
|
+
const columns = computed(() => [
|
|
288
|
+
{ name: 'status', label: common.value.status, field: 'status', align: 'left' as const },
|
|
289
|
+
{ name: 'toEmail', label: msg.value.recipient, field: 'toEmail', align: 'left' as const },
|
|
290
|
+
{
|
|
291
|
+
name: 'subject',
|
|
292
|
+
label: msg.value.history.columnSubject,
|
|
293
|
+
field: 'subject',
|
|
294
|
+
align: 'left' as const,
|
|
295
|
+
},
|
|
296
|
+
{ name: 'fromEmail', label: msg.value.sender, field: 'fromEmail', align: 'left' as const },
|
|
264
297
|
{
|
|
265
298
|
name: 'createdAt',
|
|
266
|
-
label:
|
|
299
|
+
label: msg.value.history.columnCreatedAt,
|
|
267
300
|
field: (r: EmailHistoryRow) => formatTs(r.createdAt),
|
|
268
301
|
align: 'left' as const,
|
|
269
302
|
},
|
|
270
303
|
{
|
|
271
304
|
name: 'sentAt',
|
|
272
|
-
label:
|
|
305
|
+
label: msg.value.history.columnSentAt,
|
|
273
306
|
field: (r: EmailHistoryRow) => formatTs(r.sentAt),
|
|
274
307
|
align: 'left' as const,
|
|
275
308
|
},
|
|
276
309
|
{ name: 'actions', label: '', field: 'id' as never, align: 'right' as const },
|
|
277
|
-
];
|
|
310
|
+
]);
|
|
278
311
|
|
|
279
312
|
const detailOpen = ref(false);
|
|
280
313
|
const detailLoading = ref(false);
|
|
@@ -312,7 +345,7 @@ async function reload(): Promise<void> {
|
|
|
312
345
|
if (seq !== reloadSeq) return;
|
|
313
346
|
rows.value = [];
|
|
314
347
|
pagination.value.rowsNumber = 0;
|
|
315
|
-
|
|
348
|
+
notify('negative', errMsg(err));
|
|
316
349
|
} finally {
|
|
317
350
|
if (seq === reloadSeq) loading.value = false;
|
|
318
351
|
}
|
|
@@ -342,25 +375,21 @@ async function openDetail(row: EmailHistoryRow): Promise<void> {
|
|
|
342
375
|
detail.value = await props.loadEmailDetail(row.id);
|
|
343
376
|
} catch (err) {
|
|
344
377
|
detailOpen.value = false;
|
|
345
|
-
|
|
378
|
+
notify('negative', errMsg(err));
|
|
346
379
|
} finally {
|
|
347
380
|
detailLoading.value = false;
|
|
348
381
|
}
|
|
349
382
|
}
|
|
350
383
|
|
|
351
384
|
async function onResend(id: string): Promise<void> {
|
|
352
|
-
const { ok, result } = await runWrite(
|
|
385
|
+
const { ok, result } = await runWrite(msg.value.history.mfaResend, (code) =>
|
|
353
386
|
props.resendEmail(id, code || undefined),
|
|
354
387
|
);
|
|
355
388
|
if (!ok) return;
|
|
356
389
|
if (result && result.success === false) {
|
|
357
|
-
|
|
358
|
-
type: 'negative',
|
|
359
|
-
message: result.message ?? 'Versand fehlgeschlagen',
|
|
360
|
-
position: 'top',
|
|
361
|
-
});
|
|
390
|
+
notify('negative', result.message ?? msg.value.history.sendFailed);
|
|
362
391
|
} else {
|
|
363
|
-
|
|
392
|
+
notify('positive', msg.value.history.resendSuccess);
|
|
364
393
|
}
|
|
365
394
|
await reload();
|
|
366
395
|
}
|
|
@@ -374,11 +403,11 @@ async function confirmDelete(): Promise<void> {
|
|
|
374
403
|
const id = pendingDeleteId.value;
|
|
375
404
|
confirmDeleteOpen.value = false;
|
|
376
405
|
if (!id) return;
|
|
377
|
-
const { ok } = await runWrite(
|
|
406
|
+
const { ok } = await runWrite(msg.value.history.mfaRemove, (code) =>
|
|
378
407
|
props.deleteEmail(id, code || undefined),
|
|
379
408
|
);
|
|
380
409
|
if (!ok) return;
|
|
381
|
-
|
|
410
|
+
notify('positive', msg.value.history.removeSuccess);
|
|
382
411
|
if (detail.value?.id === id) detailOpen.value = false;
|
|
383
412
|
await reload();
|
|
384
413
|
}
|
|
@@ -394,7 +423,7 @@ async function runWrite<T>(
|
|
|
394
423
|
const result = await invoke('');
|
|
395
424
|
return { ok: true, result };
|
|
396
425
|
} catch (err) {
|
|
397
|
-
|
|
426
|
+
notify('negative', errMsg(err));
|
|
398
427
|
return { ok: false };
|
|
399
428
|
}
|
|
400
429
|
}
|
|
@@ -408,11 +437,11 @@ async function runWrite<T>(
|
|
|
408
437
|
} catch (err) {
|
|
409
438
|
const status = (err as { response?: { status?: number } })?.response?.status;
|
|
410
439
|
if (status === 401) {
|
|
411
|
-
mfaError.value =
|
|
440
|
+
mfaError.value = shell.value.mfa.invalidCode;
|
|
412
441
|
continue;
|
|
413
442
|
}
|
|
414
443
|
showMfa.value = false;
|
|
415
|
-
|
|
444
|
+
notify('negative', errMsg(err));
|
|
416
445
|
return { ok: false };
|
|
417
446
|
}
|
|
418
447
|
}
|
|
@@ -457,13 +486,13 @@ function statusColor(status: EmailHistoryStatus): string {
|
|
|
457
486
|
function statusLabel(status: EmailHistoryStatus): string {
|
|
458
487
|
switch (status) {
|
|
459
488
|
case 'SENT':
|
|
460
|
-
return
|
|
489
|
+
return msg.value.history.statusSent;
|
|
461
490
|
case 'FAILED':
|
|
462
|
-
return
|
|
491
|
+
return msg.value.history.statusFailed;
|
|
463
492
|
case 'BOUNCED':
|
|
464
|
-
return
|
|
493
|
+
return msg.value.history.statusBounced;
|
|
465
494
|
default:
|
|
466
|
-
return
|
|
495
|
+
return msg.value.history.statusPending;
|
|
467
496
|
}
|
|
468
497
|
}
|
|
469
498
|
|
|
@@ -471,14 +500,14 @@ function errMsg(err: unknown): string {
|
|
|
471
500
|
return (
|
|
472
501
|
(err as { response?: { data?: { message?: string } } })?.response?.data?.message ??
|
|
473
502
|
(err as Error)?.message ??
|
|
474
|
-
|
|
503
|
+
msg.value.errorAction
|
|
475
504
|
);
|
|
476
505
|
}
|
|
477
506
|
|
|
478
507
|
function formatTs(iso: string | null | undefined): string {
|
|
479
508
|
if (!iso) return '—';
|
|
480
509
|
try {
|
|
481
|
-
return new Date(iso).toLocaleString(
|
|
510
|
+
return new Date(iso).toLocaleString(intlLocale.value, {
|
|
482
511
|
day: '2-digit',
|
|
483
512
|
month: 'short',
|
|
484
513
|
year: 'numeric',
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
/>
|
|
33
33
|
|
|
34
34
|
<div v-if="pageError" class="mc-banner mc-banner--error" role="alert">
|
|
35
|
-
<strong>
|
|
35
|
+
<strong>{{ common.error }}:</strong> {{ pageError }}
|
|
36
36
|
<button class="mc-banner-x" type="button" @click="pageError = null">×</button>
|
|
37
37
|
</div>
|
|
38
38
|
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
:active-locale="activeLocale"
|
|
44
44
|
/>
|
|
45
45
|
|
|
46
|
-
<div v-if="loading" class="mc-loading">
|
|
46
|
+
<div v-if="loading" class="mc-loading">{{ msg.page.loading }}</div>
|
|
47
47
|
|
|
48
48
|
<!-- ─── Tab: Promotions ─── -->
|
|
49
49
|
<MarketingPromotionsTab
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
/>
|
|
60
60
|
|
|
61
61
|
<div v-else-if="rows.length === 0" class="mc-banner mc-banner--info">
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
{{ msg.page.emptyPlansBefore }} <strong>{{ msg.page.emptyPlansLink }}</strong>
|
|
63
|
+
{{ msg.page.emptyPlansAfter }}
|
|
64
64
|
</div>
|
|
65
65
|
|
|
66
66
|
<MarketingCatalogPreview
|
|
@@ -122,11 +122,14 @@ import {
|
|
|
122
122
|
type PromotionResult,
|
|
123
123
|
type PromotionRow,
|
|
124
124
|
} from '@saasicat/types';
|
|
125
|
-
import { usePlans } from '../use-plans.js';
|
|
126
|
-
import { useMarketingProjections } from '../use-marketing-projections.js';
|
|
127
|
-
import { usePromotions } from '../use-promotions.js';
|
|
128
|
-
import { useCatalogEntries } from '../use-catalog-entries.js';
|
|
129
|
-
import {
|
|
125
|
+
import { usePlans } from '../vue/use-plans.js';
|
|
126
|
+
import { useMarketingProjections } from '../vue/use-marketing-projections.js';
|
|
127
|
+
import { usePromotions } from '../vue/use-promotions.js';
|
|
128
|
+
import { useCatalogEntries } from '../vue/use-catalog-entries.js';
|
|
129
|
+
import { formatCurrency } from '../client/i18n/currency.js';
|
|
130
|
+
import { useSaMessages, useSuperAdminI18n } from '../vue/use-super-admin-i18n.js';
|
|
131
|
+
import { formatMessage } from '../client/i18n/format.js';
|
|
132
|
+
import { defaultHttpClient, type HttpClient } from '../client/types.js';
|
|
130
133
|
import MarketingPromotionsTab from '../components/MarketingPromotionsTab.vue';
|
|
131
134
|
import MarketingCatalogAdmin from './marketing-catalog/MarketingCatalogAdmin.vue';
|
|
132
135
|
import MarketingCatalogHeader from './marketing-catalog/MarketingCatalogHeader.vue';
|
|
@@ -156,6 +159,10 @@ const props = defineProps<{
|
|
|
156
159
|
planAccents?: Record<string, string>;
|
|
157
160
|
}>();
|
|
158
161
|
|
|
162
|
+
const msg = useSaMessages('marketing');
|
|
163
|
+
const common = useSaMessages('common');
|
|
164
|
+
const { locale, intlLocale } = useSuperAdminI18n();
|
|
165
|
+
|
|
159
166
|
const availableLocales = computed(() =>
|
|
160
167
|
props.availableLocales && props.availableLocales.length > 0 ? props.availableLocales : ['de'],
|
|
161
168
|
);
|
|
@@ -457,15 +464,25 @@ function formatVersionTab(v: PlanVersionRow): string {
|
|
|
457
464
|
}
|
|
458
465
|
|
|
459
466
|
function formatVersionTitle(v: PlanVersionRow): string {
|
|
460
|
-
const from = v.validFrom
|
|
461
|
-
|
|
467
|
+
const from = v.validFrom
|
|
468
|
+
? formatDateLong(v.validFrom)
|
|
469
|
+
: msg.value.admin.versionValidFromUnknown;
|
|
470
|
+
const until = v.validUntil ? formatDateLong(v.validUntil) : common.value.unlimited;
|
|
462
471
|
const changeNote = v.changeNote ? ` — ${v.changeNote}` : '';
|
|
463
|
-
return
|
|
472
|
+
return formatMessage(msg.value.admin.versionTitle, {
|
|
473
|
+
version: v.version,
|
|
474
|
+
from,
|
|
475
|
+
until,
|
|
476
|
+
changeNote,
|
|
477
|
+
});
|
|
464
478
|
}
|
|
465
479
|
|
|
466
480
|
function formatDateShort(iso: string): string {
|
|
467
481
|
try {
|
|
468
|
-
return new Date(iso).toLocaleDateString(
|
|
482
|
+
return new Date(iso).toLocaleDateString(intlLocale.value, {
|
|
483
|
+
day: '2-digit',
|
|
484
|
+
month: '2-digit',
|
|
485
|
+
});
|
|
469
486
|
} catch {
|
|
470
487
|
return iso.slice(0, 10);
|
|
471
488
|
}
|
|
@@ -473,7 +490,7 @@ function formatDateShort(iso: string): string {
|
|
|
473
490
|
|
|
474
491
|
function formatDateLong(iso: string): string {
|
|
475
492
|
try {
|
|
476
|
-
return new Date(iso).toLocaleDateString(
|
|
493
|
+
return new Date(iso).toLocaleDateString(intlLocale.value, {
|
|
477
494
|
day: '2-digit',
|
|
478
495
|
month: 'short',
|
|
479
496
|
year: 'numeric',
|
|
@@ -577,9 +594,7 @@ function yearlyOf(row: MarketingRow): number {
|
|
|
577
594
|
return row.liveVersion ? Number.parseFloat(row.liveVersion.yearlyNet) || 0 : 0;
|
|
578
595
|
}
|
|
579
596
|
function formatEuro(value: number): string {
|
|
580
|
-
|
|
581
|
-
const text = Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(2).replace('.', ',');
|
|
582
|
-
return `${text} €`;
|
|
597
|
+
return formatCurrency(Math.round(value * 100) / 100, locale.value);
|
|
583
598
|
}
|
|
584
599
|
|
|
585
600
|
// ─── Promo application in the preview (SPEC_V2 §9a) ───
|
|
@@ -601,7 +616,11 @@ function promoResultOf(row: MarketingRow): PromotionResult | null {
|
|
|
601
616
|
function promoBadgeOf(row: MarketingRow): string {
|
|
602
617
|
const promo = promoOf(row);
|
|
603
618
|
if (!promo) return '';
|
|
604
|
-
return
|
|
619
|
+
return (
|
|
620
|
+
promo.i18n?.[activeLocale.value]?.badge ||
|
|
621
|
+
promo.i18n?.de?.badge ||
|
|
622
|
+
msg.value.preview.promoBadgeFallback
|
|
623
|
+
);
|
|
605
624
|
}
|
|
606
625
|
function promoFineprintOf(row: MarketingRow): string {
|
|
607
626
|
const promo = promoOf(row);
|
|
@@ -614,9 +633,9 @@ function promoColorOf(row: MarketingRow): string {
|
|
|
614
633
|
|
|
615
634
|
// ─── CTA ───
|
|
616
635
|
function autoCtaText(row: MarketingRow): string {
|
|
617
|
-
if (!row.liveVersion) return
|
|
618
|
-
if (row.m.trialEnabled) return
|
|
619
|
-
return
|
|
636
|
+
if (!row.liveVersion) return msg.value.cta.contact;
|
|
637
|
+
if (row.m.trialEnabled) return formatMessage(msg.value.cta.trial, { days: row.m.trialDays });
|
|
638
|
+
return msg.value.cta.choosePlan;
|
|
620
639
|
}
|
|
621
640
|
function ctaText(row: MarketingRow): string {
|
|
622
641
|
return row.m.ctaLabel && row.m.ctaLabel.length > 0 ? row.m.ctaLabel : autoCtaText(row);
|