@burdenoff/microfe-workspaces 2026.520.1 → 2026.529.1
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/WorkspacesRoot.js +4 -1
- package/dist/WorkspacesRoot.js.map +1 -1
- package/dist/WorkspacesRoutes.js +4 -4
- package/dist/WorkspacesRoutes.js.map +1 -1
- package/dist/components/CreateProjectDialog.js +1 -1
- package/dist/components/CreateProjectDialog.js.map +1 -1
- package/dist/components/CreateWorkspaceDialog.js +2 -2
- package/dist/components/CreateWorkspaceDialog.js.map +1 -1
- package/dist/components/InviteMemberDialog.js +2 -2
- package/dist/components/InviteMemberDialog.js.map +1 -1
- package/dist/components/MemberListItem.js +71 -86
- package/dist/components/MemberListItem.js.map +1 -1
- package/dist/components/ProjectCard.js +12 -10
- package/dist/components/ProjectCard.js.map +1 -1
- package/dist/components/WorkspaceCard.js.map +1 -1
- package/dist/components/WorkspacesErrorBoundary.js +12 -4
- package/dist/components/WorkspacesErrorBoundary.js.map +1 -1
- package/dist/components/tags/ProjectTagsWidget.js +248 -0
- package/dist/components/tags/ProjectTagsWidget.js.map +1 -0
- package/dist/hooks/useOrgsWithPermission.js +1 -1
- package/dist/hooks/useOrgsWithPermission.js.map +1 -1
- package/dist/hooks/useWorkspacesEventEmitter.js.map +1 -1
- package/dist/hooks/useWorkspacesPageView.js +6 -4
- package/dist/hooks/useWorkspacesPageView.js.map +1 -1
- package/dist/pages/CreateWorkspacePage.js +239 -224
- package/dist/pages/CreateWorkspacePage.js.map +1 -1
- package/dist/pages/InviteAcceptancePage.js +28 -28
- package/dist/pages/InviteAcceptancePage.js.map +1 -1
- package/dist/pages/MembersListPage.js +380 -352
- package/dist/pages/MembersListPage.js.map +1 -1
- package/dist/pages/ProjectDetailPage.js +96 -97
- package/dist/pages/ProjectDetailPage.js.map +1 -1
- package/dist/pages/ProjectsListPage.js +307 -304
- package/dist/pages/ProjectsListPage.js.map +1 -1
- package/dist/pages/WorkspaceSettingsPage.js +94 -91
- package/dist/pages/WorkspaceSettingsPage.js.map +1 -1
- package/dist/pages/WorkspacesListPage.js +1 -1
- package/dist/pages/WorkspacesListPage.js.map +1 -1
- package/dist/pages/dashboard/DashboardCustomizer.js +68 -68
- package/dist/pages/dashboard/DashboardCustomizer.js.map +1 -1
- package/dist/pages/dashboard/DashboardGrid.js +52 -41
- package/dist/pages/dashboard/DashboardGrid.js.map +1 -1
- package/dist/pages/dashboard/DashboardPage.js +74 -65
- package/dist/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/pages/dashboard/WidgetWrapper.js +3 -3
- package/dist/pages/dashboard/WidgetWrapper.js.map +1 -1
- package/dist/pages/dashboard/config.js +126 -30
- package/dist/pages/dashboard/config.js.map +1 -1
- package/dist/pages/dashboard/hooks/useDashboardData.js +39 -2
- package/dist/pages/dashboard/hooks/useDashboardData.js.map +1 -1
- package/dist/pages/dashboard/widgets/AgentsWidget.js +109 -0
- package/dist/pages/dashboard/widgets/AgentsWidget.js.map +1 -0
- package/dist/pages/dashboard/widgets/GroupsWidget.js +6 -5
- package/dist/pages/dashboard/widgets/GroupsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/MembersWidget.js +6 -6
- package/dist/pages/dashboard/widgets/MembersWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/ProjectsWidget.js +8 -7
- package/dist/pages/dashboard/widgets/ProjectsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/QuickActionsWidget.js +72 -18
- package/dist/pages/dashboard/widgets/QuickActionsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/RecentActivityWidget.js +3 -3
- package/dist/pages/dashboard/widgets/RecentActivityWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/SessionsWidget.js +78 -0
- package/dist/pages/dashboard/widgets/SessionsWidget.js.map +1 -0
- package/dist/pages/dashboard/widgets/StorageWidget.js +35 -20
- package/dist/pages/dashboard/widgets/StorageWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/TagCloudWidget.js +2 -2
- package/dist/pages/dashboard/widgets/TagCloudWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/TipsWidget.js +81 -22
- package/dist/pages/dashboard/widgets/TipsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/UpcomingEventsWidget.js +6 -5
- package/dist/pages/dashboard/widgets/UpcomingEventsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/VibesWidget.js +64 -0
- package/dist/pages/dashboard/widgets/VibesWidget.js.map +1 -0
- package/dist/pages/dashboard/widgets/WelcomeWidget.js +5 -5
- package/dist/pages/dashboard/widgets/WelcomeWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js +3 -3
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WorkspacesWidget.js +6 -5
- package/dist/pages/dashboard/widgets/WorkspacesWidget.js.map +1 -1
- package/dist/providers/WorkspacesProvider.js +1 -1
- package/dist/providers/WorkspacesProvider.js.map +1 -1
- package/dist/store/workspacesStore.js.map +1 -1
- package/dist/utils/formatters.js +21 -16
- package/dist/utils/formatters.js.map +1 -1
- package/dist/utils/telemetryError.js +1 -1
- package/dist/utils/telemetryError.js.map +1 -1
- package/package.json +7 -7
- package/dist/WorkspacesRoot.d.ts +0 -35
- package/dist/WorkspacesRoot.d.ts.map +0 -1
- package/dist/WorkspacesRoutes.d.ts +0 -10
- package/dist/WorkspacesRoutes.d.ts.map +0 -1
- package/dist/components/CreateProjectDialog.d.ts +0 -6
- package/dist/components/CreateProjectDialog.d.ts.map +0 -1
- package/dist/components/CreateWorkspaceDialog.d.ts +0 -2
- package/dist/components/CreateWorkspaceDialog.d.ts.map +0 -1
- package/dist/components/InviteMemberDialog.d.ts +0 -7
- package/dist/components/InviteMemberDialog.d.ts.map +0 -1
- package/dist/components/MemberListItem.d.ts +0 -11
- package/dist/components/MemberListItem.d.ts.map +0 -1
- package/dist/components/ProjectCard.d.ts +0 -13
- package/dist/components/ProjectCard.d.ts.map +0 -1
- package/dist/components/WorkspaceCard.d.ts +0 -8
- package/dist/components/WorkspaceCard.d.ts.map +0 -1
- package/dist/components/WorkspacesErrorBoundary.d.ts +0 -27
- package/dist/components/WorkspacesErrorBoundary.d.ts.map +0 -1
- package/dist/components/index.d.ts +0 -8
- package/dist/components/index.d.ts.map +0 -1
- package/dist/constants/permissions.d.ts +0 -33
- package/dist/constants/permissions.d.ts.map +0 -1
- package/dist/generated/global-operations.d.ts +0 -319
- package/dist/generated/global-operations.d.ts.map +0 -1
- package/dist/generated/global-types.d.ts +0 -23527
- package/dist/generated/global-types.d.ts.map +0 -1
- package/dist/generated/wspace-operations.d.ts +0 -2300
- package/dist/generated/wspace-operations.d.ts.map +0 -1
- package/dist/generated/wspace-types.d.ts +0 -57851
- package/dist/generated/wspace-types.d.ts.map +0 -1
- package/dist/hooks/index.d.ts +0 -8
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/useMemberMutations.d.ts +0 -61
- package/dist/hooks/useMemberMutations.d.ts.map +0 -1
- package/dist/hooks/useOrgsWithPermission.d.ts +0 -7
- package/dist/hooks/useOrgsWithPermission.d.ts.map +0 -1
- package/dist/hooks/useProjectMutations.d.ts +0 -26
- package/dist/hooks/useProjectMutations.d.ts.map +0 -1
- package/dist/hooks/useProjects.d.ts +0 -16
- package/dist/hooks/useProjects.d.ts.map +0 -1
- package/dist/hooks/useScopedNavigation.d.ts +0 -4
- package/dist/hooks/useScopedNavigation.d.ts.map +0 -1
- package/dist/hooks/useTenants.d.ts +0 -13
- package/dist/hooks/useTenants.d.ts.map +0 -1
- package/dist/hooks/useWorkspaceActivity.d.ts +0 -12
- package/dist/hooks/useWorkspaceActivity.d.ts.map +0 -1
- package/dist/hooks/useWorkspaceMembers.d.ts +0 -24
- package/dist/hooks/useWorkspaceMembers.d.ts.map +0 -1
- package/dist/hooks/useWorkspaceMutations.d.ts +0 -36
- package/dist/hooks/useWorkspaceMutations.d.ts.map +0 -1
- package/dist/hooks/useWorkspacePermissions.d.ts +0 -29
- package/dist/hooks/useWorkspacePermissions.d.ts.map +0 -1
- package/dist/hooks/useWorkspaceRoles.d.ts +0 -8
- package/dist/hooks/useWorkspaceRoles.d.ts.map +0 -1
- package/dist/hooks/useWorkspaces.d.ts +0 -21
- package/dist/hooks/useWorkspaces.d.ts.map +0 -1
- package/dist/hooks/useWorkspacesEventEmitter.d.ts +0 -18
- package/dist/hooks/useWorkspacesEventEmitter.d.ts.map +0 -1
- package/dist/hooks/useWorkspacesPageView.d.ts +0 -27
- package/dist/hooks/useWorkspacesPageView.d.ts.map +0 -1
- package/dist/index.d.ts +0 -33
- package/dist/index.d.ts.map +0 -1
- package/dist/pages/ActivityListPage.d.ts +0 -2
- package/dist/pages/ActivityListPage.d.ts.map +0 -1
- package/dist/pages/CreateWorkspacePage.d.ts +0 -2
- package/dist/pages/CreateWorkspacePage.d.ts.map +0 -1
- package/dist/pages/InviteAcceptancePage.d.ts +0 -6
- package/dist/pages/InviteAcceptancePage.d.ts.map +0 -1
- package/dist/pages/MembersListPage.d.ts +0 -2
- package/dist/pages/MembersListPage.d.ts.map +0 -1
- package/dist/pages/ProjectDetailPage.d.ts +0 -2
- package/dist/pages/ProjectDetailPage.d.ts.map +0 -1
- package/dist/pages/ProjectsListPage.d.ts +0 -2
- package/dist/pages/ProjectsListPage.d.ts.map +0 -1
- package/dist/pages/WorkspaceDetailPage.d.ts +0 -2
- package/dist/pages/WorkspaceDetailPage.d.ts.map +0 -1
- package/dist/pages/WorkspaceSettingsPage.d.ts +0 -2
- package/dist/pages/WorkspaceSettingsPage.d.ts.map +0 -1
- package/dist/pages/WorkspacesListPage.d.ts +0 -2
- package/dist/pages/WorkspacesListPage.d.ts.map +0 -1
- package/dist/pages/dashboard/DashboardCustomizer.d.ts +0 -12
- package/dist/pages/dashboard/DashboardCustomizer.d.ts.map +0 -1
- package/dist/pages/dashboard/DashboardGrid.d.ts +0 -8
- package/dist/pages/dashboard/DashboardGrid.d.ts.map +0 -1
- package/dist/pages/dashboard/DashboardPage.d.ts +0 -14
- package/dist/pages/dashboard/DashboardPage.d.ts.map +0 -1
- package/dist/pages/dashboard/WidgetWrapper.d.ts +0 -17
- package/dist/pages/dashboard/WidgetWrapper.d.ts.map +0 -1
- package/dist/pages/dashboard/config.d.ts +0 -9
- package/dist/pages/dashboard/config.d.ts.map +0 -1
- package/dist/pages/dashboard/hooks/useDashboardData.d.ts +0 -9
- package/dist/pages/dashboard/hooks/useDashboardData.d.ts.map +0 -1
- package/dist/pages/dashboard/hooks/useDashboardPreferences.d.ts +0 -4
- package/dist/pages/dashboard/hooks/useDashboardPreferences.d.ts.map +0 -1
- package/dist/pages/dashboard/types.d.ts +0 -145
- package/dist/pages/dashboard/types.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/GroupsWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/GroupsWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/MembersWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/MembersWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/ProjectsWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/ProjectsWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/QuickActionsWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/QuickActionsWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/RecentActivityWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/RecentActivityWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/StorageWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/StorageWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/SystemHealthWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/SystemHealthWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/SystemHealthWidget.js +0 -59
- package/dist/pages/dashboard/widgets/SystemHealthWidget.js.map +0 -1
- package/dist/pages/dashboard/widgets/TagCloudWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/TagCloudWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/TipsWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/TipsWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/UpcomingEventsWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/UpcomingEventsWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/WelcomeWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/WelcomeWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.d.ts.map +0 -1
- package/dist/pages/dashboard/widgets/WorkspacesWidget.d.ts +0 -4
- package/dist/pages/dashboard/widgets/WorkspacesWidget.d.ts.map +0 -1
- package/dist/providers/WorkspacesProvider.d.ts +0 -13
- package/dist/providers/WorkspacesProvider.d.ts.map +0 -1
- package/dist/store/workspacesStore.d.ts +0 -82
- package/dist/store/workspacesStore.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -280
- package/dist/types/index.d.ts.map +0 -1
- package/dist/utils/formatters.d.ts +0 -60
- package/dist/utils/formatters.d.ts.map +0 -1
- package/dist/utils/i18n.d.ts +0 -13
- package/dist/utils/i18n.d.ts.map +0 -1
- package/dist/utils/index.d.ts +0 -3
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/nativeBridge.d.ts +0 -3
- package/dist/utils/nativeBridge.d.ts.map +0 -1
- package/dist/utils/projectTags.d.ts +0 -6
- package/dist/utils/projectTags.d.ts.map +0 -1
- package/dist/utils/slug.d.ts +0 -13
- package/dist/utils/slug.d.ts.map +0 -1
- package/dist/utils/telemetryError.d.ts +0 -2
- package/dist/utils/telemetryError.d.ts.map +0 -1
- package/dist/utils/tokenHelpers.d.ts +0 -114
- package/dist/utils/tokenHelpers.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateWorkspacePage.js","names":[],"sources":["../../src/pages/CreateWorkspacePage.tsx"],"sourcesContent":["import { useEffect, useMemo } from 'react';\nimport { ArrowLeft, AlertCircle } from 'lucide-react';\nimport { Link, useNavigate } from 'react-router-dom';\nimport {\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useForm, z } from '@burdenoff/fe-libs/form';\nimport { AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useCreateWorkspace } from '../hooks/useWorkspaceMutations';\nimport { useMyTenants, useMyOrganizations } from '../hooks/useTenants';\nimport { useOrgsWithPermission } from '../hooks/useOrgsWithPermission';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\nimport { generateSlug } from '../utils/slug';\nimport { tWithFallback } from '../utils/i18n';\n\ntype CreateWorkspaceFormData = {\n name: string;\n slug: string;\n tenantId: string;\n organizationId: string;\n type?: 'TEAM' | 'PERSONAL';\n};\n\nexport function CreateWorkspacePage() {\n useWorkspacesPageView('workspaces.create');\n const { t } = useI18n();\n const createWorkspaceSchema = useMemo(\n () =>\n z.object({\n name: z\n .string()\n .min(\n 2,\n tWithFallback(\n t,\n 'createWorkspace.validation.nameMin',\n 'Name must be at least 2 characters'\n )\n )\n .max(100),\n slug: z\n .string()\n .min(\n 2,\n tWithFallback(\n t,\n 'createWorkspace.validation.slugMin',\n 'Slug must be at least 2 characters'\n )\n )\n .max(50)\n .regex(\n /^[a-z0-9-]+$/,\n tWithFallback(\n t,\n 'createWorkspace.validation.slugFormat',\n 'Slug can only contain lowercase letters, numbers, and hyphens'\n )\n ),\n tenantId: z\n .string()\n .min(\n 1,\n tWithFallback(t, 'createWorkspace.validation.tenantRequired', 'Please select a tenant')\n ),\n organizationId: z\n .string()\n .min(\n 1,\n tWithFallback(\n t,\n 'createWorkspace.validation.organizationRequired',\n 'Please select an organization'\n )\n ),\n type: z.enum(['TEAM', 'PERSONAL']).optional(),\n }),\n [t]\n );\n\n const navigate = useNavigate();\n const { basePath = '/' } = useWorkspacesContext();\n const { mutate: createWorkspace, isPending } = useCreateWorkspace();\n const { data: tenantsData, isLoading: isLoadingTenants, error: tenantsError } = useMyTenants();\n const {\n data: organizationsData,\n isLoading: isLoadingOrganizations,\n error: organizationsError,\n } = useMyOrganizations();\n\n const tenants = tenantsData?.items ?? [];\n const allOrganizations = organizationsData?.items ?? [];\n\n const defaultTenantId = useMemo(() => {\n const sharedTenant = tenants.find(\n (tenant) => tenant.type === 'SHARED' || tenant.slug === 'burdenoff-shared'\n );\n return sharedTenant?.id ?? tenants[0]?.id ?? '';\n }, [tenants]);\n\n const form = useForm<CreateWorkspaceFormData>({\n schema: createWorkspaceSchema,\n defaultValues: {\n name: '',\n slug: '',\n tenantId: '',\n organizationId: '',\n type: 'TEAM',\n },\n });\n\n const selectedTenantId = form.watch('tenantId');\n const workspaceName = form.watch('name');\n\n // Check workspace:create permission across ALL the user's orgs up front\n // (bulk-checked in a single rbac round-trip). This is the authoritative\n // gate — only orgs where the user can actually create a workspace make\n // it into the dropdown, and the page can decisively render the \"no\n // permissions anywhere\" state once the check resolves.\n const allOrgIds = useMemo(() => allOrganizations.map((o) => o.id), [allOrganizations]);\n const {\n allowedIds: workspaceCreateAllowedOrgIds,\n loading: isCheckingOrgPermissions,\n isError: orgPermissionsHadError,\n } = useOrgsWithPermission(allOrgIds, 'workspace', 'create');\n\n // Filter organizations by selected tenant AND permission. When the rbac\n // permission lookup errored we deliberately skip the permission filter\n // (see `orgPermissionsHadError` block below) — the gateway @rbac\n // directive on `createWorkspace` is the authoritative gate, so it's\n // safer to let the user pick from the full tenant list and hit a 403 on\n // submit than to lock them out of a flow they actually have access to.\n const tenantOrganizations = useMemo(() => {\n if (!selectedTenantId) return [];\n return allOrganizations.filter((org) => org.tenantId === selectedTenantId);\n }, [selectedTenantId, allOrganizations]);\n const filteredOrganizations = useMemo(() => {\n if (orgPermissionsHadError) return tenantOrganizations;\n return tenantOrganizations.filter((org) => workspaceCreateAllowedOrgIds.has(org.id));\n }, [tenantOrganizations, workspaceCreateAllowedOrgIds, orgPermissionsHadError]);\n\n // Auto-generate slug from name (clear when name is empty)\n useEffect(() => {\n form.setValue('slug', workspaceName ? generateSlug(workspaceName) : '');\n }, [workspaceName, form]);\n\n // Reset organizationId when tenant changes\n useEffect(() => {\n form.setValue('organizationId', '');\n }, [selectedTenantId, form]);\n\n useEffect(() => {\n if (!form.getValues('tenantId') && defaultTenantId) {\n form.setValue('tenantId', defaultTenantId, {\n shouldDirty: false,\n shouldTouch: false,\n });\n }\n }, [defaultTenantId, form]);\n\n useEffect(() => {\n const currentOrganizationId = form.getValues('organizationId');\n const hasCurrentOrganization = filteredOrganizations.some(\n (organization) => organization.id === currentOrganizationId\n );\n\n if (!hasCurrentOrganization && filteredOrganizations[0]?.id) {\n form.setValue('organizationId', filteredOrganizations[0].id, {\n shouldDirty: false,\n shouldTouch: false,\n });\n }\n }, [filteredOrganizations, form]);\n\n const onSubmit = (data: CreateWorkspaceFormData) => {\n createWorkspace(\n {\n name: data.name,\n slug: data.slug,\n tenantId: data.tenantId,\n organizationId: data.organizationId,\n type: data.type,\n },\n {\n onSuccess: (newWorkspace) => {\n // Navigate to the new workspace\n navigate(`${basePath}/${newWorkspace.id}`);\n },\n }\n );\n };\n\n // `workspace:create` is an org-scoped permission. Page-level `PermissionGate`\n // resolved at the outer shell scope and incorrectly denied users who *do*\n // have the permission inside at least one of their orgs. The authoritative\n // gate now lives on the org dropdown (only orgs where the user has\n // workspace:create are listed via useOrgsWithPermission) and on the gateway\n // @rbac directive enforcing the createWorkspace mutation. We still want a\n // clear \"you can't create anywhere\" empty state — once tenants and org\n // permission lookups have settled, if no org is eligible we render it.\n // The AccessDenied empty-state should ONLY render when we know with\n // certainty that the user has no creatable org. That requires:\n // 1. tenants + organizations queries both succeeded (otherwise an\n // empty `allOrganizations` is a data-fetch failure, not an authz\n // failure — masking it as \"permission denied\" hides the real\n // error and offers the user no path to retry),\n // 2. the rbac permission lookup also succeeded (errors there fall\n // through to the unfiltered form via the warning banner below),\n // 3. and even then, only when the user has at least one org but none\n // of them allow workspace:create.\n // If `allOrganizations` is empty because the user genuinely belongs to\n // no orgs, the inner \"no organizations found for this tenant\" message\n // is a better surface than an authz-denied page.\n const hasAnyCreatableOrg = workspaceCreateAllowedOrgIds.size > 0;\n const stillResolvingPermissions =\n isLoadingTenants || isLoadingOrganizations || isCheckingOrgPermissions;\n const orgDataLoadedSuccessfully =\n !tenantsError && !organizationsError && allOrganizations.length > 0;\n if (\n !stillResolvingPermissions &&\n !orgPermissionsHadError &&\n orgDataLoadedSuccessfully &&\n !hasAnyCreatableOrg\n ) {\n return (\n <div className=\"p-6\">\n <Link\n to={`${basePath}/list`}\n className=\"inline-flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors mb-6\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'createWorkspace.backToWorkspaces', 'Back to Workspaces')}\n </Link>\n <AccessDenied\n variant=\"card\"\n title={tWithFallback(t, 'createWorkspace.permissionRequiredTitle', 'Permission Required')}\n description={tWithFallback(\n t,\n 'createWorkspace.permissionRequiredDescription',\n \"You don't have permission to create workspaces in any of your organizations.\"\n )}\n details={tWithFallback(\n t,\n 'createWorkspace.permissionRequiredDetails',\n 'Required: workspace:create'\n )}\n primaryAction={{\n label: tWithFallback(t, 'createWorkspace.goBack', 'Go Back'),\n onClick: () => navigate(`${basePath}/list`),\n }}\n />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Back link */}\n <Link\n to={`${basePath}/list`}\n className=\"inline-flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'createWorkspace.backToWorkspaces', 'Back to Workspaces')}\n </Link>\n\n {/* Form card */}\n <Card className=\"max-w-2xl mx-auto\">\n <CardHeader>\n <CardTitle>{tWithFallback(t, 'createWorkspace.title', 'Create New Workspace')}</CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'createWorkspace.subtitle',\n 'Set up a new workspace for your team or personal use'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {orgPermissionsHadError && (\n <div\n role=\"alert\"\n className=\"mb-4 flex items-start gap-2 rounded-md border border-warning/30 bg-warning/10 p-3 text-sm text-foreground\"\n >\n <AlertCircle size={16} className=\"mt-0.5 shrink-0 text-warning\" />\n <span>\n {tWithFallback(\n t,\n 'createWorkspace.permissionCheckUnavailable',\n \"We couldn't verify your workspace-create permissions just now, so the organization list isn't filtered. If you submit and don't have access, the request will be rejected and you can retry.\"\n )}\n </span>\n </div>\n )}\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n <div className=\"space-y-2\">\n <label htmlFor=\"workspace-name\" className=\"text-sm font-medium text-foreground\">\n {tWithFallback(t, 'createWorkspace.nameLabel', 'Workspace Name *')}\n </label>\n <input\n id=\"workspace-name\"\n placeholder={tWithFallback(t, 'createWorkspace.namePlaceholder', 'My Workspace')}\n className=\"h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground\"\n {...form.register('name')}\n />\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.nameHint',\n 'A descriptive name for your workspace'\n )}\n </p>\n {form.formState.errors.name?.message && (\n <p className=\"text-sm text-destructive\">{form.formState.errors.name.message}</p>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <label htmlFor=\"workspace-slug\" className=\"text-sm font-medium text-foreground\">\n {tWithFallback(t, 'createWorkspace.slugLabel', 'Slug *')}\n </label>\n <input\n id=\"workspace-slug\"\n placeholder={tWithFallback(t, 'createWorkspace.slugPlaceholder', 'my-workspace')}\n className=\"h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground\"\n {...form.register('slug')}\n />\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.slugHint',\n 'URL-friendly identifier (auto-generated, but you can edit it)'\n )}\n </p>\n {form.formState.errors.slug?.message && (\n <p className=\"text-sm text-destructive\">{form.formState.errors.slug.message}</p>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <label htmlFor=\"workspace-tenant\" className=\"text-sm font-medium text-foreground\">\n {tWithFallback(t, 'createWorkspace.tenantLabel', 'Tenant *')}\n </label>\n {isLoadingTenants ? (\n <Skeleton className=\"h-10 w-full\" />\n ) : tenantsError ? (\n <div className=\"flex items-center gap-2 text-sm text-destructive\">\n <AlertCircle size={16} />\n {tWithFallback(\n t,\n 'createWorkspace.failedToLoadTenants',\n 'Failed to load tenants'\n )}\n </div>\n ) : tenants.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.noTenantsAvailable',\n 'No tenants available. Contact your administrator.'\n )}\n </div>\n ) : (\n <select\n id=\"workspace-tenant\"\n className=\"h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground\"\n {...form.register('tenantId')}\n >\n <option value=\"\">\n {tWithFallback(t, 'createWorkspace.selectTenantPlaceholder', 'Select a tenant')}\n </option>\n {tenants.map((tenant) => (\n <option key={tenant.id} value={tenant.id}>\n {tenant.name}\n </option>\n ))}\n </select>\n )}\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.tenantHint',\n 'Select which tenant this workspace belongs to'\n )}\n </p>\n {form.formState.errors.tenantId?.message && (\n <p className=\"text-sm text-destructive\">{form.formState.errors.tenantId.message}</p>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <label\n htmlFor=\"workspace-organization\"\n className=\"text-sm font-medium text-foreground\"\n >\n {tWithFallback(t, 'createWorkspace.organizationLabel', 'Organization *')}\n </label>\n {isLoadingOrganizations || isCheckingOrgPermissions ? (\n // While the permission check is in flight,\n // `workspaceCreateAllowedOrgIds` is empty so\n // `filteredOrganizations` is also empty. Render the same\n // skeleton we use for the org-load itself instead of the\n // \"no organizations found\" empty-state — otherwise a slow\n // rbac response briefly looks like an authorization\n // failure for users who DO have workspace:create.\n <Skeleton className=\"h-10 w-full\" />\n ) : organizationsError ? (\n <div className=\"flex items-center gap-2 text-sm text-destructive\">\n <AlertCircle size={16} />\n {tWithFallback(\n t,\n 'createWorkspace.failedToLoadOrganizations',\n 'Failed to load organizations'\n )}\n </div>\n ) : !selectedTenantId ? (\n <div className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.selectTenantFirst',\n 'Please select a tenant first'\n )}\n </div>\n ) : filteredOrganizations.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.noOrganizationsFound',\n 'No organizations found for this tenant'\n )}\n </div>\n ) : (\n <select\n id=\"workspace-organization\"\n className=\"h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground\"\n disabled={!selectedTenantId}\n {...form.register('organizationId')}\n >\n <option value=\"\">\n {tWithFallback(\n t,\n 'createWorkspace.selectOrganizationPlaceholder',\n 'Select an organization'\n )}\n </option>\n {filteredOrganizations.map((org) => (\n <option key={org.id} value={org.id}>\n {org.name}\n </option>\n ))}\n </select>\n )}\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.organizationHint',\n 'Select which organization owns this workspace'\n )}\n </p>\n {form.formState.errors.organizationId?.message && (\n <p className=\"text-sm text-destructive\">\n {form.formState.errors.organizationId.message}\n </p>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <label htmlFor=\"workspace-type\" className=\"text-sm font-medium text-foreground\">\n {tWithFallback(t, 'createWorkspace.typeLabel', 'Workspace Type')}\n </label>\n <select\n id=\"workspace-type\"\n className=\"h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground\"\n {...form.register('type')}\n >\n <option value=\"TEAM\">\n {tWithFallback(t, 'createWorkspace.typeTeam', 'Team Workspace')}\n </option>\n <option value=\"PERSONAL\">\n {tWithFallback(t, 'createWorkspace.typePersonal', 'Personal Workspace')}\n </option>\n </select>\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.typeHint',\n 'Choose between a collaborative workspace or a personal one'\n )}\n </p>\n </div>\n\n <div className=\"flex justify-end gap-3 pt-4\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`${basePath}/list`)}\n disabled={isPending}\n >\n {tWithFallback(t, 'createWorkspace.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"submit\"\n disabled={\n isPending ||\n isLoadingTenants ||\n isLoadingOrganizations ||\n isCheckingOrgPermissions\n }\n >\n {isPending\n ? tWithFallback(t, 'createWorkspace.creating', 'Creating...')\n : tWithFallback(t, 'createWorkspace.submit', 'Create Workspace')}\n </Button>\n </div>\n </form>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CreateWorkspacePage.js","names":[],"sources":["../../src/pages/CreateWorkspacePage.tsx"],"sourcesContent":["import { useEffect, useMemo } from 'react';\nimport { ArrowLeft, AlertCircle } from 'lucide-react';\nimport { Link, useNavigate } from 'react-router-dom';\nimport {\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useForm, z } from '@burdenoff/fe-libs/form';\nimport { AccessDenied, UpgradeInlineBanner } from '@burdenoff/fe-libs/shared/components';\nimport { useUpgradePrompt } from '@burdenoff/fe-libs/shared/hooks';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useCreateWorkspace } from '../hooks/useWorkspaceMutations';\nimport { useMyTenants, useMyOrganizations } from '../hooks/useTenants';\nimport { useOrgsWithPermission } from '../hooks/useOrgsWithPermission';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\nimport { generateSlug } from '../utils/slug';\nimport { tWithFallback } from '../utils/i18n';\n\ntype CreateWorkspaceFormData = {\n name: string;\n slug: string;\n tenantId: string;\n organizationId: string;\n type?: 'TEAM' | 'PERSONAL';\n};\n\nexport function CreateWorkspacePage() {\n useWorkspacesPageView('workspaces.create');\n const { t } = useI18n();\n const {\n isFree,\n approachingLimits,\n plan: planSnapshot,\n } = useUpgradePrompt({ resource: 'workspaces' });\n const workspacesUsage = approachingLimits[0];\n const atWorkspaceCap =\n !!workspacesUsage &&\n typeof workspacesUsage.limit === 'number' &&\n workspacesUsage.current >= workspacesUsage.limit;\n const showUpgradeBanner = isFree && !!workspacesUsage;\n const createWorkspaceSchema = useMemo(\n () =>\n z.object({\n name: z\n .string()\n .min(\n 2,\n tWithFallback(\n t,\n 'createWorkspace.validation.nameMin',\n 'Name must be at least 2 characters'\n )\n )\n .max(100),\n slug: z\n .string()\n .min(\n 2,\n tWithFallback(\n t,\n 'createWorkspace.validation.slugMin',\n 'Slug must be at least 2 characters'\n )\n )\n .max(50)\n .regex(\n /^[a-z0-9-]+$/,\n tWithFallback(\n t,\n 'createWorkspace.validation.slugFormat',\n 'Slug can only contain lowercase letters, numbers, and hyphens'\n )\n ),\n tenantId: z\n .string()\n .min(\n 1,\n tWithFallback(t, 'createWorkspace.validation.tenantRequired', 'Please select a tenant')\n ),\n organizationId: z\n .string()\n .min(\n 1,\n tWithFallback(\n t,\n 'createWorkspace.validation.organizationRequired',\n 'Please select an organization'\n )\n ),\n type: z.enum(['TEAM', 'PERSONAL']).optional(),\n }),\n [t]\n );\n\n const navigate = useNavigate();\n const { basePath = '/' } = useWorkspacesContext();\n const { mutate: createWorkspace, isPending } = useCreateWorkspace();\n const { data: tenantsData, isLoading: isLoadingTenants, error: tenantsError } = useMyTenants();\n const {\n data: organizationsData,\n isLoading: isLoadingOrganizations,\n error: organizationsError,\n } = useMyOrganizations();\n\n const tenants = useMemo(() => tenantsData?.items ?? [], [tenantsData]);\n const allOrganizations = useMemo(() => organizationsData?.items ?? [], [organizationsData]);\n\n const defaultTenantId = useMemo(() => {\n const sharedTenant = tenants.find(\n (tenant) => tenant.type === 'SHARED' || tenant.slug === 'burdenoff-shared'\n );\n return sharedTenant?.id ?? tenants[0]?.id ?? '';\n }, [tenants]);\n\n const form = useForm<CreateWorkspaceFormData>({\n schema: createWorkspaceSchema,\n defaultValues: {\n name: '',\n slug: '',\n tenantId: '',\n organizationId: '',\n type: 'TEAM',\n },\n });\n\n const selectedTenantId = form.watch('tenantId');\n const workspaceName = form.watch('name');\n\n // Check workspace:create permission across ALL the user's orgs up front\n // (bulk-checked in a single rbac round-trip). This is the authoritative\n // gate — only orgs where the user can actually create a workspace make\n // it into the dropdown, and the page can decisively render the \"no\n // permissions anywhere\" state once the check resolves.\n const allOrgIds = useMemo(() => allOrganizations.map((o) => o.id), [allOrganizations]);\n const {\n allowedIds: workspaceCreateAllowedOrgIds,\n loading: isCheckingOrgPermissions,\n isError: orgPermissionsHadError,\n } = useOrgsWithPermission(allOrgIds, 'workspace', 'create');\n\n // Filter organizations by selected tenant AND permission. When the rbac\n // permission lookup errored we deliberately skip the permission filter\n // (see `orgPermissionsHadError` block below) — the gateway @rbac\n // directive on `createWorkspace` is the authoritative gate, so it's\n // safer to let the user pick from the full tenant list and hit a 403 on\n // submit than to lock them out of a flow they actually have access to.\n const tenantOrganizations = useMemo(() => {\n if (!selectedTenantId) return [];\n return allOrganizations.filter((org) => org.tenantId === selectedTenantId);\n }, [selectedTenantId, allOrganizations]);\n const filteredOrganizations = useMemo(() => {\n if (orgPermissionsHadError) return tenantOrganizations;\n return tenantOrganizations.filter((org) => workspaceCreateAllowedOrgIds.has(org.id));\n }, [tenantOrganizations, workspaceCreateAllowedOrgIds, orgPermissionsHadError]);\n\n // Auto-generate slug from name (clear when name is empty)\n useEffect(() => {\n form.setValue('slug', workspaceName ? generateSlug(workspaceName) : '');\n }, [workspaceName, form]);\n\n // Reset organizationId when tenant changes\n useEffect(() => {\n form.setValue('organizationId', '');\n }, [selectedTenantId, form]);\n\n useEffect(() => {\n if (!form.getValues('tenantId') && defaultTenantId) {\n form.setValue('tenantId', defaultTenantId, {\n shouldDirty: false,\n shouldTouch: false,\n });\n }\n }, [defaultTenantId, form]);\n\n useEffect(() => {\n const currentOrganizationId = form.getValues('organizationId');\n const hasCurrentOrganization = filteredOrganizations.some(\n (organization) => organization.id === currentOrganizationId\n );\n\n if (!hasCurrentOrganization && filteredOrganizations[0]?.id) {\n form.setValue('organizationId', filteredOrganizations[0].id, {\n shouldDirty: false,\n shouldTouch: false,\n });\n }\n }, [filteredOrganizations, form]);\n\n const onSubmit = (data: CreateWorkspaceFormData) => {\n createWorkspace(\n {\n name: data.name,\n slug: data.slug,\n tenantId: data.tenantId,\n organizationId: data.organizationId,\n type: data.type,\n },\n {\n onSuccess: (newWorkspace) => {\n // Navigate to the new workspace\n navigate(`${basePath}/${newWorkspace.id}`);\n },\n }\n );\n };\n\n // `workspace:create` is an org-scoped permission. Page-level `PermissionGate`\n // resolved at the outer shell scope and incorrectly denied users who *do*\n // have the permission inside at least one of their orgs. The authoritative\n // gate now lives on the org dropdown (only orgs where the user has\n // workspace:create are listed via useOrgsWithPermission) and on the gateway\n // @rbac directive enforcing the createWorkspace mutation. We still want a\n // clear \"you can't create anywhere\" empty state — once tenants and org\n // permission lookups have settled, if no org is eligible we render it.\n // The AccessDenied empty-state should ONLY render when we know with\n // certainty that the user has no creatable org. That requires:\n // 1. tenants + organizations queries both succeeded (otherwise an\n // empty `allOrganizations` is a data-fetch failure, not an authz\n // failure — masking it as \"permission denied\" hides the real\n // error and offers the user no path to retry),\n // 2. the rbac permission lookup also succeeded (errors there fall\n // through to the unfiltered form via the warning banner below),\n // 3. and even then, only when the user has at least one org but none\n // of them allow workspace:create.\n // If `allOrganizations` is empty because the user genuinely belongs to\n // no orgs, the inner \"no organizations found for this tenant\" message\n // is a better surface than an authz-denied page.\n const hasAnyCreatableOrg = workspaceCreateAllowedOrgIds.size > 0;\n const stillResolvingPermissions =\n isLoadingTenants || isLoadingOrganizations || isCheckingOrgPermissions;\n const orgDataLoadedSuccessfully =\n !tenantsError && !organizationsError && allOrganizations.length > 0;\n if (\n !stillResolvingPermissions &&\n !orgPermissionsHadError &&\n orgDataLoadedSuccessfully &&\n !hasAnyCreatableOrg\n ) {\n return (\n <div className=\"p-6\">\n <Link\n to={`${basePath}/list`}\n className=\"inline-flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors mb-6\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'createWorkspace.backToWorkspaces', 'Back to Workspaces')}\n </Link>\n <AccessDenied\n variant=\"card\"\n title={tWithFallback(t, 'createWorkspace.permissionRequiredTitle', 'Permission Required')}\n description={tWithFallback(\n t,\n 'createWorkspace.permissionRequiredDescription',\n \"You don't have permission to create workspaces in any of your organizations.\"\n )}\n details={tWithFallback(\n t,\n 'createWorkspace.permissionRequiredDetails',\n 'Required: workspace:create'\n )}\n primaryAction={{\n label: tWithFallback(t, 'createWorkspace.goBack', 'Go Back'),\n onClick: () => navigate(`${basePath}/list`),\n }}\n />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Back link */}\n <Link\n to={`${basePath}/list`}\n className=\"inline-flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors\"\n >\n <ArrowLeft size={20} />\n {tWithFallback(t, 'createWorkspace.backToWorkspaces', 'Back to Workspaces')}\n </Link>\n\n {showUpgradeBanner && (\n <div className=\"max-w-2xl mx-auto w-full\">\n <UpgradeInlineBanner\n resource=\"workspaces\"\n current={workspacesUsage.current}\n limit={workspacesUsage.limit ?? undefined}\n severity={atWorkspaceCap ? 'critical' : undefined}\n message={\n atWorkspaceCap\n ? tWithFallback(\n t,\n 'createWorkspace.upgradeCapMessage',\n `You've used all workspaces in the ${planSnapshot?.planName ?? 'free'} plan.`\n )\n : tWithFallback(\n t,\n 'createWorkspace.upgradeApproachingMessage',\n 'Upgrade to create more workspaces.'\n )\n }\n />\n </div>\n )}\n\n {/* Form card */}\n <Card className=\"max-w-2xl mx-auto\">\n <CardHeader>\n <CardTitle>{tWithFallback(t, 'createWorkspace.title', 'Create New Workspace')}</CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'createWorkspace.subtitle',\n 'Set up a new workspace for your team or personal use'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {orgPermissionsHadError && (\n <div\n role=\"alert\"\n className=\"mb-4 flex items-start gap-2 rounded-md border border-warning/30 bg-warning/10 p-3 text-sm text-foreground\"\n >\n <AlertCircle size={16} className=\"mt-0.5 shrink-0 text-warning\" />\n <span>\n {tWithFallback(\n t,\n 'createWorkspace.permissionCheckUnavailable',\n \"We couldn't verify your workspace-create permissions just now, so the organization list isn't filtered. If you submit and don't have access, the request will be rejected and you can retry.\"\n )}\n </span>\n </div>\n )}\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n <div className=\"space-y-2\">\n <label htmlFor=\"workspace-name\" className=\"text-sm font-medium text-foreground\">\n {tWithFallback(t, 'createWorkspace.nameLabel', 'Workspace Name *')}\n </label>\n <input\n id=\"workspace-name\"\n placeholder={tWithFallback(t, 'createWorkspace.namePlaceholder', 'My Workspace')}\n className=\"h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground\"\n {...form.register('name')}\n />\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.nameHint',\n 'A descriptive name for your workspace'\n )}\n </p>\n {form.formState.errors.name?.message && (\n <p className=\"text-sm text-destructive\">{form.formState.errors.name.message}</p>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <label htmlFor=\"workspace-slug\" className=\"text-sm font-medium text-foreground\">\n {tWithFallback(t, 'createWorkspace.slugLabel', 'Slug *')}\n </label>\n <input\n id=\"workspace-slug\"\n placeholder={tWithFallback(t, 'createWorkspace.slugPlaceholder', 'my-workspace')}\n className=\"h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground\"\n {...form.register('slug')}\n />\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.slugHint',\n 'URL-friendly identifier (auto-generated, but you can edit it)'\n )}\n </p>\n {form.formState.errors.slug?.message && (\n <p className=\"text-sm text-destructive\">{form.formState.errors.slug.message}</p>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <label htmlFor=\"workspace-tenant\" className=\"text-sm font-medium text-foreground\">\n {tWithFallback(t, 'createWorkspace.tenantLabel', 'Tenant *')}\n </label>\n {isLoadingTenants ? (\n <Skeleton className=\"h-10 w-full\" />\n ) : tenantsError ? (\n <div className=\"flex items-center gap-2 text-sm text-destructive\">\n <AlertCircle size={16} />\n {tWithFallback(\n t,\n 'createWorkspace.failedToLoadTenants',\n 'Failed to load tenants'\n )}\n </div>\n ) : tenants.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.noTenantsAvailable',\n 'No tenants available. Contact your administrator.'\n )}\n </div>\n ) : (\n <select\n id=\"workspace-tenant\"\n className=\"h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground\"\n {...form.register('tenantId')}\n >\n <option value=\"\">\n {tWithFallback(t, 'createWorkspace.selectTenantPlaceholder', 'Select a tenant')}\n </option>\n {tenants.map((tenant) => (\n <option key={tenant.id} value={tenant.id}>\n {tenant.name}\n </option>\n ))}\n </select>\n )}\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.tenantHint',\n 'Select which tenant this workspace belongs to'\n )}\n </p>\n {form.formState.errors.tenantId?.message && (\n <p className=\"text-sm text-destructive\">{form.formState.errors.tenantId.message}</p>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <label\n htmlFor=\"workspace-organization\"\n className=\"text-sm font-medium text-foreground\"\n >\n {tWithFallback(t, 'createWorkspace.organizationLabel', 'Organization *')}\n </label>\n {isLoadingOrganizations || isCheckingOrgPermissions ? (\n // While the permission check is in flight,\n // `workspaceCreateAllowedOrgIds` is empty so\n // `filteredOrganizations` is also empty. Render the same\n // skeleton we use for the org-load itself instead of the\n // \"no organizations found\" empty-state — otherwise a slow\n // rbac response briefly looks like an authorization\n // failure for users who DO have workspace:create.\n <Skeleton className=\"h-10 w-full\" />\n ) : organizationsError ? (\n <div className=\"flex items-center gap-2 text-sm text-destructive\">\n <AlertCircle size={16} />\n {tWithFallback(\n t,\n 'createWorkspace.failedToLoadOrganizations',\n 'Failed to load organizations'\n )}\n </div>\n ) : !selectedTenantId ? (\n <div className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.selectTenantFirst',\n 'Please select a tenant first'\n )}\n </div>\n ) : filteredOrganizations.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.noOrganizationsFound',\n 'No organizations found for this tenant'\n )}\n </div>\n ) : (\n <select\n id=\"workspace-organization\"\n className=\"h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground\"\n disabled={!selectedTenantId}\n {...form.register('organizationId')}\n >\n <option value=\"\">\n {tWithFallback(\n t,\n 'createWorkspace.selectOrganizationPlaceholder',\n 'Select an organization'\n )}\n </option>\n {filteredOrganizations.map((org) => (\n <option key={org.id} value={org.id}>\n {org.name}\n </option>\n ))}\n </select>\n )}\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.organizationHint',\n 'Select which organization owns this workspace'\n )}\n </p>\n {form.formState.errors.organizationId?.message && (\n <p className=\"text-sm text-destructive\">\n {form.formState.errors.organizationId.message}\n </p>\n )}\n </div>\n\n <div className=\"space-y-2\">\n <label htmlFor=\"workspace-type\" className=\"text-sm font-medium text-foreground\">\n {tWithFallback(t, 'createWorkspace.typeLabel', 'Workspace Type')}\n </label>\n <select\n id=\"workspace-type\"\n className=\"h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground\"\n {...form.register('type')}\n >\n <option value=\"TEAM\">\n {tWithFallback(t, 'createWorkspace.typeTeam', 'Team Workspace')}\n </option>\n <option value=\"PERSONAL\">\n {tWithFallback(t, 'createWorkspace.typePersonal', 'Personal Workspace')}\n </option>\n </select>\n <p className=\"text-xs text-muted-foreground\">\n {tWithFallback(\n t,\n 'createWorkspace.typeHint',\n 'Choose between a collaborative workspace or a personal one'\n )}\n </p>\n </div>\n\n <div className=\"flex justify-end gap-3 pt-4\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`${basePath}/list`)}\n disabled={isPending}\n >\n {tWithFallback(t, 'createWorkspace.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"submit\"\n disabled={\n isPending ||\n isLoadingTenants ||\n isLoadingOrganizations ||\n isCheckingOrgPermissions ||\n atWorkspaceCap\n }\n title={\n atWorkspaceCap\n ? tWithFallback(\n t,\n 'createWorkspace.disabledAtCap',\n 'Workspace limit reached — upgrade your plan to create more.'\n )\n : undefined\n }\n >\n {isPending\n ? tWithFallback(t, 'createWorkspace.creating', 'Creating...')\n : tWithFallback(t, 'createWorkspace.submit', 'Create Workspace')}\n </Button>\n </div>\n </form>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAgCA,SAAgB,IAAsB;AACpC,IAAsB,oBAAoB;CAC1C,IAAM,EAAE,SAAM,GAAS,EACjB,EACJ,WACA,sBACA,MAAM,OACJ,EAAiB,EAAE,UAAU,cAAc,CAAC,EAC1C,IAAkB,EAAkB,IACpC,IACJ,CAAC,CAAC,KACF,OAAO,EAAgB,SAAU,YACjC,EAAgB,WAAW,EAAgB,OACvC,KAAoB,KAAU,CAAC,CAAC,GAChC,IAAwB,QAE1B,EAAE,OAAO;EACP,MAAM,EACH,QAAQ,CACR,IACC,GACA,EACE,GACA,sCACA,qCACD,CACF,CACA,IAAI,IAAI;EACX,MAAM,EACH,QAAQ,CACR,IACC,GACA,EACE,GACA,sCACA,qCACD,CACF,CACA,IAAI,GAAG,CACP,MACC,gBACA,EACE,GACA,yCACA,gEACD,CACF;EACH,UAAU,EACP,QAAQ,CACR,IACC,GACA,EAAc,GAAG,6CAA6C,yBAAyB,CACxF;EACH,gBAAgB,EACb,QAAQ,CACR,IACC,GACA,EACE,GACA,mDACA,gCACD,CACF;EACH,MAAM,EAAE,KAAK,CAAC,QAAQ,WAAW,CAAC,CAAC,UAAU;EAC9C,CAAC,EACJ,CAAC,EAAE,CACJ,EAEK,IAAW,GAAa,EACxB,EAAE,cAAW,QAAQ,GAAsB,EAC3C,EAAE,QAAQ,GAAiB,iBAAc,GAAoB,EAC7D,EAAE,MAAM,GAAa,WAAW,GAAkB,OAAO,MAAiB,GAAc,EACxF,EACJ,MAAM,GACN,WAAW,GACX,OAAO,MACL,GAAoB,EAElB,IAAU,QAAc,GAAa,SAAS,EAAE,EAAE,CAAC,EAAY,CAAC,EAChE,IAAmB,QAAc,GAAmB,SAAS,EAAE,EAAE,CAAC,EAAkB,CAAC,EAErF,IAAkB,QACD,EAAQ,MAC1B,MAAW,EAAO,SAAS,YAAY,EAAO,SAAS,mBACzD,EACoB,MAAM,EAAQ,IAAI,MAAM,IAC5C,CAAC,EAAQ,CAAC,EAEP,IAAO,EAAiC;EAC5C,QAAQ;EACR,eAAe;GACb,MAAM;GACN,MAAM;GACN,UAAU;GACV,gBAAgB;GAChB,MAAM;GACP;EACF,CAAC,EAEI,IAAmB,EAAK,MAAM,WAAW,EACzC,IAAgB,EAAK,MAAM,OAAO,EAQlC,EACJ,YAAY,GACZ,SAAS,GACT,SAAS,MACP,EALc,QAAc,EAAiB,KAAK,MAAM,EAAE,GAAG,EAAE,CAAC,EAAiB,CAAC,EAKjD,aAAa,SAAS,EAQrD,IAAsB,QACrB,IACE,EAAiB,QAAQ,MAAQ,EAAI,aAAa,EAAiB,GAD5C,EAAE,EAE/B,CAAC,GAAkB,EAAiB,CAAC,EAClC,IAAwB,QACxB,IAA+B,IAC5B,EAAoB,QAAQ,MAAQ,EAA6B,IAAI,EAAI,GAAG,CAAC,EACnF;EAAC;EAAqB;EAA8B;EAAuB,CAAC;AAqB/E,CAlBA,QAAgB;AACd,IAAK,SAAS,QAAQ,IAAgB,EAAa,EAAc,GAAG,GAAG;IACtE,CAAC,GAAe,EAAK,CAAC,EAGzB,QAAgB;AACd,IAAK,SAAS,kBAAkB,GAAG;IAClC,CAAC,GAAkB,EAAK,CAAC,EAE5B,QAAgB;AACd,EAAI,CAAC,EAAK,UAAU,WAAW,IAAI,KACjC,EAAK,SAAS,YAAY,GAAiB;GACzC,aAAa;GACb,aAAa;GACd,CAAC;IAEH,CAAC,GAAiB,EAAK,CAAC,EAE3B,QAAgB;EACd,IAAM,IAAwB,EAAK,UAAU,iBAAiB;AAK9D,EAAI,CAJ2B,EAAsB,MAClD,MAAiB,EAAa,OAAO,EACvC,IAE8B,EAAsB,IAAI,MACvD,EAAK,SAAS,kBAAkB,EAAsB,GAAG,IAAI;GAC3D,aAAa;GACb,aAAa;GACd,CAAC;IAEH,CAAC,GAAuB,EAAK,CAAC;CAEjC,IAAM,MAAY,MAAkC;AAClD,IACE;GACE,MAAM,EAAK;GACX,MAAM,EAAK;GACX,UAAU,EAAK;GACf,gBAAgB,EAAK;GACrB,MAAM,EAAK;GACZ,EACD,EACE,YAAY,MAAiB;AAE3B,KAAS,GAAG,EAAS,GAAG,EAAa,KAAK;KAE7C,CACF;IAwBG,KAAqB,EAA6B,OAAO,GACzD,KACJ,KAAoB,KAA0B,GAC1C,KACJ,CAAC,KAAgB,CAAC,KAAsB,EAAiB,SAAS;AAsCpE,QApCE,CAAC,MACD,CAAC,KACD,MACA,CAAC,KAGC,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GACE,IAAI,GAAG,EAAS;GAChB,WAAU;aAFZ,CAIE,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA,EACtB,EAAc,GAAG,oCAAoC,qBAAqB,CACtE;MACP,kBAAC,GAAD;GACE,SAAQ;GACR,OAAO,EAAc,GAAG,2CAA2C,sBAAsB;GACzF,aAAa,EACX,GACA,iDACA,+EACD;GACD,SAAS,EACP,GACA,6CACA,6BACD;GACD,eAAe;IACb,OAAO,EAAc,GAAG,0BAA0B,UAAU;IAC5D,eAAe,EAAS,GAAG,EAAS,OAAO;IAC5C;GACD,CAAA,CACE;MAKR,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,GAAD;IACE,IAAI,GAAG,EAAS;IAChB,WAAU;cAFZ,CAIE,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA,EACtB,EAAc,GAAG,oCAAoC,qBAAqB,CACtE;;GAEN,MACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KACE,UAAS;KACT,SAAS,EAAgB;KACzB,OAAO,EAAgB,SAAS,KAAA;KAChC,UAAU,IAAiB,aAAa,KAAA;KACxC,SACE,IACI,EACE,GACA,qCACA,qCAAqC,IAAc,YAAY,OAAO,QACvE,GACD,EACE,GACA,6CACA,qCACD;KAEP,CAAA;IACE,CAAA;GAIR,kBAAC,IAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAY,EAAc,GAAG,yBAAyB,uBAAuB,EAAa,CAAA,EAC1F,kBAAC,GAAD,EAAA,UACG,EACC,GACA,4BACA,uDACD,EACe,CAAA,CACP,EAAA,CAAA,EACb,kBAAC,GAAD,EAAA,UAAA,CACG,KACC,kBAAC,OAAD;KACE,MAAK;KACL,WAAU;eAFZ,CAIE,kBAAC,GAAD;MAAa,MAAM;MAAI,WAAU;MAAiC,CAAA,EAClE,kBAAC,QAAD,EAAA,UACG,EACC,GACA,8CACA,+LACD,EACI,CAAA,CACH;QAER,kBAAC,QAAD;KAAM,UAAU,EAAK,aAAa,GAAS;KAAE,WAAU;eAAvD;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,SAAD;SAAO,SAAQ;SAAiB,WAAU;mBACvC,EAAc,GAAG,6BAA6B,mBAAmB;SAC5D,CAAA;QACR,kBAAC,SAAD;SACE,IAAG;SACH,aAAa,EAAc,GAAG,mCAAmC,eAAe;SAChF,WAAU;SACV,GAAI,EAAK,SAAS,OAAO;SACzB,CAAA;QACF,kBAAC,KAAD;SAAG,WAAU;mBACV,EACC,GACA,4BACA,wCACD;SACC,CAAA;QACH,EAAK,UAAU,OAAO,MAAM,WAC3B,kBAAC,KAAD;SAAG,WAAU;mBAA4B,EAAK,UAAU,OAAO,KAAK;SAAY,CAAA;QAE9E;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,SAAD;SAAO,SAAQ;SAAiB,WAAU;mBACvC,EAAc,GAAG,6BAA6B,SAAS;SAClD,CAAA;QACR,kBAAC,SAAD;SACE,IAAG;SACH,aAAa,EAAc,GAAG,mCAAmC,eAAe;SAChF,WAAU;SACV,GAAI,EAAK,SAAS,OAAO;SACzB,CAAA;QACF,kBAAC,KAAD;SAAG,WAAU;mBACV,EACC,GACA,4BACA,gEACD;SACC,CAAA;QACH,EAAK,UAAU,OAAO,MAAM,WAC3B,kBAAC,KAAD;SAAG,WAAU;mBAA4B,EAAK,UAAU,OAAO,KAAK;SAAY,CAAA;QAE9E;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,SAAD;SAAO,SAAQ;SAAmB,WAAU;mBACzC,EAAc,GAAG,+BAA+B,WAAW;SACtD,CAAA;QACP,IACC,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,GAClC,IACF,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAa,MAAM,IAAM,CAAA,EACxB,EACC,GACA,uCACA,yBACD,CACG;aACJ,EAAQ,WAAW,IACrB,kBAAC,OAAD;SAAK,WAAU;mBACZ,EACC,GACA,sCACA,oDACD;SACG,CAAA,GAEN,kBAAC,UAAD;SACE,IAAG;SACH,WAAU;SACV,GAAI,EAAK,SAAS,WAAW;mBAH/B,CAKE,kBAAC,UAAD;UAAQ,OAAM;oBACX,EAAc,GAAG,2CAA2C,kBAAkB;UACxE,CAAA,EACR,EAAQ,KAAK,MACZ,kBAAC,UAAD;UAAwB,OAAO,EAAO;oBACnC,EAAO;UACD,EAFI,EAAO,GAEX,CACT,CACK;;QAEX,kBAAC,KAAD;SAAG,WAAU;mBACV,EACC,GACA,8BACA,gDACD;SACC,CAAA;QACH,EAAK,UAAU,OAAO,UAAU,WAC/B,kBAAC,KAAD;SAAG,WAAU;mBAA4B,EAAK,UAAU,OAAO,SAAS;SAAY,CAAA;QAElF;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,SAAD;SACE,SAAQ;SACR,WAAU;mBAET,EAAc,GAAG,qCAAqC,iBAAiB;SAClE,CAAA;QACP,KAA0B,IAQzB,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,GAClC,IACF,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAa,MAAM,IAAM,CAAA,EACxB,EACC,GACA,6CACA,+BACD,CACG;aACH,IAQD,EAAsB,WAAW,IACnC,kBAAC,OAAD;SAAK,WAAU;mBACZ,EACC,GACA,wCACA,yCACD;SACG,CAAA,GAEN,kBAAC,UAAD;SACE,IAAG;SACH,WAAU;SACV,UAAU,CAAC;SACX,GAAI,EAAK,SAAS,iBAAiB;mBAJrC,CAME,kBAAC,UAAD;UAAQ,OAAM;oBACX,EACC,GACA,iDACA,yBACD;UACM,CAAA,EACR,EAAsB,KAAK,MAC1B,kBAAC,UAAD;UAAqB,OAAO,EAAI;oBAC7B,EAAI;UACE,EAFI,EAAI,GAER,CACT,CACK;aAlCT,kBAAC,OAAD;SAAK,WAAU;mBACZ,EACC,GACA,qCACA,+BACD;SACG,CAAA;QA8BR,kBAAC,KAAD;SAAG,WAAU;mBACV,EACC,GACA,oCACA,gDACD;SACC,CAAA;QACH,EAAK,UAAU,OAAO,gBAAgB,WACrC,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAK,UAAU,OAAO,eAAe;SACpC,CAAA;QAEF;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,SAAD;SAAO,SAAQ;SAAiB,WAAU;mBACvC,EAAc,GAAG,6BAA6B,iBAAiB;SAC1D,CAAA;QACR,kBAAC,UAAD;SACE,IAAG;SACH,WAAU;SACV,GAAI,EAAK,SAAS,OAAO;mBAH3B,CAKE,kBAAC,UAAD;UAAQ,OAAM;oBACX,EAAc,GAAG,4BAA4B,iBAAiB;UACxD,CAAA,EACT,kBAAC,UAAD;UAAQ,OAAM;oBACX,EAAc,GAAG,gCAAgC,qBAAqB;UAChE,CAAA,CACF;;QACT,kBAAC,KAAD;SAAG,WAAU;mBACV,EACC,GACA,4BACA,6DACD;SACC,CAAA;QACA;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QACE,MAAK;QACL,SAAQ;QACR,eAAe,EAAS,GAAG,EAAS,OAAO;QAC3C,UAAU;kBAET,EAAc,GAAG,0BAA0B,SAAS;QAC9C,CAAA,EACT,kBAAC,GAAD;QACE,MAAK;QACL,UACE,KACA,KACA,KACA,KACA;QAEF,OACE,IACI,EACE,GACA,iCACA,8DACD,GACD,KAAA;kBAGL,IACG,EAAc,GAAG,4BAA4B,cAAc,GAC3D,EAAc,GAAG,0BAA0B,mBAAmB;QAC3D,CAAA,CACL;;MACD;OACK,EAAA,CAAA,CACT;;GACH"}
|
|
@@ -51,7 +51,7 @@ function k() {
|
|
|
51
51
|
}), /* @__PURE__ */ g(v, {
|
|
52
52
|
variant: "outline",
|
|
53
53
|
onClick: () => k("/workspaces/list"),
|
|
54
|
-
children: [/* @__PURE__ */ h(u, { className: "mr-2
|
|
54
|
+
children: [/* @__PURE__ */ h(u, { className: "mr-2 size-4" }), t(o, "inviteAcceptance.backToWorkspaces", "Back to Workspaces")]
|
|
55
55
|
})]
|
|
56
56
|
})]
|
|
57
57
|
})]
|
|
@@ -147,14 +147,14 @@ function k() {
|
|
|
147
147
|
disabled: K || J,
|
|
148
148
|
className: "flex-1",
|
|
149
149
|
size: "lg",
|
|
150
|
-
children: K ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(f, { className: "mr-2
|
|
150
|
+
children: K ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(f, { className: "mr-2 size-4 animate-spin" }), t(o, "inviteAcceptance.accepting", "Accepting...")] }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(c, { className: "mr-2 size-4" }), t(o, "inviteAcceptance.acceptButton", "Accept Invitation")] })
|
|
151
151
|
}), /* @__PURE__ */ h(v, {
|
|
152
152
|
variant: "outline",
|
|
153
153
|
onClick: X,
|
|
154
154
|
disabled: K || J,
|
|
155
155
|
className: "flex-1",
|
|
156
156
|
size: "lg",
|
|
157
|
-
children: J ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(f, { className: "mr-2
|
|
157
|
+
children: J ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(f, { className: "mr-2 size-4 animate-spin" }), t(o, "inviteAcceptance.rejecting", "Rejecting...")] }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(p, { className: "mr-2 size-4" }), t(o, "inviteAcceptance.rejectButton", "Reject")] })
|
|
158
158
|
})]
|
|
159
159
|
})]
|
|
160
160
|
})]
|
|
@@ -170,7 +170,7 @@ function A() {
|
|
|
170
170
|
className: "max-w-2xl w-full",
|
|
171
171
|
children: [/* @__PURE__ */ h(S, { children: /* @__PURE__ */ g("div", {
|
|
172
172
|
className: "flex items-center gap-3",
|
|
173
|
-
children: [/* @__PURE__ */ h(w, { className: "
|
|
173
|
+
children: [/* @__PURE__ */ h(w, { className: "size-12 rounded-lg" }), /* @__PURE__ */ g("div", {
|
|
174
174
|
className: "flex-1 space-y-2",
|
|
175
175
|
children: [/* @__PURE__ */ h(w, { className: "h-6 w-48" }), /* @__PURE__ */ h(w, { className: "h-4 w-64" })]
|
|
176
176
|
})]
|
|
@@ -194,7 +194,7 @@ function A() {
|
|
|
194
194
|
});
|
|
195
195
|
}
|
|
196
196
|
function j({ error: e, onRetry: n }) {
|
|
197
|
-
let { t: r } = O();
|
|
197
|
+
let { t: r } = O(), i = E();
|
|
198
198
|
return /* @__PURE__ */ h("div", {
|
|
199
199
|
className: "min-h-screen flex items-center justify-center p-4 bg-muted/30",
|
|
200
200
|
children: /* @__PURE__ */ g(y, {
|
|
@@ -215,7 +215,7 @@ function j({ error: e, onRetry: n }) {
|
|
|
215
215
|
className: "space-y-4",
|
|
216
216
|
children: [/* @__PURE__ */ g("div", {
|
|
217
217
|
className: "flex gap-3 p-4 rounded-lg border border-destructive/50 bg-destructive/10",
|
|
218
|
-
children: [/* @__PURE__ */ h(o, { className: "
|
|
218
|
+
children: [/* @__PURE__ */ h(o, { className: "size-5 text-destructive flex-shrink-0 mt-0.5" }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
|
|
219
219
|
className: "font-medium text-destructive",
|
|
220
220
|
children: t(r, "inviteAcceptance.errorDetailsLabel", "Error Details")
|
|
221
221
|
}), /* @__PURE__ */ h("p", {
|
|
@@ -227,12 +227,12 @@ function j({ error: e, onRetry: n }) {
|
|
|
227
227
|
children: [/* @__PURE__ */ g(v, {
|
|
228
228
|
onClick: n,
|
|
229
229
|
className: "flex-1",
|
|
230
|
-
children: [/* @__PURE__ */ h(f, { className: "mr-2
|
|
230
|
+
children: [/* @__PURE__ */ h(f, { className: "mr-2 size-4" }), t(r, "inviteAcceptance.tryAgain", "Try Again")]
|
|
231
231
|
}), /* @__PURE__ */ g(v, {
|
|
232
232
|
variant: "outline",
|
|
233
|
-
onClick: () =>
|
|
233
|
+
onClick: () => i("/workspaces/list"),
|
|
234
234
|
className: "flex-1",
|
|
235
|
-
children: [/* @__PURE__ */ h(u, { className: "mr-2
|
|
235
|
+
children: [/* @__PURE__ */ h(u, { className: "mr-2 size-4" }), t(r, "inviteAcceptance.goToWorkspaces", "Go to Workspaces")]
|
|
236
236
|
})]
|
|
237
237
|
})]
|
|
238
238
|
})]
|
|
@@ -240,7 +240,7 @@ function j({ error: e, onRetry: n }) {
|
|
|
240
240
|
});
|
|
241
241
|
}
|
|
242
242
|
function M() {
|
|
243
|
-
let { t: e } = O();
|
|
243
|
+
let { t: e } = O(), n = E();
|
|
244
244
|
return /* @__PURE__ */ h("div", {
|
|
245
245
|
className: "min-h-screen flex items-center justify-center p-4 bg-muted/30",
|
|
246
246
|
children: /* @__PURE__ */ g(y, {
|
|
@@ -261,7 +261,7 @@ function M() {
|
|
|
261
261
|
className: "space-y-4",
|
|
262
262
|
children: [/* @__PURE__ */ g("div", {
|
|
263
263
|
className: "flex gap-3 p-4 rounded-lg border border-border bg-muted/50",
|
|
264
|
-
children: [/* @__PURE__ */ h(o, { className: "
|
|
264
|
+
children: [/* @__PURE__ */ h(o, { className: "size-5 text-muted-foreground flex-shrink-0 mt-0.5" }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
|
|
265
265
|
className: "font-medium",
|
|
266
266
|
children: t(e, "inviteAcceptance.invalidLinkHeading", "Invalid Invitation Link")
|
|
267
267
|
}), /* @__PURE__ */ h("p", {
|
|
@@ -269,16 +269,16 @@ function M() {
|
|
|
269
269
|
children: t(e, "inviteAcceptance.invalidLinkBody", "The invitation you're trying to access doesn't exist. It may have been deleted or the link is incorrect.")
|
|
270
270
|
})] })]
|
|
271
271
|
}), /* @__PURE__ */ g(v, {
|
|
272
|
-
onClick: () =>
|
|
272
|
+
onClick: () => n("/workspaces/list"),
|
|
273
273
|
className: "w-full",
|
|
274
|
-
children: [/* @__PURE__ */ h(u, { className: "mr-2
|
|
274
|
+
children: [/* @__PURE__ */ h(u, { className: "mr-2 size-4" }), t(e, "inviteAcceptance.goToWorkspaces", "Go to Workspaces")]
|
|
275
275
|
})]
|
|
276
276
|
})]
|
|
277
277
|
})
|
|
278
278
|
});
|
|
279
279
|
}
|
|
280
280
|
function N({ invitation: e }) {
|
|
281
|
-
let { t: n } = O();
|
|
281
|
+
let { t: n } = O(), r = E();
|
|
282
282
|
return /* @__PURE__ */ h("div", {
|
|
283
283
|
className: "min-h-screen flex items-center justify-center p-4 bg-muted/30",
|
|
284
284
|
children: /* @__PURE__ */ g(y, {
|
|
@@ -299,7 +299,7 @@ function N({ invitation: e }) {
|
|
|
299
299
|
className: "space-y-4",
|
|
300
300
|
children: [/* @__PURE__ */ g("div", {
|
|
301
301
|
className: "flex gap-3 p-4 rounded-lg border border-status-success/30 bg-status-success/10 transition-colors",
|
|
302
|
-
children: [/* @__PURE__ */ h(c, { className: "
|
|
302
|
+
children: [/* @__PURE__ */ h(c, { className: "size-5 text-status-success flex-shrink-0 mt-0.5" }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
|
|
303
303
|
className: "font-medium text-status-success",
|
|
304
304
|
children: t(n, "inviteAcceptance.alreadyMember", "You're already a member")
|
|
305
305
|
}), /* @__PURE__ */ g("p", {
|
|
@@ -314,7 +314,7 @@ function N({ invitation: e }) {
|
|
|
314
314
|
]
|
|
315
315
|
})] })]
|
|
316
316
|
}), /* @__PURE__ */ h(v, {
|
|
317
|
-
onClick: () =>
|
|
317
|
+
onClick: () => r(`/workspaces/${e.workspaceId}/members`),
|
|
318
318
|
className: "w-full",
|
|
319
319
|
children: t(n, "inviteAcceptance.goToWorkspace", "Go to Workspace")
|
|
320
320
|
})]
|
|
@@ -323,7 +323,7 @@ function N({ invitation: e }) {
|
|
|
323
323
|
});
|
|
324
324
|
}
|
|
325
325
|
function P({ invitation: e }) {
|
|
326
|
-
let { t: n } = O();
|
|
326
|
+
let { t: n } = O(), r = E();
|
|
327
327
|
return /* @__PURE__ */ h("div", {
|
|
328
328
|
className: "min-h-screen flex items-center justify-center p-4 bg-muted/30",
|
|
329
329
|
children: /* @__PURE__ */ g(y, {
|
|
@@ -344,7 +344,7 @@ function P({ invitation: e }) {
|
|
|
344
344
|
className: "space-y-4",
|
|
345
345
|
children: [/* @__PURE__ */ g("div", {
|
|
346
346
|
className: "flex gap-3 p-4 rounded-lg border border-border bg-muted/50",
|
|
347
|
-
children: [/* @__PURE__ */ h(p, { className: "
|
|
347
|
+
children: [/* @__PURE__ */ h(p, { className: "size-5 text-muted-foreground flex-shrink-0 mt-0.5" }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
|
|
348
348
|
className: "font-medium",
|
|
349
349
|
children: t(n, "inviteAcceptance.invitationDeclined", "Invitation Declined")
|
|
350
350
|
}), /* @__PURE__ */ g("p", {
|
|
@@ -359,16 +359,16 @@ function P({ invitation: e }) {
|
|
|
359
359
|
]
|
|
360
360
|
})] })]
|
|
361
361
|
}), /* @__PURE__ */ g(v, {
|
|
362
|
-
onClick: () =>
|
|
362
|
+
onClick: () => r("/workspaces/list"),
|
|
363
363
|
className: "w-full",
|
|
364
|
-
children: [/* @__PURE__ */ h(u, { className: "mr-2
|
|
364
|
+
children: [/* @__PURE__ */ h(u, { className: "mr-2 size-4" }), t(n, "inviteAcceptance.goToWorkspaces", "Go to Workspaces")]
|
|
365
365
|
})]
|
|
366
366
|
})]
|
|
367
367
|
})
|
|
368
368
|
});
|
|
369
369
|
}
|
|
370
370
|
function F({ invitation: e }) {
|
|
371
|
-
let { t: n } = O();
|
|
371
|
+
let { t: n } = O(), r = E();
|
|
372
372
|
return /* @__PURE__ */ h("div", {
|
|
373
373
|
className: "min-h-screen flex items-center justify-center p-4 bg-muted/30",
|
|
374
374
|
children: /* @__PURE__ */ g(y, {
|
|
@@ -389,7 +389,7 @@ function F({ invitation: e }) {
|
|
|
389
389
|
className: "space-y-4",
|
|
390
390
|
children: [/* @__PURE__ */ g("div", {
|
|
391
391
|
className: "flex gap-3 p-4 rounded-lg border border-status-warning/30 bg-status-warning/10 transition-colors",
|
|
392
|
-
children: [/* @__PURE__ */ h(l, { className: "
|
|
392
|
+
children: [/* @__PURE__ */ h(l, { className: "size-5 text-status-warning flex-shrink-0 mt-0.5" }), /* @__PURE__ */ g("div", { children: [
|
|
393
393
|
/* @__PURE__ */ h("p", {
|
|
394
394
|
className: "font-medium text-status-warning",
|
|
395
395
|
children: t(n, "inviteAcceptance.expiredHeading", "Invitation No Longer Valid")
|
|
@@ -417,16 +417,16 @@ function F({ invitation: e }) {
|
|
|
417
417
|
})
|
|
418
418
|
] })]
|
|
419
419
|
}), /* @__PURE__ */ g(v, {
|
|
420
|
-
onClick: () =>
|
|
420
|
+
onClick: () => r("/workspaces/list"),
|
|
421
421
|
className: "w-full",
|
|
422
|
-
children: [/* @__PURE__ */ h(u, { className: "mr-2
|
|
422
|
+
children: [/* @__PURE__ */ h(u, { className: "mr-2 size-4" }), t(n, "inviteAcceptance.goToWorkspaces", "Go to Workspaces")]
|
|
423
423
|
})]
|
|
424
424
|
})]
|
|
425
425
|
})
|
|
426
426
|
});
|
|
427
427
|
}
|
|
428
428
|
function I({ invitation: e }) {
|
|
429
|
-
let { t: n } = O();
|
|
429
|
+
let { t: n } = O(), r = E();
|
|
430
430
|
return /* @__PURE__ */ h("div", {
|
|
431
431
|
className: "min-h-screen flex items-center justify-center p-4 bg-muted/30",
|
|
432
432
|
children: /* @__PURE__ */ g(y, {
|
|
@@ -447,7 +447,7 @@ function I({ invitation: e }) {
|
|
|
447
447
|
className: "space-y-4",
|
|
448
448
|
children: [/* @__PURE__ */ g("div", {
|
|
449
449
|
className: "flex gap-3 p-4 rounded-lg border border-destructive/50 bg-destructive/10",
|
|
450
|
-
children: [/* @__PURE__ */ h(s, { className: "
|
|
450
|
+
children: [/* @__PURE__ */ h(s, { className: "size-5 text-destructive flex-shrink-0 mt-0.5" }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("p", {
|
|
451
451
|
className: "font-medium text-destructive",
|
|
452
452
|
children: t(n, "inviteAcceptance.cancelledHeading", "Invitation No Longer Available")
|
|
453
453
|
}), /* @__PURE__ */ g("p", {
|
|
@@ -462,9 +462,9 @@ function I({ invitation: e }) {
|
|
|
462
462
|
]
|
|
463
463
|
})] })]
|
|
464
464
|
}), /* @__PURE__ */ g(v, {
|
|
465
|
-
onClick: () =>
|
|
465
|
+
onClick: () => r("/workspaces/list"),
|
|
466
466
|
className: "w-full",
|
|
467
|
-
children: [/* @__PURE__ */ h(u, { className: "mr-2
|
|
467
|
+
children: [/* @__PURE__ */ h(u, { className: "mr-2 size-4" }), t(n, "inviteAcceptance.goToWorkspaces", "Go to Workspaces")]
|
|
468
468
|
})]
|
|
469
469
|
})]
|
|
470
470
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InviteAcceptancePage.js","names":[],"sources":["../../src/pages/InviteAcceptancePage.tsx"],"sourcesContent":["import { useParams, useNavigate, useLocation } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Button,\n Badge,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Mail,\n CheckCircle,\n XCircle,\n Clock,\n AlertTriangle,\n Ban,\n Home,\n RefreshCw,\n} from 'lucide-react';\nimport { useInvitation } from '../hooks/useWorkspaceMembers';\nimport { useAcceptInvitation, useRejectInvitation } from '../hooks/useMemberMutations';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\nimport type { WorkspaceInvitation } from '../types';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\n\n/**\n * Page for accepting or rejecting workspace invitations\n * Accessible via /workspaces/invite/:invitationId\n */\nexport function InviteAcceptancePage() {\n useWorkspacesPageView('workspaces.invite');\n const { t } = useI18n();\n const { invitationId: routeInvitationId } = useParams<{ invitationId: string }>();\n const location = useLocation();\n const navigate = useNavigate();\n const { authToken } = useWorkspacesContext();\n const invitationId =\n routeInvitationId || location.pathname.split('/').filter(Boolean).at(-1) || '';\n const isAuthenticated = Boolean(authToken);\n\n const inviteLoginPath = invitationId\n ? `/auth/login?returnTo=${encodeURIComponent(`/workspaces/invite/${invitationId}`)}`\n : '/auth/login?returnTo=%2Fworkspaces%2Flist';\n\n // Fetch invitation details\n const {\n data: invitation,\n isLoading,\n error,\n refetch,\n } = useInvitation(invitationId || '', isAuthenticated);\n\n // Mutations\n const { mutate: acceptInvitation, isPending: isAccepting } = useAcceptInvitation();\n const { mutate: rejectInvitation, isPending: isRejecting } = useRejectInvitation();\n\n // Handler for accepting invitation\n const handleAccept = () => {\n if (!invitationId) return;\n\n acceptInvitation(invitationId, {\n onSuccess: (acceptedInvitation) => {\n // Redirect to workspace members page\n const workspaceId = acceptedInvitation.workspaceId || invitation?.workspaceId;\n if (workspaceId) {\n navigate(`/workspaces/${workspaceId}/members`);\n } else {\n navigate('/workspaces/list');\n }\n },\n onError: (error) => {\n console.error('Failed to accept invitation:', error);\n },\n });\n };\n\n if (!isAuthenticated) {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-muted/30 p-4\">\n <Card className=\"max-w-xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-primary/10 p-3\">\n <Mail className=\"text-primary\" size={24} />\n </div>\n <div>\n <CardTitle>\n {tWithFallback(\n t,\n 'inviteAcceptance.signInRequired',\n 'Sign in to view your invitation'\n )}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.signInDescription',\n 'Workspace invitations require an authenticated Burdenoff account before you can review or accept them.'\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'inviteAcceptance.signInHint',\n 'Use the same email address that received the invitation, then come back here to accept or reject it.'\n )}\n </p>\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <Button asChild>\n <a href={inviteLoginPath}>\n {tWithFallback(t, 'inviteAcceptance.signInButton', 'Sign In')}\n </a>\n </Button>\n <Button variant=\"outline\" onClick={() => navigate('/workspaces/list')}>\n <Home className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'inviteAcceptance.backToWorkspaces', 'Back to Workspaces')}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n }\n\n // Handler for rejecting invitation\n const handleReject = () => {\n if (!invitationId) return;\n\n rejectInvitation(invitationId, {\n onSuccess: () => {\n // Redirect to workspaces list\n navigate('/workspaces/list');\n },\n onError: (error) => {\n console.error('Failed to reject invitation:', error);\n },\n });\n };\n\n // Loading state\n if (isLoading) {\n return <LoadingSkeleton />;\n }\n\n // Error state (network error or other issues)\n if (error) {\n return <ErrorState error={error} onRetry={() => refetch()} />;\n }\n\n // Not found state\n if (!invitation) {\n return <NotFoundState />;\n }\n\n // Check invitation status and show appropriate UI\n switch (invitation.status) {\n case 'ACCEPTED':\n return <AlreadyAcceptedState invitation={invitation} />;\n case 'REJECTED':\n return <AlreadyRejectedState invitation={invitation} />;\n case 'EXPIRED':\n return <ExpiredState invitation={invitation} />;\n case 'CANCELLED':\n return <CancelledState invitation={invitation} />;\n case 'PENDING':\n // Check if invitation has expired based on expiresAt\n if (invitation.expiresAt && new Date(invitation.expiresAt) < new Date()) {\n return <ExpiredState invitation={invitation} />;\n }\n\n // Show main acceptance UI\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-primary/10\">\n <Mail className=\"text-primary\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.pageTitle', 'Workspace Invitation')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.pageSubtitle',\n \"You've been invited to join a workspace\"\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n {/* Invitation Details */}\n <div className=\"space-y-4 p-4 rounded-lg bg-muted/50\">\n <div>\n <p className=\"text-sm font-medium text-muted-foreground\">\n {tWithFallback(t, 'inviteAcceptance.emailAddressLabel', 'Email Address')}\n </p>\n <p className=\"text-lg font-medium mt-1\">{invitation.email}</p>\n </div>\n\n {invitation.expiresAt && (\n <div>\n <p className=\"text-sm font-medium text-muted-foreground\">\n {tWithFallback(t, 'inviteAcceptance.expiresLabel', 'Expires')}\n </p>\n <p className=\"text-lg font-medium mt-1 flex items-center gap-2\">\n <Clock size={16} className=\"text-muted-foreground\" />\n {new Date(invitation.expiresAt).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n })}\n </p>\n </div>\n )}\n\n {invitation.roleIds && invitation.roleIds.length > 0 && (\n <div>\n <p className=\"text-sm font-medium text-muted-foreground mb-2\">\n {tWithFallback(t, 'inviteAcceptance.rolesLabel', 'Roles')}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {invitation.roleIds.map((roleId) => (\n <Badge key={roleId} variant=\"secondary\">\n {roleId}\n </Badge>\n ))}\n </div>\n </div>\n )}\n\n <div>\n <p className=\"text-sm font-medium text-muted-foreground\">\n {tWithFallback(t, 'inviteAcceptance.invitationIdLabel', 'Invitation ID')}\n </p>\n <p className=\"text-sm font-mono mt-1 text-muted-foreground\">{invitation.id}</p>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-col sm:flex-row gap-3 pt-4 border-t\">\n <Button\n onClick={handleAccept}\n disabled={isAccepting || isRejecting}\n className=\"flex-1\"\n size=\"lg\"\n >\n {isAccepting ? (\n <>\n <RefreshCw className=\"mr-2 h-4 w-4 animate-spin\" />\n {tWithFallback(t, 'inviteAcceptance.accepting', 'Accepting...')}\n </>\n ) : (\n <>\n <CheckCircle className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'inviteAcceptance.acceptButton', 'Accept Invitation')}\n </>\n )}\n </Button>\n <Button\n variant=\"outline\"\n onClick={handleReject}\n disabled={isAccepting || isRejecting}\n className=\"flex-1\"\n size=\"lg\"\n >\n {isRejecting ? (\n <>\n <RefreshCw className=\"mr-2 h-4 w-4 animate-spin\" />\n {tWithFallback(t, 'inviteAcceptance.rejecting', 'Rejecting...')}\n </>\n ) : (\n <>\n <XCircle className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'inviteAcceptance.rejectButton', 'Reject')}\n </>\n )}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n\n default:\n return <NotFoundState />;\n }\n}\n\n/**\n * Loading skeleton while fetching invitation\n */\nfunction LoadingSkeleton() {\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"h-12 w-12 rounded-lg\" />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-6 w-48\" />\n <Skeleton className=\"h-4 w-64\" />\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n <div className=\"space-y-4 p-4 rounded-lg bg-muted/50\">\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-6 w-48\" />\n </div>\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-6 w-64\" />\n </div>\n </div>\n <div className=\"flex gap-3 pt-4\">\n <Skeleton className=\"h-12 flex-1\" />\n <Skeleton className=\"h-12 flex-1\" />\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Error state with retry option\n */\nfunction ErrorState({ error, onRetry }: { error: Error; onRetry: () => void }) {\n const { t } = useI18n();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-destructive/10\">\n <AlertTriangle className=\"text-destructive\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.errorTitle', 'Error Loading Invitation')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.errorDescription',\n \"We couldn't load this invitation. Please try again.\"\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-destructive/50 bg-destructive/10\">\n <AlertTriangle className=\"h-5 w-5 text-destructive flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium text-destructive\">\n {tWithFallback(t, 'inviteAcceptance.errorDetailsLabel', 'Error Details')}\n </p>\n <p className=\"text-sm mt-1 text-destructive/90\">{error.message}</p>\n </div>\n </div>\n\n <div className=\"flex gap-3\">\n <Button onClick={onRetry} className=\"flex-1\">\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'inviteAcceptance.tryAgain', 'Try Again')}\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => (window.location.href = '/workspaces/list')}\n className=\"flex-1\"\n >\n <Home className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'inviteAcceptance.goToWorkspaces', 'Go to Workspaces')}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Not found state (invalid invitation ID)\n */\nfunction NotFoundState() {\n const { t } = useI18n();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-muted\">\n <AlertTriangle className=\"text-muted-foreground\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.notFoundTitle', 'Invitation Not Found')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.notFoundDescription',\n 'This invitation link is invalid or has been removed'\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-border bg-muted/50\">\n <AlertTriangle className=\"h-5 w-5 text-muted-foreground flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium\">\n {tWithFallback(t, 'inviteAcceptance.invalidLinkHeading', 'Invalid Invitation Link')}\n </p>\n <p className=\"text-sm mt-1 text-muted-foreground\">\n {tWithFallback(\n t,\n 'inviteAcceptance.invalidLinkBody',\n \"The invitation you're trying to access doesn't exist. It may have been deleted or the link is incorrect.\"\n )}\n </p>\n </div>\n </div>\n\n <Button onClick={() => (window.location.href = '/workspaces/list')} className=\"w-full\">\n <Home className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'inviteAcceptance.goToWorkspaces', 'Go to Workspaces')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Already accepted state\n */\nfunction AlreadyAcceptedState({ invitation }: { invitation: WorkspaceInvitation }) {\n const { t } = useI18n();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-status-success/10 transition-colors\">\n <CheckCircle className=\"text-status-success\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(\n t,\n 'inviteAcceptance.alreadyAcceptedTitle',\n 'Invitation Already Accepted'\n )}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.alreadyAcceptedDescription',\n 'This invitation has already been accepted'\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-status-success/30 bg-status-success/10 transition-colors\">\n <CheckCircle className=\"h-5 w-5 text-status-success flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium text-status-success\">\n {tWithFallback(t, 'inviteAcceptance.alreadyMember', \"You're already a member\")}\n </p>\n <p className=\"text-sm mt-1 text-status-success/80\">\n {tWithFallback(t, 'inviteAcceptance.alreadyAcceptedPrefix', 'This invitation to ')}\n <span className=\"font-medium\">{invitation.email}</span>\n {tWithFallback(\n t,\n 'inviteAcceptance.alreadyAcceptedSuffix',\n ' has already been accepted.'\n )}\n </p>\n </div>\n </div>\n\n <Button\n onClick={() => (window.location.href = `/workspaces/${invitation.workspaceId}/members`)}\n className=\"w-full\"\n >\n {tWithFallback(t, 'inviteAcceptance.goToWorkspace', 'Go to Workspace')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Already rejected state\n */\nfunction AlreadyRejectedState({ invitation }: { invitation: WorkspaceInvitation }) {\n const { t } = useI18n();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-muted\">\n <XCircle className=\"text-muted-foreground\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.rejectedTitle', 'Invitation Rejected')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.rejectedDescription',\n \"You've already declined this invitation\"\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-border bg-muted/50\">\n <XCircle className=\"h-5 w-5 text-muted-foreground flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium\">\n {tWithFallback(t, 'inviteAcceptance.invitationDeclined', 'Invitation Declined')}\n </p>\n <p className=\"text-sm mt-1 text-muted-foreground\">\n {tWithFallback(t, 'inviteAcceptance.rejectedPrefix', 'This invitation to ')}\n <span className=\"font-medium\">{invitation.email}</span>\n {tWithFallback(t, 'inviteAcceptance.rejectedSuffix', ' was previously rejected.')}\n </p>\n </div>\n </div>\n\n <Button onClick={() => (window.location.href = '/workspaces/list')} className=\"w-full\">\n <Home className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'inviteAcceptance.goToWorkspaces', 'Go to Workspaces')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Expired state\n */\nfunction ExpiredState({ invitation }: { invitation: WorkspaceInvitation }) {\n const { t } = useI18n();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-status-warning/10 transition-colors\">\n <Clock className=\"text-status-warning\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.expiredTitle', 'Invitation Expired')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.expiredDescription',\n 'This invitation has expired'\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-status-warning/30 bg-status-warning/10 transition-colors\">\n <Clock className=\"h-5 w-5 text-status-warning flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium text-status-warning\">\n {tWithFallback(t, 'inviteAcceptance.expiredHeading', 'Invitation No Longer Valid')}\n </p>\n <p className=\"text-sm mt-1 text-status-warning/80\">\n {tWithFallback(t, 'inviteAcceptance.expiredPrefix', 'This invitation to ')}\n <span className=\"font-medium\">{invitation.email}</span>\n {tWithFallback(t, 'inviteAcceptance.expiredMiddle', ' expired on ')}\n {invitation.expiresAt &&\n new Date(invitation.expiresAt).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n })}\n .\n </p>\n <p className=\"text-sm mt-2 text-status-warning/80\">\n {tWithFallback(\n t,\n 'inviteAcceptance.expiredContactAdmin',\n 'Please contact the workspace admin to request a new invitation.'\n )}\n </p>\n </div>\n </div>\n\n <Button onClick={() => (window.location.href = '/workspaces/list')} className=\"w-full\">\n <Home className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'inviteAcceptance.goToWorkspaces', 'Go to Workspaces')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Cancelled state\n */\nfunction CancelledState({ invitation }: { invitation: WorkspaceInvitation }) {\n const { t } = useI18n();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-destructive/10\">\n <Ban className=\"text-destructive\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.cancelledTitle', 'Invitation Cancelled')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.cancelledDescription',\n 'This invitation has been cancelled by the sender'\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-destructive/50 bg-destructive/10\">\n <Ban className=\"h-5 w-5 text-destructive flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium text-destructive\">\n {tWithFallback(\n t,\n 'inviteAcceptance.cancelledHeading',\n 'Invitation No Longer Available'\n )}\n </p>\n <p className=\"text-sm mt-1 text-destructive/90\">\n {tWithFallback(t, 'inviteAcceptance.cancelledPrefix', 'This invitation to ')}\n <span className=\"font-medium\">{invitation.email}</span>\n {tWithFallback(\n t,\n 'inviteAcceptance.cancelledSuffix',\n ' was cancelled by the workspace admin and is no longer valid.'\n )}\n </p>\n </div>\n </div>\n\n <Button onClick={() => (window.location.href = '/workspaces/list')} className=\"w-full\">\n <Home className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'inviteAcceptance.goToWorkspaces', 'Go to Workspaces')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InviteAcceptancePage.js","names":[],"sources":["../../src/pages/InviteAcceptancePage.tsx"],"sourcesContent":["import { useParams, useNavigate, useLocation } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Button,\n Badge,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Mail,\n CheckCircle,\n XCircle,\n Clock,\n AlertTriangle,\n Ban,\n Home,\n RefreshCw,\n} from 'lucide-react';\nimport { useInvitation } from '../hooks/useWorkspaceMembers';\nimport { useAcceptInvitation, useRejectInvitation } from '../hooks/useMemberMutations';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\nimport type { WorkspaceInvitation } from '../types';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\n\n/**\n * Page for accepting or rejecting workspace invitations\n * Accessible via /workspaces/invite/:invitationId\n */\nexport function InviteAcceptancePage() {\n useWorkspacesPageView('workspaces.invite');\n const { t } = useI18n();\n const { invitationId: routeInvitationId } = useParams<{ invitationId: string }>();\n const location = useLocation();\n const navigate = useNavigate();\n const { authToken } = useWorkspacesContext();\n const invitationId =\n routeInvitationId || location.pathname.split('/').filter(Boolean).at(-1) || '';\n const isAuthenticated = Boolean(authToken);\n\n const inviteLoginPath = invitationId\n ? `/auth/login?returnTo=${encodeURIComponent(`/workspaces/invite/${invitationId}`)}`\n : '/auth/login?returnTo=%2Fworkspaces%2Flist';\n\n // Fetch invitation details\n const {\n data: invitation,\n isLoading,\n error,\n refetch,\n } = useInvitation(invitationId || '', isAuthenticated);\n\n // Mutations\n const { mutate: acceptInvitation, isPending: isAccepting } = useAcceptInvitation();\n const { mutate: rejectInvitation, isPending: isRejecting } = useRejectInvitation();\n\n // Handler for accepting invitation\n const handleAccept = () => {\n if (!invitationId) return;\n\n acceptInvitation(invitationId, {\n onSuccess: (acceptedInvitation) => {\n // Redirect to workspace members page\n const workspaceId = acceptedInvitation.workspaceId || invitation?.workspaceId;\n if (workspaceId) {\n navigate(`/workspaces/${workspaceId}/members`);\n } else {\n navigate('/workspaces/list');\n }\n },\n onError: (error) => {\n console.error('Failed to accept invitation:', error);\n },\n });\n };\n\n if (!isAuthenticated) {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-muted/30 p-4\">\n <Card className=\"max-w-xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-primary/10 p-3\">\n <Mail className=\"text-primary\" size={24} />\n </div>\n <div>\n <CardTitle>\n {tWithFallback(\n t,\n 'inviteAcceptance.signInRequired',\n 'Sign in to view your invitation'\n )}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.signInDescription',\n 'Workspace invitations require an authenticated Burdenoff account before you can review or accept them.'\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(\n t,\n 'inviteAcceptance.signInHint',\n 'Use the same email address that received the invitation, then come back here to accept or reject it.'\n )}\n </p>\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <Button asChild>\n <a href={inviteLoginPath}>\n {tWithFallback(t, 'inviteAcceptance.signInButton', 'Sign In')}\n </a>\n </Button>\n <Button variant=\"outline\" onClick={() => navigate('/workspaces/list')}>\n <Home className=\"mr-2 size-4\" />\n {tWithFallback(t, 'inviteAcceptance.backToWorkspaces', 'Back to Workspaces')}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n }\n\n // Handler for rejecting invitation\n const handleReject = () => {\n if (!invitationId) return;\n\n rejectInvitation(invitationId, {\n onSuccess: () => {\n // Redirect to workspaces list\n navigate('/workspaces/list');\n },\n onError: (error) => {\n console.error('Failed to reject invitation:', error);\n },\n });\n };\n\n // Loading state\n if (isLoading) {\n return <LoadingSkeleton />;\n }\n\n // Error state (network error or other issues)\n if (error) {\n return <ErrorState error={error} onRetry={() => refetch()} />;\n }\n\n // Not found state\n if (!invitation) {\n return <NotFoundState />;\n }\n\n // Check invitation status and show appropriate UI\n switch (invitation.status) {\n case 'ACCEPTED':\n return <AlreadyAcceptedState invitation={invitation} />;\n case 'REJECTED':\n return <AlreadyRejectedState invitation={invitation} />;\n case 'EXPIRED':\n return <ExpiredState invitation={invitation} />;\n case 'CANCELLED':\n return <CancelledState invitation={invitation} />;\n case 'PENDING':\n // Check if invitation has expired based on expiresAt\n if (invitation.expiresAt && new Date(invitation.expiresAt) < new Date()) {\n return <ExpiredState invitation={invitation} />;\n }\n\n // Show main acceptance UI\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-primary/10\">\n <Mail className=\"text-primary\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.pageTitle', 'Workspace Invitation')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.pageSubtitle',\n \"You've been invited to join a workspace\"\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n {/* Invitation Details */}\n <div className=\"space-y-4 p-4 rounded-lg bg-muted/50\">\n <div>\n <p className=\"text-sm font-medium text-muted-foreground\">\n {tWithFallback(t, 'inviteAcceptance.emailAddressLabel', 'Email Address')}\n </p>\n <p className=\"text-lg font-medium mt-1\">{invitation.email}</p>\n </div>\n\n {invitation.expiresAt && (\n <div>\n <p className=\"text-sm font-medium text-muted-foreground\">\n {tWithFallback(t, 'inviteAcceptance.expiresLabel', 'Expires')}\n </p>\n <p className=\"text-lg font-medium mt-1 flex items-center gap-2\">\n <Clock size={16} className=\"text-muted-foreground\" />\n {new Date(invitation.expiresAt).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n })}\n </p>\n </div>\n )}\n\n {invitation.roleIds && invitation.roleIds.length > 0 && (\n <div>\n <p className=\"text-sm font-medium text-muted-foreground mb-2\">\n {tWithFallback(t, 'inviteAcceptance.rolesLabel', 'Roles')}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {invitation.roleIds.map((roleId) => (\n <Badge key={roleId} variant=\"secondary\">\n {roleId}\n </Badge>\n ))}\n </div>\n </div>\n )}\n\n <div>\n <p className=\"text-sm font-medium text-muted-foreground\">\n {tWithFallback(t, 'inviteAcceptance.invitationIdLabel', 'Invitation ID')}\n </p>\n <p className=\"text-sm font-mono mt-1 text-muted-foreground\">{invitation.id}</p>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-col sm:flex-row gap-3 pt-4 border-t\">\n <Button\n onClick={handleAccept}\n disabled={isAccepting || isRejecting}\n className=\"flex-1\"\n size=\"lg\"\n >\n {isAccepting ? (\n <>\n <RefreshCw className=\"mr-2 size-4 animate-spin\" />\n {tWithFallback(t, 'inviteAcceptance.accepting', 'Accepting...')}\n </>\n ) : (\n <>\n <CheckCircle className=\"mr-2 size-4\" />\n {tWithFallback(t, 'inviteAcceptance.acceptButton', 'Accept Invitation')}\n </>\n )}\n </Button>\n <Button\n variant=\"outline\"\n onClick={handleReject}\n disabled={isAccepting || isRejecting}\n className=\"flex-1\"\n size=\"lg\"\n >\n {isRejecting ? (\n <>\n <RefreshCw className=\"mr-2 size-4 animate-spin\" />\n {tWithFallback(t, 'inviteAcceptance.rejecting', 'Rejecting...')}\n </>\n ) : (\n <>\n <XCircle className=\"mr-2 size-4\" />\n {tWithFallback(t, 'inviteAcceptance.rejectButton', 'Reject')}\n </>\n )}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n\n default:\n return <NotFoundState />;\n }\n}\n\n/**\n * Loading skeleton while fetching invitation\n */\nfunction LoadingSkeleton() {\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"size-12 rounded-lg\" />\n <div className=\"flex-1 space-y-2\">\n <Skeleton className=\"h-6 w-48\" />\n <Skeleton className=\"h-4 w-64\" />\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n <div className=\"space-y-4 p-4 rounded-lg bg-muted/50\">\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-6 w-48\" />\n </div>\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-6 w-64\" />\n </div>\n </div>\n <div className=\"flex gap-3 pt-4\">\n <Skeleton className=\"h-12 flex-1\" />\n <Skeleton className=\"h-12 flex-1\" />\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Error state with retry option\n */\nfunction ErrorState({ error, onRetry }: { error: Error; onRetry: () => void }) {\n const { t } = useI18n();\n const navigate = useNavigate();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-destructive/10\">\n <AlertTriangle className=\"text-destructive\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.errorTitle', 'Error Loading Invitation')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.errorDescription',\n \"We couldn't load this invitation. Please try again.\"\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-destructive/50 bg-destructive/10\">\n <AlertTriangle className=\"size-5 text-destructive flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium text-destructive\">\n {tWithFallback(t, 'inviteAcceptance.errorDetailsLabel', 'Error Details')}\n </p>\n <p className=\"text-sm mt-1 text-destructive/90\">{error.message}</p>\n </div>\n </div>\n\n <div className=\"flex gap-3\">\n <Button onClick={onRetry} className=\"flex-1\">\n <RefreshCw className=\"mr-2 size-4\" />\n {tWithFallback(t, 'inviteAcceptance.tryAgain', 'Try Again')}\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => navigate('/workspaces/list')}\n className=\"flex-1\"\n >\n <Home className=\"mr-2 size-4\" />\n {tWithFallback(t, 'inviteAcceptance.goToWorkspaces', 'Go to Workspaces')}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Not found state (invalid invitation ID)\n */\nfunction NotFoundState() {\n const { t } = useI18n();\n const navigate = useNavigate();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-muted\">\n <AlertTriangle className=\"text-muted-foreground\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.notFoundTitle', 'Invitation Not Found')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.notFoundDescription',\n 'This invitation link is invalid or has been removed'\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-border bg-muted/50\">\n <AlertTriangle className=\"size-5 text-muted-foreground flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium\">\n {tWithFallback(t, 'inviteAcceptance.invalidLinkHeading', 'Invalid Invitation Link')}\n </p>\n <p className=\"text-sm mt-1 text-muted-foreground\">\n {tWithFallback(\n t,\n 'inviteAcceptance.invalidLinkBody',\n \"The invitation you're trying to access doesn't exist. It may have been deleted or the link is incorrect.\"\n )}\n </p>\n </div>\n </div>\n\n <Button onClick={() => navigate('/workspaces/list')} className=\"w-full\">\n <Home className=\"mr-2 size-4\" />\n {tWithFallback(t, 'inviteAcceptance.goToWorkspaces', 'Go to Workspaces')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Already accepted state\n */\nfunction AlreadyAcceptedState({ invitation }: { invitation: WorkspaceInvitation }) {\n const { t } = useI18n();\n const navigate = useNavigate();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-status-success/10 transition-colors\">\n <CheckCircle className=\"text-status-success\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(\n t,\n 'inviteAcceptance.alreadyAcceptedTitle',\n 'Invitation Already Accepted'\n )}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.alreadyAcceptedDescription',\n 'This invitation has already been accepted'\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-status-success/30 bg-status-success/10 transition-colors\">\n <CheckCircle className=\"size-5 text-status-success flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium text-status-success\">\n {tWithFallback(t, 'inviteAcceptance.alreadyMember', \"You're already a member\")}\n </p>\n <p className=\"text-sm mt-1 text-status-success/80\">\n {tWithFallback(t, 'inviteAcceptance.alreadyAcceptedPrefix', 'This invitation to ')}\n <span className=\"font-medium\">{invitation.email}</span>\n {tWithFallback(\n t,\n 'inviteAcceptance.alreadyAcceptedSuffix',\n ' has already been accepted.'\n )}\n </p>\n </div>\n </div>\n\n <Button\n onClick={() => navigate(`/workspaces/${invitation.workspaceId}/members`)}\n className=\"w-full\"\n >\n {tWithFallback(t, 'inviteAcceptance.goToWorkspace', 'Go to Workspace')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Already rejected state\n */\nfunction AlreadyRejectedState({ invitation }: { invitation: WorkspaceInvitation }) {\n const { t } = useI18n();\n const navigate = useNavigate();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-muted\">\n <XCircle className=\"text-muted-foreground\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.rejectedTitle', 'Invitation Rejected')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.rejectedDescription',\n \"You've already declined this invitation\"\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-border bg-muted/50\">\n <XCircle className=\"size-5 text-muted-foreground flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium\">\n {tWithFallback(t, 'inviteAcceptance.invitationDeclined', 'Invitation Declined')}\n </p>\n <p className=\"text-sm mt-1 text-muted-foreground\">\n {tWithFallback(t, 'inviteAcceptance.rejectedPrefix', 'This invitation to ')}\n <span className=\"font-medium\">{invitation.email}</span>\n {tWithFallback(t, 'inviteAcceptance.rejectedSuffix', ' was previously rejected.')}\n </p>\n </div>\n </div>\n\n <Button onClick={() => navigate('/workspaces/list')} className=\"w-full\">\n <Home className=\"mr-2 size-4\" />\n {tWithFallback(t, 'inviteAcceptance.goToWorkspaces', 'Go to Workspaces')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Expired state\n */\nfunction ExpiredState({ invitation }: { invitation: WorkspaceInvitation }) {\n const { t } = useI18n();\n const navigate = useNavigate();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-status-warning/10 transition-colors\">\n <Clock className=\"text-status-warning\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.expiredTitle', 'Invitation Expired')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.expiredDescription',\n 'This invitation has expired'\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-status-warning/30 bg-status-warning/10 transition-colors\">\n <Clock className=\"size-5 text-status-warning flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium text-status-warning\">\n {tWithFallback(t, 'inviteAcceptance.expiredHeading', 'Invitation No Longer Valid')}\n </p>\n <p className=\"text-sm mt-1 text-status-warning/80\">\n {tWithFallback(t, 'inviteAcceptance.expiredPrefix', 'This invitation to ')}\n <span className=\"font-medium\">{invitation.email}</span>\n {tWithFallback(t, 'inviteAcceptance.expiredMiddle', ' expired on ')}\n {invitation.expiresAt &&\n new Date(invitation.expiresAt).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n })}\n .\n </p>\n <p className=\"text-sm mt-2 text-status-warning/80\">\n {tWithFallback(\n t,\n 'inviteAcceptance.expiredContactAdmin',\n 'Please contact the workspace admin to request a new invitation.'\n )}\n </p>\n </div>\n </div>\n\n <Button onClick={() => navigate('/workspaces/list')} className=\"w-full\">\n <Home className=\"mr-2 size-4\" />\n {tWithFallback(t, 'inviteAcceptance.goToWorkspaces', 'Go to Workspaces')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n}\n\n/**\n * Cancelled state\n */\nfunction CancelledState({ invitation }: { invitation: WorkspaceInvitation }) {\n const { t } = useI18n();\n const navigate = useNavigate();\n return (\n <div className=\"min-h-screen flex items-center justify-center p-4 bg-muted/30\">\n <Card className=\"max-w-2xl w-full\">\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-destructive/10\">\n <Ban className=\"text-destructive\" size={24} />\n </div>\n <div className=\"flex-1\">\n <CardTitle>\n {tWithFallback(t, 'inviteAcceptance.cancelledTitle', 'Invitation Cancelled')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'inviteAcceptance.cancelledDescription',\n 'This invitation has been cancelled by the sender'\n )}\n </CardDescription>\n </div>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"flex gap-3 p-4 rounded-lg border border-destructive/50 bg-destructive/10\">\n <Ban className=\"size-5 text-destructive flex-shrink-0 mt-0.5\" />\n <div>\n <p className=\"font-medium text-destructive\">\n {tWithFallback(\n t,\n 'inviteAcceptance.cancelledHeading',\n 'Invitation No Longer Available'\n )}\n </p>\n <p className=\"text-sm mt-1 text-destructive/90\">\n {tWithFallback(t, 'inviteAcceptance.cancelledPrefix', 'This invitation to ')}\n <span className=\"font-medium\">{invitation.email}</span>\n {tWithFallback(\n t,\n 'inviteAcceptance.cancelledSuffix',\n ' was cancelled by the workspace admin and is no longer valid.'\n )}\n </p>\n </div>\n </div>\n\n <Button onClick={() => navigate('/workspaces/list')} className=\"w-full\">\n <Home className=\"mr-2 size-4\" />\n {tWithFallback(t, 'inviteAcceptance.goToWorkspaces', 'Go to Workspaces')}\n </Button>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AAiCA,SAAgB,IAAuB;AACrC,GAAsB,oBAAoB;CAC1C,IAAM,EAAE,SAAM,GAAS,EACjB,EAAE,cAAc,MAAsB,GAAqC,EAC3E,IAAW,GAAa,EACxB,IAAW,GAAa,EACxB,EAAE,iBAAc,GAAsB,EACtC,IACJ,KAAqB,EAAS,SAAS,MAAM,IAAI,CAAC,OAAO,QAAQ,CAAC,GAAG,GAAG,IAAI,IACxE,IAAkB,EAAQ,GAE1B,IAAkB,IACpB,wBAAwB,mBAAmB,sBAAsB,IAAe,KAChF,6CAGE,EACJ,MAAM,GACN,cACA,UACA,eACE,EAAc,KAAgB,IAAI,EAAgB,EAGhD,EAAE,QAAQ,GAAkB,WAAW,MAAgB,GAAqB,EAC5E,EAAE,QAAQ,GAAkB,WAAW,MAAgB,GAAqB,EAG5E,UAAqB;AACpB,OAEL,EAAiB,GAAc;GAC7B,YAAY,MAAuB;IAEjC,IAAM,IAAc,EAAmB,eAAe,GAAY;AAClE,IACE,EADE,IACO,eAAe,EAAY,YAE3B,mBAAmB;;GAGhC,UAAU,MAAU;AAClB,YAAQ,MAAM,gCAAgC,EAAM;;GAEvD,CAAC;;AAGJ,KAAI,CAAC,EACH,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAM,WAAU;MAAe,MAAM;MAAM,CAAA;KACvC,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACG,EACC,GACA,mCACA,kCACD,EACS,CAAA,EACZ,kBAAC,GAAD,EAAA,UACG,EACC,GACA,sCACA,yGACD,EACe,CAAA,CACd,EAAA,CAAA,CACF;OACK,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB,CACE,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,GACA,+BACA,uGACD;KACC,CAAA,EACJ,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAQ,SAAA;gBACN,kBAAC,KAAD;OAAG,MAAM;iBACN,EAAc,GAAG,iCAAiC,UAAU;OAC3D,CAAA;MACG,CAAA,EACT,kBAAC,GAAD;MAAQ,SAAQ;MAAU,eAAe,EAAS,mBAAmB;gBAArE,CACE,kBAAC,GAAD,EAAM,WAAU,eAAgB,CAAA,EAC/B,EAAc,GAAG,qCAAqC,qBAAqB,CACrE;QACL;OACM;MACT;;EACH,CAAA;CAKV,IAAM,UAAqB;AACpB,OAEL,EAAiB,GAAc;GAC7B,iBAAiB;AAEf,MAAS,mBAAmB;;GAE9B,UAAU,MAAU;AAClB,YAAQ,MAAM,gCAAgC,EAAM;;GAEvD,CAAC;;AAIJ,KAAI,EACF,QAAO,kBAAC,GAAD,EAAmB,CAAA;AAI5B,KAAI,EACF,QAAO,kBAAC,GAAD;EAAmB;EAAO,eAAe,GAAS;EAAI,CAAA;AAI/D,KAAI,CAAC,EACH,QAAO,kBAAC,GAAD,EAAiB,CAAA;AAI1B,SAAQ,EAAW,QAAnB;EACE,KAAK,WACH,QAAO,kBAAC,GAAD,EAAkC,eAAc,CAAA;EACzD,KAAK,WACH,QAAO,kBAAC,GAAD,EAAkC,eAAc,CAAA;EACzD,KAAK,UACH,QAAO,kBAAC,GAAD,EAA0B,eAAc,CAAA;EACjD,KAAK,YACH,QAAO,kBAAC,GAAD,EAA4B,eAAc,CAAA;EACnD,KAAK,UAOH,QALI,EAAW,aAAa,IAAI,KAAK,EAAW,UAAU,mBAAG,IAAI,MAAM,GAC9D,kBAAC,GAAD,EAA0B,eAAc,CAAA,GAK/C,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD;OAAM,WAAU;OAAe,MAAM;OAAM,CAAA;MACvC,CAAA,EACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAA,UACG,EAAc,GAAG,8BAA8B,uBAAuB,EAC7D,CAAA,EACZ,kBAAC,GAAD,EAAA,UACG,EACC,GACA,iCACA,0CACD,EACe,CAAA,CACd;QACF;QACK,CAAA,EACb,kBAAC,GAAD;KAAa,WAAU;eAAvB,CAEE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAc,GAAG,sCAAsC,gBAAgB;QACtE,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBAA4B,EAAW;QAAU,CAAA,CAC1D,EAAA,CAAA;OAEL,EAAW,aACV,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAc,GAAG,iCAAiC,UAAU;QAC3D,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBAAb,CACE,kBAAC,GAAD;SAAO,MAAM;SAAI,WAAU;SAA0B,CAAA,EACpD,IAAI,KAAK,EAAW,UAAU,CAAC,mBAAmB,SAAS;SAC1D,MAAM;SACN,OAAO;SACP,KAAK;SACL,MAAM;SACN,QAAQ;SACT,CAAC,CACA;UACA,EAAA,CAAA;OAGP,EAAW,WAAW,EAAW,QAAQ,SAAS,KACjD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAc,GAAG,+BAA+B,QAAQ;QACvD,CAAA,EACJ,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAW,QAAQ,KAAK,MACvB,kBAAC,GAAD;SAAoB,SAAQ;mBACzB;SACK,EAFI,EAEJ,CACR;QACE,CAAA,CACF,EAAA,CAAA;OAGR,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAc,GAAG,sCAAsC,gBAAgB;QACtE,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBAAgD,EAAW;QAAO,CAAA,CAC3E,EAAA,CAAA;OACF;SAGN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OACE,SAAS;OACT,UAAU,KAAe;OACzB,WAAU;OACV,MAAK;iBAEJ,IACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAW,WAAU,4BAA6B,CAAA,EACjD,EAAc,GAAG,8BAA8B,eAAe,CAC9D,EAAA,CAAA,GAEH,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAa,WAAU,eAAgB,CAAA,EACtC,EAAc,GAAG,iCAAiC,oBAAoB,CACtE,EAAA,CAAA;OAEE,CAAA,EACT,kBAAC,GAAD;OACE,SAAQ;OACR,SAAS;OACT,UAAU,KAAe;OACzB,WAAU;OACV,MAAK;iBAEJ,IACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAW,WAAU,4BAA6B,CAAA,EACjD,EAAc,GAAG,8BAA8B,eAAe,CAC9D,EAAA,CAAA,GAEH,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAS,WAAU,eAAgB,CAAA,EAClC,EAAc,GAAG,iCAAiC,SAAS,CAC3D,EAAA,CAAA;OAEE,CAAA,CACL;QACM;OACT;;GACH,CAAA;EAGV,QACE,QAAO,kBAAC,GAAD,EAAiB,CAAA;;;AAO9B,SAAS,IAAkB;AACzB,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAU,WAAU,sBAAuB,CAAA,EAC3C,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,EACjC,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,CAC7B;OACF;OACK,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,EACjC,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,CAC7B;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,EACjC,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,CAC7B;QACF;QACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,EACpC,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,CAChC;OACM;MACT;;EACH,CAAA;;AAOV,SAAS,EAAW,EAAE,UAAO,cAAkD;CAC7E,IAAM,EAAE,SAAM,GAAS,EACjB,IAAW,GAAa;AAC9B,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAe,WAAU;MAAmB,MAAM;MAAM,CAAA;KACpD,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAA,UACG,EAAc,GAAG,+BAA+B,2BAA2B,EAClE,CAAA,EACZ,kBAAC,GAAD,EAAA,UACG,EACC,GACA,qCACA,sDACD,EACe,CAAA,CACd;OACF;OACK,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAe,WAAU,gDAAiD,CAAA,EAC1E,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAc,GAAG,sCAAsC,gBAAgB;MACtE,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBAAoC,EAAM;MAAY,CAAA,CAC/D,EAAA,CAAA,CACF;QAEN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAQ,SAAS;MAAS,WAAU;gBAApC,CACE,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA,EACpC,EAAc,GAAG,6BAA6B,YAAY,CACpD;SACT,kBAAC,GAAD;MACE,SAAQ;MACR,eAAe,EAAS,mBAAmB;MAC3C,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,eAAgB,CAAA,EAC/B,EAAc,GAAG,mCAAmC,mBAAmB,CACjE;QACL;OACM;MACT;;EACH,CAAA;;AAOV,SAAS,IAAgB;CACvB,IAAM,EAAE,SAAM,GAAS,EACjB,IAAW,GAAa;AAC9B,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAe,WAAU;MAAwB,MAAM;MAAM,CAAA;KACzD,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAA,UACG,EAAc,GAAG,kCAAkC,uBAAuB,EACjE,CAAA,EACZ,kBAAC,GAAD,EAAA,UACG,EACC,GACA,wCACA,sDACD,EACe,CAAA,CACd;OACF;OACK,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAe,WAAU,qDAAsD,CAAA,EAC/E,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAc,GAAG,uCAAuC,0BAA0B;MACjF,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBACV,EACC,GACA,oCACA,2GACD;MACC,CAAA,CACA,EAAA,CAAA,CACF;QAEN,kBAAC,GAAD;KAAQ,eAAe,EAAS,mBAAmB;KAAE,WAAU;eAA/D,CACE,kBAAC,GAAD,EAAM,WAAU,eAAgB,CAAA,EAC/B,EAAc,GAAG,mCAAmC,mBAAmB,CACjE;OACG;MACT;;EACH,CAAA;;AAOV,SAAS,EAAqB,EAAE,iBAAmD;CACjF,IAAM,EAAE,SAAM,GAAS,EACjB,IAAW,GAAa;AAC9B,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAa,WAAU;MAAsB,MAAM;MAAM,CAAA;KACrD,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAA,UACG,EACC,GACA,yCACA,8BACD,EACS,CAAA,EACZ,kBAAC,GAAD,EAAA,UACG,EACC,GACA,+CACA,4CACD,EACe,CAAA,CACd;OACF;OACK,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAa,WAAU,mDAAoD,CAAA,EAC3E,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAc,GAAG,kCAAkC,0BAA0B;MAC5E,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAc,GAAG,0CAA0C,sBAAsB;OAClF,kBAAC,QAAD;QAAM,WAAU;kBAAe,EAAW;QAAa,CAAA;OACtD,EACC,GACA,0CACA,8BACD;OACC;QACA,EAAA,CAAA,CACF;QAEN,kBAAC,GAAD;KACE,eAAe,EAAS,eAAe,EAAW,YAAY,UAAU;KACxE,WAAU;eAET,EAAc,GAAG,kCAAkC,kBAAkB;KAC/D,CAAA,CACG;MACT;;EACH,CAAA;;AAOV,SAAS,EAAqB,EAAE,iBAAmD;CACjF,IAAM,EAAE,SAAM,GAAS,EACjB,IAAW,GAAa;AAC9B,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAS,WAAU;MAAwB,MAAM;MAAM,CAAA;KACnD,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAA,UACG,EAAc,GAAG,kCAAkC,sBAAsB,EAChE,CAAA,EACZ,kBAAC,GAAD,EAAA,UACG,EACC,GACA,wCACA,0CACD,EACe,CAAA,CACd;OACF;OACK,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAS,WAAU,qDAAsD,CAAA,EACzE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAc,GAAG,uCAAuC,sBAAsB;MAC7E,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAc,GAAG,mCAAmC,sBAAsB;OAC3E,kBAAC,QAAD;QAAM,WAAU;kBAAe,EAAW;QAAa,CAAA;OACtD,EAAc,GAAG,mCAAmC,4BAA4B;OAC/E;QACA,EAAA,CAAA,CACF;QAEN,kBAAC,GAAD;KAAQ,eAAe,EAAS,mBAAmB;KAAE,WAAU;eAA/D,CACE,kBAAC,GAAD,EAAM,WAAU,eAAgB,CAAA,EAC/B,EAAc,GAAG,mCAAmC,mBAAmB,CACjE;OACG;MACT;;EACH,CAAA;;AAOV,SAAS,EAAa,EAAE,iBAAmD;CACzE,IAAM,EAAE,SAAM,GAAS,EACjB,IAAW,GAAa;AAC9B,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAO,WAAU;MAAsB,MAAM;MAAM,CAAA;KAC/C,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAA,UACG,EAAc,GAAG,iCAAiC,qBAAqB,EAC9D,CAAA,EACZ,kBAAC,GAAD,EAAA,UACG,EACC,GACA,uCACA,8BACD,EACe,CAAA,CACd;OACF;OACK,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAO,WAAU,mDAAoD,CAAA,EACrE,kBAAC,OAAD,EAAA,UAAA;MACE,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAc,GAAG,mCAAmC,6BAA6B;OAChF,CAAA;MACJ,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAc,GAAG,kCAAkC,sBAAsB;QAC1E,kBAAC,QAAD;SAAM,WAAU;mBAAe,EAAW;SAAa,CAAA;QACtD,EAAc,GAAG,kCAAkC,eAAe;QAClE,EAAW,aACV,IAAI,KAAK,EAAW,UAAU,CAAC,mBAAmB,SAAS;SACzD,MAAM;SACN,OAAO;SACP,KAAK;SACN,CAAC;QAAC;QAEH;;MACJ,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,GACA,wCACA,kEACD;OACC,CAAA;MACA,EAAA,CAAA,CACF;QAEN,kBAAC,GAAD;KAAQ,eAAe,EAAS,mBAAmB;KAAE,WAAU;eAA/D,CACE,kBAAC,GAAD,EAAM,WAAU,eAAgB,CAAA,EAC/B,EAAc,GAAG,mCAAmC,mBAAmB,CACjE;OACG;MACT;;EACH,CAAA;;AAOV,SAAS,EAAe,EAAE,iBAAmD;CAC3E,IAAM,EAAE,SAAM,GAAS,EACjB,IAAW,GAAa;AAC9B,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAK,WAAU;MAAmB,MAAM;MAAM,CAAA;KAC1C,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAA,UACG,EAAc,GAAG,mCAAmC,uBAAuB,EAClE,CAAA,EACZ,kBAAC,GAAD,EAAA,UACG,EACC,GACA,yCACA,mDACD,EACe,CAAA,CACd;OACF;OACK,CAAA,EACb,kBAAC,GAAD;IAAa,WAAU;cAAvB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAK,WAAU,gDAAiD,CAAA,EAChE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EACC,GACA,qCACA,iCACD;MACC,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAc,GAAG,oCAAoC,sBAAsB;OAC5E,kBAAC,QAAD;QAAM,WAAU;kBAAe,EAAW;QAAa,CAAA;OACtD,EACC,GACA,oCACA,gEACD;OACC;QACA,EAAA,CAAA,CACF;QAEN,kBAAC,GAAD;KAAQ,eAAe,EAAS,mBAAmB;KAAE,WAAU;eAA/D,CACE,kBAAC,GAAD,EAAM,WAAU,eAAgB,CAAA,EAC/B,EAAc,GAAG,mCAAmC,mBAAmB,CACjE;OACG;MACT;;EACH,CAAA"}
|