@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.
Files changed (214) hide show
  1. package/README.md +64 -4
  2. package/dist/chunk-A3W2N26K.js +714 -0
  3. package/dist/chunk-QZOSDCNP.js +98 -0
  4. package/dist/chunk-X5SQ5HMB.js +3231 -0
  5. package/dist/client/index.cjs +3988 -0
  6. package/dist/client/index.d.cts +321 -0
  7. package/dist/client/index.d.ts +321 -0
  8. package/dist/client/index.js +70 -0
  9. package/dist/index.cjs +4446 -1249
  10. package/dist/index.d.cts +297 -888
  11. package/dist/index.d.ts +297 -888
  12. package/dist/index.js +609 -1348
  13. package/dist/messages-7b0P8W75.d.cts +1652 -0
  14. package/dist/messages-7b0P8W75.d.ts +1652 -0
  15. package/dist/quasar/index.cjs +3340 -0
  16. package/dist/quasar/index.d.cts +95 -0
  17. package/dist/quasar/index.d.ts +95 -0
  18. package/dist/quasar/index.js +96 -0
  19. package/dist/testing-e2e/admin-pages-suite.cjs +14 -11
  20. package/dist/testing-e2e/admin-pages-suite.js +14 -11
  21. package/dist/use-super-admin-i18n-B3v3-SWZ.d.ts +210 -0
  22. package/dist/use-super-admin-i18n-DMktRVEt.d.cts +210 -0
  23. package/package.json +23 -3
  24. package/src/{action-registry.ts → client/action-registry.ts} +4 -4
  25. package/src/{batch-column-fetcher.ts → client/batch-column-fetcher.ts} +4 -4
  26. package/src/{boot-loader.ts → client/boot-loader.ts} +3 -3
  27. package/src/client/i18n/currency.ts +42 -0
  28. package/src/client/i18n/define.ts +59 -0
  29. package/src/client/i18n/format.ts +12 -0
  30. package/src/client/i18n/index.ts +14 -0
  31. package/src/client/i18n/locale.ts +15 -0
  32. package/src/client/i18n/messages/audit.ts +42 -0
  33. package/src/client/i18n/messages/bundles.ts +459 -0
  34. package/src/client/i18n/messages/common.ts +147 -0
  35. package/src/client/i18n/messages/dashboard.ts +16 -0
  36. package/src/client/i18n/messages/discovery.ts +229 -0
  37. package/src/client/i18n/messages/email.ts +125 -0
  38. package/src/client/i18n/messages/marketing.ts +270 -0
  39. package/src/client/i18n/messages/nav.ts +72 -0
  40. package/src/client/i18n/messages/pilots.ts +192 -0
  41. package/src/client/i18n/messages/plan-detail.ts +266 -0
  42. package/src/client/i18n/messages/plan-editor.ts +177 -0
  43. package/src/client/i18n/messages/plan-versions.ts +251 -0
  44. package/src/client/i18n/messages/plans.ts +503 -0
  45. package/src/client/i18n/messages/promos.ts +202 -0
  46. package/src/client/i18n/messages/shell.ts +145 -0
  47. package/src/client/i18n/messages/tenants.ts +104 -0
  48. package/src/client/i18n/messages/users.ts +78 -0
  49. package/src/client/i18n/messages.ts +84 -0
  50. package/src/client/index.ts +27 -0
  51. package/src/{manifest-loader.ts → client/manifest-loader.ts} +4 -4
  52. package/src/{nav-builder.ts → client/nav-builder.ts} +44 -51
  53. package/src/{plan-versions-catalog.ts → client/plan-versions-catalog.ts} +42 -30
  54. package/src/components/BundleVersionPublishDialog.vue +35 -24
  55. package/src/components/FeatureGate.vue +1 -1
  56. package/src/components/MarketingPromotionsTab.vue +112 -59
  57. package/src/components/MfaPromptDialog.vue +11 -11
  58. package/src/components/TenantActionConfirmDialog.vue +19 -17
  59. package/src/components/VersionDiffPreview.vue +72 -43
  60. package/src/components/bundle-editor/BundleCreatePanel.vue +76 -63
  61. package/src/components/bundle-editor/BundleFeaturesEditor.vue +13 -6
  62. package/src/components/bundle-editor/BundlePlanCompatPicker.vue +19 -14
  63. package/src/components/bundle-editor/BundleQuotasEditor.vue +7 -4
  64. package/src/components/bundle-editor/BundleStatusBanner.vue +36 -19
  65. package/src/components/bundle-editor/BundleVersionInlineEditor.vue +51 -35
  66. package/src/components/bundle-editor/BundleVersionStrip.vue +24 -12
  67. package/src/components/bundle-editor/bundle-version-status.ts +29 -29
  68. package/src/components/dialogs/PilotCreateDialog.vue +58 -63
  69. package/src/components/dialogs/PilotEditDialog.vue +40 -34
  70. package/src/components/dialogs/PromoCodeCreateDialog.vue +89 -63
  71. package/src/components/dialogs/PromoCodeEditDialog.vue +98 -66
  72. package/src/components/dialogs/types.ts +3 -13
  73. package/src/components/plan/PlanCycleToggle.vue +21 -10
  74. package/src/components/plan/PlanGrid.vue +2 -2
  75. package/src/components/plan/PriceSummary.vue +1 -1
  76. package/src/components/plan/PromoCodeInput.vue +1 -1
  77. package/src/components/plan/PublicBundleGrid.vue +1 -1
  78. package/src/components/plan-cockpit/PlanCockpit.vue +34 -15
  79. package/src/components/plan-cockpit/PlanCockpitAuditLog.vue +13 -6
  80. package/src/components/plan-cockpit/PlanCockpitDiffPanel.vue +18 -9
  81. package/src/components/plan-cockpit/PlanCockpitHeader.vue +9 -6
  82. package/src/components/plan-cockpit/PlanCockpitImpactPanel.vue +24 -11
  83. package/src/components/plan-cockpit/PlanCockpitKpis.vue +28 -17
  84. package/src/components/plan-cockpit/PlanCockpitVersions.vue +50 -25
  85. package/src/components/plan-create-dialog/PlanCreateDialog.vue +45 -35
  86. package/src/components/plan-detail/PlanAuditLog.vue +11 -6
  87. package/src/components/plan-detail/PlanDetail.vue +21 -23
  88. package/src/components/plan-detail/PlanDetailHeader.vue +20 -11
  89. package/src/components/plan-detail/PlanDetailKpis.vue +30 -17
  90. package/src/components/plan-detail/PlanTerminateDialog.vue +22 -9
  91. package/src/components/plan-detail/PlanVersionDiffPanel.vue +61 -27
  92. package/src/components/plan-detail/PlanVersionsPanel.vue +71 -36
  93. package/src/components/plan-list/PlanList.vue +99 -57
  94. package/src/components/plan-matrix/PlanMatrix.vue +85 -38
  95. package/src/components/plan-review/PlanReview.vue +105 -80
  96. package/src/components/plan-version-editor/PlanCatalogPreview.vue +43 -20
  97. package/src/components/plan-version-editor/PlanComponentPool.vue +15 -7
  98. package/src/components/plan-version-editor/PlanVersionBasket.vue +45 -24
  99. package/src/components/plan-version-editor/PlanVersionDiffDialog.vue +8 -7
  100. package/src/components/plan-version-editor/PlanVersionEditor.vue +74 -40
  101. package/src/components/plan-version-editor/PlanVersionEditorHeader.vue +24 -12
  102. package/src/index.ts +82 -79
  103. package/src/pages-standard/AdminLayout.vue +43 -18
  104. package/src/pages-standard/AdminManifestErrorPage.vue +10 -10
  105. package/src/pages-standard/AuditPage.vue +58 -19
  106. package/src/pages-standard/BundlesPage.vue +29 -18
  107. package/src/pages-standard/DashboardPage.vue +31 -17
  108. package/src/pages-standard/DiscoveryPage.vue +40 -28
  109. package/src/pages-standard/EmailHistoryPage.vue +98 -69
  110. package/src/pages-standard/MarketingCatalogPage.vue +40 -21
  111. package/src/pages-standard/PilotsPage.vue +64 -52
  112. package/src/pages-standard/PlanVersionsPage.vue +9 -5
  113. package/src/pages-standard/PlansPage.vue +91 -59
  114. package/src/pages-standard/PlatformEmailPage.vue +120 -53
  115. package/src/pages-standard/PromoCodeDetailPage.vue +66 -63
  116. package/src/pages-standard/PromoCodesPage.vue +51 -54
  117. package/src/pages-standard/SubscriptionsPage.vue +14 -9
  118. package/src/pages-standard/SuperAdminLoginPage.vue +19 -16
  119. package/src/pages-standard/SuperAdminSetupWizard.vue +53 -49
  120. package/src/pages-standard/TenantDetailPage.vue +54 -40
  121. package/src/pages-standard/TenantsPage.vue +57 -44
  122. package/src/pages-standard/UsersPage.vue +70 -52
  123. package/src/pages-standard/bundles-page/BundleAccordionList.vue +20 -8
  124. package/src/pages-standard/bundles-page/BundleDetailPanel.vue +28 -18
  125. package/src/pages-standard/bundles-page/BundlesFilterBar.vue +4 -1
  126. package/src/pages-standard/bundles-page/BundlesHeader.vue +9 -8
  127. package/src/pages-standard/bundles-page/BundlesKpis.vue +29 -11
  128. package/src/pages-standard/discovery-page/CatalogEntryTransPanel.vue +20 -8
  129. package/src/pages-standard/discovery-page/DiscoveryCapList.vue +5 -3
  130. package/src/pages-standard/discovery-page/DiscoveryFeatureCard.vue +43 -24
  131. package/src/pages-standard/discovery-page/DiscoveryHeader.vue +7 -4
  132. package/src/pages-standard/discovery-page/DiscoveryKpis.vue +28 -15
  133. package/src/pages-standard/discovery-page/DiscoveryQuotaCard.vue +20 -10
  134. package/src/pages-standard/discovery-page/DiscoveryStatusControl.vue +9 -6
  135. package/src/pages-standard/discovery-page/discovery-ui.ts +40 -52
  136. package/src/pages-standard/marketing-catalog/MarketingCatalogAdmin.vue +81 -49
  137. package/src/pages-standard/marketing-catalog/MarketingCatalogHeader.vue +13 -10
  138. package/src/pages-standard/marketing-catalog/MarketingCatalogPreview.vue +24 -20
  139. package/src/pages-standard/marketing-catalog/MarketingCatalogToolbar.vue +6 -3
  140. package/src/pages-standard/plan-versions/PlanDiffCard.vue +16 -6
  141. package/src/pages-standard/plan-versions/PlanVersionHeader.vue +42 -26
  142. package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +46 -27
  143. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +8 -6
  144. package/src/pages-standard/plan-versions/PlanVersionsList.vue +40 -17
  145. package/src/pages-standard/plan-versions/PlanVersionsMatrix.vue +1 -1
  146. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +25 -13
  147. package/src/pages-standard/plan-versions/format.ts +33 -17
  148. package/src/pages-standard/plans-page/PlanArchiveDialog.vue +12 -8
  149. package/src/pages-standard/plans-page/PlanBundleOverview.vue +15 -6
  150. package/src/pages-standard/plans-page/PlanDiscardDraftDialog.vue +18 -7
  151. package/src/pages-standard/plans-page/PlanPublishDialog.vue +23 -12
  152. package/src/pages-standard/tenants/format.ts +3 -2
  153. package/src/pages-tenant/MySubscriptionBundlesPage.vue +73 -38
  154. package/src/pages-tenant/OnboardingConfigurator.vue +3 -3
  155. package/src/pages-tenant/PackageSnapshotPanel.vue +1 -1
  156. package/src/pages-tenant/PlanChangeWizard.vue +10 -6
  157. package/src/pages-tenant/TenantPlanSection.vue +20 -16
  158. package/src/pages-tenant/default-i18n.ts +217 -1
  159. package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +9 -7
  160. package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +11 -12
  161. package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +4 -1
  162. package/src/pages-tenant/tenant-plan-section/TenantPlanCardHeader.vue +1 -1
  163. package/src/pages-tenant/tenant-plan-section/TenantUsageGrid.vue +1 -1
  164. package/src/quasar/create-super-admin-app.ts +192 -0
  165. package/src/quasar/index.ts +11 -0
  166. package/src/quasar/notify.ts +30 -0
  167. package/src/testing-e2e/admin-pages-suite.ts +14 -11
  168. package/src/{manifest-store-factory.ts → vue/manifest-store-factory.ts} +1 -1
  169. package/src/{platform-loaders.ts → vue/platform-loaders.ts} +4 -4
  170. package/src/{project-page-host.ts → vue/project-page-host.ts} +6 -4
  171. package/src/{create-super-admin-app.ts → vue/super-admin-context.ts} +20 -139
  172. package/src/vue/ui-notify.ts +30 -0
  173. package/src/{use-actions.ts → vue/use-actions.ts} +1 -1
  174. package/src/{use-api-list.ts → vue/use-api-list.ts} +1 -1
  175. package/src/{use-audit-entries.ts → vue/use-audit-entries.ts} +3 -3
  176. package/src/{use-batch-columns.ts → vue/use-batch-columns.ts} +1 -1
  177. package/src/{use-bulk-publish.ts → vue/use-bulk-publish.ts} +7 -5
  178. package/src/{use-bundle-versions-map.ts → vue/use-bundle-versions-map.ts} +7 -5
  179. package/src/{use-bundles.ts → vue/use-bundles.ts} +14 -14
  180. package/src/{use-catalog-entries.ts → vue/use-catalog-entries.ts} +14 -11
  181. package/src/{use-discovery.ts → vue/use-discovery.ts} +9 -6
  182. package/src/{use-entitlement.ts → vue/use-entitlement.ts} +4 -4
  183. package/src/{use-live-plan-versions.ts → vue/use-live-plan-versions.ts} +5 -5
  184. package/src/{use-manifest.ts → vue/use-manifest.ts} +1 -1
  185. package/src/{use-marketing-projections.ts → vue/use-marketing-projections.ts} +10 -7
  186. package/src/{use-nav.ts → vue/use-nav.ts} +9 -3
  187. package/src/{use-plan-editor.ts → vue/use-plan-editor.ts} +2 -2
  188. package/src/{use-plan-versions.ts → vue/use-plan-versions.ts} +3 -3
  189. package/src/{use-plans.ts → vue/use-plans.ts} +13 -13
  190. package/src/{use-platform-tenant-actions.ts → vue/use-platform-tenant-actions.ts} +9 -6
  191. package/src/{use-promotions.ts → vue/use-promotions.ts} +10 -11
  192. package/src/{use-public-boot.ts → vue/use-public-boot.ts} +1 -1
  193. package/src/{use-subscription-draft.ts → vue/use-subscription-draft.ts} +2 -3
  194. package/src/{use-super-admin-context.ts → vue/use-super-admin-context.ts} +5 -5
  195. package/src/vue/use-super-admin-i18n.ts +82 -0
  196. package/src/{use-tenant-action-flow.ts → vue/use-tenant-action-flow.ts} +12 -7
  197. package/src/{use-tenant-billing-catalog.ts → vue/use-tenant-billing-catalog.ts} +2 -2
  198. package/src/{use-tenant-billing.ts → vue/use-tenant-billing.ts} +2 -2
  199. package/src/{use-tenant-manifest.ts → vue/use-tenant-manifest.ts} +2 -4
  200. package/src/{use-tenant-subscription-bundles.ts → vue/use-tenant-subscription-bundles.ts} +5 -5
  201. package/src/{use-tenants.ts → vue/use-tenants.ts} +3 -3
  202. package/dist/testing-e2e/admin-pages-suite.d.cts +0 -37
  203. package/dist/testing-e2e/admin-pages-suite.d.ts +0 -37
  204. package/src/components/BusinessTypeVersionEditorDialog.vue +0 -417
  205. package/src/components/BusinessTypeVersionPublishDialog.vue +0 -258
  206. package/src/pages-standard/BusinessTypesPage.vue +0 -662
  207. package/src/pages-standard/plan-versions/VersionDiffPreview.vue +0 -167
  208. package/src/use-business-types.ts +0 -269
  209. /package/src/{http-json.ts → client/http-json.ts} +0 -0
  210. /package/src/{types.ts → client/types.ts} +0 -0
  211. /package/src/{version.ts → client/version.ts} +0 -0
  212. /package/src/{create-admin-routes.ts → vue/create-admin-routes.ts} +0 -0
  213. /package/src/{entitlement-provider.ts → vue/entitlement-provider.ts} +0 -0
  214. /package/src/{feature-router-guard.ts → vue/feature-router-guard.ts} +0 -0
