'use client' import { useCallback, useMemo, useState } from 'react' import { Checkbox, ChipModal, ChipModalBody, ChipModalError, ChipModalField, ChipModalFooter, ChipModalHeader, ChipTag, Label, } from '@sim/emcn' import { createLogger } from '@sim/logger' import { getErrorMessage } from '@sim/utils/errors' import { ArrowRight, Plus } from 'lucide-react' import { useParams } from 'next/navigation' import { getEnv, isTruthy } from '@/lib/core/config/env' import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel' import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section' import { GroupDetail } from '@/ee/access-control/components/group-detail' import { WorkspaceSelect } from '@/ee/access-control/components/workspace-select' import { useCreatePermissionGroup, useOrganizationWorkspaces, usePermissionGroups, useUserPermissionConfig, } from '@/ee/access-control/hooks/permission-groups' const logger = createLogger('AccessControl') export function AccessControl() { const params = useParams() const workspaceId = typeof params?.workspaceId === 'string' ? params.workspaceId : undefined /** * Access control is governed by the workspace's OWNING organization, which may * differ from the caller's active org (e.g. external members). Resolve the org * id and the caller's admin status server-side from the workspace so gating is * never keyed off the session's active org. */ const { data: userPermissionConfig, isPending: entitlementLoading } = useUserPermissionConfig(workspaceId) const organizationId = userPermissionConfig?.organizationId ?? undefined const currentUserIsOrgAdmin = userPermissionConfig?.isOrgAdmin ?? false const { data: permissionGroups = [], isPending: groupsLoading } = usePermissionGroups( organizationId, !!organizationId && currentUserIsOrgAdmin ) const { data: organizationWorkspaces = [], isPending: workspacesLoading } = useOrganizationWorkspaces(organizationId, !!organizationId && currentUserIsOrgAdmin) const accessControlEnabledLocally = isTruthy(getEnv('NEXT_PUBLIC_ACCESS_CONTROL_ENABLED')) const isEntitled = accessControlEnabledLocally || !!userPermissionConfig?.entitled const canManage = isEntitled && currentUserIsOrgAdmin && !!organizationId const isLoading = !workspaceId || entitlementLoading || (!!organizationId && currentUserIsOrgAdmin && groupsLoading) const createPermissionGroup = useCreatePermissionGroup() const [searchTerm, setSearchTerm] = useState('') const [selectedGroupId, setSelectedGroupId] = useState(null) const [showCreateModal, setShowCreateModal] = useState(false) const [newGroupName, setNewGroupName] = useState('') const [newGroupDescription, setNewGroupDescription] = useState('') const [newGroupIsDefault, setNewGroupIsDefault] = useState(false) const [newGroupWorkspaceIds, setNewGroupWorkspaceIds] = useState([]) const [createError, setCreateError] = useState(null) const workspaceOptions = useMemo( () => organizationWorkspaces.map((ws) => ({ value: ws.id, label: ws.name })), [organizationWorkspaces] ) const filteredGroups = useMemo(() => { if (!searchTerm.trim()) return permissionGroups const searchLower = searchTerm.toLowerCase() return permissionGroups.filter((g) => g.name.toLowerCase().includes(searchLower)) }, [permissionGroups, searchTerm]) const selectedGroup = useMemo( () => (selectedGroupId ? permissionGroups.find((g) => g.id === selectedGroupId) : undefined), [permissionGroups, selectedGroupId] ) const handleCreatePermissionGroup = useCallback(async () => { if (!newGroupName.trim() || !organizationId) return setCreateError(null) try { await createPermissionGroup.mutateAsync({ organizationId, name: newGroupName.trim(), description: newGroupDescription.trim() || undefined, isDefault: newGroupIsDefault, workspaceIds: newGroupIsDefault ? undefined : newGroupWorkspaceIds, }) setShowCreateModal(false) setNewGroupName('') setNewGroupDescription('') setNewGroupIsDefault(false) setNewGroupWorkspaceIds([]) } catch (error) { logger.error('Failed to create permission group', error) setCreateError(getErrorMessage(error, 'Failed to create permission group')) } }, [ newGroupName, newGroupDescription, newGroupIsDefault, newGroupWorkspaceIds, organizationId, createPermissionGroup, ]) const handleCloseCreateModal = useCallback(() => { setShowCreateModal(false) setNewGroupName('') setNewGroupDescription('') setNewGroupIsDefault(false) setNewGroupWorkspaceIds([]) setCreateError(null) }, []) if (isLoading) { return null } if (!canManage) { return ( {!organizationId ? "Access Control applies to organization workspaces. This workspace isn't part of an organization." : 'Only organization admins on Enterprise plans can manage Access Control settings.'} ) } if (selectedGroup && organizationId) { return ( setSelectedGroupId(null)} onDeleted={() => setSelectedGroupId(null)} /> ) } return ( <> setShowCreateModal(true), }, ]} > {permissionGroups.length === 0 ? ( No permission groups yet. Click "Create group" to get started. ) : filteredGroups.length === 0 ? ( No groups found matching "{searchTerm}" ) : (
{filteredGroups.map((group) => ( ))}
)}
Create Permission Group { setNewGroupName(value) if (createError) setCreateError(null) }} placeholder='e.g., Marketing Team' /> setNewGroupDescription(value)} placeholder='e.g., Limited access for marketing users' />
{ const isDefault = checked === true setNewGroupIsDefault(isDefault) if (isDefault) setNewGroupWorkspaceIds([]) }} />
{!newGroupIsDefault && (

Applies to all members of the selected workspaces. Restrict to specific people later from the group's Members section.

)}
{createError}
) }