@fayz-ai/admin 0.46.1 → 0.48.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/dist/ImportWizard-SYP3OXZU.js +3 -0
- package/dist/{ImportWizard-7UFB2PPF.js.map → ImportWizard-SYP3OXZU.js.map} +1 -1
- package/dist/PersonTimeline-X7JTPUWJ.js +3 -0
- package/dist/PersonTimeline-X7JTPUWJ.js.map +1 -0
- package/dist/ScheduleEditor-BXWJ7CMI.js +6 -0
- package/dist/{ScheduleEditor-MNHZCQIG.js.map → ScheduleEditor-BXWJ7CMI.js.map} +1 -1
- package/dist/SubscriptionPage-VBDDRSVW.js +8 -0
- package/dist/{SubscriptionPage-JWWS44SE.js.map → SubscriptionPage-VBDDRSVW.js.map} +1 -1
- package/dist/access/ModuleUnavailable.d.ts +14 -0
- package/dist/access/ModuleUnavailable.d.ts.map +1 -0
- package/dist/access/context.d.ts.map +1 -1
- package/dist/access/useModuleAccess.d.ts +11 -0
- package/dist/access/useModuleAccess.d.ts.map +1 -0
- package/dist/app/AdminShell.d.ts +1 -1
- package/dist/app/AdminShell.d.ts.map +1 -1
- package/dist/app/OfflineBoot.d.ts.map +1 -1
- package/dist/app/admin-app.d.ts +1 -1
- package/dist/app/admin-app.d.ts.map +1 -1
- package/dist/app/config.d.ts +3 -3
- package/dist/app/config.d.ts.map +1 -1
- package/dist/app/rail-preset.d.ts.map +1 -1
- package/dist/billing/TrialWidget.d.ts.map +1 -1
- package/dist/billing/ai-usage.d.ts +67 -0
- package/dist/billing/ai-usage.d.ts.map +1 -0
- package/dist/billing/index.d.ts +2 -0
- package/dist/billing/index.d.ts.map +1 -1
- package/dist/billing/index.js +3 -2
- package/dist/billing/module-families.d.ts +25 -0
- package/dist/billing/module-families.d.ts.map +1 -0
- package/dist/billing/module-pricing.d.ts +199 -0
- package/dist/billing/module-pricing.d.ts.map +1 -0
- package/dist/{chunk-IUCDHAAB.js → chunk-2Q6QHTZV.js} +13 -78
- package/dist/chunk-2Q6QHTZV.js.map +1 -0
- package/dist/{chunk-46UABOOC.js → chunk-5GCC7YCE.js} +40 -39
- package/dist/chunk-5GCC7YCE.js.map +1 -0
- package/dist/{chunk-WXNTUCX3.js → chunk-E4MESMNR.js} +10 -4
- package/dist/chunk-E4MESMNR.js.map +1 -0
- package/dist/chunk-F346TYKO.js +1448 -0
- package/dist/chunk-F346TYKO.js.map +1 -0
- package/dist/chunk-GZWX4ZIK.js +111 -0
- package/dist/chunk-GZWX4ZIK.js.map +1 -0
- package/dist/{chunk-OINP2UYL.js → chunk-KVIINVY6.js} +133 -169
- package/dist/chunk-KVIINVY6.js.map +1 -0
- package/dist/chunk-OEY3V6J3.js +581 -0
- package/dist/chunk-OEY3V6J3.js.map +1 -0
- package/dist/{chunk-V2IBAF4O.js → chunk-ZMP52ZHM.js} +23 -83
- package/dist/chunk-ZMP52ZHM.js.map +1 -0
- package/dist/components/RightRail.d.ts.map +1 -1
- package/dist/components/auth/CenteredLogin.d.ts +1 -1
- package/dist/components/auth/CenteredLogin.d.ts.map +1 -1
- package/dist/components/auth/LoginForm.d.ts +1 -1
- package/dist/components/auth/LoginForm.d.ts.map +1 -1
- package/dist/components/auth/LoginPage.d.ts +1 -1
- package/dist/components/auth/LoginPage.d.ts.map +1 -1
- package/dist/components/auth/OAuthButtons.d.ts +1 -1
- package/dist/components/auth/OAuthButtons.d.ts.map +1 -1
- package/dist/components/auth/ProtectedRoute.d.ts +1 -1
- package/dist/components/auth/ProtectedRoute.d.ts.map +1 -1
- package/dist/components/auth/RecoveryForm.d.ts.map +1 -1
- package/dist/components/auth/SignupForm.d.ts.map +1 -1
- package/dist/components/auth/SplitLogin.d.ts +1 -1
- package/dist/components/auth/SplitLogin.d.ts.map +1 -1
- package/dist/components/billing/AiUsageSection.d.ts +16 -0
- package/dist/components/billing/AiUsageSection.d.ts.map +1 -0
- package/dist/components/billing/InvoiceList.d.ts +1 -1
- package/dist/components/billing/InvoiceList.d.ts.map +1 -1
- package/dist/components/billing/PlanCheckoutSheet.d.ts +24 -0
- package/dist/components/billing/PlanCheckoutSheet.d.ts.map +1 -0
- package/dist/components/billing/PlanSelector.d.ts +1 -1
- package/dist/components/billing/PlanSelector.d.ts.map +1 -1
- package/dist/components/billing/PricingOverview.d.ts +20 -0
- package/dist/components/billing/PricingOverview.d.ts.map +1 -0
- package/dist/components/billing/SoftLimitWidget.d.ts.map +1 -1
- package/dist/components/billing/SubscriptionCard.d.ts +1 -1
- package/dist/components/billing/SubscriptionCard.d.ts.map +1 -1
- package/dist/components/billing/SubscriptionPage.d.ts.map +1 -1
- package/dist/components/billing/UpgradePrompt.d.ts.map +1 -1
- package/dist/components/billing/access-contract.d.ts +5 -3
- package/dist/components/billing/access-contract.d.ts.map +1 -1
- package/dist/components/billing/plan-feature.d.ts.map +1 -1
- package/dist/components/chat/AssistantActivityBar.d.ts.map +1 -1
- package/dist/components/chat/AssistantInvite.d.ts.map +1 -1
- package/dist/components/chat/AssistantRecordingView.d.ts.map +1 -1
- package/dist/components/chat/ChatAttachments.d.ts.map +1 -1
- package/dist/components/chat/ChatComposer.d.ts.map +1 -1
- package/dist/components/chat/ChatConversation.d.ts.map +1 -1
- package/dist/components/chat/ChatFab.d.ts.map +1 -1
- package/dist/components/chat/ChatHistory.d.ts.map +1 -1
- package/dist/components/chat/ChatMessages.d.ts.map +1 -1
- package/dist/components/chat/ChatSuggestions.d.ts.map +1 -1
- package/dist/components/chat/ChoiceCard.d.ts.map +1 -1
- package/dist/components/chat/ConfirmActionCard.d.ts.map +1 -1
- package/dist/components/chat/ConnectorSuggestionCard.d.ts.map +1 -1
- package/dist/components/chat/RecordChip.d.ts.map +1 -1
- package/dist/components/chat/TourCoachCard.d.ts.map +1 -1
- package/dist/components/connect/AddConnectorPanel.d.ts.map +1 -1
- package/dist/components/connect/ConnectConsentPage.d.ts.map +1 -1
- package/dist/components/connect/ConnectorDetail.d.ts.map +1 -1
- package/dist/components/connect/ConnectorRow.d.ts.map +1 -1
- package/dist/components/connect/ConnectorSyncActions.d.ts.map +1 -1
- package/dist/components/connect/ConnectorsPanel.d.ts.map +1 -1
- package/dist/components/layout/BottomNav.d.ts.map +1 -1
- package/dist/components/notifications/NotificationInbox.d.ts +1 -1
- package/dist/components/notifications/NotificationInbox.d.ts.map +1 -1
- package/dist/components/notifications/UpdateReady.d.ts.map +1 -1
- package/dist/components/organization/PermissionMatrixEditor.d.ts.map +1 -1
- package/dist/components/organization/PermissionProfilesTab.d.ts.map +1 -1
- package/dist/components/organization/TeamTab.d.ts.map +1 -1
- package/dist/components/plugins/ConnectorsHub.d.ts.map +1 -1
- package/dist/components/plugins/PluginSettingsPanel.d.ts.map +1 -1
- package/dist/components/settings/AddModulesPanel.d.ts.map +1 -1
- package/dist/components/settings/BrandingSettings.d.ts.map +1 -1
- package/dist/components/settings/CompanySettings.d.ts +1 -1
- package/dist/components/settings/CompanySettings.d.ts.map +1 -1
- package/dist/components/settings/ConnectedBrandingSettings.d.ts.map +1 -1
- package/dist/components/settings/ConnectedCompanySettings.d.ts.map +1 -1
- package/dist/components/settings/ConnectedFieldRulesSettings.d.ts.map +1 -1
- package/dist/components/settings/ConnectedModulesSettings.d.ts.map +1 -1
- package/dist/components/settings/ConnectedSecuritySettings.d.ts.map +1 -1
- package/dist/components/settings/FieldRulesEditor.d.ts +12 -0
- package/dist/components/settings/FieldRulesEditor.d.ts.map +1 -0
- package/dist/components/settings/FieldRulesSettings.d.ts.map +1 -1
- package/dist/components/settings/HolidaysSettings.d.ts.map +1 -1
- package/dist/components/settings/ModuleCard.d.ts +18 -3
- package/dist/components/settings/ModuleCard.d.ts.map +1 -1
- package/dist/components/settings/ModuleFamilyBits.d.ts +4 -0
- package/dist/components/settings/ModuleFamilyBits.d.ts.map +1 -0
- package/dist/components/settings/ModulesSettings.d.ts +3 -1
- package/dist/components/settings/ModulesSettings.d.ts.map +1 -1
- package/dist/components/settings/SecuritySettings.d.ts +1 -1
- package/dist/components/settings/SecuritySettings.d.ts.map +1 -1
- package/dist/components/settings/SettingsPage.d.ts +19 -0
- package/dist/components/settings/SettingsPage.d.ts.map +1 -1
- package/dist/components/settings/UserProfile.d.ts +1 -1
- package/dist/components/settings/UserProfile.d.ts.map +1 -1
- package/dist/components/settings/module-links.d.ts +10 -0
- package/dist/components/settings/module-links.d.ts.map +1 -0
- package/dist/components/settings/module-scope.d.ts +28 -0
- package/dist/components/settings/module-scope.d.ts.map +1 -0
- package/dist/components/settings/settings-focus.d.ts +17 -0
- package/dist/components/settings/settings-focus.d.ts.map +1 -0
- package/dist/components/settings/settings-parents.d.ts +11 -0
- package/dist/components/settings/settings-parents.d.ts.map +1 -0
- package/dist/components/settings/settings-sections.d.ts +56 -0
- package/dist/components/settings/settings-sections.d.ts.map +1 -0
- package/dist/components/settings/settings-shortcuts.d.ts +7 -0
- package/dist/components/settings/settings-shortcuts.d.ts.map +1 -0
- package/dist/components/settings/settings-subtabs.d.ts +14 -0
- package/dist/components/settings/settings-subtabs.d.ts.map +1 -0
- package/dist/components/shared/ContactPicker.d.ts.map +1 -1
- package/dist/components/shared/PersonLink.d.ts.map +1 -1
- package/dist/components/shared/RecordPickerModal.d.ts.map +1 -1
- package/dist/components/survey/PublicSurveyPage.d.ts.map +1 -1
- package/dist/crud/CrudDetailPage.d.ts.map +1 -1
- package/dist/crud/CrudFormPage.d.ts.map +1 -1
- package/dist/crud/CrudListView.d.ts.map +1 -1
- package/dist/crud/CrudPage.d.ts.map +1 -1
- package/dist/crud/EntityOverview.d.ts.map +1 -1
- package/dist/crud/ImportWizard.d.ts.map +1 -1
- package/dist/crud/InlineField.d.ts +36 -0
- package/dist/crud/InlineField.d.ts.map +1 -0
- package/dist/crud/LookupCreateInline.d.ts.map +1 -1
- package/dist/crud/RelatedSection.d.ts.map +1 -1
- package/dist/crud/TagsField.d.ts.map +1 -1
- package/dist/crud/archetypes/AccessTab.d.ts.map +1 -1
- package/dist/crud/archetypes/ActiveToggle.d.ts.map +1 -1
- package/dist/crud/archetypes/AddressFormModal.d.ts +34 -0
- package/dist/crud/archetypes/AddressFormModal.d.ts.map +1 -0
- package/dist/crud/archetypes/AddressesTab.d.ts +2 -20
- package/dist/crud/archetypes/AddressesTab.d.ts.map +1 -1
- package/dist/crud/archetypes/ArchetypeStatusBar.d.ts.map +1 -1
- package/dist/crud/archetypes/BlockSettingsPopover.d.ts +1 -1
- package/dist/crud/archetypes/BlockSettingsPopover.d.ts.map +1 -1
- package/dist/crud/archetypes/ClientOrdersTab.d.ts.map +1 -1
- package/dist/crud/archetypes/KanbanBoard.d.ts.map +1 -1
- package/dist/crud/archetypes/LocationFormLayout.d.ts.map +1 -1
- package/dist/crud/archetypes/OrderBoardView.d.ts.map +1 -1
- package/dist/crud/archetypes/OrderCreateScreen.d.ts +3 -1
- package/dist/crud/archetypes/OrderCreateScreen.d.ts.map +1 -1
- package/dist/crud/archetypes/OrderDetailPage.d.ts.map +1 -1
- package/dist/crud/archetypes/OrderDetailRail.d.ts.map +1 -1
- package/dist/crud/archetypes/OrderFormView.d.ts.map +1 -1
- package/dist/crud/archetypes/PayeeAccountsSection.d.ts.map +1 -1
- package/dist/crud/archetypes/PaymentStatusBadge.d.ts.map +1 -1
- package/dist/crud/archetypes/PersonPicker.d.ts.map +1 -1
- package/dist/crud/archetypes/ScheduleDateExceptions.d.ts.map +1 -1
- package/dist/crud/archetypes/ScheduleGridPanel.d.ts.map +1 -1
- package/dist/crud/fieldToColumn.d.ts.map +1 -1
- package/dist/db.cjs +831 -5
- package/dist/db.d.ts +2 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +1 -1
- package/dist/directory/AppSwitcher.d.ts.map +1 -1
- package/dist/handbook/NotebookPanel.d.ts.map +1 -1
- package/dist/hooks/useAITools.d.ts.map +1 -1
- package/dist/hooks/useAuth.d.ts +3 -3
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useChat.d.ts.map +1 -1
- package/dist/hooks/useFieldRules.d.ts +4 -2
- package/dist/hooks/useFieldRules.d.ts.map +1 -1
- package/dist/hooks/useFormatters.d.ts.map +1 -1
- package/dist/hooks/useGlobalSearch.d.ts.map +1 -1
- package/dist/hooks/useLayout.d.ts.map +1 -1
- package/dist/hooks/useNotifications.d.ts +1 -1
- package/dist/hooks/useNotifications.d.ts.map +1 -1
- package/dist/hooks/useTenant.d.ts +2 -2
- package/dist/hooks/useTenant.d.ts.map +1 -1
- package/dist/hooks/useTenantPlugins.d.ts +1 -1
- package/dist/impersonation/ImpersonationBanner.d.ts.map +1 -1
- package/dist/index.d.ts +48 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4953 -4557
- package/dist/index.js.map +1 -1
- package/dist/lib/currency.d.ts +6 -0
- package/dist/lib/currency.d.ts.map +1 -1
- package/dist/lib/field-rules-db.d.ts +36 -0
- package/dist/lib/field-rules-db.d.ts.map +1 -0
- package/dist/onboarding/ActivationProvider.d.ts.map +1 -1
- package/dist/onboarding/activation.store.d.ts +1 -1
- package/dist/onboarding/activation.store.d.ts.map +1 -1
- package/dist/onboarding/checklist.d.ts +1 -1
- package/dist/onboarding/checklist.d.ts.map +1 -1
- package/dist/onboarding/tasks.d.ts +1 -1
- package/dist/onboarding/tasks.d.ts.map +1 -1
- package/dist/org/WorkspaceChooser.d.ts.map +1 -1
- package/dist/org/WorkspaceUnitSheet.d.ts.map +1 -1
- package/dist/org/adapters/supabase.d.ts +1 -0
- package/dist/org/adapters/supabase.d.ts.map +1 -1
- package/dist/org/index.js +2 -2
- package/dist/permissions/v1-catalog.d.ts +16 -0
- package/dist/permissions/v1-catalog.d.ts.map +1 -0
- package/dist/plugins/PluginRegistryManager.d.ts.map +1 -1
- package/dist/plugins/QuickActionsButton.d.ts.map +1 -1
- package/dist/plugins/SettingsGroup.d.ts +12 -4
- package/dist/plugins/SettingsGroup.d.ts.map +1 -1
- package/dist/plugins/WidgetSlot.d.ts.map +1 -1
- package/dist/projects/ProjectsSettings.d.ts.map +1 -1
- package/dist/projects/SeuSiteWidget.d.ts.map +1 -1
- package/dist/settings/MessageTemplateRow.d.ts +16 -0
- package/dist/settings/MessageTemplateRow.d.ts.map +1 -0
- package/dist/settings/SettingsForm.d.ts +60 -0
- package/dist/settings/SettingsForm.d.ts.map +1 -0
- package/dist/settings/UnitScopePicker.d.ts +22 -0
- package/dist/settings/UnitScopePicker.d.ts.map +1 -0
- package/dist/settings/core-v1-tabs.d.ts +8 -0
- package/dist/settings/core-v1-tabs.d.ts.map +1 -0
- package/dist/settings/defineSettingsTab.d.ts +17 -0
- package/dist/settings/defineSettingsTab.d.ts.map +1 -0
- package/dist/settings/registry-parent.d.ts +8 -0
- package/dist/settings/registry-parent.d.ts.map +1 -0
- package/dist/settings/useSettingKeys.d.ts +28 -0
- package/dist/settings/useSettingKeys.d.ts.map +1 -0
- package/dist/stores/auth.store.d.ts +1 -1
- package/dist/stores/auth.store.d.ts.map +1 -1
- package/dist/stores/notifications.store.d.ts +1 -1
- package/dist/stores/notifications.store.d.ts.map +1 -1
- package/dist/stores/tenant.store.d.ts +1 -1
- package/dist/stores/tenant.store.d.ts.map +1 -1
- package/dist/tasks/TasksPanel.d.ts +4 -0
- package/dist/tasks/TasksPanel.d.ts.map +1 -0
- package/dist/tasks/TasksRailPanel.d.ts.map +1 -1
- package/dist/tasks/index.d.ts +15 -14
- package/dist/tasks/index.d.ts.map +1 -1
- package/dist/timeline/PersonTimeline.d.ts +1 -0
- package/dist/timeline/PersonTimeline.d.ts.map +1 -1
- package/dist/types/billing.d.ts +2 -0
- package/dist/types/billing.d.ts.map +1 -1
- package/dist/types/plugins.d.ts +2 -0
- package/dist/types/plugins.d.ts.map +1 -1
- package/dist/ui.d.ts +2 -1
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +1 -1
- package/dist/units/MemberUnitsCell.d.ts.map +1 -1
- package/dist/units/UnitMembersTab.d.ts.map +1 -1
- package/dist/units/UnitSwitcher.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/ImportWizard-7UFB2PPF.js +0 -3
- package/dist/ScheduleEditor-MNHZCQIG.js +0 -6
- package/dist/SubscriptionPage-JWWS44SE.js +0 -9
- package/dist/access/index.d.ts +0 -12
- package/dist/access/index.d.ts.map +0 -1
- package/dist/access/resolver.d.ts +0 -2
- package/dist/access/resolver.d.ts.map +0 -1
- package/dist/app/LoginPage.d.ts +0 -3
- package/dist/app/LoginPage.d.ts.map +0 -1
- package/dist/chunk-46UABOOC.js.map +0 -1
- package/dist/chunk-IUCDHAAB.js.map +0 -1
- package/dist/chunk-OINP2UYL.js.map +0 -1
- package/dist/chunk-QOS6UAQ4.js +0 -54
- package/dist/chunk-QOS6UAQ4.js.map +0 -1
- package/dist/chunk-V2IBAF4O.js.map +0 -1
- package/dist/chunk-VH4LLIMH.js +0 -531
- package/dist/chunk-VH4LLIMH.js.map +0 -1
- package/dist/chunk-WXNTUCX3.js.map +0 -1
- package/dist/components/auth/index.d.ts +0 -7
- package/dist/components/auth/index.d.ts.map +0 -1
- package/dist/components/layout/index.d.ts +0 -6
- package/dist/components/layout/index.d.ts.map +0 -1
- package/dist/components/notifications/index.d.ts +0 -5
- package/dist/components/notifications/index.d.ts.map +0 -1
- package/dist/components/organization/index.d.ts +0 -5
- package/dist/components/organization/index.d.ts.map +0 -1
- package/dist/components/settings/index.d.ts +0 -11
- package/dist/components/settings/index.d.ts.map +0 -1
- package/dist/crud/index.d.ts +0 -18
- package/dist/crud/index.d.ts.map +0 -1
- package/dist/hooks/index.d.ts +0 -20
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/lib/format.d.ts +0 -7
- package/dist/lib/format.d.ts.map +0 -1
- package/dist/lib/plugins.d.ts +0 -2
- package/dist/lib/plugins.d.ts.map +0 -1
- package/dist/stores/billing.store.d.ts +0 -2
- package/dist/stores/billing.store.d.ts.map +0 -1
- package/dist/stores/index.d.ts +0 -13
- package/dist/stores/index.d.ts.map +0 -1
- package/dist/stores/layout.store.d.ts +0 -2
- package/dist/stores/layout.store.d.ts.map +0 -1
- package/dist/stores/permissions.store.d.ts +0 -2
- package/dist/stores/permissions.store.d.ts.map +0 -1
- package/dist/tasks/components/TaskCard.d.ts +0 -11
- package/dist/tasks/components/TaskCard.d.ts.map +0 -1
- package/dist/tasks/components/TaskDetail.d.ts +0 -5
- package/dist/tasks/components/TaskDetail.d.ts.map +0 -1
- package/dist/tasks/components/TaskLabelBadge.d.ts +0 -9
- package/dist/tasks/components/TaskLabelBadge.d.ts.map +0 -1
- package/dist/tasks/components/TaskPriorityBadge.d.ts +0 -7
- package/dist/tasks/components/TaskPriorityBadge.d.ts.map +0 -1
- package/dist/tasks/components/TaskQuickAdd.d.ts +0 -5
- package/dist/tasks/components/TaskQuickAdd.d.ts.map +0 -1
- package/dist/tasks/components/TaskSourceBadge.d.ts +0 -5
- package/dist/tasks/components/TaskSourceBadge.d.ts.map +0 -1
- package/dist/tasks/components/TaskStatusGroup.d.ts +0 -17
- package/dist/tasks/components/TaskStatusGroup.d.ts.map +0 -1
- package/dist/tasks/components/TasksFilterBar.d.ts +0 -3
- package/dist/tasks/components/TasksFilterBar.d.ts.map +0 -1
- package/dist/tasks/components/TasksPanel.d.ts +0 -14
- package/dist/tasks/components/TasksPanel.d.ts.map +0 -1
- package/dist/tasks/data/mock.d.ts +0 -3
- package/dist/tasks/data/mock.d.ts.map +0 -1
- package/dist/tasks/data/supabase.d.ts +0 -3
- package/dist/tasks/data/supabase.d.ts.map +0 -1
- package/dist/tasks/entity.d.ts +0 -11
- package/dist/tasks/entity.d.ts.map +0 -1
- package/dist/tasks/store.d.ts +0 -34
- package/dist/tasks/store.d.ts.map +0 -1
- package/dist/tasks/types.d.ts +0 -89
- package/dist/tasks/types.d.ts.map +0 -1
- package/dist/theme/index.d.ts +0 -8
- package/dist/theme/index.d.ts.map +0 -1
- package/dist/timeline/index.d.ts +0 -7
- package/dist/timeline/index.d.ts.map +0 -1
- package/dist/timeline-LECYQ4IA.js +0 -3
- package/dist/timeline-LECYQ4IA.js.map +0 -1
- package/dist/types/index.d.ts +0 -16
- package/dist/types/index.d.ts.map +0 -1
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
import { useOrganizationStore, getSupabaseClientOptional } from './chunk-GZWX4ZIK.js';
|
|
2
|
+
import { create } from 'zustand';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { tl } from '@fayz-ai/core';
|
|
5
|
+
|
|
6
|
+
var initialState = {
|
|
7
|
+
subscription: null,
|
|
8
|
+
invoices: [],
|
|
9
|
+
plans: [],
|
|
10
|
+
loading: false,
|
|
11
|
+
checkout: null
|
|
12
|
+
};
|
|
13
|
+
var useBillingStore = create((set) => ({
|
|
14
|
+
...initialState,
|
|
15
|
+
setSubscription: (subscription) => set({ subscription }),
|
|
16
|
+
setInvoices: (invoices) => set({ invoices }),
|
|
17
|
+
setPlans: (plans) => set({ plans }),
|
|
18
|
+
setLoading: (loading) => set({ loading }),
|
|
19
|
+
setCheckout: (checkout) => set({ checkout }),
|
|
20
|
+
reset: () => set(initialState)
|
|
21
|
+
}));
|
|
22
|
+
var NO_TRIAL = { status: "none", daysLeft: 0, endingSoon: false };
|
|
23
|
+
var DAY_MS = 864e5;
|
|
24
|
+
function resolveTrial(org, paidPlanIds2, now = Date.now()) {
|
|
25
|
+
if (!org?.trialEndsAt) return NO_TRIAL;
|
|
26
|
+
if (org.plan && paidPlanIds2.has(org.plan)) return NO_TRIAL;
|
|
27
|
+
const ends = Date.parse(org.trialEndsAt);
|
|
28
|
+
if (Number.isNaN(ends)) return NO_TRIAL;
|
|
29
|
+
const remaining = ends - now;
|
|
30
|
+
if (remaining <= 0) return { status: "expired", endsAt: org.trialEndsAt, daysLeft: 0, endingSoon: false };
|
|
31
|
+
const daysLeft = Math.ceil(remaining / DAY_MS);
|
|
32
|
+
return {
|
|
33
|
+
status: "active",
|
|
34
|
+
endsAt: org.trialEndsAt,
|
|
35
|
+
daysLeft,
|
|
36
|
+
endingSoon: remaining <= 2 * DAY_MS
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function effectivePlan(org, plans, trial, trialPlanId) {
|
|
40
|
+
if (trial.status === "active") {
|
|
41
|
+
const named2 = trialPlanId ? plans.find((p) => p.id === trialPlanId) : void 0;
|
|
42
|
+
if (named2) return named2;
|
|
43
|
+
const paid = plans.filter((p) => p.price > 0);
|
|
44
|
+
if (paid.length) return paid.reduce((best, p) => p.price > best.price ? p : best);
|
|
45
|
+
}
|
|
46
|
+
if (plans.length === 0) return null;
|
|
47
|
+
const named = org?.plan ? plans.find((p) => p.id === org.plan) : void 0;
|
|
48
|
+
if (named) return named;
|
|
49
|
+
const floor = plans.reduce((cheapest, p) => p.price < cheapest.price ? p : cheapest);
|
|
50
|
+
if (org?.plan) {
|
|
51
|
+
console.warn(
|
|
52
|
+
`[billing] tenant plan "${org.plan}" n\xE3o existe neste cat\xE1logo (${plans.map((p) => p.id).join(", ")}) \u2014 aplicando o piso "${floor.id}"`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return floor;
|
|
56
|
+
}
|
|
57
|
+
function paidPlanIds(plans) {
|
|
58
|
+
return new Set(plans.filter((p) => p.price > 0).map((p) => p.id));
|
|
59
|
+
}
|
|
60
|
+
function useTrial() {
|
|
61
|
+
const org = useOrganizationStore((s) => s.currentOrg);
|
|
62
|
+
const plans = useBillingStore((s) => s.plans);
|
|
63
|
+
const [now, setNow] = React.useState(() => Date.now());
|
|
64
|
+
React.useEffect(() => {
|
|
65
|
+
const id = window.setInterval(() => setNow(Date.now()), 36e5);
|
|
66
|
+
return () => window.clearInterval(id);
|
|
67
|
+
}, []);
|
|
68
|
+
return React.useMemo(
|
|
69
|
+
() => resolveTrial(org, paidPlanIds(plans), now),
|
|
70
|
+
[org?.plan, org?.trialEndsAt, plans, now]
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
var PRICE_BOOK = {
|
|
74
|
+
// Selling and the floor
|
|
75
|
+
orders: { price: 99, per: "unit", label: ["Orders & POS", "Pedidos e PDV"] },
|
|
76
|
+
"orders.scale": { price: 29, per: "unit", label: ["Scale & sale by weight", "Balan\xE7a e venda por peso"] },
|
|
77
|
+
// The orders facet that takes delivery-app orders (iFood, 99Food…).
|
|
78
|
+
"orders.delivery": { price: 39, per: "unit", label: ["Delivery & iFood", "Delivery e iFood"] },
|
|
79
|
+
tables: { price: 79, per: "unit", label: ["Tables & tabs", "Sal\xE3o e mesas"] },
|
|
80
|
+
"tables.tablets": { price: 39, per: "unit", label: ["Table tablets", "Tablets de mesa"] },
|
|
81
|
+
"tables.waitlist": { price: 29, per: "unit", label: ["Waitlist", "Fila de espera"] },
|
|
82
|
+
reservations: { price: 29, per: "unit", label: ["Reservations", "Reservas"] },
|
|
83
|
+
menu: { price: 39, per: "unit", label: ["Menu", "Card\xE1pio"] },
|
|
84
|
+
"menu.qr_menu": { price: 29, per: "unit", label: ["QR menu", "Card\xE1pio digital (QR)"] },
|
|
85
|
+
production: { price: 49, per: "unit", label: ["Kitchen (KDS)", "Cozinha (KDS)"] },
|
|
86
|
+
// The resto preset mounts the kitchen as `kitchen`; same price, never both on.
|
|
87
|
+
kitchen: { price: 49, per: "unit", label: ["Kitchen (KDS)", "Cozinha (KDS)"] },
|
|
88
|
+
shop: { price: 79, per: "account", label: ["Online store", "Loja online"] },
|
|
89
|
+
// Services
|
|
90
|
+
agenda: { price: 79, per: "unit", label: ["Schedule", "Agenda"] },
|
|
91
|
+
"agenda.public_booking": { price: 29, per: "unit", label: ["Online booking", "Agendamento online"] },
|
|
92
|
+
"agenda.smart_fit": { price: 29, per: "unit", label: ["Smart fit", "Encaixe inteligente"] },
|
|
93
|
+
"agenda.kiosk": { price: 39, per: "unit", label: ["Kiosks", "Totens"] },
|
|
94
|
+
clinical: { price: 79, per: "unit", label: ["Clinical records", "Prontu\xE1rio"] },
|
|
95
|
+
// Back office
|
|
96
|
+
inventory: { price: 69, per: "unit", label: ["Inventory", "Estoque"] },
|
|
97
|
+
"inventory.costing": { price: 29, per: "unit", label: ["Recipe costing & margin", "Ficha t\xE9cnica e CMV"] },
|
|
98
|
+
"inventory.purchasing": { price: 39, per: "unit", label: ["Purchasing", "Compras e reposi\xE7\xE3o"] },
|
|
99
|
+
financial: { price: 79, per: "unit", label: ["Financial", "Financeiro"] },
|
|
100
|
+
"financial.reconciliation": { price: 39, per: "unit", label: ["Bank reconciliation", "Concilia\xE7\xE3o banc\xE1ria"] },
|
|
101
|
+
"financial.dre": { price: 19, per: "account", label: ["P&L and cash flow", "DRE e fluxo de caixa"] },
|
|
102
|
+
"fiscal-br": { price: 59, per: "unit", label: ["Invoicing (NFC-e/NF-e)", "Fiscal (NFC-e/NF-e)"] },
|
|
103
|
+
openbanking: { price: 29, per: "account", label: ["Open banking", "Open banking"] },
|
|
104
|
+
workforce: { price: 49, per: "unit", label: ["Team & shifts", "Equipe e escala"] },
|
|
105
|
+
"workforce.time_clock": { price: 39, per: "unit", label: ["Time clock", "Ponto eletr\xF4nico"] },
|
|
106
|
+
// Clients and growth — one client base for the whole group
|
|
107
|
+
crm: { price: 39, per: "account", label: ["Clients (CRM)", "Clientes (CRM)"] },
|
|
108
|
+
"crm.pipeline": { price: 19, per: "account", label: ["Sales pipeline", "Funil de vendas"] },
|
|
109
|
+
"crm.automation": { price: 29, per: "account", label: ["Pipeline automations", "Automa\xE7\xF5es de funil"] },
|
|
110
|
+
"crm.loyalty": { price: 39, per: "account", label: ["Club & cashback", "Clube e Cashback"] },
|
|
111
|
+
conversations: { price: 49, per: "account", label: ["Conversations (WhatsApp)", "Conversas (WhatsApp)"] },
|
|
112
|
+
// The upsell every trade gets: an AI attendant answering each unit's WhatsApp.
|
|
113
|
+
// Below a generic AI agent (R$ 500+) and a fraction of a receptionist.
|
|
114
|
+
"conversations.atendeai": { price: 149, per: "unit", label: ["AI attendant", "AtendeAI"] },
|
|
115
|
+
marketing: { price: 49, per: "account", label: ["Marketing", "Marketing"] },
|
|
116
|
+
automations: { price: 39, per: "account", label: ["Automations", "Automa\xE7\xF5es"] },
|
|
117
|
+
forms: { price: 29, per: "account", label: ["Forms & contracts", "Formul\xE1rios e contratos"] },
|
|
118
|
+
// The forms plugin's runtime id.
|
|
119
|
+
custom_forms: { price: 29, per: "account", label: ["Forms & contracts", "Formul\xE1rios e contratos"] },
|
|
120
|
+
scribe: { price: 49, per: "account", label: ["AI scribe", "Escriba (IA)"] },
|
|
121
|
+
reports: { price: 29, per: "account", label: ["Reports", "Relat\xF3rios"] },
|
|
122
|
+
reputation: { price: 29, per: "account", label: ["Reviews", "Avalia\xE7\xF5es"] },
|
|
123
|
+
sites: { price: 29, per: "account", label: ["Website", "Site"] },
|
|
124
|
+
courses: { price: 49, per: "account", label: ["Courses", "Cursos"] },
|
|
125
|
+
// Coming soon — proposed prices (docs/saas/PRICING-COMPETITORS.md), never billed.
|
|
126
|
+
tiss: { price: 99, per: "unit", label: ["Health-plan billing (TISS)", "Faturamento de Conv\xEAnio (TISS)"], comingSoon: true },
|
|
127
|
+
"pet.grooming": { price: 79, per: "unit", label: ["Bath & grooming", "Banho e tosa"], comingSoon: true },
|
|
128
|
+
"pet.vet": { price: 99, per: "unit", label: ["Vet records", "Prontu\xE1rio veterin\xE1rio"], comingSoon: true },
|
|
129
|
+
"pet.lodging": { price: 49, per: "unit", label: ["Pet hotel & daycare", "Hotel e creche"], comingSoon: true },
|
|
130
|
+
"pet.packages": { price: 29, per: "account", label: ["Pet packages", "Pacotes pet"], comingSoon: true },
|
|
131
|
+
marketplaces: { price: 79, per: "account", label: ["Marketplaces (Mercado Livre\u2026)", "Marketplaces (Mercado Livre\u2026)"], comingSoon: true }
|
|
132
|
+
};
|
|
133
|
+
var COMING_SOON_MODULES = Object.keys(PRICE_BOOK).filter((k) => PRICE_BOOK[k].comingSoon);
|
|
134
|
+
var UNIT_TIERS = [
|
|
135
|
+
{ from: 1, factor: 1 },
|
|
136
|
+
{ from: 2, factor: 0.85 },
|
|
137
|
+
{ from: 6, factor: 0.65 },
|
|
138
|
+
{ from: 21, factor: 0.45 }
|
|
139
|
+
];
|
|
140
|
+
var EXTRA_SEAT_PRICE = 19;
|
|
141
|
+
var BACK_OFFICE = ["financial", "inventory", "crm", "forms", "custom_forms", "marketing", "automations", "reports"];
|
|
142
|
+
var BASE_PACKAGES = {
|
|
143
|
+
// Calibrated so the 3-unit restaurant archetype lands at R$ 1.950 on Scale,
|
|
144
|
+
// the price of the first proposal sent.
|
|
145
|
+
chefcontrol: { id: "chefcontrol", name: "ChefControl", unitPrice: 328, includes: [...BACK_OFFICE, "orders", "tables", "menu", "reservations"] },
|
|
146
|
+
beautycontrol: { id: "beautycontrol", name: "BeautyControl", unitPrice: 199, includes: [...BACK_OFFICE, "agenda"] },
|
|
147
|
+
storecontrol: { id: "storecontrol", name: "StoreControl", unitPrice: 189, includes: [...BACK_OFFICE, "shop", "orders"] },
|
|
148
|
+
gocontrol: { id: "gocontrol", name: "GoControl", unitPrice: 149, includes: [...BACK_OFFICE] }
|
|
149
|
+
};
|
|
150
|
+
var PACKAGE_BY_TRADE = {
|
|
151
|
+
food: "chefcontrol",
|
|
152
|
+
beauty: "beautycontrol",
|
|
153
|
+
commerce: "storecontrol"
|
|
154
|
+
};
|
|
155
|
+
function packageFor(opts = {}) {
|
|
156
|
+
if (opts.package && BASE_PACKAGES[opts.package]) return BASE_PACKAGES[opts.package];
|
|
157
|
+
for (const t of opts.trades ?? []) {
|
|
158
|
+
const id = PACKAGE_BY_TRADE[t];
|
|
159
|
+
if (id) return BASE_PACKAGES[id];
|
|
160
|
+
}
|
|
161
|
+
const on = new Set(opts.modules ?? []);
|
|
162
|
+
if (["tables", "menu", "kitchen", "production", "reservations"].some((k) => on.has(k))) return BASE_PACKAGES.chefcontrol;
|
|
163
|
+
if (["agenda", "clinical"].some((k) => on.has(k))) return BASE_PACKAGES.beautycontrol;
|
|
164
|
+
if (on.has("shop")) return BASE_PACKAGES.storecontrol;
|
|
165
|
+
return BASE_PACKAGES.gocontrol;
|
|
166
|
+
}
|
|
167
|
+
function includedIn(pkg, key, extra) {
|
|
168
|
+
return !!pkg && (pkg.includes.includes(key) || !!extra?.includes(key));
|
|
169
|
+
}
|
|
170
|
+
var FREE_AI_CREDITS = 30;
|
|
171
|
+
var UPSELL_KEY = "conversations.atendeai";
|
|
172
|
+
var EXTRA_AI_CREDITS = [
|
|
173
|
+
{ credits: 100, price: 19 },
|
|
174
|
+
{ credits: 1e3, price: 149 }
|
|
175
|
+
];
|
|
176
|
+
var PRICING_PLANS = [
|
|
177
|
+
{ id: "a-la-carte", name: ["\xC0 la carte", "Avulso"], platformFee: 99, seatsPerUnit: 3, discount: 0, aiCredits: 50 },
|
|
178
|
+
{ id: "essential", name: ["Essential", "Essencial"], platformFee: 79, seatsPerUnit: 5, discount: 0, aiCredits: 100 },
|
|
179
|
+
// Pro is the natural middle: a lower fee and a real discount make it the
|
|
180
|
+
// cheapest choice once a salon or restaurant outgrows five logins.
|
|
181
|
+
{ id: "pro", name: ["Pro", "Pro"], platformFee: 119, seatsPerUnit: 7, discount: 0.08, aiCredits: 300 },
|
|
182
|
+
{ id: "scale", name: ["Scale", "Scale"], platformFee: 449, seatsPerUnit: null, discount: 0.1, aiCredits: 1e3 }
|
|
183
|
+
];
|
|
184
|
+
var round = (n) => Math.round(n * 100) / 100;
|
|
185
|
+
var brl = (n) => `R$ ${n.toLocaleString("pt-BR", { minimumFractionDigits: 0, maximumFractionDigits: 2 })}`;
|
|
186
|
+
function packageSummary(pkg) {
|
|
187
|
+
const seen = /* @__PURE__ */ new Set();
|
|
188
|
+
const names = pkg.includes.filter((k) => PRICE_BOOK[k]).map((k) => tl(...PRICE_BOOK[k].label)).filter((n) => seen.has(n) ? false : (seen.add(n), true));
|
|
189
|
+
return names.length > 1 ? `${names.slice(0, -1).join(", ")} ${tl("and", "e")} ${names[names.length - 1]}` : names.join("");
|
|
190
|
+
}
|
|
191
|
+
function tierFactorAt(n) {
|
|
192
|
+
let factor = UNIT_TIERS[0].factor;
|
|
193
|
+
for (const tier of UNIT_TIERS) if (n >= tier.from) factor = tier.factor;
|
|
194
|
+
return factor;
|
|
195
|
+
}
|
|
196
|
+
function unitFactor(units2) {
|
|
197
|
+
const n = Math.max(1, Math.floor(units2));
|
|
198
|
+
let sum = 0;
|
|
199
|
+
for (let i = 1; i <= n; i++) {
|
|
200
|
+
let factor = UNIT_TIERS[0].factor;
|
|
201
|
+
for (const tier of UNIT_TIERS) if (i >= tier.from) factor = tier.factor;
|
|
202
|
+
sum += factor;
|
|
203
|
+
}
|
|
204
|
+
return sum;
|
|
205
|
+
}
|
|
206
|
+
function billableModules(modules, pkg, alsoIncluded) {
|
|
207
|
+
const on = new Set(modules);
|
|
208
|
+
return Object.keys(PRICE_BOOK).filter((key) => {
|
|
209
|
+
if (!on.has(key) || PRICE_BOOK[key].comingSoon || includedIn(pkg, key, alsoIncluded)) return false;
|
|
210
|
+
const dot = key.indexOf(".");
|
|
211
|
+
return dot < 0 || on.has(key.slice(0, dot));
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
function quote(size, plan) {
|
|
215
|
+
const units2 = Math.max(1, Math.floor(size.unitModules?.length || size.units));
|
|
216
|
+
const lines = [{
|
|
217
|
+
kind: "platform",
|
|
218
|
+
key: "platform",
|
|
219
|
+
label: tl("Platform", "Plataforma"),
|
|
220
|
+
detail: tl("Login, registries, dashboard and support", "Acesso, cadastros, painel e suporte"),
|
|
221
|
+
amount: plan.platformFee
|
|
222
|
+
}];
|
|
223
|
+
const footprints = size.unitModules?.length ? size.unitModules : null;
|
|
224
|
+
const all = [...size.modules, ...(footprints ?? []).flatMap((u) => u.modules)];
|
|
225
|
+
const pkg = packageFor({ package: size.package, trades: size.trades, modules: all });
|
|
226
|
+
const negotiated = size.alsoIncluded;
|
|
227
|
+
const base = pkg.unitPrice * unitFactor(units2);
|
|
228
|
+
let modules = base;
|
|
229
|
+
let tierOff = 0;
|
|
230
|
+
lines.push({
|
|
231
|
+
kind: "package",
|
|
232
|
+
key: `package:${pkg.id}`,
|
|
233
|
+
label: `${pkg.name} \xB7 ${units2} ${units2 === 1 ? tl("unit", "unidade") : tl("units", "unidades")}`,
|
|
234
|
+
detail: `${tl("Includes", "Inclui")} ${packageSummary(pkg)} \xB7 ${brl(pkg.unitPrice)} ${tl("the first unit, less for the next", "a primeira unidade, menos nas seguintes")}`,
|
|
235
|
+
amount: round(base)
|
|
236
|
+
});
|
|
237
|
+
const on = billableModules(all, pkg, negotiated);
|
|
238
|
+
if (footprints) {
|
|
239
|
+
const perUnit = footprints.map((u) => {
|
|
240
|
+
const keys = billableModules(u.modules, pkg, negotiated).filter((k) => PRICE_BOOK[k].per === "unit");
|
|
241
|
+
return { u, keys, list: keys.reduce((sum, k) => sum + PRICE_BOOK[k].price, 0) };
|
|
242
|
+
}).sort((a, b) => b.list - a.list);
|
|
243
|
+
perUnit.forEach(({ u, keys, list }, i) => {
|
|
244
|
+
modules += list;
|
|
245
|
+
tierOff += list * (1 - tierFactorAt(i + 1));
|
|
246
|
+
if (!keys.length) return;
|
|
247
|
+
lines.push({
|
|
248
|
+
kind: "unit",
|
|
249
|
+
key: `unit:${u.id}`,
|
|
250
|
+
label: u.name,
|
|
251
|
+
detail: keys.map((k) => tl(...PRICE_BOOK[k].label)).join(" \xB7 ") || tl("No per-unit module", "Nenhum m\xF3dulo por unidade"),
|
|
252
|
+
amount: list
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
let perUnitList = 0;
|
|
257
|
+
for (const key of on) {
|
|
258
|
+
const entry = PRICE_BOOK[key];
|
|
259
|
+
if (footprints && entry.per === "unit") continue;
|
|
260
|
+
const amount = entry.per === "unit" ? entry.price * units2 : entry.price;
|
|
261
|
+
if (entry.per === "unit") perUnitList += entry.price;
|
|
262
|
+
modules += amount;
|
|
263
|
+
lines.push({
|
|
264
|
+
kind: "module",
|
|
265
|
+
key,
|
|
266
|
+
label: tl(...entry.label),
|
|
267
|
+
detail: entry.per === "unit" && units2 > 1 ? `${brl(entry.price)} \xD7 ${units2} ${tl("units", "unidades")}` : entry.per === "unit" ? tl("per unit", "por unidade") : tl("whole group", "grupo todo"),
|
|
268
|
+
amount
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
if (!footprints) tierOff = perUnitList * (units2 - unitFactor(units2));
|
|
272
|
+
tierOff = round(tierOff);
|
|
273
|
+
if (tierOff > 0) {
|
|
274
|
+
lines.push({
|
|
275
|
+
kind: "tier",
|
|
276
|
+
key: "unit-tiers",
|
|
277
|
+
label: tl("Multi-unit discount", "Desconto por unidade adicional"),
|
|
278
|
+
detail: tl("Units 2\u20135 pay 85%, 6\u201320 pay 65%, 21+ pay 45%", "Unidades 2\u20135 pagam 85%, 6\u201320 pagam 65%, 21+ pagam 45%"),
|
|
279
|
+
amount: -tierOff
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
if (plan.discount > 0 && modules > 0) {
|
|
283
|
+
const off = round((modules - tierOff) * plan.discount);
|
|
284
|
+
lines.push({
|
|
285
|
+
kind: "discount",
|
|
286
|
+
key: "plan-discount",
|
|
287
|
+
label: `${tl("Plan discount", "Desconto do plano")} ${tl(...plan.name)}`,
|
|
288
|
+
detail: `${Math.round(plan.discount * 100)}% ${tl("off the modules", "sobre os m\xF3dulos")}`,
|
|
289
|
+
amount: -off
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
if (plan.seatsPerUnit === null) {
|
|
293
|
+
lines.push({ kind: "seats", key: "seats", label: tl("Users", "Usu\xE1rios"), detail: tl("Unlimited", "Ilimitados"), amount: 0 });
|
|
294
|
+
} else {
|
|
295
|
+
const included = plan.seatsPerUnit * units2;
|
|
296
|
+
const extra = Math.max(0, Math.floor(size.users) - included);
|
|
297
|
+
lines.push({
|
|
298
|
+
kind: "seats",
|
|
299
|
+
key: "seats",
|
|
300
|
+
label: tl("Users", "Usu\xE1rios"),
|
|
301
|
+
detail: extra > 0 ? `${extra} ${tl("beyond the", "al\xE9m dos")} ${included} ${tl("included", "inclu\xEDdos")} \xD7 ${brl(EXTRA_SEAT_PRICE)}` : `${Math.floor(size.users)} ${tl("of", "de")} ${included} ${tl("included", "inclu\xEDdos")}`,
|
|
302
|
+
amount: extra * EXTRA_SEAT_PRICE
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
if (plan.aiCredits) {
|
|
306
|
+
lines.push({
|
|
307
|
+
kind: "credits",
|
|
308
|
+
key: "ai-credits",
|
|
309
|
+
label: tl("AI assistant", "Assistente de IA"),
|
|
310
|
+
detail: `${plan.aiCredits.toLocaleString("pt-BR")} ${tl("credits/mo included", "cr\xE9ditos/m\xEAs inclu\xEDdos")}`,
|
|
311
|
+
amount: 0
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
const total = round(lines.reduce((sum, line) => sum + line.amount, 0));
|
|
315
|
+
return { planId: plan.id, planName: tl(...plan.name), lines, total };
|
|
316
|
+
}
|
|
317
|
+
function quoteAll(size, plans = PRICING_PLANS) {
|
|
318
|
+
return plans.map((plan) => quote(size, plan));
|
|
319
|
+
}
|
|
320
|
+
function activeModuleKeys(plugins, opts = {}) {
|
|
321
|
+
const out = [];
|
|
322
|
+
for (const plugin of plugins) {
|
|
323
|
+
if (!plugin.isActive || plugin.activationReason === "dependency") continue;
|
|
324
|
+
if (opts.offered?.length && !opts.offered.includes(plugin.id)) continue;
|
|
325
|
+
const keys = [plugin.id];
|
|
326
|
+
const facets = plugin.config?.facets ?? {};
|
|
327
|
+
for (const [facet, on] of Object.entries(facets)) if (on) keys.push(`${plugin.id}.${facet}`);
|
|
328
|
+
out.push(...opts.trades?.length ? keys.filter((k) => moduleFitsTrades(k, opts.trades)) : keys);
|
|
329
|
+
}
|
|
330
|
+
return out;
|
|
331
|
+
}
|
|
332
|
+
var FOOD_COMMERCE = ["food", "commerce"];
|
|
333
|
+
var SERVICES = ["beauty", "education"];
|
|
334
|
+
var MODULE_TRADES = {
|
|
335
|
+
orders: FOOD_COMMERCE,
|
|
336
|
+
"orders.scale": FOOD_COMMERCE,
|
|
337
|
+
"orders.delivery": FOOD_COMMERCE,
|
|
338
|
+
shop: ["commerce", "food"],
|
|
339
|
+
tables: ["food"],
|
|
340
|
+
"tables.tablets": ["food"],
|
|
341
|
+
"tables.waitlist": ["food"],
|
|
342
|
+
reservations: ["food"],
|
|
343
|
+
menu: ["food"],
|
|
344
|
+
"menu.qr_menu": ["food"],
|
|
345
|
+
production: ["food"],
|
|
346
|
+
kitchen: ["food"],
|
|
347
|
+
"inventory.costing": ["food"],
|
|
348
|
+
agenda: SERVICES,
|
|
349
|
+
"agenda.public_booking": SERVICES,
|
|
350
|
+
"agenda.smart_fit": SERVICES,
|
|
351
|
+
"agenda.kiosk": SERVICES,
|
|
352
|
+
clinical: ["beauty"],
|
|
353
|
+
scribe: ["beauty"],
|
|
354
|
+
courses: ["education"],
|
|
355
|
+
tiss: ["beauty"],
|
|
356
|
+
"pet.grooming": ["pet"],
|
|
357
|
+
"pet.vet": ["pet"],
|
|
358
|
+
"pet.lodging": ["pet"],
|
|
359
|
+
"pet.packages": ["pet"],
|
|
360
|
+
marketplaces: ["commerce"]
|
|
361
|
+
};
|
|
362
|
+
var TRADE_BY_APP = {
|
|
363
|
+
resto: "food",
|
|
364
|
+
beauty: "beauty",
|
|
365
|
+
shop: "commerce",
|
|
366
|
+
school: "education",
|
|
367
|
+
ticket: "events",
|
|
368
|
+
fiscal: "accounting",
|
|
369
|
+
full: "generic"
|
|
370
|
+
};
|
|
371
|
+
function moduleFitsTrades(key, trades) {
|
|
372
|
+
const own = MODULE_TRADES[key] ?? MODULE_TRADES[key.split(".")[0]];
|
|
373
|
+
return !own || own.some((t) => trades.includes(t));
|
|
374
|
+
}
|
|
375
|
+
function perUnitModules(modules, pkg) {
|
|
376
|
+
return billableModules(modules, pkg).filter((k) => PRICE_BOOK[k].per === "unit");
|
|
377
|
+
}
|
|
378
|
+
var SCENARIO_VERTICAL_LABELS = {
|
|
379
|
+
food: ["Food service", "Alimenta\xE7\xE3o"],
|
|
380
|
+
beauty: ["Beauty & clinics", "Beleza e cl\xEDnicas"],
|
|
381
|
+
commerce: ["Retail & e-commerce", "Varejo e loja online"],
|
|
382
|
+
generic: ["Other", "Outros"]
|
|
383
|
+
};
|
|
384
|
+
var BEAUTY_UNIT = ["agenda", "inventory", "financial", "fiscal-br", "workforce"];
|
|
385
|
+
var BEAUTY_ACCOUNT = ["crm", "marketing", "automations", "custom_forms", "reports"];
|
|
386
|
+
var RESTAURANT_UNIT = ["orders", "orders.delivery", "tables", "reservations", "menu", "menu.qr_menu", "kitchen", "inventory", "inventory.costing", "financial", "fiscal-br", "workforce"];
|
|
387
|
+
var units = (n, prefix, modules) => Array.from({ length: n }, (_, i) => ({ id: `${prefix}-${i + 1}`, name: `${"Unidade" } ${i + 1}`, modules }));
|
|
388
|
+
var PRICING_SCENARIOS = [
|
|
389
|
+
{
|
|
390
|
+
// Calibration point: a three-format restaurant group lands near R$ 1.950 on the top plan.
|
|
391
|
+
id: "restaurante-3-unidades",
|
|
392
|
+
name: ["Restaurant group, 3 units (store, dining room, dark kitchen)", "Restaurante com 3 unidades (emp\xF3rio, sal\xE3o, dark kitchen)"],
|
|
393
|
+
vertical: "food",
|
|
394
|
+
assumptions: ["Usu\xE1rios ilimitados no plano de cima; 40 pessoas com login."],
|
|
395
|
+
size: {
|
|
396
|
+
units: 3,
|
|
397
|
+
users: 40,
|
|
398
|
+
modules: ["crm", "financial", "financial.dre", "reports"],
|
|
399
|
+
unitModules: [
|
|
400
|
+
{ id: "emporio", name: "Emp\xF3rio", modules: ["orders", "orders.scale", "orders.delivery", "inventory", "inventory.purchasing", "financial", "financial.reconciliation", "fiscal-br", "workforce", "workforce.time_clock"] },
|
|
401
|
+
{ id: "salao", name: "Restaurante com sal\xE3o", modules: ["tables", "reservations", "menu", "menu.qr_menu", "orders", "orders.delivery", "production", "inventory", "inventory.costing", "financial", "fiscal-br", "workforce", "workforce.time_clock"] },
|
|
402
|
+
{ id: "dark", name: "Dark kitchen", modules: ["orders", "orders.delivery", "production", "inventory", "inventory.costing", "financial", "fiscal-br", "workforce", "workforce.time_clock"] }
|
|
403
|
+
]
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
id: "cafe",
|
|
408
|
+
name: ["Caf\xE9, 1 unit", "Caf\xE9 de 1 unidade"],
|
|
409
|
+
vertical: "food",
|
|
410
|
+
size: { units: 1, users: 4, modules: ["orders", "financial", "inventory", "fiscal-br"] }
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
id: "rede-10",
|
|
414
|
+
name: ["Restaurant network, 10 units", "Rede de restaurantes, 10 unidades"],
|
|
415
|
+
vertical: "food",
|
|
416
|
+
size: {
|
|
417
|
+
units: 10,
|
|
418
|
+
users: 120,
|
|
419
|
+
modules: ["orders", "orders.delivery", "menu", "menu.qr_menu", "production", "inventory", "inventory.costing", "financial", "financial.dre", "fiscal-br", "workforce", "workforce.time_clock", "crm", "crm.loyalty", "reports"]
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
id: "restaurante-e-servicos",
|
|
424
|
+
name: ["Restaurant + back office, 2 units", "Restaurante + escrit\xF3rio, 2 unidades"],
|
|
425
|
+
vertical: "food",
|
|
426
|
+
assumptions: ["Uma unidade com toda a opera\xE7\xE3o; a outra s\xF3 com financeiro, equipe e ponto."],
|
|
427
|
+
size: {
|
|
428
|
+
units: 2,
|
|
429
|
+
users: 25,
|
|
430
|
+
modules: ["crm", "financial", "financial.dre", "reports"],
|
|
431
|
+
unitModules: [
|
|
432
|
+
{ id: "restaurante", name: "Restaurante", modules: [...RESTAURANT_UNIT] },
|
|
433
|
+
{ id: "escritorio", name: "Escrit\xF3rio", modules: ["financial", "workforce", "workforce.time_clock"] }
|
|
434
|
+
]
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
id: "rede-estetica-60",
|
|
439
|
+
name: ["Beauty network, 60 units", "Rede de est\xE9tica, 60 unidades"],
|
|
440
|
+
vertical: "beauty",
|
|
441
|
+
assumptions: ["Todas as unidades com agenda, prontu\xE1rio, estoque, financeiro, fiscal e equipe; 6 logins por unidade."],
|
|
442
|
+
size: { units: 60, users: 360, modules: [...BEAUTY_ACCOUNT, "financial", "financial.dre"], unitModules: units(60, "u", [...BEAUTY_UNIT, "clinical"]) }
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
id: "saloes-3",
|
|
446
|
+
name: ["Salon chain, 3 units", "Rede de sal\xF5es, 3 unidades"],
|
|
447
|
+
vertical: "beauty",
|
|
448
|
+
size: { units: 3, users: 24, modules: [...BEAUTY_ACCOUNT, "financial", "financial.dre"], unitModules: units(3, "u", [...BEAUTY_UNIT]) }
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
id: "salao-1",
|
|
452
|
+
name: ["Salon, 1 unit", "Sal\xE3o de 1 unidade"],
|
|
453
|
+
vertical: "beauty",
|
|
454
|
+
size: { units: 1, users: 6, modules: [...BEAUTY_UNIT, ...BEAUTY_ACCOUNT] }
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
id: "clinica-1",
|
|
458
|
+
name: ["Aesthetic clinic, 1 unit", "Cl\xEDnica de est\xE9tica, 1 unidade"],
|
|
459
|
+
vertical: "beauty",
|
|
460
|
+
size: { units: 1, users: 5, modules: ["agenda", "clinical", "financial", "fiscal-br", "crm", "custom_forms"] }
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
id: "cozinha-loja-online",
|
|
464
|
+
name: ["Central kitchen + online store", "Cozinha central + loja online"],
|
|
465
|
+
vertical: "food",
|
|
466
|
+
size: { units: 1, users: 9, modules: ["shop", "orders", "kitchen", "inventory", "inventory.costing", "inventory.purchasing", "financial", "fiscal-br", "crm"] }
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
id: "loja-online-fisica",
|
|
470
|
+
name: ["Online store + physical store", "Loja online + loja f\xEDsica"],
|
|
471
|
+
vertical: "commerce",
|
|
472
|
+
size: {
|
|
473
|
+
units: 2,
|
|
474
|
+
users: 4,
|
|
475
|
+
modules: ["shop", "financial", "crm"],
|
|
476
|
+
unitModules: [
|
|
477
|
+
{ id: "online", name: "Loja online", modules: ["orders", "inventory", "financial"] },
|
|
478
|
+
{ id: "fisica", name: "Loja f\xEDsica", modules: ["orders", "inventory", "financial", "fiscal-br"] }
|
|
479
|
+
]
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
];
|
|
483
|
+
function pricingForPlans(plans) {
|
|
484
|
+
const tiers = PRICING_PLANS.filter((p) => p.id !== "a-la-carte");
|
|
485
|
+
const paid = plans.filter((p) => p.price > 0 && !p.pricing).sort((a, b) => a.price - b.price);
|
|
486
|
+
return plans.map((plan) => {
|
|
487
|
+
const declared = plan.entitlements?.limits?.ai_credits_month;
|
|
488
|
+
const credits = declared !== void 0 && declared >= 0 ? { aiCredits: declared } : {};
|
|
489
|
+
if (plan.pricing) return { id: plan.id, name: [plan.name, plan.name], ...plan.pricing, ...credits };
|
|
490
|
+
if (plan.price <= 0) return null;
|
|
491
|
+
const rank = paid.indexOf(plan) - paid.length + tiers.length;
|
|
492
|
+
const tier = tiers[Math.max(0, rank)];
|
|
493
|
+
return { ...tier, id: plan.id, name: [plan.name, plan.name], ...credits };
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
function aiCreditsFor(plan, pricing) {
|
|
497
|
+
const declared = plan.entitlements?.limits?.ai_credits_month;
|
|
498
|
+
if (declared !== void 0 && declared >= 0) return declared;
|
|
499
|
+
return pricing?.aiCredits ?? FREE_AI_CREDITS;
|
|
500
|
+
}
|
|
501
|
+
function planFit(plan, size) {
|
|
502
|
+
const limits = plan.entitlements?.limits ?? {};
|
|
503
|
+
const units2 = size.unitModules?.length || size.units;
|
|
504
|
+
const checks = [["locations", units2], ["users", size.users]];
|
|
505
|
+
for (const [limit, have] of checks) {
|
|
506
|
+
const max = limits[limit];
|
|
507
|
+
if (max !== void 0 && max >= 0 && have > max) return { fits: false, limit, max, have };
|
|
508
|
+
}
|
|
509
|
+
return { fits: true };
|
|
510
|
+
}
|
|
511
|
+
var DAY = 864e5;
|
|
512
|
+
function currentPeriod(now = /* @__PURE__ */ new Date()) {
|
|
513
|
+
return {
|
|
514
|
+
start: new Date(now.getFullYear(), now.getMonth(), 1),
|
|
515
|
+
end: new Date(now.getFullYear(), now.getMonth() + 1, 1)
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
function summarizeAiUsage(raw, included, now = /* @__PURE__ */ new Date(), names = {}) {
|
|
519
|
+
const { start, end } = currentPeriod(now);
|
|
520
|
+
const used = raw.byUser.reduce((sum, u) => sum + u.credits, 0);
|
|
521
|
+
const elapsedDays = Math.max(1, (now.getTime() - start.getTime()) / DAY);
|
|
522
|
+
const totalDays = Math.round((Date.UTC(end.getFullYear(), end.getMonth(), 1) - Date.UTC(start.getFullYear(), start.getMonth(), 1)) / DAY);
|
|
523
|
+
const projected = Math.round(used / elapsedDays * totalDays);
|
|
524
|
+
return {
|
|
525
|
+
used,
|
|
526
|
+
included,
|
|
527
|
+
remaining: Math.max(0, included - used),
|
|
528
|
+
ratio: included > 0 ? used / included : used > 0 ? Infinity : 0,
|
|
529
|
+
over: used > included,
|
|
530
|
+
overBy: Math.max(0, used - included),
|
|
531
|
+
periodStart: start,
|
|
532
|
+
periodEnd: end,
|
|
533
|
+
// Calendar days, so a daylight-saving hour never adds one.
|
|
534
|
+
daysLeft: Math.max(0, Math.round((Date.UTC(end.getFullYear(), end.getMonth(), end.getDate()) - Date.UTC(now.getFullYear(), now.getMonth(), now.getDate())) / DAY)),
|
|
535
|
+
projected,
|
|
536
|
+
projectedOver: projected > included,
|
|
537
|
+
byUser: [...raw.byUser].sort((a, b) => b.credits - a.credits).map((u) => ({ ...u, name: names[u.userId] ?? "Ex-integrante da equipe" })),
|
|
538
|
+
byFeature: [...raw.byFeature].sort((a, b) => b.credits - a.credits)
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
function useAiUsage(included) {
|
|
542
|
+
const tenantId = useOrganizationStore((s) => s.currentOrg?.id ?? null);
|
|
543
|
+
const members = useOrganizationStore((s) => s.members);
|
|
544
|
+
const [raw, setRaw] = React.useState(null);
|
|
545
|
+
React.useEffect(() => {
|
|
546
|
+
const supabase = getSupabaseClientOptional();
|
|
547
|
+
if (!supabase || !tenantId) {
|
|
548
|
+
setRaw("missing");
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
let alive = true;
|
|
552
|
+
const { start, end } = currentPeriod();
|
|
553
|
+
void supabase.rpc("ai_usage_summary", { p_from: start.toISOString(), p_to: end.toISOString() }).then((res) => {
|
|
554
|
+
if (!alive) return;
|
|
555
|
+
if (res.error || !res.data) {
|
|
556
|
+
setRaw("missing");
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
setRaw({
|
|
560
|
+
byUser: (res.data.by_user ?? []).map((u) => ({ userId: String(u.user_id), credits: Number(u.credits) || 0 })),
|
|
561
|
+
byFeature: (res.data.by_feature ?? []).map((f) => ({ feature: String(f.feature), credits: Number(f.credits) || 0 }))
|
|
562
|
+
});
|
|
563
|
+
});
|
|
564
|
+
return () => {
|
|
565
|
+
alive = false;
|
|
566
|
+
};
|
|
567
|
+
}, [tenantId]);
|
|
568
|
+
const names = React.useMemo(() => {
|
|
569
|
+
const out = {};
|
|
570
|
+
for (const m of members) out[m.userId] = m.user?.fullName || m.user?.email || "\u2014";
|
|
571
|
+
return out;
|
|
572
|
+
}, [members]);
|
|
573
|
+
if (raw === null) return { status: "loading" };
|
|
574
|
+
if (raw === "missing") return { status: "not-metered" };
|
|
575
|
+
const summary = summarizeAiUsage(raw, included, /* @__PURE__ */ new Date(), names);
|
|
576
|
+
return summary.used > 0 ? { status: "ok", summary } : { status: "empty", summary };
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
export { COMING_SOON_MODULES, EXTRA_AI_CREDITS, EXTRA_SEAT_PRICE, NO_TRIAL, PRICE_BOOK, PRICING_PLANS, PRICING_SCENARIOS, SCENARIO_VERTICAL_LABELS, TRADE_BY_APP, UNIT_TIERS, UPSELL_KEY, activeModuleKeys, aiCreditsFor, billableModules, currentPeriod, effectivePlan, includedIn, moduleFitsTrades, packageFor, paidPlanIds, perUnitModules, planFit, pricingForPlans, quote, quoteAll, resolveTrial, summarizeAiUsage, unitFactor, useAiUsage, useBillingStore, useTrial };
|
|
580
|
+
//# sourceMappingURL=chunk-OEY3V6J3.js.map
|
|
581
|
+
//# sourceMappingURL=chunk-OEY3V6J3.js.map
|