diff --git a/.claude/settings.local.json b/.claude/settings.local.json index b17be45..0d37522 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -4,7 +4,13 @@ "Bash(ssh-keygen:*)", "Bash(chmod:*)", "Bash(git init:*)", - "Bash(git add:*)" + "Bash(git add:*)", + "Bash(git rm:*)", + "Bash(git branch:*)", + "Bash(git remote add:*)", + "Bash(git commit:*)", + "Bash(git config:*)", + "Bash(git push:*)" ] } } diff --git a/dev/Horizon_NewFeatures.md b/dev/Horizon_NewFeatures.md new file mode 100644 index 0000000..a5ed975 --- /dev/null +++ b/dev/Horizon_NewFeatures.md @@ -0,0 +1,51 @@ +# Horizon + +This is a web application that syncs insurance policy data from an insurance brokerage's line of business system to a local database (postgres) and then allows for additional functionality: + +- Client Filtering + + - Designation + + - Claims Assignment + + - AE + +- Policy Grouping + + - Groups don't cross clients, they are meant to align work tasks in an efficient manner. For example pulling a clients credit report is a per client task not a per policy + + - + +- Task Assignment + + - Policies may need to retain individual tasks even if they are a member group. + + - Tasks should be able to be assigned to a policy group or individual policy + + - Tasks should be automatically assigned based on a date trigger: Group Date, or Policy Expiration Date + + - Tasks should only be assigned automatically after a policy exists in the system for 20 days + + - There should be a manual assignment in the ui that let's users assign tasks en masse using filters (policies for client A, new policies with no assignment, or just manual checkbox selection of multiple policies) + +- Logging + + - Authentication + + - Task Activities + + - Assignment + + - Changes + + - Removal + + - Completion + + - User Activities + + - Creation / Deletion + + - Role Change (Admin/Manager/Advocate) + + diff --git a/ondeck/prisma/migrations/20260325112534_add_user_photo_title_office/migration.sql b/ondeck/prisma/migrations/20260325112534_add_user_photo_title_office/migration.sql new file mode 100644 index 0000000..e9dda49 --- /dev/null +++ b/ondeck/prisma/migrations/20260325112534_add_user_photo_title_office/migration.sql @@ -0,0 +1,4 @@ +-- AlterTable +ALTER TABLE "users" ADD COLUMN "job_title" TEXT, +ADD COLUMN "office" TEXT, +ADD COLUMN "photo_url" TEXT; diff --git a/ondeck/prisma/schema.prisma b/ondeck/prisma/schema.prisma index 62b6658..89b8688 100644 --- a/ondeck/prisma/schema.prisma +++ b/ondeck/prisma/schema.prisma @@ -31,6 +31,7 @@ model User { createdTasks Task[] @relation("TaskCreatedBy") completedTasks Task[] @relation("TaskCompletedBy") taskAssignments TaskAssignment[] + taskNotes TaskNote[] @relation("TaskNoteAuthor") createdTemplates TaskTemplate[] syncLogs SyncLog[] auditLogs AuditLog[] @@ -302,6 +303,7 @@ model Task { creator User? @relation("TaskCreatedBy", fields: [createdBy], references: [id]) completer User? @relation("TaskCompletedBy", fields: [completedBy], references: [id]) assignments TaskAssignment[] + taskNotes TaskNote[] @@index([clientId]) @@index([policyId]) @@ -325,6 +327,20 @@ model TaskAssignment { @@map("task_assignments") } +model TaskNote { + id String @id @default(cuid()) + taskId String @map("task_id") + userId String @map("user_id") + content String @db.Text + createdAt DateTime @default(now()) @map("created_at") + + task Task @relation(fields: [taskId], references: [id], onDelete: Cascade) + user User @relation("TaskNoteAuthor", fields: [userId], references: [id]) + + @@index([taskId]) + @@map("task_notes") +} + // ============================================ // Sync & System Management // ============================================ diff --git a/ondeck/src/app/(dashboard)/admin/users/page.tsx b/ondeck/src/app/(dashboard)/admin/users/page.tsx index dae6acb..5f02944 100644 --- a/ondeck/src/app/(dashboard)/admin/users/page.tsx +++ b/ondeck/src/app/(dashboard)/admin/users/page.tsx @@ -19,7 +19,17 @@ export default async function UsersPage() { const [users, roles] = await Promise.all([ prisma.user.findMany({ orderBy: { displayName: 'asc' }, - include: { + select: { + id: true, + email: true, + displayName: true, + department: true, + jobTitle: true, + photoUrl: true, + office: true, + isActive: true, + lastLoginAt: true, + createdAt: true, userRoles: { include: { role: true, diff --git a/ondeck/src/app/(dashboard)/manager/page.tsx b/ondeck/src/app/(dashboard)/manager/page.tsx index b1286c6..fe9b9c2 100644 --- a/ondeck/src/app/(dashboard)/manager/page.tsx +++ b/ondeck/src/app/(dashboard)/manager/page.tsx @@ -2,11 +2,7 @@ import { getServerSession } from 'next-auth' import { authOptions } from '@/lib/auth' import { redirect } from 'next/navigation' import { prisma } from '@/lib/db' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Badge } from '@/components/ui/badge' -import { Users, CheckSquare, TrendingUp, AlertCircle, Clock } from 'lucide-react' -import { WorkloadKPIs } from '@/components/dashboard/workload-kpis' -import { TeamMembersByDepartment } from '@/components/manager/team-members-by-department' +import { ManagerPageClient } from '@/components/manager/manager-page-client' export default async function ManagerPage() { const session = await getServerSession(authOptions) @@ -23,7 +19,7 @@ export default async function ManagerPage() { } // Fetch team statistics - const [totalUsers, activeUsers, totalTasks, completedTasks, overdueTasks] = await Promise.all([ + const [, activeUsers, totalTasks, completedTasks, overdueTasks] = await Promise.all([ prisma.user.count(), prisma.user.count({ where: { isActive: true } }), prisma.task.count(), @@ -95,166 +91,14 @@ export default async function ManagerPage() { } }) - const completionRate = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0 - return ( -
- Monitor team performance and task assignments -
-- Active users -
-- All team tasks -
-- {completionRate}% completion rate -
-- Require attention -
-- Active tasks -
-- No tasks created yet -
- ) : ( -- {task.client.name} -
- )} -- Assigned to: {task.assignments.map(a => a.user.displayName).join(', ')} -
- )} -