@taskforcehq/taskforce 0.3.305 → 0.3.307
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 +0 -2
- package/dist/Taskforce.module.css +603 -107
- package/dist/TaskforceCore.js +216 -43
- package/dist/TaskforceCore.test.js +611 -28
- package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/assets/fonts/Noir_medium.woff2 +0 -0
- package/dist/assets/fonts/Noir_regular.woff2 +0 -0
- package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/compat/workspaceSyncCompat.js +46 -2
- package/dist/compat/workspaceSyncCompat.test.js +38 -1
- package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
- package/dist/components/activity/EntityActivityTimeline.js +81 -0
- package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
- package/dist/components/context/ContextAttachmentManager.js +561 -0
- package/dist/components/features/AgentsModule.d.ts +14 -1
- package/dist/components/features/AgentsModule.js +366 -18
- package/dist/components/features/AgentsModule.test.js +507 -8
- package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
- package/dist/components/features/DocumentIndex.d.ts +2 -2
- package/dist/components/features/DocumentIndex.js +3 -4
- package/dist/components/features/DocumentViewer.d.ts +7 -1
- package/dist/components/features/DocumentViewer.js +62 -4
- package/dist/components/features/DocumentWorkspace.d.ts +10 -2
- package/dist/components/features/DocumentWorkspace.js +15 -4
- package/dist/components/features/DocumentWorkspace.test.js +51 -1
- package/dist/components/features/TaskSettings.d.ts +2 -0
- package/dist/components/features/TaskSettings.js +83 -78
- package/dist/components/features/TaskSettings.test.js +171 -82
- package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
- package/dist/components/task/TaskActionHeader.js +11 -5
- package/dist/components/task/TaskActionHeader.test.js +10 -0
- package/dist/components/task/TaskCard.js +24 -29
- package/dist/components/task/TaskCard.test.js +38 -3
- package/dist/components/task/TaskContextUpload.js +4 -526
- package/dist/components/task/TaskContextUpload.test.js +3 -3
- package/dist/components/task/TaskForm.js +61 -116
- package/dist/components/task/TaskForm.test.js +110 -8
- package/dist/components/task/TaskKanban.d.ts +2 -1
- package/dist/components/task/TaskKanban.js +94 -21
- package/dist/components/task/TaskKanban.test.js +36 -0
- package/dist/components/task/TaskList.js +5 -1
- package/dist/components/task/TaskList.test.js +4 -0
- package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
- package/dist/components/ui/EditableAvatarButton.js +18 -0
- package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
- package/dist/components/ui/HierarchyActionBadge.js +5 -0
- package/dist/components/views/AppShellHeader.d.ts +3 -1
- package/dist/components/views/AppShellHeader.js +27 -11
- package/dist/components/views/AppShellHeader.test.js +18 -1
- package/dist/components/views/PlanComparisonPage.d.ts +9 -1
- package/dist/components/views/PlanComparisonPage.js +78 -14
- package/dist/components/views/PlanComparisonPage.test.js +257 -0
- package/dist/components/views/PlansPage.js +127 -36
- package/dist/components/views/PlansPage.test.js +294 -12
- package/dist/components/views/StandaloneLayout.js +529 -592
- package/dist/components/views/WidgetView.js +10 -8
- package/dist/components/views/panels/PlanningDrawer.d.ts +25 -5
- package/dist/components/views/panels/PlanningDrawer.js +270 -55
- package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
- package/dist/components/views/panels/PlanningDrawer.test.js +529 -0
- package/dist/components/views/planningScope.d.ts +20 -0
- package/dist/components/views/planningScope.js +25 -0
- package/dist/components/views/planningScope.test.d.ts +1 -0
- package/dist/components/views/planningScope.test.js +60 -0
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
- package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
- package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
- package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
- package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
- package/dist/config/envSchema.js +1 -0
- package/dist/core/AiProfileService.d.ts +46 -2
- package/dist/core/AiProfileService.js +1073 -82
- package/dist/core/AiProfileService.test.js +19 -1
- package/dist/core/AiProfiles.test.js +1249 -44
- package/dist/core/AttachmentLinkService.d.ts +3 -0
- package/dist/core/AttachmentLinkService.js +110 -23
- package/dist/core/AuthIdentityService.d.ts +107 -0
- package/dist/core/AuthIdentityService.js +284 -0
- package/dist/core/AuthTokenService.d.ts +4 -0
- package/dist/core/AuthTokenService.js +34 -6
- package/dist/core/AuthTokenService.test.js +3 -3
- package/dist/core/EntitlementsPolicy.test.js +2 -2
- package/dist/core/GlobalSettingsService.js +127 -6
- package/dist/core/McpTokenService.d.ts +12 -0
- package/dist/core/McpTokenService.js +44 -1
- package/dist/core/PlanEntitlementService.d.ts +23 -2
- package/dist/core/PlanEntitlementService.js +343 -57
- package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
- package/dist/core/PlanFeatureCatalog.test.js +84 -0
- package/dist/core/PlanVersionPolicy.test.js +35 -2
- package/dist/core/PlanningEntities.test.js +418 -4
- package/dist/core/SignupMonetizationSettings.test.js +199 -27
- package/dist/core/SyncReconciliationService.js +2 -65
- package/dist/core/SystemAdmin.test.js +42 -42
- package/dist/core/TaskActivityService.d.ts +28 -1
- package/dist/core/TaskActivityService.js +227 -46
- package/dist/core/TaskActivitySync.test.d.ts +1 -0
- package/dist/core/TaskActivitySync.test.js +90 -0
- package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
- package/dist/core/TaskAuditTimeline.test.js +96 -0
- package/dist/core/Taskforce.d.ts +415 -40
- package/dist/core/Taskforce.ids.test.js +58 -0
- package/dist/core/Taskforce.js +1543 -266
- package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
- package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
- package/dist/core/Taskforce.mcpAuth.test.js +109 -0
- package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
- package/dist/core/WorkspaceLifecycleService.js +0 -5
- package/dist/core/WorkspacePermissions.test.js +25 -1
- package/dist/core/WorkspacePlanMode.test.js +117 -16
- package/dist/core/shared.d.ts +1 -1
- package/dist/core/shared.js +5 -1
- package/dist/core/types.d.ts +75 -2
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +28 -2
- package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
- package/dist/hooks/bootstrapTimeouts.js +8 -0
- package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
- package/dist/hooks/bootstrapTimeouts.test.js +12 -0
- package/dist/hooks/sync/bootstrap.js +2 -0
- package/dist/hooks/sync/controlPlane.d.ts +37 -0
- package/dist/hooks/sync/controlPlane.js +78 -0
- package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
- package/dist/hooks/sync/controlPlane.test.js +121 -0
- package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
- package/dist/hooks/sync/lifecyclePolicy.js +93 -0
- package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
- package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +13 -4
- package/dist/hooks/sync/orchestratorShared.js +129 -48
- package/dist/hooks/sync/orchestratorShared.test.js +50 -1
- package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
- package/dist/hooks/sync/pullLifecycle.js +24 -0
- package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
- package/dist/hooks/sync/pullLifecycle.test.js +80 -0
- package/dist/hooks/sync/recovery.d.ts +16 -2
- package/dist/hooks/sync/recovery.js +179 -53
- package/dist/hooks/sync/recovery.test.d.ts +1 -0
- package/dist/hooks/sync/recovery.test.js +292 -0
- package/dist/hooks/sync/transfers.d.ts +16 -3
- package/dist/hooks/sync/transfers.js +210 -66
- package/dist/hooks/sync/transfers.test.d.ts +1 -0
- package/dist/hooks/sync/transfers.test.js +928 -0
- package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
- package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
- package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
- package/dist/hooks/sync/useSyncStatusActions.js +88 -0
- package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
- package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
- package/dist/hooks/sync/useSyncStatusControls.js +60 -0
- package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
- package/dist/hooks/useFilterSort.js +13 -13
- package/dist/hooks/useFilterSort.test.js +87 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
- package/dist/hooks/useSyncOrchestrator.js +409 -183
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
- package/dist/hooks/useTaskData.js +8 -3
- package/dist/hooks/useTaskData.test.js +45 -0
- package/dist/hooks/useTaskforce.d.ts +145 -52
- package/dist/hooks/useTaskforce.js +592 -253
- package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.runtime-routing.test.js +246 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +2468 -201
- package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
- package/dist/hooks/useWorkspaceSyncController.js +13 -2
- package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +328 -40
- package/dist/localization/locales/en-US.d.ts +0 -1
- package/dist/localization/locales/en-US.js +0 -1
- package/dist/localization/locales/es-419.js +0 -1
- package/dist/localization/locales/pt-BR.js +0 -1
- package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
- package/dist/mcp/canonicalAssetHelpers.js +18 -10
- package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
- package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
- package/dist/mcp/clientIntegrations.d.ts +1 -0
- package/dist/mcp/clientIntegrations.js +25 -0
- package/dist/mcp/clientIntegrations.test.js +14 -3
- package/dist/mcp/clientProfileDefaults.js +3 -3
- package/dist/mcp/collaborationRegistrar.js +7 -7
- package/dist/mcp/documentAssetRegistrar.js +116 -10
- package/dist/mcp/runtime.d.ts +3 -0
- package/dist/mcp/runtime.js +1099 -185
- package/dist/mcp/runtime.test.js +1491 -140
- package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
- package/dist/mcp/taskPlanningRegistrar.js +48 -0
- package/dist/mcp/toolRegistry.d.ts +56 -0
- package/dist/mcp/toolRegistry.js +8 -0
- package/dist/mcp/toolRegistry.test.js +4 -0
- package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
- package/dist/migrations/taskSchemaMigrations.js +192 -61
- package/dist/migrations/taskSchemaMigrations.test.js +15 -0
- package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/dist/resources/templates/workflows/collaborate.yaml +1 -1
- package/dist/resources/templates/workflows/evaluate.yaml +2 -2
- package/dist/resources/templates/workflows/plan.yaml +1 -1
- package/dist/resources/templates/workflows/review.yaml +2 -2
- package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
- package/dist/server/aiProfileAvatarAssets.js +319 -0
- package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
- package/dist/server/aiProfileAvatarAssets.test.js +213 -0
- package/dist/server/annotatedAttachmentsRoutes.test.js +69 -10
- package/dist/server/auth/providers/apple.d.ts +33 -0
- package/dist/server/auth/providers/apple.js +82 -0
- package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
- package/dist/server/auth/providers/appleClientSecret.js +65 -0
- package/dist/server/auth/providers/github.d.ts +26 -0
- package/dist/server/auth/providers/github.js +86 -0
- package/dist/server/auth/providers/google.d.ts +21 -0
- package/dist/server/auth/providers/google.js +56 -0
- package/dist/server/auth/providers/types.d.ts +21 -0
- package/dist/server/auth/providers/types.js +1 -0
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.js +6 -3
- package/dist/server/documentReviewRoutes.test.js +36 -3
- package/dist/server/index.cookieProxy.test.js +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.js +124 -9
- package/dist/server/index.rateLimit.test.js +3 -0
- package/dist/server/index.test.js +111 -3
- package/dist/server/routes/admin.d.ts +3 -0
- package/dist/server/routes/admin.js +459 -28
- package/dist/server/routes/annotatedAttachments.js +51 -0
- package/dist/server/routes/auth.d.ts +26 -2
- package/dist/server/routes/auth.js +1170 -71
- package/dist/server/routes/authSupport.d.ts +5 -1
- package/dist/server/routes/authSupport.js +13 -2
- package/dist/server/routes/billing.js +372 -35
- package/dist/server/routes/billing.test.js +595 -12
- package/dist/server/routes/documents.d.ts +1 -0
- package/dist/server/routes/documents.js +182 -70
- package/dist/server/routes/shared.d.ts +28 -2
- package/dist/server/routes/shared.js +69 -14
- package/dist/server/routes/sync.integration.test.js +658 -39
- package/dist/server/routes/sync.js +74 -608
- package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
- package/dist/server/routes/syncAuxRoutes.js +91 -0
- package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
- package/dist/server/routes/syncAuxRoutes.test.js +158 -0
- package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
- package/dist/server/routes/syncPullApplyRoutes.js +204 -0
- package/dist/server/routes/syncPushRoutes.d.ts +24 -0
- package/dist/server/routes/syncPushRoutes.js +212 -0
- package/dist/server/routes/syncRouteGuards.d.ts +36 -0
- package/dist/server/routes/syncRouteGuards.js +67 -0
- package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
- package/dist/server/routes/syncRouteGuards.test.js +94 -0
- package/dist/server/routes/syncRouteTypes.d.ts +13 -0
- package/dist/server/routes/syncRouteTypes.js +1 -0
- package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
- package/dist/server/routes/syncSnapshotRoutes.js +182 -0
- package/dist/server/routes/tasks.js +55 -10
- package/dist/server/routes/workspaces.js +36 -5
- package/dist/server/routes.js +147 -11
- package/dist/server/routes.test.js +2704 -183
- package/dist/services/workflowExportSnapshots.test.js +2 -0
- package/dist/shared/aiProfileSeatScope.d.ts +5 -0
- package/dist/shared/aiProfileSeatScope.js +21 -0
- package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
- package/dist/shared/aiProfileSurfaceType.js +10 -8
- package/dist/shared/passwordPolicy.d.ts +13 -0
- package/dist/shared/passwordPolicy.js +84 -0
- package/dist/shared/passwordPolicy.test.d.ts +1 -0
- package/dist/shared/passwordPolicy.test.js +34 -0
- package/dist/storage/objectStorage.d.ts +1 -0
- package/dist/storage/objectStorage.js +2 -1
- package/dist/storage/objectStorageClient.d.ts +1 -0
- package/dist/storage/objectStorageClient.js +41 -8
- package/dist/storage/objectStorageClient.test.js +26 -1
- package/dist/storage/objectStorageConfig.js +3 -1
- package/dist/storage/objectStorageConfig.test.js +13 -1
- package/dist/storage/workspaceAssetStore.d.ts +15 -3
- package/dist/storage/workspaceAssetStore.js +132 -44
- package/dist/storage/workspaceAssetStore.test.js +93 -6
- package/dist/styles/fonts.css +70 -0
- package/dist/sync/collaborationSyncPayload.d.ts +6 -1
- package/dist/sync/collaborationSyncPayload.js +19 -11
- package/dist/sync/collaborationSyncPayload.test.js +14 -1
- package/dist/sync/collaborationSyncState.d.ts +3 -3
- package/dist/sync/collaborationSyncState.js +19 -12
- package/dist/sync/contentSyncPayload.d.ts +5 -1
- package/dist/sync/contentSyncPayload.js +9 -0
- package/dist/sync/contentSyncPayload.test.js +39 -0
- package/dist/sync/contentSyncState.d.ts +9 -9
- package/dist/sync/contentSyncState.js +248 -107
- package/dist/sync/planningSyncPayload.js +5 -0
- package/dist/sync/planningSyncPayload.test.js +24 -0
- package/dist/sync/syncApplyHandlers.d.ts +11 -4
- package/dist/sync/syncApplyHandlers.js +115 -42
- package/dist/sync/syncApplyHandlers.test.js +251 -4
- package/dist/sync/syncFieldSemantics.d.ts +12 -0
- package/dist/sync/syncFieldSemantics.js +55 -0
- package/dist/sync/syncResourceAdapters.d.ts +46 -0
- package/dist/sync/syncResourceAdapters.js +79 -0
- package/dist/sync/syncService.d.ts +6 -0
- package/dist/sync/syncService.js +65 -1
- package/dist/sync/syncService.test.js +96 -3
- package/dist/sync/taskSyncChangeKey.d.ts +2 -0
- package/dist/sync/taskSyncChangeKey.js +143 -0
- package/dist/sync/taskSyncPayload.js +3 -8
- package/dist/sync/workspacePullFeed.d.ts +4 -0
- package/dist/sync/workspacePullFeed.js +132 -72
- package/dist/sync/workspacePullFeed.test.js +92 -0
- package/dist/sync/workspaceRepair.js +5 -2
- package/dist/sync/workspaceSyncModel.d.ts +73 -6
- package/dist/sync/workspaceSyncModel.js +342 -73
- package/dist/sync/workspaceSyncModel.test.js +559 -14
- package/dist/sync/workspaceSyncState.d.ts +17 -0
- package/dist/sync/workspaceSyncState.js +2 -1
- package/dist/sync/workspaceSyncSurface.js +3 -8
- package/dist/types.d.ts +50 -2
- package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
- package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
- package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
- package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
- package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
- package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
- package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
- package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-D4XseTwW.js} +1 -1
- package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
- package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
- package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
- package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
- package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
- package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
- package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
- package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-oOA9bcdK.js} +4 -4
- package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
- package/dist/ui/assets/index-607WPo_X.js +4 -0
- package/dist/ui/assets/index-CYyodXsg.css +1 -0
- package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-B32hGuF2.js} +1 -1
- package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/ui/fonts/Noir_medium.otf +0 -0
- package/dist/ui/fonts/Noir_medium.woff2 +0 -0
- package/dist/ui/fonts/Noir_regular.otf +0 -0
- package/dist/ui/fonts/Noir_regular.woff2 +0 -0
- package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/ui/index.html +3 -3
- package/dist/ui/product/agent manager.png +0 -0
- package/dist/ui/product/agent_manager_02.png +0 -0
- package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
- package/dist/utils/aiProfileEvents.d.ts +7 -0
- package/dist/utils/aiProfileEvents.js +6 -0
- package/dist/utils/assignees.d.ts +8 -0
- package/dist/utils/assignees.js +10 -1
- package/dist/utils/assignees.test.d.ts +1 -0
- package/dist/utils/assignees.test.js +25 -0
- package/dist/utils/avatarDisplay.d.ts +1 -0
- package/dist/utils/avatarDisplay.js +15 -0
- package/dist/utils/avatarUpload.d.ts +27 -0
- package/dist/utils/avatarUpload.js +132 -0
- package/dist/utils/avatarUpload.test.d.ts +1 -0
- package/dist/utils/avatarUpload.test.js +40 -0
- package/dist/utils/bootstrapTrace.d.ts +7 -0
- package/dist/utils/bootstrapTrace.js +29 -0
- package/dist/utils/commercialLifecyclePresentation.js +3 -0
- package/dist/utils/contextAssetEvents.d.ts +2 -0
- package/dist/utils/contextFiles.d.ts +3 -1
- package/dist/utils/contextFiles.js +2 -1
- package/dist/utils/syncEventDetails.d.ts +3 -0
- package/dist/utils/syncEventDetails.js +64 -0
- package/dist/utils/syncEventDetails.test.d.ts +1 -0
- package/dist/utils/syncEventDetails.test.js +23 -0
- package/dist/utils/syncEventPresentation.d.ts +15 -0
- package/dist/utils/syncEventPresentation.js +129 -0
- package/dist/utils/syncEventPresentation.test.d.ts +1 -0
- package/dist/utils/syncEventPresentation.test.js +64 -0
- package/dist/utils/syncStatusPresentation.d.ts +72 -0
- package/dist/utils/syncStatusPresentation.js +217 -0
- package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
- package/dist/utils/syncStatusPresentation.test.js +164 -0
- package/dist/utils/taskActivity.d.ts +9 -1
- package/dist/utils/taskActivity.js +290 -22
- package/dist/utils/taskActivity.test.js +141 -8
- package/dist/utils/taskSearch.d.ts +22 -0
- package/dist/utils/taskSearch.js +87 -0
- package/dist/utils/taskSearch.test.d.ts +1 -0
- package/dist/utils/taskSearch.test.js +69 -0
- package/dist/utils/taskUtils.js +10 -3
- package/dist/utils/taskUtils.test.d.ts +1 -0
- package/dist/utils/taskUtils.test.js +19 -0
- package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
- package/dist/utils/workspaceSyncPresentation.js +68 -2
- package/dist/utils/workspaceSyncPresentation.test.js +36 -1
- package/package.json +3 -2
- package/scripts/export-sqlite-to-postgres.mjs +7 -9
- package/scripts/run-e2e-realtime.sh +17 -3
- package/scripts/run-smoke.sh +17 -5
- package/scripts/run-soak.sh +17 -5
- package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/src/resources/templates/workflows/collaborate.yaml +1 -1
- package/src/resources/templates/workflows/evaluate.yaml +2 -2
- package/src/resources/templates/workflows/plan.yaml +1 -1
- package/src/resources/templates/workflows/review.yaml +2 -2
- package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BG6P_GVW.js +0 -3
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
- package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
- package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
- package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
- package/dist/ui/assets/TaskSettings-ln0aF7xc.js +0 -9
- package/dist/ui/assets/index-C2-OXZV7.css +0 -1
- package/dist/ui/assets/index-DcSI5F86.js +0 -6
- package/scripts/migrate-planning-model.ts +0 -233
|
@@ -9,6 +9,8 @@ describe('PlanComparisonPage', () => {
|
|
|
9
9
|
vi.stubGlobal('fetch', vi.fn(async () => ({
|
|
10
10
|
ok: true,
|
|
11
11
|
json: async () => ({
|
|
12
|
+
pageTitle: 'Subscription Plans',
|
|
13
|
+
pageDescription: 'Manage your subscription and explore available features. Your current plan is highlighted below.',
|
|
12
14
|
pricingSource: {
|
|
13
15
|
environment: 'production',
|
|
14
16
|
runtimeMode: 'cloud'
|
|
@@ -17,6 +19,7 @@ describe('PlanComparisonPage', () => {
|
|
|
17
19
|
{
|
|
18
20
|
planId: 'free',
|
|
19
21
|
displayName: 'Free',
|
|
22
|
+
description: 'Start using Taskforce at no cost.',
|
|
20
23
|
status: 'active',
|
|
21
24
|
defaultVersion: {
|
|
22
25
|
planVersionId: 'free-v1',
|
|
@@ -33,6 +36,7 @@ describe('PlanComparisonPage', () => {
|
|
|
33
36
|
{
|
|
34
37
|
planId: 'team-5',
|
|
35
38
|
displayName: 'Team 5',
|
|
39
|
+
description: 'For small collaborative teams.',
|
|
36
40
|
status: 'active',
|
|
37
41
|
defaultVersion: {
|
|
38
42
|
planVersionId: 'team-5-v2',
|
|
@@ -59,6 +63,28 @@ describe('PlanComparisonPage', () => {
|
|
|
59
63
|
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
|
|
60
64
|
expect(await screen.findByText('Pricing source: production (cloud)')).toBeInTheDocument();
|
|
61
65
|
});
|
|
66
|
+
it('renders plan descriptions when provided by the pricing payload', async () => {
|
|
67
|
+
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
|
|
68
|
+
expect(await screen.findByText('Start using Taskforce at no cost.')).toBeInTheDocument();
|
|
69
|
+
expect(screen.getByText('For small collaborative teams.')).toBeInTheDocument();
|
|
70
|
+
});
|
|
71
|
+
it('prefers pricing payload header copy when provided', async () => {
|
|
72
|
+
vi.stubGlobal('fetch', vi.fn(async () => ({
|
|
73
|
+
ok: true,
|
|
74
|
+
json: async () => ({
|
|
75
|
+
pageTitle: 'Choose Your Taskforce Plan',
|
|
76
|
+
pageDescription: 'Compare plans and pick the right fit for your team.',
|
|
77
|
+
pricingSource: {
|
|
78
|
+
environment: 'production',
|
|
79
|
+
runtimeMode: 'cloud'
|
|
80
|
+
},
|
|
81
|
+
plans: []
|
|
82
|
+
})
|
|
83
|
+
})));
|
|
84
|
+
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", subtitle: "Fallback subtitle", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
|
|
85
|
+
expect(await screen.findByRole('heading', { name: 'Choose Your Taskforce Plan' })).toBeInTheDocument();
|
|
86
|
+
expect(screen.getByText('Compare plans and pick the right fit for your team.')).toBeInTheDocument();
|
|
87
|
+
});
|
|
62
88
|
it('falls back to provided pricing source details when the pricing response omits them', async () => {
|
|
63
89
|
globalThis.__DEBUG_MODE__ = true;
|
|
64
90
|
vi.stubGlobal('fetch', vi.fn(async () => ({
|
|
@@ -92,6 +118,188 @@ describe('PlanComparisonPage', () => {
|
|
|
92
118
|
await screen.findByRole('heading', { name: 'Subscription Plans' });
|
|
93
119
|
expect(screen.queryByText('Pricing source: production (cloud)')).not.toBeInTheDocument();
|
|
94
120
|
});
|
|
121
|
+
it('renders public feature copy when provided by the pricing payload', async () => {
|
|
122
|
+
vi.stubGlobal('fetch', vi.fn(async () => ({
|
|
123
|
+
ok: true,
|
|
124
|
+
json: async () => ({
|
|
125
|
+
pricingSource: {
|
|
126
|
+
environment: 'production',
|
|
127
|
+
runtimeMode: 'cloud'
|
|
128
|
+
},
|
|
129
|
+
plans: [
|
|
130
|
+
{
|
|
131
|
+
planId: 'team-5',
|
|
132
|
+
displayName: 'Team 5',
|
|
133
|
+
status: 'active',
|
|
134
|
+
defaultVersion: {
|
|
135
|
+
planVersionId: 'team-5-v2',
|
|
136
|
+
versionNumber: 2,
|
|
137
|
+
seatLimit: 5,
|
|
138
|
+
metadata: {}
|
|
139
|
+
},
|
|
140
|
+
features: [
|
|
141
|
+
{
|
|
142
|
+
featureKey: 'collaboration.ai_profiles',
|
|
143
|
+
access: 'enabled',
|
|
144
|
+
label: 'AI Profiles',
|
|
145
|
+
publicLabel: 'AI teammates',
|
|
146
|
+
publicDescription: 'Add reusable AI teammates to your workspace.'
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
pricing: {
|
|
150
|
+
month: { pricingType: 'stripe', stripePriceId: 'price_team_5_month', unitAmount: 2000, currency: 'usd', interval: 'month' },
|
|
151
|
+
year: null
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
})
|
|
156
|
+
})));
|
|
157
|
+
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
|
|
158
|
+
expect(await screen.findByText('AI teammates')).toBeInTheDocument();
|
|
159
|
+
expect(screen.getByText('Add reusable AI teammates to your workspace.')).toBeInTheDocument();
|
|
160
|
+
expect(screen.queryByText('Collaboration Ai Profiles')).not.toBeInTheDocument();
|
|
161
|
+
});
|
|
162
|
+
it('renders inline numeric feature limits next to each feature label', async () => {
|
|
163
|
+
vi.stubGlobal('fetch', vi.fn(async () => ({
|
|
164
|
+
ok: true,
|
|
165
|
+
json: async () => ({
|
|
166
|
+
pricingSource: {
|
|
167
|
+
environment: 'production',
|
|
168
|
+
runtimeMode: 'cloud'
|
|
169
|
+
},
|
|
170
|
+
plans: [
|
|
171
|
+
{
|
|
172
|
+
planId: 'free',
|
|
173
|
+
displayName: 'Free',
|
|
174
|
+
status: 'active',
|
|
175
|
+
defaultVersion: {
|
|
176
|
+
planVersionId: 'free-v1',
|
|
177
|
+
versionNumber: 1,
|
|
178
|
+
seatLimit: 12,
|
|
179
|
+
metadata: {}
|
|
180
|
+
},
|
|
181
|
+
features: [
|
|
182
|
+
{
|
|
183
|
+
featureKey: 'workspace.workspaces',
|
|
184
|
+
access: 'enabled',
|
|
185
|
+
label: 'Workspaces',
|
|
186
|
+
config: { maxWorkspaces: 1 }
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
featureKey: 'collaboration.ai_profiles',
|
|
190
|
+
access: 'limited',
|
|
191
|
+
label: 'AI Profiles',
|
|
192
|
+
publicLabel: 'AI Agents',
|
|
193
|
+
config: { maxAiProfiles: 4 }
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
featureKey: 'context.uploads',
|
|
197
|
+
access: 'enabled',
|
|
198
|
+
label: 'Cloud Storage',
|
|
199
|
+
config: { storageLimitMb: 24 }
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
featureKey: 'collaboration.team_management',
|
|
203
|
+
access: 'enabled',
|
|
204
|
+
label: 'Team Management'
|
|
205
|
+
}
|
|
206
|
+
],
|
|
207
|
+
pricing: {
|
|
208
|
+
month: { pricingType: 'free', stripePriceId: null, unitAmount: null, currency: null, interval: 'month' },
|
|
209
|
+
year: null
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
})
|
|
214
|
+
})));
|
|
215
|
+
const { container } = render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
|
|
216
|
+
const freeCard = await screen.findByTestId('plan-card-free');
|
|
217
|
+
const featureTextNodes = Array.from(freeCard.querySelectorAll('span')).map((node) => node.textContent);
|
|
218
|
+
expect(featureTextNodes).toContain('1x Workspaces');
|
|
219
|
+
expect(featureTextNodes).toContain('4x AI Agents');
|
|
220
|
+
expect(featureTextNodes).toContain('24MB Cloud Storage');
|
|
221
|
+
expect(featureTextNodes).toContain('12x Team Management');
|
|
222
|
+
expect(container.querySelector('[class*="featureLimitUnit"]')?.textContent).toBe('MB');
|
|
223
|
+
});
|
|
224
|
+
it('renders the storage unit suffix in a smaller accent span', async () => {
|
|
225
|
+
vi.stubGlobal('fetch', vi.fn(async () => ({
|
|
226
|
+
ok: true,
|
|
227
|
+
json: async () => ({
|
|
228
|
+
pricingSource: {
|
|
229
|
+
environment: 'production',
|
|
230
|
+
runtimeMode: 'cloud'
|
|
231
|
+
},
|
|
232
|
+
plans: [
|
|
233
|
+
{
|
|
234
|
+
planId: 'free',
|
|
235
|
+
displayName: 'Free',
|
|
236
|
+
status: 'active',
|
|
237
|
+
defaultVersion: {
|
|
238
|
+
planVersionId: 'free-v1',
|
|
239
|
+
versionNumber: 1,
|
|
240
|
+
seatLimit: null,
|
|
241
|
+
metadata: {}
|
|
242
|
+
},
|
|
243
|
+
features: [
|
|
244
|
+
{
|
|
245
|
+
featureKey: 'context.uploads',
|
|
246
|
+
access: 'enabled',
|
|
247
|
+
label: 'Cloud Storage',
|
|
248
|
+
config: { storageLimitMb: 64 }
|
|
249
|
+
}
|
|
250
|
+
],
|
|
251
|
+
pricing: {
|
|
252
|
+
month: { pricingType: 'free', stripePriceId: null, unitAmount: null, currency: null, interval: 'month' },
|
|
253
|
+
year: null
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
})
|
|
258
|
+
})));
|
|
259
|
+
const { container } = render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
|
|
260
|
+
await screen.findByText('Cloud Storage');
|
|
261
|
+
const accent = container.querySelector('[class*="featureLimitAccent"]');
|
|
262
|
+
const unit = container.querySelector('[class*="featureLimitUnit"]');
|
|
263
|
+
expect(accent?.textContent).toBe('64MB');
|
|
264
|
+
expect(unit?.textContent).toBe('MB');
|
|
265
|
+
});
|
|
266
|
+
it('hides missing yearly pricing rows and buttons instead of rendering unavailable state', async () => {
|
|
267
|
+
vi.stubGlobal('fetch', vi.fn(async () => ({
|
|
268
|
+
ok: true,
|
|
269
|
+
json: async () => ({
|
|
270
|
+
pricingSource: {
|
|
271
|
+
environment: 'production',
|
|
272
|
+
runtimeMode: 'cloud'
|
|
273
|
+
},
|
|
274
|
+
plans: [
|
|
275
|
+
{
|
|
276
|
+
planId: 'operator',
|
|
277
|
+
displayName: 'Operator',
|
|
278
|
+
status: 'active',
|
|
279
|
+
defaultVersion: {
|
|
280
|
+
planVersionId: 'operator-v1',
|
|
281
|
+
versionNumber: 1,
|
|
282
|
+
seatLimit: null,
|
|
283
|
+
metadata: {}
|
|
284
|
+
},
|
|
285
|
+
features: [],
|
|
286
|
+
pricing: {
|
|
287
|
+
month: { pricingType: 'stripe', stripePriceId: 'price_operator_month', unitAmount: 999, currency: 'usd', interval: 'month' },
|
|
288
|
+
year: null
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
})
|
|
293
|
+
})));
|
|
294
|
+
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
|
|
295
|
+
const operatorCard = await screen.findByTestId('plan-card-operator');
|
|
296
|
+
expect(within(operatorCard).getByText('$9.99')).toBeInTheDocument();
|
|
297
|
+
expect(within(operatorCard).getByText('/ month')).toBeInTheDocument();
|
|
298
|
+
expect(within(operatorCard).queryByText('/ year')).not.toBeInTheDocument();
|
|
299
|
+
expect(within(operatorCard).queryByText('Unavailable')).not.toBeInTheDocument();
|
|
300
|
+
expect(within(operatorCard).getByRole('button', { name: 'Choose Monthly' })).toBeInTheDocument();
|
|
301
|
+
expect(within(operatorCard).queryByRole('button', { name: 'Choose Yearly' })).not.toBeInTheDocument();
|
|
302
|
+
});
|
|
95
303
|
it('does not mark a plan current when only the plan id matches but the version does not', async () => {
|
|
96
304
|
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: "team-5-v1", currentEntitlementState: "active", onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
|
|
97
305
|
expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
@@ -102,15 +310,64 @@ describe('PlanComparisonPage', () => {
|
|
|
102
310
|
expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
103
311
|
expect(screen.getByText('Current Plan')).toBeInTheDocument();
|
|
104
312
|
});
|
|
313
|
+
it('can show the current plan as a non-interactive indicator when billing is managed from page chrome', async () => {
|
|
314
|
+
const onSelectPlan = vi.fn();
|
|
315
|
+
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: "team-5-v2", currentEntitlementState: "active", canManageCurrentPlan: true, currentPlanCardActionMode: "indicator", onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
|
|
316
|
+
expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
317
|
+
const currentCard = screen.getByTestId('plan-card-team-5');
|
|
318
|
+
expect(currentCard).not.toHaveAttribute('role', 'button');
|
|
319
|
+
expect(screen.queryByTestId('plan-manage-team-5')).not.toBeInTheDocument();
|
|
320
|
+
expect(screen.queryByRole('button', { name: 'Manage Plan' })).not.toBeInTheDocument();
|
|
321
|
+
expect(screen.getByTestId('plan-current-team-5')).toBeDisabled();
|
|
322
|
+
fireEvent.click(currentCard);
|
|
323
|
+
expect(onSelectPlan).not.toHaveBeenCalled();
|
|
324
|
+
});
|
|
325
|
+
it('can render the page header bar even when shell chrome is present', async () => {
|
|
326
|
+
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, chrome: _jsx("div", { children: "Shell chrome" }), showHeaderBarWithChrome: true, topActions: _jsx("button", { type: "button", children: "Manage billing" }), onBack: () => { }, backLabel: "Back to App", onSelectPlan: () => { } }));
|
|
327
|
+
expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
328
|
+
expect(screen.getByRole('button', { name: 'Back to App' })).toBeInTheDocument();
|
|
329
|
+
expect(screen.getByRole('button', { name: 'Manage billing' })).toBeInTheDocument();
|
|
330
|
+
});
|
|
105
331
|
it('does not mark a canceled entitlement as current through the plan-id fallback path', async () => {
|
|
106
332
|
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: null, currentEntitlementState: "canceled", onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
|
|
107
333
|
expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
108
334
|
expect(screen.queryByText('Current Plan')).not.toBeInTheDocument();
|
|
109
335
|
});
|
|
336
|
+
it('does not mark a linked pending-plan-selection entitlement as the current plan', async () => {
|
|
337
|
+
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: "team-5-v2", currentEntitlementState: "pending_plan_selection", canManageCurrentPlan: true, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
|
|
338
|
+
expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
339
|
+
expect(screen.queryByRole('button', { name: 'Manage Plan' })).not.toBeInTheDocument();
|
|
340
|
+
expect(screen.queryByText('Current Plan')).not.toBeInTheDocument();
|
|
341
|
+
expect(screen.getByRole('button', { name: 'Choose Monthly' })).toBeInTheDocument();
|
|
342
|
+
});
|
|
110
343
|
it('can disable the page back button while onboarding remains blocked', async () => {
|
|
111
344
|
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, onBack: () => { }, backLabel: "Back to App", backDisabled: true, onSelectPlan: () => { } }));
|
|
112
345
|
expect(await screen.findByRole('button', { name: 'Back to App' })).toBeDisabled();
|
|
113
346
|
});
|
|
347
|
+
it('shows pricing before auth resolves but keeps plan selection disabled until bootstrap finishes', async () => {
|
|
348
|
+
const onSelectPlan = vi.fn();
|
|
349
|
+
const view = render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, authSessionResolved: false, onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
|
|
350
|
+
expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
|
|
351
|
+
const freeCard = screen.getByTestId('plan-card-free');
|
|
352
|
+
expect(screen.getByRole('button', { name: 'Get Started Free' })).toBeDisabled();
|
|
353
|
+
expect(screen.getByRole('button', { name: 'Get Started Monthly' })).toBeDisabled();
|
|
354
|
+
expect(freeCard).not.toHaveAttribute('role', 'button');
|
|
355
|
+
view.rerender(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, authSessionResolved: true, onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
|
|
356
|
+
const enabledFreeCard = screen.getByTestId('plan-card-free');
|
|
357
|
+
expect(screen.getByRole('button', { name: 'Get Started Free' })).toBeEnabled();
|
|
358
|
+
expect(screen.getByRole('button', { name: 'Get Started Monthly' })).toBeEnabled();
|
|
359
|
+
expect(enabledFreeCard).toHaveAttribute('role', 'button');
|
|
360
|
+
fireEvent.click(screen.getByRole('button', { name: 'Get Started Free' }));
|
|
361
|
+
await waitFor(() => {
|
|
362
|
+
expect(onSelectPlan).toHaveBeenCalledWith({
|
|
363
|
+
planId: 'free',
|
|
364
|
+
planVersionId: 'free-v1',
|
|
365
|
+
interval: 'month',
|
|
366
|
+
pricingType: 'free',
|
|
367
|
+
isCurrentPlan: false
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
});
|
|
114
371
|
it('selects the whole plan card using the default available interval', async () => {
|
|
115
372
|
const onSelectPlan = vi.fn();
|
|
116
373
|
render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { useLocation, useNavigate } from 'react-router-dom';
|
|
4
4
|
import { User } from 'lucide-react';
|
|
@@ -9,16 +9,29 @@ import { resolveTaskforceCloudEnvironmentFromBaseUrl } from '../../config/cloudE
|
|
|
9
9
|
import { ACCOUNT_PROFILE_SUMMARY_PATH, invalidateAccountProfileSummaryCache, loadAccountProfileSummaryCached } from '../../utils/accountProfileSummaryCache';
|
|
10
10
|
import { isCommercialEntitlementActive, resolveCommercialLifecyclePresentation } from '../../utils/commercialLifecyclePresentation';
|
|
11
11
|
const TRANSIENT_CHECKOUT_QUERY_CLEAR_DELAY_MS = 1600;
|
|
12
|
-
const
|
|
12
|
+
const CHECKOUT_CONFIRM_INITIAL_RETRY_DELAYS_MS = [0, 500, 1000, 2000];
|
|
13
|
+
const CHECKOUT_CONFIRM_RETRY_INTERVAL_MS = 5000;
|
|
14
|
+
const CHECKOUT_CONFIRM_MAX_AUTO_RETRY_MS = 45000;
|
|
15
|
+
const HIDDEN_GATE_MESSAGE = 'Choose a plan to continue.';
|
|
13
16
|
function shouldRetryCheckoutConfirmation(statusCode, errorCode) {
|
|
14
17
|
if (statusCode === 401) {
|
|
15
18
|
return true;
|
|
16
19
|
}
|
|
17
|
-
|
|
20
|
+
const normalizedErrorCode = String(errorCode || '').trim().toUpperCase();
|
|
21
|
+
return normalizedErrorCode === 'CHECKOUT_SESSION_INCOMPLETE'
|
|
22
|
+
|| normalizedErrorCode === 'CHECKOUT_PLAN_VERSION_UNRESOLVED';
|
|
18
23
|
}
|
|
19
24
|
function parseInterval(raw) {
|
|
20
25
|
return raw === 'year' ? 'year' : 'month';
|
|
21
26
|
}
|
|
27
|
+
function normalizeIntervalValue(raw) {
|
|
28
|
+
const normalized = String(raw || '').trim().toLowerCase();
|
|
29
|
+
if (normalized === 'year')
|
|
30
|
+
return 'year';
|
|
31
|
+
if (normalized === 'month')
|
|
32
|
+
return 'month';
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
22
35
|
function normalizeApiBaseUrl(raw) {
|
|
23
36
|
const trimmed = String(raw || '').trim();
|
|
24
37
|
if (!trimmed)
|
|
@@ -40,16 +53,19 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
40
53
|
const location = useLocation();
|
|
41
54
|
const [accountProfileSummary, setAccountProfileSummary] = useState(null);
|
|
42
55
|
const [actionBusy, setActionBusy] = useState(false);
|
|
56
|
+
const [continueActionBusy, setContinueActionBusy] = useState(false);
|
|
43
57
|
const [feedback, setFeedback] = useState(null);
|
|
44
58
|
const checkoutStartRan = useRef(false);
|
|
45
|
-
const
|
|
59
|
+
const checkoutSuccessSettledRef = useRef(null);
|
|
46
60
|
const transientQueryClearTimeoutRef = useRef(null);
|
|
61
|
+
const onContinueToTaskforceRef = useRef(onContinueToTaskforce);
|
|
47
62
|
const query = useMemo(() => new URLSearchParams(location.search), [location.search]);
|
|
48
63
|
const checkoutState = String(query.get('checkout') || '').trim().toLowerCase();
|
|
49
64
|
const gateState = String(query.get('gate') || '').trim().toLowerCase();
|
|
50
65
|
const queryPlanId = String(query.get('planId') || '').trim();
|
|
51
66
|
const queryPlanVersionId = String(query.get('planVersionId') || '').trim();
|
|
52
67
|
const queryInterval = parseInterval(query.get('interval'));
|
|
68
|
+
const queryIntervalValue = normalizeIntervalValue(query.get('interval'));
|
|
53
69
|
const querySessionId = String(query.get('session_id') || '').trim();
|
|
54
70
|
const normalizedApiBaseUrl = useMemo(() => normalizeApiBaseUrl(apiBaseUrl), [apiBaseUrl]);
|
|
55
71
|
const normalizedConnectedEnvironmentSource = useMemo(() => normalizeApiBaseUrl(connectedEnvironmentSource), [connectedEnvironmentSource]);
|
|
@@ -80,16 +96,15 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
80
96
|
const nextQuery = params.toString();
|
|
81
97
|
navigate(`/${nextQuery ? `?${nextQuery}` : ''}${location.hash || ''}`);
|
|
82
98
|
}, [location.hash, location.search, navigate]);
|
|
83
|
-
const
|
|
84
|
-
const endpoints = [
|
|
85
|
-
normalizedApiBaseUrl ? `${normalizedApiBaseUrl}/api/taskforce/public/pricing` : '',
|
|
86
|
-
'/api/taskforce/public/pricing'
|
|
87
|
-
].map((value) => String(value || '').trim()).filter((value, index, all) => value && all.indexOf(value) === index);
|
|
88
|
-
return endpoints;
|
|
89
|
-
}, [normalizedApiBaseUrl]);
|
|
99
|
+
const pricingEndpoint = useMemo(() => buildCloudBillingUrl('/api/taskforce/public/pricing'), [buildCloudBillingUrl]);
|
|
90
100
|
const lifecyclePresentation = useMemo(() => resolveCommercialLifecyclePresentation(accountProfileSummary, gateState), [accountProfileSummary, gateState]);
|
|
91
101
|
const hasResolvedActiveEntitlement = useMemo(() => lifecyclePresentation.allowReturnToApp, [lifecyclePresentation.allowReturnToApp]);
|
|
92
|
-
const gateMessage = useMemo(() =>
|
|
102
|
+
const gateMessage = useMemo(() => {
|
|
103
|
+
const message = String(lifecyclePresentation.message || '').trim();
|
|
104
|
+
if (!message || message === HIDDEN_GATE_MESSAGE)
|
|
105
|
+
return null;
|
|
106
|
+
return message;
|
|
107
|
+
}, [lifecyclePresentation.message]);
|
|
93
108
|
const clearTransientQueryState = useCallback(() => {
|
|
94
109
|
const next = new URLSearchParams(location.search);
|
|
95
110
|
next.delete('checkout');
|
|
@@ -110,6 +125,9 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
110
125
|
transientQueryClearTimeoutRef.current = null;
|
|
111
126
|
}, TRANSIENT_CHECKOUT_QUERY_CLEAR_DELAY_MS);
|
|
112
127
|
}, [clearTransientQueryState]);
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
onContinueToTaskforceRef.current = onContinueToTaskforce;
|
|
130
|
+
}, [onContinueToTaskforce]);
|
|
113
131
|
const loadAccountProfileSummary = useCallback(async (options) => {
|
|
114
132
|
const accountProfileSummaryUrl = buildCloudBillingUrl(ACCOUNT_PROFILE_SUMMARY_PATH);
|
|
115
133
|
if (!isAuthenticated) {
|
|
@@ -131,11 +149,14 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
131
149
|
return null;
|
|
132
150
|
}
|
|
133
151
|
}, [authUserId, buildCloudBillingUrl, isAuthenticated, onAccountProfileSummaryChange]);
|
|
134
|
-
const resolveRecoveryMessage = useCallback((summary, fallback) => {
|
|
152
|
+
const resolveRecoveryMessage = useCallback((summary, fallback, options) => {
|
|
153
|
+
const normalizedFallback = String(fallback || '').trim();
|
|
154
|
+
if (options?.preferFallback && normalizedFallback)
|
|
155
|
+
return normalizedFallback;
|
|
135
156
|
const message = resolveCommercialLifecyclePresentation(summary, gateState).message;
|
|
136
157
|
if (message)
|
|
137
158
|
return message;
|
|
138
|
-
return
|
|
159
|
+
return normalizedFallback || 'Unable to confirm checkout completion.';
|
|
139
160
|
}, [gateState]);
|
|
140
161
|
const shouldAutoContinueAfterActivation = useCallback((summary, fallbackGate) => {
|
|
141
162
|
return !resolveCommercialLifecyclePresentation(summary, fallbackGate).allowReturnToApp;
|
|
@@ -226,6 +247,47 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
226
247
|
retryable: false
|
|
227
248
|
};
|
|
228
249
|
}
|
|
250
|
+
const confirmViaSummary = async () => {
|
|
251
|
+
invalidateAccountProfileSummaryCache(buildCloudBillingUrl(ACCOUNT_PROFILE_SUMMARY_PATH), { identityKey: authUserId });
|
|
252
|
+
const summary = await loadAccountProfileSummary({ force: true });
|
|
253
|
+
const summaryState = String(summary?.entitlementState || '').trim().toLowerCase();
|
|
254
|
+
if (!isCommercialEntitlementActive(summaryState)) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
const expectedPlanId = queryPlanId;
|
|
258
|
+
const expectedPlanVersionId = queryPlanVersionId;
|
|
259
|
+
const expectedInterval = queryIntervalValue;
|
|
260
|
+
const currentPlanId = String(summary?.planId || '').trim();
|
|
261
|
+
const currentPlanVersionId = String(summary?.planVersionId || '').trim();
|
|
262
|
+
const currentInterval = normalizeIntervalValue(summary?.billingInterval ?? null);
|
|
263
|
+
const preSummary = options?.preConfirmationSummary ?? null;
|
|
264
|
+
const preState = String(preSummary?.entitlementState || '').trim().toLowerCase();
|
|
265
|
+
const preWasActive = isCommercialEntitlementActive(preState);
|
|
266
|
+
const prePlanId = String(preSummary?.planId || '').trim();
|
|
267
|
+
const prePlanVersionId = String(preSummary?.planVersionId || '').trim();
|
|
268
|
+
const preInterval = normalizeIntervalValue(preSummary?.billingInterval ?? null);
|
|
269
|
+
if (expectedPlanId && currentPlanId && currentPlanId !== expectedPlanId) {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
if (expectedPlanVersionId && currentPlanVersionId && currentPlanVersionId !== expectedPlanVersionId) {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
if (expectedInterval && currentInterval && currentInterval !== expectedInterval) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
if (preWasActive) {
|
|
279
|
+
const requestedPlanChanged = Boolean(expectedPlanId) && currentPlanId === expectedPlanId && prePlanId !== currentPlanId;
|
|
280
|
+
const requestedPlanVersionChanged = Boolean(expectedPlanVersionId) && currentPlanVersionId === expectedPlanVersionId && prePlanVersionId !== currentPlanVersionId;
|
|
281
|
+
const requestedIntervalChanged = Boolean(expectedInterval) && currentInterval === expectedInterval && preInterval !== currentInterval;
|
|
282
|
+
if (!requestedPlanChanged && !requestedPlanVersionChanged && !requestedIntervalChanged) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (options?.autoContinueOnActivation === true) {
|
|
287
|
+
await onContinueToTaskforceRef.current?.();
|
|
288
|
+
}
|
|
289
|
+
return true;
|
|
290
|
+
};
|
|
229
291
|
try {
|
|
230
292
|
const res = await fetch(buildCloudBillingUrl('/api/taskforce/billing/checkout-session/confirm'), {
|
|
231
293
|
method: 'POST',
|
|
@@ -236,17 +298,18 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
236
298
|
const payload = await res.json().catch(() => ({}));
|
|
237
299
|
if (!res.ok) {
|
|
238
300
|
const errorCode = String(payload?.code || '').trim();
|
|
301
|
+
const retryable = shouldRetryCheckoutConfirmation(res.status, errorCode);
|
|
302
|
+
if (retryable && await confirmViaSummary()) {
|
|
303
|
+
return { confirmed: true };
|
|
304
|
+
}
|
|
239
305
|
return {
|
|
240
306
|
confirmed: false,
|
|
241
307
|
errorMessage: String(payload?.error || 'Unable to confirm checkout completion.'),
|
|
242
|
-
retryable
|
|
308
|
+
retryable
|
|
243
309
|
};
|
|
244
310
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const summaryState = String(summary?.entitlementState || '').trim().toLowerCase();
|
|
248
|
-
if (options?.autoContinueOnActivation === true && isCommercialEntitlementActive(summaryState)) {
|
|
249
|
-
await onContinueToTaskforce?.();
|
|
311
|
+
if (await confirmViaSummary()) {
|
|
312
|
+
return { confirmed: true };
|
|
250
313
|
}
|
|
251
314
|
return { confirmed: true };
|
|
252
315
|
}
|
|
@@ -257,14 +320,14 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
257
320
|
retryable: true
|
|
258
321
|
};
|
|
259
322
|
}
|
|
260
|
-
}, [authUserId, buildCloudBillingUrl, loadAccountProfileSummary,
|
|
323
|
+
}, [authUserId, buildCloudBillingUrl, loadAccountProfileSummary, queryIntervalValue, queryPlanId, queryPlanVersionId]);
|
|
261
324
|
const openBillingPortal = useCallback(async () => {
|
|
262
325
|
if (!isAuthenticated) {
|
|
263
326
|
navigate(`/login?mode=login&next=${encodeURIComponent(buildEmbeddedPlansPath())}`);
|
|
264
327
|
return;
|
|
265
328
|
}
|
|
266
329
|
setActionBusy(true);
|
|
267
|
-
setFeedback(
|
|
330
|
+
setFeedback({ type: 'info', message: 'Opening billing portal...' });
|
|
268
331
|
try {
|
|
269
332
|
const res = await fetch(buildCloudBillingUrl('/api/taskforce/billing/portal-session'), {
|
|
270
333
|
method: 'POST',
|
|
@@ -289,6 +352,17 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
289
352
|
setActionBusy(false);
|
|
290
353
|
}
|
|
291
354
|
}, [buildCloudBillingUrl, isAuthenticated, navigate]);
|
|
355
|
+
const handleContinueToTaskforce = useCallback(async () => {
|
|
356
|
+
if (!onContinueToTaskforce || continueActionBusy || continueBusy)
|
|
357
|
+
return;
|
|
358
|
+
setContinueActionBusy(true);
|
|
359
|
+
try {
|
|
360
|
+
await onContinueToTaskforce();
|
|
361
|
+
}
|
|
362
|
+
finally {
|
|
363
|
+
setContinueActionBusy(false);
|
|
364
|
+
}
|
|
365
|
+
}, [continueActionBusy, continueBusy, onContinueToTaskforce]);
|
|
292
366
|
useEffect(() => {
|
|
293
367
|
void loadAccountProfileSummary();
|
|
294
368
|
}, [loadAccountProfileSummary]);
|
|
@@ -306,7 +380,7 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
306
380
|
}, []);
|
|
307
381
|
useEffect(() => {
|
|
308
382
|
if (checkoutState !== 'success') {
|
|
309
|
-
|
|
383
|
+
checkoutSuccessSettledRef.current = null;
|
|
310
384
|
}
|
|
311
385
|
}, [checkoutState]);
|
|
312
386
|
useEffect(() => {
|
|
@@ -326,7 +400,8 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
326
400
|
if (checkoutState === 'success') {
|
|
327
401
|
checkoutStartRan.current = true;
|
|
328
402
|
setFeedback({ type: 'success', message: 'Checkout completed successfully. Finalizing your plan...' });
|
|
329
|
-
|
|
403
|
+
const shouldWaitForAuthBootstrap = !isAuthenticated && !authSessionResolved;
|
|
404
|
+
if (shouldWaitForAuthBootstrap) {
|
|
330
405
|
return () => {
|
|
331
406
|
cancelled = true;
|
|
332
407
|
pendingRetryTimeouts.forEach((timeoutId) => window.clearTimeout(timeoutId));
|
|
@@ -342,33 +417,40 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
342
417
|
};
|
|
343
418
|
}
|
|
344
419
|
const successFlowKey = querySessionId || '__missing_session__';
|
|
345
|
-
if (
|
|
420
|
+
if (checkoutSuccessSettledRef.current === successFlowKey) {
|
|
346
421
|
return () => {
|
|
347
422
|
cancelled = true;
|
|
348
423
|
pendingRetryTimeouts.forEach((timeoutId) => window.clearTimeout(timeoutId));
|
|
349
424
|
pendingRetryTimeouts.clear();
|
|
350
425
|
};
|
|
351
426
|
}
|
|
352
|
-
checkoutSuccessHandledRef.current = successFlowKey;
|
|
353
427
|
void (async () => {
|
|
428
|
+
const autoConfirmStartedAt = Date.now();
|
|
354
429
|
const preConfirmationSummary = await loadAccountProfileSummary({ force: true });
|
|
355
430
|
if (cancelled)
|
|
356
431
|
return;
|
|
357
432
|
let confirmation = querySessionId
|
|
358
433
|
? { confirmed: false, errorMessage: 'Unable to confirm checkout completion.', retryable: true }
|
|
359
434
|
: { confirmed: false, errorMessage: 'Checkout session is missing.', retryable: false };
|
|
360
|
-
|
|
435
|
+
let attemptIndex = 0;
|
|
436
|
+
while (true) {
|
|
437
|
+
const delayMs = attemptIndex < CHECKOUT_CONFIRM_INITIAL_RETRY_DELAYS_MS.length
|
|
438
|
+
? CHECKOUT_CONFIRM_INITIAL_RETRY_DELAYS_MS[attemptIndex]
|
|
439
|
+
: CHECKOUT_CONFIRM_RETRY_INTERVAL_MS;
|
|
440
|
+
attemptIndex += 1;
|
|
361
441
|
await waitForRetry(delayMs);
|
|
362
442
|
if (cancelled)
|
|
363
443
|
return;
|
|
364
444
|
confirmation = querySessionId
|
|
365
445
|
? await confirmCheckoutSession(querySessionId, {
|
|
366
|
-
autoContinueOnActivation: shouldAutoContinueAfterActivation(preConfirmationSummary, gateState)
|
|
446
|
+
autoContinueOnActivation: shouldAutoContinueAfterActivation(preConfirmationSummary, gateState),
|
|
447
|
+
preConfirmationSummary
|
|
367
448
|
})
|
|
368
449
|
: { confirmed: false, errorMessage: 'Checkout session is missing.', retryable: false };
|
|
369
450
|
if (cancelled)
|
|
370
451
|
return;
|
|
371
452
|
if (confirmation.confirmed) {
|
|
453
|
+
checkoutSuccessSettledRef.current = successFlowKey;
|
|
372
454
|
setFeedback({ type: 'success', message: 'Checkout completed successfully.' });
|
|
373
455
|
scheduleTransientQueryClear();
|
|
374
456
|
return;
|
|
@@ -376,6 +458,9 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
376
458
|
if (!confirmation.retryable) {
|
|
377
459
|
break;
|
|
378
460
|
}
|
|
461
|
+
if ((Date.now() - autoConfirmStartedAt) >= CHECKOUT_CONFIRM_MAX_AUTO_RETRY_MS) {
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
379
464
|
}
|
|
380
465
|
if (cancelled)
|
|
381
466
|
return;
|
|
@@ -383,11 +468,18 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
383
468
|
const summary = await loadAccountProfileSummary({ force: true });
|
|
384
469
|
if (cancelled)
|
|
385
470
|
return;
|
|
471
|
+
if (!confirmation.retryable) {
|
|
472
|
+
checkoutSuccessSettledRef.current = successFlowKey;
|
|
473
|
+
}
|
|
386
474
|
setFeedback({
|
|
387
475
|
type: 'error',
|
|
388
|
-
message: resolveRecoveryMessage(summary, confirmation.errorMessage
|
|
476
|
+
message: resolveRecoveryMessage(summary, confirmation.errorMessage, {
|
|
477
|
+
preferFallback: !confirmation.retryable
|
|
478
|
+
})
|
|
389
479
|
});
|
|
390
|
-
|
|
480
|
+
if (!confirmation.retryable) {
|
|
481
|
+
scheduleTransientQueryClear();
|
|
482
|
+
}
|
|
391
483
|
return;
|
|
392
484
|
}
|
|
393
485
|
})();
|
|
@@ -464,7 +556,7 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
464
556
|
}, [accountProfileSummary, gateState, isAuthenticated, navigate, openBillingPortal, shouldAutoContinueAfterActivation, startCheckout]);
|
|
465
557
|
const handleBack = useCallback(() => {
|
|
466
558
|
if (hasResolvedActiveEntitlement && onContinueToTaskforce) {
|
|
467
|
-
void
|
|
559
|
+
void handleContinueToTaskforce();
|
|
468
560
|
return;
|
|
469
561
|
}
|
|
470
562
|
if (embedded) {
|
|
@@ -476,9 +568,8 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
|
|
|
476
568
|
return;
|
|
477
569
|
}
|
|
478
570
|
navigate('/');
|
|
479
|
-
}, [closeEmbeddedPlansScreen, embedded, hasResolvedActiveEntitlement, navigate, onContinueToTaskforce]);
|
|
480
|
-
const
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
return (_jsx(PlanComparisonPage, { chrome: chrome, heading: "Subscription Plans", subtitle: "Manage your subscription and explore available features. Your current plan is highlighted below.", isAuthenticated: isAuthenticated, authSessionResolved: authSessionResolved, currentPlanId: String(accountProfileSummary?.planId || queryPlanId || '').trim() || null, currentPlanVersionId: String(accountProfileSummary?.planVersionId || queryPlanVersionId || '').trim() || null, currentEntitlementState: String(accountProfileSummary?.entitlementState || '').trim() || null, canManageCurrentPlan: Boolean(accountProfileSummary?.stripeCustomerId), pricingEndpoint: pricingEndpoints[0], statusBanner: feedback, onBack: handleBack, backLabel: hasResolvedActiveEntitlement ? 'Take Me to Taskforce' : (embedded ? 'Back to Board' : 'Back to App'), backDisabled: continueBusy || (isAuthenticated && !hasResolvedActiveEntitlement), topActions: embedded ? topActions : null, shellOwnsScroll: shellOwnsScroll, showPageBackButton: !embedded, fallbackPricingSource: fallbackPricingSource, onSelectPlan: handleSelectPlan }));
|
|
571
|
+
}, [closeEmbeddedPlansScreen, embedded, handleContinueToTaskforce, hasResolvedActiveEntitlement, navigate, onContinueToTaskforce]);
|
|
572
|
+
const headerActions = embedded ? null : (_jsxs(_Fragment, { children: [_jsx("button", { className: styles.navAction, onClick: handleBack, disabled: continueBusy || continueActionBusy || (isAuthenticated && !hasResolvedActiveEntitlement), children: hasResolvedActiveEntitlement ? 'Take Me to Taskforce' : 'Back' }), isAuthenticated && accountProfileSummary?.stripeCustomerId && (_jsx("button", { className: styles.navAction, onClick: () => { void openBillingPortal(); }, disabled: actionBusy, children: "Manage billing" })), !isAuthenticated && (_jsxs("button", { className: styles.navAction, onClick: () => navigate(`/login?mode=login&next=${encodeURIComponent(buildEmbeddedPlansPath())}`), children: [_jsx(User, { size: 16, style: { marginRight: '8px', verticalAlign: 'text-bottom' } }), "Sign In"] }))] }));
|
|
573
|
+
const chrome = embedded ? null : (_jsx(AppShellHeader, { projectName: projectName, currentWorkspaceId: currentWorkspaceId, runtimeMode: runtimeMode === 'cloud' ? 'cloud' : 'local', theme: currentTheme, onBrandClick: handleBack, actions: headerActions }));
|
|
574
|
+
return (_jsx(PlanComparisonPage, { chrome: chrome, heading: "Subscription Plans", subtitle: "Manage your subscription and explore available features. Your current plan is highlighted below.", isAuthenticated: isAuthenticated, authSessionResolved: authSessionResolved, currentPlanId: String(accountProfileSummary?.planId || queryPlanId || '').trim() || null, currentPlanVersionId: String(accountProfileSummary?.planVersionId || queryPlanVersionId || '').trim() || null, currentEntitlementState: String(accountProfileSummary?.entitlementState || '').trim() || null, markCurrentPlan: lifecyclePresentation.markCurrentPlan, canManageCurrentPlan: Boolean(accountProfileSummary?.stripeCustomerId), pricingEndpoint: pricingEndpoint, statusBanner: feedback, onBack: handleBack, backLabel: hasResolvedActiveEntitlement ? 'Take Me to Taskforce' : (embedded ? 'Back to Board' : 'Back to App'), backDisabled: continueBusy || continueActionBusy || (isAuthenticated && !hasResolvedActiveEntitlement), topActions: null, shellOwnsScroll: shellOwnsScroll, showPageBackButton: false, showHeaderBarWithChrome: false, currentPlanCardActionMode: "manage", fallbackPricingSource: fallbackPricingSource, onSelectPlan: handleSelectPlan }));
|
|
484
575
|
}
|