'use client'; import { useEffect, useMemo, useState } from 'react'; import { useMutation, useSuspenseQuery } from '@tanstack/react-query'; import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Checkbox } from '@/components/ui/checkbox'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { createCrmUserRoleAssignmentMutation, deleteCrmUserRoleAssignmentMutation, updateCrmUserRoleAssignmentMutation } from '../api/mutations'; import { crmUserRoleAssignmentsQueryOptions } from '../api/queries'; import type { CrmUserRoleAssignmentMutationPayload, CrmUserRoleAssignmentRecord, UpdateCrmUserRoleAssignmentPayload } from '../api/types'; type AssignmentEditorState = { branchScopeMode: CrmUserRoleAssignmentMutationPayload['branchScopeMode']; branchScopeIds: string[]; productTypeScopeMode: CrmUserRoleAssignmentMutationPayload['productTypeScopeMode']; productTypeScopeIds: string[]; isPrimary: boolean; isActive: boolean; }; const emptyCreateState: CrmUserRoleAssignmentMutationPayload = { userId: '', roleProfileId: '', branchScopeMode: 'inherit', branchScopeIds: [], productTypeScopeMode: 'inherit', productTypeScopeIds: [], isPrimary: false, isActive: true }; function ScopeSelector(props: { label: string; mode: CrmUserRoleAssignmentMutationPayload['branchScopeMode']; ids: string[]; options: Array<{ id: string; label: string; code: string }>; onModeChange: (value: CrmUserRoleAssignmentMutationPayload['branchScopeMode']) => void; onIdsChange: (value: string[]) => void; }) { return (
{props.mode === 'selected' ? (
{props.options.map((option) => { const checked = props.ids.includes(option.id); return ( ); })}
) : null}
); } export function UserRoleAssignmentsPage() { const { data } = useSuspenseQuery(crmUserRoleAssignmentsQueryOptions()); const [selectedId, setSelectedId] = useState(data.assignments[0]?.id ?? null); const [createState, setCreateState] = useState(emptyCreateState); const [editorState, setEditorState] = useState(null); const selectedAssignment = useMemo( () => data.assignments.find((assignment) => assignment.id === selectedId) ?? null, [data.assignments, selectedId] ); useEffect(() => { if (!selectedAssignment) { setEditorState(null); return; } setEditorState({ branchScopeMode: selectedAssignment.branchScopeMode, branchScopeIds: selectedAssignment.branchScopeIds, productTypeScopeMode: selectedAssignment.productTypeScopeMode, productTypeScopeIds: selectedAssignment.productTypeScopeIds, isPrimary: selectedAssignment.isPrimary, isActive: selectedAssignment.isActive }); }, [selectedAssignment]); const createMutation = useMutation({ ...createCrmUserRoleAssignmentMutation, onSuccess: () => { toast.success('CRM role assignment created successfully'); setCreateState(emptyCreateState); }, onError: (error) => toast.error( error instanceof Error ? error.message : 'Unable to create CRM role assignment' ) }); const updateMutation = useMutation({ ...updateCrmUserRoleAssignmentMutation, onSuccess: () => toast.success('CRM role assignment updated successfully'), onError: (error) => toast.error( error instanceof Error ? error.message : 'Unable to update CRM role assignment' ) }); const deleteMutation = useMutation({ ...deleteCrmUserRoleAssignmentMutation, onSuccess: () => { toast.success('CRM role assignment deleted successfully'); setSelectedId(null); }, onError: (error) => toast.error( error instanceof Error ? error.message : 'Unable to delete CRM role assignment' ) }); async function handleCreate() { if (!createState.userId || !createState.roleProfileId) { toast.error('User and role profile are required'); return; } await createMutation.mutateAsync(createState); } async function handleUpdate() { if (!selectedAssignment || !editorState) { return; } await updateMutation.mutateAsync({ id: selectedAssignment.id, payload: editorState satisfies UpdateCrmUserRoleAssignmentPayload }); } return (
Assign CRM Role One user can hold multiple CRM roles in the same organization. Primary role is for display; effective access unions across active assignments.
setCreateState({ ...createState, branchScopeMode: value, branchScopeIds: value === 'selected' ? createState.branchScopeIds : [] }) } onIdsChange={(value) => setCreateState({ ...createState, branchScopeIds: value })} /> setCreateState({ ...createState, productTypeScopeMode: value, productTypeScopeIds: value === 'selected' ? createState.productTypeScopeIds : [] }) } onIdsChange={(value) => setCreateState({ ...createState, productTypeScopeIds: value }) } />
Existing Assignments Active and historical CRM role assignments in this organization. {data.assignments.map((assignment) => ( ))} Assignment Detail Update scope, activation, and primary-role display for the selected CRM assignment. {!selectedAssignment || !editorState ? (
Select an assignment to edit.
) : ( <>
User
{selectedAssignment.userName}
{selectedAssignment.userEmail}
Role Profile
{selectedAssignment.roleProfileName}
{selectedAssignment.roleProfileCode}
setEditorState({ ...editorState, branchScopeMode: value, branchScopeIds: value === 'selected' ? editorState.branchScopeIds : [] }) } onIdsChange={(value) => setEditorState({ ...editorState, branchScopeIds: value }) } /> setEditorState({ ...editorState, productTypeScopeMode: value, productTypeScopeIds: value === 'selected' ? editorState.productTypeScopeIds : [] }) } onIdsChange={(value) => setEditorState({ ...editorState, productTypeScopeIds: value }) } />
)}
); }