@burdenoff/microfe-organization 2026.616.1 → 2026.624.2
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/organization-management/AdminOrganizationRoot.js +4 -4
- package/dist/organization-management/AdminOrganizationRoot.js.map +1 -1
- package/dist/organization-management/UserOrganizationRoot.js +4 -4
- package/dist/organization-management/UserOrganizationRoot.js.map +1 -1
- package/dist/organization-management/modules/members/components/BulkInviteForm.js +157 -176
- package/dist/organization-management/modules/members/components/BulkInviteForm.js.map +1 -1
- package/dist/organization-management/modules/members/components/InviteMemberForm.js +2 -2
- package/dist/organization-management/modules/members/components/InviteMemberForm.js.map +1 -1
- package/dist/organization-management/modules/members/components/MyInviteCard.js +2 -2
- package/dist/organization-management/modules/members/components/MyInviteCard.js.map +1 -1
- package/dist/organization-management/modules/members/components/PendingInvitesList.js +78 -101
- package/dist/organization-management/modules/members/components/PendingInvitesList.js.map +1 -1
- package/dist/organization-management/modules/members/pages/InvitePeoplePage.js +1 -1
- package/dist/organization-management/modules/members/pages/InvitePeoplePage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MemberDetailPage.js +2 -2
- package/dist/organization-management/modules/members/pages/MemberDetailPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MembersListPage.js +3 -3
- package/dist/organization-management/modules/members/pages/MembersListPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MyInvitesPage.js +2 -2
- package/dist/organization-management/modules/members/pages/MyInvitesPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/OrganizationInviteAcceptancePage.js +5 -5
- package/dist/organization-management/modules/members/pages/OrganizationInviteAcceptancePage.js.map +1 -1
- package/dist/organization-management/modules/organizations/components/OrganizationForm.js +2 -2
- package/dist/organization-management/modules/organizations/components/OrganizationForm.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationCreatePage.js +2 -2
- package/dist/organization-management/modules/organizations/pages/OrganizationCreatePage.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.js +4 -4
- package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationEditPage.js +2 -2
- package/dist/organization-management/modules/organizations/pages/OrganizationEditPage.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js +5 -5
- package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/components/WorkspaceCard.js +3 -3
- package/dist/organization-management/modules/workspaces/components/WorkspaceCard.js.map +1 -1
- package/dist/organization-management/modules/workspaces/components/WorkspaceForm.js +2 -2
- package/dist/organization-management/modules/workspaces/components/WorkspaceForm.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.js +2 -2
- package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspaceDetailPage.js +215 -285
- package/dist/organization-management/modules/workspaces/pages/WorkspaceDetailPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspaceEditPage.js +2 -2
- package/dist/organization-management/modules/workspaces/pages/WorkspaceEditPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js +4 -4
- package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js.map +1 -1
- package/dist/organization-management/shared/components/feedback/EmptyState.js +2 -2
- package/dist/organization-management/shared/components/feedback/EmptyState.js.map +1 -1
- package/dist/organization-management/shared/components/feedback/ErrorState.js +2 -2
- package/dist/organization-management/shared/components/feedback/ErrorState.js.map +1 -1
- package/dist/organization-management/shared/components/feedback/LoadingState.js +1 -1
- package/dist/organization-management/shared/components/feedback/LoadingState.js.map +1 -1
- package/dist/organization-management/shared/components/input/SearchInput.js +1 -1
- package/dist/organization-management/shared/components/input/SearchInput.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceDetailPage.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/pages/WorkspaceDetailPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Briefcase, Edit, Trash2, UserPlus, Users } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n ActorIdentity,\n buildActorFallback,\n useActorProfiles,\n type ActorInput,\n} from '@burdenoff/fe-libs/shared';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useWorkspace } from '../hooks/useWorkspaces';\nimport { useRemoveWorkspaceMember, useWorkspaceMembers } from '../hooks/useWorkspaceMembers';\nimport { WorkspaceStatusBadge } from '../components/WorkspaceStatusBadge';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { EmptyState } from '../../../shared/components/feedback/EmptyState';\nimport { MemberRoleBadge } from '../../members/components/MemberRoleBadge';\nimport { AddWorkspaceMemberDialog } from '../components/AddWorkspaceMemberDialog';\nimport { useConfirmDialog } from '../../../shared/components/dialog/ConfirmDialog';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ntype ActiveTab = 'overview' | 'members';\n\nfunction formatDate(dateString: string) {\n return new Date(dateString).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\nexport function WorkspaceDetailPage() {\n const tr = useTr();\n const { id } = useParams<{ id: string }>();\n const { navigate, basePath = '/organizations', apiGatewayUrl, authToken } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const { workspace, loading, error } = useWorkspace(id ?? '');\n const [activeTab, setActiveTab] = useState<ActiveTab>('overview');\n const [isAddMemberDialogOpen, setIsAddMemberDialogOpen] = useState(false);\n const { openConfirmDialog, ConfirmDialog } = useConfirmDialog();\n\n const shouldFetchMembers = activeTab === 'members' && Boolean(id);\n const {\n members,\n loading: membersLoading,\n error: membersError,\n refetch: refetchMembers,\n } = useWorkspaceMembers(shouldFetchMembers ? (id ?? '') : '', 50, 0);\n const { removeWorkspaceMember, loading: removingMember } = useRemoveWorkspaceMember();\n const resolvedMemberCount =\n members.length > 0 || activeTab === 'members' ? members.length : (workspace?.memberCount ?? 0);\n\n const memberActors = useMemo<ActorInput[]>(\n () => members.map((member) => ({ actorId: member.userId, actorType: 'user' })),\n [members]\n );\n const profileMap = useActorProfiles(memberActors, {\n apiGatewayUrl,\n authToken,\n orgId: workspace?.organizationId,\n workspaceId: id,\n });\n\n const tabItems = useMemo(\n () => [\n { id: 'overview' as const, label: tr('workspaces.detail.tab.overview', 'Overview') },\n {\n id: 'members' as const,\n label: `${tr('workspaces.detail.tab.members', 'Members')} (${resolvedMemberCount})`,\n },\n ],\n [resolvedMemberCount, tr]\n );\n\n const handleRemoveMember = (userId: string) => {\n if (!id) return;\n\n openConfirmDialog({\n title: tr('workspaces.removeMember.title', 'Remove workspace member'),\n description: `${tr('workspaces.removeMember.prefix', 'Remove')} ${userId} ${tr('workspaces.removeMember.suffix', 'from this workspace? They will keep their organization membership.')}`,\n confirmText: tr('common.remove', 'Remove'),\n variant: 'danger',\n onConfirm: () => {\n void (async () => {\n try {\n const result = await removeWorkspaceMember(id, userId);\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr('workspaces.removeMember.failed', 'Failed to remove workspace member')\n );\n }\n\n await refetchMembers();\n toast.success(\n tr('workspaces.removeMember.success', 'Workspace member removed successfully')\n );\n } catch (removeError) {\n toast.error(\n removeError instanceof Error\n ? removeError.message\n : tr('workspaces.removeMember.failed', 'Failed to remove workspace member')\n );\n }\n })();\n },\n });\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (!hasPermission(PERMISSIONS.WORKSPACE_READ)) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <div className=\"p-8 text-center text-[var(--color-text-secondary)]\">\n {tr(\n 'workspaces.detail.noPermission',\n \"You don't have permission to view this workspace.\"\n )}\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('workspaces.detail.loading', 'Loading workspace details...')} />\n </div>\n );\n }\n\n if (error || !workspace) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error?.message || tr('workspaces.detail.notFound', 'Workspace not found')}\n action={{\n label: tr('workspaces.create.backToWorkspaces', 'Back to Workspaces'),\n onClick: () => navigate(`${basePath}/workspaces`),\n }}\n />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-300\">\n <div className=\"mx-auto flex w-full max-w-7xl flex-col gap-6\">\n <div className=\"space-y-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces`)}\n className=\"inline-flex min-h-10 items-center gap-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:text-[var(--color-text-primary)] active:scale-[0.98]\"\n >\n <ArrowLeft size={20} aria-hidden=\"true\" />\n <span className=\"text-sm font-medium\">\n {tr('workspaces.create.backToWorkspaces', 'Back to Workspaces')}\n </span>\n </button>\n\n <div className=\"flex flex-col gap-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-5 shadow-[var(--shadow-elevation-1)] lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"flex min-w-0 items-start gap-4\">\n <div className=\"flex size-16 items-center justify-center rounded-xl bg-[var(--color-status-info-bgSubtle)] text-[var(--color-status-info-text)]\">\n <Briefcase size={28} aria-hidden=\"true\" />\n </div>\n\n <div className=\"min-w-0 space-y-2\">\n <div className=\"flex flex-wrap items-start gap-2\">\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)]\">\n {workspace.name}\n </h1>\n <WorkspaceStatusBadge status={workspace.status} />\n </div>\n <p className=\"break-all font-mono text-sm text-[var(--color-text-secondary)]\">\n /{workspace.slug}\n </p>\n </div>\n </div>\n\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${workspace.organizationId}`)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] px-4 py-2.5 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <Users size={16} aria-hidden=\"true\" />\n <span>{tr('workspaces.detail.viewOrganization', 'View Organization')}</span>\n </button>\n {hasPermission(PERMISSIONS.WORKSPACE_UPDATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${id}/edit`)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90 active:scale-[0.98]\"\n >\n <Edit size={16} aria-hidden=\"true\" />\n <span>{tr('workspaces.edit.title', 'Edit Workspace')}</span>\n </button>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] shadow-[var(--shadow-elevation-1)]\">\n <div className=\"overflow-x-auto border-b border-[var(--color-border-default)]\">\n <div className=\"flex min-w-max gap-2 px-4 pt-4 sm:px-6\">\n {tabItems.map((tabItem) => {\n const isActive = activeTab === tabItem.id;\n return (\n <button\n type=\"button\"\n key={tabItem.id}\n onClick={() => setActiveTab(tabItem.id)}\n className={`inline-flex min-h-11 items-center rounded-t-lg border-b-2 px-4 py-3 text-sm font-medium transition-colors ${\n isActive\n ? 'border-[var(--color-action-primary-bg)] text-[var(--color-action-primary-bg)]'\n : 'border-transparent text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]'\n }`}\n aria-pressed={isActive}\n >\n {tabItem.label}\n </button>\n );\n })}\n </div>\n </div>\n\n <div className=\"p-4 sm:p-6\">\n {activeTab === 'overview' ? (\n <div className=\"grid grid-cols-1 gap-6 xl:grid-cols-[minmax(0,1fr)_320px]\">\n <section className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-5\">\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)]\">\n {tr('workspaces.detail.detailsSection', 'Workspace details')}\n </h2>\n\n <dl className=\"mt-5 grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('common.name', 'Name')}\n </dt>\n <dd className=\"mt-1 text-sm text-[var(--color-text-primary)]\">\n {workspace.name}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('common.slug', 'Slug')}\n </dt>\n <dd className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-primary)]\">\n {workspace.slug}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('common.status', 'Status')}\n </dt>\n <dd className=\"mt-1\">\n <WorkspaceStatusBadge status={workspace.status} />\n </dd>\n </div>\n <div className=\"sm:col-span-2\">\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('members.detail.orgId', 'Organization ID')}\n </dt>\n <dd className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-primary)]\">\n {workspace.organizationId}\n </dd>\n </div>\n {workspace.endpoint ? (\n <div className=\"sm:col-span-2\">\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('workspaces.detail.endpoint', 'Endpoint')}\n </dt>\n <dd className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-primary)]\">\n {workspace.endpoint}\n </dd>\n </div>\n ) : null}\n </dl>\n </section>\n\n <aside className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-5\">\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)]\">\n {tr('common.metadata', 'Metadata')}\n </h2>\n\n <dl className=\"mt-5 space-y-4\">\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.members', 'Members')}\n </dt>\n <dd className=\"mt-1 text-sm text-[var(--color-text-primary)]\">\n {resolvedMemberCount}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </dt>\n <dd className=\"mt-1 text-sm text-[var(--color-text-primary)]\">\n {formatDate(workspace.createdAt)}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('common.lastUpdated', 'Last updated')}\n </dt>\n <dd className=\"mt-1 text-sm text-[var(--color-text-primary)]\">\n {formatDate(workspace.updatedAt)}\n </dd>\n </div>\n {workspace.region ? (\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('workspaces.detail.region', 'Region')}\n </dt>\n <dd className=\"mt-1 text-sm text-[var(--color-text-primary)]\">\n {workspace.region}\n </dd>\n </div>\n ) : null}\n </dl>\n </aside>\n </div>\n ) : (\n <section className=\"space-y-4\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)]\">\n {tr('workspaces.detail.membersTitle', 'Workspace members')}\n </h2>\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {tr(\n 'workspaces.detail.membersSubtitle',\n 'Add organization members to this workspace and manage access.'\n )}\n </p>\n </div>\n {hasPermission(PERMISSIONS.MEMBER_INVITE) && (\n <button\n type=\"button\"\n onClick={() => setIsAddMemberDialogOpen(true)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90 active:scale-[0.98]\"\n >\n <UserPlus size={16} aria-hidden=\"true\" />\n <span>{tr('workspaces.detail.addMember', 'Add Member')}</span>\n </button>\n )}\n </div>\n\n {membersLoading ? (\n <div className=\"py-8\">\n <LoadingState\n message={tr(\n 'workspaces.detail.loadingMembers',\n 'Loading workspace members...'\n )}\n />\n </div>\n ) : membersError ? (\n <ErrorState\n message={membersError.message}\n action={{\n label: tr('common.retry', 'Retry'),\n onClick: () => {\n void refetchMembers();\n },\n }}\n />\n ) : members.length > 0 ? (\n <>\n <div className=\"grid gap-4 md:hidden\">\n {members.map((member) => (\n <article\n key={member.id}\n className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-4\"\n >\n <div className=\"space-y-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <ActorIdentity\n profile={\n profileMap[member.userId] ??\n buildActorFallback({\n actorId: member.userId,\n actorType: 'user',\n })\n }\n variant=\"inline\"\n />\n <p className=\"mt-1 text-sm text-[var(--color-text-secondary)]\">\n {tr('members.list.joined', 'Joined')}{' '}\n {formatDate(member.joinedAt)}\n </p>\n </div>\n <MemberRoleBadge role={member.role} />\n </div>\n\n <dl className=\"grid grid-cols-1 gap-3 text-sm\">\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('members.list.invitedBy', 'Invited by')}\n </dt>\n <dd className=\"mt-1 break-all font-mono text-[var(--color-text-primary)]\">\n {member.invitedBy || '—'}\n </dd>\n </div>\n </dl>\n\n <button\n type=\"button\"\n onClick={() => handleRemoveMember(member.userId)}\n disabled={removingMember}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-status-error-border)] px-3 py-2 text-sm text-[var(--color-status-error-text)] transition-all duration-200 hover:bg-[var(--color-status-error-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr('common.remove', 'Remove')}\n </button>\n </div>\n </article>\n ))}\n </div>\n\n <div className=\"hidden overflow-hidden rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] md:block\">\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full\">\n <thead className=\"bg-[var(--color-bg-subtle)]\">\n <tr>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('members.detail.userId', 'User ID')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('members.list.column.role', 'Role')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('members.list.joined', 'Joined')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('members.list.invitedBy', 'Invited by')}\n </th>\n <th className=\"px-6 py-3 text-right text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-[var(--color-border-default)]\">\n {members.map((member) => (\n <tr\n key={member.id}\n className=\"transition-colors hover:bg-[var(--color-bg-subtle)]\"\n >\n <td className=\"px-6 py-4\">\n <ActorIdentity\n profile={\n profileMap[member.userId] ??\n buildActorFallback({\n actorId: member.userId,\n actorType: 'user',\n })\n }\n variant=\"cell\"\n />\n </td>\n <td className=\"px-6 py-4\">\n <MemberRoleBadge role={member.role} />\n </td>\n <td className=\"px-6 py-4 text-sm text-[var(--color-text-secondary)]\">\n {formatDate(member.joinedAt)}\n </td>\n <td className=\"px-6 py-4 break-all font-mono text-sm text-[var(--color-text-secondary)]\">\n {member.invitedBy || '—'}\n </td>\n <td className=\"px-6 py-4 text-right\">\n <button\n type=\"button\"\n onClick={() => handleRemoveMember(member.userId)}\n disabled={removingMember}\n className=\"rounded-lg p-2 text-[var(--color-status-error-text)] transition-all duration-200 hover:bg-[var(--color-status-error-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n aria-label={`${tr('workspaces.removeMember.ariaPrefix', 'Remove')} ${member.userId} ${tr('workspaces.removeMember.ariaSuffix', 'from workspace')}`}\n title={`${tr('workspaces.removeMember.ariaPrefix', 'Remove')} ${member.userId} ${tr('workspaces.removeMember.ariaSuffix', 'from workspace')}`}\n >\n <Trash2 size={18} aria-hidden=\"true\" />\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </>\n ) : (\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-6\">\n <EmptyState\n icon={<Users size={40} aria-hidden=\"true\" />}\n title={tr('workspaces.detail.emptyMembersTitle', 'No workspace members yet')}\n description={tr(\n 'workspaces.detail.emptyMembersDescription',\n 'Add people from the parent organization to grant workspace access.'\n )}\n action={{\n label: tr('workspaces.detail.addMember', 'Add Member'),\n onClick: () => setIsAddMemberDialogOpen(true),\n }}\n />\n </div>\n )}\n </section>\n )}\n </div>\n </div>\n </div>\n\n <AddWorkspaceMemberDialog\n open={isAddMemberDialogOpen}\n onOpenChange={setIsAddMemberDialogOpen}\n workspaceId={workspace.id}\n organizationId={workspace.organizationId}\n existingMembers={members}\n onInviteOrganizationMember={() =>\n navigate(`${basePath}/${workspace.organizationId}/members/invite`)\n }\n />\n {ConfirmDialog}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkspaceDetailPage.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/pages/WorkspaceDetailPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Briefcase, Edit, Trash2, UserPlus, Users } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n ActorIdentity,\n buildActorFallback,\n useActorProfiles,\n type ActorInput,\n} from '@burdenoff/fe-libs/shared';\nimport { ResponsiveTable, type ResponsiveTableColumn } from '@burdenoff/fe-libs/ui';\nimport type { WorkspaceMember } from '../types/workspace-member';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useWorkspace } from '../hooks/useWorkspaces';\nimport { useRemoveWorkspaceMember, useWorkspaceMembers } from '../hooks/useWorkspaceMembers';\nimport { WorkspaceStatusBadge } from '../components/WorkspaceStatusBadge';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { EmptyState } from '../../../shared/components/feedback/EmptyState';\nimport { MemberRoleBadge } from '../../members/components/MemberRoleBadge';\nimport { AddWorkspaceMemberDialog } from '../components/AddWorkspaceMemberDialog';\nimport { useConfirmDialog } from '../../../shared/components/dialog/ConfirmDialog';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ntype ActiveTab = 'overview' | 'members';\n\nfunction formatDate(dateString: string) {\n return new Date(dateString).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\nexport function WorkspaceDetailPage() {\n const tr = useTr();\n const { id } = useParams<{ id: string }>();\n const { navigate, basePath = '/organizations', apiGatewayUrl, authToken } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const { workspace, loading, error } = useWorkspace(id ?? '');\n const [activeTab, setActiveTab] = useState<ActiveTab>('overview');\n const [isAddMemberDialogOpen, setIsAddMemberDialogOpen] = useState(false);\n const { openConfirmDialog, ConfirmDialog } = useConfirmDialog();\n\n const shouldFetchMembers = activeTab === 'members' && Boolean(id);\n const {\n members,\n loading: membersLoading,\n error: membersError,\n refetch: refetchMembers,\n } = useWorkspaceMembers(shouldFetchMembers ? (id ?? '') : '', 50, 0);\n const { removeWorkspaceMember, loading: removingMember } = useRemoveWorkspaceMember();\n const resolvedMemberCount =\n members.length > 0 || activeTab === 'members' ? members.length : (workspace?.memberCount ?? 0);\n\n const memberActors = useMemo<ActorInput[]>(\n () => members.map((member) => ({ actorId: member.userId, actorType: 'user' })),\n [members]\n );\n const profileMap = useActorProfiles(memberActors, {\n apiGatewayUrl,\n authToken,\n orgId: workspace?.organizationId,\n workspaceId: id,\n });\n\n const tabItems = useMemo(\n () => [\n { id: 'overview' as const, label: tr('workspaces.detail.tab.overview', 'Overview') },\n {\n id: 'members' as const,\n label: `${tr('workspaces.detail.tab.members', 'Members')} (${resolvedMemberCount})`,\n },\n ],\n [resolvedMemberCount, tr]\n );\n\n const handleRemoveMember = (userId: string) => {\n if (!id) return;\n\n openConfirmDialog({\n title: tr('workspaces.removeMember.title', 'Remove workspace member'),\n description: `${tr('workspaces.removeMember.prefix', 'Remove')} ${userId} ${tr('workspaces.removeMember.suffix', 'from this workspace? They will keep their organization membership.')}`,\n confirmText: tr('common.remove', 'Remove'),\n variant: 'danger',\n onConfirm: () => {\n void (async () => {\n try {\n const result = await removeWorkspaceMember(id, userId);\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr('workspaces.removeMember.failed', 'Failed to remove workspace member')\n );\n }\n\n await refetchMembers();\n toast.success(\n tr('workspaces.removeMember.success', 'Workspace member removed successfully')\n );\n } catch (removeError) {\n toast.error(\n removeError instanceof Error\n ? removeError.message\n : tr('workspaces.removeMember.failed', 'Failed to remove workspace member')\n );\n }\n })();\n },\n });\n };\n\n const memberColumns: ResponsiveTableColumn<WorkspaceMember>[] = [\n {\n key: 'user',\n header: tr('members.detail.userId', 'User ID'),\n priority: 'primary',\n cell: (member) => (\n <ActorIdentity\n profile={\n profileMap[member.userId] ??\n buildActorFallback({ actorId: member.userId, actorType: 'user' })\n }\n variant=\"cell\"\n />\n ),\n },\n {\n key: 'role',\n header: tr('members.list.column.role', 'Role'),\n priority: 'secondary',\n cell: (member) => <MemberRoleBadge role={member.role} />,\n },\n {\n key: 'joined',\n header: tr('members.list.joined', 'Joined'),\n priority: 'secondary',\n cell: (member) => (\n <span className=\"text-sm text-[var(--color-text-secondary)]\">\n {formatDate(member.joinedAt)}\n </span>\n ),\n },\n {\n key: 'invitedBy',\n header: tr('members.list.invitedBy', 'Invited by'),\n priority: 'secondary',\n cell: (member) => (\n <span className=\"break-all font-mono text-sm text-[var(--color-text-secondary)]\">\n {member.invitedBy || '—'}\n </span>\n ),\n },\n ];\n\n const renderMemberActions = (member: WorkspaceMember) => (\n <button\n type=\"button\"\n onClick={() => handleRemoveMember(member.userId)}\n disabled={removingMember}\n className=\"rounded-lg p-2 text-[var(--color-status-error-text)] transition-all duration-200 hover:bg-[var(--color-status-error-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n aria-label={`${tr('workspaces.removeMember.ariaPrefix', 'Remove')} ${member.userId} ${tr('workspaces.removeMember.ariaSuffix', 'from workspace')}`}\n title={`${tr('workspaces.removeMember.ariaPrefix', 'Remove')} ${member.userId} ${tr('workspaces.removeMember.ariaSuffix', 'from workspace')}`}\n >\n <Trash2 size={18} aria-hidden=\"true\" />\n </button>\n );\n\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (!hasPermission(PERMISSIONS.WORKSPACE_READ)) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <div className=\"p-8 text-center text-[var(--color-text-secondary)]\">\n {tr(\n 'workspaces.detail.noPermission',\n \"You don't have permission to view this workspace.\"\n )}\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('workspaces.detail.loading', 'Loading workspace details...')} />\n </div>\n );\n }\n\n if (error || !workspace) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error?.message || tr('workspaces.detail.notFound', 'Workspace not found')}\n action={{\n label: tr('workspaces.create.backToWorkspaces', 'Back to Workspaces'),\n onClick: () => navigate(`${basePath}/workspaces`),\n }}\n />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-200\">\n <div className=\"mx-auto flex w-full max-w-7xl flex-col gap-6\">\n <div className=\"space-y-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces`)}\n className=\"inline-flex min-h-10 items-center gap-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:text-[var(--color-text-primary)]\"\n >\n <ArrowLeft size={20} aria-hidden=\"true\" />\n <span className=\"text-sm font-medium\">\n {tr('workspaces.create.backToWorkspaces', 'Back to Workspaces')}\n </span>\n </button>\n\n <div className=\"flex flex-col gap-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-5 shadow-[var(--shadow-elevation-1)] lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"flex min-w-0 items-start gap-4\">\n <div className=\"flex size-16 items-center justify-center rounded-xl bg-[var(--color-status-info-bgSubtle)] text-[var(--color-status-info-text)]\">\n <Briefcase size={28} aria-hidden=\"true\" />\n </div>\n\n <div className=\"min-w-0 space-y-2\">\n <div className=\"flex flex-wrap items-start gap-2\">\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)]\">\n {workspace.name}\n </h1>\n <WorkspaceStatusBadge status={workspace.status} />\n </div>\n <p className=\"break-all font-mono text-sm text-[var(--color-text-secondary)]\">\n /{workspace.slug}\n </p>\n </div>\n </div>\n\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${workspace.organizationId}`)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] px-4 py-2.5 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <Users size={16} aria-hidden=\"true\" />\n <span>{tr('workspaces.detail.viewOrganization', 'View Organization')}</span>\n </button>\n {hasPermission(PERMISSIONS.WORKSPACE_UPDATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${id}/edit`)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90\"\n >\n <Edit size={16} aria-hidden=\"true\" />\n <span>{tr('workspaces.edit.title', 'Edit Workspace')}</span>\n </button>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] shadow-[var(--shadow-elevation-1)]\">\n <div className=\"overflow-x-auto border-b border-[var(--color-border-default)]\">\n <div className=\"flex min-w-max gap-2 px-4 pt-4 sm:px-6\">\n {tabItems.map((tabItem) => {\n const isActive = activeTab === tabItem.id;\n return (\n <button\n type=\"button\"\n key={tabItem.id}\n onClick={() => setActiveTab(tabItem.id)}\n className={`inline-flex min-h-11 items-center rounded-t-lg border-b-2 px-4 py-3 text-sm font-medium transition-colors ${\n isActive\n ? 'border-[var(--color-action-primary-bg)] text-[var(--color-action-primary-bg)]'\n : 'border-transparent text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]'\n }`}\n aria-pressed={isActive}\n >\n {tabItem.label}\n </button>\n );\n })}\n </div>\n </div>\n\n <div className=\"p-4 sm:p-6\">\n {activeTab === 'overview' ? (\n <div className=\"grid grid-cols-1 gap-6 xl:grid-cols-[minmax(0,1fr)_320px]\">\n <section className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-5\">\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)]\">\n {tr('workspaces.detail.detailsSection', 'Workspace details')}\n </h2>\n\n <dl className=\"mt-5 grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('common.name', 'Name')}\n </dt>\n <dd className=\"mt-1 text-sm text-[var(--color-text-primary)]\">\n {workspace.name}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('common.slug', 'Slug')}\n </dt>\n <dd className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-primary)]\">\n {workspace.slug}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('common.status', 'Status')}\n </dt>\n <dd className=\"mt-1\">\n <WorkspaceStatusBadge status={workspace.status} />\n </dd>\n </div>\n <div className=\"sm:col-span-2\">\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('members.detail.orgId', 'Organization ID')}\n </dt>\n <dd className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-primary)]\">\n {workspace.organizationId}\n </dd>\n </div>\n {workspace.endpoint ? (\n <div className=\"sm:col-span-2\">\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('workspaces.detail.endpoint', 'Endpoint')}\n </dt>\n <dd className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-primary)]\">\n {workspace.endpoint}\n </dd>\n </div>\n ) : null}\n </dl>\n </section>\n\n <aside className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-5\">\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)]\">\n {tr('common.metadata', 'Metadata')}\n </h2>\n\n <dl className=\"mt-5 space-y-4\">\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.members', 'Members')}\n </dt>\n <dd className=\"mt-1 text-sm text-[var(--color-text-primary)]\">\n {resolvedMemberCount}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </dt>\n <dd className=\"mt-1 text-sm text-[var(--color-text-primary)]\">\n {formatDate(workspace.createdAt)}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('common.lastUpdated', 'Last updated')}\n </dt>\n <dd className=\"mt-1 text-sm text-[var(--color-text-primary)]\">\n {formatDate(workspace.updatedAt)}\n </dd>\n </div>\n {workspace.region ? (\n <div>\n <dt className=\"text-sm font-medium text-[var(--color-text-secondary)]\">\n {tr('workspaces.detail.region', 'Region')}\n </dt>\n <dd className=\"mt-1 text-sm text-[var(--color-text-primary)]\">\n {workspace.region}\n </dd>\n </div>\n ) : null}\n </dl>\n </aside>\n </div>\n ) : (\n <section className=\"space-y-4\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)]\">\n {tr('workspaces.detail.membersTitle', 'Workspace members')}\n </h2>\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {tr(\n 'workspaces.detail.membersSubtitle',\n 'Add organization members to this workspace and manage access.'\n )}\n </p>\n </div>\n {hasPermission(PERMISSIONS.MEMBER_INVITE) && (\n <button\n type=\"button\"\n onClick={() => setIsAddMemberDialogOpen(true)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90\"\n >\n <UserPlus size={16} aria-hidden=\"true\" />\n <span>{tr('workspaces.detail.addMember', 'Add Member')}</span>\n </button>\n )}\n </div>\n\n {membersLoading ? (\n <div className=\"py-8\">\n <LoadingState\n message={tr(\n 'workspaces.detail.loadingMembers',\n 'Loading workspace members...'\n )}\n />\n </div>\n ) : membersError ? (\n <ErrorState\n message={membersError.message}\n action={{\n label: tr('common.retry', 'Retry'),\n onClick: () => {\n void refetchMembers();\n },\n }}\n />\n ) : members.length > 0 ? (\n <div className=\"overflow-hidden rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] md:p-2\">\n <ResponsiveTable\n columns={memberColumns}\n data={members}\n rowKey={(member) => member.id}\n rowActions={renderMemberActions}\n />\n </div>\n ) : (\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-6\">\n <EmptyState\n icon={<Users size={40} aria-hidden=\"true\" />}\n title={tr('workspaces.detail.emptyMembersTitle', 'No workspace members yet')}\n description={tr(\n 'workspaces.detail.emptyMembersDescription',\n 'Add people from the parent organization to grant workspace access.'\n )}\n action={{\n label: tr('workspaces.detail.addMember', 'Add Member'),\n onClick: () => setIsAddMemberDialogOpen(true),\n }}\n />\n </div>\n )}\n </section>\n )}\n </div>\n </div>\n </div>\n\n <AddWorkspaceMemberDialog\n open={isAddMemberDialogOpen}\n onOpenChange={setIsAddMemberDialogOpen}\n workspaceId={workspace.id}\n organizationId={workspace.organizationId}\n existingMembers={members}\n onInviteOrganizationMember={() =>\n navigate(`${basePath}/${workspace.organizationId}/members/invite`)\n }\n />\n {ConfirmDialog}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -39,14 +39,14 @@ function m() {
|
|
|
39
39
|
}
|
|
40
40
|
})
|
|
41
41
|
}) : /* @__PURE__ */ f("div", {
|
|
42
|
-
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-
|
|
42
|
+
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-200",
|
|
43
43
|
children: [/* @__PURE__ */ f("div", {
|
|
44
44
|
className: "mb-6",
|
|
45
45
|
children: [
|
|
46
46
|
/* @__PURE__ */ f("button", {
|
|
47
47
|
type: "button",
|
|
48
48
|
onClick: E,
|
|
49
|
-
className: "\n inline-flex items-center gap-2 mb-4\n text-[var(--color-text-secondary)]\n hover:text-[var(--color-text-primary)]\n
|
|
49
|
+
className: "\n inline-flex items-center gap-2 mb-4\n text-[var(--color-text-secondary)]\n hover:text-[var(--color-text-primary)]\n \n transition-all duration-200\n ",
|
|
50
50
|
children: [/* @__PURE__ */ d(l, { size: 20 }), /* @__PURE__ */ f("span", {
|
|
51
51
|
className: "text-sm font-medium",
|
|
52
52
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceEditPage.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/pages/WorkspaceEditPage.tsx"],"sourcesContent":["import { useParams } from 'react-router-dom';\nimport { ArrowLeft } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useWorkspace, useUpdateWorkspace } from '../hooks/useWorkspaces';\nimport { WorkspaceForm } from '../components/WorkspaceForm';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport type { UpdateWorkspaceInput } from '../types';\n\nexport function WorkspaceEditPage() {\n const tr = useTr();\n const { id } = useParams<{ id: string }>();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const { workspace, loading: fetchLoading, error } = useWorkspace(id!);\n const { updateWorkspace, loading: updateLoading } = useUpdateWorkspace();\n\n const handleSubmit = async (data: UpdateWorkspaceInput) => {\n if (!id) return;\n\n try {\n const result = await updateWorkspace(id, data);\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ?? tr('workspaces.edit.failed', 'Failed to update workspace')\n );\n }\n\n toast.success(tr('workspaces.edit.success', 'Workspace updated successfully'));\n navigate(`${basePath}/workspaces/${id}`);\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tr('workspaces.edit.failed', 'Failed to update workspace')\n );\n }\n };\n\n const handleCancel = () => {\n navigate(`${basePath}/workspaces/${id}`);\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (!hasPermission(PERMISSIONS.WORKSPACE_UPDATE)) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <div className=\"p-8 text-center text-[var(--color-text-secondary)]\">\n {tr('workspaces.edit.noPermission', \"You don't have permission to edit workspaces.\")}\n </div>\n </div>\n );\n }\n\n if (fetchLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('workspaces.edit.loading', 'Loading workspace...')} />\n </div>\n );\n }\n\n if (error || !workspace) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error?.message || tr('workspaces.detail.notFound', 'Workspace not found')}\n action={{\n label: tr('workspaces.create.backToWorkspaces', 'Back to Workspaces'),\n onClick: () => navigate(`${basePath}/workspaces`),\n }}\n />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-
|
|
1
|
+
{"version":3,"file":"WorkspaceEditPage.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/pages/WorkspaceEditPage.tsx"],"sourcesContent":["import { useParams } from 'react-router-dom';\nimport { ArrowLeft } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useWorkspace, useUpdateWorkspace } from '../hooks/useWorkspaces';\nimport { WorkspaceForm } from '../components/WorkspaceForm';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport type { UpdateWorkspaceInput } from '../types';\n\nexport function WorkspaceEditPage() {\n const tr = useTr();\n const { id } = useParams<{ id: string }>();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const { workspace, loading: fetchLoading, error } = useWorkspace(id!);\n const { updateWorkspace, loading: updateLoading } = useUpdateWorkspace();\n\n const handleSubmit = async (data: UpdateWorkspaceInput) => {\n if (!id) return;\n\n try {\n const result = await updateWorkspace(id, data);\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ?? tr('workspaces.edit.failed', 'Failed to update workspace')\n );\n }\n\n toast.success(tr('workspaces.edit.success', 'Workspace updated successfully'));\n navigate(`${basePath}/workspaces/${id}`);\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tr('workspaces.edit.failed', 'Failed to update workspace')\n );\n }\n };\n\n const handleCancel = () => {\n navigate(`${basePath}/workspaces/${id}`);\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (!hasPermission(PERMISSIONS.WORKSPACE_UPDATE)) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <div className=\"p-8 text-center text-[var(--color-text-secondary)]\">\n {tr('workspaces.edit.noPermission', \"You don't have permission to edit workspaces.\")}\n </div>\n </div>\n );\n }\n\n if (fetchLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('workspaces.edit.loading', 'Loading workspace...')} />\n </div>\n );\n }\n\n if (error || !workspace) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error?.message || tr('workspaces.detail.notFound', 'Workspace not found')}\n action={{\n label: tr('workspaces.create.backToWorkspaces', 'Back to Workspaces'),\n onClick: () => navigate(`${basePath}/workspaces`),\n }}\n />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-200\">\n <div className=\"mb-6\">\n <button\n type=\"button\"\n onClick={handleCancel}\n className=\"\n inline-flex items-center gap-2 mb-4\n text-[var(--color-text-secondary)]\n hover:text-[var(--color-text-primary)]\n \n transition-all duration-200\n \"\n >\n <ArrowLeft size={20} />\n <span className=\"text-sm font-medium\">\n {tr('common.backTo', 'Back to')} {workspace.name}\n </span>\n </button>\n\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)] mb-2\">\n {tr('workspaces.edit.title', 'Edit Workspace')}\n </h1>\n <p className=\"text-[var(--color-text-secondary)]\">\n {tr('workspaces.edit.subtitle', 'Update workspace information')}\n </p>\n </div>\n\n <div className=\"max-w-2xl\">\n <div className=\"bg-[var(--color-bg-surface)] border border-[var(--color-border-default)] rounded-lg p-6 shadow-[var(--shadow-elevation-1)]\">\n <WorkspaceForm\n workspace={workspace}\n onSubmit={handleSubmit}\n onCancel={handleCancel}\n loading={updateLoading}\n />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,SAAgB,IAAoB;CAClC,IAAM,IAAK,GAAO,EACZ,EAAE,UAAO,GAA2B,EACpC,EAAE,aAAU,cAAW,qBAAqB,GAAe,EAC3D,EAAE,kBAAe,WAAW,MAAuB,GAAgB,EACnE,EAAE,cAAW,SAAS,GAAc,aAAU,EAAa,EAAI,EAC/D,EAAE,oBAAiB,SAAS,MAAkB,GAAoB,EAElE,IAAe,OAAO,MAA+B;AACpD,QAEL,KAAI;GACF,IAAM,IAAS,MAAM,EAAgB,GAAI,EAAK;AAC9C,OAAI,EAAO,QAAQ,OACjB,OAAU,MACR,EAAO,OAAO,IAAI,WAAW,EAAG,0BAA0B,6BAA6B,CACxF;AAIH,GADA,EAAM,QAAQ,EAAG,2BAA2B,iCAAiC,CAAC,EAC9E,EAAS,GAAG,EAAS,cAAc,IAAK;WACjC,GAAO;AACd,KAAM,MACJ,aAAiB,QACb,EAAM,UACN,EAAG,0BAA0B,6BAA6B,CAC/D;;IAIC,UAAqB;AACzB,IAAS,GAAG,EAAS,cAAc,IAAK;;AA2C1C,QAxCI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAc,SAAS,EAAG,6BAA6B,yBAAyB,EAAI,CAAA;EAChF,CAAA,GAIL,EAAc,EAAY,iBAAiB,GAU5C,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAc,SAAS,EAAG,2BAA2B,uBAAuB,EAAI,CAAA;EAC5E,CAAA,GAIN,KAAS,CAAC,IAEV,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,SAAS,GAAO,WAAW,EAAG,8BAA8B,sBAAsB;GAClF,QAAQ;IACN,OAAO,EAAG,sCAAsC,qBAAqB;IACrE,eAAe,EAAS,GAAG,EAAS,aAAa;IAClD;GACD,CAAA;EACE,CAAA,GAKR,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;eAHZ,CAWE,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA,EACvB,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACG,EAAG,iBAAiB,UAAU;OAAC;OAAE,EAAU;OACvC;QACA;;IAET,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,yBAAyB,iBAAiB;KAC3C,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,4BAA4B,+BAA+B;KAC7D,CAAA;IACA;MAEN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KACa;KACX,UAAU;KACV,UAAU;KACV,SAAS;KACT,CAAA;IACE,CAAA;GACF,CAAA,CACF;MApEJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAG,gCAAgC,gDAAgD;GAChF,CAAA;EACF,CAAA"}
|
|
@@ -117,7 +117,7 @@ function E({ mode: E = "my" } = {}) {
|
|
|
117
117
|
}
|
|
118
118
|
})
|
|
119
119
|
}) : /* @__PURE__ */ w("div", {
|
|
120
|
-
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-
|
|
120
|
+
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-200",
|
|
121
121
|
children: [/* @__PURE__ */ w("div", {
|
|
122
122
|
className: "mx-auto flex w-full max-w-7xl flex-col gap-6",
|
|
123
123
|
children: [
|
|
@@ -135,7 +135,7 @@ function E({ mode: E = "my" } = {}) {
|
|
|
135
135
|
}), A(l.WORKSPACE_CREATE) && /* @__PURE__ */ w("button", {
|
|
136
136
|
type: "button",
|
|
137
137
|
onClick: () => O(`${k}/workspaces/new`),
|
|
138
|
-
className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90
|
|
138
|
+
className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90",
|
|
139
139
|
children: [/* @__PURE__ */ C(y, {
|
|
140
140
|
size: 18,
|
|
141
141
|
"aria-hidden": "true"
|
|
@@ -169,7 +169,7 @@ function E({ mode: E = "my" } = {}) {
|
|
|
169
169
|
...N,
|
|
170
170
|
status: e.target.value ? e.target.value : void 0
|
|
171
171
|
}),
|
|
172
|
-
className: "bg-transparent text-[var(--color-text-primary)] focus:outline-none",
|
|
172
|
+
className: "bg-transparent text-[var(--color-text-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
173
173
|
"aria-label": D("workspaces.list.filterByStatus", "Filter by workspace status"),
|
|
174
174
|
children: [
|
|
175
175
|
/* @__PURE__ */ C("option", {
|
|
@@ -196,7 +196,7 @@ function E({ mode: E = "my" } = {}) {
|
|
|
196
196
|
onClick: () => {
|
|
197
197
|
U();
|
|
198
198
|
},
|
|
199
|
-
className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]
|
|
199
|
+
className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]",
|
|
200
200
|
"aria-label": D("workspaces.list.refresh", "Refresh workspaces"),
|
|
201
201
|
title: D("workspaces.list.refresh", "Refresh workspaces"),
|
|
202
202
|
children: /* @__PURE__ */ C(oe, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspacesListPage.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/pages/WorkspacesListPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { Briefcase, Eye, Plus, RefreshCw, SquarePen, Trash2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useDeleteWorkspace, useWorkspaces } from '../hooks/useWorkspaces';\nimport { WorkspaceStatusBadge } from '../components/WorkspaceStatusBadge';\nimport { SearchInput } from '../../../shared/components/input/SearchInput';\nimport { SelectionCheckbox } from '../../../shared/components/input/SelectionCheckbox';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { EmptyState } from '../../../shared/components/feedback/EmptyState';\nimport { useDebouncedValue } from '../../../shared/hooks/useDebouncedValue';\nimport { useConfirmDialog } from '../../../shared/components/dialog/ConfirmDialog';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport type { WorkspaceFilterInput } from '../types';\nimport { WorkspaceStatus } from '../types';\nimport {\n isNative,\n nativeConfirm,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../../../utils/nativeBridge';\n\nfunction formatDate(date: string) {\n return new Date(date).toLocaleDateString();\n}\n\n/**\n * `mode` controls the scope of the listing:\n * - `'my'` — membership-scoped (`myWorkspaces`); the default for user-facing\n * app shells. A regular user only sees workspaces they belong to.\n * - `'admin'` — platform-wide (`allWorkspaces`, super-admin only); the admin app.\n */\nexport interface WorkspacesListPageProps {\n mode?: 'my' | 'admin';\n}\n\nexport function WorkspacesListPage({ mode = 'my' }: WorkspacesListPageProps = {}) {\n const tr = useTr();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const [searchQuery, setSearchQuery] = useState('');\n const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);\n const [filter, setFilter] = useState<WorkspaceFilterInput>({});\n const [selectedWorkspaceIds, setSelectedWorkspaceIds] = useState<Set<string>>(new Set());\n const { openConfirmDialog, ConfirmDialog } = useConfirmDialog();\n\n // 'my' shells call the self-scoped `myWorkspaces` (no server-side filter arg),\n // so we over-fetch a page and filter client-side below. The admin app keeps\n // the server-filtered, paginated `allWorkspaces`.\n const scope = mode === 'admin' ? 'all' : 'my';\n const {\n workspaces: fetchedWorkspaces,\n loading,\n error,\n refetch,\n } = useWorkspaces(\n { ...filter, search: debouncedSearchQuery || undefined },\n scope === 'my' ? 100 : 20,\n 0,\n scope\n );\n\n const workspaces = useMemo(() => {\n if (scope !== 'my') return fetchedWorkspaces;\n const query = debouncedSearchQuery.trim().toLowerCase();\n return fetchedWorkspaces.filter((workspace) => {\n const matchesSearch =\n !query ||\n workspace.name.toLowerCase().includes(query) ||\n (workspace.slug?.toLowerCase().includes(query) ?? false);\n const matchesStatus = !filter.status || workspace.status === filter.status;\n return matchesSearch && matchesStatus;\n });\n }, [fetchedWorkspaces, scope, debouncedSearchQuery, filter.status]);\n\n const { deleteWorkspace, loading: deleteLoading } = useDeleteWorkspace();\n\n useEffect(() => {\n setSelectedWorkspaceIds((previousSelection) => {\n const visibleIds = new Set(workspaces.map((workspace) => workspace.id));\n const nextSelection = new Set(\n [...previousSelection].filter((workspaceId) => visibleIds.has(workspaceId))\n );\n\n if (nextSelection.size === previousSelection.size) {\n return previousSelection;\n }\n\n return nextSelection;\n });\n }, [workspaces]);\n\n const selectedWorkspaces = useMemo(\n () => workspaces.filter((workspace) => selectedWorkspaceIds.has(workspace.id)),\n [selectedWorkspaceIds, workspaces]\n );\n\n const allVisibleSelected =\n workspaces.length > 0 &&\n workspaces.every((workspace) => selectedWorkspaceIds.has(workspace.id));\n const partiallySelected =\n workspaces.some((workspace) => selectedWorkspaceIds.has(workspace.id)) && !allVisibleSelected;\n\n const executeSuspend = async (workspaceIds: string[]) => {\n try {\n const results = await Promise.allSettled(\n workspaceIds.map(async (workspaceId) => {\n const result = await deleteWorkspace(workspaceId);\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr('workspaces.suspend.failed', 'Failed to suspend workspace')\n );\n }\n })\n );\n\n const rejectedResult = results.find((result) => result.status === 'rejected');\n if (rejectedResult?.status === 'rejected') {\n throw rejectedResult.reason;\n }\n\n setSelectedWorkspaceIds(new Set());\n await refetch();\n const successMsg =\n workspaceIds.length === 1\n ? tr('workspaces.suspend.successSingle', 'Workspace suspended successfully')\n : `${workspaceIds.length} ${tr('workspaces.suspend.successMany', 'workspaces suspended successfully')}`;\n toast.success(successMsg);\n void nativeNotify('success');\n if (isNative()) void nativeToast(successMsg);\n } catch (suspendError) {\n const errorMsg =\n suspendError instanceof Error\n ? suspendError.message\n : tr('workspaces.suspend.failed', 'Failed to suspend workspace');\n toast.error(errorMsg);\n void nativeNotify('error');\n if (isNative()) void nativeToast(errorMsg);\n }\n };\n\n const handleDelete = (workspaceId: string, workspaceName: string) => {\n nativeImpact('medium');\n const title = tr('workspaces.suspend.title', 'Suspend workspace');\n const description = `${tr('workspaces.suspend.prefix', 'Suspend')} ${workspaceName}? ${tr(\n 'workspaces.suspend.suffix',\n 'Workspace members will lose access until it is reactivated.'\n )}`;\n void nativeConfirm({\n title,\n message: description,\n okButtonTitle: tr('workspaces.suspend.confirm', 'Suspend'),\n }).then((nativeResult) => {\n if (nativeResult === null) {\n openConfirmDialog({\n title,\n description,\n confirmText: tr('workspaces.suspend.confirm', 'Suspend'),\n variant: 'warning',\n onConfirm: () => {\n void executeSuspend([workspaceId]);\n },\n });\n } else if (nativeResult) {\n void executeSuspend([workspaceId]);\n }\n });\n };\n\n const handleBulkDelete = () => {\n if (selectedWorkspaces.length === 0) return;\n\n openConfirmDialog({\n title: tr('workspaces.suspend.bulkTitle', 'Suspend selected workspaces'),\n description: `${tr('workspaces.suspend.prefix', 'Suspend')} ${selectedWorkspaces.length} ${tr(\n selectedWorkspaces.length === 1\n ? 'workspaces.suspend.bulkSuffixSingle'\n : 'workspaces.suspend.bulkSuffixMany',\n selectedWorkspaces.length === 1 ? 'selected workspace?' : 'selected workspaces?'\n )}`,\n confirmText: `${tr('workspaces.suspend.confirm', 'Suspend')} ${selectedWorkspaces.length}`,\n variant: 'warning',\n onConfirm: () => {\n void executeSuspend(selectedWorkspaces.map((workspace) => workspace.id));\n },\n });\n };\n\n const toggleWorkspaceSelection = (workspaceId: string, checked: boolean) => {\n setSelectedWorkspaceIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n if (checked) {\n nextSelection.add(workspaceId);\n } else {\n nextSelection.delete(workspaceId);\n }\n return nextSelection;\n });\n };\n\n const toggleAllWorkspaces = (checked: boolean) => {\n setSelectedWorkspaceIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n workspaces.forEach((workspace) => {\n if (checked) {\n nextSelection.add(workspace.id);\n } else {\n nextSelection.delete(workspace.id);\n }\n });\n return nextSelection;\n });\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (!hasPermission(PERMISSIONS.WORKSPACE_LIST)) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <div className=\"p-8 text-center text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.noPermission', \"You don't have permission to view workspaces.\")}\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('workspaces.list.loading', 'Loading workspaces...')} />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error.message}\n action={{\n label: tr('common.retry', 'Retry'),\n onClick: () => {\n void refetch();\n },\n }}\n />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-300\">\n <div className=\"mx-auto flex w-full max-w-7xl flex-col gap-6\">\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"space-y-2\">\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)]\">\n {tr('workspaces.list.title', 'Workspaces')}\n </h1>\n <p className=\"max-w-2xl text-[var(--color-text-secondary)]\">\n {tr(\n 'workspaces.list.subtitle',\n 'Manage organization workspaces, review their status, and open the workspace detail flow.'\n )}\n </p>\n </div>\n\n {hasPermission(PERMISSIONS.WORKSPACE_CREATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/new`)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90 active:scale-[0.98]\"\n >\n <Plus size={18} aria-hidden=\"true\" />\n <span className=\"font-medium\">\n {tr('workspaces.create.button', 'Create Workspace')}\n </span>\n </button>\n )}\n </div>\n\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center\">\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('workspaces.list.searchPlaceholder', 'Search workspaces...')}\n label={tr('workspaces.list.searchLabel', 'Search workspaces')}\n inputId=\"workspaces-search\"\n className=\"flex-1\"\n />\n\n <label className=\"flex min-h-11 min-w-[180px] flex-col justify-center rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-sm text-[var(--color-text-secondary)]\">\n <span className=\"sr-only\">\n {tr('workspaces.list.filterByStatus', 'Filter by workspace status')}\n </span>\n <select\n value={filter.status || ''}\n onChange={(event) =>\n setFilter({\n ...filter,\n status: event.target.value\n ? (event.target.value as WorkspaceStatus)\n : undefined,\n })\n }\n className=\"bg-transparent text-[var(--color-text-primary)] focus:outline-none\"\n aria-label={tr('workspaces.list.filterByStatus', 'Filter by workspace status')}\n >\n <option value=\"\">{tr('workspaces.list.allStatuses', 'All statuses')}</option>\n <option value={WorkspaceStatus.ACTIVE}>\n {tr('workspaces.status.active', 'Active')}\n </option>\n <option value={WorkspaceStatus.INACTIVE}>\n {tr('workspaces.status.inactive', 'Inactive')}\n </option>\n <option value={WorkspaceStatus.ARCHIVED}>\n {tr('workspaces.status.archived', 'Archived')}\n </option>\n </select>\n </label>\n\n <button\n type=\"button\"\n onClick={() => {\n void refetch();\n }}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)] active:scale-95\"\n aria-label={tr('workspaces.list.refresh', 'Refresh workspaces')}\n title={tr('workspaces.list.refresh', 'Refresh workspaces')}\n >\n <RefreshCw size={18} aria-hidden=\"true\" />\n </button>\n </div>\n\n {workspaces.length > 0 ? (\n <div className=\"mt-4 flex flex-col gap-3 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"flex items-center gap-2 text-sm text-[var(--color-text-primary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllWorkspaces}\n ariaLabel={tr('workspaces.list.selectAll', 'Select all workspaces')}\n />\n <span>{tr('common.selectAllVisible', 'Select all visible')}</span>\n </label>\n\n {selectedWorkspaceIds.size > 0 ? (\n <button\n type=\"button\"\n onClick={() => setSelectedWorkspaceIds(new Set())}\n className=\"text-sm text-[var(--color-text-secondary)] transition-colors hover:text-[var(--color-text-primary)]\"\n >\n {tr('common.clearSelection', 'Clear selection')}\n </button>\n ) : null}\n </div>\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <span className=\"text-sm text-[var(--color-text-secondary)]\">\n {selectedWorkspaceIds.size} {tr('common.selected', 'selected')}\n </span>\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={handleBulkDelete}\n disabled={selectedWorkspaces.length === 0 || deleteLoading}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-status-warning-border)] px-3 py-2 text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n <span>{tr('workspaces.list.suspendSelected', 'Suspend Selected')}</span>\n {selectedWorkspaces.length > 0 ? (\n <span>({selectedWorkspaces.length})</span>\n ) : null}\n </button>\n )}\n </div>\n </div>\n ) : null}\n </div>\n\n {workspaces.length === 0 ? (\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-6 shadow-[var(--shadow-elevation-1)]\">\n <EmptyState\n icon={<Briefcase size={40} aria-hidden=\"true\" />}\n title={tr('workspaces.list.emptyNoneTitle', 'No workspaces found')}\n description={\n hasPermission(PERMISSIONS.WORKSPACE_CREATE)\n ? tr(\n 'workspaces.list.emptyNoneDescription',\n 'Create a workspace to start mapping members, organization ownership, and collaboration settings.'\n )\n : tr(\n 'workspaces.list.emptyNoneDescriptionViewer',\n 'No workspaces have been created yet.'\n )\n }\n action={\n hasPermission(PERMISSIONS.WORKSPACE_CREATE)\n ? {\n label: tr('workspaces.create.button', 'Create Workspace'),\n onClick: () => navigate(`${basePath}/workspaces/new`),\n }\n : undefined\n }\n />\n </div>\n ) : (\n <>\n <div className=\"grid gap-4 md:hidden\">\n {workspaces.map((workspace) => (\n <article\n key={workspace.id}\n className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-4 shadow-[var(--shadow-elevation-1)]\"\n >\n <div className=\"flex items-start gap-3\">\n <SelectionCheckbox\n checked={selectedWorkspaceIds.has(workspace.id)}\n onChange={(checked) => toggleWorkspaceSelection(workspace.id, checked)}\n ariaLabel={`${tr('workspaces.list.selectOne', 'Select workspace')} ${workspace.name}`}\n />\n\n <div className=\"min-w-0 flex-1 space-y-3\">\n <div>\n <div className=\"flex flex-wrap items-start gap-2\">\n <h2 className=\"text-base font-semibold text-[var(--color-text-primary)]\">\n {workspace.name}\n </h2>\n <WorkspaceStatusBadge status={workspace.status} />\n </div>\n <p className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{workspace.slug}\n </p>\n </div>\n\n <dl className=\"grid grid-cols-2 gap-3 text-sm\">\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.members', 'Members')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {workspace.memberCount ?? 0}\n </dd>\n </div>\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {formatDate(workspace.createdAt)}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n\n <div className=\"mt-4 flex flex-wrap gap-2 border-t border-[var(--color-border-default)] pt-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <Eye size={16} aria-hidden=\"true\" />\n {tr('common.view', 'View')}\n </button>\n {hasPermission(PERMISSIONS.WORKSPACE_UPDATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}/edit`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <SquarePen size={16} aria-hidden=\"true\" />\n {tr('common.edit', 'Edit')}\n </button>\n )}\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(workspace.id, workspace.name)}\n disabled={deleteLoading}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-status-warning-border)] px-3 py-2 text-sm text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr('workspaces.suspend.confirm', 'Suspend')}\n </button>\n )}\n </div>\n </article>\n ))}\n </div>\n\n <div className=\"hidden overflow-hidden rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] shadow-[var(--shadow-elevation-1)] md:block\">\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full\">\n <thead className=\"bg-[var(--color-bg-subtle)]\">\n <tr>\n <th className=\"w-12 px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllWorkspaces}\n ariaLabel={tr('workspaces.list.selectAll', 'Select all workspaces')}\n />\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.column.workspace', 'Workspace')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.status', 'Status')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </th>\n <th className=\"px-6 py-3 text-right text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-[var(--color-border-default)]\">\n {workspaces.map((workspace) => (\n <tr\n key={workspace.id}\n className=\"transition-colors hover:bg-[var(--color-bg-subtle)]\"\n >\n <td className=\"px-6 py-4 align-top\">\n <SelectionCheckbox\n checked={selectedWorkspaceIds.has(workspace.id)}\n onChange={(checked) => toggleWorkspaceSelection(workspace.id, checked)}\n ariaLabel={`${tr('workspaces.list.selectOne', 'Select workspace')} ${workspace.name}`}\n />\n </td>\n <td className=\"px-6 py-4\">\n <div>\n <p className=\"font-medium text-[var(--color-text-primary)]\">\n {workspace.name}\n </p>\n <p className=\"break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{workspace.slug}\n </p>\n </div>\n </td>\n <td className=\"px-6 py-4 align-top\">\n <WorkspaceStatusBadge status={workspace.status} />\n </td>\n <td className=\"px-6 py-4 align-top text-sm text-[var(--color-text-secondary)]\">\n {formatDate(workspace.createdAt)}\n </td>\n <td className=\"px-6 py-4 align-top\">\n <div className=\"flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}`)}\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.view', 'View')} ${workspace.name}`}\n aria-label={`${tr('common.view', 'View')} ${workspace.name}`}\n >\n <Eye size={18} aria-hidden=\"true\" />\n </button>\n {hasPermission(PERMISSIONS.WORKSPACE_UPDATE) && (\n <button\n type=\"button\"\n onClick={() =>\n navigate(`${basePath}/workspaces/${workspace.id}/edit`)\n }\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.edit', 'Edit')} ${workspace.name}`}\n aria-label={`${tr('common.edit', 'Edit')} ${workspace.name}`}\n >\n <SquarePen size={18} aria-hidden=\"true\" />\n </button>\n )}\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(workspace.id, workspace.name)}\n disabled={deleteLoading}\n className=\"rounded-lg p-2 text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n title={`${tr('workspaces.suspend.confirm', 'Suspend')} ${workspace.name}`}\n aria-label={`${tr('workspaces.suspend.confirm', 'Suspend')} ${workspace.name}`}\n >\n <Trash2 size={18} aria-hidden=\"true\" />\n </button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </>\n )}\n </div>\n\n {ConfirmDialog}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkspacesListPage.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/pages/WorkspacesListPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { Briefcase, Eye, Plus, RefreshCw, SquarePen, Trash2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useDeleteWorkspace, useWorkspaces } from '../hooks/useWorkspaces';\nimport { WorkspaceStatusBadge } from '../components/WorkspaceStatusBadge';\nimport { SearchInput } from '../../../shared/components/input/SearchInput';\nimport { SelectionCheckbox } from '../../../shared/components/input/SelectionCheckbox';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { EmptyState } from '../../../shared/components/feedback/EmptyState';\nimport { useDebouncedValue } from '../../../shared/hooks/useDebouncedValue';\nimport { useConfirmDialog } from '../../../shared/components/dialog/ConfirmDialog';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport type { WorkspaceFilterInput } from '../types';\nimport { WorkspaceStatus } from '../types';\nimport {\n isNative,\n nativeConfirm,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../../../utils/nativeBridge';\n\nfunction formatDate(date: string) {\n return new Date(date).toLocaleDateString();\n}\n\n/**\n * `mode` controls the scope of the listing:\n * - `'my'` — membership-scoped (`myWorkspaces`); the default for user-facing\n * app shells. A regular user only sees workspaces they belong to.\n * - `'admin'` — platform-wide (`allWorkspaces`, super-admin only); the admin app.\n */\nexport interface WorkspacesListPageProps {\n mode?: 'my' | 'admin';\n}\n\nexport function WorkspacesListPage({ mode = 'my' }: WorkspacesListPageProps = {}) {\n const tr = useTr();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const [searchQuery, setSearchQuery] = useState('');\n const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);\n const [filter, setFilter] = useState<WorkspaceFilterInput>({});\n const [selectedWorkspaceIds, setSelectedWorkspaceIds] = useState<Set<string>>(new Set());\n const { openConfirmDialog, ConfirmDialog } = useConfirmDialog();\n\n // 'my' shells call the self-scoped `myWorkspaces` (no server-side filter arg),\n // so we over-fetch a page and filter client-side below. The admin app keeps\n // the server-filtered, paginated `allWorkspaces`.\n const scope = mode === 'admin' ? 'all' : 'my';\n const {\n workspaces: fetchedWorkspaces,\n loading,\n error,\n refetch,\n } = useWorkspaces(\n { ...filter, search: debouncedSearchQuery || undefined },\n scope === 'my' ? 100 : 20,\n 0,\n scope\n );\n\n const workspaces = useMemo(() => {\n if (scope !== 'my') return fetchedWorkspaces;\n const query = debouncedSearchQuery.trim().toLowerCase();\n return fetchedWorkspaces.filter((workspace) => {\n const matchesSearch =\n !query ||\n workspace.name.toLowerCase().includes(query) ||\n (workspace.slug?.toLowerCase().includes(query) ?? false);\n const matchesStatus = !filter.status || workspace.status === filter.status;\n return matchesSearch && matchesStatus;\n });\n }, [fetchedWorkspaces, scope, debouncedSearchQuery, filter.status]);\n\n const { deleteWorkspace, loading: deleteLoading } = useDeleteWorkspace();\n\n useEffect(() => {\n setSelectedWorkspaceIds((previousSelection) => {\n const visibleIds = new Set(workspaces.map((workspace) => workspace.id));\n const nextSelection = new Set(\n [...previousSelection].filter((workspaceId) => visibleIds.has(workspaceId))\n );\n\n if (nextSelection.size === previousSelection.size) {\n return previousSelection;\n }\n\n return nextSelection;\n });\n }, [workspaces]);\n\n const selectedWorkspaces = useMemo(\n () => workspaces.filter((workspace) => selectedWorkspaceIds.has(workspace.id)),\n [selectedWorkspaceIds, workspaces]\n );\n\n const allVisibleSelected =\n workspaces.length > 0 &&\n workspaces.every((workspace) => selectedWorkspaceIds.has(workspace.id));\n const partiallySelected =\n workspaces.some((workspace) => selectedWorkspaceIds.has(workspace.id)) && !allVisibleSelected;\n\n const executeSuspend = async (workspaceIds: string[]) => {\n try {\n const results = await Promise.allSettled(\n workspaceIds.map(async (workspaceId) => {\n const result = await deleteWorkspace(workspaceId);\n if (result.errors?.length) {\n throw new Error(\n result.errors[0]?.message ??\n tr('workspaces.suspend.failed', 'Failed to suspend workspace')\n );\n }\n })\n );\n\n const rejectedResult = results.find((result) => result.status === 'rejected');\n if (rejectedResult?.status === 'rejected') {\n throw rejectedResult.reason;\n }\n\n setSelectedWorkspaceIds(new Set());\n await refetch();\n const successMsg =\n workspaceIds.length === 1\n ? tr('workspaces.suspend.successSingle', 'Workspace suspended successfully')\n : `${workspaceIds.length} ${tr('workspaces.suspend.successMany', 'workspaces suspended successfully')}`;\n toast.success(successMsg);\n void nativeNotify('success');\n if (isNative()) void nativeToast(successMsg);\n } catch (suspendError) {\n const errorMsg =\n suspendError instanceof Error\n ? suspendError.message\n : tr('workspaces.suspend.failed', 'Failed to suspend workspace');\n toast.error(errorMsg);\n void nativeNotify('error');\n if (isNative()) void nativeToast(errorMsg);\n }\n };\n\n const handleDelete = (workspaceId: string, workspaceName: string) => {\n nativeImpact('medium');\n const title = tr('workspaces.suspend.title', 'Suspend workspace');\n const description = `${tr('workspaces.suspend.prefix', 'Suspend')} ${workspaceName}? ${tr(\n 'workspaces.suspend.suffix',\n 'Workspace members will lose access until it is reactivated.'\n )}`;\n void nativeConfirm({\n title,\n message: description,\n okButtonTitle: tr('workspaces.suspend.confirm', 'Suspend'),\n }).then((nativeResult) => {\n if (nativeResult === null) {\n openConfirmDialog({\n title,\n description,\n confirmText: tr('workspaces.suspend.confirm', 'Suspend'),\n variant: 'warning',\n onConfirm: () => {\n void executeSuspend([workspaceId]);\n },\n });\n } else if (nativeResult) {\n void executeSuspend([workspaceId]);\n }\n });\n };\n\n const handleBulkDelete = () => {\n if (selectedWorkspaces.length === 0) return;\n\n openConfirmDialog({\n title: tr('workspaces.suspend.bulkTitle', 'Suspend selected workspaces'),\n description: `${tr('workspaces.suspend.prefix', 'Suspend')} ${selectedWorkspaces.length} ${tr(\n selectedWorkspaces.length === 1\n ? 'workspaces.suspend.bulkSuffixSingle'\n : 'workspaces.suspend.bulkSuffixMany',\n selectedWorkspaces.length === 1 ? 'selected workspace?' : 'selected workspaces?'\n )}`,\n confirmText: `${tr('workspaces.suspend.confirm', 'Suspend')} ${selectedWorkspaces.length}`,\n variant: 'warning',\n onConfirm: () => {\n void executeSuspend(selectedWorkspaces.map((workspace) => workspace.id));\n },\n });\n };\n\n const toggleWorkspaceSelection = (workspaceId: string, checked: boolean) => {\n setSelectedWorkspaceIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n if (checked) {\n nextSelection.add(workspaceId);\n } else {\n nextSelection.delete(workspaceId);\n }\n return nextSelection;\n });\n };\n\n const toggleAllWorkspaces = (checked: boolean) => {\n setSelectedWorkspaceIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n workspaces.forEach((workspace) => {\n if (checked) {\n nextSelection.add(workspace.id);\n } else {\n nextSelection.delete(workspace.id);\n }\n });\n return nextSelection;\n });\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (!hasPermission(PERMISSIONS.WORKSPACE_LIST)) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <div className=\"p-8 text-center text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.noPermission', \"You don't have permission to view workspaces.\")}\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('workspaces.list.loading', 'Loading workspaces...')} />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error.message}\n action={{\n label: tr('common.retry', 'Retry'),\n onClick: () => {\n void refetch();\n },\n }}\n />\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-200\">\n <div className=\"mx-auto flex w-full max-w-7xl flex-col gap-6\">\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"space-y-2\">\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)]\">\n {tr('workspaces.list.title', 'Workspaces')}\n </h1>\n <p className=\"max-w-2xl text-[var(--color-text-secondary)]\">\n {tr(\n 'workspaces.list.subtitle',\n 'Manage organization workspaces, review their status, and open the workspace detail flow.'\n )}\n </p>\n </div>\n\n {hasPermission(PERMISSIONS.WORKSPACE_CREATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/new`)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90\"\n >\n <Plus size={18} aria-hidden=\"true\" />\n <span className=\"font-medium\">\n {tr('workspaces.create.button', 'Create Workspace')}\n </span>\n </button>\n )}\n </div>\n\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center\">\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('workspaces.list.searchPlaceholder', 'Search workspaces...')}\n label={tr('workspaces.list.searchLabel', 'Search workspaces')}\n inputId=\"workspaces-search\"\n className=\"flex-1\"\n />\n\n <label className=\"flex min-h-11 min-w-[180px] flex-col justify-center rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-sm text-[var(--color-text-secondary)]\">\n <span className=\"sr-only\">\n {tr('workspaces.list.filterByStatus', 'Filter by workspace status')}\n </span>\n <select\n value={filter.status || ''}\n onChange={(event) =>\n setFilter({\n ...filter,\n status: event.target.value\n ? (event.target.value as WorkspaceStatus)\n : undefined,\n })\n }\n className=\"bg-transparent text-[var(--color-text-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n aria-label={tr('workspaces.list.filterByStatus', 'Filter by workspace status')}\n >\n <option value=\"\">{tr('workspaces.list.allStatuses', 'All statuses')}</option>\n <option value={WorkspaceStatus.ACTIVE}>\n {tr('workspaces.status.active', 'Active')}\n </option>\n <option value={WorkspaceStatus.INACTIVE}>\n {tr('workspaces.status.inactive', 'Inactive')}\n </option>\n <option value={WorkspaceStatus.ARCHIVED}>\n {tr('workspaces.status.archived', 'Archived')}\n </option>\n </select>\n </label>\n\n <button\n type=\"button\"\n onClick={() => {\n void refetch();\n }}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n aria-label={tr('workspaces.list.refresh', 'Refresh workspaces')}\n title={tr('workspaces.list.refresh', 'Refresh workspaces')}\n >\n <RefreshCw size={18} aria-hidden=\"true\" />\n </button>\n </div>\n\n {workspaces.length > 0 ? (\n <div className=\"mt-4 flex flex-col gap-3 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"flex items-center gap-2 text-sm text-[var(--color-text-primary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllWorkspaces}\n ariaLabel={tr('workspaces.list.selectAll', 'Select all workspaces')}\n />\n <span>{tr('common.selectAllVisible', 'Select all visible')}</span>\n </label>\n\n {selectedWorkspaceIds.size > 0 ? (\n <button\n type=\"button\"\n onClick={() => setSelectedWorkspaceIds(new Set())}\n className=\"text-sm text-[var(--color-text-secondary)] transition-colors hover:text-[var(--color-text-primary)]\"\n >\n {tr('common.clearSelection', 'Clear selection')}\n </button>\n ) : null}\n </div>\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <span className=\"text-sm text-[var(--color-text-secondary)]\">\n {selectedWorkspaceIds.size} {tr('common.selected', 'selected')}\n </span>\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={handleBulkDelete}\n disabled={selectedWorkspaces.length === 0 || deleteLoading}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-status-warning-border)] px-3 py-2 text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n <span>{tr('workspaces.list.suspendSelected', 'Suspend Selected')}</span>\n {selectedWorkspaces.length > 0 ? (\n <span>({selectedWorkspaces.length})</span>\n ) : null}\n </button>\n )}\n </div>\n </div>\n ) : null}\n </div>\n\n {workspaces.length === 0 ? (\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-6 shadow-[var(--shadow-elevation-1)]\">\n <EmptyState\n icon={<Briefcase size={40} aria-hidden=\"true\" />}\n title={tr('workspaces.list.emptyNoneTitle', 'No workspaces found')}\n description={\n hasPermission(PERMISSIONS.WORKSPACE_CREATE)\n ? tr(\n 'workspaces.list.emptyNoneDescription',\n 'Create a workspace to start mapping members, organization ownership, and collaboration settings.'\n )\n : tr(\n 'workspaces.list.emptyNoneDescriptionViewer',\n 'No workspaces have been created yet.'\n )\n }\n action={\n hasPermission(PERMISSIONS.WORKSPACE_CREATE)\n ? {\n label: tr('workspaces.create.button', 'Create Workspace'),\n onClick: () => navigate(`${basePath}/workspaces/new`),\n }\n : undefined\n }\n />\n </div>\n ) : (\n <>\n <div className=\"grid gap-4 md:hidden\">\n {workspaces.map((workspace) => (\n <article\n key={workspace.id}\n className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-4 shadow-[var(--shadow-elevation-1)]\"\n >\n <div className=\"flex items-start gap-3\">\n <SelectionCheckbox\n checked={selectedWorkspaceIds.has(workspace.id)}\n onChange={(checked) => toggleWorkspaceSelection(workspace.id, checked)}\n ariaLabel={`${tr('workspaces.list.selectOne', 'Select workspace')} ${workspace.name}`}\n />\n\n <div className=\"min-w-0 flex-1 space-y-3\">\n <div>\n <div className=\"flex flex-wrap items-start gap-2\">\n <h2 className=\"text-base font-semibold text-[var(--color-text-primary)]\">\n {workspace.name}\n </h2>\n <WorkspaceStatusBadge status={workspace.status} />\n </div>\n <p className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{workspace.slug}\n </p>\n </div>\n\n <dl className=\"grid grid-cols-2 gap-3 text-sm\">\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.members', 'Members')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {workspace.memberCount ?? 0}\n </dd>\n </div>\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {formatDate(workspace.createdAt)}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n\n <div className=\"mt-4 flex flex-wrap gap-2 border-t border-[var(--color-border-default)] pt-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <Eye size={16} aria-hidden=\"true\" />\n {tr('common.view', 'View')}\n </button>\n {hasPermission(PERMISSIONS.WORKSPACE_UPDATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}/edit`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <SquarePen size={16} aria-hidden=\"true\" />\n {tr('common.edit', 'Edit')}\n </button>\n )}\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(workspace.id, workspace.name)}\n disabled={deleteLoading}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-status-warning-border)] px-3 py-2 text-sm text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr('workspaces.suspend.confirm', 'Suspend')}\n </button>\n )}\n </div>\n </article>\n ))}\n </div>\n\n <div className=\"hidden overflow-hidden rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] shadow-[var(--shadow-elevation-1)] md:block\">\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full\">\n <thead className=\"bg-[var(--color-bg-subtle)]\">\n <tr>\n <th className=\"w-12 px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllWorkspaces}\n ariaLabel={tr('workspaces.list.selectAll', 'Select all workspaces')}\n />\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('workspaces.list.column.workspace', 'Workspace')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.status', 'Status')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </th>\n <th className=\"px-6 py-3 text-right text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-[var(--color-border-default)]\">\n {workspaces.map((workspace) => (\n <tr\n key={workspace.id}\n className=\"transition-colors hover:bg-[var(--color-bg-subtle)]\"\n >\n <td className=\"px-6 py-4 align-top\">\n <SelectionCheckbox\n checked={selectedWorkspaceIds.has(workspace.id)}\n onChange={(checked) => toggleWorkspaceSelection(workspace.id, checked)}\n ariaLabel={`${tr('workspaces.list.selectOne', 'Select workspace')} ${workspace.name}`}\n />\n </td>\n <td className=\"px-6 py-4\">\n <div>\n <p className=\"font-medium text-[var(--color-text-primary)]\">\n {workspace.name}\n </p>\n <p className=\"break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{workspace.slug}\n </p>\n </div>\n </td>\n <td className=\"px-6 py-4 align-top\">\n <WorkspaceStatusBadge status={workspace.status} />\n </td>\n <td className=\"px-6 py-4 align-top text-sm text-[var(--color-text-secondary)]\">\n {formatDate(workspace.createdAt)}\n </td>\n <td className=\"px-6 py-4 align-top\">\n <div className=\"flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/workspaces/${workspace.id}`)}\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.view', 'View')} ${workspace.name}`}\n aria-label={`${tr('common.view', 'View')} ${workspace.name}`}\n >\n <Eye size={18} aria-hidden=\"true\" />\n </button>\n {hasPermission(PERMISSIONS.WORKSPACE_UPDATE) && (\n <button\n type=\"button\"\n onClick={() =>\n navigate(`${basePath}/workspaces/${workspace.id}/edit`)\n }\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.edit', 'Edit')} ${workspace.name}`}\n aria-label={`${tr('common.edit', 'Edit')} ${workspace.name}`}\n >\n <SquarePen size={18} aria-hidden=\"true\" />\n </button>\n )}\n {hasPermission(PERMISSIONS.WORKSPACE_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(workspace.id, workspace.name)}\n disabled={deleteLoading}\n className=\"rounded-lg p-2 text-[var(--color-status-warning-text)] transition-all duration-200 hover:bg-[var(--color-status-warning-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50\"\n title={`${tr('workspaces.suspend.confirm', 'Suspend')} ${workspace.name}`}\n aria-label={`${tr('workspaces.suspend.confirm', 'Suspend')} ${workspace.name}`}\n >\n <Trash2 size={18} aria-hidden=\"true\" />\n </button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </>\n )}\n </div>\n\n {ConfirmDialog}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { jsx as e, jsxs as t } from "react/jsx-runtime";
|
|
|
2
2
|
//#region src/organization-management/shared/components/feedback/EmptyState.tsx
|
|
3
3
|
function n({ icon: n, title: r, description: i, action: a }) {
|
|
4
4
|
return /* @__PURE__ */ t("div", {
|
|
5
|
-
className: "flex flex-col items-center justify-center py-12 text-center animate-in fade-in duration-
|
|
5
|
+
className: "flex flex-col items-center justify-center py-12 text-center animate-in fade-in duration-200",
|
|
6
6
|
children: [
|
|
7
7
|
/* @__PURE__ */ e("div", {
|
|
8
8
|
className: "text-[var(--color-text-muted)] mb-4",
|
|
@@ -19,7 +19,7 @@ function n({ icon: n, title: r, description: i, action: a }) {
|
|
|
19
19
|
a && /* @__PURE__ */ e("button", {
|
|
20
20
|
type: "button",
|
|
21
21
|
onClick: a.onClick,
|
|
22
|
-
className: "\n inline-flex items-center gap-2 px-4 py-2\n bg-[var(--color-action-primary-bg)]\n text-[var(--color-action-primary-text)]\n rounded-lg\n hover:opacity-90
|
|
22
|
+
className: "\n inline-flex items-center gap-2 px-4 py-2\n bg-[var(--color-action-primary-bg)]\n text-[var(--color-action-primary-text)]\n rounded-lg\n hover:opacity-90\n \n transition-all duration-200\n font-medium\n ",
|
|
23
23
|
children: a.label
|
|
24
24
|
})
|
|
25
25
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState.js","names":[],"sources":["../../../../../src/organization-management/shared/components/feedback/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\ninterface EmptyStateProps {\n icon: ReactNode;\n title: string;\n description: string;\n action?: {\n label: string;\n onClick: () => void;\n };\n}\n\nexport function EmptyState({ icon, title, description, action }: EmptyStateProps) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 text-center animate-in fade-in duration-
|
|
1
|
+
{"version":3,"file":"EmptyState.js","names":[],"sources":["../../../../../src/organization-management/shared/components/feedback/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\ninterface EmptyStateProps {\n icon: ReactNode;\n title: string;\n description: string;\n action?: {\n label: string;\n onClick: () => void;\n };\n}\n\nexport function EmptyState({ icon, title, description, action }: EmptyStateProps) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 text-center animate-in fade-in duration-200\">\n <div className=\"text-[var(--color-text-muted)] mb-4\">{icon}</div>\n <h3 className=\"text-lg font-semibold text-[var(--color-text-primary)] mb-2\">{title}</h3>\n <p className=\"text-sm text-[var(--color-text-muted)] mb-6 max-w-md\">{description}</p>\n {action && (\n <button\n type=\"button\"\n onClick={action.onClick}\n className=\"\n inline-flex items-center gap-2 px-4 py-2\n bg-[var(--color-action-primary-bg)]\n text-[var(--color-action-primary-text)]\n rounded-lg\n hover:opacity-90\n \n transition-all duration-200\n font-medium\n \"\n >\n {action.label}\n </button>\n )}\n </div>\n );\n}\n"],"mappings":";;AAYA,SAAgB,EAAW,EAAE,SAAM,UAAO,gBAAa,aAA2B;AAChF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAuC;IAAW,CAAA;GACjE,kBAAC,MAAD;IAAI,WAAU;cAA+D;IAAW,CAAA;GACxF,kBAAC,KAAD;IAAG,WAAU;cAAwD;IAAgB,CAAA;GACpF,KACC,kBAAC,UAAD;IACE,MAAK;IACL,SAAS,EAAO;IAChB,WAAU;cAWT,EAAO;IACD,CAAA;GAEP"}
|
|
@@ -5,7 +5,7 @@ import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
|
5
5
|
function i({ title: i, message: a, action: o }) {
|
|
6
6
|
let s = e(), c = i ?? s("common.error.title", "Something went wrong");
|
|
7
7
|
return /* @__PURE__ */ r("div", {
|
|
8
|
-
className: "flex flex-col items-center justify-center py-12 text-center animate-in fade-in duration-
|
|
8
|
+
className: "flex flex-col items-center justify-center py-12 text-center animate-in fade-in duration-200",
|
|
9
9
|
role: "alert",
|
|
10
10
|
children: [
|
|
11
11
|
/* @__PURE__ */ n("div", {
|
|
@@ -26,7 +26,7 @@ function i({ title: i, message: a, action: o }) {
|
|
|
26
26
|
o && /* @__PURE__ */ n("button", {
|
|
27
27
|
type: "button",
|
|
28
28
|
onClick: o.onClick,
|
|
29
|
-
className: "\n inline-flex items-center gap-2 px-4 py-2\n bg-[var(--color-action-primary-bg)]\n text-[var(--color-action-primary-text)]\n rounded-lg\n hover:opacity-90
|
|
29
|
+
className: "\n inline-flex items-center gap-2 px-4 py-2\n bg-[var(--color-action-primary-bg)]\n text-[var(--color-action-primary-text)]\n rounded-lg\n hover:opacity-90\n \n transition-all duration-200\n font-medium\n ",
|
|
30
30
|
children: o.label
|
|
31
31
|
})
|
|
32
32
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorState.js","names":[],"sources":["../../../../../src/organization-management/shared/components/feedback/ErrorState.tsx"],"sourcesContent":["import { AlertCircle } from 'lucide-react';\nimport { useTr } from '../../hooks/useTr';\n\ninterface ErrorStateProps {\n title?: string;\n message: string;\n action?: {\n label: string;\n onClick: () => void;\n };\n}\n\nexport function ErrorState({ title, message, action }: ErrorStateProps) {\n const tr = useTr();\n const resolvedTitle = title ?? tr('common.error.title', 'Something went wrong');\n return (\n <div\n className=\"flex flex-col items-center justify-center py-12 text-center animate-in fade-in duration-
|
|
1
|
+
{"version":3,"file":"ErrorState.js","names":[],"sources":["../../../../../src/organization-management/shared/components/feedback/ErrorState.tsx"],"sourcesContent":["import { AlertCircle } from 'lucide-react';\nimport { useTr } from '../../hooks/useTr';\n\ninterface ErrorStateProps {\n title?: string;\n message: string;\n action?: {\n label: string;\n onClick: () => void;\n };\n}\n\nexport function ErrorState({ title, message, action }: ErrorStateProps) {\n const tr = useTr();\n const resolvedTitle = title ?? tr('common.error.title', 'Something went wrong');\n return (\n <div\n className=\"flex flex-col items-center justify-center py-12 text-center animate-in fade-in duration-200\"\n role=\"alert\"\n >\n <div className=\"size-16 rounded-full bg-[var(--color-status-error-muted)] flex items-center justify-center mb-4\">\n <AlertCircle size={32} className=\"text-[var(--color-status-error)]\" />\n </div>\n <h3 className=\"text-lg font-semibold text-[var(--color-text-primary)] mb-2\">\n {resolvedTitle}\n </h3>\n <p className=\"text-sm text-[var(--color-text-muted)] mb-6 max-w-md\">{message}</p>\n {action && (\n <button\n type=\"button\"\n onClick={action.onClick}\n className=\"\n inline-flex items-center gap-2 px-4 py-2\n bg-[var(--color-action-primary-bg)]\n text-[var(--color-action-primary-text)]\n rounded-lg\n hover:opacity-90\n \n transition-all duration-200\n font-medium\n \"\n >\n {action.label}\n </button>\n )}\n </div>\n );\n}\n"],"mappings":";;;;AAYA,SAAgB,EAAW,EAAE,UAAO,YAAS,aAA2B;CACtE,IAAM,IAAK,GAAO,EACZ,IAAgB,KAAS,EAAG,sBAAsB,uBAAuB;AAC/E,QACE,kBAAC,OAAD;EACE,WAAU;EACV,MAAK;YAFP;GAIE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KAAa,MAAM;KAAI,WAAU;KAAqC,CAAA;IAClE,CAAA;GACN,kBAAC,MAAD;IAAI,WAAU;cACX;IACE,CAAA;GACL,kBAAC,KAAD;IAAG,WAAU;cAAwD;IAAY,CAAA;GAChF,KACC,kBAAC,UAAD;IACE,MAAK;IACL,SAAS,EAAO;IAChB,WAAU;cAWT,EAAO;IACD,CAAA;GAEP"}
|
|
@@ -5,7 +5,7 @@ import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
|
5
5
|
function i({ message: i }) {
|
|
6
6
|
let a = e(), o = i ?? a("common.loading", "Loading...");
|
|
7
7
|
return /* @__PURE__ */ r("output", {
|
|
8
|
-
className: "flex flex-col items-center justify-center py-12 animate-in fade-in duration-
|
|
8
|
+
className: "flex flex-col items-center justify-center py-12 animate-in fade-in duration-200",
|
|
9
9
|
"aria-live": "polite",
|
|
10
10
|
"aria-busy": "true",
|
|
11
11
|
children: [/* @__PURE__ */ n(t, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoadingState.js","names":[],"sources":["../../../../../src/organization-management/shared/components/feedback/LoadingState.tsx"],"sourcesContent":["import { Loader2 } from 'lucide-react';\nimport { useTr } from '../../hooks/useTr';\n\ninterface LoadingStateProps {\n message?: string;\n}\n\nexport function LoadingState({ message }: LoadingStateProps) {\n const tr = useTr();\n const resolvedMessage = message ?? tr('common.loading', 'Loading...');\n return (\n <output\n className=\"flex flex-col items-center justify-center py-12 animate-in fade-in duration-
|
|
1
|
+
{"version":3,"file":"LoadingState.js","names":[],"sources":["../../../../../src/organization-management/shared/components/feedback/LoadingState.tsx"],"sourcesContent":["import { Loader2 } from 'lucide-react';\nimport { useTr } from '../../hooks/useTr';\n\ninterface LoadingStateProps {\n message?: string;\n}\n\nexport function LoadingState({ message }: LoadingStateProps) {\n const tr = useTr();\n const resolvedMessage = message ?? tr('common.loading', 'Loading...');\n return (\n <output\n className=\"flex flex-col items-center justify-center py-12 animate-in fade-in duration-200\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n >\n <Loader2 size={48} className=\"text-[var(--color-status-info)] animate-spin mb-4\" />\n <p className=\"text-sm text-[var(--color-text-muted)]\">{resolvedMessage}</p>\n </output>\n );\n}\n"],"mappings":";;;;AAOA,SAAgB,EAAa,EAAE,cAA8B;CAC3D,IAAM,IAAK,GAAO,EACZ,IAAkB,KAAW,EAAG,kBAAkB,aAAa;AACrE,QACE,kBAAC,UAAD;EACE,WAAU;EACV,aAAU;EACV,aAAU;YAHZ,CAKE,kBAAC,GAAD;GAAS,MAAM;GAAI,WAAU;GAAsD,CAAA,EACnF,kBAAC,KAAD;GAAG,WAAU;aAA0C;GAAoB,CAAA,CACpE"}
|
|
@@ -28,7 +28,7 @@ function a({ value: a, onChange: o, placeholder: s, className: c = "", label: l,
|
|
|
28
28
|
a && /* @__PURE__ */ r("button", {
|
|
29
29
|
type: "button",
|
|
30
30
|
onClick: () => o(""),
|
|
31
|
-
className: "\n absolute right-3 top-1/2 -translate-y-1/2\n p-1 rounded-md\n text-[var(--color-text-muted)]\n hover:text-[var(--color-text-primary)]\n hover:bg-[var(--color-bg-subtle)]\n
|
|
31
|
+
className: "\n absolute right-3 top-1/2 -translate-y-1/2\n p-1 rounded-md\n text-[var(--color-text-muted)]\n hover:text-[var(--color-text-primary)]\n hover:bg-[var(--color-bg-subtle)]\n \n transition-all duration-200\n ",
|
|
32
32
|
"aria-label": "Clear search",
|
|
33
33
|
children: /* @__PURE__ */ r(n, { size: 16 })
|
|
34
34
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchInput.js","names":[],"sources":["../../../../../src/organization-management/shared/components/input/SearchInput.tsx"],"sourcesContent":["import { Search, X } from 'lucide-react';\nimport { useTr } from '../../hooks/useTr';\n\ninterface SearchInputProps {\n value: string;\n onChange: (value: string) => void;\n placeholder?: string;\n className?: string;\n label?: string;\n inputId?: string;\n}\n\n/**\n * SearchInput\n * Reusable search input component with clear button\n */\nexport function SearchInput({\n value,\n onChange,\n placeholder,\n className = '',\n label,\n inputId,\n}: SearchInputProps) {\n const tr = useTr();\n const resolvedPlaceholder = placeholder ?? tr('common.search.placeholder', 'Search...');\n return (\n <div className={`relative ${className}`}>\n {label ? (\n <label htmlFor={inputId} className=\"sr-only\">\n {label}\n </label>\n ) : null}\n <Search\n size={18}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\"\n />\n <input\n id={inputId}\n type=\"text\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder={resolvedPlaceholder}\n aria-label={label ?? resolvedPlaceholder}\n className=\"\n w-full pl-[3.25rem] pr-10 py-2\n bg-[var(--color-bg-surface)]\n border border-[var(--color-border-default)]\n rounded-lg\n text-[var(--color-text-primary)]\n placeholder:text-[var(--color-text-muted)]\n focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)]\n transition-all duration-200\n \"\n />\n {value && (\n <button\n type=\"button\"\n onClick={() => onChange('')}\n className=\"\n absolute right-3 top-1/2 -translate-y-1/2\n p-1 rounded-md\n text-[var(--color-text-muted)]\n hover:text-[var(--color-text-primary)]\n hover:bg-[var(--color-bg-subtle)]\n
|
|
1
|
+
{"version":3,"file":"SearchInput.js","names":[],"sources":["../../../../../src/organization-management/shared/components/input/SearchInput.tsx"],"sourcesContent":["import { Search, X } from 'lucide-react';\nimport { useTr } from '../../hooks/useTr';\n\ninterface SearchInputProps {\n value: string;\n onChange: (value: string) => void;\n placeholder?: string;\n className?: string;\n label?: string;\n inputId?: string;\n}\n\n/**\n * SearchInput\n * Reusable search input component with clear button\n */\nexport function SearchInput({\n value,\n onChange,\n placeholder,\n className = '',\n label,\n inputId,\n}: SearchInputProps) {\n const tr = useTr();\n const resolvedPlaceholder = placeholder ?? tr('common.search.placeholder', 'Search...');\n return (\n <div className={`relative ${className}`}>\n {label ? (\n <label htmlFor={inputId} className=\"sr-only\">\n {label}\n </label>\n ) : null}\n <Search\n size={18}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\"\n />\n <input\n id={inputId}\n type=\"text\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder={resolvedPlaceholder}\n aria-label={label ?? resolvedPlaceholder}\n className=\"\n w-full pl-[3.25rem] pr-10 py-2\n bg-[var(--color-bg-surface)]\n border border-[var(--color-border-default)]\n rounded-lg\n text-[var(--color-text-primary)]\n placeholder:text-[var(--color-text-muted)]\n focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)]\n transition-all duration-200\n \"\n />\n {value && (\n <button\n type=\"button\"\n onClick={() => onChange('')}\n className=\"\n absolute right-3 top-1/2 -translate-y-1/2\n p-1 rounded-md\n text-[var(--color-text-muted)]\n hover:text-[var(--color-text-primary)]\n hover:bg-[var(--color-bg-subtle)]\n \n transition-all duration-200\n \"\n aria-label=\"Clear search\"\n >\n <X size={16} />\n </button>\n )}\n </div>\n );\n}\n"],"mappings":";;;;AAgBA,SAAgB,EAAY,EAC1B,UACA,aACA,gBACA,eAAY,IACZ,UACA,cACmB;CACnB,IAAM,IAAK,GAAO,EACZ,IAAsB,KAAe,EAAG,6BAA6B,YAAY;AACvF,QACE,kBAAC,OAAD;EAAK,WAAW,YAAY;YAA5B;GACG,IACC,kBAAC,SAAD;IAAO,SAAS;IAAS,WAAU;cAChC;IACK,CAAA,GACN;GACJ,kBAAC,GAAD;IACE,MAAM;IACN,WAAU;IACV,CAAA;GACF,kBAAC,SAAD;IACE,IAAI;IACJ,MAAK;IACE;IACP,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;IACzC,aAAa;IACb,cAAY,KAAS;IACrB,WAAU;IAUV,CAAA;GACD,KACC,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAS,GAAG;IAC3B,WAAU;IASV,cAAW;cAEX,kBAAC,GAAD,EAAG,MAAM,IAAM,CAAA;IACR,CAAA;GAEP"}
|