@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,394 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useEffectEvent, useLayoutEffect, useRef, useSyncExternalStore } from "react";
|
|
2
|
-
|
|
3
|
-
import { toDate } from "../lib/format";
|
|
4
|
-
import type { DateInput } from "../lib/format";
|
|
5
|
-
import { readStored, removeStored, writeStored } from "../lib/safe-storage";
|
|
6
|
-
import type { PaidPrice } from "./billing-overview";
|
|
7
|
-
import type { BillingStanding } from "./billing-standing";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* "Payment processing" after the way back from a checkout (docs/billing-harmonization.md
|
|
11
|
-
* §12.21, §14.4; keksdose's `features/billing/checkout-return.ts`, made router-agnostic).
|
|
12
|
-
*
|
|
13
|
-
* The provider tells the app about a payment by WEBHOOK, and the webhook may land after
|
|
14
|
-
* the buyer is back: Cloud Run scales to zero, and a cold start can outlast the
|
|
15
|
-
* provider's redirect. Without this, someone who has just paid comes back to a page that
|
|
16
|
-
* still says their trial has ended. So the return is recognised (`?checkout=done`,
|
|
17
|
-
* `isCheckoutReturn`), the page says "your payment is being processed"
|
|
18
|
-
* (`BillingBanner kind="processing"`), and the overview is asked again every few seconds
|
|
19
|
-
* until it has moved.
|
|
20
|
-
*
|
|
21
|
-
* **"Landed" is judged against the overview at departure** ({@link checkoutFingerprint},
|
|
22
|
-
* noted by {@link noteCheckoutStarted}), not by "is it `active` yet": a trial and a beta
|
|
23
|
-
* grant can both buy, and a running free grant keeps its status whatever the provider
|
|
24
|
-
* says (§12.11) — only its period end moves — so "active" alone would wait for ever on
|
|
25
|
-
* one of them. A return with no departure on record (another tab, another device) waits
|
|
26
|
-
* for `active`. kastlan's 60-second poll for `source === "provider"` is the case this
|
|
27
|
-
* replaces: a payer who bought under a grant never matched it.
|
|
28
|
-
*
|
|
29
|
-
* **Bounded:** after `timeoutMs` (10 minutes) the device stops asking, and the page says
|
|
30
|
-
* what the overview says, whatever that is — a checkout abandoned at the provider must
|
|
31
|
-
* not leave "processing" up for good.
|
|
32
|
-
*
|
|
33
|
-
* **Remembered across the whole-page return, per payer.** The departure goes into the
|
|
34
|
-
* browser's storage through the kit's safe storage (a throwing storage — Safari's
|
|
35
|
-
* private mode — keeps it in memory for this page instead), under `storageKey`; a mark
|
|
36
|
-
* names its payer, so it never speaks for another account on a shared device. It is a
|
|
37
|
-
* browser entry on the app's origin: an app whose privacy text lists its entries names
|
|
38
|
-
* it (Kurvenschmiede passes its own key).
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
/** The overview fields a completed checkout changes (wire names, `GET /billing/overview`).
|
|
42
|
-
* Pass the overview as it came; the other fields are ignored. */
|
|
43
|
-
export type CheckoutOverview = Pick<BillingStanding, "status" | "in_good_standing"> & {
|
|
44
|
-
plan: string;
|
|
45
|
-
source: string;
|
|
46
|
-
current_period_end?: DateInput;
|
|
47
|
-
/** 0.39 (§15.2.10): what the payer pays — a plan switch moves only this under a grant,
|
|
48
|
-
* and keeps `active` without one. Left out or null: nothing paid. */
|
|
49
|
-
paid?: Pick<PaidPrice, "plan" | "interval"> | null;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/** How long a return keeps the page in "processing" before it trusts the overview. */
|
|
53
|
-
const PROCESSING_FOR = 10 * 60_000;
|
|
54
|
-
/** How often the overview is asked meanwhile. */
|
|
55
|
-
const POLL_EVERY = 4_000;
|
|
56
|
-
/** The browser entry, unless the app names its own. */
|
|
57
|
-
const STORAGE_KEY = "eifi1-billing-checkout";
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* What of the overview a completed checkout — or plan switch — changes, as one string:
|
|
61
|
-
* the plan (read without case, §12.16), the status, the source, the standing, the
|
|
62
|
-
* period's end (read as an instant, so `…Z` and `…+00:00` agree) and, since 0.39, the
|
|
63
|
-
* paid plan and period (`paid`, §15.2.10). A switch keeps `active`, and under a grant
|
|
64
|
-
* the plan too, so only `paid` shows it landed: one storage key serves the checkout and
|
|
65
|
-
* the switch.
|
|
66
|
-
*/
|
|
67
|
-
export function checkoutFingerprint(o: CheckoutOverview): string {
|
|
68
|
-
const end = toDate(o.current_period_end ?? null);
|
|
69
|
-
return [
|
|
70
|
-
String(o.plan ?? "").toLowerCase(),
|
|
71
|
-
o.status,
|
|
72
|
-
o.source,
|
|
73
|
-
String(o.in_good_standing),
|
|
74
|
-
end ? end.toISOString() : "",
|
|
75
|
-
String(o.paid?.plan ?? "").toLowerCase(),
|
|
76
|
-
o.paid?.interval ?? "",
|
|
77
|
-
].join("|");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Whether the overview `now` shows the checkout: it differs from the fingerprint taken
|
|
82
|
-
* at departure (`before`), or — with no departure on record — it is `active`.
|
|
83
|
-
*/
|
|
84
|
-
export function checkoutLanded(before: string | null, now: CheckoutOverview): boolean {
|
|
85
|
-
return before === null ? now.status === "active" : checkoutFingerprint(now) !== before;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/* ── The store: one per storage key, shared by every mounted instance ─────── */
|
|
89
|
-
|
|
90
|
-
interface PendingCheckout {
|
|
91
|
-
/** Whose checkout: a user's or a company's id, as a string. */
|
|
92
|
-
payer: string;
|
|
93
|
-
/** The overview's fingerprint at departure, or null when it was not known. */
|
|
94
|
-
before: string | null;
|
|
95
|
-
/** When the buyer came back; null while they are (or were) at the provider. */
|
|
96
|
-
returnedAt: number | null;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** One mounted hook: what the shared timers call, kept current on every render. */
|
|
100
|
-
interface Instance {
|
|
101
|
-
payer: string | null;
|
|
102
|
-
refetch: () => unknown;
|
|
103
|
-
onLanded: (() => void) | undefined;
|
|
104
|
-
timeoutMs: number;
|
|
105
|
-
pollMs: number;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
interface CheckoutStore {
|
|
109
|
-
key: string;
|
|
110
|
-
pending: PendingCheckout | null;
|
|
111
|
-
listeners: Set<() => void>;
|
|
112
|
-
/** The mounted instances, in mount order: the last is the latest. */
|
|
113
|
-
instances: Instance[];
|
|
114
|
-
poll: ReturnType<typeof setInterval> | null;
|
|
115
|
-
pollEvery: number;
|
|
116
|
-
expiry: ReturnType<typeof setTimeout> | null;
|
|
117
|
-
expiryAt: number | null;
|
|
118
|
-
/** An instance consumed the marker in this commit; the others leave it be. */
|
|
119
|
-
consuming: boolean;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** Module-level, so the banner's instance and the subscription page's share one state,
|
|
123
|
-
* one poll and one landing (keksdose mounts the hook twice, §14.4). */
|
|
124
|
-
const stores = new Map<string, CheckoutStore>();
|
|
125
|
-
|
|
126
|
-
function readPending(key: string): PendingCheckout | null {
|
|
127
|
-
const raw = readStored(key);
|
|
128
|
-
if (raw === null) return null;
|
|
129
|
-
try {
|
|
130
|
-
const value = JSON.parse(raw) as Partial<PendingCheckout> | null;
|
|
131
|
-
if (
|
|
132
|
-
value &&
|
|
133
|
-
typeof value.payer === "string" &&
|
|
134
|
-
(value.before === null || typeof value.before === "string") &&
|
|
135
|
-
(value.returnedAt === null || typeof value.returnedAt === "number")
|
|
136
|
-
) {
|
|
137
|
-
return { payer: value.payer, before: value.before, returnedAt: value.returnedAt };
|
|
138
|
-
}
|
|
139
|
-
} catch {
|
|
140
|
-
// Not ours, or damaged: as if nothing was noted.
|
|
141
|
-
}
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function storeOf(key: string): CheckoutStore {
|
|
146
|
-
let store = stores.get(key);
|
|
147
|
-
if (!store) {
|
|
148
|
-
store = {
|
|
149
|
-
key,
|
|
150
|
-
pending: readPending(key),
|
|
151
|
-
listeners: new Set(),
|
|
152
|
-
instances: [],
|
|
153
|
-
poll: null,
|
|
154
|
-
pollEvery: 0,
|
|
155
|
-
expiry: null,
|
|
156
|
-
expiryAt: null,
|
|
157
|
-
consuming: false,
|
|
158
|
-
};
|
|
159
|
-
stores.set(key, store);
|
|
160
|
-
}
|
|
161
|
-
return store;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function setPending(store: CheckoutStore, next: PendingCheckout | null): void {
|
|
165
|
-
store.pending = next;
|
|
166
|
-
if (next) writeStored(store.key, JSON.stringify(next));
|
|
167
|
-
else removeStored(store.key);
|
|
168
|
-
for (const listener of store.listeners) listener();
|
|
169
|
-
sync(store);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/** The latest mounted instance's refetch, failures swallowed: a poll that fails is
|
|
173
|
-
* simply asked again at the next tick. */
|
|
174
|
-
function refetchLatest(store: CheckoutStore): void {
|
|
175
|
-
const latest = store.instances.at(-1);
|
|
176
|
-
if (!latest) return;
|
|
177
|
-
try {
|
|
178
|
-
const result = latest.refetch() as PromiseLike<unknown> | undefined;
|
|
179
|
-
if (result && typeof result.then === "function") result.then(undefined, () => {});
|
|
180
|
-
} catch {
|
|
181
|
-
// as above
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/** Arms or stops the store's two timers — the bound and the poll — for its state. */
|
|
186
|
-
function sync(store: CheckoutStore): void {
|
|
187
|
-
const pending = store.pending;
|
|
188
|
-
const latest = store.instances.at(-1);
|
|
189
|
-
const returnedAt = pending?.returnedAt ?? null;
|
|
190
|
-
|
|
191
|
-
if (returnedAt === null) {
|
|
192
|
-
if (store.expiry) clearTimeout(store.expiry);
|
|
193
|
-
store.expiry = null;
|
|
194
|
-
store.expiryAt = null;
|
|
195
|
-
} else {
|
|
196
|
-
const at = returnedAt + (latest?.timeoutMs ?? PROCESSING_FOR);
|
|
197
|
-
if (at <= Date.now()) {
|
|
198
|
-
setPending(store, null);
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
if (store.expiryAt !== at) {
|
|
202
|
-
if (store.expiry) clearTimeout(store.expiry);
|
|
203
|
-
store.expiryAt = at;
|
|
204
|
-
store.expiry = setTimeout(() => {
|
|
205
|
-
store.expiry = null;
|
|
206
|
-
store.expiryAt = null;
|
|
207
|
-
if (store.pending === pending) setPending(store, null);
|
|
208
|
-
}, at - Date.now());
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// One poll for every instance, while a mounted one is the mark's payer.
|
|
213
|
-
const watching = returnedAt !== null && store.instances.some((i) => i.payer === pending!.payer);
|
|
214
|
-
const every = latest?.pollMs ?? POLL_EVERY;
|
|
215
|
-
if (!watching) {
|
|
216
|
-
if (store.poll) clearInterval(store.poll);
|
|
217
|
-
store.poll = null;
|
|
218
|
-
} else if (!store.poll || store.pollEvery !== every) {
|
|
219
|
-
if (store.poll) clearInterval(store.poll);
|
|
220
|
-
store.pollEvery = every;
|
|
221
|
-
store.poll = setInterval(() => refetchLatest(store), every);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/** A mounted instance joins the store's timers; the latest is the one they call. */
|
|
226
|
-
function register(store: CheckoutStore, instance: Instance): () => void {
|
|
227
|
-
store.instances.push(instance);
|
|
228
|
-
return () => {
|
|
229
|
-
store.instances = store.instances.filter((i) => i !== instance);
|
|
230
|
-
sync(store);
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Whether this instance is the one to consume a return marker: the first in a commit is.
|
|
236
|
-
* Another instance in the same commit sees the same marker and leaves it be; the claim
|
|
237
|
-
* lapses once the commit's effects have run.
|
|
238
|
-
*/
|
|
239
|
-
function claimReturn(store: CheckoutStore): boolean {
|
|
240
|
-
if (store.consuming) return false;
|
|
241
|
-
store.consuming = true;
|
|
242
|
-
void Promise.resolve().then(() => {
|
|
243
|
-
store.consuming = false;
|
|
244
|
-
});
|
|
245
|
-
return true;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Note the departure for a checkout — just before the page leaves for the provider (or
|
|
250
|
-
* for the pay page, `payPageUrl(url, locale)`):
|
|
251
|
-
*
|
|
252
|
-
* noteCheckoutStarted(user.id, overview.data);
|
|
253
|
-
* window.location.assign(payPageUrl(url, i18n.language));
|
|
254
|
-
*
|
|
255
|
-
* `payer` is the user's or the company's id: a mark never speaks for another payer.
|
|
256
|
-
* `overview` is what the page shows now; left out, the return waits for `active`. Pass
|
|
257
|
-
* the same `storageKey` as the hook's.
|
|
258
|
-
*
|
|
259
|
-
* A plan switch (0.39, §15.2.10) is waited for the same way, under the same key: note
|
|
260
|
-
* the departure before `POST /billing/plan`, and once it answers put the return marker
|
|
261
|
-
* on the page's URL yourself (`checkoutReturnUrl`'s `?checkout=done`) — the row follows
|
|
262
|
-
* by webhook, and the fingerprint's `paid` shows it landed.
|
|
263
|
-
*/
|
|
264
|
-
export function noteCheckoutStarted(
|
|
265
|
-
payer: string | number,
|
|
266
|
-
overview?: CheckoutOverview,
|
|
267
|
-
opts: { storageKey?: string } = {},
|
|
268
|
-
): void {
|
|
269
|
-
const store = storeOf(opts.storageKey ?? STORAGE_KEY);
|
|
270
|
-
setPending(store, {
|
|
271
|
-
payer: String(payer),
|
|
272
|
-
before: overview ? checkoutFingerprint(overview) : null,
|
|
273
|
-
returnedAt: null,
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
export interface CheckoutProcessingOptions {
|
|
278
|
-
/** The signed-in payer — the user's or the company's id; null while unknown (the
|
|
279
|
-
* marker then waits in the URL). */
|
|
280
|
-
payer: string | number | null;
|
|
281
|
-
/** The page was reached as the way back: `isCheckoutReturn(location.search)`. */
|
|
282
|
-
returned: boolean;
|
|
283
|
-
/** Drop the marker, with replace — `setSearchParams((p) => withoutCheckoutReturn(p),
|
|
284
|
-
* { replace: true })`. Called once per return, by the first instance that sees it. */
|
|
285
|
-
onConsumed: () => void;
|
|
286
|
-
/** The overview query's data, judged here against the departure. */
|
|
287
|
-
overview: CheckoutOverview | undefined;
|
|
288
|
-
/** The overview query's refetch: the hook polls with it — one timer for every
|
|
289
|
-
* instance, with the latest mounted one's — and "Check again" calls it. */
|
|
290
|
-
refetch: () => unknown;
|
|
291
|
-
/** Once per landing: refresh what a new standing changes — the plans, the items whose
|
|
292
|
-
* `locked` may have lifted. The overview itself is already fresh. */
|
|
293
|
-
onLanded?: () => void;
|
|
294
|
-
/** How long a return keeps "processing". Default 600 000 (10 minutes). */
|
|
295
|
-
timeoutMs?: number;
|
|
296
|
-
/** How often the overview is asked meanwhile. Default 4 000. */
|
|
297
|
-
pollMs?: number;
|
|
298
|
-
/** The browser entry. Default `"eifi1-billing-checkout"`. */
|
|
299
|
-
storageKey?: string;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Whether this payer is back from a checkout whose payment the overview has not shown
|
|
304
|
-
* yet — and the "Check again" for the banner that says so:
|
|
305
|
-
*
|
|
306
|
-
* const [params, setParams] = useSearchParams();
|
|
307
|
-
* const overview = useQuery(billingOverviewQuery);
|
|
308
|
-
* const { processing, checkAgain } = useCheckoutProcessing({
|
|
309
|
-
* payer: user?.id ?? null,
|
|
310
|
-
* returned: isCheckoutReturn(params),
|
|
311
|
-
* onConsumed: () => setParams((p) => withoutCheckoutReturn(p), { replace: true }),
|
|
312
|
-
* overview: overview.data,
|
|
313
|
-
* refetch: overview.refetch,
|
|
314
|
-
* onLanded: () => void qc.invalidateQueries({ queryKey: ["budgets"] }),
|
|
315
|
-
* });
|
|
316
|
-
* processing && <BillingBanner kind="processing" onAction={checkAgain} />
|
|
317
|
-
*
|
|
318
|
-
* The kit has no router: the app says whether the URL returned and how to drop the
|
|
319
|
-
* marker. Mount it wherever the return lands and the banner shows — every instance with
|
|
320
|
-
* the same `storageKey` shares one state: the first that sees the marker consumes it,
|
|
321
|
-
* one timer polls, and `onLanded` runs once. The app's `refetchOnWindowFocus` doesn't
|
|
322
|
-
* matter.
|
|
323
|
-
*/
|
|
324
|
-
export function useCheckoutProcessing(options: CheckoutProcessingOptions): {
|
|
325
|
-
processing: boolean;
|
|
326
|
-
checkAgain: () => void;
|
|
327
|
-
} {
|
|
328
|
-
const {
|
|
329
|
-
payer,
|
|
330
|
-
returned,
|
|
331
|
-
onConsumed,
|
|
332
|
-
overview,
|
|
333
|
-
refetch,
|
|
334
|
-
onLanded,
|
|
335
|
-
timeoutMs = PROCESSING_FOR,
|
|
336
|
-
pollMs = POLL_EVERY,
|
|
337
|
-
storageKey = STORAGE_KEY,
|
|
338
|
-
} = options;
|
|
339
|
-
const payerKey = payer === null || payer === undefined ? null : String(payer);
|
|
340
|
-
const store = storeOf(storageKey);
|
|
341
|
-
const subscribe = useCallback(
|
|
342
|
-
(notify: () => void) => {
|
|
343
|
-
store.listeners.add(notify);
|
|
344
|
-
return () => {
|
|
345
|
-
store.listeners.delete(notify);
|
|
346
|
-
};
|
|
347
|
-
},
|
|
348
|
-
[store],
|
|
349
|
-
);
|
|
350
|
-
const snapshot = () => store.pending;
|
|
351
|
-
const pending = useSyncExternalStore(subscribe, snapshot, snapshot);
|
|
352
|
-
const processing = payerKey !== null && pending?.payer === payerKey && pending.returnedAt !== null;
|
|
353
|
-
|
|
354
|
-
// This instance, as the shared timers see it. Registered before paint, so a mark that
|
|
355
|
-
// ran out while the page was closed is dropped before "processing" can flash.
|
|
356
|
-
const instanceRef = useRef<Instance>({ payer: payerKey, refetch, onLanded, timeoutMs, pollMs });
|
|
357
|
-
useLayoutEffect(() => register(store, instanceRef.current), [store]);
|
|
358
|
-
useLayoutEffect(() => {
|
|
359
|
-
Object.assign(instanceRef.current, { payer: payerKey, refetch, onLanded, timeoutMs, pollMs });
|
|
360
|
-
sync(store);
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
// The return: note it, then drop the marker so a reload does not count it twice.
|
|
364
|
-
const consumed = useEffectEvent(() => onConsumed());
|
|
365
|
-
useEffect(() => {
|
|
366
|
-
if (!returned || payerKey === null || !claimReturn(store)) return;
|
|
367
|
-
const before = store.pending?.payer === payerKey ? store.pending.before : null;
|
|
368
|
-
setPending(store, { payer: payerKey, before, returnedAt: Date.now() });
|
|
369
|
-
consumed();
|
|
370
|
-
}, [returned, payerKey, store]);
|
|
371
|
-
|
|
372
|
-
// Caught up: the overview has moved since the departure. Judged against the store as
|
|
373
|
-
// it is NOW, so a second instance in the same commit finds the mark gone.
|
|
374
|
-
useEffect(() => {
|
|
375
|
-
if (!processing || !overview) return;
|
|
376
|
-
const live = store.pending;
|
|
377
|
-
if (!live || live.payer !== payerKey || live.returnedAt === null) return;
|
|
378
|
-
if (!checkoutLanded(live.before, overview)) return;
|
|
379
|
-
setPending(store, null);
|
|
380
|
-
const latest = [...store.instances].reverse().find((i) => i.onLanded);
|
|
381
|
-
latest?.onLanded?.();
|
|
382
|
-
}, [processing, overview, payerKey, store]);
|
|
383
|
-
|
|
384
|
-
const checkAgain = useCallback(() => {
|
|
385
|
-
try {
|
|
386
|
-
const result = instanceRef.current.refetch() as PromiseLike<unknown> | undefined;
|
|
387
|
-
if (result && typeof result.then === "function") result.then(undefined, () => {});
|
|
388
|
-
} catch {
|
|
389
|
-
// The banner stays; the next poll asks again.
|
|
390
|
-
}
|
|
391
|
-
}, []);
|
|
392
|
-
|
|
393
|
-
return { processing, checkAgain };
|
|
394
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The way back from the provider's checkout (docs/billing-harmonization.md §14.4,
|
|
3
|
-
* decision 20): `?checkout=done` on the app's subscription page — kastlan's
|
|
4
|
-
* `/admin/billing`, keksdose's and Kurvenschmiede's `/settings/subscription`.
|
|
5
|
-
*
|
|
6
|
-
* The checkout request carries NO success URL: a redirect the client chooses is an open
|
|
7
|
-
* redirect, and Paddle's create-transaction takes none. The way back is configuration
|
|
8
|
-
* instead — the pay page's Paddle.js `successUrl` (`checkoutReturnUrl(returnUrl)`), or a
|
|
9
|
-
* hosted checkout's redirect in Paddle's dashboard — and the page that lands reads the
|
|
10
|
-
* marker with {@link isCheckoutReturn}, then drops it with `replace`
|
|
11
|
-
* ({@link withoutCheckoutReturn}) so a reload or a shared link does not count twice.
|
|
12
|
-
*
|
|
13
|
-
* Pure and router-agnostic, and imports nothing: the pay page (`dist/pay/`, no React)
|
|
14
|
-
* bundles this module too. server-kit names the same two values
|
|
15
|
-
* (`CHECKOUT_RETURN_PARAM`, `CHECKOUT_RETURN_VALUE`, `checkout_return_url`) for the
|
|
16
|
-
* deploy notes and its tests.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/** The query parameter of the way back. */
|
|
20
|
-
export const CHECKOUT_RETURN_PARAM = "checkout";
|
|
21
|
-
/** Its one value: the buyer came back from a completed checkout. */
|
|
22
|
-
export const CHECKOUT_RETURN_VALUE = "done";
|
|
23
|
-
|
|
24
|
-
/** The query of `where`, however the app holds it: a search string ("?a=1"), a whole
|
|
25
|
-
* URL, `URLSearchParams`, or a location (`{ search }`). */
|
|
26
|
-
function paramsOf(where: string | URLSearchParams | { search: string }): URLSearchParams {
|
|
27
|
-
if (where instanceof URLSearchParams) return where;
|
|
28
|
-
const text = typeof where === "string" ? where : where.search;
|
|
29
|
-
const query = text.includes("?") ? text.slice(text.indexOf("?") + 1) : text;
|
|
30
|
-
// A whole URL's hash is not part of its query.
|
|
31
|
-
return new URLSearchParams(query.split("#")[0]);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Whether the page was reached as the way back from a checkout: `?checkout=done`.
|
|
36
|
-
*
|
|
37
|
-
* const returned = isCheckoutReturn(location.search); // react-router's useLocation()
|
|
38
|
-
* const returned = isCheckoutReturn(searchParams); // useSearchParams()[0]
|
|
39
|
-
*/
|
|
40
|
-
export function isCheckoutReturn(where: string | URLSearchParams | { search: string }): boolean {
|
|
41
|
-
return paramsOf(where).get(CHECKOUT_RETURN_PARAM) === CHECKOUT_RETURN_VALUE;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* The same parameters without the marker — every other one kept, in order. A new
|
|
46
|
-
* object; the one passed in is not changed:
|
|
47
|
-
*
|
|
48
|
-
* setSearchParams((p) => withoutCheckoutReturn(p), { replace: true });
|
|
49
|
-
*/
|
|
50
|
-
export function withoutCheckoutReturn(params: URLSearchParams): URLSearchParams {
|
|
51
|
-
const next = new URLSearchParams(params);
|
|
52
|
-
next.delete(CHECKOUT_RETURN_PARAM);
|
|
53
|
-
return next;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* The subscription page's way-back URL: `page` with `checkout=done` in its query —
|
|
58
|
-
* after any query it already has, before its hash. A marker already there is replaced,
|
|
59
|
-
* not doubled.
|
|
60
|
-
*
|
|
61
|
-
* checkoutReturnUrl("https://keksdose.app/settings/subscription")
|
|
62
|
-
* // → "https://keksdose.app/settings/subscription?checkout=done"
|
|
63
|
-
*
|
|
64
|
-
* What the pay page hands Paddle.js as `successUrl`, and what a hosted checkout's
|
|
65
|
-
* redirect is set to in Paddle's dashboard.
|
|
66
|
-
*/
|
|
67
|
-
export function checkoutReturnUrl(page: string): string {
|
|
68
|
-
const hashAt = page.indexOf("#");
|
|
69
|
-
const hash = hashAt === -1 ? "" : page.slice(hashAt);
|
|
70
|
-
const beforeHash = hashAt === -1 ? page : page.slice(0, hashAt);
|
|
71
|
-
const queryAt = beforeHash.indexOf("?");
|
|
72
|
-
const path = queryAt === -1 ? beforeHash : beforeHash.slice(0, queryAt);
|
|
73
|
-
// Kept as written, part by part: a URLSearchParams round trip would re-encode the
|
|
74
|
-
// page's own parameters (a space as "+").
|
|
75
|
-
const kept = (queryAt === -1 ? "" : beforeHash.slice(queryAt + 1))
|
|
76
|
-
.split("&")
|
|
77
|
-
.filter((part) => part !== "" && decodeKey(part) !== CHECKOUT_RETURN_PARAM);
|
|
78
|
-
kept.push(`${CHECKOUT_RETURN_PARAM}=${CHECKOUT_RETURN_VALUE}`);
|
|
79
|
-
return `${path}?${kept.join("&")}${hash}`;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** The decoded key of one `key=value` part of a query. */
|
|
83
|
-
function decodeKey(part: string): string {
|
|
84
|
-
const key = part.split("=")[0].replace(/\+/g, " ");
|
|
85
|
-
try {
|
|
86
|
-
return decodeURIComponent(key);
|
|
87
|
-
} catch {
|
|
88
|
-
return key;
|
|
89
|
-
}
|
|
90
|
-
}
|