- Fix all TypeScript compilation errors (0 errors in src/) - Add try/catch error handling to ALL API routes (38 handlers) - Fix empty catch blocks (api-auth.ts now logs warnings) - Add aria-labels to all icon-only buttons (WCAG 2.1 AA) - Fix Prisma type mismatches (OR filter, Person.companyId, Estimate.projectId, Ticket.createdAt) - Fix webhook PATCH route (moved to [id]/route.ts) - Fix mobile-bottom-nav type safety - Fix KB route where-clause type - Fix test-mail banner null vs undefined - Fix task comment fetch: add cancellation + error toast - ESLint: 0 errors, 0 warnings - 175 files, 24.741 lines of code
41 lines
1.7 KiB
TypeScript
Executable File
41 lines
1.7 KiB
TypeScript
Executable File
import { NextResponse } from 'next/server'
|
|
import { db } from '@/lib/db'
|
|
|
|
export const dynamic = 'force-dynamic'
|
|
|
|
// GET /api/aos/contracts — contracts list with company, expiry stats
|
|
export async function GET() {
|
|
try {
|
|
const contracts = await db.contract.findMany({
|
|
orderBy: { updatedAt: 'desc' },
|
|
})
|
|
|
|
// enrich with company names (separate query to keep SQLite happy)
|
|
const companyIds = [...new Set(contracts.map((c) => c.companyId))]
|
|
const companies = await db.company.findMany({ where: { id: { in: companyIds } }, select: { id: true, name: true } })
|
|
const companyMap = new Map(companies.map((c) => [c.id, c.name]))
|
|
|
|
const enriched = contracts.map((c) => ({ ...c, companyName: companyMap.get(c.companyId) ?? '—' }))
|
|
|
|
const stats = {
|
|
total: contracts.length,
|
|
active: contracts.filter((c) => c.status === 'active').length,
|
|
draft: contracts.filter((c) => c.status === 'draft').length,
|
|
sent: contracts.filter((c) => c.status === 'sent').length,
|
|
signed: contracts.filter((c) => c.status === 'signed' || c.status === 'active').length,
|
|
expired: contracts.filter((c) => c.status === 'expired').length,
|
|
expiringSoon: contracts.filter((c) => {
|
|
if (!c.endDate || c.status === 'expired') return false
|
|
const days = (c.endDate.getTime() - Date.now()) / 86400000
|
|
return days <= 30 && days >= 0
|
|
}).length,
|
|
totalValueCents: contracts.filter((c) => c.status === 'active').reduce((s, c) => s + c.valueCents, 0),
|
|
}
|
|
|
|
return NextResponse.json({ contracts: enriched, stats })
|
|
} catch (err) {
|
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
|
return NextResponse.json({ error: msg }, { status: 500 })
|
|
}
|
|
}
|