diff --git a/ondeck/prisma/schema.prisma b/ondeck/prisma/schema.prisma index 547d158..62b6658 100644 --- a/ondeck/prisma/schema.prisma +++ b/ondeck/prisma/schema.prisma @@ -19,6 +19,9 @@ model User { email String @unique displayName String? @map("display_name") department String? + jobTitle String? @map("job_title") + photoUrl String? @map("photo_url") + office String? isActive Boolean @default(true) @map("is_active") lastLoginAt DateTime? @map("last_login_at") createdAt DateTime @default(now()) @map("created_at") @@ -286,6 +289,7 @@ model Task { createdBy String? @map("created_by") completedAt DateTime? @map("completed_at") completedBy String? @map("completed_by") + notes String? @db.Text naReason String? @map("na_reason") @db.Text cancelledReason String? @map("cancelled_reason") @db.Text createdAt DateTime @default(now()) @map("created_at") diff --git a/ondeck/src/app/(dashboard)/tasks/assign/page-client.tsx b/ondeck/src/app/(dashboard)/tasks/assign/page-client.tsx index e1e4612..c16c620 100644 --- a/ondeck/src/app/(dashboard)/tasks/assign/page-client.tsx +++ b/ondeck/src/app/(dashboard)/tasks/assign/page-client.tsx @@ -9,7 +9,9 @@ import { Checkbox } from '@/components/ui/checkbox' import { Select, SelectContent, + SelectGroup, SelectItem, + SelectLabel, SelectTrigger, SelectValue, } from '@/components/ui/select' @@ -21,10 +23,10 @@ import { TableHeader, TableRow, } from '@/components/ui/table' -import { Users, Filter, CheckSquare } from 'lucide-react' +import { Users, Filter, CheckSquare, Wand2, MessageSquare } from 'lucide-react' import { formatDate } from '@/lib/utils' -interface SimpleUser { id: string; displayName: string | null; email: string } +interface SimpleUser { id: string; displayName: string | null; email: string; department: string | null } interface SimpleClient { id: string; name: string } interface SimpleDesignation { id: string; name: string } @@ -50,6 +52,15 @@ const DEPT_OPTIONS = [ { value: 'OTHER', label: 'Other' }, ] +interface GenResult { + tasksCreated: number + tasksAssigned: number + clientsFound: number + groupsProcessed: number + advocateName: string | null + message?: string +} + export function BulkAssignClient({ users, clients, designations }: BulkAssignClientProps) { const [tasks, setTasks] = useState([]) const [loading, setLoading] = useState(false) @@ -57,6 +68,12 @@ export function BulkAssignClient({ users, clients, designations }: BulkAssignCli const [assignTo, setAssignTo] = useState('') const [assigning, setAssigning] = useState(false) + // Generate & assign state + const [genAdvocate, setGenAdvocate] = useState('') + const [genDesignation, setGenDesignation] = useState('') + const [generating, setGenerating] = useState(false) + const [genResult, setGenResult] = useState(null) + // Filters const [clientFilter, setClientFilter] = useState('_all') const [designationFilter, setDesignationFilter] = useState('_all') @@ -122,6 +139,63 @@ export function BulkAssignClient({ users, clients, designations }: BulkAssignCli } } + const handleGenerateAndAssign = async () => { + if (!genAdvocate || !genDesignation) return + setGenerating(true) + setGenResult(null) + try { + const res = await fetch('/api/tasks/generate-and-assign', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ advocateId: genAdvocate, designationId: genDesignation }), + }) + const data = await res.json() + if (!res.ok) throw new Error(data.error) + setGenResult(data) + if (data.tasksCreated > 0) { + toast.success(`Generated ${data.tasksCreated} task(s) and assigned to ${data.advocateName}`) + fetchTasks() + } else if (data.clientsFound === 0) { + toast.info('No clients found with this advocate and designation') + } else { + toast.info(data.message || 'No new tasks to generate') + } + } catch (err: any) { + toast.error(err.message || 'Failed to generate tasks') + } finally { + setGenerating(false) + } + } + + const renderUserOptions = () => { + const claims = users.filter((u) => u.department?.toLowerCase().includes('claims')) + const others = users.filter((u) => !u.department?.toLowerCase().includes('claims')) + return ( + <> + {claims.length > 0 && ( + + Claims + {claims.map((u) => ( + + {u.displayName || u.email} + + ))} + + )} + {others.length > 0 && ( + + All Staff + {others.map((u) => ( + + {u.displayName || u.email} + + ))} + + )} + + ) + } + const statusColor: Record = { NOT_STARTED: 'secondary', IN_PROGRESS: 'default', @@ -134,11 +208,63 @@ export function BulkAssignClient({ users, clients, designations }: BulkAssignCli

- Bulk Task Assignment + Tasks

-

Filter tasks and assign them to a team member

+

Generate and assign tasks to claims advocates

+ {/* Generate & Assign card */} + + + + + Generate & Assign Tasks + + + +
+
+

Claims Advocate

+ +
+
+

Designation

+ +
+ +
+ {genResult && ( +

+ {genResult.tasksCreated > 0 + ? `Created ${genResult.tasksCreated} task(s) across ${genResult.clientsFound} client(s) and assigned to ${genResult.advocateName}.` + : genResult.clientsFound === 0 + ? `No clients found assigned to this advocate with that designation.` + : genResult.message || 'No new tasks to generate — all tasks may already exist.'} +

+ )} +
+
+ {/* Filter bar */} @@ -197,11 +323,7 @@ export function BulkAssignClient({ users, clients, designations }: BulkAssignCli Select user - {users.map((u) => ( - - {u.displayName || u.email} - - ))} + {renderUserOptions()} + + + + + {/* Note panel */} + {noteOpen && ( +
+