feat(verpleegrapportage): Nieuwe module + opruiming codebase
Verpleegrapportage module: - Nieuwe /epd/verpleegrapportage met patiëntenoverzicht - Rapportage invoer workspace met timeline view - Overdracht overzicht met AI-samenvatting - API endpoints voor verpleegrapportage data Opruiming: - Oude /epd/overdracht en /epd/dagregistratie verwijderd (vervangen) - Oude /api/nursing-logs verwijderd (geconsolideerd naar reports) - Verouderde design docs en reports verwijderd - Fonts verplaatst van docs/ naar public/fonts/ Bugfixes: - Risk-manager: fix constraint violation (db values vs display labels) - Overdracht API: filter op rapportages i.p.v. encounters Database: - Migratie voor consolidatie nursing_logs naar reports tabel 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,114 +0,0 @@
|
||||
import { z } from 'zod';
|
||||
import type { Database } from '@/lib/supabase/database.types';
|
||||
|
||||
// Database types
|
||||
export type NursingLog = Database['public']['Tables']['nursing_logs']['Row'];
|
||||
export type NursingLogInsert = Database['public']['Tables']['nursing_logs']['Insert'];
|
||||
export type NursingLogUpdate = Database['public']['Tables']['nursing_logs']['Update'];
|
||||
|
||||
// Category enum
|
||||
export const NURSING_LOG_CATEGORIES = [
|
||||
'medicatie',
|
||||
'adl',
|
||||
'gedrag',
|
||||
'incident',
|
||||
'observatie',
|
||||
] as const;
|
||||
|
||||
export type NursingLogCategory = (typeof NURSING_LOG_CATEGORIES)[number];
|
||||
|
||||
// Zod schemas for validation
|
||||
export const NursingLogCategorySchema = z.enum(NURSING_LOG_CATEGORIES);
|
||||
|
||||
export const CreateNursingLogSchema = z.object({
|
||||
patient_id: z.string().uuid('Patient ID moet een geldige UUID zijn'),
|
||||
category: NursingLogCategorySchema,
|
||||
content: z
|
||||
.string()
|
||||
.min(1, 'Notitie mag niet leeg zijn')
|
||||
.max(500, 'Notitie mag maximaal 500 karakters bevatten'),
|
||||
timestamp: z.string().datetime().optional(),
|
||||
include_in_handover: z.boolean().default(false),
|
||||
});
|
||||
|
||||
export type CreateNursingLogInput = z.infer<typeof CreateNursingLogSchema>;
|
||||
|
||||
export const UpdateNursingLogSchema = z.object({
|
||||
category: NursingLogCategorySchema.optional(),
|
||||
content: z
|
||||
.string()
|
||||
.min(1, 'Notitie mag niet leeg zijn')
|
||||
.max(500, 'Notitie mag maximaal 500 karakters bevatten')
|
||||
.optional(),
|
||||
timestamp: z.string().datetime().optional(),
|
||||
include_in_handover: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type UpdateNursingLogInput = z.infer<typeof UpdateNursingLogSchema>;
|
||||
|
||||
// Response types
|
||||
export interface NursingLogListResponse {
|
||||
logs: NursingLog[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
// Category display configuration
|
||||
export const CATEGORY_CONFIG: Record<
|
||||
NursingLogCategory,
|
||||
{
|
||||
label: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
bgColor: string;
|
||||
textColor: string;
|
||||
}
|
||||
> = {
|
||||
medicatie: {
|
||||
label: 'Medicatie',
|
||||
icon: 'Pill',
|
||||
color: 'blue',
|
||||
bgColor: 'bg-blue-100',
|
||||
textColor: 'text-blue-700',
|
||||
},
|
||||
adl: {
|
||||
label: 'ADL/verzorging',
|
||||
icon: 'Utensils',
|
||||
color: 'green',
|
||||
bgColor: 'bg-green-100',
|
||||
textColor: 'text-green-700',
|
||||
},
|
||||
gedrag: {
|
||||
label: 'Gedragsobservatie',
|
||||
icon: 'User',
|
||||
color: 'purple',
|
||||
bgColor: 'bg-purple-100',
|
||||
textColor: 'text-purple-700',
|
||||
},
|
||||
incident: {
|
||||
label: 'Incident',
|
||||
icon: 'AlertTriangle',
|
||||
color: 'red',
|
||||
bgColor: 'bg-red-100',
|
||||
textColor: 'text-red-700',
|
||||
},
|
||||
observatie: {
|
||||
label: 'Algemene observatie',
|
||||
icon: 'FileText',
|
||||
color: 'gray',
|
||||
bgColor: 'bg-gray-100',
|
||||
textColor: 'text-gray-700',
|
||||
},
|
||||
};
|
||||
|
||||
// Helper function to calculate shift_date from timestamp
|
||||
export function calculateShiftDate(timestamp: Date | string): string {
|
||||
const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
|
||||
const hours = date.getHours();
|
||||
|
||||
// Night shift (before 7:00) belongs to previous day
|
||||
if (hours < 7) {
|
||||
date.setDate(date.getDate() - 1);
|
||||
}
|
||||
|
||||
return date.toISOString().split('T')[0];
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { z } from 'zod';
|
||||
import type { NursingLog } from './nursing-log';
|
||||
import type { Json } from '@/lib/supabase/database.types';
|
||||
|
||||
// Patient overview for list view
|
||||
export interface PatientOverzicht {
|
||||
@@ -34,7 +34,6 @@ export interface PatientDetail {
|
||||
};
|
||||
vitals: VitalSign[];
|
||||
reports: Report[];
|
||||
nursingLogs: NursingLog[];
|
||||
risks: RiskAssessment[];
|
||||
conditions: Condition[];
|
||||
}
|
||||
@@ -49,13 +48,16 @@ export interface VitalSign {
|
||||
effective_datetime: string;
|
||||
}
|
||||
|
||||
// Report (rapportage)
|
||||
// Report (rapportage) - now includes verpleegkundig type (was nursing_logs)
|
||||
export interface Report {
|
||||
id: string;
|
||||
type: string;
|
||||
content: string;
|
||||
created_at: string;
|
||||
created_by: string | null;
|
||||
structured_data?: Json | null; // Contains category for verpleegkundig
|
||||
include_in_handover?: boolean | null;
|
||||
shift_date?: string | null;
|
||||
}
|
||||
|
||||
// Risk assessment
|
||||
@@ -88,7 +90,7 @@ export interface Aandachtspunt {
|
||||
tekst: string;
|
||||
urgent: boolean;
|
||||
bron: {
|
||||
type: 'observatie' | 'rapportage' | 'dagnotitie' | 'risico';
|
||||
type: 'observatie' | 'rapportage' | 'verpleegkundig' | 'risico';
|
||||
id: string;
|
||||
datum: string;
|
||||
label: string;
|
||||
@@ -98,6 +100,7 @@ export interface Aandachtspunt {
|
||||
// Zod schema for generate request
|
||||
export const GenerateOverdrachtSchema = z.object({
|
||||
patientId: z.string().uuid('Patient ID moet een geldige UUID zijn'),
|
||||
period: z.enum(['1d', '3d', '7d', '14d']).optional().default('1d'),
|
||||
});
|
||||
|
||||
export type GenerateOverdrachtInput = z.infer<typeof GenerateOverdrachtSchema>;
|
||||
|
||||
@@ -15,9 +15,79 @@ export const REPORT_TYPES = [
|
||||
'intake',
|
||||
'behandeladvies',
|
||||
'vrije_notitie',
|
||||
'verpleegkundig', // Korte verpleegkundige notities (was nursing_logs)
|
||||
] as const;
|
||||
export type ReportType = (typeof REPORT_TYPES)[number];
|
||||
|
||||
// Types die getoond worden in het verpleegkundig overzicht
|
||||
export const VERPLEEG_REPORT_TYPES = [
|
||||
'verpleegkundig',
|
||||
'observatie',
|
||||
'incident',
|
||||
'medicatie',
|
||||
'crisis',
|
||||
] as const;
|
||||
export type VerpleegReportType = (typeof VERPLEEG_REPORT_TYPES)[number];
|
||||
|
||||
// Categorieën voor verpleegkundige notities (in structured_data.category)
|
||||
export const VERPLEEGKUNDIG_CATEGORIES = [
|
||||
'medicatie',
|
||||
'adl',
|
||||
'gedrag',
|
||||
'incident',
|
||||
'observatie',
|
||||
] as const;
|
||||
export type VerpleegkundigCategory = (typeof VERPLEEGKUNDIG_CATEGORIES)[number];
|
||||
|
||||
// Category display configuration voor verpleegkundige notities
|
||||
export const CATEGORY_CONFIG: Record<
|
||||
VerpleegkundigCategory,
|
||||
{
|
||||
label: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
bgColor: string;
|
||||
textColor: string;
|
||||
}
|
||||
> = {
|
||||
medicatie: {
|
||||
label: 'Medicatie',
|
||||
icon: 'Pill',
|
||||
color: 'blue',
|
||||
bgColor: 'bg-blue-100',
|
||||
textColor: 'text-blue-700',
|
||||
},
|
||||
adl: {
|
||||
label: 'ADL/verzorging',
|
||||
icon: 'Utensils',
|
||||
color: 'green',
|
||||
bgColor: 'bg-green-100',
|
||||
textColor: 'text-green-700',
|
||||
},
|
||||
gedrag: {
|
||||
label: 'Gedragsobservatie',
|
||||
icon: 'User',
|
||||
color: 'purple',
|
||||
bgColor: 'bg-purple-100',
|
||||
textColor: 'text-purple-700',
|
||||
},
|
||||
incident: {
|
||||
label: 'Incident',
|
||||
icon: 'AlertTriangle',
|
||||
color: 'red',
|
||||
bgColor: 'bg-red-100',
|
||||
textColor: 'text-red-700',
|
||||
},
|
||||
observatie: {
|
||||
label: 'Algemene observatie',
|
||||
icon: 'FileText',
|
||||
color: 'gray',
|
||||
bgColor: 'bg-gray-100',
|
||||
textColor: 'text-gray-700',
|
||||
},
|
||||
};
|
||||
|
||||
// Schema voor standaard rapportages (20-5000 karakters)
|
||||
export const CreateReportSchema = z.object({
|
||||
patient_id: z.string().uuid('Patient ID moet een geldige UUID zijn'),
|
||||
type: z.enum(REPORT_TYPES),
|
||||
@@ -33,6 +103,33 @@ export const CreateReportSchema = z.object({
|
||||
|
||||
export type CreateReportInput = z.infer<typeof CreateReportSchema>;
|
||||
|
||||
// Schema voor verpleegkundige notities (1-500 karakters, met category)
|
||||
export const CreateVerpleegkundigSchema = z.object({
|
||||
patient_id: z.string().uuid('Patient ID moet een geldige UUID zijn'),
|
||||
type: z.literal('verpleegkundig'),
|
||||
content: z
|
||||
.string()
|
||||
.min(1, 'Notitie mag niet leeg zijn')
|
||||
.max(500, 'Notitie mag maximaal 500 karakters bevatten'),
|
||||
category: z.enum(VERPLEEGKUNDIG_CATEGORIES),
|
||||
include_in_handover: z.boolean().default(false),
|
||||
});
|
||||
|
||||
export type CreateVerpleegkundigInput = z.infer<typeof CreateVerpleegkundigSchema>;
|
||||
|
||||
// Update schema voor verpleegkundige notities
|
||||
export const UpdateVerpleegkundigSchema = z.object({
|
||||
content: z
|
||||
.string()
|
||||
.min(1, 'Notitie mag niet leeg zijn')
|
||||
.max(500, 'Notitie mag maximaal 500 karakters bevatten')
|
||||
.optional(),
|
||||
category: z.enum(VERPLEEGKUNDIG_CATEGORIES).optional(),
|
||||
include_in_handover: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type UpdateVerpleegkundigInput = z.infer<typeof UpdateVerpleegkundigSchema>;
|
||||
|
||||
export interface ClassificationResult {
|
||||
type: ReportType;
|
||||
confidence: number;
|
||||
@@ -43,3 +140,29 @@ export interface ReportListResponse {
|
||||
reports: Report[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
// Helper function to calculate shift_date from timestamp
|
||||
// Night shift (before 7:00) belongs to previous day
|
||||
export function calculateShiftDate(timestamp: Date | string): string {
|
||||
const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
|
||||
const hours = date.getHours();
|
||||
|
||||
// Night shift (before 7:00) belongs to previous day
|
||||
if (hours < 7) {
|
||||
date.setDate(date.getDate() - 1);
|
||||
}
|
||||
|
||||
return date.toISOString().split('T')[0];
|
||||
}
|
||||
|
||||
// Helper to extract category from structured_data
|
||||
export function getVerpleegkundigCategory(
|
||||
structuredData: Report['structured_data'] | undefined | null
|
||||
): VerpleegkundigCategory | null {
|
||||
if (!structuredData || typeof structuredData !== 'object') return null;
|
||||
const data = structuredData as { category?: string };
|
||||
if (data.category && VERPLEEGKUNDIG_CATEGORIES.includes(data.category as VerpleegkundigCategory)) {
|
||||
return data.category as VerpleegkundigCategory;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user