@@ -1,15 +1,12 @@
1
1
  <template>
2
2
  <div class="mc-page-head">
3
3
  <div>
4
- <h2 class="mc-h-title">Marketing-Catalog</h2>
5
- <p class="mc-h-sub">
6
- Öffentliche Marketing-Projektion · gefilterte Sicht für Website, Pricing-Page und
7
- Checkout
8
- </p>
4
+ <h2 class="mc-h-title">{{ msg.header.title }}</h2>
5
+ <p class="mc-h-sub">{{ msg.header.subtitle }}</p>
9
6
  </div>
10
7
  <div class="mc-head-actions">
11
8
  <div class="mc-locale-mgr">
12
- <span class="mc-locale-mgr-label">Sprachen:</span>
9
+ <span class="mc-locale-mgr-label">{{ msg.header.localesLabel }}</span>
13
10
  <span
14
11
  v-for="loc in activeLocaleSet"
15
12
  :key="loc"
@@ -22,13 +19,15 @@
22
19
  @click="$emit('localeChange', loc)"
23
20
  >
24
21
  {{ loc.toUpperCase() }}
25
- <span v-if="loc === defaultLocale" title="Default-Sprache">★</span>
22
+ <span v-if="loc === defaultLocale" :title="msg.header.defaultLocale"
23
+ >★</span
24
+ >
26
25
  </button>
