moonhead 1.0.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 +32 -0
- package/dist/components/layout/app-header.d.ts +1 -0
- package/dist/components/layout/app-header.js +1 -0
- package/dist/components/layout/app-sidebar.d.ts +9 -0
- package/dist/components/layout/app-sidebar.js +1 -0
- package/dist/components/layout/brand-logo.d.ts +2 -0
- package/dist/components/layout/brand-logo.js +1 -0
- package/dist/components/layout/user-menu.d.ts +6 -0
- package/dist/components/layout/user-menu.js +1 -0
- package/dist/components/ui/action-form.d.ts +10 -0
- package/dist/components/ui/action-form.js +1 -0
- package/dist/components/ui/alert-dialog.d.ts +14 -0
- package/dist/components/ui/alert-dialog.js +1 -0
- package/dist/components/ui/alert.d.ts +12 -0
- package/dist/components/ui/alert.js +1 -0
- package/dist/components/ui/avatar.d.ts +12 -0
- package/dist/components/ui/avatar.js +1 -0
- package/dist/components/ui/badge.d.ts +2 -0
- package/dist/components/ui/badge.js +1 -0
- package/dist/components/ui/button.d.ts +12 -0
- package/dist/components/ui/button.js +1 -0
- package/dist/components/ui/card.d.ts +2 -0
- package/dist/components/ui/card.js +1 -0
- package/dist/components/ui/checkbox.d.ts +5 -0
- package/dist/components/ui/checkbox.js +1 -0
- package/dist/components/ui/combobox.d.ts +18 -0
- package/dist/components/ui/combobox.js +1 -0
- package/dist/components/ui/copy-button.d.ts +8 -0
- package/dist/components/ui/copy-button.js +1 -0
- package/dist/components/ui/country-select.d.ts +12 -0
- package/dist/components/ui/country-select.js +1 -0
- package/dist/components/ui/data-table.d.ts +11 -0
- package/dist/components/ui/data-table.js +1 -0
- package/dist/components/ui/date-range-picker.d.ts +25 -0
- package/dist/components/ui/date-range-picker.js +1 -0
- package/dist/components/ui/dialog.d.ts +19 -0
- package/dist/components/ui/dialog.js +1 -0
- package/dist/components/ui/drawer.d.ts +24 -0
- package/dist/components/ui/drawer.js +1 -0
- package/dist/components/ui/dropdown-menu.d.ts +17 -0
- package/dist/components/ui/dropdown-menu.js +1 -0
- package/dist/components/ui/field.d.ts +7 -0
- package/dist/components/ui/field.js +1 -0
- package/dist/components/ui/fieldset.d.ts +4 -0
- package/dist/components/ui/fieldset.js +1 -0
- package/dist/components/ui/form-field.d.ts +17 -0
- package/dist/components/ui/form-field.js +1 -0
- package/dist/components/ui/form.d.ts +3 -0
- package/dist/components/ui/form.js +1 -0
- package/dist/components/ui/icon-tile.d.ts +5 -0
- package/dist/components/ui/icon-tile.js +1 -0
- package/dist/components/ui/identity.d.ts +6 -0
- package/dist/components/ui/identity.js +1 -0
- package/dist/components/ui/input.d.ts +4 -0
- package/dist/components/ui/input.js +1 -0
- package/dist/components/ui/number-input.d.ts +19 -0
- package/dist/components/ui/number-input.js +1 -0
- package/dist/components/ui/otp-field.d.ts +6 -0
- package/dist/components/ui/otp-field.js +1 -0
- package/dist/components/ui/page-toolbar.d.ts +9 -0
- package/dist/components/ui/page-toolbar.js +1 -0
- package/dist/components/ui/password-input.d.ts +7 -0
- package/dist/components/ui/password-input.js +1 -0
- package/dist/components/ui/radio-group.d.ts +5 -0
- package/dist/components/ui/radio-group.js +1 -0
- package/dist/components/ui/search-input.d.ts +4 -0
- package/dist/components/ui/search-input.js +1 -0
- package/dist/components/ui/section-card.d.ts +7 -0
- package/dist/components/ui/section-card.js +1 -0
- package/dist/components/ui/select-field.d.ts +19 -0
- package/dist/components/ui/select-field.js +1 -0
- package/dist/components/ui/select.d.ts +17 -0
- package/dist/components/ui/select.js +1 -0
- package/dist/components/ui/sidebar.d.ts +27 -0
- package/dist/components/ui/sidebar.js +1 -0
- package/dist/components/ui/slider.d.ts +10 -0
- package/dist/components/ui/slider.js +1 -0
- package/dist/components/ui/sort-button.d.ts +5 -0
- package/dist/components/ui/sort-button.js +1 -0
- package/dist/components/ui/spinner.d.ts +4 -0
- package/dist/components/ui/spinner.js +1 -0
- package/dist/components/ui/status-badge.d.ts +11 -0
- package/dist/components/ui/status-badge.js +1 -0
- package/dist/components/ui/switch-field.d.ts +18 -0
- package/dist/components/ui/switch-field.js +1 -0
- package/dist/components/ui/switch.d.ts +3 -0
- package/dist/components/ui/switch.js +1 -0
- package/dist/components/ui/table-pagination.d.ts +9 -0
- package/dist/components/ui/table-pagination.js +1 -0
- package/dist/components/ui/table.d.ts +18 -0
- package/dist/components/ui/table.js +1 -0
- package/dist/components/ui/tabs.d.ts +8 -0
- package/dist/components/ui/tabs.js +1 -0
- package/dist/components/ui/tag-input.d.ts +9 -0
- package/dist/components/ui/tag-input.js +1 -0
- package/dist/components/ui/text-link.d.ts +10 -0
- package/dist/components/ui/text-link.js +1 -0
- package/dist/components/ui/textarea.d.ts +2 -0
- package/dist/components/ui/textarea.js +1 -0
- package/dist/components/ui/toast.d.ts +1 -0
- package/dist/components/ui/toast.js +1 -0
- package/dist/components/ui/tree.d.ts +32 -0
- package/dist/components/ui/tree.js +1 -0
- package/dist/db/client.d.ts +8 -0
- package/dist/db/client.js +1 -0
- package/dist/db/index.d.ts +3 -0
- package/dist/db/index.js +1 -0
- package/dist/db/logger.d.ts +2 -0
- package/dist/db/logger.js +1 -0
- package/dist/db/migrations/20260628182304_wonderful_groot/migration.sql +289 -0
- package/dist/db/migrations/20260628182304_wonderful_groot/snapshot.json +3750 -0
- package/dist/db/migrations/20260630082829_wet_robin_chapel/migration.sql +2 -0
- package/dist/db/migrations/20260630082829_wet_robin_chapel/snapshot.json +3791 -0
- package/dist/db/migrations/20260702132335_wooden_iron_monger/migration.sql +48 -0
- package/dist/db/migrations/20260702132335_wooden_iron_monger/snapshot.json +4407 -0
- package/dist/db/migrations/20260702142948_vengeful_rhino/migration.sql +1 -0
- package/dist/db/migrations/20260702142948_vengeful_rhino/snapshot.json +4420 -0
- package/dist/db/migrations/20260702185813_curved_pyro/migration.sql +16 -0
- package/dist/db/migrations/20260702185813_curved_pyro/snapshot.json +4646 -0
- package/dist/db/migrations/20260702192041_shiny_franklin_storm/migration.sql +16 -0
- package/dist/db/migrations/20260702192041_shiny_franklin_storm/snapshot.json +4872 -0
- package/dist/db/migrations/20260704101548_bizarre_namorita/migration.sql +1 -0
- package/dist/db/migrations/20260704101548_bizarre_namorita/snapshot.json +4885 -0
- package/dist/db/migrations/20260704105911_sleepy_juggernaut/migration.sql +1 -0
- package/dist/db/migrations/20260704105911_sleepy_juggernaut/snapshot.json +4898 -0
- package/dist/db/migrations/20260704115959_lean_sandman/migration.sql +1 -0
- package/dist/db/migrations/20260704115959_lean_sandman/snapshot.json +4885 -0
- package/dist/db/migrations/20260707231532_daffy_captain_stacy/migration.sql +10 -0
- package/dist/db/migrations/20260707231532_daffy_captain_stacy/snapshot.json +4919 -0
- package/dist/db/migrations/20260708190355_spooky_jimmy_woo/migration.sql +3 -0
- package/dist/db/migrations/20260708190355_spooky_jimmy_woo/snapshot.json +4970 -0
- package/dist/db/migrations/20260711145212_drop_legacy_earning_status/migration.sql +7 -0
- package/dist/db/migrations/20260711145212_drop_legacy_earning_status/snapshot.json +4968 -0
- package/dist/db/migrations/20260712161249_dashboard_stat_indexes/migration.sql +3 -0
- package/dist/db/migrations/20260712161249_dashboard_stat_indexes/snapshot.json +5038 -0
- package/dist/db/migrations/20260713013911_add_payout_paid_at/migration.sql +2 -0
- package/dist/db/migrations/20260713013911_add_payout_paid_at/snapshot.json +5072 -0
- package/dist/db/schema/analytics-outbox.d.ts +145 -0
- package/dist/db/schema/analytics-outbox.js +1 -0
- package/dist/db/schema/audit-logs.d.ts +204 -0
- package/dist/db/schema/audit-logs.js +1 -0
- package/dist/db/schema/campaigns.d.ts +180 -0
- package/dist/db/schema/campaigns.js +1 -0
- package/dist/db/schema/casinos.d.ts +129 -0
- package/dist/db/schema/casinos.js +1 -0
- package/dist/db/schema/commission-rule-groups.d.ts +84 -0
- package/dist/db/schema/commission-rule-groups.js +1 -0
- package/dist/db/schema/commission-rules.d.ts +145 -0
- package/dist/db/schema/commission-rules.js +1 -0
- package/dist/db/schema/commissions.d.ts +242 -0
- package/dist/db/schema/commissions.js +1 -0
- package/dist/db/schema/conversions.d.ts +302 -0
- package/dist/db/schema/conversions.js +1 -0
- package/dist/db/schema/deals.d.ts +180 -0
- package/dist/db/schema/deals.js +1 -0
- package/dist/db/schema/earnings.d.ts +262 -0
- package/dist/db/schema/earnings.js +1 -0
- package/dist/db/schema/groups.d.ts +214 -0
- package/dist/db/schema/groups.js +1 -0
- package/dist/db/schema/index.d.ts +18 -0
- package/dist/db/schema/index.js +1 -0
- package/dist/db/schema/payouts.d.ts +182 -0
- package/dist/db/schema/payouts.js +1 -0
- package/dist/db/schema/platform-settings.d.ts +84 -0
- package/dist/db/schema/platform-settings.js +1 -0
- package/dist/db/schema/player-activity.d.ts +159 -0
- package/dist/db/schema/player-activity.js +1 -0
- package/dist/db/schema/revshare-carryover.d.ts +129 -0
- package/dist/db/schema/revshare-carryover.js +1 -0
- package/dist/db/schema/sessions.d.ts +213 -0
- package/dist/db/schema/sessions.js +1 -0
- package/dist/db/schema/table.d.ts +1 -0
- package/dist/db/schema/table.js +1 -0
- package/dist/db/schema/users.d.ts +609 -0
- package/dist/db/schema/users.js +1 -0
- package/dist/db/schema/verification-tokens.d.ts +106 -0
- package/dist/db/schema/verification-tokens.js +1 -0
- package/dist/db/types/branded.d.ts +3 -0
- package/dist/db/types/branded.js +0 -0
- package/dist/db/types/commission-rules.d.ts +70 -0
- package/dist/db/types/commission-rules.js +1 -0
- package/dist/db/types/index.d.ts +2 -0
- package/dist/db/types/index.js +1 -0
- package/dist/emails/admin/support-message.d.ts +39 -0
- package/dist/emails/admin/support-message.js +5 -0
- package/dist/emails/affiliate/activated.d.ts +33 -0
- package/dist/emails/affiliate/activated.js +1 -0
- package/dist/emails/affiliate/deal-notice.d.ts +35 -0
- package/dist/emails/affiliate/deal-notice.js +1 -0
- package/dist/emails/affiliate/invite.d.ts +35 -0
- package/dist/emails/affiliate/invite.js +1 -0
- package/dist/emails/affiliate/signup-verify.d.ts +35 -0
- package/dist/emails/affiliate/signup-verify.js +1 -0
- package/dist/emails/auth/password-reset.d.ts +37 -0
- package/dist/emails/auth/password-reset.js +1 -0
- package/dist/emails/layout.d.ts +10 -0
- package/dist/emails/layout.js +1 -0
- package/dist/emails/manager/affiliate-activated.d.ts +33 -0
- package/dist/emails/manager/affiliate-activated.js +1 -0
- package/dist/emails/manager/bulk-affiliates-activated.d.ts +33 -0
- package/dist/emails/manager/bulk-affiliates-activated.js +1 -0
- package/dist/emails/manager/invite.d.ts +35 -0
- package/dist/emails/manager/invite.js +1 -0
- package/dist/emails/manager/pending-approval.d.ts +33 -0
- package/dist/emails/manager/pending-approval.js +1 -0
- package/dist/emails/preview-env.d.ts +2 -0
- package/dist/emails/preview-env.js +1 -0
- package/dist/features/affiliates/actions.d.ts +60 -0
- package/dist/features/affiliates/actions.js +1 -0
- package/dist/features/affiliates/activation-email.d.ts +8 -0
- package/dist/features/affiliates/activation-email.js +1 -0
- package/dist/features/affiliates/bulk-approve.d.ts +2 -0
- package/dist/features/affiliates/bulk-approve.js +1 -0
- package/dist/features/affiliates/components/affiliate-actions-menu.d.ts +6 -0
- package/dist/features/affiliates/components/affiliate-actions-menu.js +1 -0
- package/dist/features/affiliates/components/affiliate-create-button.d.ts +1 -0
- package/dist/features/affiliates/components/affiliate-create-button.js +1 -0
- package/dist/features/affiliates/components/affiliate-detail-tabs.d.ts +6 -0
- package/dist/features/affiliates/components/affiliate-detail-tabs.js +1 -0
- package/dist/features/affiliates/components/affiliate-dialog.d.ts +11 -0
- package/dist/features/affiliates/components/affiliate-dialog.js +1 -0
- package/dist/features/affiliates/components/affiliate-profile-fields.d.ts +6 -0
- package/dist/features/affiliates/components/affiliate-profile-fields.js +1 -0
- package/dist/features/affiliates/components/affiliate-status-badge.d.ts +4 -0
- package/dist/features/affiliates/components/affiliate-status-badge.js +1 -0
- package/dist/features/affiliates/components/affiliate-status-tabs.d.ts +4 -0
- package/dist/features/affiliates/components/affiliate-status-tabs.js +1 -0
- package/dist/features/affiliates/components/affiliates-table.d.ts +10 -0
- package/dist/features/affiliates/components/affiliates-table.js +1 -0
- package/dist/features/affiliates/components/assign-parent-dialog.d.ts +5 -0
- package/dist/features/affiliates/components/assign-parent-dialog.js +1 -0
- package/dist/features/affiliates/components/detach-affiliate-confirm.d.ts +5 -0
- package/dist/features/affiliates/components/detach-affiliate-confirm.js +1 -0
- package/dist/features/affiliates/components/reject-affiliate-confirm.d.ts +5 -0
- package/dist/features/affiliates/components/reject-affiliate-confirm.js +1 -0
- package/dist/features/affiliates/components/sub-affiliate-invite-button.d.ts +3 -0
- package/dist/features/affiliates/components/sub-affiliate-invite-button.js +1 -0
- package/dist/features/affiliates/invite.d.ts +6 -0
- package/dist/features/affiliates/invite.js +1 -0
- package/dist/features/affiliates/list-params.d.ts +27 -0
- package/dist/features/affiliates/list-params.js +1 -0
- package/dist/features/affiliates/pending-notification.d.ts +18 -0
- package/dist/features/affiliates/pending-notification.js +1 -0
- package/dist/features/affiliates/sub-invite.d.ts +7 -0
- package/dist/features/affiliates/sub-invite.js +1 -0
- package/dist/features/audit/action-labels.d.ts +15 -0
- package/dist/features/audit/action-labels.js +1 -0
- package/dist/features/audit/components/audit-log-table.d.ts +5 -0
- package/dist/features/audit/components/audit-log-table.js +1 -0
- package/dist/features/audit/list-params.d.ts +2 -0
- package/dist/features/audit/list-params.js +1 -0
- package/dist/features/audit/read.d.ts +27 -0
- package/dist/features/audit/read.js +1 -0
- package/dist/features/auth/actions.d.ts +33 -0
- package/dist/features/auth/actions.js +1 -0
- package/dist/features/auth/authorization.d.ts +14 -0
- package/dist/features/auth/authorization.js +1 -0
- package/dist/features/auth/components/accept-invite-form.d.ts +3 -0
- package/dist/features/auth/components/accept-invite-form.js +1 -0
- package/dist/features/auth/components/forgot-password-form.d.ts +1 -0
- package/dist/features/auth/components/forgot-password-form.js +1 -0
- package/dist/features/auth/components/permissions-form.d.ts +5 -0
- package/dist/features/auth/components/permissions-form.js +1 -0
- package/dist/features/auth/components/reset-password-form.d.ts +3 -0
- package/dist/features/auth/components/reset-password-form.js +1 -0
- package/dist/features/auth/components/signin-form.d.ts +5 -0
- package/dist/features/auth/components/signin-form.js +1 -0
- package/dist/features/auth/components/signup-form.d.ts +1 -0
- package/dist/features/auth/components/signup-form.js +1 -0
- package/dist/features/auth/components/verify-email-form.d.ts +3 -0
- package/dist/features/auth/components/verify-email-form.js +1 -0
- package/dist/features/auth/password-reset.d.ts +6 -0
- package/dist/features/auth/password-reset.js +1 -0
- package/dist/features/auth/permissions.d.ts +49 -0
- package/dist/features/auth/permissions.js +1 -0
- package/dist/features/auth/require.d.ts +3 -0
- package/dist/features/auth/require.js +1 -0
- package/dist/features/auth/signup-email.d.ts +6 -0
- package/dist/features/auth/signup-email.js +1 -0
- package/dist/features/campaigns/actions.d.ts +53 -0
- package/dist/features/campaigns/actions.js +1 -0
- package/dist/features/campaigns/components/campaign-dialog.d.ts +7 -0
- package/dist/features/campaigns/components/campaign-dialog.js +1 -0
- package/dist/features/campaigns/components/campaign-row-actions.d.ts +8 -0
- package/dist/features/campaigns/components/campaign-row-actions.js +1 -0
- package/dist/features/campaigns/components/campaign-status-badge.d.ts +6 -0
- package/dist/features/campaigns/components/campaign-status-badge.js +1 -0
- package/dist/features/campaigns/components/campaign-status-tabs.d.ts +1 -0
- package/dist/features/campaigns/components/campaign-status-tabs.js +1 -0
- package/dist/features/campaigns/components/campaigns-table.d.ts +7 -0
- package/dist/features/campaigns/components/campaigns-table.js +1 -0
- package/dist/features/campaigns/components/create-campaign-button.d.ts +5 -0
- package/dist/features/campaigns/components/create-campaign-button.js +1 -0
- package/dist/features/campaigns/components/sub-id-builder.d.ts +4 -0
- package/dist/features/campaigns/components/sub-id-builder.js +1 -0
- package/dist/features/campaigns/components/tracking-link-box.d.ts +3 -0
- package/dist/features/campaigns/components/tracking-link-box.js +1 -0
- package/dist/features/campaigns/components/tracking-link-cell.d.ts +4 -0
- package/dist/features/campaigns/components/tracking-link-cell.js +1 -0
- package/dist/features/campaigns/components/tracking-link-dialog.d.ts +6 -0
- package/dist/features/campaigns/components/tracking-link-dialog.js +1 -0
- package/dist/features/campaigns/list-params.d.ts +14 -0
- package/dist/features/campaigns/list-params.js +1 -0
- package/dist/features/campaigns/tracking-url.d.ts +8 -0
- package/dist/features/campaigns/tracking-url.js +1 -0
- package/dist/features/casinos/actions.d.ts +39 -0
- package/dist/features/casinos/actions.js +1 -0
- package/dist/features/casinos/components/casino-create-button.d.ts +1 -0
- package/dist/features/casinos/components/casino-create-button.js +1 -0
- package/dist/features/casinos/components/casino-dialog.d.ts +11 -0
- package/dist/features/casinos/components/casino-dialog.js +1 -0
- package/dist/features/casinos/components/casino-form-fields.d.ts +7 -0
- package/dist/features/casinos/components/casino-form-fields.js +1 -0
- package/dist/features/casinos/components/casino-status-tabs.d.ts +1 -0
- package/dist/features/casinos/components/casino-status-tabs.js +1 -0
- package/dist/features/casinos/components/casinos-table.d.ts +6 -0
- package/dist/features/casinos/components/casinos-table.js +1 -0
- package/dist/features/casinos/components/delete-casino-confirm.d.ts +5 -0
- package/dist/features/casinos/components/delete-casino-confirm.js +1 -0
- package/dist/features/casinos/list-params.d.ts +14 -0
- package/dist/features/casinos/list-params.js +1 -0
- package/dist/features/commissions/actions.d.ts +76 -0
- package/dist/features/commissions/actions.js +1 -0
- package/dist/features/commissions/components/casino-bindings-field.d.ts +10 -0
- package/dist/features/commissions/components/casino-bindings-field.js +1 -0
- package/dist/features/commissions/components/commission-create-button.d.ts +1 -0
- package/dist/features/commissions/components/commission-create-button.js +1 -0
- package/dist/features/commissions/components/commission-detail-dialog.d.ts +5 -0
- package/dist/features/commissions/components/commission-detail-dialog.js +1 -0
- package/dist/features/commissions/components/commission-editor.d.ts +8 -0
- package/dist/features/commissions/components/commission-editor.js +1 -0
- package/dist/features/commissions/components/commission-read-view.d.ts +5 -0
- package/dist/features/commissions/components/commission-read-view.js +1 -0
- package/dist/features/commissions/components/commission-status-badge.d.ts +4 -0
- package/dist/features/commissions/components/commission-status-badge.js +1 -0
- package/dist/features/commissions/components/commission-status-tabs.d.ts +1 -0
- package/dist/features/commissions/components/commission-status-tabs.js +1 -0
- package/dist/features/commissions/components/commissions-table.d.ts +14 -0
- package/dist/features/commissions/components/commissions-table.js +1 -0
- package/dist/features/commissions/components/delete-commission-confirm.d.ts +5 -0
- package/dist/features/commissions/components/delete-commission-confirm.js +1 -0
- package/dist/features/commissions/components/duplicate-commission-dialog.d.ts +6 -0
- package/dist/features/commissions/components/duplicate-commission-dialog.js +1 -0
- package/dist/features/commissions/components/rule-editor/conditions-block.d.ts +9 -0
- package/dist/features/commissions/components/rule-editor/conditions-block.js +1 -0
- package/dist/features/commissions/components/rule-editor/modifiers-block.d.ts +9 -0
- package/dist/features/commissions/components/rule-editor/modifiers-block.js +1 -0
- package/dist/features/commissions/components/rule-editor/qualifiers-block.d.ts +9 -0
- package/dist/features/commissions/components/rule-editor/qualifiers-block.js +1 -0
- package/dist/features/commissions/components/rule-editor/reducer.d.ts +102 -0
- package/dist/features/commissions/components/rule-editor/reducer.js +1 -0
- package/dist/features/commissions/components/rule-editor/rewards-block.d.ts +9 -0
- package/dist/features/commissions/components/rule-editor/rewards-block.js +1 -0
- package/dist/features/commissions/components/rule-editor/rule-card.d.ts +10 -0
- package/dist/features/commissions/components/rule-editor/rule-card.js +1 -0
- package/dist/features/commissions/components/rule-editor/rule-editor.d.ts +7 -0
- package/dist/features/commissions/components/rule-editor/rule-editor.js +1 -0
- package/dist/features/commissions/components/rule-editor/rule-group-card.d.ts +9 -0
- package/dist/features/commissions/components/rule-editor/rule-group-card.js +1 -0
- package/dist/features/commissions/components/rule-editor/state.d.ts +21 -0
- package/dist/features/commissions/components/rule-editor/state.js +1 -0
- package/dist/features/commissions/components/rule-groups-read-view.d.ts +4 -0
- package/dist/features/commissions/components/rule-groups-read-view.js +1 -0
- package/dist/features/commissions/list-params.d.ts +14 -0
- package/dist/features/commissions/list-params.js +1 -0
- package/dist/features/commissions/rule-validation.d.ts +173 -0
- package/dist/features/commissions/rule-validation.js +1 -0
- package/dist/features/dashboard/affiliate-queries.d.ts +14 -0
- package/dist/features/dashboard/affiliate-queries.js +1 -0
- package/dist/features/dashboard/clickhouse.d.ts +3 -0
- package/dist/features/dashboard/clickhouse.js +2 -0
- package/dist/features/dashboard/components/affiliate-charts.d.ts +5 -0
- package/dist/features/dashboard/components/affiliate-charts.js +1 -0
- package/dist/features/dashboard/components/affiliate-stats.d.ts +5 -0
- package/dist/features/dashboard/components/affiliate-stats.js +1 -0
- package/dist/features/dashboard/components/charts/funnel-chart.d.ts +11 -0
- package/dist/features/dashboard/components/charts/funnel-chart.js +1 -0
- package/dist/features/dashboard/components/charts/rank-bar-chart.d.ts +10 -0
- package/dist/features/dashboard/components/charts/rank-bar-chart.js +1 -0
- package/dist/features/dashboard/components/charts/time-series-chart.d.ts +12 -0
- package/dist/features/dashboard/components/charts/time-series-chart.js +1 -0
- package/dist/features/dashboard/components/charts-grid.d.ts +8 -0
- package/dist/features/dashboard/components/charts-grid.js +1 -0
- package/dist/features/dashboard/components/dashboard-charts.d.ts +4 -0
- package/dist/features/dashboard/components/dashboard-charts.js +1 -0
- package/dist/features/dashboard/components/dashboard-period-tabs.d.ts +1 -0
- package/dist/features/dashboard/components/dashboard-period-tabs.js +1 -0
- package/dist/features/dashboard/components/money-stat-card.d.ts +6 -0
- package/dist/features/dashboard/components/money-stat-card.js +1 -0
- package/dist/features/dashboard/components/stat-card.d.ts +6 -0
- package/dist/features/dashboard/components/stat-card.js +1 -0
- package/dist/features/dashboard/components/top-affiliates.d.ts +4 -0
- package/dist/features/dashboard/components/top-affiliates.js +1 -0
- package/dist/features/dashboard/list-params.d.ts +24 -0
- package/dist/features/dashboard/list-params.js +1 -0
- package/dist/features/dashboard/queries.d.ts +63 -0
- package/dist/features/dashboard/queries.js +1 -0
- package/dist/features/dashboard/series.d.ts +32 -0
- package/dist/features/dashboard/series.js +1 -0
- package/dist/features/deals/actions.d.ts +60 -0
- package/dist/features/deals/actions.js +1 -0
- package/dist/features/deals/components/affiliate-deals.d.ts +10 -0
- package/dist/features/deals/components/affiliate-deals.js +1 -0
- package/dist/features/deals/components/assign-deal-button.d.ts +9 -0
- package/dist/features/deals/components/assign-deal-button.js +1 -0
- package/dist/features/deals/components/deal-dialog.d.ts +19 -0
- package/dist/features/deals/components/deal-dialog.js +1 -0
- package/dist/features/deals/components/deal-row-actions.d.ts +6 -0
- package/dist/features/deals/components/deal-row-actions.js +1 -0
- package/dist/features/deals/components/deal-status-badge.d.ts +10 -0
- package/dist/features/deals/components/deal-status-badge.js +1 -0
- package/dist/features/deals/components/deal-status-tabs.d.ts +1 -0
- package/dist/features/deals/components/deal-status-tabs.js +1 -0
- package/dist/features/deals/components/delegate-deal-button.d.ts +8 -0
- package/dist/features/deals/components/delegate-deal-button.js +1 -0
- package/dist/features/deals/deal-assigned-email.d.ts +11 -0
- package/dist/features/deals/deal-assigned-email.js +1 -0
- package/dist/features/deals/deal-delegated-email.d.ts +13 -0
- package/dist/features/deals/deal-delegated-email.js +1 -0
- package/dist/features/deals/list-params.d.ts +14 -0
- package/dist/features/deals/list-params.js +1 -0
- package/dist/features/earnings/components/earnings-balances.d.ts +4 -0
- package/dist/features/earnings/components/earnings-balances.js +1 -0
- package/dist/features/earnings/components/earnings-ledger.d.ts +5 -0
- package/dist/features/earnings/components/earnings-ledger.js +1 -0
- package/dist/features/earnings/components/earnings-status-badge.d.ts +4 -0
- package/dist/features/earnings/components/earnings-status-badge.js +1 -0
- package/dist/features/earnings/components/earnings-status-tabs.d.ts +1 -0
- package/dist/features/earnings/components/earnings-status-tabs.js +1 -0
- package/dist/features/earnings/components/sub-affiliate-earnings.d.ts +4 -0
- package/dist/features/earnings/components/sub-affiliate-earnings.js +1 -0
- package/dist/features/earnings/list-params.d.ts +14 -0
- package/dist/features/earnings/list-params.js +1 -0
- package/dist/features/earnings/queries.d.ts +30 -0
- package/dist/features/earnings/queries.js +1 -0
- package/dist/features/groups/actions.d.ts +36 -0
- package/dist/features/groups/actions.js +1 -0
- package/dist/features/groups/components/delete-group-confirm.d.ts +5 -0
- package/dist/features/groups/components/delete-group-confirm.js +1 -0
- package/dist/features/groups/components/group-create-button.d.ts +1 -0
- package/dist/features/groups/components/group-create-button.js +1 -0
- package/dist/features/groups/components/group-dialog.d.ts +11 -0
- package/dist/features/groups/components/group-dialog.js +1 -0
- package/dist/features/groups/components/group-form-fields.d.ts +10 -0
- package/dist/features/groups/components/group-form-fields.js +1 -0
- package/dist/features/groups/components/group-status-tabs.d.ts +1 -0
- package/dist/features/groups/components/group-status-tabs.js +1 -0
- package/dist/features/groups/components/groups-table.d.ts +9 -0
- package/dist/features/groups/components/groups-table.js +1 -0
- package/dist/features/groups/list-params.d.ts +14 -0
- package/dist/features/groups/list-params.js +1 -0
- package/dist/features/managers/actions.d.ts +43 -0
- package/dist/features/managers/actions.js +1 -0
- package/dist/features/managers/components/manager-create-button.d.ts +1 -0
- package/dist/features/managers/components/manager-create-button.js +1 -0
- package/dist/features/managers/components/manager-dialog.d.ts +11 -0
- package/dist/features/managers/components/manager-dialog.js +1 -0
- package/dist/features/managers/components/manager-permissions-dialog.d.ts +7 -0
- package/dist/features/managers/components/manager-permissions-dialog.js +1 -0
- package/dist/features/managers/components/manager-profile-fields.d.ts +7 -0
- package/dist/features/managers/components/manager-profile-fields.js +1 -0
- package/dist/features/managers/components/manager-status-tabs.d.ts +1 -0
- package/dist/features/managers/components/manager-status-tabs.js +1 -0
- package/dist/features/managers/components/managers-table.d.ts +8 -0
- package/dist/features/managers/components/managers-table.js +1 -0
- package/dist/features/managers/invite.d.ts +6 -0
- package/dist/features/managers/invite.js +1 -0
- package/dist/features/managers/list-params.d.ts +14 -0
- package/dist/features/managers/list-params.js +1 -0
- package/dist/features/payouts/actions.d.ts +12 -0
- package/dist/features/payouts/actions.js +1 -0
- package/dist/features/payouts/balance.d.ts +2 -0
- package/dist/features/payouts/balance.js +1 -0
- package/dist/features/payouts/components/my-payouts-table.d.ts +5 -0
- package/dist/features/payouts/components/my-payouts-table.js +1 -0
- package/dist/features/payouts/components/payout-row-actions.d.ts +5 -0
- package/dist/features/payouts/components/payout-row-actions.js +1 -0
- package/dist/features/payouts/components/payout-status-badge.d.ts +4 -0
- package/dist/features/payouts/components/payout-status-badge.js +1 -0
- package/dist/features/payouts/components/payout-status-tabs.d.ts +1 -0
- package/dist/features/payouts/components/payout-status-tabs.js +1 -0
- package/dist/features/payouts/components/payouts-table.d.ts +6 -0
- package/dist/features/payouts/components/payouts-table.js +1 -0
- package/dist/features/payouts/components/request-payout-dialog.d.ts +4 -0
- package/dist/features/payouts/components/request-payout-dialog.js +1 -0
- package/dist/features/payouts/constants.d.ts +2 -0
- package/dist/features/payouts/constants.js +1 -0
- package/dist/features/payouts/list-params.d.ts +14 -0
- package/dist/features/payouts/list-params.js +1 -0
- package/dist/features/payouts/my-queries.d.ts +14 -0
- package/dist/features/payouts/my-queries.js +1 -0
- package/dist/features/payouts/queries.d.ts +14 -0
- package/dist/features/payouts/queries.js +1 -0
- package/dist/features/postbacks/actions.d.ts +27 -0
- package/dist/features/postbacks/actions.js +1 -0
- package/dist/features/postbacks/components/integration-dialog.d.ts +6 -0
- package/dist/features/postbacks/components/integration-dialog.js +1 -0
- package/dist/features/postbacks/components/postback-editor.d.ts +5 -0
- package/dist/features/postbacks/components/postback-editor.js +1 -0
- package/dist/features/postbacks/components/postbacks-table.d.ts +4 -0
- package/dist/features/postbacks/components/postbacks-table.js +1 -0
- package/dist/features/settings/actions.d.ts +2 -0
- package/dist/features/settings/actions.js +1 -0
- package/dist/features/settings/components/affiliate-approval-setting.d.ts +3 -0
- package/dist/features/settings/components/affiliate-approval-setting.js +1 -0
- package/dist/features/settings/components/manager-totp-setting.d.ts +3 -0
- package/dist/features/settings/components/manager-totp-setting.js +1 -0
- package/dist/features/support/actions.d.ts +12 -0
- package/dist/features/support/actions.js +1 -0
- package/dist/features/support/components/support-page.d.ts +4 -0
- package/dist/features/support/components/support-page.js +1 -0
- package/dist/features/support/email.d.ts +13 -0
- package/dist/features/support/email.js +1 -0
- package/dist/features/users/actions.d.ts +4 -0
- package/dist/features/users/actions.js +1 -0
- package/dist/features/users/components/password-section.d.ts +1 -0
- package/dist/features/users/components/password-section.js +1 -0
- package/dist/features/users/components/preferences-section.d.ts +4 -0
- package/dist/features/users/components/preferences-section.js +1 -0
- package/dist/features/users/components/settings-tabs.d.ts +1 -0
- package/dist/features/users/components/settings-tabs.js +1 -0
- package/dist/features/users/components/totp-section.d.ts +4 -0
- package/dist/features/users/components/totp-section.js +1 -0
- package/dist/features/users/list-params.d.ts +12 -0
- package/dist/features/users/list-params.js +1 -0
- package/dist/features/users/totp.d.ts +7 -0
- package/dist/features/users/totp.js +1 -0
- package/dist/i18n/config.d.ts +5 -0
- package/dist/i18n/config.js +1 -0
- package/dist/i18n/get-locale.d.ts +3 -0
- package/dist/i18n/get-locale.js +1 -0
- package/dist/i18n/locale.d.ts +2 -0
- package/dist/i18n/locale.js +1 -0
- package/dist/lib/actions/parse-form.d.ts +3 -0
- package/dist/lib/actions/parse-form.js +1 -0
- package/dist/lib/actions/state.d.ts +22 -0
- package/dist/lib/actions/state.js +0 -0
- package/dist/lib/audit/actions.d.ts +9 -0
- package/dist/lib/audit/actions.js +1 -0
- package/dist/lib/audit/record.d.ts +4 -0
- package/dist/lib/audit/record.js +1 -0
- package/dist/lib/auth/action.d.ts +45 -0
- package/dist/lib/auth/action.js +1 -0
- package/dist/lib/auth/config.d.ts +24 -0
- package/dist/lib/auth/config.js +1 -0
- package/dist/lib/auth/jwt.d.ts +17 -0
- package/dist/lib/auth/jwt.js +1 -0
- package/dist/lib/auth/password-options.d.ts +6 -0
- package/dist/lib/auth/password-options.js +1 -0
- package/dist/lib/auth/password.d.ts +3 -0
- package/dist/lib/auth/password.js +1 -0
- package/dist/lib/auth/session.d.ts +26 -0
- package/dist/lib/auth/session.js +1 -0
- package/dist/lib/auth/tokens.d.ts +43 -0
- package/dist/lib/auth/tokens.js +1 -0
- package/dist/lib/auth/totp-challenge.d.ts +4 -0
- package/dist/lib/auth/totp-challenge.js +1 -0
- package/dist/lib/auth/totp.d.ts +7 -0
- package/dist/lib/auth/totp.js +1 -0
- package/dist/lib/auth/verification-tokens.d.ts +19 -0
- package/dist/lib/auth/verification-tokens.js +1 -0
- package/dist/lib/cn.d.ts +2 -0
- package/dist/lib/cn.js +1 -0
- package/dist/lib/countries.d.ts +18 -0
- package/dist/lib/countries.js +1 -0
- package/dist/lib/currencies.d.ts +6 -0
- package/dist/lib/currencies.js +1 -0
- package/dist/lib/data/countries-by-continent.json +257 -0
- package/dist/lib/db/errors.d.ts +4 -0
- package/dist/lib/db/errors.js +1 -0
- package/dist/lib/email/client.d.ts +6 -0
- package/dist/lib/email/client.js +1 -0
- package/dist/lib/email/env.d.ts +12 -0
- package/dist/lib/email/env.js +1 -0
- package/dist/lib/email/format.d.ts +5 -0
- package/dist/lib/email/format.js +1 -0
- package/dist/lib/email/locale.d.ts +3 -0
- package/dist/lib/email/locale.js +1 -0
- package/dist/lib/email/send.d.ts +12 -0
- package/dist/lib/email/send.js +1 -0
- package/dist/lib/env.d.ts +20 -0
- package/dist/lib/env.js +1 -0
- package/dist/lib/errors/codes.d.ts +72 -0
- package/dist/lib/errors/codes.js +1 -0
- package/dist/lib/errors/server.d.ts +10 -0
- package/dist/lib/errors/server.js +1 -0
- package/dist/lib/format.d.ts +3 -0
- package/dist/lib/format.js +1 -0
- package/dist/lib/hooks/use-deferred-dialog.d.ts +11 -0
- package/dist/lib/hooks/use-deferred-dialog.js +1 -0
- package/dist/lib/hooks/use-form-reset.d.ts +2 -0
- package/dist/lib/hooks/use-form-reset.js +1 -0
- package/dist/lib/hooks/use-form-toast.d.ts +2 -0
- package/dist/lib/hooks/use-form-toast.js +1 -0
- package/dist/lib/i18n/format-datetime.d.ts +1 -0
- package/dist/lib/i18n/format-datetime.js +1 -0
- package/dist/lib/i18n/relative-time.d.ts +1 -0
- package/dist/lib/i18n/relative-time.js +1 -0
- package/dist/lib/list-params.d.ts +51 -0
- package/dist/lib/list-params.js +1 -0
- package/dist/lib/money.d.ts +2 -0
- package/dist/lib/money.js +1 -0
- package/dist/lib/platform-settings.d.ts +5 -0
- package/dist/lib/platform-settings.js +1 -0
- package/dist/lib/preferences/actions.d.ts +1 -0
- package/dist/lib/preferences/actions.js +1 -0
- package/dist/lib/preferences/index.d.ts +15 -0
- package/dist/lib/preferences/index.js +1 -0
- package/dist/lib/preferences/read.d.ts +2 -0
- package/dist/lib/preferences/read.js +1 -0
- package/dist/lib/slug.d.ts +1 -0
- package/dist/lib/slug.js +1 -0
- package/dist/lib/toast.d.ts +13 -0
- package/dist/lib/toast.js +1 -0
- package/dist/lib/tracking-cache.d.ts +2 -0
- package/dist/lib/tracking-cache.js +1 -0
- package/dist/lib/users.d.ts +12 -0
- package/dist/lib/users.js +1 -0
- package/dist/lib/validation/zod.d.ts +30 -0
- package/dist/lib/validation/zod.js +1 -0
- package/dist/messages/de/emails.json +136 -0
- package/dist/messages/de/index.json +1104 -0
- package/dist/messages/en/emails.json +136 -0
- package/dist/messages/en/index.json +1104 -0
- package/dist/theme/config.d.ts +8 -0
- package/dist/theme/config.js +1 -0
- package/dist/theme/get-theme.d.ts +3 -0
- package/dist/theme/get-theme.js +1 -0
- package/dist/theme/theme.d.ts +2 -0
- package/dist/theme/theme.js +1 -0
- package/package.json +131 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type PublicUser } from "../../db/schema/index.js";
|
|
2
|
+
import type { AffiliateSortKey, AffiliateStatusFilter } from "./list-params.js";
|
|
3
|
+
import type { FormState } from "../../lib/actions/state.js";
|
|
4
|
+
import { type ListParams, type ListResult } from "../../lib/list-params.js";
|
|
5
|
+
export type CreateAffiliateState = FormState<{
|
|
6
|
+
id: string;
|
|
7
|
+
}>;
|
|
8
|
+
export type UpdateAffiliateProfileState = FormState;
|
|
9
|
+
export type AffiliateParent = {
|
|
10
|
+
id: string;
|
|
11
|
+
firstName: string;
|
|
12
|
+
lastName: string;
|
|
13
|
+
email: string;
|
|
14
|
+
};
|
|
15
|
+
export type AffiliateRow = PublicUser & {
|
|
16
|
+
parent: AffiliateParent | null;
|
|
17
|
+
};
|
|
18
|
+
export declare function listAffiliates(params: ListParams<AffiliateSortKey> & {
|
|
19
|
+
status: AffiliateStatusFilter;
|
|
20
|
+
}): Promise<ListResult<AffiliateRow>>;
|
|
21
|
+
export declare const createAffiliateAction: (args_0: FormState<{
|
|
22
|
+
id: string;
|
|
23
|
+
}>, args_1: FormData) => Promise<FormState<{
|
|
24
|
+
id: string;
|
|
25
|
+
}>>;
|
|
26
|
+
export declare const resendAffiliateInviteAction: (args_0: string) => Promise<import("../../lib/actions/state.js").ActionResult<void>>;
|
|
27
|
+
export declare const listSubAffiliatesOf: (parentId: string, params: ListParams<"createdAt" | "email" | "firstName" | "lastName">) => Promise<ListResult<AffiliateRow>>;
|
|
28
|
+
export declare const getAffiliateById: (affiliateId: string) => Promise<AffiliateRow | null>;
|
|
29
|
+
export type AffiliateEditData = {
|
|
30
|
+
email: string;
|
|
31
|
+
firstName: string;
|
|
32
|
+
lastName: string;
|
|
33
|
+
};
|
|
34
|
+
export declare const getAffiliateEditData: (affiliateId: string) => Promise<AffiliateEditData>;
|
|
35
|
+
export declare const updateAffiliateProfileAction: (args_0: string, args_1: FormState<void>, args_2: FormData) => Promise<FormState<void>>;
|
|
36
|
+
export declare const approveAffiliateAction: (args_0: string) => Promise<import("../../lib/actions/state.js").ActionResult<void>>;
|
|
37
|
+
export declare const rejectAffiliateAction: (args_0: string, args_1: FormState<void>, args_2: FormData) => Promise<FormState<void>>;
|
|
38
|
+
export declare const unrejectAffiliateAction: (args_0: string) => Promise<import("../../lib/actions/state.js").ActionResult<void>>;
|
|
39
|
+
export declare const inviteSubAffiliateAction: (args_0: FormState<{
|
|
40
|
+
id: string;
|
|
41
|
+
}>, args_1: FormData) => Promise<FormState<{
|
|
42
|
+
id: string;
|
|
43
|
+
}>>;
|
|
44
|
+
export declare const inviteSubAffiliateForAffiliateAction: (args_0: string, args_1: FormState<{
|
|
45
|
+
id: string;
|
|
46
|
+
}>, args_2: FormData) => Promise<FormState<{
|
|
47
|
+
id: string;
|
|
48
|
+
}>>;
|
|
49
|
+
export type InviteSubAffiliateState = FormState<{
|
|
50
|
+
id: string;
|
|
51
|
+
}>;
|
|
52
|
+
export type AffiliateParentOption = {
|
|
53
|
+
id: string;
|
|
54
|
+
firstName: string;
|
|
55
|
+
lastName: string;
|
|
56
|
+
email: string;
|
|
57
|
+
};
|
|
58
|
+
export declare const searchParentAffiliateOptions: (query: string, excludeId: string) => Promise<AffiliateParentOption[]>;
|
|
59
|
+
export declare const assignAffiliateParentAction: (args_0: string, args_1: string) => Promise<import("../../lib/actions/state.js").ActionResult<void>>;
|
|
60
|
+
export declare const detachAffiliateAction: (args_0: string) => Promise<import("../../lib/actions/state.js").ActionResult<void>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use server";import{db as m}from"../../db/index.js";import{campaigns as b,deals as I,displayName as O,publicUserColumns as x,SIGNUP_SOURCE as h,USER_ROLE as l,USER_STATUS as w,users as t}from"../../db/schema/index.js";import{and as N,count as E,eq as f,inArray as k,isNotNull as C,isNull as F,ne as W}from"drizzle-orm";import{alias as R}from"drizzle-orm/pg-core";import{revalidatePath as A}from"next/cache";import{sendAffiliateActivatedEmail as z}from"./activation-email.js";import{sendAffiliateInvite as D}from"./invite.js";import{notifyManagersOfActivatedAffiliate as H}from"./pending-notification.js";import{sendSubAffiliateInvite as q}from"./sub-invite.js";import{requireSession as X}from"../auth/authorization.js";import{hasPermission as Y}from"../auth/permissions.js";import{sendSignupVerificationEmail as Z}from"../auth/signup-email.js";import{parseForm as L}from"../../lib/actions/parse-form.js";import{authAction as _,authFormAction as S,authQuery as P}from"../../lib/auth/action.js";import{revokeAllSessionsForUser as tt}from"../../lib/auth/tokens.js";import{isUniqueViolation as U}from"../../lib/db/errors.js";import{appError as n}from"../../lib/errors/codes.js";import{success as d}from"../../lib/errors/server.js";import{paginate as $}from"../../lib/list-params.js";import{findUserOfRole as T,orderByUser as J,requireUserOfRole as et,userSearchFilter as B}from"../../lib/users.js";import{UserProfileSchema as K}from"../../lib/validation/zod.js";const Q=K,at=K;function it(s){switch(s){case"all":return;case"pending":return N(f(t.status,w.active),F(t.approvedAt));case"approved":return N(f(t.status,w.active),C(t.approvedAt));case"deactivated":return f(t.status,w.blocked);case"rejected":return f(t.status,w.rejected)}}function V(s){const{parentId:i,parentFirstName:a,parentLastName:e,parentEmail:r,...o}=s;return{...o,parent:i!==null?{id:i,firstName:a??"",lastName:e??"",email:r??""}:null}}async function Ft(s){const{user:i,carrier:a}=await X(),e=Y(a,"affiliates:read"),r=i.role===l.affiliate;if(!e&&!r)throw n("forbidden",{toast:!0});const o=B(s.q),c=it(s.status),[u,p]=J(s.sort,s.dir),g=e?void 0:f(t.parentAffiliateId,i.id),v=N(f(t.role,l.affiliate),g,o,c),y=R(t,"parent");return $(s,{count:async()=>{const[j]=await m.select({total:E()}).from(t).where(v);return j?.total??0},fetch:async({offset:j,limit:M})=>(await m.select({...x,parentId:y.id,parentFirstName:y.firstName,parentLastName:y.lastName,parentEmail:y.email}).from(t).leftJoin(y,f(y.id,t.parentAffiliateId)).where(v).orderBy(u,p).limit(M).offset(j)).map(V)})}const Pt=S({permission:"affiliates:manage",revalidate:["/affiliates"]},async({audit:s},i)=>{const a=await L(i,Q),[e]=await m.insert(t).values({email:a.email,firstName:a.firstName,lastName:a.lastName,role:l.affiliate,signupSource:h.admin_invite,inviteAcceptedAt:null}).returning({id:t.id,email:t.email,firstName:t.firstName}).catch(r=>{if(U(r))return[];throw r});if(!e)throw n("email_already_exists",{field:"email"});await s({action:"affiliate.create",subjectId:e.id,target:{type:"user",id:e.id,label:e.email},metadata:{signupSource:h.admin_invite}});try{return await D({userId:e.id,email:e.email,firstName:e.firstName}),d({id:e.id},"Toasts.affiliateInvited")}catch{return d({id:e.id},"Toasts.affiliateInvitedEmailFailed")}}),jt=_({permission:"affiliates:manage",revalidate:["/affiliates"]},async(s,i)=>{const a=R(t,"parent"),[e]=await m.select({id:t.id,email:t.email,firstName:t.firstName,role:t.role,status:t.status,inviteAcceptedAt:t.inviteAcceptedAt,signupSource:t.signupSource,parentFirstName:a.firstName,parentLastName:a.lastName}).from(t).leftJoin(a,f(a.id,t.parentAffiliateId)).where(f(t.id,i)).limit(1);if(!e||e.role!==l.affiliate)throw n("user_not_found",{toast:!0});if(e.inviteAcceptedAt!==null)throw n("invite_already_accepted",{toast:!0});if(e.status!==w.active)throw n("user_blocked",{toast:!0});return e.signupSource===h.self_signup?(await Z({userId:e.id,email:e.email,firstName:e.firstName}),d("Toasts.affiliateVerificationResent")):e.signupSource===h.affiliate_invite&&e.parentFirstName!==null&&e.parentLastName!==null?(await q({userId:e.id,email:e.email,firstName:e.firstName,parentName:O({firstName:e.parentFirstName,lastName:e.parentLastName})}),d("Toasts.affiliateInviteResent")):(await D({userId:e.id,email:e.email,firstName:e.firstName}),d("Toasts.affiliateInviteResent"))}),xt=P("affiliates:read",async(s,i,a)=>{const e=B(a.q),[r,o]=J(a.sort,a.dir),c=N(f(t.role,l.affiliate),f(t.parentAffiliateId,i),e);return $(a,{count:async()=>{const[u]=await m.select({total:E()}).from(t).where(c);return u?.total??0},fetch:async({offset:u,limit:p})=>(await m.select(x).from(t).where(c).orderBy(r,o).limit(p).offset(u)).map(v=>({...v,parent:null}))})}),Et=P("affiliates:read",async(s,i)=>{const a=R(t,"parent"),[e]=await m.select({...x,parentId:a.id,parentFirstName:a.firstName,parentLastName:a.lastName,parentEmail:a.email}).from(t).leftJoin(a,f(a.id,t.parentAffiliateId)).where(N(f(t.id,i),f(t.role,l.affiliate))).limit(1);return e?V(e):null}),Rt=P("affiliates:read",async(s,i)=>{const[a]=await m.select({email:t.email,firstName:t.firstName,lastName:t.lastName,role:t.role}).from(t).where(f(t.id,i)).limit(1);if(!a||a.role!==l.affiliate)throw n("user_not_found",{toast:!0});return{email:a.email,firstName:a.firstName,lastName:a.lastName}}),Lt=S({permission:"affiliates:manage",revalidate:["/affiliates"]},async({audit:s},i,a)=>{const e=await L(a,at);if(await et(i,l.affiliate),await m.update(t).set({email:e.email,firstName:e.firstName,lastName:e.lastName}).where(f(t.id,i)).catch(o=>{if(U(o))return null;throw o})===null)throw n("email_already_exists",{field:"email"});return await s({action:"affiliate.update",subjectId:i,target:{type:"user",id:i,label:e.email},metadata:{changed:["email","firstName","lastName"]}}),d("Toasts.affiliateUpdated")}),Ut=_({permission:"affiliates:manage",revalidate:["/affiliates"]},async({user:s,audit:i},a)=>{if(a===s.id)throw n("cannot_target_self",{toast:!0});const[e]=await m.update(t).set({approvedAt:new Date,approvedBy:s.id}).where(N(f(t.id,a),f(t.role,l.affiliate),f(t.status,w.active),C(t.inviteAcceptedAt),F(t.approvedAt))).returning({id:t.id,email:t.email,firstName:t.firstName,lastName:t.lastName});if(!e)throw await T(a,l.affiliate)?n("affiliate_already_approved",{toast:!0}):n("user_not_found",{toast:!0});await i({action:"affiliate.approve",subjectId:e.id,target:{type:"user",id:e.id,label:e.email}});try{await H({affiliateEmail:e.email,affiliateFirstName:e.firstName,affiliateLastName:e.lastName})}catch(r){console.error("[approveAffiliate] manager notification failed",{error:r instanceof Error?r.message:String(r),userId:e.id})}try{await z({userId:e.id,email:e.email,firstName:e.firstName})}catch(r){return console.error("[approveAffiliate] activation email failed",{error:r instanceof Error?r.message:String(r),userId:e.id}),d("Toasts.affiliateApprovedEmailFailed")}return d("Toasts.affiliateApproved")}),Tt=S({permission:"affiliates:manage",revalidate:["/affiliates"]},async({user:s,audit:i},a,e)=>{if(a===s.id)throw n("cannot_target_self",{toast:!0});const[r]=await m.update(t).set({status:w.rejected}).where(N(f(t.id,a),f(t.role,l.affiliate),f(t.status,w.active),k(t.signupSource,[h.self_signup,h.affiliate_invite]),F(t.approvedAt))).returning({id:t.id,email:t.email});if(!r)throw await T(a,l.affiliate)?n("affiliate_not_pending",{toast:!0}):n("user_not_found",{toast:!0});return await tt(r.id),await i({action:"affiliate.reject",subjectId:r.id,target:{type:"user",id:r.id,label:r.email}}),d("Toasts.affiliateRejected")}),Bt=_({permission:"affiliates:manage",revalidate:["/affiliates"]},async({user:s,audit:i},a)=>{if(a===s.id)throw n("cannot_target_self",{toast:!0});const[e]=await m.update(t).set({status:w.active}).where(N(f(t.id,a),f(t.role,l.affiliate),f(t.status,w.rejected))).returning({id:t.id,email:t.email});if(!e)throw await T(a,l.affiliate)?n("affiliate_not_rejected",{toast:!0}):n("user_not_found",{toast:!0});return await i({action:"affiliate.unreject",subjectId:e.id,target:{type:"user",id:e.id,label:e.email}}),d("Toasts.affiliateUnrejected")});async function G(s,i,a){const e=await L(a,Q),{created:r,parent:o}=await m.transaction(async u=>{const[p]=await u.select({email:t.email,firstName:t.firstName,lastName:t.lastName,role:t.role,parentAffiliateId:t.parentAffiliateId}).from(t).where(f(t.id,s)).for("update");if(!p||p.role!==l.affiliate||p.parentAffiliateId!==null)throw n("user_not_found",{toast:!0});if(e.email.toLowerCase()===p.email.toLowerCase())throw n("cannot_target_self",{field:"email"});const[g]=await u.insert(t).values({email:e.email,firstName:e.firstName,lastName:e.lastName,role:l.affiliate,signupSource:h.affiliate_invite,parentAffiliateId:s,inviteAcceptedAt:null}).returning({id:t.id,email:t.email,firstName:t.firstName}).catch(v=>{if(U(v))return[];throw v});if(!g)throw n("email_already_exists",{field:"email"});return{created:g,parent:p}});await i({action:"affiliate.sub_invite",subjectId:r.id,target:{type:"user",id:r.id,label:r.email},metadata:{signupSource:h.affiliate_invite,parentAffiliateId:s,parentEmail:o.email}});const c=O({firstName:o.firstName,lastName:o.lastName});try{return await q({userId:r.id,email:r.email,firstName:r.firstName,parentName:c}),d({id:r.id},"Toasts.subAffiliateInvited")}catch{return d({id:r.id},"Toasts.subAffiliateInvitedEmailFailed")}}const Ot=S({revalidate:["/affiliates"]},async({user:s,audit:i},a)=>{if(s.role!==l.affiliate||s.parentAffiliateId!==null)throw n("forbidden",{toast:!0});return G(s.id,i,a)}),kt=S({permission:"affiliates:manage",revalidate:["/affiliates"]},async({audit:s},i,a)=>{const e=await G(i,s,a);return A(`/affiliates/${i}`),e}),Ct=P("affiliates:read",async(s,i,a)=>m.select({id:t.id,firstName:t.firstName,lastName:t.lastName,email:t.email}).from(t).where(N(f(t.role,l.affiliate),F(t.parentAffiliateId),W(t.id,a),B(i.trim()))).orderBy(t.firstName,t.lastName).limit(20)),Dt=_({permission:"affiliates:manage",revalidate:["/affiliates"]},async({audit:s},i,a)=>{if(i===a)throw n("cannot_target_self",{toast:!0});const e=await m.transaction(async r=>{const o=await r.select({id:t.id,email:t.email,role:t.role,parentAffiliateId:t.parentAffiliateId}).from(t).where(k(t.id,[i,a])).orderBy(t.id).for("update"),c=o.find(g=>g.id===i),u=o.find(g=>g.id===a);if(!c||c.role!==l.affiliate)throw n("user_not_found",{toast:!0});if(!u||u.role!==l.affiliate||u.parentAffiliateId!==null)throw n("user_not_found",{toast:!0});const[p]=await r.select({n:E()}).from(t).where(f(t.parentAffiliateId,i));if((p?.n??0)>0)throw n("affiliate_has_sub_affiliates",{toast:!0});return await r.update(t).set({parentAffiliateId:a}).where(f(t.id,i)),await r.delete(b).where(f(b.affiliateId,i)),await r.delete(I).where(f(I.affiliateId,i)),await s({action:"affiliate.attach",subjectId:i,target:{type:"user",id:i,label:c.email},metadata:{parentAffiliateId:a,previous:c.parentAffiliateId}},r),{email:c.email,parentAffiliateId:c.parentAffiliateId}});return A(`/affiliates/${i}`),A(`/affiliates/${a}`),e.parentAffiliateId&&A(`/affiliates/${e.parentAffiliateId}`),A("/deals"),A("/campaigns"),d("Toasts.affiliateAttached")}),qt=_({permission:"affiliates:manage",revalidate:["/affiliates"]},async({audit:s},i)=>{const a=await m.transaction(async e=>{const[r]=await e.select({email:t.email,role:t.role,parentAffiliateId:t.parentAffiliateId}).from(t).where(f(t.id,i)).for("update");if(!r||r.role!==l.affiliate)throw n("user_not_found",{toast:!0});if(r.parentAffiliateId===null)throw n("affiliate_not_sub",{toast:!0});return await e.update(t).set({parentAffiliateId:null}).where(f(t.id,i)),await e.delete(b).where(f(b.affiliateId,i)),await e.delete(I).where(f(I.affiliateId,i)),await s({action:"affiliate.detach",subjectId:i,target:{type:"user",id:i,label:r.email},metadata:{previous:r.parentAffiliateId}},e),{email:r.email,parentAffiliateId:r.parentAffiliateId}});return A(`/affiliates/${i}`),A(`/affiliates/${a.parentAffiliateId}`),A("/deals"),A("/campaigns"),d("Toasts.affiliateDetached")});export{Ut as approveAffiliateAction,Dt as assignAffiliateParentAction,Pt as createAffiliateAction,qt as detachAffiliateAction,Et as getAffiliateById,Rt as getAffiliateEditData,Ot as inviteSubAffiliateAction,kt as inviteSubAffiliateForAffiliateAction,Ft as listAffiliates,xt as listSubAffiliatesOf,Tt as rejectAffiliateAction,jt as resendAffiliateInviteAction,Ct as searchParentAffiliateOptions,Bt as unrejectAffiliateAction,Lt as updateAffiliateProfileAction};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"server-only";import{getTranslations as o}from"next-intl/server";import{AffiliateActivatedEmail as s}from"../../emails/affiliate/activated.js";import{resolveUserLocale as c}from"../../lib/email/locale.js";import{sendEmail as f}from"../../lib/email/send.js";import{env as n}from"../../lib/env.js";async function b(t){const a=t.locale??await c(t.userId),[r,e]=await Promise.all([o({locale:a,namespace:"Emails.Common"}),o({locale:a,namespace:"Emails.AffiliateActivated"})]),m=new URL("/signin",n.APP_URL).toString(),l=e("greetingNamed",{name:t.firstName}),i=n.BRAND_NAME;await f({to:t.email,subject:e("subject",{brandName:i}),react:s({signinUrl:m,lang:a,strings:{preview:e("preview",{brandName:i}),heading:e("heading"),greeting:l,body:e("body"),cta:e("cta",{brandName:i}),fallback:e("fallback"),brandName:i,footerNote:r("footerNote")}})})}export{b as sendAffiliateActivatedEmail};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"server-only";import{db as i}from"../../db/index.js";import{USER_ROLE as n,USER_STATUS as c,userPreferences as t,users as a}from"../../db/schema/index.js";import{and as f,eq as l,inArray as d,isNotNull as p,isNull as u}from"drizzle-orm";import{sendAffiliateActivatedEmail as N}from"./activation-email.js";import{notifyManagersOfBulkActivatedAffiliates as A}from"./pending-notification.js";import{defaultLocale as g,locales as v}from"../../i18n/config.js";const w=v;async function O(o){const r=await i.update(a).set({approvedAt:new Date,approvedBy:o}).where(f(l(a.role,n.affiliate),l(a.status,c.active),p(a.inviteAcceptedAt),u(a.approvedAt))).returning({id:a.id,email:a.email,firstName:a.firstName,lastName:a.lastName});if(r.length===0)return;const s=await i.select({userId:t.userId,locale:t.locale}).from(t).where(d(t.userId,r.map(e=>e.id))),m=new Map(s.filter(e=>!!(e.locale&&w.includes(e.locale))).map(e=>[e.userId,e.locale]));await Promise.allSettled(r.map(e=>N({userId:e.id,email:e.email,firstName:e.firstName,locale:m.get(e.id)??g})));try{await A(r.map(e=>({email:e.email,firstName:e.firstName,lastName:e.lastName})))}catch(e){console.error("[bulkApprove] manager notification failed",{error:e instanceof Error?e.message:String(e),count:r.length})}}export{O as bulkApprovePendingAffiliates};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type PublicUser } from "../../../db/schema/index.js";
|
|
2
|
+
export declare function AffiliateActionsMenu({ affiliate, currentUserId, trigger, }: {
|
|
3
|
+
affiliate: PublicUser;
|
|
4
|
+
currentUserId: string;
|
|
5
|
+
trigger?: "icon" | "button";
|
|
6
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{Fragment as le,jsx as e,jsxs as t}from"react/jsx-runtime";import{isInvitePending as L,isSubAffiliate as _,SIGNUP_SOURCE as g,USER_STATUS as u}from"../../../db/schema/index.js";import{IconArrowBackUp as E,IconCheck as B,IconChevronDown as V,IconDots as F,IconLink as G,IconLock as X,IconLockOpen as q,IconMailForward as H,IconPencil as J,IconUnlink as K,IconX as Q}from"@tabler/icons-react";import{useTranslations as W}from"next-intl";import{useState as f,useTransition as Y}from"react";import{buttonVariants as Z}from"../../../components/ui/button.js";import{DropdownMenu as $,DropdownMenuContent as ee,DropdownMenuItem as i,DropdownMenuSeparator as ne,DropdownMenuTrigger as w}from"../../../components/ui/dropdown-menu.js";import{Spinner as b}from"../../../components/ui/spinner.js";import{approveAffiliateAction as oe,getAffiliateEditData as te,resendAffiliateInviteAction as ie,unrejectAffiliateAction as re}from"../actions.js";import{AffiliateDialog as se}from"./affiliate-dialog.js";import{AssignParentDialog as ae}from"./assign-parent-dialog.js";import{DetachAffiliateConfirm as de}from"./detach-affiliate-confirm.js";import{RejectAffiliateConfirm as ce}from"./reject-affiliate-confirm.js";import{setUserStatus as ue}from"../../users/actions.js";import{useDeferredDialog as pe}from"../../../lib/hooks/use-deferred-dialog.js";import{toastActionResult as p}from"../../../lib/toast.js";function Oe({affiliate:n,currentUserId:h,trigger:M="icon"}){const o=W("Affiliates"),l=pe(()=>te(n.id)),[C,I]=f(!1),[k,v]=f(!1),[S,D]=f(!1),[r,a]=Y();if(n.id===h)return null;const s=n.status===u.blocked,d=n.status===u.rejected,A=L(n),z=n.signupSource===g.self_signup,O=n.signupSource===g.affiliate_invite,m=!s&&!d&&!n.approvedAt,P=m&&(z||O),x=m&&!A,c=l.isLoading,j=_(n),U=()=>{const R=s?u.active:u.blocked;a(async()=>{p(await ue(n.id,R))})},N=()=>{a(async()=>{p(await ie(n.id))})},y=()=>{a(async()=>{p(await oe(n.id))})},T=()=>{a(async()=>{p(await re(n.id))})};return t(le,{children:[t($,{children:[M==="button"?t(w,{disabled:c,className:Z({variant:"secondary",size:"sm"}),children:[c?e(b,{}):null,o("manage"),e(V,{size:14,"aria-hidden":!0})]}):e(w,{"aria-label":o("rowActions"),disabled:c,className:"inline-flex size-7 cursor-pointer items-center justify-center rounded-md text-muted-foreground outline-none hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card data-popup-open:bg-accent data-popup-open:text-accent-foreground",children:c?e(b,{}):e(F,{size:16,"aria-hidden":!0})}),t(ee,{children:[x&&t(i,{onClick:y,disabled:r,children:[e(B,{size:14,"aria-hidden":!0,className:"text-muted-foreground"}),o("approve")]}),d&&t(i,{onClick:T,disabled:r,children:[e(E,{size:14,"aria-hidden":!0,className:"text-muted-foreground"}),o("unreject")]}),t(i,{onClick:l.trigger,children:[e(J,{size:14,"aria-hidden":!0,className:"text-muted-foreground"}),o("edit")]}),t(i,{onClick:()=>D(!0),children:[e(G,{size:14,"aria-hidden":!0,className:"text-muted-foreground"}),o("assignParent")]}),j&&t(i,{onClick:()=>v(!0),children:[e(K,{size:14,"aria-hidden":!0,className:"text-muted-foreground"}),o("detach")]}),A&&!d&&t(i,{onClick:N,disabled:r,children:[e(H,{size:14,"aria-hidden":!0,className:"text-muted-foreground"}),n.signupSource===g.self_signup?o("resendVerification"):o("resendInvite")]}),e(ne,{}),P&&t(i,{variant:"destructive",onClick:()=>I(!0),disabled:r,children:[e(Q,{size:14,"aria-hidden":!0}),o("reject")]}),!d&&!m&&t(i,{variant:s?"default":"destructive",onClick:U,disabled:r,children:[s?e(q,{size:14,"aria-hidden":!0}):e(X,{size:14,"aria-hidden":!0}),o(s?"activate":"deactivate")]})]})]}),e(se,{mode:"edit",affiliateId:n.id,controller:l}),e(ce,{affiliateId:n.id,open:C,onOpenChange:I}),e(ae,{affiliateId:n.id,open:S,onOpenChange:D}),e(de,{affiliateId:n.id,open:k,onOpenChange:v})]})}export{Oe as AffiliateActionsMenu};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function AffiliateCreateButton(): import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{Fragment as f,jsx as e,jsxs as t}from"react/jsx-runtime";import{IconPlus as r}from"@tabler/icons-react";import{useTranslations as n}from"next-intl";import{Button as a}from"../../../components/ui/button.js";import{Spinner as l}from"../../../components/ui/spinner.js";import{AffiliateDialog as s}from"./affiliate-dialog.js";import{useDeferredDialog as m}from"../../../lib/hooks/use-deferred-dialog.js";function A(){const o=n("Affiliates"),i=m(()=>Promise.resolve(null));return t(f,{children:[t(a,{variant:"primary",size:"sm",type:"button",onClick:i.trigger,disabled:i.isLoading,"aria-label":o("createTitle"),children:[i.isLoading?e(l,{}):e(r,{size:16,"aria-hidden":!0}),e("span",{className:"hidden sm:inline",children:o("createTitle")})]}),e(s,{mode:"create",controller:i})]})}export{A as AffiliateCreateButton};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as y}from"react/jsx-runtime";import{useTranslations as u}from"next-intl";import{useQueryStates as m}from"nuqs";import{useTransition as d}from"react";import{Tabs as p,TabsIndicator as A,TabsList as c,TabsTab as D}from"../../../components/ui/tabs.js";import{AFFILIATE_DETAIL_TABS as h,affiliateDetailTabParser as g}from"../list-params.js";function E({hideSubAffiliates:i=!1,hideDeals:t=!1,hideCampaigns:s=!1,hideActivity:f=!1}){const n=u("Affiliates.DetailTabs"),[r,l]=d(),[{tab:o},b]=m({tab:g},{shallow:!1,clearOnDefault:!0,startTransition:l}),T=h.filter(a=>!(i&&a==="subAffiliates"||t&&a==="deals"||s&&a==="campaigns"||f&&a==="activity"));return e(p,{value:o,onValueChange:a=>b({tab:a}),"data-pending":r?"":void 0,children:y(c,{children:[T.map(a=>e(D,{value:a,children:n(a)},a)),e(A,{})]})})}export{E as AffiliateDetailTabs};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type AffiliateEditData } from "../actions.js";
|
|
2
|
+
import type { DeferredDialogController } from "../../../lib/hooks/use-deferred-dialog.js";
|
|
3
|
+
export type AffiliateDialogProps = {
|
|
4
|
+
mode: "create";
|
|
5
|
+
controller: DeferredDialogController<null>;
|
|
6
|
+
} | {
|
|
7
|
+
mode: "edit";
|
|
8
|
+
affiliateId: string;
|
|
9
|
+
controller: DeferredDialogController<AffiliateEditData>;
|
|
10
|
+
};
|
|
11
|
+
export declare function AffiliateDialog(props: AffiliateDialogProps): import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as t,jsxs as c}from"react/jsx-runtime";import{useTranslations as f}from"next-intl";import{use as C,useActionState as m}from"react";import{ActionForm as P}from"../../../components/ui/action-form.js";import{Button as D}from"../../../components/ui/button.js";import{Dialog as S,DialogBody as b,DialogClose as p,DialogContent as y,DialogDescription as F,DialogFooter as O,DialogHeader as v,DialogTitle as E}from"../../../components/ui/dialog.js";import{createAffiliateAction as I,updateAffiliateProfileAction as T}from"../actions.js";import{AffiliateProfileFields as k}from"./affiliate-profile-fields.js";function j(e){const i=f("Affiliates"),o=f("Common");return t(S,{open:e.controller.open,onOpenChange:e.controller.setOpen,disablePointerDismissal:!0,children:c(y,{closeLabel:o("close"),children:[c(v,{children:[t(E,{children:e.mode==="create"?i("createDialogTitle"):i("editDialogTitle")}),t(F,{children:e.mode==="create"?i("createDialogDesc"):i("editDialogDesc")})]}),e.mode==="create"?t(B,{onSuccess:()=>e.controller.setOpen(!1)}):e.controller.promise&&t(L,{affiliateId:e.affiliateId,dataPromise:e.controller.promise,onSuccess:()=>e.controller.setOpen(!1)},e.affiliateId)]})})}function B({onSuccess:e}){const i=f("Common"),[o,l,a]=m(async(n,r)=>{const s=await I(n,r);return s?.ok&&e(),s},void 0);return t(u,{action:l,state:o,isPending:a,submitLabel:i(a?"creating":"create"),resetOnSuccess:!0})}function L({affiliateId:e,dataPromise:i,onSuccess:o}){const l=C(i),a=f("Affiliates"),[n,r,s]=m(async(g,A)=>{const d=await T(e,g,A);return d?.ok&&o(),d},void 0);return t(u,{action:r,state:n,isPending:s,submitLabel:a(s?"saving":"save"),defaults:l})}function u({action:e,state:i,isPending:o,submitLabel:l,resetOnSuccess:a=!1,defaults:n}){const r=f("Common");return c(P,{action:e,actionState:i,resetOnSuccess:a,className:"contents",errorClassName:"mx-6 mt-4",children:[t(b,{children:t(k,{defaults:n})}),c(O,{children:[t(p,{render:t(D,{type:"button",variant:"secondary",size:"sm"}),children:r("cancel")}),t(D,{type:"submit",size:"sm",disabled:o,children:l})]})]})}export{j as AffiliateDialog};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AffiliateEditData } from "../actions.js";
|
|
2
|
+
type Defaults = Partial<Pick<AffiliateEditData, "email" | "firstName" | "lastName">>;
|
|
3
|
+
export declare function AffiliateProfileFields({ defaults, }: {
|
|
4
|
+
defaults?: Defaults;
|
|
5
|
+
}): import("react").JSX.Element;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as m}from"react/jsx-runtime";import{useTranslations as o}from"next-intl";import{FormField as i}from"../../../components/ui/form-field.js";import{Input as l}from"../../../components/ui/input.js";function u({defaults:a={}}){const t=o();return m("div",{className:"flex flex-col gap-4",children:[e(i,{name:"email",label:t("Common.email"),children:e(l,{name:"email",type:"email","aria-required":"true",autoComplete:"off",defaultValue:a.email??""})}),m("div",{className:"grid gap-4 sm:grid-cols-2",children:[e(i,{name:"firstName",label:t("Common.firstName"),children:e(l,{name:"firstName",type:"text","aria-required":"true",autoComplete:"off",defaultValue:a.firstName??""})}),e(i,{name:"lastName",label:t("Common.lastName"),children:e(l,{name:"lastName",type:"text","aria-required":"true",autoComplete:"off",defaultValue:a.lastName??""})})]})]})}export{u as AffiliateProfileFields};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as s}from"react/jsx-runtime";import{isInvitePending as r,SIGNUP_SOURCE as u,USER_STATUS as a}from"../../../db/schema/index.js";import{useTranslations as i}from"next-intl";import{StatusBadge as e}from"../../../components/ui/status-badge.js";function S({affiliate:n}){const t=i("Affiliates");return n.status===a.rejected?s(e,{tone:"danger",children:t("statusRejected")}):n.status===a.blocked?s(e,{tone:"danger",children:t("statusDeactivated")}):r(n)?n.signupSource===u.self_signup?s(e,{tone:"warning",children:t("statusEmailNotVerified")}):s(e,{tone:"warning",children:t("statusPending")}):n.approvedAt?s(e,{tone:"success",children:t("statusActive")}):s(e,{tone:"warning",children:t("statusPendingApproval")})}export{S as AffiliateStatusBadge};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as a,jsxs as S}from"react/jsx-runtime";import{useTranslations as f}from"next-intl";import{useQueryStates as l}from"nuqs";import{useTransition as u}from"react";import{Tabs as T,TabsIndicator as m,TabsList as p,TabsTab as b}from"../../../components/ui/tabs.js";import{affiliateStatusParser as c}from"../list-params.js";import{listSearchParsers as d}from"../../../lib/list-params.js";function L({statuses:s}){const e=f("Affiliates.Tabs"),[i,r]=u(),[{status:n},o]=l({status:c,page:d.page},{shallow:!1,clearOnDefault:!0,startTransition:r});return a(T,{value:n,onValueChange:t=>o({status:t,page:null}),"data-pending":i?"":void 0,children:S(p,{children:[s.map(t=>a(b,{value:t,children:e(t)},t)),a(m,{})]})})}export{L as AffiliateStatusTabs};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AffiliateRow } from "../actions.js";
|
|
2
|
+
import { type ListResult } from "../../../lib/list-params.js";
|
|
3
|
+
export declare function AffiliatesTable({ result, canManage, canViewDetail, showParent, currentUserId, now, }: {
|
|
4
|
+
result: ListResult<AffiliateRow>;
|
|
5
|
+
canManage: boolean;
|
|
6
|
+
canViewDetail: boolean;
|
|
7
|
+
showParent: boolean;
|
|
8
|
+
currentUserId: string;
|
|
9
|
+
now: Date;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as P}from"react/jsx-runtime";import{displayName as d}from"../../../db/schema/index.js";import{IconUserOff as h}from"@tabler/icons-react";import{useLocale as N,useTranslations as v}from"next-intl";import{useMemo as b}from"react";import{Avatar as S}from"../../../components/ui/avatar.js";import{DataTable as T}from"../../../components/ui/data-table.js";import{Identity as R}from"../../../components/ui/identity.js";import{SortButton as g}from"../../../components/ui/sort-button.js";import{TablePagination as D}from"../../../components/ui/table-pagination.js";import{TextLink as x}from"../../../components/ui/text-link.js";import{AffiliateActionsMenu as I}from"./affiliate-actions-menu.js";import{AffiliateStatusBadge as w}from"./affiliate-status-badge.js";import{useFormatDateTime as z}from"../../../lib/i18n/format-datetime.js";import{formatRelative as B}from"../../../lib/i18n/relative-time.js";import{PAGE_SIZE_OPTIONS as L}from"../../../lib/list-params.js";function K({result:n,canManage:s,canViewDetail:l,showParent:m,currentUserId:f,now:p}){const i=v("Affiliates"),c=N(),u=z(),y=b(()=>{const o=[{id:"email",header:()=>e(g,{column:"email",children:i("columnEmail")}),cell:({row:a})=>{const t=a.original,r=d(t),A=r!==t.email;return e(R,{visual:e(S,{seed:t.email,name:r,size:"lg"}),primary:l?e(x,{href:`/affiliates/${t.id}`,tone:"plain",children:r}):e("span",{children:r}),secondary:A&&e("span",{className:"font-mono",children:t.email})})}},{id:"status",header:()=>i("columnStatus"),cell:({row:a})=>e(w,{affiliate:a.original})}];return m&&o.push({id:"invitedBy",header:()=>i("columnInvitedBy"),cell:({row:a})=>{const t=a.original.parent;return t?e(x,{href:`/affiliates/${t.id}`,tone:"plain",className:"text-sm text-foreground",children:d(t)}):e("span",{className:"text-xs text-muted-foreground",children:"-"})}}),o.push({id:"createdAt",header:()=>e(g,{column:"createdAt",children:i("columnCreated")}),cell:({row:a})=>{const t=a.original.createdAt;return e("span",{className:"text-sm text-muted-foreground tabular-nums",title:u(t),children:B(c,t,p)})}}),s&&o.push({id:"actions",header:()=>e("span",{className:"sr-only",children:i("columnActions")}),cell:({row:a})=>e("div",{className:"flex justify-end",children:e(I,{affiliate:a.original,currentUserId:f})}),meta:{pin:"right",className:"text-right"}}),o},[i,c,u,s,l,m,f,p]);return e(T,{data:n.rows,columns:y,getRowId:o=>o.id,empty:P("div",{className:"flex flex-col items-center gap-3 py-4",children:[e("div",{className:"flex size-10 items-center justify-center rounded-full bg-muted text-muted-foreground",children:e(h,{size:18,"aria-hidden":!0})}),e("span",{children:i("empty")})]}),pagination:e(D,{page:n.page,pageSize:n.pageSize,totalPages:n.totalPages,pageSizeOptions:L})})}export{K as AffiliatesTable};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as i}from"react/jsx-runtime";import{useTranslations as c}from"next-intl";import{useState as b,useTransition as C}from"react";import{Button as p}from"../../../components/ui/button.js";import{Combobox as h}from"../../../components/ui/combobox.js";import{Dialog as P,DialogBody as x,DialogClose as y,DialogContent as v,DialogDescription as T,DialogFooter as A,DialogHeader as F,DialogTitle as N}from"../../../components/ui/dialog.js";import{FormField as w}from"../../../components/ui/form-field.js";import{assignAffiliateParentAction as B,searchParentAffiliateOptions as O}from"../actions.js";import{toastActionResult as I}from"../../../lib/toast.js";function E({affiliateId:r,open:d,onOpenChange:f}){const o=c("Affiliates"),l=c("Common"),[n,m]=b(null),[s,u]=C(),g=a=>{a||m(null),f(a)},D=()=>{n&&u(async()=>{const a=await B(r,n.value);I(a),a.ok&&g(!1)})};return e(P,{open:d,onOpenChange:g,disablePointerDismissal:!0,children:i(v,{closeLabel:l("close"),children:[i(F,{children:[e(N,{children:o("assignParentTitle")}),e(T,{children:o("assignParentDesc")})]}),e(x,{children:i("div",{className:"flex flex-col gap-4",children:[e(w,{name:"parentId",label:o("parentLabel"),nativeLabel:!1,children:e(h,{value:n,onChange:m,onSearch:async a=>(await O(a,r)).map(t=>({value:t.id,label:`${t.firstName} ${t.lastName}`,description:t.email})),placeholder:o("parentPlaceholder"),searchPlaceholder:o("parentSearchPlaceholder"),emptyText:o("parentNoResults"),loadingText:l("loading")})}),e("p",{className:"text-xs text-muted-foreground",children:o("assignParentWarning")})]})}),i(A,{children:[e(y,{render:e(p,{type:"button",variant:"secondary",size:"sm",disabled:s}),children:l("cancel")}),e(p,{type:"button",size:"sm",onClick:D,disabled:s||!n,children:o(s?"assigning":"assignParentConfirm")})]})]})})}export{E as AssignParentDialog};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as t,jsxs as r}from"react/jsx-runtime";import{useTranslations as a}from"next-intl";import{useActionState as d,useEffect as p}from"react";import{ActionForm as D}from"../../../components/ui/action-form.js";import{AlertDialog as g,AlertDialogClose as u,AlertDialogContent as b,AlertDialogDescription as C,AlertDialogFooter as h,AlertDialogTitle as v}from"../../../components/ui/alert-dialog.js";import{Button as l}from"../../../components/ui/button.js";import{detachAffiliateAction as F}from"../actions.js";function k({affiliateId:c,open:s,onOpenChange:e}){const o=a("Affiliates"),f=a("Common"),m=F.bind(null,c),[i,A,n]=d(m,void 0);return p(()=>{i?.ok&&e(!1)},[i,e]),t(g,{open:s,onOpenChange:e,children:r(b,{children:[t(v,{children:o("detachConfirm")}),t(C,{children:o("detachDescription")}),t(D,{action:A,actionState:i,className:"flex flex-col gap-3",children:r(h,{children:[t(u,{render:t(l,{type:"button",variant:"secondary",size:"sm",disabled:n,children:f("cancel")})}),t(l,{type:"submit",variant:"destructive",size:"sm",disabled:n,children:o(n?"detaching":"confirmDetach")})]})})]})})}export{k as DetachAffiliateConfirm};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as t,jsxs as a}from"react/jsx-runtime";import{useTranslations as r}from"next-intl";import{useActionState as p,useEffect as g}from"react";import{ActionForm as D}from"../../../components/ui/action-form.js";import{AlertDialog as u,AlertDialogClose as d,AlertDialogContent as b,AlertDialogDescription as C,AlertDialogFooter as j,AlertDialogTitle as v}from"../../../components/ui/alert-dialog.js";import{Button as l}from"../../../components/ui/button.js";import{rejectAffiliateAction as F}from"../actions.js";function S({affiliateId:c,open:s,onOpenChange:e}){const o=r("Affiliates"),f=r("Common"),m=F.bind(null,c),[i,A,n]=p(m,void 0);return g(()=>{i?.ok&&e(!1)},[i,e]),t(u,{open:s,onOpenChange:e,children:a(b,{children:[t(v,{children:o("rejectConfirm")}),t(C,{children:o("rejectDescription")}),t(D,{action:A,actionState:i,className:"flex flex-col gap-3",children:a(j,{children:[t(d,{render:t(l,{type:"button",variant:"secondary",size:"sm",disabled:n,children:f("cancel")})}),t(l,{type:"submit",variant:"destructive",size:"sm",disabled:n,children:o(n?"rejecting":"confirmReject")})]})})]})})}export{S as RejectAffiliateConfirm};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{Fragment as h,jsx as i,jsxs as t}from"react/jsx-runtime";import{IconUserPlus as D}from"@tabler/icons-react";import{useTranslations as s}from"next-intl";import{useActionState as p,useState as d}from"react";import{ActionForm as A}from"../../../components/ui/action-form.js";import{Button as r}from"../../../components/ui/button.js";import{Dialog as S,DialogBody as b,DialogClose as v,DialogContent as C,DialogDescription as y,DialogFooter as F,DialogHeader as I,DialogTitle as B}from"../../../components/ui/dialog.js";import{inviteSubAffiliateAction as T,inviteSubAffiliateForAffiliateAction as z}from"../actions.js";import{AffiliateProfileFields as P}from"./affiliate-profile-fields.js";function E({parentAffiliateId:n}={}){const o=s("Affiliates"),l=s("Common"),[a,e]=d(!1);return t(h,{children:[t(r,{variant:"primary",size:"sm",type:"button",onClick:()=>e(!0),children:[i(D,{size:16,"aria-hidden":!0}),o("inviteSubTitle")]}),i(S,{open:a,onOpenChange:e,disablePointerDismissal:!0,children:t(C,{closeLabel:l("close"),children:[t(I,{children:[i(B,{children:o("inviteSubDialogTitle")}),i(y,{children:o("inviteSubDialogDesc")})]}),i(O,{parentAffiliateId:n,onSuccess:()=>e(!1)})]})})]})}function O({parentAffiliateId:n,onSuccess:o}){const l=s("Common"),a=s("Affiliates"),[e,g,f]=p(async(m,c)=>{const u=n?await z(n,m,c):await T(m,c);return u?.ok&&o(),u},void 0);return t(A,{action:g,actionState:e,resetOnSuccess:!0,className:"contents",errorClassName:"mx-6 mt-4",children:[i(b,{children:i(P,{})}),t(F,{children:[i(v,{render:i(r,{type:"button",variant:"secondary",size:"sm"}),children:l("cancel")}),i(r,{type:"submit",size:"sm",disabled:f,children:a(f?"inviting":"invite")})]})]})}export{E as SubAffiliateInviteButton};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"server-only";import{getFormatter as p,getLocale as g,getTranslations as r}from"next-intl/server";import{AffiliateInviteEmail as d}from"../../emails/affiliate/invite.js";import{issueVerificationToken as v}from"../../lib/auth/verification-tokens.js";import{formatTokenExpiry as A}from"../../lib/email/format.js";import{sendEmail as u}from"../../lib/email/send.js";import{env as n}from"../../lib/env.js";async function y(o){const a=await v({userId:o.userId,purpose:"invite"}),t=await g(),[s,e,m]=await Promise.all([r({locale:t,namespace:"Emails.Common"}),r({locale:t,namespace:"Emails.AffiliateInvite"}),p({locale:t})]),c=new URL(`/accept-invite/${a.raw}`,n.APP_URL).toString(),f=A(a.expiresAt,m),l=e("greetingNamed",{name:o.firstName}),i=n.BRAND_NAME;await u({to:o.email,subject:e("subject",{brandName:i}),react:d({inviteUrl:c,lang:t,strings:{preview:e("preview",{brandName:i}),heading:e("heading"),greeting:l,body:e("body",{brandName:i}),cta:e("cta"),expiresAtMessage:e("expiresAt",{date:f}),fallback:e("fallback"),brandName:i,footerNote:s("footerNote")}})})}export{y as sendAffiliateInvite};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const AFFILIATE_SORT_KEYS: readonly ["email", "firstName", "lastName", "createdAt"];
|
|
2
|
+
export type AffiliateSortKey = (typeof AFFILIATE_SORT_KEYS)[number];
|
|
3
|
+
export declare const AFFILIATE_STATUSES: readonly ["all", "pending", "approved", "deactivated", "rejected"];
|
|
4
|
+
export type AffiliateStatusFilter = (typeof AFFILIATE_STATUSES)[number];
|
|
5
|
+
export declare const AFFILIATE_STATUSES_NO_APPROVAL: readonly ["all", "deactivated"];
|
|
6
|
+
export declare const affiliateStatusParser: Omit<import("nuqs/server").SingleParserBuilder<"rejected" | "deactivated" | "pending" | "approved" | "all">, "parseServerSide"> & {
|
|
7
|
+
readonly defaultValue: NonNullable<"rejected" | "deactivated" | "pending" | "approved" | "all">;
|
|
8
|
+
parseServerSide(value: string | string[] | undefined): NonNullable<"rejected" | "deactivated" | "pending" | "approved" | "all">;
|
|
9
|
+
};
|
|
10
|
+
export declare const loadAffiliateStatus: import("nuqs/server").LoaderFunction<{
|
|
11
|
+
status: Omit<import("nuqs/server").SingleParserBuilder<"rejected" | "deactivated" | "pending" | "approved" | "all">, "parseServerSide"> & {
|
|
12
|
+
readonly defaultValue: NonNullable<"rejected" | "deactivated" | "pending" | "approved" | "all">;
|
|
13
|
+
parseServerSide(value: string | string[] | undefined): NonNullable<"rejected" | "deactivated" | "pending" | "approved" | "all">;
|
|
14
|
+
};
|
|
15
|
+
}>;
|
|
16
|
+
export declare const AFFILIATE_DETAIL_TABS: readonly ["performance", "deals", "campaigns", "subAffiliates", "activity"];
|
|
17
|
+
export type AffiliateDetailTab = (typeof AFFILIATE_DETAIL_TABS)[number];
|
|
18
|
+
export declare const affiliateDetailTabParser: Omit<import("nuqs/server").SingleParserBuilder<"campaigns" | "deals" | "performance" | "subAffiliates" | "activity">, "parseServerSide"> & {
|
|
19
|
+
readonly defaultValue: NonNullable<"campaigns" | "deals" | "performance" | "subAffiliates" | "activity">;
|
|
20
|
+
parseServerSide(value: string | string[] | undefined): NonNullable<"campaigns" | "deals" | "performance" | "subAffiliates" | "activity">;
|
|
21
|
+
};
|
|
22
|
+
export declare const loadAffiliateDetailTab: import("nuqs/server").LoaderFunction<{
|
|
23
|
+
tab: Omit<import("nuqs/server").SingleParserBuilder<"campaigns" | "deals" | "performance" | "subAffiliates" | "activity">, "parseServerSide"> & {
|
|
24
|
+
readonly defaultValue: NonNullable<"campaigns" | "deals" | "performance" | "subAffiliates" | "activity">;
|
|
25
|
+
parseServerSide(value: string | string[] | undefined): NonNullable<"campaigns" | "deals" | "performance" | "subAffiliates" | "activity">;
|
|
26
|
+
};
|
|
27
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createLoader as t,parseAsStringLiteral as e}from"nuqs/server";const A=["email","firstName","lastName","createdAt"],a=["all","pending","approved","deactivated","rejected"],l=["all","deactivated"],i=e(a).withDefault("all"),f=t({status:i}),r=["performance","deals","campaigns","subAffiliates","activity"],o=e(r).withDefault("performance"),p=t({tab:o});export{r as AFFILIATE_DETAIL_TABS,A as AFFILIATE_SORT_KEYS,a as AFFILIATE_STATUSES,l as AFFILIATE_STATUSES_NO_APPROVAL,o as affiliateDetailTabParser,i as affiliateStatusParser,p as loadAffiliateDetailTab,f as loadAffiliateStatus};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "server-only";
|
|
2
|
+
export declare function notifyManagersOfPendingAffiliate(args: {
|
|
3
|
+
affiliateEmail: string;
|
|
4
|
+
affiliateFirstName: string;
|
|
5
|
+
affiliateLastName: string;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
export declare function notifyManagersOfActivatedAffiliate(args: {
|
|
8
|
+
affiliateEmail: string;
|
|
9
|
+
affiliateFirstName: string;
|
|
10
|
+
affiliateLastName: string;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
type BulkAffiliateInput = {
|
|
13
|
+
email: string;
|
|
14
|
+
firstName: string;
|
|
15
|
+
lastName: string;
|
|
16
|
+
};
|
|
17
|
+
export declare function notifyManagersOfBulkActivatedAffiliates(affiliates: ReadonlyArray<BulkAffiliateInput>): Promise<void>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"server-only";import{db as d}from"../../db/index.js";import{displayName as v,groupPermissions as g,USER_STATUS as E,userGroups as p,userPermissions as N,userPreferences as u,users as r}from"../../db/schema/index.js";import{and as P,eq as A,inArray as m,isNotNull as y,or as L}from"drizzle-orm";import{getTranslations as s}from"next-intl/server";import{ManagerAffiliateActivatedEmail as U}from"../../emails/manager/affiliate-activated.js";import{ManagerBulkAffiliatesActivatedEmail as R}from"../../emails/manager/bulk-affiliates-activated.js";import{AffiliatePendingApprovalEmail as h}from"../../emails/manager/pending-approval.js";import{defaultLocale as k,locales as M}from"../../i18n/config.js";import{sendEmail as w}from"../../lib/email/send.js";import{env as f}from"../../lib/env.js";const S=M;async function b(){const a=d.select({id:N.userId}).from(N).where(m(N.permission,["*","affiliates:manage"])),e=d.select({id:p.userId}).from(p).innerJoin(g,A(g.groupId,p.groupId)).where(m(g.permission,["*","affiliates:manage"]));return(await d.selectDistinct({id:r.id,email:r.email,firstName:r.firstName,lastName:r.lastName,locale:u.locale}).from(r).leftJoin(u,A(u.userId,r.id)).where(P(A(r.status,E.active),y(r.inviteAcceptedAt),L(m(r.id,a),m(r.id,e))))).map(i=>({id:i.id,email:i.email,firstName:i.firstName,lastName:i.lastName,locale:i.locale&&S.includes(i.locale)?i.locale:k}))}async function W(a){const e=await b();if(e.length===0)return;const l=new URL("/affiliates",f.APP_URL).toString(),i=v({firstName:a.affiliateFirstName,lastName:a.affiliateLastName});await Promise.allSettled(e.map(o=>B({recipient:o,affiliateEmail:a.affiliateEmail,affiliateLabel:i,reviewUrl:l})))}async function B(a){const{recipient:e,affiliateEmail:l,affiliateLabel:i,reviewUrl:o}=a,[n,t]=await Promise.all([s({locale:e.locale,namespace:"Emails.Common"}),s({locale:e.locale,namespace:"Emails.AffiliatePendingApproval"})]),c=t("greetingNamed",{name:e.firstName});await w({to:e.email,subject:t("subject"),react:h({reviewUrl:o,lang:e.locale,strings:{preview:t("preview"),heading:t("heading"),greeting:c,body:t("body",{name:i,email:l}),cta:t("cta"),fallback:t("fallback"),brandName:f.BRAND_NAME,footerNote:n("footerNote")}})})}async function z(a){const e=await b();if(e.length===0)return;const l=new URL("/affiliates",f.APP_URL).toString(),i=v({firstName:a.affiliateFirstName,lastName:a.affiliateLastName});await Promise.allSettled(e.map(o=>O({recipient:o,affiliateEmail:a.affiliateEmail,affiliateLabel:i,affiliatesUrl:l})))}async function O(a){const{recipient:e,affiliateEmail:l,affiliateLabel:i,affiliatesUrl:o}=a,[n,t]=await Promise.all([s({locale:e.locale,namespace:"Emails.Common"}),s({locale:e.locale,namespace:"Emails.ManagerAffiliateActivated"})]),c=t("greetingNamed",{name:e.firstName});await w({to:e.email,subject:t("subject"),react:U({affiliatesUrl:o,lang:e.locale,strings:{preview:t("preview"),heading:t("heading"),greeting:c,body:t("body",{name:i,email:l}),cta:t("cta"),fallback:t("fallback"),brandName:f.BRAND_NAME,footerNote:n("footerNote")}})})}async function H(a){if(a.length===0)return;const e=await b();if(e.length===0)return;const l=new URL("/affiliates",f.APP_URL).toString();await Promise.allSettled(e.map(i=>_({recipient:i,count:a.length,affiliatesUrl:l})))}async function _(a){const{recipient:e,count:l,affiliatesUrl:i}=a,[o,n]=await Promise.all([s({locale:e.locale,namespace:"Emails.Common"}),s({locale:e.locale,namespace:"Emails.ManagerBulkAffiliatesActivated"})]),t=n("greetingNamed",{name:e.firstName});await w({to:e.email,subject:n("subject",{count:l}),react:R({affiliatesUrl:i,lang:e.locale,strings:{preview:n("preview",{count:l}),heading:n("heading",{count:l}),greeting:t,body:n("body",{count:l}),cta:n("cta"),fallback:n("fallback"),brandName:f.BRAND_NAME,footerNote:o("footerNote")}})})}export{z as notifyManagersOfActivatedAffiliate,H as notifyManagersOfBulkActivatedAffiliates,W as notifyManagersOfPendingAffiliate};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"server-only";import{getFormatter as l,getLocale as N,getTranslations as n}from"next-intl/server";import{AffiliateInviteEmail as d}from"../../emails/affiliate/invite.js";import{issueVerificationToken as g}from"../../lib/auth/verification-tokens.js";import{formatTokenExpiry as v}from"../../lib/email/format.js";import{sendEmail as u}from"../../lib/email/send.js";import{env as o}from"../../lib/env.js";async function y(t){const r=await g({userId:t.userId,purpose:"invite"}),i=await N(),[m,e,s]=await Promise.all([n({locale:i,namespace:"Emails.Common"}),n({locale:i,namespace:"Emails.SubAffiliateInvite"}),l({locale:i})]),p=new URL(`/accept-invite/${r.raw}`,o.APP_URL).toString(),c=v(r.expiresAt,s),f=e("greetingNamed",{name:t.firstName}),a=o.BRAND_NAME;await u({to:t.email,subject:e("subject",{brandName:a,parentName:t.parentName}),react:d({inviteUrl:p,lang:i,strings:{preview:e("preview",{brandName:a,parentName:t.parentName}),heading:e("heading"),greeting:f,body:e("body",{brandName:a,parentName:t.parentName}),cta:e("cta"),expiresAtMessage:e("expiresAt",{date:c}),fallback:e("fallback"),brandName:a,footerNote:m("footerNote")}})})}export{y as sendSubAffiliateInvite};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AuditAction } from "../../lib/audit/actions.js";
|
|
2
|
+
import type messages from "../../messages/en/index.json";
|
|
3
|
+
/**
|
|
4
|
+
* Compile-time guard: every audit action must have an i18n label under
|
|
5
|
+
* `AuditLog.actions` (action key with dots replaced by underscores). Adding an
|
|
6
|
+
* action to AUDIT_ACTIONS without a matching label makes this assertion fail to
|
|
7
|
+
* type-check — the error lists the action key(s) still missing a label.
|
|
8
|
+
*/
|
|
9
|
+
type DotsToUnderscores<S extends string> = S extends `${infer Head}.${infer Tail}` ? DotsToUnderscores<`${Head}_${Tail}`> : S;
|
|
10
|
+
type RequiredActionLabel = DotsToUnderscores<AuditAction>;
|
|
11
|
+
type ProvidedActionLabel = keyof (typeof messages)["AuditLog"]["actions"];
|
|
12
|
+
type MissingActionLabel = Exclude<RequiredActionLabel, ProvidedActionLabel>;
|
|
13
|
+
/** `true` iff every audit action has an i18n label (compile-time enforced). */
|
|
14
|
+
export declare const auditActionLabelsAreComplete: [MissingActionLabel] extends [never] ? true : MissingActionLabel;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=!0;export{e as auditActionLabelsAreComplete};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as p}from"react/jsx-runtime";import{IconHistory as A}from"@tabler/icons-react";import{useMessages as y,useTranslations as x}from"next-intl";import{useMemo as b}from"react";import{Avatar as w}from"../../../components/ui/avatar.js";import{DataTable as L}from"../../../components/ui/data-table.js";import{Identity as R}from"../../../components/ui/identity.js";import{SortButton as v}from"../../../components/ui/sort-button.js";import{TablePagination as T}from"../../../components/ui/table-pagination.js";import{useFormatDateTime as N}from"../../../lib/i18n/format-datetime.js";import{PAGE_SIZE_OPTIONS as E}from"../../../lib/list-params.js";function I(o,t){const l=t.replaceAll(".","_"),n=o?.[l];return typeof n=="string"?n:t}function B({result:o}){const t=x("AuditLog"),l=y(),n=N(),i=l.AuditLog,d=i?.actions!=null&&typeof i.actions=="object"&&!Array.isArray(i.actions)?i.actions:void 0,g=b(()=>[{id:"createdAt",header:()=>e(v,{column:"createdAt",children:t("columnTime")}),cell:({row:a})=>e("span",{className:"whitespace-nowrap text-sm text-muted-foreground tabular-nums",children:n(a.original.createdAt)})},{id:"actor",header:()=>t("columnActor"),cell:({row:a})=>{const{actorEmail:r,actorId:m,actorRole:s}=a.original;return e(R,{visual:e(w,{seed:r??m??"\u2014",name:r,size:"lg"}),primary:e("span",{className:"font-mono",children:r??"\u2014"}),secondary:s})}},{id:"action",header:()=>t("columnAction"),cell:({row:a})=>I(d,a.original.action)},{id:"target",header:()=>t("columnTarget"),cell:({row:a})=>{const{targetLabel:r,targetId:m,metadata:s,actorEmail:f}=a.original,u=r??m;if(!u)return e("span",{className:"text-muted-foreground",children:"\u2014"});const c=s&&typeof s.parentEmail=="string"?s.parentEmail:null;return p("div",{className:"flex flex-col",children:[e("span",{children:u}),c&&c!==f?e("span",{className:"text-xs text-muted-foreground",children:t("assignedUnder",{parent:c})}):null]})}}],[t,n,d]);return e(L,{data:o.rows,columns:g,getRowId:a=>a.id,empty:p("div",{className:"flex flex-col items-center gap-3 py-4",children:[e("div",{className:"flex size-10 items-center justify-center rounded-full bg-muted text-muted-foreground",children:e(A,{size:18,"aria-hidden":!0})}),e("span",{children:t("empty")})]}),pagination:e(T,{page:o.page,pageSize:o.pageSize,totalPages:o.totalPages,pageSizeOptions:E})})}export{B as AuditLogTable};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const t=["createdAt"];export{t as AUDIT_SORT_KEYS};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import "server-only";
|
|
2
|
+
import { type AuditLog } from "../../db/schema/index.js";
|
|
3
|
+
import { type ListParams, type ListResult } from "../../lib/list-params.js";
|
|
4
|
+
export type AuditLogRow = AuditLog;
|
|
5
|
+
/**
|
|
6
|
+
* Full audit history for a single affiliate: entries the affiliate triggered
|
|
7
|
+
* (actorId) and entries that concern the affiliate (subjectId). No actor-role
|
|
8
|
+
* scoping — this is one affiliate's history, so a logs:read manager also sees
|
|
9
|
+
* admin/manager actions on that affiliate. Hardened: only returns rows when the
|
|
10
|
+
* id belongs to an affiliate, so it cannot be used to read a manager's or
|
|
11
|
+
* admin's history.
|
|
12
|
+
*/
|
|
13
|
+
export declare const listAffiliateAuditLogs: (affiliateId: string, params: ListParams<"createdAt">) => Promise<ListResult<{
|
|
14
|
+
id: string;
|
|
15
|
+
createdAt: Date;
|
|
16
|
+
actorId: string | null;
|
|
17
|
+
actorRole: "platform_admin" | "manager" | "affiliate";
|
|
18
|
+
actorEmail: string | null;
|
|
19
|
+
subjectId: string | null;
|
|
20
|
+
action: string;
|
|
21
|
+
targetType: string | null;
|
|
22
|
+
targetId: string | null;
|
|
23
|
+
targetLabel: string | null;
|
|
24
|
+
metadata: Record<string, unknown> | null;
|
|
25
|
+
ipAddress: string | null;
|
|
26
|
+
userAgent: string | null;
|
|
27
|
+
}>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"server-only";import{db as a}from"../../db/index.js";import{auditLogs as t,USER_ROLE as n,users as e}from"../../db/schema/index.js";import{and as f,asc as l,count as p,desc as y,eq as r,or as L}from"drizzle-orm";import{authQuery as g}from"../../lib/auth/action.js";import{paginate as u}from"../../lib/list-params.js";const b=g("logs:read",async(A,o,i)=>{const[m]=await a.select({id:e.id}).from(e).where(f(r(e.id,o),r(e.role,n.affiliate))).limit(1);if(!m)return u(i,{count:async()=>0,fetch:async()=>[]});const c=L(r(t.actorId,o),r(t.subjectId,o));return u(i,{count:async()=>{const[s]=await a.select({total:p()}).from(t).where(c);return s?.total??0},fetch:async({offset:s,limit:d})=>a.select().from(t).where(c).orderBy(i.dir==="asc"?l(t.createdAt):y(t.createdAt)).limit(d).offset(s)})});export{b as listAffiliateAuditLogs};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { FormState } from "../../lib/actions/state.js";
|
|
2
|
+
export type AuthState = FormState<{
|
|
3
|
+
totpRequired?: true;
|
|
4
|
+
}>;
|
|
5
|
+
export declare const signInAction: (args_0: FormState<{
|
|
6
|
+
totpRequired?: true;
|
|
7
|
+
}>, args_1: FormData) => Promise<FormState<{
|
|
8
|
+
totpRequired?: true;
|
|
9
|
+
}>>;
|
|
10
|
+
export type VerifyTotpState = FormState;
|
|
11
|
+
export declare const verifyTotpAction: (args_0: FormState<void>, args_1: FormData) => Promise<FormState<void>>;
|
|
12
|
+
export declare const cancelTotpChallengeAction: () => Promise<void>;
|
|
13
|
+
export declare function signOutAction(): Promise<void>;
|
|
14
|
+
export type AcceptInviteState = FormState;
|
|
15
|
+
export declare const acceptInviteAction: (args_0: string, args_1: FormState<void>, args_2: FormData) => Promise<FormState<void>>;
|
|
16
|
+
export type ForgotPasswordState = FormState;
|
|
17
|
+
export declare const forgotPasswordAction: (args_0: FormState<{
|
|
18
|
+
message: string;
|
|
19
|
+
} | undefined>, args_1: FormData) => Promise<FormState<{
|
|
20
|
+
message: string;
|
|
21
|
+
} | undefined>>;
|
|
22
|
+
export type ChangePasswordState = FormState;
|
|
23
|
+
export declare const changePasswordAction: (args_0: FormState<{
|
|
24
|
+
message: string;
|
|
25
|
+
}>, args_1: FormData) => Promise<FormState<{
|
|
26
|
+
message: string;
|
|
27
|
+
}>>;
|
|
28
|
+
export type ResetPasswordState = FormState;
|
|
29
|
+
export declare const resetPasswordAction: (args_0: string, args_1: FormState<void>, args_2: FormData) => Promise<FormState<void>>;
|
|
30
|
+
export type SignupState = FormState;
|
|
31
|
+
export declare const signupAction: (args_0: FormState<never>, args_1: FormData) => Promise<FormState<never>>;
|
|
32
|
+
export type VerifyEmailState = FormState;
|
|
33
|
+
export declare const verifyEmailAction: (args_0: string, args_1: FormState<void>, args_2: FormData) => Promise<FormState<void>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use server";import{db as d}from"../../db/index.js";import{canSignIn as h,SIGNUP_SOURCE as I,USER_ROLE as N,users as t}from"../../db/schema/index.js";import{and as j,eq as m}from"drizzle-orm";import{redirect as f}from"next/navigation";import{z as r}from"zod";import{notifyManagersOfActivatedAffiliate as b,notifyManagersOfPendingAffiliate as C}from"../affiliates/pending-notification.js";import{sendPasswordResetEmail as O}from"./password-reset.js";import{sendSignupVerificationEmail as V}from"./signup-email.js";import{parseForm as v}from"../../lib/actions/parse-form.js";import{authFormAction as D,formAction as u}from"../../lib/auth/action.js";import{hashPassword as P,verifyPassword as M}from"../../lib/auth/password.js";import{signIn as S,signOut as L}from"../../lib/auth/session.js";import{revokeAllSessionsForUser as T}from"../../lib/auth/tokens.js";import{decryptSecret as U,verifyCode as W}from"../../lib/auth/totp.js";import{clearTotpChallenge as x,issueTotpChallenge as X,readTotpChallenge as z}from"../../lib/auth/totp-challenge.js";import{consumeVerificationToken as k,inspectVerificationToken as G}from"../../lib/auth/verification-tokens.js";import{isUniqueViolation as $}from"../../lib/db/errors.js";import{appError as o}from"../../lib/errors/codes.js";import{success as R}from"../../lib/errors/server.js";import{getPlatformSettings as E}from"../../lib/platform-settings.js";import{hydratePreferencesToCookies as A}from"../../lib/preferences/index.js";import{formDataToObject as q,NAME_MAX as B,PASSWORD_MAX as y,PASSWORD_MIN as _,UserProfileSchema as J,V as g}from"../../lib/validation/zod.js";const K=r.object({email:r.email().trim().toLowerCase(),password:r.string().min(_).max(y)}),It=u({},async a=>{const n=K.safeParse(q(a));if(!n.success)throw o("invalid_credentials",{field:"password"});const[i]=await d.select().from(t).where(m(t.email,n.data.email)).limit(1);if(!i?.passwordHash)throw o("invalid_credentials",{field:"password"});if(!await M(i.passwordHash,n.data.password))throw o("invalid_credentials",{field:"password"});if(!h(i.status))throw o("user_blocked",{toast:!0});if(!i.inviteAcceptedAt)throw o("email_not_verified",{toast:!0});if(i.role===N.affiliate&&!i.approvedAt)throw o("affiliate_not_approved",{toast:!0});if(i.totpConfirmedAt)return await X(i.id),{totpRequired:!0};await S(i.id),await A(i.id),(await E()).requireManagerTotp&&i.role===N.manager&&f("/user/settings"),f("/")}),Q=r.object({code:r.string().regex(/^\d{6}$/)}),kt=u({},async a=>{const n=await v(a,Q),i=await z();if(!i)throw o("totp_challenge_expired");const[e]=await d.select({id:t.id,email:t.email,status:t.status,totpSecret:t.totpSecret,totpConfirmedAt:t.totpConfirmedAt}).from(t).where(m(t.id,i)).limit(1);if(!e?.totpSecret||!e.totpConfirmedAt)throw await x(),o("totp_challenge_expired");if(!h(e.status))throw await x(),o("user_blocked",{toast:!0});const s=U(e.totpSecret);if(!W(s,n.code,e.email))throw o("totp_invalid_code",{field:"code"});await x(),await S(e.id),await A(e.id),f("/")}),Et=async()=>{await x()};async function Ft(){await L(),f("/signin")}const Y=r.object({password:r.string().min(_).max(y),confirmPassword:r.string()}).refine(a=>a.password===a.confirmPassword,{path:["confirmPassword"],message:g.passwordsMustMatch}),bt=u({},async(a,n)=>{const i=await v(n,Y),e=await k(a,"invite");if(e.kind!=="ok")throw o("invalid_token");const[s]=await d.select({signupSource:t.signupSource,role:t.role,email:t.email,firstName:t.firstName,lastName:t.lastName,status:t.status}).from(t).where(m(t.id,e.userId)).limit(1);if(!s)throw o("user_not_found",{toast:!0});if(!h(s.status))throw o("user_blocked",{toast:!0});const p=await P(i.password),l=new Date,c=s.signupSource===I.affiliate_invite,H=await E(),F=c&&H.requireAffiliateApproval;if(await d.update(t).set({passwordHash:p,inviteAcceptedAt:l,...F?{}:{approvedAt:l}}).where(m(t.id,e.userId)),F){try{await C({affiliateEmail:s.email,affiliateFirstName:s.firstName,affiliateLastName:s.lastName})}catch(w){console.error("[acceptInvite] pending notification failed",{error:w instanceof Error?w.message:String(w),userId:e.userId}),f("/signup/awaiting-approval?notify=failed")}f("/signup/awaiting-approval")}if(s.role===N.affiliate)try{await b({affiliateEmail:s.email,affiliateFirstName:s.firstName,affiliateLastName:s.lastName})}catch(w){console.error("[acceptInvite] manager notification failed",{error:w instanceof Error?w.message:String(w),userId:e.userId})}await S(e.userId),await A(e.userId),f("/")}),Z=r.object({email:r.email().trim().toLowerCase()}),Ct=u({},async a=>{const n=Z.safeParse(q(a));if(!n.success)return;const[i]=await d.select({id:t.id,email:t.email,firstName:t.firstName,status:t.status}).from(t).where(m(t.email,n.data.email)).limit(1);if(!(!i||!h(i.status)))try{await O({userId:i.id,email:i.email,firstName:i.firstName})}catch{return R("Toasts.passwordResetEmailFailed")}}),tt=r.object({password:r.string().min(_).max(y),confirmPassword:r.string()}).refine(a=>a.password===a.confirmPassword,{path:["confirmPassword"],message:g.passwordsMustMatch}),at=r.object({currentPassword:r.string().min(1,g.fieldRequired),password:r.string().min(_,g.passwordTooShort).max(y),confirmPassword:r.string()}).refine(a=>a.password===a.confirmPassword,{path:["confirmPassword"],message:g.passwordsMustMatch}),Mt=D({},async({user:a,audit:n},i)=>{const e=await v(i,at),[s]=await d.select({passwordHash:t.passwordHash}).from(t).where(m(t.id,a.id)).limit(1);if(!s?.passwordHash)throw o("invalid_credentials",{field:"currentPassword"});if(!await M(s.passwordHash,e.currentPassword))throw o("invalid_credentials",{field:"currentPassword"});const l=await P(e.password);return await d.transaction(async c=>{await c.update(t).set({passwordHash:l}).where(m(t.id,a.id)),await n({action:"user.password.change",subjectId:a.id,target:{type:"user",id:a.id,label:a.email}},c)}),await T(a.id),await S(a.id),await R("Toasts.passwordChanged")}),Tt=u({},async(a,n)=>{const i=await v(n,tt),e=await k(a,"password_reset");if(e.kind!=="ok")throw o("invalid_token");const[s]=await d.select({id:t.id,status:t.status}).from(t).where(m(t.id,e.userId)).limit(1);if(!s)throw o("user_not_found",{toast:!0});if(!h(s.status))throw o("user_blocked",{toast:!0});const p=await P(i.password);await d.update(t).set({passwordHash:p}).where(m(t.id,s.id)),await T(s.id),await S(s.id),await A(s.id),f("/")}),et=J.extend({password:r.string().min(_).max(y),confirmPassword:r.string().max(B),tosAccepted:r.preprocess(a=>a==="on"||a==="true"||a===!0,r.literal(!0,g.tosRequired))}).refine(a=>a.password===a.confirmPassword,{path:["confirmPassword"],message:g.passwordsMustMatch}),Rt=u({},async a=>{const n=await v(a,et),i=await P(n.password),e=new Date,[s]=await d.insert(t).values({email:n.email,firstName:n.firstName,lastName:n.lastName,passwordHash:i,role:N.affiliate,signupSource:I.self_signup,inviteAcceptedAt:null,tosAcceptedAt:e}).returning({id:t.id,email:t.email,firstName:t.firstName}).catch(p=>{if($(p))return[];throw p});if(!s)throw o("email_already_exists",{field:"email"});try{await V({userId:s.id,email:s.email,firstName:s.firstName})}catch{}f("/signup/check-email")}),it=r.object({token:r.string().min(1)}),qt=u({},async(a,n)=>{it.parse({token:a});const i=await G(a,"email_verify");if(i.kind!=="ok")throw o("invalid_token");const[e]=await d.select({id:t.id,email:t.email,firstName:t.firstName,lastName:t.lastName,status:t.status}).from(t).where(j(m(t.id,i.userId),m(t.signupSource,I.self_signup))).limit(1);if(!e)throw o("invalid_token");if(!h(e.status))throw o("user_blocked",{toast:!0});if((await k(a,"email_verify")).kind!=="ok")throw o("invalid_token");const p=await E(),l=new Date;await d.update(t).set({inviteAcceptedAt:l,...p.requireAffiliateApproval?{}:{approvedAt:l}}).where(m(t.id,e.id)),p.requireAffiliateApproval&&f(await C({affiliateEmail:e.email,affiliateFirstName:e.firstName,affiliateLastName:e.lastName}).then(()=>"/signup/awaiting-approval").catch(c=>(console.error("[verifyEmail] manager notification failed",{error:c instanceof Error?c.message:String(c),userId:e.id}),"/signup/awaiting-approval?notify=failed")));try{await b({affiliateEmail:e.email,affiliateFirstName:e.firstName,affiliateLastName:e.lastName})}catch(c){console.error("[verifyEmail] manager notification failed",{error:c instanceof Error?c.message:String(c),userId:e.id})}await S(e.id),await A(e.id),f("/")});export{bt as acceptInviteAction,Et as cancelTotpChallengeAction,Mt as changePasswordAction,Ct as forgotPasswordAction,Tt as resetPasswordAction,It as signInAction,Ft as signOutAction,Rt as signupAction,qt as verifyEmailAction,kt as verifyTotpAction};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "server-only";
|
|
2
|
+
import { type PublicUser, type UserRole } from "../../db/schema/index.js";
|
|
3
|
+
import { type Permission, type PermissionCarrier } from "./permissions.js";
|
|
4
|
+
export declare function requireSession(): Promise<{
|
|
5
|
+
user: PublicUser;
|
|
6
|
+
carrier: PermissionCarrier;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function requireCurrentCarrier(): Promise<PermissionCarrier>;
|
|
9
|
+
export declare function requirePermission(carrier: PermissionCarrier, perm: Permission): void;
|
|
10
|
+
export declare function guardPermission(carrier: PermissionCarrier, perm: Permission): void;
|
|
11
|
+
export declare function requirePlatformAdmin(user: PublicUser): void;
|
|
12
|
+
export declare function guardPlatformAdmin(user: PublicUser): void;
|
|
13
|
+
export declare function requireRole(user: PublicUser, role: UserRole): void;
|
|
14
|
+
export declare function guardRole(user: PublicUser, role: UserRole): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"server-only";import{USER_ROLE as s}from"../../db/schema/index.js";import{redirect as e}from"next/navigation";import{loadSession as t}from"../../lib/auth/session.js";import{appError as o}from"../../lib/errors/codes.js";import{hasPermission as n}from"./permissions.js";function m(r){return{role:r.user.role,permissions:new Set(r.permissions)}}async function a(){const r=await t();return r||e("/signin"),{user:r.user,carrier:m(r)}}async function l(){return(await a()).carrier}function U(r,i){if(!n(r,i))throw o("forbidden",{toast:!0})}function b(r,i){n(r,i)||e("/")}function y(r){if(r.role!==s.platform_admin)throw o("forbidden",{toast:!0})}function C(r){r.role!==s.platform_admin&&e("/")}function S(r,i){if(r.role!==i)throw o("forbidden",{toast:!0})}function x(r,i){r.role!==i&&e("/")}export{b as guardPermission,C as guardPlatformAdmin,x as guardRole,l as requireCurrentCarrier,U as requirePermission,y as requirePlatformAdmin,S as requireRole,a as requireSession};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as t,jsxs as w}from"react/jsx-runtime";import{useTranslations as p}from"next-intl";import{useActionState as d}from"react";import{ActionForm as l}from"../../../components/ui/action-form.js";import{Button as u}from"../../../components/ui/button.js";import{FormField as r}from"../../../components/ui/form-field.js";import{PasswordInput as i}from"../../../components/ui/password-input.js";import{acceptInviteAction as f}from"../actions.js";function S({token:a}){const o=p("Auth.AcceptInvite"),[n,m,e]=d(async(s,c)=>f(a,s,c),void 0);return w(l,{action:m,actionState:n,className:"flex flex-col gap-4",children:[t(r,{name:"password",label:o("passwordLabel"),children:t(i,{name:"password","aria-required":"true",autoComplete:"new-password"})}),t(r,{name:"confirmPassword",label:o("confirmPasswordLabel"),children:t(i,{name:"confirmPassword","aria-required":"true",autoComplete:"new-password"})}),t(u,{type:"submit",disabled:e,children:o(e?"submitting":"submit")})]})}export{S as AcceptInviteForm};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ForgotPasswordForm(): import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as m}from"react/jsx-runtime";import{useTranslations as n}from"next-intl";import{useActionState as a}from"react";import{ActionForm as l}from"../../../components/ui/action-form.js";import{Alert as c}from"../../../components/ui/alert.js";import{Button as f}from"../../../components/ui/button.js";import{FormField as u}from"../../../components/ui/form-field.js";import{Input as p}from"../../../components/ui/input.js";import{TextLink as r}from"../../../components/ui/text-link.js";import{forgotPasswordAction as d}from"../actions.js";function P(){const t=n("Auth.ForgotPassword"),[o,s,i]=a(d,void 0);return o?.ok?m("div",{className:"flex flex-col gap-4",children:[e(c,{tone:"info",title:t("successTitle"),children:t("successMessage")}),e(r,{href:"/signin",className:"text-sm",children:t("backToSignIn")})]}):m(l,{action:s,actionState:o,className:"flex flex-col gap-4",children:[e(u,{name:"email",label:t("emailLabel"),children:e(p,{name:"email",type:"email","aria-required":"true",autoComplete:"email"})}),e(f,{type:"submit",disabled:i,children:t(i?"submitting":"submit")}),e(r,{href:"/signin",tone:"muted",className:"self-start text-sm",children:t("backToSignIn")})]})}export{P as ForgotPasswordForm};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{useTranslations as k}from"next-intl";import{useState as x}from"react";import{Checkbox as b,CheckboxGroup as C}from"../../../components/ui/checkbox.js";import{Field as n,FieldError as L,FieldLabel as F}from"../../../components/ui/field.js";import{Fieldset as w,FieldsetLegend as v}from"../../../components/ui/fieldset.js";import{actionsThatImply as I,expandImplied as y,groupedPermissions as R,permissionAction as W,permissionCategory as A,WILDCARD_PERMISSION as l}from"../permissions.js";import{useFormReset as G}from"../../../lib/hooks/use-form-reset.js";function _({name:t="permissions",defaultValues:d=[]}){const i=k("Groups"),N=R(),m=d.includes(l),c=y(d.filter(s=>s!==l)),[p,f]=x(m),[u,g]=x(c),h=G(()=>{f(m),g(c)});return r(n,{ref:h,name:t,className:"flex flex-col gap-4",children:[r(n,{className:"flex-row items-start gap-2 rounded-md border border-border bg-card p-3",children:[e(b,{name:t,value:l,checked:p,onCheckedChange:f,className:"mt-0.5"}),r("div",{className:"flex flex-col",children:[e(F,{className:"font-medium text-foreground",children:i("wildcardLabel")}),e("span",{className:"text-xs text-muted-foreground",children:i("wildcardWarning")})]})]}),e(C,{value:u,onValueChange:s=>{const o=new Set(s);for(const a of u){if(o.has(a))continue;const P=A(a);for(const S of I(W(a)))o.delete(`${P}:${S}`)}g(y(Array.from(o)))},disabled:p,"aria-label":i("permissionsLabel"),children:N.map(s=>r(w,{className:"gap-1.5",children:[e(v,{className:"text-xs font-medium tracking-wide text-muted-foreground uppercase",children:s.category}),s.permissions.map(o=>r(n,{className:"flex-row items-center gap-2",children:[e(b,{name:t,value:o}),e(F,{className:"font-mono text-xs font-normal",children:o})]},o))]},s.category))}),e(L,{})]})}export{_ as PermissionsForm};
|