feat(#132): création enfant staff (onglet Enfants) — front + back.

Squash depuis develop : POST /enfants staff + parent_user_id, photo
multipart, modale création + sélection famille, fixes UX/birth_date.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-17 19:00:12 +02:00
co-authored by Cursor
parent 3c7f4f6e16
commit 04f49cb62f
12 changed files with 1177 additions and 118 deletions
@@ -1,4 +1,5 @@
import { ApiProperty } from '@nestjs/swagger';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import {
IsBoolean,
IsDateString,
@@ -6,11 +7,23 @@ import {
IsNotEmpty,
IsOptional,
IsString,
IsUUID,
MaxLength,
ValidateIf,
} from 'class-validator';
import { GenreType, StatutEnfantType } from 'src/entities/children.entity';
/** Multipart envoie des strings ("true"/"false") — JSON envoie déjà des booleans. */
function toBoolean({ value }: { value: unknown }): boolean | unknown {
if (typeof value === 'boolean') return value;
if (typeof value === 'string') {
const v = value.trim().toLowerCase();
if (v === 'true' || v === '1') return true;
if (v === 'false' || v === '0' || v === '') return false;
}
return value;
}
export class CreateEnfantsDto {
@ApiProperty({ enum: StatutEnfantType, example: StatutEnfantType.SANS_GARDE })
@IsEnum(StatutEnfantType)
@@ -52,6 +65,7 @@ export class CreateEnfantsDto {
photo_url?: string;
@ApiProperty({ default: false })
@Transform(toBoolean)
@IsBoolean()
consent_photo: boolean;
@@ -61,6 +75,20 @@ export class CreateEnfantsDto {
consent_photo_at?: string;
@ApiProperty({ default: false })
@Transform(toBoolean)
@IsBoolean()
is_multiple: boolean;
/**
* Parent pivot du foyer — obligatoire pour staff (gestionnaire/admin).
* Ignoré / interdit en externe pour un PARENT (ticket #132).
*/
@ApiPropertyOptional({
description:
'UUID du parent pivot (staff only). Obligatoire pour GESTIONNAIRE / ADMIN / SUPER_ADMIN.',
format: 'uuid',
})
@IsOptional()
@IsUUID('4')
parent_user_id?: string;
}