@eifi1/ui-kit 0.54.0 → 0.55.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 +90 -76
- package/dist/admin/plan-change.js +2 -2
- package/dist/admin/plan-change.js.map +1 -1
- package/dist/admin/user-roster.d.ts +6 -0
- package/dist/admin/user-roster.js +4 -0
- package/dist/admin/user-roster.js.map +1 -1
- package/dist/billing/billing-labels.d.ts +26 -0
- package/dist/billing/billing-labels.js +9 -0
- package/dist/billing/billing-labels.js.map +1 -1
- package/dist/billing/subscription-standing.d.ts +61 -0
- package/dist/billing/subscription-standing.js +51 -0
- package/dist/billing/subscription-standing.js.map +1 -0
- package/dist/billing/usage-meter.d.ts +52 -0
- package/dist/billing/usage-meter.js +52 -0
- package/dist/billing/usage-meter.js.map +1 -0
- package/dist/chart.d.ts +1 -0
- package/dist/chart.js +4 -0
- package/dist/chart.js.map +1 -1
- package/dist/components/alert-banner.js +2 -3
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.js +3 -15
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.js +2 -2
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/bulk-action-bar.js +2 -1
- package/dist/components/bulk-action-bar.js.map +1 -1
- package/dist/components/button.d.ts +35 -1
- package/dist/components/button.js +5 -9
- package/dist/components/button.js.map +1 -1
- package/dist/components/calendar-heatmap.js +2 -2
- package/dist/components/calendar-heatmap.js.map +1 -1
- package/dist/components/camera-button.d.ts +89 -0
- package/dist/components/camera-button.js +122 -0
- package/dist/components/camera-button.js.map +1 -0
- package/dist/components/camera-capture.d.ts +66 -0
- package/dist/components/camera-capture.js +190 -0
- package/dist/components/camera-capture.js.map +1 -0
- package/dist/components/camera-labels.d.ts +20 -0
- package/dist/components/camera-labels.js +15 -0
- package/dist/components/camera-labels.js.map +1 -0
- package/dist/components/chart-edge.d.ts +9 -0
- package/dist/components/chart-edge.js +14 -3
- package/dist/components/chart-edge.js.map +1 -1
- package/dist/components/chart-zoom-core.js +34 -29
- package/dist/components/chart-zoom-core.js.map +1 -1
- package/dist/components/checkbox-group.js +1 -1
- package/dist/components/checkbox-group.js.map +1 -1
- package/dist/components/combobox-core.js +3 -2
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.js +2 -2
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/consent-again-notice-labels.d.ts +25 -0
- package/dist/components/consent-again-notice-labels.js +15 -0
- package/dist/components/consent-again-notice-labels.js.map +1 -0
- package/dist/components/consent-again-notice.d.ts +85 -0
- package/dist/components/consent-again-notice.js +94 -0
- package/dist/components/consent-again-notice.js.map +1 -0
- package/dist/components/country-select.js +2 -7
- package/dist/components/country-select.js.map +1 -1
- package/dist/components/currency-select.js +2 -2
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.js +2 -2
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-column-settings.js +2 -2
- package/dist/components/data-table-column-settings.js.map +1 -1
- package/dist/components/data-table-fit.js.map +1 -1
- package/dist/components/data-table-virtual.js +13 -3
- package/dist/components/data-table-virtual.js.map +1 -1
- package/dist/components/date-field.js +2 -2
- package/dist/components/date-field.js.map +1 -1
- package/dist/components/date-picker.js +2 -2
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/date-range-picker.js +2 -6
- package/dist/components/date-range-picker.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +3 -1
- package/dist/components/dialog-frame.js.map +1 -1
- package/dist/components/dropdown.js +7 -3
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/entity-combobox.js +2 -2
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/field-parts.d.ts +108 -6
- package/dist/components/field-parts.js +59 -6
- package/dist/components/field-parts.js.map +1 -1
- package/dist/components/field-suggestion-labels.d.ts +2 -0
- package/dist/components/field-suggestion-labels.js +10 -0
- package/dist/components/field-suggestion-labels.js.map +1 -0
- package/dist/components/field.js +1 -1
- package/dist/components/field.js.map +1 -1
- package/dist/components/file-button.d.ts +1 -1
- package/dist/components/file-button.js.map +1 -1
- package/dist/components/floating-panel.d.ts +7 -6
- package/dist/components/floating-panel.js +3 -17
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +3 -2
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/hover-menu.js +3 -2
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/icon-button.d.ts +23 -5
- package/dist/components/icon-button.js +6 -8
- package/dist/components/icon-button.js.map +1 -1
- package/dist/components/inline-confirm.js +2 -1
- package/dist/components/inline-confirm.js.map +1 -1
- package/dist/components/inline-entity-combobox.js +2 -2
- package/dist/components/inline-entity-combobox.js.map +1 -1
- package/dist/components/input.js +2 -2
- package/dist/components/input.js.map +1 -1
- package/dist/components/jump-calendar.js +3 -3
- package/dist/components/jump-calendar.js.map +1 -1
- package/dist/components/legal.d.ts +13 -1
- package/dist/components/legal.js +12 -0
- package/dist/components/legal.js.map +1 -1
- package/dist/components/legended-series-chart.d.ts +80 -0
- package/dist/components/legended-series-chart.js +70 -0
- package/dist/components/legended-series-chart.js.map +1 -0
- package/dist/components/lightbox.js +2 -1
- package/dist/components/lightbox.js.map +1 -1
- package/dist/components/mini-calendar.js +13 -5
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +23 -2
- package/dist/components/modal.js +24 -6
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +1 -1
- package/dist/components/month-picker.js +6 -6
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.js +2 -2
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.js +2 -6
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-input.js +2 -2
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/page-header-layout.d.ts +18 -0
- package/dist/components/page-header-layout.js +23 -0
- package/dist/components/page-header-layout.js.map +1 -0
- package/dist/components/page-header-skeleton.d.ts +41 -0
- package/dist/components/page-header-skeleton.js +52 -0
- package/dist/components/page-header-skeleton.js.map +1 -0
- package/dist/components/page-header.js +4 -17
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/popover.js +7 -2
- package/dist/components/popover.js.map +1 -1
- package/dist/components/release-notes-labels.d.ts +16 -0
- package/dist/components/release-notes-labels.js +18 -0
- package/dist/components/release-notes-labels.js.map +1 -0
- package/dist/components/release-notes.d.ts +65 -0
- package/dist/components/release-notes.js +65 -0
- package/dist/components/release-notes.js.map +1 -0
- package/dist/components/select.js +2 -2
- package/dist/components/select.js.map +1 -1
- package/dist/components/series-chart-labels.d.ts +9 -0
- package/dist/components/series-chart-labels.js +3 -1
- package/dist/components/series-chart-labels.js.map +1 -1
- package/dist/components/series-chart.d.ts +5 -0
- package/dist/components/series-chart.js +89 -36
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/toggle-group.js +3 -2
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/treemap-layout.js.map +1 -1
- package/dist/components/treemap.d.ts +17 -15
- package/dist/components/treemap.js +167 -85
- package/dist/components/treemap.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/eslint/role-utilities.d.ts +2 -2
- package/dist/eslint/role-utilities.js.map +1 -1
- package/dist/feedback/feedback-inbox-page.d.ts +260 -0
- package/dist/feedback/feedback-inbox-page.js +207 -0
- package/dist/feedback/feedback-inbox-page.js.map +1 -0
- package/dist/feedback/feedback-vocabulary.js +2 -2
- package/dist/feedback/feedback-vocabulary.js.map +1 -1
- package/dist/feedback.d.ts +1 -0
- package/dist/feedback.js +6 -0
- package/dist/feedback.js.map +1 -1
- package/dist/hooks/use-debounce.d.ts +32 -5
- package/dist/hooks/use-debounce.js +6 -5
- package/dist/hooks/use-debounce.js.map +1 -1
- package/dist/hooks/use-file-picker.d.ts +3 -1
- package/dist/hooks/use-file-picker.js.map +1 -1
- package/dist/hooks/use-focus-trap.d.ts +19 -3
- package/dist/hooks/use-focus-trap.js +15 -5
- package/dist/hooks/use-focus-trap.js.map +1 -1
- package/dist/hooks/use-has-camera.d.ts +36 -0
- package/dist/hooks/use-has-camera.js +53 -0
- package/dist/hooks/use-has-camera.js.map +1 -0
- package/dist/hooks/use-hotkey.js +1 -10
- package/dist/hooks/use-hotkey.js.map +1 -1
- package/dist/hooks/use-overlay-history.d.ts +6 -1
- package/dist/hooks/use-overlay-history.js +10 -2
- package/dist/hooks/use-overlay-history.js.map +1 -1
- package/dist/i18n/defaults.js +11 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +75 -3
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +20 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +92 -4
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +71 -3
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +72 -2
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +74 -3
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +74 -3
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +71 -3
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +22 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +24 -5
- package/dist/index.js +35 -1
- package/dist/index.js.map +1 -1
- package/dist/landing/landing-labels.d.ts +8 -0
- package/dist/landing/landing-labels.js +2 -1
- package/dist/landing/landing-labels.js.map +1 -1
- package/dist/lib/changelog.d.ts +130 -0
- package/dist/lib/changelog.js +137 -0
- package/dist/lib/changelog.js.map +1 -0
- package/dist/lib/clipboard-minus.js +2 -2
- package/dist/lib/clipboard-minus.js.map +1 -1
- package/dist/lib/dates.d.ts +29 -3
- package/dist/lib/dates.js +41 -12
- package/dist/lib/dates.js.map +1 -1
- package/dist/lib/editable-content.d.ts +33 -0
- package/dist/lib/editable-content.js +15 -0
- package/dist/lib/editable-content.js.map +1 -0
- package/dist/lib/focus-left.d.ts +47 -1
- package/dist/lib/focus-left.js +11 -2
- package/dist/lib/focus-left.js.map +1 -1
- package/dist/lib/server-wake.d.ts +49 -9
- package/dist/lib/server-wake.js +25 -14
- package/dist/lib/server-wake.js.map +1 -1
- package/dist/lib/session-refresh.d.ts +53 -0
- package/dist/lib/session-refresh.js +27 -1
- package/dist/lib/session-refresh.js.map +1 -1
- package/dist/rhf/fields.js +3 -3
- package/dist/rhf/fields.js.map +1 -1
- package/dist/shell/app-shell.d.ts +25 -1
- package/dist/shell/app-shell.js +3 -1
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/dev-menu.d.ts +3 -0
- package/dist/shell/dev-menu.js +4 -2
- package/dist/shell/dev-menu.js.map +1 -1
- package/dist/shell/held-changes-banner-labels.d.ts +23 -0
- package/dist/shell/held-changes-banner-labels.js +14 -0
- package/dist/shell/held-changes-banner-labels.js.map +1 -0
- package/dist/shell/held-changes-banner.d.ts +75 -0
- package/dist/shell/held-changes-banner.js +106 -0
- package/dist/shell/held-changes-banner.js.map +1 -0
- package/dist/shell/sync-status-indicator.d.ts +27 -12
- package/dist/shell/sync-status-indicator.js +13 -4
- package/dist/shell/sync-status-indicator.js.map +1 -1
- package/dist/shell/top-bar-parts-labels.d.ts +5 -0
- package/dist/shell/top-bar-parts-labels.js +3 -1
- package/dist/shell/top-bar-parts-labels.js.map +1 -1
- package/dist/shell.d.ts +2 -0
- package/dist/shell.js +3 -0
- package/dist/shell.js.map +1 -1
- package/dist/sync/engine.d.ts +11 -2
- package/dist/sync/engine.js +13 -5
- package/dist/sync/engine.js.map +1 -1
- package/dist/sync/hooks.d.ts +3 -2
- package/dist/sync/hooks.js +4 -2
- package/dist/sync/hooks.js.map +1 -1
- package/dist/testing/css-variables.generated.d.ts +2 -2
- package/dist/testing/css-variables.generated.js +1 -1
- package/dist/testing/css-variables.generated.js.map +1 -1
- package/dist/theme/chart-palette.d.ts +18 -0
- package/dist/theme/chart-palette.js +17 -1
- package/dist/theme/chart-palette.js.map +1 -1
- package/dist/theme/contrast-tokens.d.ts +3 -3
- package/dist/theme/contrast-tokens.js.map +1 -1
- package/dist/theme/contrast.d.ts +4 -4
- package/dist/theme/contrast.js.map +1 -1
- package/dist/tour/tour-overlay.js +2 -1
- package/dist/tour/tour-overlay.js.map +1 -1
- package/package.json +5 -9
- package/tokens.css +19 -54
- package/src/account/account-parts.ts +0 -47
- package/src/account/account-settings-labels.ts +0 -240
- package/src/account/account-settings.tsx +0 -698
- package/src/account/data-export-setting-labels.ts +0 -20
- package/src/account/data-export-setting.tsx +0 -200
- package/src/account/delete-account-setting-labels.ts +0 -33
- package/src/account/delete-account-setting.tsx +0 -342
- package/src/account/email-change-setting-labels.ts +0 -31
- package/src/account/email-change-setting.tsx +0 -443
- package/src/account/passkeys-setting.tsx +0 -445
- package/src/account/sessions-setting-labels.ts +0 -24
- package/src/account/sessions-setting.tsx +0 -283
- package/src/admin/admin-action-confirm-labels.ts +0 -19
- package/src/admin/admin-action-confirm.tsx +0 -509
- package/src/admin/admin-action-log-labels.ts +0 -83
- package/src/admin/admin-action-log.tsx +0 -464
- package/src/admin/admin-area-labels.ts +0 -114
- package/src/admin/admin-forbidden.tsx +0 -75
- package/src/admin/admin-overview.tsx +0 -258
- package/src/admin/admin-parts.ts +0 -68
- package/src/admin/admin-sections.tsx +0 -208
- package/src/admin/admin-tool-links.tsx +0 -90
- package/src/admin/invitations-panel-labels.ts +0 -31
- package/src/admin/invitations-panel.tsx +0 -516
- package/src/admin/mail-test-card-labels.ts +0 -19
- package/src/admin/mail-test-card.tsx +0 -189
- package/src/admin/plan-change-labels.ts +0 -5
- package/src/admin/plan-change.tsx +0 -474
- package/src/admin/reviewer-scope-editor-labels.ts +0 -16
- package/src/admin/reviewer-scope-editor.tsx +0 -224
- package/src/admin/role-select-labels.ts +0 -16
- package/src/admin/role-select.tsx +0 -282
- package/src/admin/transfer-ownership-dialog-labels.ts +0 -20
- package/src/admin/transfer-ownership-dialog.tsx +0 -162
- package/src/admin/user-roster-labels.ts +0 -17
- package/src/admin/user-roster.tsx +0 -559
- package/src/auth/accept-invitation-labels.ts +0 -21
- package/src/auth/accept-invitation.tsx +0 -210
- package/src/auth/auth-errors-labels.ts +0 -23
- package/src/auth/auth-errors.ts +0 -439
- package/src/auth/complete-name-dialog-labels.ts +0 -16
- package/src/auth/complete-name-dialog.tsx +0 -253
- package/src/auth/email-tag.ts +0 -75
- package/src/auth/forgot-password-form-labels.ts +0 -20
- package/src/auth/forgot-password-form.tsx +0 -221
- package/src/auth/form-rules.ts +0 -40
- package/src/auth/new-password-fields.tsx +0 -85
- package/src/auth/not-found-page-labels.ts +0 -12
- package/src/auth/not-found-page.tsx +0 -95
- package/src/auth/register-form-labels.ts +0 -31
- package/src/auth/register-form.tsx +0 -456
- package/src/auth/reset-password-form-labels.ts +0 -27
- package/src/auth/reset-password-form.tsx +0 -341
- package/src/auth/sign-in-form-labels.ts +0 -44
- package/src/auth/sign-in-form.tsx +0 -858
- package/src/auth/status-parts.tsx +0 -132
- package/src/auth/verify-email-labels.ts +0 -26
- package/src/auth/verify-email.tsx +0 -445
- package/src/billing/billing-banner.tsx +0 -258
- package/src/billing/billing-labels.ts +0 -381
- package/src/billing/billing-lock.ts +0 -108
- package/src/billing/billing-overview.ts +0 -157
- package/src/billing/billing-standing.ts +0 -80
- package/src/billing/cancel-request.ts +0 -97
- package/src/billing/cancel-subscription.tsx +0 -98
- package/src/billing/checkout-processing.ts +0 -394
- package/src/billing/checkout-return.ts +0 -90
- package/src/billing/pay-page.ts +0 -330
- package/src/billing/plan-card.tsx +0 -562
- package/src/billing/plan-change-labels.ts +0 -66
- package/src/billing/plan-limit-notice.tsx +0 -148
- package/src/billing/plan-limit-toast.tsx +0 -90
- package/src/billing/plan-limit.ts +0 -52
- package/src/billing/plan-price.ts +0 -98
- package/src/billing/plan-switch.tsx +0 -216
- package/src/billing/provider-page.ts +0 -84
- package/src/billing/subscription-actions.tsx +0 -247
- package/src/billing/subscription-status-chip.tsx +0 -95
- package/src/chart.ts +0 -103
- package/src/components/account-chips-labels.ts +0 -16
- package/src/components/account-chips.tsx +0 -474
- package/src/components/alert-banner.tsx +0 -670
- package/src/components/amount-input.tsx +0 -816
- package/src/components/appearance-labels.ts +0 -63
- package/src/components/authed-image-labels.ts +0 -11
- package/src/components/authed-image.tsx +0 -209
- package/src/components/autocomplete.tsx +0 -645
- package/src/components/breadcrumbs-labels.ts +0 -10
- package/src/components/breadcrumbs.tsx +0 -205
- package/src/components/bulk-action-bar-labels.ts +0 -11
- package/src/components/bulk-action-bar.tsx +0 -443
- package/src/components/button-group.tsx +0 -223
- package/src/components/button-look.ts +0 -256
- package/src/components/button.tsx +0 -339
- package/src/components/calculator.tsx +0 -341
- package/src/components/calendar-heatmap-labels.ts +0 -15
- package/src/components/calendar-heatmap.tsx +0 -600
- package/src/components/card.tsx +0 -377
- package/src/components/chart-edge.ts +0 -106
- package/src/components/chart-figure.tsx +0 -35
- package/src/components/chart-height.ts +0 -30
- package/src/components/chart-zoom-core.tsx +0 -627
- package/src/components/chart-zoom.tsx +0 -22
- package/src/components/chart.tsx +0 -554
- package/src/components/checkbox-group.tsx +0 -247
- package/src/components/checkbox.tsx +0 -346
- package/src/components/chip-input.tsx +0 -370
- package/src/components/chip-labels.ts +0 -13
- package/src/components/chip.tsx +0 -843
- package/src/components/choice-card.tsx +0 -544
- package/src/components/column-mapper-labels.ts +0 -38
- package/src/components/column-mapper.tsx +0 -655
- package/src/components/combobox-core.tsx +0 -1321
- package/src/components/combobox-suggestions.tsx +0 -131
- package/src/components/combobox.tsx +0 -716
- package/src/components/confirm-context.ts +0 -7
- package/src/components/confirm-dialog-labels.ts +0 -13
- package/src/components/confirm-dialog.tsx +0 -341
- package/src/components/copy-button-labels.ts +0 -13
- package/src/components/copy-button.tsx +0 -192
- package/src/components/country-select-labels.ts +0 -11
- package/src/components/country-select.tsx +0 -539
- package/src/components/currency-option-list.tsx +0 -188
- package/src/components/currency-select.tsx +0 -343
- package/src/components/danger-confirm-labels.ts +0 -20
- package/src/components/danger-confirm.tsx +0 -987
- package/src/components/data-table-cells.tsx +0 -118
- package/src/components/data-table-column-settings.tsx +0 -198
- package/src/components/data-table-filter-popover.tsx +0 -289
- package/src/components/data-table-filters.ts +0 -315
- package/src/components/data-table-fit.ts +0 -301
- package/src/components/data-table-groups.tsx +0 -288
- package/src/components/data-table-head.tsx +0 -280
- package/src/components/data-table-labels.ts +0 -198
- package/src/components/data-table-leading-row.tsx +0 -58
- package/src/components/data-table-mobile.tsx +0 -1117
- package/src/components/data-table-pagination.tsx +0 -202
- package/src/components/data-table-resize.ts +0 -188
- package/src/components/data-table-row-actions.tsx +0 -302
- package/src/components/data-table-row.tsx +0 -496
- package/src/components/data-table-selection.ts +0 -71
- package/src/components/data-table-shared.tsx +0 -287
- package/src/components/data-table-sort.ts +0 -163
- package/src/components/data-table-virtual.ts +0 -576
- package/src/components/data-table.tsx +0 -2598
- package/src/components/date-field.tsx +0 -684
- package/src/components/date-format-setting.tsx +0 -64
- package/src/components/date-picker.tsx +0 -404
- package/src/components/date-range-picker.tsx +0 -518
- package/src/components/description-list-labels.ts +0 -9
- package/src/components/description-list.tsx +0 -386
- package/src/components/dialog-frame-labels.ts +0 -7
- package/src/components/dialog-frame.tsx +0 -284
- package/src/components/disclosure.tsx +0 -476
- package/src/components/dropdown.tsx +0 -461
- package/src/components/empty-state.tsx +0 -136
- package/src/components/entity-combobox.tsx +0 -422
- package/src/components/error-boundary-labels.ts +0 -20
- package/src/components/error-boundary.tsx +0 -675
- package/src/components/facing-pair.ts +0 -93
- package/src/components/field-base-labels.ts +0 -20
- package/src/components/field-base.tsx +0 -656
- package/src/components/field-parts.tsx +0 -825
- package/src/components/field-strip.tsx +0 -129
- package/src/components/field.tsx +0 -206
- package/src/components/file-button.tsx +0 -295
- package/src/components/file-dropzone.tsx +0 -559
- package/src/components/floating-panel-labels.ts +0 -10
- package/src/components/floating-panel.tsx +0 -828
- package/src/components/focus-ring.ts +0 -16
- package/src/components/form-actions-labels.ts +0 -11
- package/src/components/form-actions.tsx +0 -578
- package/src/components/full-bleed-dialog.tsx +0 -294
- package/src/components/grouped-picker.tsx +0 -184
- package/src/components/help-popover.tsx +0 -117
- package/src/components/hover-menu.tsx +0 -343
- package/src/components/iban-input-labels.ts +0 -14
- package/src/components/iban-input.tsx +0 -236
- package/src/components/icon-button.tsx +0 -959
- package/src/components/icon-picker-labels.ts +0 -13
- package/src/components/icon-picker.tsx +0 -232
- package/src/components/image-grid-labels.ts +0 -11
- package/src/components/image-grid.tsx +0 -202
- package/src/components/inline-confirm.tsx +0 -116
- package/src/components/inline-edit-field-labels.ts +0 -11
- package/src/components/inline-edit-field.tsx +0 -552
- package/src/components/inline-entity-combobox.tsx +0 -849
- package/src/components/input.tsx +0 -394
- package/src/components/jump-calendar.tsx +0 -265
- package/src/components/language-select.tsx +0 -93
- package/src/components/legal-labels.ts +0 -105
- package/src/components/legal-page.tsx +0 -711
- package/src/components/legal.tsx +0 -668
- package/src/components/lightbox-labels.ts +0 -18
- package/src/components/lightbox.tsx +0 -399
- package/src/components/line-items-labels.ts +0 -14
- package/src/components/line-items.tsx +0 -602
- package/src/components/list-labels.ts +0 -12
- package/src/components/list.tsx +0 -870
- package/src/components/loading-state.tsx +0 -78
- package/src/components/measured-grid-labels.ts +0 -25
- package/src/components/measured-grid.tsx +0 -837
- package/src/components/menu-item.tsx +0 -241
- package/src/components/mini-calendar-labels.ts +0 -17
- package/src/components/mini-calendar.tsx +0 -792
- package/src/components/modal.tsx +0 -534
- package/src/components/money-draft.ts +0 -83
- package/src/components/money-field.tsx +0 -76
- package/src/components/month-grid.tsx +0 -229
- package/src/components/month-picker-labels.ts +0 -22
- package/src/components/month-picker.tsx +0 -1087
- package/src/components/multi-entity-combobox.tsx +0 -369
- package/src/components/multi-select.tsx +0 -376
- package/src/components/nav-pills.tsx +0 -198
- package/src/components/number-field.tsx +0 -327
- package/src/components/number-input.tsx +0 -559
- package/src/components/numeric-field.ts +0 -169
- package/src/components/numpad-sheet.tsx +0 -285
- package/src/components/one-time-code-input.tsx +0 -270
- package/src/components/page-contents-labels.ts +0 -9
- package/src/components/page-contents.tsx +0 -282
- package/src/components/page-header-context.ts +0 -8
- package/src/components/page-header.tsx +0 -298
- package/src/components/password-strength-labels.ts +0 -22
- package/src/components/password-strength.tsx +0 -241
- package/src/components/phone-input-labels.ts +0 -10
- package/src/components/phone-input.tsx +0 -282
- package/src/components/picker-sheet.tsx +0 -330
- package/src/components/pie-chart-labels.ts +0 -40
- package/src/components/pie-chart.tsx +0 -480
- package/src/components/popover-labels.ts +0 -14
- package/src/components/popover.tsx +0 -268
- package/src/components/progress-bar-labels.ts +0 -10
- package/src/components/progress-bar.tsx +0 -479
- package/src/components/qr-code.tsx +0 -76
- package/src/components/reauth-dialog-labels.ts +0 -13
- package/src/components/reauth-dialog.tsx +0 -265
- package/src/components/row-actions-labels.ts +0 -12
- package/src/components/row-actions.tsx +0 -795
- package/src/components/scroll-area.tsx +0 -123
- package/src/components/search-field.tsx +0 -192
- package/src/components/select.tsx +0 -294
- package/src/components/separator.tsx +0 -33
- package/src/components/series-chart-axes.ts +0 -342
- package/src/components/series-chart-budget.ts +0 -150
- package/src/components/series-chart-labels.ts +0 -33
- package/src/components/series-chart-thin.ts +0 -180
- package/src/components/series-chart-ticks.ts +0 -194
- package/src/components/series-chart.tsx +0 -1906
- package/src/components/server-wake-labels.ts +0 -11
- package/src/components/server-wake.tsx +0 -129
- package/src/components/settings-fields.tsx +0 -237
- package/src/components/share-card-labels.ts +0 -30
- package/src/components/share-card.tsx +0 -675
- package/src/components/signature-pad-labels.ts +0 -24
- package/src/components/signature-pad.tsx +0 -747
- package/src/components/signed-amount-labels.ts +0 -10
- package/src/components/signed-amount.tsx +0 -336
- package/src/components/skeleton.tsx +0 -80
- package/src/components/slider.tsx +0 -338
- package/src/components/sparkline-labels.ts +0 -14
- package/src/components/sparkline.tsx +0 -322
- package/src/components/spinner.tsx +0 -81
- package/src/components/stat-tile-labels.ts +0 -15
- package/src/components/stat-tile.tsx +0 -754
- package/src/components/status-dot.tsx +0 -170
- package/src/components/swatch-picker-labels.ts +0 -10
- package/src/components/swatch-picker.tsx +0 -283
- package/src/components/swipeable-row.tsx +0 -386
- package/src/components/switch.tsx +0 -273
- package/src/components/table-skeleton.tsx +0 -136
- package/src/components/table.tsx +0 -647
- package/src/components/tabs-labels.ts +0 -13
- package/src/components/tabs.tsx +0 -693
- package/src/components/text-link.tsx +0 -359
- package/src/components/text.tsx +0 -150
- package/src/components/textarea.tsx +0 -330
- package/src/components/tile-radio.tsx +0 -332
- package/src/components/time-input.tsx +0 -121
- package/src/components/toast-labels.ts +0 -12
- package/src/components/toast.tsx +0 -519
- package/src/components/toggle-group.tsx +0 -752
- package/src/components/toggle-legend.tsx +0 -394
- package/src/components/tooltip.tsx +0 -1149
- package/src/components/translation-review-editor.tsx +0 -290
- package/src/components/translation-review-labels.ts +0 -181
- package/src/components/translation-review-parts.tsx +0 -272
- package/src/components/translation-review.tsx +0 -1240
- package/src/components/tree-view.tsx +0 -589
- package/src/components/treemap-labels.ts +0 -47
- package/src/components/treemap-layout.ts +0 -210
- package/src/components/treemap.tsx +0 -1184
- package/src/components/trigger-aria.ts +0 -44
- package/src/components/use-anchor-dir.ts +0 -20
- package/src/components/use-mobile-reveal.ts +0 -62
- package/src/components/use-table-state.ts +0 -753
- package/src/components/user-avatar.tsx +0 -116
- package/src/components/wizard-stepper.tsx +0 -42
- package/src/components/write-lock-labels.ts +0 -10
- package/src/components/write-lock.tsx +0 -253
- package/src/currencies.ts +0 -90
- package/src/data-table.ts +0 -42
- package/src/demo/demo-banner.tsx +0 -153
- package/src/demo/demo-countdown.ts +0 -136
- package/src/demo/demo-ended.tsx +0 -90
- package/src/demo/demo-labels.ts +0 -78
- package/src/demo/demo-session.ts +0 -32
- package/src/demo/demo-start.tsx +0 -156
- package/src/eslint/index.ts +0 -161
- package/src/eslint/role-utilities.generated.ts +0 -146
- package/src/eslint/role-utilities.ts +0 -233
- package/src/feedback/feedback-attachment-download.tsx +0 -77
- package/src/feedback/feedback-attachment-labels.ts +0 -37
- package/src/feedback/feedback-attachment.tsx +0 -1239
- package/src/feedback/feedback-capture.ts +0 -287
- package/src/feedback/feedback-comment-thread.tsx +0 -353
- package/src/feedback/feedback-context-labels.ts +0 -11
- package/src/feedback/feedback-context.tsx +0 -245
- package/src/feedback/feedback-crash.ts +0 -547
- package/src/feedback/feedback-diagnostics.tsx +0 -41
- package/src/feedback/feedback-dialog-labels.ts +0 -29
- package/src/feedback/feedback-dialog.tsx +0 -452
- package/src/feedback/feedback-entry-file.tsx +0 -150
- package/src/feedback/feedback-inbox.tsx +0 -552
- package/src/feedback/feedback-labels.ts +0 -144
- package/src/feedback/feedback-menu-labels.ts +0 -12
- package/src/feedback/feedback-menu.tsx +0 -177
- package/src/feedback/feedback-mutation.ts +0 -20
- package/src/feedback/feedback-page-link.ts +0 -90
- package/src/feedback/feedback-public-labels.ts +0 -81
- package/src/feedback/feedback-public-list.tsx +0 -524
- package/src/feedback/feedback-public-switch.tsx +0 -102
- package/src/feedback/feedback-public-types.ts +0 -101
- package/src/feedback/feedback-record.ts +0 -428
- package/src/feedback/feedback-replies-context.ts +0 -9
- package/src/feedback/feedback-replies.tsx +0 -343
- package/src/feedback/feedback-rework-entry-chip.tsx +0 -18
- package/src/feedback/feedback-row-detail-labels.ts +0 -31
- package/src/feedback/feedback-row-detail.tsx +0 -871
- package/src/feedback/feedback-status-undo.ts +0 -109
- package/src/feedback/feedback-submit-dialog.tsx +0 -131
- package/src/feedback/feedback-submit.tsx +0 -270
- package/src/feedback/feedback-swipe.tsx +0 -192
- package/src/feedback/feedback-table-labels.ts +0 -27
- package/src/feedback/feedback-table.tsx +0 -912
- package/src/feedback/feedback-thread-labels.ts +0 -22
- package/src/feedback/feedback-thread-parts-labels.ts +0 -41
- package/src/feedback/feedback-thread.tsx +0 -905
- package/src/feedback/feedback-vocabulary.ts +0 -263
- package/src/feedback/feedback-vote-button.tsx +0 -124
- package/src/feedback.ts +0 -116
- package/src/hooks/use-anchored-panel.ts +0 -396
- package/src/hooks/use-anchored-rect.ts +0 -77
- package/src/hooks/use-announce.ts +0 -85
- package/src/hooks/use-authed-src.ts +0 -167
- package/src/hooks/use-body-scroll-lock.ts +0 -119
- package/src/hooks/use-breakpoint.ts +0 -133
- package/src/hooks/use-close-transition.ts +0 -107
- package/src/hooks/use-copy-to-clipboard.ts +0 -122
- package/src/hooks/use-debounce.ts +0 -114
- package/src/hooks/use-dismiss.ts +0 -371
- package/src/hooks/use-document-title.ts +0 -33
- package/src/hooks/use-file-drop.ts +0 -121
- package/src/hooks/use-file-picker-labels.ts +0 -28
- package/src/hooks/use-file-picker.tsx +0 -359
- package/src/hooks/use-focus-trap.ts +0 -199
- package/src/hooks/use-hotkey.ts +0 -212
- package/src/hooks/use-large-text.ts +0 -41
- package/src/hooks/use-long-press.ts +0 -140
- package/src/hooks/use-media-query.ts +0 -39
- package/src/hooks/use-mounted.ts +0 -39
- package/src/hooks/use-noindex.ts +0 -37
- package/src/hooks/use-overlay-history.ts +0 -714
- package/src/hooks/use-row-swipe.ts +0 -207
- package/src/hooks/use-search-param-state.ts +0 -434
- package/src/hooks/use-windowed-rows.ts +0 -225
- package/src/i18n/defaults.ts +0 -267
- package/src/i18n/german.ts +0 -2059
- package/src/i18n/kit-labels.tsx +0 -1003
- package/src/i18n/languages.ts +0 -349
- package/src/i18n/locales/de-CH.ts +0 -24
- package/src/i18n/locales/en.ts +0 -267
- package/src/i18n/locales/es.ts +0 -1999
- package/src/i18n/locales/fr.ts +0 -2037
- package/src/i18n/locales/hu.ts +0 -2004
- package/src/i18n/locales/it.ts +0 -2014
- package/src/i18n/locales/zh.ts +0 -1912
- package/src/i18n/plurals.ts +0 -86
- package/src/i18n/review.ts +0 -475
- package/src/i18n/shared-labels.ts +0 -138
- package/src/i18n/swiss.ts +0 -29
- package/src/index.ts +0 -1191
- package/src/landing/access.ts +0 -93
- package/src/landing/landing-actions.tsx +0 -97
- package/src/landing/landing-labels.ts +0 -59
- package/src/landing/landing-sections.tsx +0 -341
- package/src/landing/page-seo.ts +0 -261
- package/src/landing/public-header.tsx +0 -121
- package/src/landing/public-page.tsx +0 -106
- package/src/landing/routing.tsx +0 -225
- package/src/lib/broadcast.ts +0 -52
- package/src/lib/calc.ts +0 -323
- package/src/lib/chip-edge-snap.ts +0 -212
- package/src/lib/clipboard-minus.ts +0 -107
- package/src/lib/clipping.ts +0 -34
- package/src/lib/cn.ts +0 -28
- package/src/lib/column-mapping.ts +0 -234
- package/src/lib/countries.ts +0 -91
- package/src/lib/data-attributes.ts +0 -14
- package/src/lib/date-format.ts +0 -227
- package/src/lib/dates.ts +0 -288
- package/src/lib/day-format.ts +0 -96
- package/src/lib/decimal-marks.ts +0 -108
- package/src/lib/describe-failure.ts +0 -18
- package/src/lib/device-settings.ts +0 -147
- package/src/lib/direction.ts +0 -74
- package/src/lib/document-navigation.ts +0 -17
- package/src/lib/document-title.ts +0 -41
- package/src/lib/download.ts +0 -172
- package/src/lib/float-clearance.ts +0 -70
- package/src/lib/floating-stack.ts +0 -70
- package/src/lib/focus-left.ts +0 -156
- package/src/lib/format.ts +0 -585
- package/src/lib/http-status.ts +0 -38
- package/src/lib/iban.ts +0 -251
- package/src/lib/ime.ts +0 -24
- package/src/lib/intl-cache.ts +0 -27
- package/src/lib/iso-day.ts +0 -13
- package/src/lib/lazy-with-fallback.ts +0 -82
- package/src/lib/logger.ts +0 -69
- package/src/lib/minus.ts +0 -50
- package/src/lib/path-pattern.ts +0 -55
- package/src/lib/person-name.ts +0 -155
- package/src/lib/phone.ts +0 -208
- package/src/lib/plain-text.ts +0 -22
- package/src/lib/presence.ts +0 -18
- package/src/lib/qr-encode.ts +0 -444
- package/src/lib/quiet-focus.ts +0 -32
- package/src/lib/reduced-motion.ts +0 -22
- package/src/lib/refs.ts +0 -22
- package/src/lib/round.ts +0 -43
- package/src/lib/safe-storage.ts +0 -119
- package/src/lib/server-wake.ts +0 -315
- package/src/lib/session-refresh.ts +0 -472
- package/src/lib/share-format.ts +0 -18
- package/src/lib/status-tone.ts +0 -43
- package/src/lib/strip-fade.ts +0 -287
- package/src/lib/table-text.ts +0 -554
- package/src/lib/text-case.ts +0 -19
- package/src/lib/text-match.ts +0 -169
- package/src/lib/thenable.ts +0 -19
- package/src/lib/translation-review.ts +0 -769
- package/src/notifications/device-zone-report.ts +0 -67
- package/src/notifications/feedback-notification-types-labels.ts +0 -33
- package/src/notifications/feedback-notification-types.ts +0 -71
- package/src/notifications/notification-bell.tsx +0 -119
- package/src/notifications/notification-inbox.tsx +0 -309
- package/src/notifications/notification-parts.tsx +0 -81
- package/src/notifications/notification-types-setting.tsx +0 -406
- package/src/notifications/notification-types.ts +0 -89
- package/src/notifications/notifications-labels.ts +0 -287
- package/src/notifications/push-device-setting.tsx +0 -230
- package/src/notifications/push-devices-setting.tsx +0 -374
- package/src/notifications/push-worker.ts +0 -168
- package/src/notifications/quiet-hours-setting.tsx +0 -238
- package/src/notifications/unsubscribe-panel.tsx +0 -200
- package/src/notifications/use-push-device.ts +0 -448
- package/src/offline/local-first.ts +0 -100
- package/src/offline/pwa-update-prompt-labels.ts +0 -9
- package/src/offline/pwa-update-prompt.tsx +0 -78
- package/src/offline/query-persistence.ts +0 -391
- package/src/offline/service-worker-updates.ts +0 -81
- package/src/offline/shared-computer-labels.ts +0 -8
- package/src/offline/shared-computer.tsx +0 -87
- package/src/offline/sign-out-pending-dialog-labels.ts +0 -21
- package/src/offline/sign-out-pending-dialog.tsx +0 -135
- package/src/offline.ts +0 -37
- package/src/push-worker.ts +0 -25
- package/src/rhf/fields.tsx +0 -2187
- package/src/rhf/form-core.tsx +0 -324
- package/src/rhf/form.tsx +0 -12
- package/src/rhf/line-items.tsx +0 -135
- package/src/rhf/use-rhf-wizard-step.ts +0 -104
- package/src/rhf.ts +0 -21
- package/src/search/command-palette-labels.ts +0 -16
- package/src/search/command-palette.tsx +0 -624
- package/src/search/global-search-labels.ts +0 -13
- package/src/search/global-search.tsx +0 -660
- package/src/search/search-index.ts +0 -283
- package/src/search/use-command-key.ts +0 -23
- package/src/search.ts +0 -14
- package/src/settings/device-reset-setting-labels.ts +0 -20
- package/src/settings/device-reset-setting.tsx +0 -116
- package/src/settings/settings-card-classes.ts +0 -11
- package/src/settings/settings-catalogue.ts +0 -150
- package/src/settings/settings-context.ts +0 -33
- package/src/settings/settings-heading.tsx +0 -67
- package/src/settings/settings-labels.ts +0 -87
- package/src/settings/settings-layout.tsx +0 -471
- package/src/settings/settings-section.tsx +0 -108
- package/src/settings/use-account-appearance.ts +0 -148
- package/src/settings/use-account-language.ts +0 -146
- package/src/settings/use-settings-focus.ts +0 -128
- package/src/settings/use-settings-route.ts +0 -258
- package/src/shell/account-menu-language.tsx +0 -130
- package/src/shell/account-menu-text-size.tsx +0 -80
- package/src/shell/admin-menu.tsx +0 -183
- package/src/shell/app-shell-labels.ts +0 -11
- package/src/shell/app-shell.tsx +0 -1560
- package/src/shell/auth-layout.tsx +0 -186
- package/src/shell/company-switcher-labels.ts +0 -13
- package/src/shell/company-switcher.tsx +0 -136
- package/src/shell/dev-menu.tsx +0 -257
- package/src/shell/fill-height.tsx +0 -45
- package/src/shell/language-code.ts +0 -5
- package/src/shell/option-switcher-menu.tsx +0 -84
- package/src/shell/sync-status-indicator.tsx +0 -303
- package/src/shell/top-bar-actions.tsx +0 -87
- package/src/shell/top-bar-brand.tsx +0 -78
- package/src/shell/top-bar-parts-labels.ts +0 -148
- package/src/shell/top-bar.tsx +0 -40
- package/src/shell/topbar-action-menu.tsx +0 -567
- package/src/shell/topbar-controls.tsx +0 -269
- package/src/shell/tour-menu.tsx +0 -187
- package/src/shell.ts +0 -108
- package/src/sync/db.ts +0 -129
- package/src/sync/engine.ts +0 -1011
- package/src/sync/hooks.ts +0 -98
- package/src/sync/testing.ts +0 -73
- package/src/sync/wire.ts +0 -61
- package/src/sync.ts +0 -37
- package/src/table-text.ts +0 -8
- package/src/testing/css-variables.generated.ts +0 -112
- package/src/testing/css-variables.ts +0 -189
- package/src/testing/index.ts +0 -29
- package/src/testing/react.ts +0 -58
- package/src/testing/tour.ts +0 -41
- package/src/testing/viewport.ts +0 -357
- package/src/theme/chart-palette.ts +0 -232
- package/src/theme/color.ts +0 -272
- package/src/theme/contrast-tokens.ts +0 -268
- package/src/theme/contrast.ts +0 -250
- package/src/theme/palette-derive.ts +0 -825
- package/src/theme/palette-presets.ts +0 -544
- package/src/theme/palette-store.ts +0 -108
- package/src/theme/text-size.ts +0 -289
- package/src/theme/theme-store.ts +0 -157
- package/src/tour/tour-catalogue-labels.ts +0 -75
- package/src/tour/tour-catalogue.tsx +0 -335
- package/src/tour/tour-dock.ts +0 -134
- package/src/tour/tour-engine.ts +0 -37
- package/src/tour/tour-gates.ts +0 -218
- package/src/tour/tour-guide-button.tsx +0 -64
- package/src/tour/tour-guide-labels.ts +0 -15
- package/src/tour/tour-info.ts +0 -144
- package/src/tour/tour-labels.ts +0 -23
- package/src/tour/tour-overlay.tsx +0 -1170
- package/src/tour/tour.tsx +0 -750
- package/src/tour/use-tour-progress.ts +0 -671
- package/src/tour/use-tour-url-sync.ts +0 -266
- package/src/tour.ts +0 -21
- package/src/vite-env.d.ts +0 -23
- package/src/wizard/stepper-nav.tsx +0 -360
- package/src/wizard/types.ts +0 -275
- package/src/wizard/use-wizard.ts +0 -560
- package/src/wizard/validation.ts +0 -39
- package/src/wizard/wizard-context.tsx +0 -74
- package/src/wizard/wizard-labels.ts +0 -29
- package/src/wizard/wizard-step.tsx +0 -76
- package/src/wizard/wizard-summary.tsx +0 -84
- package/src/wizard.ts +0 -15
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
|
-
import type { ReactNode } from "react";
|
|
3
|
-
import { Send } from "lucide-react";
|
|
4
|
-
|
|
5
|
-
import { useKitLabels, type LabelOverride } from "../i18n/kit-labels";
|
|
6
|
-
import { isRateLimited, retryAfterSeconds } from "../auth/auth-errors";
|
|
7
|
-
import { AlertBanner } from "../components/alert-banner";
|
|
8
|
-
import { Button } from "../components/button";
|
|
9
|
-
import { Chip } from "../components/chip";
|
|
10
|
-
import { SettingsSection, type SettingsSectionProps } from "../settings/settings-section";
|
|
11
|
-
import { DEFAULT_MAIL_TEST_CARD_LABELS } from "./mail-test-card-labels";
|
|
12
|
-
|
|
13
|
-
/* ── Labels ──────────────────────────────────────────────────────────────── */
|
|
14
|
-
|
|
15
|
-
/** Every string {@link MailTestCard} renders — the `mailTestCard` namespace of
|
|
16
|
-
* `<UiKitProvider labels>`, overridable per instance through `labels`
|
|
17
|
-
* (docs/admin-harmonization.md §9.2.4). */
|
|
18
|
-
export interface MailTestCardLabels {
|
|
19
|
-
/** The card's title, and the app's catalogue entry's. */
|
|
20
|
-
title: string;
|
|
21
|
-
/** The sentence under it. */
|
|
22
|
-
description: string;
|
|
23
|
-
/** The transport's chip: "Transport: resend". `backend` is the server's `mail_backend`. */
|
|
24
|
-
transport: (backend: string) => string;
|
|
25
|
-
/** The button. */
|
|
26
|
-
action: string;
|
|
27
|
-
/** The answer said "sent" through a real transport. `address` is masked ("a…@example.com"). */
|
|
28
|
-
sent: (address: string) => string;
|
|
29
|
-
/** `mail_backend` is `console`: said whatever `sent` is — a console answers `true`. */
|
|
30
|
-
console: string;
|
|
31
|
-
/** Not sent, or the request failed. The provider's error stays in the server log. */
|
|
32
|
-
failed: string;
|
|
33
|
-
/** HTTP 429 — the app's limiter (server-kit's `MAIL_TEST_LIMIT`, 3 per 10 minutes);
|
|
34
|
-
* `seconds` from `Retry-After` when the response has one. */
|
|
35
|
-
rateLimited: (seconds?: number) => string;
|
|
36
|
-
/** For the app's catalogue entry (`keywords`); the card never reads it. */
|
|
37
|
-
keywords: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Defined in ./mail-test-card-labels, which holds no component code.
|
|
41
|
-
export { DEFAULT_MAIL_TEST_CARD_LABELS };
|
|
42
|
-
|
|
43
|
-
/* ── The card ────────────────────────────────────────────────────────────── */
|
|
44
|
-
|
|
45
|
-
/** The answer of `POST /admin/mail/test` — server-kit 0.15's `MailTestResult`. */
|
|
46
|
-
export interface MailTestAnswer {
|
|
47
|
-
sent: boolean;
|
|
48
|
-
/** The transport that took it: `console`, `resend`, `smtp`, … */
|
|
49
|
-
mail_backend: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** The card's default DOM id: its catalogue entry's `anchor`, the `?focus=` target. */
|
|
53
|
-
export const MAIL_TEST_ANCHOR = "admin-mail-test";
|
|
54
|
-
|
|
55
|
-
export interface MailTestCardProps extends Omit<SettingsSectionProps, "anchor" | "title" | "description" | "children"> {
|
|
56
|
-
/** The installation's transport, as the admin page has it (`mail_backend`): the chip
|
|
57
|
-
* before a send. After one, the answer's. Optional (0.46): without it the chip shows
|
|
58
|
-
* from the first answer on, and an app needs no query only for the chip. */
|
|
59
|
-
mailBackend?: string;
|
|
60
|
-
/** The app's `POST /admin/mail/test` (kastlan `/platform/mail/test`), no body: it
|
|
61
|
-
* awaits the app's own send and answers `{sent, mail_backend}`. A rejection is read
|
|
62
|
-
* for a 429 (the limiter); anything else is "could not send". */
|
|
63
|
-
send: () => Promise<MailTestAnswer>;
|
|
64
|
-
/** The signed-in admin's own address — where the mail goes. Shown masked. */
|
|
65
|
-
address: string;
|
|
66
|
-
/** Default {@link MAIL_TEST_ANCHOR}; the app's catalogue entry names the same. */
|
|
67
|
-
anchor?: string;
|
|
68
|
-
/** The app's sentence after the kit's description. */
|
|
69
|
-
description?: ReactNode;
|
|
70
|
-
labels?: LabelOverride<MailTestCardLabels>;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* An address with its local part masked to its first character: "ada@example.com" →
|
|
75
|
-
* "a…@example.com". The domain stays, so the admin sees which mailbox to open.
|
|
76
|
-
*/
|
|
77
|
-
export function maskMailAddress(address: string): string {
|
|
78
|
-
const text = address.trim();
|
|
79
|
-
const at = text.lastIndexOf("@");
|
|
80
|
-
if (at <= 0) return text === "" ? "" : `${Array.from(text)[0]}…`;
|
|
81
|
-
return `${Array.from(text.slice(0, at))[0]}…${text.slice(at)}`;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
type Outcome =
|
|
85
|
-
| { kind: "sent"; backend: string }
|
|
86
|
-
| { kind: "console"; backend: string }
|
|
87
|
-
| { kind: "failed"; backend?: string }
|
|
88
|
-
| { kind: "limited"; seconds?: number };
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* "Send a test mail to me" (docs/admin-harmonization.md §9.2): a `SettingsSection` with a
|
|
92
|
-
* sentence, the transport as a chip, the button and the result line. One mail goes to the
|
|
93
|
-
* signed-in admin's own address, never another, through the app's own send.
|
|
94
|
-
*
|
|
95
|
-
* **The result line reads `mail_backend` first**: with `console` it says "nothing was sent"
|
|
96
|
-
* whatever `sent` is, since every console path answers `true` (§9.2 Today). Otherwise
|
|
97
|
-
* `sent` says "Sent to a…@example.com. Check the inbox." or "Could not send." — the
|
|
98
|
-
* provider's error stays in the server log (§9.2.7). A 429 says the limiter's line. The
|
|
99
|
-
* button is busy while the request runs; the line is a live region.
|
|
100
|
-
*
|
|
101
|
-
* Not a commit: the test writes nothing, so it is not under the write lock (a demo never
|
|
102
|
-
* reaches the admin area, and the server refuses it anyway). The app adds the catalogue
|
|
103
|
-
* entry `{ id, anchor: MAIL_TEST_ANCHOR, title, keywords }` from these labels.
|
|
104
|
-
*/
|
|
105
|
-
export function MailTestCard({
|
|
106
|
-
mailBackend,
|
|
107
|
-
send,
|
|
108
|
-
address,
|
|
109
|
-
anchor = MAIL_TEST_ANCHOR,
|
|
110
|
-
description,
|
|
111
|
-
labels: labelsProp,
|
|
112
|
-
...rest
|
|
113
|
-
}: MailTestCardProps) {
|
|
114
|
-
const labels = useKitLabels("mailTestCard", DEFAULT_MAIL_TEST_CARD_LABELS, labelsProp);
|
|
115
|
-
const [busy, setBusy] = useState(false);
|
|
116
|
-
const [outcome, setOutcome] = useState<Outcome | null>(null);
|
|
117
|
-
// The last transport an answer named: a later send with no answer (429, network) keeps it.
|
|
118
|
-
const [answered, setAnswered] = useState<string | undefined>(undefined);
|
|
119
|
-
|
|
120
|
-
const run = async () => {
|
|
121
|
-
if (busy) return;
|
|
122
|
-
setBusy(true);
|
|
123
|
-
setOutcome(null);
|
|
124
|
-
try {
|
|
125
|
-
const answer = await send();
|
|
126
|
-
const backend = answer.mail_backend;
|
|
127
|
-
if (backend) setAnswered(backend);
|
|
128
|
-
if (backend === "console") setOutcome({ kind: "console", backend });
|
|
129
|
-
else setOutcome(answer.sent ? { kind: "sent", backend } : { kind: "failed", backend });
|
|
130
|
-
} catch (error) {
|
|
131
|
-
setOutcome(isRateLimited(error) ? { kind: "limited", seconds: retryAfterSeconds(error) } : { kind: "failed" });
|
|
132
|
-
} finally {
|
|
133
|
-
setBusy(false);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const backend = answered ?? mailBackend;
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
<SettingsSection
|
|
141
|
-
{...rest}
|
|
142
|
-
anchor={anchor}
|
|
143
|
-
title={labels.title}
|
|
144
|
-
description={
|
|
145
|
-
description != null ? (
|
|
146
|
-
<>
|
|
147
|
-
{labels.description} {description}
|
|
148
|
-
</>
|
|
149
|
-
) : (
|
|
150
|
-
labels.description
|
|
151
|
-
)
|
|
152
|
-
}
|
|
153
|
-
>
|
|
154
|
-
<div className="space-y-2">
|
|
155
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
156
|
-
<Button variant="secondary" pending={busy} onClick={() => void run()}>
|
|
157
|
-
<Send className="size-4" aria-hidden />
|
|
158
|
-
{labels.action}
|
|
159
|
-
</Button>
|
|
160
|
-
{backend && (
|
|
161
|
-
<Chip size="sm" data-slot="mail-backend">
|
|
162
|
-
{labels.transport(backend)}
|
|
163
|
-
</Chip>
|
|
164
|
-
)}
|
|
165
|
-
</div>
|
|
166
|
-
{outcome?.kind === "sent" && (
|
|
167
|
-
<AlertBanner variant="inline" block tone="success">
|
|
168
|
-
<span data-private>{labels.sent(maskMailAddress(address))}</span>
|
|
169
|
-
</AlertBanner>
|
|
170
|
-
)}
|
|
171
|
-
{outcome?.kind === "console" && (
|
|
172
|
-
<AlertBanner variant="inline" block tone="info">
|
|
173
|
-
{labels.console}
|
|
174
|
-
</AlertBanner>
|
|
175
|
-
)}
|
|
176
|
-
{outcome?.kind === "failed" && (
|
|
177
|
-
<AlertBanner variant="inline" block tone="danger">
|
|
178
|
-
{labels.failed}
|
|
179
|
-
</AlertBanner>
|
|
180
|
-
)}
|
|
181
|
-
{outcome?.kind === "limited" && (
|
|
182
|
-
<AlertBanner variant="inline" block tone="warning">
|
|
183
|
-
{labels.rateLimited(outcome.seconds)}
|
|
184
|
-
</AlertBanner>
|
|
185
|
-
)}
|
|
186
|
-
</div>
|
|
187
|
-
</SettingsSection>
|
|
188
|
-
);
|
|
189
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
// Moved to billing/plan-change-labels in 0.52 (refactor audit 2026-10-30, MOD-6): the
|
|
2
|
-
// billing and admin folders imported each other through it. Kept so the old path still
|
|
3
|
-
// answers; nothing in the kit imports it any more but the English catalogue.
|
|
4
|
-
export { DEFAULT_PLAN_CHANGE_LABELS } from "../billing/plan-change-labels";
|
|
5
|
-
export type { PlanChangeLabels } from "../billing/plan-change-labels";
|
|
@@ -1,474 +0,0 @@
|
|
|
1
|
-
import { isValidElement, useCallback, useMemo, useState } from "react";
|
|
2
|
-
import type { ReactNode } from "react";
|
|
3
|
-
|
|
4
|
-
import { useKitLabels, useKitLocale, type LabelOverride } from "../i18n/kit-labels";
|
|
5
|
-
import { pluralForm } from "../i18n/plurals";
|
|
6
|
-
import type { PluralForms } from "../i18n/plurals";
|
|
7
|
-
import { formatNumber, EMPTY_FORMATTED_VALUE } from "../lib/format";
|
|
8
|
-
import { toLocalIso } from "../lib/dates";
|
|
9
|
-
import type { DataTableColumn } from "../components/data-table";
|
|
10
|
-
import { DatePicker } from "../components/date-picker";
|
|
11
|
-
import { Tooltip } from "../components/tooltip";
|
|
12
|
-
import { Select } from "../components/select";
|
|
13
|
-
import { COMMIT_EXCEPT_BILLING } from "../components/write-lock";
|
|
14
|
-
import { useBillingLabels } from "../billing/billing-labels";
|
|
15
|
-
import type { SubscriptionStatus } from "../billing/billing-labels";
|
|
16
|
-
import { SubscriptionStatusChip } from "../billing/subscription-status-chip";
|
|
17
|
-
import { AdminActionConfirm } from "./admin-action-confirm";
|
|
18
|
-
import type { AdminActionConfirmValues } from "./admin-action-confirm";
|
|
19
|
-
import { personLabel, useDayText } from "./admin-parts";
|
|
20
|
-
import type { AdminPerson, MaybePromise } from "./admin-parts";
|
|
21
|
-
import { DEFAULT_PLAN_CHANGE_LABELS } from "../billing/plan-change-labels";
|
|
22
|
-
import type { PlanChangeLabels } from "../billing/plan-change-labels";
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* The operator's plan parts (docs/billing-harmonization.md §14.12, decision 27):
|
|
26
|
-
* {@link planColumn} for the roster or the companies list, {@link PlanChangeConfirm}
|
|
27
|
-
* for the grant, and {@link usePlanChangeResult} for what the answer says.
|
|
28
|
-
*
|
|
29
|
-
* All three apps have the route (`POST /admin/users/{id}/plan`, kastlan's
|
|
30
|
-
* `POST /platform/companies/{id}/plan`) and server-kit's `PlanChangeRequest` /
|
|
31
|
-
* `PlanChangeResponse`; only keksdose had a UI (`users-panel.tsx`, `PlanConfirm` in
|
|
32
|
-
* `user-admin-confirm.tsx`), and these are its parts, lifted. The plan names are the
|
|
33
|
-
* app's (§3.1): every part takes `planName` or the plans with their names. The plan
|
|
34
|
-
* codes come from `GET /admin/plans` (kastlan `GET /platform/plans`), which answers
|
|
35
|
-
* whatever the billing switch says.
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
// The words and their type live in billing/plan-change-labels, which holds no component
|
|
39
|
-
// code (0.34, KS U8): PlanSwitchConfirm reads them too, and billing importing admin while
|
|
40
|
-
// this module imports billing made the two folders import each other (refactor audit
|
|
41
|
-
// 2026-10-30, MOD-6).
|
|
42
|
-
export type { PlanChangeLabels };
|
|
43
|
-
export { DEFAULT_PLAN_CHANGE_LABELS };
|
|
44
|
-
|
|
45
|
-
/** A plan code as the parts compare it: lowercase (§12.16 — an older row's "FREE" is
|
|
46
|
-
* the same plan as "free"), and no code at all as null. */
|
|
47
|
-
function codeOf(raw: string | null | undefined): string | null {
|
|
48
|
-
const code = (raw ?? "").trim().toLowerCase();
|
|
49
|
-
return code === "" ? null : code;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/* ── The column ────────────────────────────────────────────────────────────── */
|
|
53
|
-
|
|
54
|
-
/** What a row's usage is, for the line under its plan: "1/5" — and since 0.34 what
|
|
55
|
-
* {@link PlanChangeConfirm}'s `usage` takes, for the same sentence in the dialog. */
|
|
56
|
-
export interface PlanColumnUsage {
|
|
57
|
-
used: number;
|
|
58
|
-
/** The plan's limit for it; `null` (unlimited, or none known): no line. */
|
|
59
|
-
limit: number | null;
|
|
60
|
-
/**
|
|
61
|
-
* The app's word for what is counted, as it reads after a number: "budgets" in "1 of 5
|
|
62
|
-
* budgets" — the word in a sentence, not a heading's "Budgets".
|
|
63
|
-
*
|
|
64
|
-
* Its plural forms (0.33.1, keksdose): `{ one: "budget", other: "budgets" }` — your
|
|
65
|
-
* catalogue's `_one` / `_other` pair, any CLDR category allowed, `other` for the rest
|
|
66
|
-
* ({@link PluralForms}). The column picks the form for the limit in the provider's
|
|
67
|
-
* locale, so a plan of one reads "1 of 1 budget". A plain string is used as it is,
|
|
68
|
-
* whatever the count.
|
|
69
|
-
*/
|
|
70
|
-
label: string | PluralForms;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface PlanColumnOptions<T> {
|
|
74
|
-
/** The column's key. Default `"plan"`. */
|
|
75
|
-
key?: string;
|
|
76
|
-
/** The row's plan code, read without case (§12.16); null for none. */
|
|
77
|
-
plan: (row: T) => string | null;
|
|
78
|
-
/** The plan's display name, the app's (§3.1). Gets the lowercase code. */
|
|
79
|
-
planName: (code: string) => string;
|
|
80
|
-
/** The row's standing, as a `SubscriptionStatusChip` beside the name. Left out, or
|
|
81
|
-
* undefined for a row: no chip — billing off, where a status says nothing. */
|
|
82
|
-
status?: (row: T) => SubscriptionStatus | undefined;
|
|
83
|
-
/** The row's usage of its plan's limit: "1/5" under the name, "1 of 5 budgets" in
|
|
84
|
-
* the tooltip (`planChange.usageOf`, with the label's form for the limit). Undefined
|
|
85
|
-
* for a row, or a `null` limit: no line. */
|
|
86
|
-
usage?: (row: T) => PlanColumnUsage | undefined;
|
|
87
|
-
/** A select filter over these codes, each named by `planName`. Left out: none. */
|
|
88
|
-
filterPlans?: readonly string[];
|
|
89
|
-
/**
|
|
90
|
-
* The sort. Default: by the plan code (keksdose's, `users-panel.tsx:739`). A function:
|
|
91
|
-
* by its value — the catalogue's `sort` for rank order. `false`: not sortable.
|
|
92
|
-
*
|
|
93
|
-
* Client-side only, as every column's `sortBy`: a `DataTable` with `serverPagination`
|
|
94
|
-
* holds one page, so it sorts nothing itself — with `onSortsChange` it reports the
|
|
95
|
-
* column's `key` (default `"plan"`), and your server orders the rows by it.
|
|
96
|
-
*/
|
|
97
|
-
sortBy?: false | ((row: T) => string | number | null | undefined);
|
|
98
|
-
/** The header's text. Default `planChange.column`. */
|
|
99
|
-
headerText?: string;
|
|
100
|
-
/** The words, already resolved. Default English; {@link usePlanColumn} reads the
|
|
101
|
-
* provider's `planChange` namespace. */
|
|
102
|
-
labels?: LabelOverride<PlanChangeLabels>;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* A usage spelled out — `planChange.usageOf` with the figures in `locale` and the word in
|
|
107
|
-
* the form the limit takes: "1 of 1 budget", "Budgets: 1 von 5". The column's tooltip
|
|
108
|
-
* and the grant dialog's line both read it, so the rule lives once (round 0.34 C15).
|
|
109
|
-
*/
|
|
110
|
-
function usageSentence(
|
|
111
|
-
usage: PlanColumnUsage & { limit: number },
|
|
112
|
-
usageOf: PlanChangeLabels["usageOf"],
|
|
113
|
-
locale: string | undefined,
|
|
114
|
-
): string {
|
|
115
|
-
const figure = (value: number) => formatNumber(value, { locale });
|
|
116
|
-
const word = typeof usage.label === "string" ? usage.label : pluralForm(usage.limit, usage.label, locale);
|
|
117
|
-
return usageOf(figure(usage.used), figure(usage.limit), word);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/** The cell: a component, so the figures follow the provider's locale. */
|
|
121
|
-
function PlanCell({
|
|
122
|
-
code,
|
|
123
|
-
name,
|
|
124
|
-
status,
|
|
125
|
-
usage,
|
|
126
|
-
usageOf,
|
|
127
|
-
}: {
|
|
128
|
-
code: string | null;
|
|
129
|
-
name: string;
|
|
130
|
-
status: SubscriptionStatus | undefined;
|
|
131
|
-
usage: PlanColumnUsage | undefined;
|
|
132
|
-
usageOf: PlanChangeLabels["usageOf"];
|
|
133
|
-
}) {
|
|
134
|
-
const locale = useKitLocale();
|
|
135
|
-
const figure = (value: number) => formatNumber(value, { locale });
|
|
136
|
-
return (
|
|
137
|
-
<div className="whitespace-nowrap" data-plan={code ?? undefined}>
|
|
138
|
-
<div className="flex items-center gap-1.5">
|
|
139
|
-
<span className={code ? "font-medium" : "text-muted"}>{name}</span>
|
|
140
|
-
{/* The standing at a glance (§6): the kit's word and tone, never colour alone. */}
|
|
141
|
-
{status !== undefined && <SubscriptionStatusChip status={status} size="xs" />}
|
|
142
|
-
</div>
|
|
143
|
-
{usage && usage.limit !== null && (
|
|
144
|
-
// "1/5" under the plan, "1 of 5 budgets" in the tooltip: the sentence spelled out
|
|
145
|
-
// inline was the widest thing in keksdose's table.
|
|
146
|
-
<Tooltip label={usageSentence({ ...usage, limit: usage.limit }, usageOf, locale)}>
|
|
147
|
-
<span className="block text-xs tabular-nums text-muted">
|
|
148
|
-
{figure(usage.used)}/{figure(usage.limit)}
|
|
149
|
-
</span>
|
|
150
|
-
</Tooltip>
|
|
151
|
-
)}
|
|
152
|
-
</div>
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* The roster's (or the companies list's) plan column: the plan's display name, the
|
|
158
|
-
* standing chip beside it while billing is on, and the usage under it — keksdose's
|
|
159
|
-
* column, `users-panel.tsx:706-745`. Pass it in `userRosterColumns`' `extra`, or in
|
|
160
|
-
* any `DataTable`'s columns:
|
|
161
|
-
*
|
|
162
|
-
* extra: [planColumn<AdminUserRow>({
|
|
163
|
-
* plan: (u) => u.plan,
|
|
164
|
-
* planName,
|
|
165
|
-
* status: billingOn ? (u) => u.subscription?.status : undefined,
|
|
166
|
-
* usage: (u) => ({
|
|
167
|
-
* used: u.budgets_owned,
|
|
168
|
-
* limit: u.limits.budgets,
|
|
169
|
-
* label: { one: t("planUsage.budget_one"), other: t("planUsage.budget_other") },
|
|
170
|
-
* }),
|
|
171
|
-
* filterPlans: plans.map((p) => p.code),
|
|
172
|
-
* })]
|
|
173
|
-
*
|
|
174
|
-
* Pure: hand it resolved words, or use {@link usePlanColumn}.
|
|
175
|
-
*/
|
|
176
|
-
export function planColumn<T>(options: PlanColumnOptions<T>): DataTableColumn<T> {
|
|
177
|
-
const { key = "plan", plan, planName, status, usage, filterPlans, sortBy, headerText, labels: labelsProp } = options;
|
|
178
|
-
const labels: PlanChangeLabels = { ...DEFAULT_PLAN_CHANGE_LABELS, ...labelsProp };
|
|
179
|
-
const header = headerText ?? labels.column;
|
|
180
|
-
const nameOf = (code: string | null) => (code ? planName(code) : EMPTY_FORMATTED_VALUE);
|
|
181
|
-
return {
|
|
182
|
-
key,
|
|
183
|
-
header,
|
|
184
|
-
headerText: header,
|
|
185
|
-
cell: (row) => {
|
|
186
|
-
const code = codeOf(plan(row));
|
|
187
|
-
return (
|
|
188
|
-
<PlanCell
|
|
189
|
-
code={code}
|
|
190
|
-
name={nameOf(code)}
|
|
191
|
-
status={status?.(row)}
|
|
192
|
-
usage={usage?.(row)}
|
|
193
|
-
usageOf={labels.usageOf}
|
|
194
|
-
/>
|
|
195
|
-
);
|
|
196
|
-
},
|
|
197
|
-
sortBy: sortBy === false ? undefined : (sortBy ?? ((row) => codeOf(plan(row)) ?? "")),
|
|
198
|
-
filter: filterPlans
|
|
199
|
-
? {
|
|
200
|
-
type: "select",
|
|
201
|
-
getValue: (row) => codeOf(plan(row)) ?? "",
|
|
202
|
-
options: [...new Set(filterPlans.map((code) => codeOf(code)).filter((code) => code !== null))].map(
|
|
203
|
-
(code) => ({ value: code, label: planName(code) }),
|
|
204
|
-
),
|
|
205
|
-
}
|
|
206
|
-
: undefined,
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* {@link planColumn} with the `planChange` words from the provider, memoised on the
|
|
212
|
-
* options — pass stable callbacks (`useCallback`), or the column is rebuilt on every
|
|
213
|
-
* render.
|
|
214
|
-
*/
|
|
215
|
-
export function usePlanColumn<T>(options: PlanColumnOptions<T>): DataTableColumn<T> {
|
|
216
|
-
const { key, plan, planName, status, usage, filterPlans, sortBy, headerText, labels: labelsProp } = options;
|
|
217
|
-
const labels = useKitLabels("planChange", DEFAULT_PLAN_CHANGE_LABELS, labelsProp);
|
|
218
|
-
return useMemo(
|
|
219
|
-
() => planColumn<T>({ key, plan, planName, status, usage, filterPlans, sortBy, headerText, labels }),
|
|
220
|
-
[key, plan, planName, status, usage, filterPlans, sortBy, headerText, labels],
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/* ── The grant ─────────────────────────────────────────────────────────────── */
|
|
225
|
-
|
|
226
|
-
/** What {@link PlanChangeConfirmProps.onConfirm} sends: server-kit's
|
|
227
|
-
* `PlanChangeRequest` without its `acknowledged`, which comes in `values`. */
|
|
228
|
-
export interface PlanChange {
|
|
229
|
-
/** The picked plan's code. */
|
|
230
|
-
plan: string;
|
|
231
|
-
/** The end of the free grant, as ISO UTC — only when one was picked. */
|
|
232
|
-
comped_until?: string;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
export interface PlanChangeConfirmProps {
|
|
236
|
-
/**
|
|
237
|
-
* Whom it is about — a user (`AdminActionTarget`), or kastlan's company, which has no
|
|
238
|
-
* address: its name is said instead (the level is `acknowledge`, so nothing is typed).
|
|
239
|
-
*/
|
|
240
|
-
target: AdminPerson & { email?: string | null };
|
|
241
|
-
/** The plans to offer, in the catalogue's order, by their display names (§3.1) — from
|
|
242
|
-
* `GET /admin/plans`. */
|
|
243
|
-
plans: readonly { code: string; name: string }[];
|
|
244
|
-
/** The account's plan now; null for none. The select opens on it. */
|
|
245
|
-
current: string | null;
|
|
246
|
-
/**
|
|
247
|
-
* What the account uses. The column's shape (0.34, keksdose N1) — `{ used, limit, label }`,
|
|
248
|
-
* the label a word or its plural forms — is spelled out as the column's tooltip is
|
|
249
|
-
* (`planChange.usageOf`, the word in the limit's form: "1 of 1 budget"); a `null` limit
|
|
250
|
-
* gives no line. Or the app's own sentence, as it is: "3 of 5 budgets".
|
|
251
|
-
*/
|
|
252
|
-
usage?: PlanColumnUsage | ReactNode;
|
|
253
|
-
/** Offer "Free until" — only meaningful while billing is on, where a grant's end
|
|
254
|
-
* means something to the payer. */
|
|
255
|
-
grantEnd?: boolean;
|
|
256
|
-
/**
|
|
257
|
-
* Sends it: `{plan}`, and `comped_until` only when an end was picked — the END of the
|
|
258
|
-
* picked day in the operator's time zone, as ISO UTC (a grant "until 31 January" lasts
|
|
259
|
-
* through it). No end: a grant without one, or on a running beta only the plan moves
|
|
260
|
-
* and the beta keeps its own end (§12.34). `values.acknowledged` is the body's
|
|
261
|
-
* `acknowledged`. A promise is handled as `AdminActionConfirm`'s.
|
|
262
|
-
*/
|
|
263
|
-
onConfirm: (change: PlanChange, values: AdminActionConfirmValues) => MaybePromise;
|
|
264
|
-
onClose: (done: boolean) => void;
|
|
265
|
-
/** The app's words for a failure the kit has no code for. */
|
|
266
|
-
describeError?: (error: unknown) => ReactNode | undefined;
|
|
267
|
-
labels?: LabelOverride<PlanChangeLabels>;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/** The column's usage shape, told from a node: a plain object with the three fields. */
|
|
271
|
-
function isPlanUsage(value: PlanChangeConfirmProps["usage"]): value is PlanColumnUsage {
|
|
272
|
-
return (
|
|
273
|
-
typeof value === "object" &&
|
|
274
|
-
value !== null &&
|
|
275
|
-
!isValidElement(value) &&
|
|
276
|
-
"used" in value &&
|
|
277
|
-
"limit" in value &&
|
|
278
|
-
"label" in value
|
|
279
|
-
);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/** The end of the day `date` (YYYY-MM-DD) names, in this device's time zone, as ISO
|
|
283
|
-
* UTC — keksdose's `endOfDay` (`user-admin-confirm.tsx:44-46`). */
|
|
284
|
-
function endOfDay(date: string): string {
|
|
285
|
-
return new Date(`${date}T23:59:59`).toISOString();
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* An operator's plan change (§14.12): `AdminActionConfirm` at `acknowledge`, the line
|
|
290
|
-
* with the current plan and the app's usage sentence, a plan select, and — with
|
|
291
|
-
* `grantEnd` — the end of a free grant. The confirm is held while nothing would change.
|
|
292
|
-
*
|
|
293
|
-
* Exempt from a BILLING lock, built in (`COMMIT_EXCEPT_BILLING`, §12.36): a plan change
|
|
294
|
-
* is an admin route (§12.13), and the operator's own account or company may be lapsed —
|
|
295
|
-
* kastlan's review. A demo lock still holds it.
|
|
296
|
-
*/
|
|
297
|
-
export function PlanChangeConfirm({
|
|
298
|
-
target,
|
|
299
|
-
plans,
|
|
300
|
-
current: currentProp,
|
|
301
|
-
usage,
|
|
302
|
-
grantEnd = false,
|
|
303
|
-
onConfirm,
|
|
304
|
-
onClose,
|
|
305
|
-
describeError,
|
|
306
|
-
labels: labelsProp,
|
|
307
|
-
}: PlanChangeConfirmProps) {
|
|
308
|
-
const labels = useKitLabels("planChange", DEFAULT_PLAN_CHANGE_LABELS, labelsProp);
|
|
309
|
-
const locale = useKitLocale();
|
|
310
|
-
// Seeded from the account, so the picker opens on the truth and confirming without
|
|
311
|
-
// touching it is held rather than a silent free → free in the audit.
|
|
312
|
-
const current = codeOf(currentProp);
|
|
313
|
-
const [plan, setPlan] = useState(current ?? "");
|
|
314
|
-
const [until, setUntil] = useState("");
|
|
315
|
-
// A grant ends today at the earliest; read once, not on every render.
|
|
316
|
-
const [today] = useState(() => toLocalIso(new Date()));
|
|
317
|
-
const options = plans.map((p) => ({ code: codeOf(p.code) ?? p.code, name: p.name }));
|
|
318
|
-
const nameOf = (code: string) => options.find((p) => p.code === code)?.name ?? code;
|
|
319
|
-
// An account on a plan the catalogue no longer lists still opens on it.
|
|
320
|
-
if (current && !options.some((p) => p.code === current)) options.unshift({ code: current, name: current });
|
|
321
|
-
const unchanged = plan === "" || (plan === current && !until);
|
|
322
|
-
// A company has no address: the dialog says its name in the address's place.
|
|
323
|
-
const who = { ...target, email: target.email || personLabel(target, locale) };
|
|
324
|
-
// The column's shape in the column's sentence; the app's own sentence as it is.
|
|
325
|
-
const usageLine: ReactNode | undefined = isPlanUsage(usage)
|
|
326
|
-
? usage.limit === null
|
|
327
|
-
? undefined
|
|
328
|
-
: usageSentence({ ...usage, limit: usage.limit }, labels.usageOf, locale)
|
|
329
|
-
: usage;
|
|
330
|
-
|
|
331
|
-
return (
|
|
332
|
-
<AdminActionConfirm
|
|
333
|
-
level="acknowledge"
|
|
334
|
-
tone="warning"
|
|
335
|
-
target={who}
|
|
336
|
-
title={labels.title}
|
|
337
|
-
confirmLabel={labels.confirm}
|
|
338
|
-
confirmDisabledReason={unchanged ? labels.needsChange : undefined}
|
|
339
|
-
describeError={describeError}
|
|
340
|
-
commit={COMMIT_EXCEPT_BILLING}
|
|
341
|
-
onConfirm={(values) => onConfirm({ plan, ...(until ? { comped_until: endOfDay(until) } : {}) }, values)}
|
|
342
|
-
onClose={onClose}
|
|
343
|
-
>
|
|
344
|
-
{(current !== null || usageLine !== undefined) && (
|
|
345
|
-
<div className="space-y-0.5 text-xs text-muted" data-plan-current={current ?? undefined}>
|
|
346
|
-
{current !== null && <p>{labels.current(nameOf(current))}</p>}
|
|
347
|
-
{usageLine !== undefined && <p>{usageLine}</p>}
|
|
348
|
-
</div>
|
|
349
|
-
)}
|
|
350
|
-
<Select label={labels.plan} hint={labels.keepsItems} value={plan} onChange={(e) => setPlan(e.target.value)}>
|
|
351
|
-
{plan === "" && (
|
|
352
|
-
<option value="" disabled>
|
|
353
|
-
{EMPTY_FORMATTED_VALUE}
|
|
354
|
-
</option>
|
|
355
|
-
)}
|
|
356
|
-
{options.map((option) => (
|
|
357
|
-
<option key={option.code} value={option.code}>
|
|
358
|
-
{option.name}
|
|
359
|
-
</option>
|
|
360
|
-
))}
|
|
361
|
-
</Select>
|
|
362
|
-
{grantEnd && (
|
|
363
|
-
<DatePicker
|
|
364
|
-
label={labels.until}
|
|
365
|
-
hint={labels.untilHint}
|
|
366
|
-
value={until}
|
|
367
|
-
onChange={setUntil}
|
|
368
|
-
min={today}
|
|
369
|
-
clearable
|
|
370
|
-
/>
|
|
371
|
-
)}
|
|
372
|
-
</AdminActionConfirm>
|
|
373
|
-
);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/* ── The answer ────────────────────────────────────────────────────────────── */
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* A `PlanChangeResponse` as the page reads it — server-kit 0.7's (§14.12), which gained
|
|
380
|
-
* `previous_plan` nullable, `usage`, `kept_beta` and `comped_until`.
|
|
381
|
-
*/
|
|
382
|
-
export interface PlanChangeOutcome {
|
|
383
|
-
/** null: the account had no subscription. */
|
|
384
|
-
previous_plan: string | null;
|
|
385
|
-
plan: string;
|
|
386
|
-
over_limit: boolean;
|
|
387
|
-
/** The new plan's limits; null for unlimited. */
|
|
388
|
-
limits: Readonly<Record<string, number | null>>;
|
|
389
|
-
/** What the payer has, per dimension — the figures for the over-limit lines:
|
|
390
|
-
* `{ budgets: 7 }`. */
|
|
391
|
-
usage: Readonly<Record<string, number>>;
|
|
392
|
-
/** A running beta kept its own end (§12.34). */
|
|
393
|
-
kept_beta?: boolean;
|
|
394
|
-
/** The grant's end as the change wrote it; null: no end, or no grant. */
|
|
395
|
-
comped_until?: string | null;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
/** A line's tone: the app's toast kind. */
|
|
399
|
-
export type PlanChangeTone = "success" | "info" | "warning";
|
|
400
|
-
|
|
401
|
-
export interface PlanChangeLine {
|
|
402
|
-
tone: PlanChangeTone;
|
|
403
|
-
text: string;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
export interface PlanChangeResultOptions {
|
|
407
|
-
/** The app's word per dimension, for the over-limit figures: `{ budgets: "Budgets" }`.
|
|
408
|
-
* A dimension without one is named by its key. */
|
|
409
|
-
dimensionLabels?: Readonly<Record<string, string>>;
|
|
410
|
-
/** How a figure is written. Default: a number in the kit's locale. */
|
|
411
|
-
formatValue?: (dimension: string, value: number) => string;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* The lines for a plan change's answer, each with its tone, for the app's toasts —
|
|
416
|
-
* echoing the SERVER's before and after, not what was picked: a toast that reported the
|
|
417
|
-
* request would say "done" to a write that landed differently (keksdose's rule).
|
|
418
|
-
*
|
|
419
|
-
* const lines = usePlanChangeResult();
|
|
420
|
-
* for (const line of lines(res, planName)) toast[line.tone](line.text);
|
|
421
|
-
*
|
|
422
|
-
* - `changed(from, to)`, or `set(to)` with no previous plan (or the same one): success;
|
|
423
|
-
* - a running beta that kept its end: `keptBeta`, info; else a grant's end:
|
|
424
|
-
* `untilDone(date)`, success;
|
|
425
|
-
* - over the new limit: `overLimit`, then one figure line per dimension over it ("Budgets:
|
|
426
|
-
* 7 of 5", `billing.limitUsageLine`), from `usage` and `limits`: warning. A `null`
|
|
427
|
-
* limit gives no figure line.
|
|
428
|
-
*/
|
|
429
|
-
export function usePlanChangeResult(): (
|
|
430
|
-
res: PlanChangeOutcome,
|
|
431
|
-
planName: (code: string) => string,
|
|
432
|
-
options?: PlanChangeResultOptions,
|
|
433
|
-
) => PlanChangeLine[] {
|
|
434
|
-
const labels = useKitLabels("planChange", DEFAULT_PLAN_CHANGE_LABELS);
|
|
435
|
-
const billing = useBillingLabels();
|
|
436
|
-
const locale = useKitLocale();
|
|
437
|
-
const dayText = useDayText();
|
|
438
|
-
return useCallback(
|
|
439
|
-
(res, planName, options = {}) => {
|
|
440
|
-
const { dimensionLabels, formatValue } = options;
|
|
441
|
-
const name = (raw: string) => planName(codeOf(raw) ?? raw);
|
|
442
|
-
const to = name(res.plan);
|
|
443
|
-
const from = codeOf(res.previous_plan);
|
|
444
|
-
const lines: PlanChangeLine[] = [
|
|
445
|
-
{
|
|
446
|
-
tone: "success",
|
|
447
|
-
text: from !== null && from !== codeOf(res.plan) ? labels.changed(name(from), to) : labels.set(to),
|
|
448
|
-
},
|
|
449
|
-
];
|
|
450
|
-
if (res.kept_beta) lines.push({ tone: "info", text: labels.keptBeta });
|
|
451
|
-
else if (res.comped_until) lines.push({ tone: "success", text: labels.untilDone(dayText(res.comped_until)) });
|
|
452
|
-
if (res.over_limit) {
|
|
453
|
-
lines.push({ tone: "warning", text: labels.overLimit });
|
|
454
|
-
const figure = (dimension: string, value: number) =>
|
|
455
|
-
formatValue ? formatValue(dimension, value) : formatNumber(value, { locale });
|
|
456
|
-
// Read defensively: an app's server from before 0.7 sent neither.
|
|
457
|
-
for (const [dimension, limit] of Object.entries(res.limits ?? {})) {
|
|
458
|
-
const used = res.usage?.[dimension];
|
|
459
|
-
if (limit === null || used === undefined || used <= limit) continue;
|
|
460
|
-
lines.push({
|
|
461
|
-
tone: "warning",
|
|
462
|
-
text: billing.limitUsageLine(
|
|
463
|
-
dimensionLabels?.[dimension] ?? dimension,
|
|
464
|
-
figure(dimension, used),
|
|
465
|
-
figure(dimension, limit),
|
|
466
|
-
),
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
return lines;
|
|
471
|
-
},
|
|
472
|
-
[labels, billing, locale, dayText],
|
|
473
|
-
);
|
|
474
|
-
}
|