Fix Manager tab KPIs and workload metrics

- setupQueueCount: add policies: { some: {} } filter (match setup-queue API)
- recentTasks: scope to Shape clients, order by updatedAt not createdAt
- Workload API: scope all metrics to Shape clients only
- Workload API: filter tasks by task.department not assignee department
- Workload API: exclude NA/CANCELLED from totalTasks and completion rate denominator
- Workload API: scope userAssignments filter to match department/client scope
This commit is contained in:
lorentz 2026-04-13 22:44:50 +00:00
parent c40dd68360
commit 5934ff7c4f
2 changed files with 29 additions and 23 deletions

View file

@ -25,6 +25,7 @@ export default async function ManagerPage() {
prisma.client.count({
where: {
designation: { name: { in: ['Shape', 'Shape 2'] } },
policies: { some: {} },
OR: [
{ claimsAdvocateId: null },
{ setupCompletedAt: null },
@ -70,26 +71,20 @@ export default async function ManagerPage() {
orderBy: [{ department: 'asc' }, { displayName: 'asc' }],
})
// Fetch recent tasks across the team
// Fetch recent tasks across the team — Shape clients, recently updated/completed
const recentTasks = await prisma.task.findMany({
take: 10,
orderBy: { createdAt: 'desc' },
include: {
client: {
select: {
name: true,
}
where: {
status: { in: ['COMPLETED', 'IN_PROGRESS', 'NOT_STARTED'] },
client: { designation: { name: { in: ['Shape', 'Shape 2'] } } },
},
assignments: {
orderBy: { updatedAt: 'desc' },
include: {
user: {
select: {
displayName: true,
}
}
}
}
}
client: { select: { name: true } },
assignments: {
include: { user: { select: { displayName: true } } },
},
},
})
return (

View file

@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from 'next/server'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import { prisma } from '@/lib/db'
import { DepartmentType } from '@prisma/client'
export async function GET(request: NextRequest) {
try {
@ -18,10 +19,18 @@ export async function GET(request: NextRequest) {
const weekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000)
const monthAgo = new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000)
// Base task filter — scoped to assignees in the department when filtering
const deptTaskWhere = departmentFilter
? { assignments: { some: { user: { department: { equals: departmentFilter, mode: 'insensitive' as const }, isActive: true } } } }
: {}
// Shape client IDs for scoping
const shapeClients = await prisma.client.findMany({
where: { designation: { name: { in: ['Shape', 'Shape 2'] } } },
select: { id: true },
})
const shapeClientIds = shapeClients.map((c) => c.id)
// Base task filter — scoped to Shape clients only
const deptTaskWhere = {
clientId: { in: shapeClientIds },
...(departmentFilter ? { department: departmentFilter.toUpperCase() as DepartmentType } : {}),
}
// Base user filter
const deptUserWhere = departmentFilter
@ -112,6 +121,7 @@ export async function GET(request: NextRequest) {
email: true,
department: true,
taskAssignments: {
where: { task: deptTaskWhere },
include: {
task: {
select: {
@ -149,12 +159,12 @@ export async function GET(request: NextRequest) {
},
}),
// Total tasks
prisma.task.count({ where: deptTaskWhere }),
prisma.task.count({ where: { ...deptTaskWhere, status: { notIn: ['NA', 'CANCELLED'] } } }),
// Active users with task assignments
prisma.user.count({
where: {
...deptUserWhere,
taskAssignments: { some: {} },
taskAssignments: { some: { task: deptTaskWhere } },
},
}),
])
@ -192,13 +202,14 @@ export async function GET(request: NextRequest) {
// Sort users by active tasks (highest workload first)
userMetrics.sort((a, b) => b.activeTasks - a.activeTasks)
// Calculate summary metrics
// Calculate summary metrics (exclude NA/CANCELLED from all rate calculations)
const totalActive = tasksByStatus
.filter((s) => !['COMPLETED', 'CANCELLED', 'NA'].includes(s.status))
.reduce((sum, s) => sum + s._count.id, 0)
const totalCompleted = tasksByStatus.find((s) => s.status === 'COMPLETED')?._count.id || 0
// totalTasks already excludes NA/CANCELLED (see query above)
const completionRate = totalTasks > 0 ? Math.round((totalCompleted / totalTasks) * 100) : 0
// Calculate workload distribution