27
26
  <button
28
27
  v-if="loc !== defaultLocale"
29
28
  type="button"
30
29
  class="mc-locale-x"
31
- title="Sprache deaktivieren"
30
+ :title="msg.header.deactivateLocale"
32
31
  @click="$emit('removeLocale', loc)"
33
32
  >
34
33
  ×
@@ -41,7 +40,7 @@
41
40
  :disabled="addableLocales.length === 0"
42
41
  @click="$emit('update:localePickerOpen', !localePickerOpen)"
43
42
  >
44
- + Sprache
43
+ {{ msg.header.addLocale }}
45
44
  </button>
46
45
  <div v-if="localePickerOpen" class="mc-locale-picker">
47
46
  <button
@@ -67,13 +66,15 @@
67
66
  >
68
67
  <path d="M21 12a9 9 0 1 1-3-6.7M21 3v6h-6" />
69
68
  </svg>
70
- <span>Aktualisieren</span>
69
+ <span>{{ msg.header.refresh }}</span>
71
70
  </button>
72
71
  </div>
73
72
  </div>
74
73
  </template>
75
74
 
76
75
  <script setup lang="ts">
76
+ import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
77
+
77
78
  defineProps<{
78
79
  activeLocaleSet: string[];
79
80
  activeLocale: string;
@@ -90,4 +91,6 @@ defineEmits<{
90
91
  (e: 'update:localePickerOpen', value: boolean): void;
91
92
  (e: 'reload'): void;
92
93
  }>();
94
+
95
+ const msg = useSaMessages('marketing');
93
96
  </script>
@@ -7,15 +7,13 @@
7
7
  <div class="mc-chrome-url">{{ previewUrl }}</div>
8
8
  </div>
9
9
  <div class="mc-canvas">
10
- <div class="mc-eyebrow">Preise &amp; Pakete</div>
11
- <h1 class="mc-hero">Der passende Plan</h1>
12
- <p class="mc-sub">
13
- Flexibel skalieren, jederzeit upgraden. Kein Setup-Fee, monatlich kündbar.
14
- </p>
10
+ <div class="mc-eyebrow">{{ msg.preview.eyebrow }}</div>
11
+ <h1 class="mc-hero">{{ msg.preview.hero }}</h1>
12
+ <p class="mc-sub">{{ msg.preview.sub }}</p>
15
13
 
16
14
  <div v-if="visibleRows.length === 0" class="mc-banner mc-banner--info">
17
- Kein Plan ist aktuell für den Public-Catalog sichtbar. Aktiviere die Sichtbarkeit im
18
- Tab <strong>Marketing-Verwaltung</strong>.
15
+ {{ msg.preview.emptyBefore }} <strong>{{ msg.tabs.admin }}</strong
16
+ >{{ msg.preview.emptyAfter }}
19
17
  </div>
20
18
 
21
19
  <div v-else class="mc-grid">
@@ -49,42 +47,46 @@
49
47
  </template>
50
48
  <template v-else-if="!row.liveVersion">
51
49
  <span class="mc-card-price-big" style="font-size: 22px">
52
- Auf Anfrage
50
+ {{ msg.preview.priceOnRequest }}
53
51
  </span>
54
52
  </template>
55
53
  <template v-else-if="promoResultOf(row)">
56
54
  <span class="mc-card-price-big">
57
55
  {{ formatEuro(promoResultOf(row)?.discounted ?? 0) }}
58
56
  </span>
59
- <span class="mc-card-price-unit">/ Monat</span>
57
+ <span class="mc-card-price-unit">{{ msg.preview.perMonth }}</span>
60
58
  </template>
61
59
  <template v-else>
62
60
  <span class="mc-card-price-big">
63
61
  {{ formatEuro(monthlyOf(row)) }}
64
62
  </span>
65
- <span class="mc-card-price-unit">/ Monat</span>
63
+ <span class="mc-card-price-unit">{{ msg.preview.perMonth }}</span>
66
64
  </template>
67
65
  </div>
68
66
  <div v-if="promoResultOf(row)" class="mc-card-price-strike">
69
67
  <s>{{ formatEuro(promoResultOf(row)?.original ?? 0) }}</s>
70
- <span class="mc-price-regular">regulär</span>
68
+ <span class="mc-price-regular">{{ msg.preview.regularPrice }}</span>
71
69
  </div>
72
70
  <div
73
71
  v-else-if="row.liveVersion && yearlyOf(row) > 0 && !row.m.priceTag"
74
72
  class="mc-card-price-y"
75
73
  >
76
- oder {{ formatEuro(yearlyOf(row)) }} jährlich
74
+ {{
75
+ formatMessage(msg.preview.orYearly, {
76
+ price: formatEuro(yearlyOf(row)),
77
+ })
78
+ }}
77
79
  </div>
78
80
 
79
81
  <button type="button" class="mc-card-cta">{{ ctaText(row) }}</button>
80
82
  <div v-if="showTrialNote(row) && !promoOf(row)" class="mc-card-trialnote">
81
- {{ row.m.trialDays }} Tage kostenlos · keine Kreditkarte nötig
83
+ {{ formatMessage(msg.preview.trialNote, { days: row.m.trialDays }) }}
82
84
  </div>
83
85
  <div v-if="promoFineprintOf(row)" class="mc-card-fineprint">
84
86
  {{ promoFineprintOf(row) }}
85
87
  </div>
86
88
 
87
- <div class="mc-card-includes">Top-Features</div>
89
+ <div class="mc-card-includes">{{ msg.topFeatures }}</div>
88
90
  <ul v-if="row.m.topFeatures.length > 0" class="mc-card-features">
89
91
  <li v-for="(f, i) in row.m.topFeatures" :key="i">
90
92
  <span class="mc-tick">
@@ -105,7 +107,9 @@
105
107
  </span>
106
108
  </li>
107
109
  </ul>
108
- <div v-else class="mc-card-features-empty">Keine Top-Features gepflegt.</div>
110
+ <div v-else class="mc-card-features-empty">
111
+ {{ msg.preview.noTopFeatures }}
112
+ </div>
109
113
  </div>
110
114
  </div>
111
115
  </div>
@@ -113,11 +117,9 @@
113
117
  </template>
114
118
 
115
119
  <script setup lang="ts">
116
- import type {
117
- MarketingTopFeature,
118
- PromotionResult,
119
- PromotionRow,
120
- } from '@saasicat/types';
120
+ import type { MarketingTopFeature, PromotionResult, PromotionRow } from '@saasicat/types';
121
+ import { formatMessage } from '../../client/i18n/format.js';
122
+ import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
121
123
  import type { MarketingRow } from './types.js';
122
124
 
123
125
  defineProps<{
@@ -135,4 +137,6 @@ defineProps<{
135
137
  showTrialNote: (row: MarketingRow) => boolean;
136
138
  topFeatureLabel: (feature: MarketingTopFeature) => string;
137
139
  }>();
140
+
141
+ const msg = useSaMessages('marketing');
138
142
  </script>
@@ -7,7 +7,7 @@
7
7
  :class="{ active: tab === 'preview' }"
8
8
  @click="$emit('update:tab', 'preview')"
9
9
  >
10
- Public-Catalog Vorschau
10
+ {{ msg.tabs.preview }}
11
11
  </button>
12
12
  <button
13
13
  type="button"
@@ -15,7 +15,7 @@
15
15
  :class="{ active: tab === 'admin' }"
16
16
  @click="$emit('update:tab', 'admin')"
17
17
  >
18
- Marketing-Verwaltung
18
+ {{ msg.tabs.admin }}
19
19
  </button>
20
20
  <button
21
21
  type="button"
@@ -23,7 +23,7 @@
23
23
  :class="{ active: tab === 'promos' }"
24
24
  @click="$emit('update:tab', 'promos')"
25
25
  >
26
- Aktionen
26
+ {{ msg.tabs.promos }}
27
27
  <span v-if="activePromoCount > 0" class="mc-tab-count">
28
28
  {{ activePromoCount }}
29
29
  </span>
@@ -43,6 +43,7 @@
43
43
  </template>
44
44
 
45
45
  <script setup lang="ts">
46
+ import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
46
47
  import type { MarketingCatalogTab } from './types.js';
47
48
 
48
49
  defineProps<{
@@ -55,4 +56,6 @@ defineProps<{
55
56
  defineEmits<{
56
57
  (e: 'update:tab', tab: MarketingCatalogTab): void;
57
58
  }>();
59
+
60
+ const msg = useSaMessages('marketing');
58
61
  </script>
@@ -6,7 +6,7 @@
6
6
  {{ title }}
7
7
  <span v-if="versionNew" class="sa-pv-diff-card__ver">v{{ versionNew }}</span>
8
8
  </div>
9
- <div class="sa-pv-diff-card__sub">Keine Änderungen</div>
9
+ <div class="sa-pv-diff-card__sub">{{ common.noChanges }}</div>
10
10
  </div>
11
11
  </div>
12
12
  <div v-else class="sa-pv-diff-card">
@@ -27,9 +27,7 @@
27
27
  <span v-else-if="versionOld != null" class="sa-pv-diff-card__ver"
28
28
  >− v{{ versionOld }}</span
29
29
  >
30
- <span class="sa-pv-diff-card__count">
31
- {{ changes.length }} Änderung{{ changes.length !== 1 ? 'en' : '' }}
32
- </span>
30
+ <span class="sa-pv-diff-card__count">{{ changeCountLabel }}</span>
33
31
  </header>
34
32
  <div class="sa-pv-diff-card__body">
35
33
  <VersionDiffPreview :changes="changes" :field-labels="fieldLabels" />
@@ -38,10 +36,13 @@
38
36
  </template>
39
37
 
40
38
  <script setup lang="ts">
39
+ import { computed } from 'vue';
41
40
  import type { VersionChange } from '@saasicat/types';
42
- import VersionDiffPreview from './VersionDiffPreview.vue';
41
+ import { formatMessage } from '../../client/i18n/format.js';
42
+ import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
43
+ import VersionDiffPreview from '../../components/VersionDiffPreview.vue';
43
44
 
44
- defineProps<{
45
+ const props = defineProps<{
45
46
  title: string;
46
47
  versionOld: number | null;
47
48
  versionNew: number | null;
@@ -49,6 +50,15 @@ defineProps<{
49
50
  changes: VersionChange[];
50
51
  fieldLabels?: Record<string, string>;
51
52
  }>();
53
+
54
+ const msg = useSaMessages('planVersions');
55
+ const common = useSaMessages('common');
56
+
57
+ const changeCountLabel = computed(() => {
58
+ const count = props.changes.length;
59
+ const template = count === 1 ? msg.value.diff.changeCountOne : msg.value.diff.changeCountMany;
60
+ return formatMessage(template, { count });
61
+ });
52
62
  </script>
53
63
 
54
64
  <style scoped>
@@ -15,7 +15,7 @@
15
15
  class="sa-pv-header__cmp-btn"
16
16
  @click="emit('clearCompare')"
17
17
  >
18
- <q-icon name="close" size="14px" /> Vergleich beenden
18
+ <q-icon name="close" size="14px" /> {{ msg.compareEnd }}
19
19
  </button>
20
20
  </template>
21
21
  </div>
@@ -28,23 +28,21 @@
28
28
  class="sa-pv-header__meta-item sa-pv-header__meta-item--ok"
29
29
  >
30
30
  <q-icon name="rocket_launch" size="14px" />
31
- Publiziert {{ formatDateDe(snapshot.publishedAt) }}
31
+ {{ publishedOnLabel }}
32
32
  </span>
33
33
  <span
34
34
  v-if="snapshot.kind === 'drafts'"
35
35
  class="sa-pv-header__meta-item sa-pv-header__meta-item--warn"
36
36
  >
37
37
  <q-icon name="edit_note" size="14px" />
38
- <strong>{{ snapshot.draftCount }}</strong> offene Drafts
38
+ <strong>{{ snapshot.draftCount }}</strong> {{ msg.header.openDrafts }}
39
39
  </span>
40
40
  <span
41
41
  v-if="snapshot.regressionCount > 0"
42
42
  class="sa-pv-header__meta-item sa-pv-header__meta-item--bad"
43
43
  >
44
44
  <q-icon name="trending_down" size="14px" />
45
- <strong>{{ snapshot.regressionCount }}</strong> Regression{{
46
- snapshot.regressionCount === 1 ? '' : 'en'
47
- }}
45
+ <strong>{{ snapshot.regressionCount }}</strong> {{ regressionLabel }}
48
46
  </span>
49
47
  </div>
50
48
  </div>
@@ -57,7 +55,7 @@
57
55
  @click="emit('publish')"
58
56
  >
59
57
  <q-icon name="rocket_launch" size="16px" />
60
- Publish-Flow starten
58
+ {{ msg.header.startPublishFlow }}
61
59
  </button>
62
60
  </div>
63
61
  </div>
@@ -68,7 +66,7 @@
68
66
  :class="{ 'sa-pv-header__switcher--disabled': !!compareSnapshot }"
69
67
  >
70
68
  <button
71
- v-for="m in modes"
69
+ v-for="m in resolvedModes"
72
70
  :key="m.id"
73
71
  type="button"
74
72
  class="sa-pv-header__mode-btn"
@@ -81,7 +79,7 @@
81
79
  </div>
82
80
  <span v-if="compareSnapshot" class="sa-pv-header__cmp-hint">
83
81
  <q-icon name="compare_arrows" size="13px" />
84
- Vergleichsmodus aktiv — andere Ansichten deaktiviert
82
+ {{ msg.header.compareModeHint }}
85
83
  </span>
86
84
  </div>
87
85
  </header>
@@ -89,26 +87,20 @@
89
87
 
90
88
  <script setup lang="ts">
91
89
  import { computed } from 'vue';
92
- import type { CatalogSnapshot } from '../../plan-versions-catalog.js';
93
- import { formatDateDe } from './format.js';
90
+ import type { CatalogSnapshot } from '../../client/plan-versions-catalog.js';
91
+ import { formatMessage } from '../../client/i18n/format.js';
92
+ import { useSaMessages, useSuperAdminI18n } from '../../vue/use-super-admin-i18n.js';
93
+ import { formatDate } from './format.js';
94
94
  import PlanVersionStatusBadge from './PlanVersionStatusBadge.vue';
95
95
  import type { PlanVersionViewMode } from './types.js';
96
96
 
97
- const props = withDefaults(
98
- defineProps<{
99
- snapshot: CatalogSnapshot;
100
- viewMode: PlanVersionViewMode;
101
- compareSnapshot: CatalogSnapshot | null;
102
- modes?: ReadonlyArray<{ id: PlanVersionViewMode; label: string; icon: string }>;
103
- }>(),
104
- {
105
- modes: () => [
106
- { id: 'list' as const, label: 'Plan-Liste', icon: 'list' },
107
- { id: 'matrix' as const, label: 'Feature-Matrix', icon: 'grid_view' },
108
- { id: 'audit' as const, label: 'Aktivität', icon: 'history' },
109
- ],
110
- },
111
- );
97
+ const props = defineProps<{
98
+ snapshot: CatalogSnapshot;
99
+ viewMode: PlanVersionViewMode;
100
+ compareSnapshot: CatalogSnapshot | null;
101
+ /** Overrides the localized default view switcher. */
102
+ modes?: ReadonlyArray<{ id: PlanVersionViewMode; label: string; icon: string }>;
103
+ }>();
112
104
 
113
105
  const emit = defineEmits<{
114
106
  (e: 'viewChange', mode: PlanVersionViewMode): void;
@@ -116,9 +108,33 @@ const emit = defineEmits<{
116
108
  (e: 'clearCompare'): void;
117
109
  }>();
118
110
 
111
+ const msg = useSaMessages('planVersions');
112
+ const { locale } = useSuperAdminI18n();
113
+
119
114
  const canPublish = computed(
120
115
  () => props.snapshot.kind === 'drafts' && props.snapshot.draftCount > 0,
121
116
  );
117
+
118
+ const publishedOnLabel = computed(() =>
119
+ formatMessage(msg.value.header.publishedOn, {
120
+ date: formatDate(props.snapshot.publishedAt ?? undefined, locale.value),
121
+ }),
122
+ );
123
+
124
+ const regressionLabel = computed(() =>
125
+ props.snapshot.regressionCount === 1
126
+ ? msg.value.header.regressionOne
127
+ : msg.value.header.regressionMany,
128
+ );
129
+
130
+ const resolvedModes = computed(
131
+ () =>
132
+ props.modes ?? [
133
+ { id: 'list' as const, label: msg.value.header.modeList, icon: 'list' },
134
+ { id: 'matrix' as const, label: msg.value.header.modeMatrix, icon: 'grid_view' },
135
+ { id: 'audit' as const, label: msg.value.header.modeAudit, icon: 'history' },
136
+ ],
137
+ );
122
138
  </script>
123
139
 
124
140
  <style scoped>
@@ -3,18 +3,18 @@
3
3
  <div class="sa-pv-audit__card">
4
4
  <header class="sa-pv-audit__head">
5
5
  <q-icon name="history" size="18px" class="sa-pv-audit__head-icon" />
6
- <h3>Aktivität</h3>
7
- <span class="sa-pv-audit__count">{{ events.length }} Events</span>
6
+ <h3>{{ msg.audit.title }}</h3>
7
+ <span class="sa-pv-audit__count">{{ eventCountLabel }}</span>
8
8
  <q-space />
9
9
  <button v-if="!loading" type="button" class="sa-pv-audit__refresh" @click="reload">
10
- <q-icon name="refresh" size="14px" /> Neu laden
10
+ <q-icon name="refresh" size="14px" /> {{ common.reload }}
11
11
  </button>
12
12
  </header>
13
13
  <div v-if="loading" class="sa-pv-audit__loading">
14
- <q-spinner size="20px" /> Audit-Trail wird geladen…
14
+ <q-spinner size="20px" /> {{ msg.audit.loading }}
15
15
  </div>
16
16
  <div v-else-if="events.length === 0" class="sa-pv-audit__empty">
17
- Keine Plan-/Add-on-Events im Audit-Log gefunden.
17
+ {{ msg.audit.empty }}
18
18
  </div>
19
19
  <div v-else class="sa-pv-audit__list">
20
20
  <div
@@ -42,7 +42,7 @@
42
42
  <div class="sa-pv-audit__meta">
43
43
  <span
44
44
  ><q-icon name="schedule" size="12px" />
45
- {{ formatTsDe(e.createdAt) }}</span
45
+ {{ formatTimestamp(e.createdAt, locale) }}</span
46
46
  >
47
47
  <span v-if="actorEmail(e)">
48
48
  <q-icon name="person" size="12px" /> {{ actorEmail(e) }}
@@ -56,9 +56,11 @@
56
56
  </template>
57
57
 
58
58
  <script setup lang="ts">
59
- import { onMounted, ref, watch } from 'vue';
60
- import type { CatalogSnapshot } from '../../plan-versions-catalog.js';
61
- import { formatTsDe } from './format.js';
59
+ import { computed, onMounted, ref, watch } from 'vue';
60
+ import type { CatalogSnapshot } from '../../client/plan-versions-catalog.js';
61
+ import { formatMessage } from '../../client/i18n/format.js';
62
+ import { useSaMessages, useSuperAdminI18n } from '../../vue/use-super-admin-i18n.js';
63
+ import { formatTimestamp } from './format.js';
62
64
 
63
65
  // PlanVersionsAudit — data-agnostic. Consumers pass in a `loadAudit` loader
64
66
  // that supplies events; the component filters them to match the current
@@ -100,34 +102,49 @@ const props = withDefaults(
100
102
  const loading = ref(false);
101
103
  const events = ref<AuditRow[]>([]);
102
104
 
103
- const DEFAULT_ACTION_META: Record<string, ActionMeta> = {
105
+ const msg = useSaMessages('planVersions');
106
+ const common = useSaMessages('common');
107
+ const { locale } = useSuperAdminI18n();
108
+
109
+ const eventCountLabel = computed(() =>
110
+ formatMessage(msg.value.audit.eventCount, { count: events.value.length }),
111
+ );
112
+
113
+ const ACTION_ICONS: Record<string, { icon: string; color: string }> = {
114
+ PLAN_VERSION_PUBLISH: { icon: 'rocket_launch', color: '#047857' },
115
+ PLAN_VERSION_DRAFT_CREATE: { icon: 'edit_note', color: '#b45309' },
116
+ PLAN_VERSION_DRAFT_UPDATE: { icon: 'edit', color: '#3f6bff' },
117
+ PLAN_VERSION_DRAFT_DELETE: { icon: 'delete', color: '#dc2626' },
118
+ PLAN_CATALOG_UPDATE: { icon: 'rocket_launch', color: '#047857' },
119
+ };
120
+
121
+ const defaultActionMeta = computed<Record<string, ActionMeta>>(() => ({
104
122
  PLAN_VERSION_PUBLISH: {
105
- icon: 'rocket_launch',
106
- color: '#047857',
107
- label: 'Plan publiziert',
123
+ ...ACTION_ICONS.PLAN_VERSION_PUBLISH,
124
+ label: msg.value.audit.actionPlanPublished,
108
125
  },
109
126
  PLAN_VERSION_DRAFT_CREATE: {
110
- icon: 'edit_note',
111
- color: '#b45309',
112
- label: 'Plan-Draft angelegt',
127
+ ...ACTION_ICONS.PLAN_VERSION_DRAFT_CREATE,
128
+ label: msg.value.audit.actionPlanDraftCreated,
129
+ },
130
+ PLAN_VERSION_DRAFT_UPDATE: {
131
+ ...ACTION_ICONS.PLAN_VERSION_DRAFT_UPDATE,
132
+ label: msg.value.audit.actionPlanDraftUpdated,
113
133
  },
114
- PLAN_VERSION_DRAFT_UPDATE: { icon: 'edit', color: '#3f6bff', label: 'Plan-Draft geändert' },
115
134
  PLAN_VERSION_DRAFT_DELETE: {
116
- icon: 'delete',
117
- color: '#dc2626',
118
- label: 'Plan-Draft gelöscht',
135
+ ...ACTION_ICONS.PLAN_VERSION_DRAFT_DELETE,
136
+ label: msg.value.audit.actionPlanDraftDeleted,
119
137
  },
120
138
  PLAN_CATALOG_UPDATE: {
121
- icon: 'rocket_launch',
122
- color: '#047857',
123
- label: 'Catalog publiziert',
139
+ ...ACTION_ICONS.PLAN_CATALOG_UPDATE,
140
+ label: msg.value.audit.actionCatalogPublished,
124
141
  },
125
- };
142
+ }));
126
143
 
127
144
  function meta(action: string): ActionMeta {
128
145
  return (
129
146
  props.actionMeta[action] ??
130
- DEFAULT_ACTION_META[action] ?? {
147
+ defaultActionMeta.value[action] ?? {
131
148
  icon: 'circle',
132
149
  color: '#64748b',
133
150
  label: action,
@@ -156,8 +173,10 @@ function detail(e: AuditRow): string {
156
173
  changes?: unknown;
157
174
  };
158
175
  if (c.changeNote) return c.changeNote;
159
- if (c.nonRegressive === false) return 'Mit mindestens einer Verschlechterung publiziert.';
160
- if (Array.isArray(c.changes)) return `${c.changes.length} Felder geändert.`;
176
+ if (c.nonRegressive === false) return msg.value.audit.detailRegression;
177
+ if (Array.isArray(c.changes)) {
178
+ return formatMessage(msg.value.audit.detailFieldsChanged, { count: c.changes.length });
179
+ }
161
180
  return e.action;
162
181
  }
163
182
 
@@ -5,7 +5,7 @@
5
5
  <q-icon name="compare_arrows" size="22px" color="white" />
6
6
  </div>
7
7
  <div>
8
- <div class="sa-pv-diff__legend">Vergleich</div>
8
+ <div class="sa-pv-diff__legend">{{ msg.diff.legend }}</div>
9
9
  <div class="sa-pv-diff__title">
10
10
  {{ from.label }} <span class="sa-pv-diff__sep">→</span> {{ to.label }}
11
11
  </div>
@@ -13,13 +13,13 @@
13
13
  <div class="sa-pv-diff__spacer" />
14
14
  <div class="sa-pv-diff__stats">
15
15
  <div class="sa-pv-diff__stat">
16
- <div class="sa-pv-diff__stat-label">Pakete geändert</div>
16
+ <div class="sa-pv-diff__stat-label">{{ msg.diff.plansChanged }}</div>
17
17
  <div class="sa-pv-diff__stat-value sa-pv-diff__stat-value--warn">
18
18
  {{ planChangedCount }}
19
19
  </div>
20
20
  </div>
21
21
  <div v-if="regressionCount > 0" class="sa-pv-diff__stat">
22
- <div class="sa-pv-diff__stat-label">Regressionen</div>
22
+ <div class="sa-pv-diff__stat-label">{{ msg.diff.regressions }}</div>
23
23
  <div class="sa-pv-diff__stat-value sa-pv-diff__stat-value--bad">
24
24
  {{ regressionCount }}
25
25
  </div>
@@ -27,7 +27,7 @@
27
27
  </div>
28
28
  </div>
29
29
 
30
- <h2 class="sa-pv-diff__section">Pakete</h2>
30
+ <h2 class="sa-pv-diff__section">{{ msg.diff.sectionPlans }}</h2>
31
31
  <PlanDiffCard
32
32
  v-for="d in planDiffs"
33
33
  :key="d.id"
@@ -38,14 +38,14 @@
38
38
  :changes="d.changes"
39
39
  :field-labels="fieldLabels"
40
40
  />
41
-
42
41
  </div>
43
42
  </template>
44
43
 
45
44
  <script setup lang="ts">
46
45
  import { computed } from 'vue';
47
46
  import type { VersionChange } from '@saasicat/types';
48
- import type { CatalogSnapshot, ResolvedPlan } from '../../plan-versions-catalog.js';
47
+ import type { CatalogSnapshot, ResolvedPlan } from '../../client/plan-versions-catalog.js';
48
+ import { useSaMessages } from '../../vue/use-super-admin-i18n.js';
49
49
  import PlanDiffCard from './PlanDiffCard.vue';
50
50
 
51
51
  interface SnapshotEntityDiff {
@@ -64,6 +64,8 @@ const props = defineProps<{
64
64
  fieldLabels?: Record<string, string>;
65
65
  }>();
66
66
 
67
+ const msg = useSaMessages('planVersions');
68
+
67
69
  function planAccent(planId: string): string {
68
70
  return props.planAccents?.[planId] ?? '#3f6bff';
69
71
  }