feat(overdracht): E0 + E1 - Database setup en API nursing logs

Epic 0 - Database Setup:
- nursing_logs tabel met indexes en constraints
- RLS policies (SELECT/INSERT/UPDATE/DELETE)
- TypeScript types gegenereerd

Epic 1 - API Nursing Logs:
- GET/POST /api/nursing-logs (lijst + aanmaken)
- PATCH/DELETE /api/nursing-logs/[id] (bewerken + verwijderen)
- Zod validatie schemas
- Automatische shift_date berekening

Documentatie:
- PRD, FO, TO en Bouwplan voor Overdracht Dashboard

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
colinislit
2025-12-06 00:03:18 +01:00
parent ac98070fe4
commit 08cffd0245
9 changed files with 2638 additions and 0 deletions

View File

@@ -129,6 +129,7 @@ export type Database = {
based_on_examinations: string[] | null
based_on_intake_id: string | null
based_on_risk_assessments: string[] | null
behandelstructuur: Json | null
care_team_ids: string[] | null
category_code: string | null
category_display: string | null
@@ -137,6 +138,7 @@ export type Database = {
created_date: string | null
description: string | null
encounter_id: string | null
evaluatiemomenten: Json | null
goals: Json | null
id: string
identifier: string | null
@@ -145,9 +147,13 @@ export type Database = {
patient_id: string
period_end: string | null
period_start: string | null
published_at: string | null
sessie_planning: Json | null
status: Database["public"]["Enums"]["careplan_status"]
title: string
updated_at: string | null
veiligheidsplan: Json | null
version: number | null
}
Insert: {
activities?: Json | null
@@ -157,6 +163,7 @@ export type Database = {
based_on_examinations?: string[] | null
based_on_intake_id?: string | null
based_on_risk_assessments?: string[] | null
behandelstructuur?: Json | null
care_team_ids?: string[] | null
category_code?: string | null
category_display?: string | null
@@ -165,6 +172,7 @@ export type Database = {
created_date?: string | null
description?: string | null
encounter_id?: string | null
evaluatiemomenten?: Json | null
goals?: Json | null
id?: string
identifier?: string | null
@@ -173,9 +181,13 @@ export type Database = {
patient_id: string
period_end?: string | null
period_start?: string | null
published_at?: string | null
sessie_planning?: Json | null
status?: Database["public"]["Enums"]["careplan_status"]
title: string
updated_at?: string | null
veiligheidsplan?: Json | null
version?: number | null
}
Update: {
activities?: Json | null
@@ -185,6 +197,7 @@ export type Database = {
based_on_examinations?: string[] | null
based_on_intake_id?: string | null
based_on_risk_assessments?: string[] | null
behandelstructuur?: Json | null
care_team_ids?: string[] | null
category_code?: string | null
category_display?: string | null
@@ -193,6 +206,7 @@ export type Database = {
created_date?: string | null
description?: string | null
encounter_id?: string | null
evaluatiemomenten?: Json | null
goals?: Json | null
id?: string
identifier?: string | null
@@ -201,9 +215,13 @@ export type Database = {
patient_id?: string
period_end?: string | null
period_start?: string | null
published_at?: string | null
sessie_planning?: Json | null
status?: Database["public"]["Enums"]["careplan_status"]
title?: string
updated_at?: string | null
veiligheidsplan?: Json | null
version?: number | null
}
Relationships: [
{
@@ -765,6 +783,53 @@ export type Database = {
}
Relationships: []
}
nursing_logs: {
Row: {
category: string
content: string
created_at: string
created_by: string
id: string
include_in_handover: boolean
patient_id: string
shift_date: string
timestamp: string
updated_at: string
}
Insert: {
category: string
content: string
created_at?: string
created_by: string
id?: string
include_in_handover?: boolean
patient_id: string
shift_date: string
timestamp?: string
updated_at?: string
}
Update: {
category?: string
content?: string
created_at?: string
created_by?: string
id?: string
include_in_handover?: boolean
patient_id?: string
shift_date?: string
timestamp?: string
updated_at?: string
}
Relationships: [
{
foreignKeyName: "nursing_logs_patient_id_fkey"
columns: ["patient_id"]
isOneToOne: false
referencedRelation: "patients"
referencedColumns: ["id"]
},
]
}
observations: {
Row: {
body_site: string | null

114
lib/types/nursing-log.ts Normal file
View File

@@ -0,0 +1,114 @@
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];
}