Files
recordalexia/frontend/src/app/core/models.ts
Jaume Garriga Maestre 24a0c8a0dd feat: cuentas de familia (multi-tenant), registro/login y preferencias
Convierte recordaLexia de una sola familia a multi-familia, con cuentas
propias y persistencia de preferencias.

Backend:
- Tenant Family (email único + contraseña BCrypt + PIN + prefs de cuenta);
  family_id en child/activity/material_item/reward; aislamiento por familia
  (acceso cruzado responde 404).
- Auth propia (sin Keycloak): registro/login email+contraseña, sesiones de
  familia persistidas en BD (sobreviven a reinicios), panel de padres tras PIN.
- Liquibase 002-multitenant; seeder crea una familia demo.
- Tests de aislamiento entre familias, registro/login y gate del panel.

Frontend:
- Login, registro y pantalla de cuenta; guards (sesion + PIN) e interceptor
  de sesion global; perfiles scopeados a la familia.

Preferencias:
- OpenDyslexic persistida por nino (child.dyslexiaFont) y default de cuenta.

Decisiones en docs/adr/0004.
2026-06-21 13:11:34 +02:00

268 lines
5.1 KiB
TypeScript

// Modelos TypeScript alineados con los DTOs del backend (es.asepeyo.recordalexia.web.dto).
// Mantener en sincronía con el backend, en especial TodayResponse.
export type ViewMode = 'BOARD' | 'FOCUS';
export type Language = 'ES' | 'CA';
/** Resumen de perfil para la pantalla de selección. */
export interface ChildSummary {
id: number;
name: string;
mascot: string;
accentColor: string;
age: number;
coins: number;
viewMode: ViewMode;
language: Language;
}
/** Datos del niño embebidos en /today. */
export interface ChildInfo {
id: number;
name: string;
mascot: string;
accentColor: string;
viewMode: ViewMode;
language: Language;
soundEnabled: boolean;
ttsEnabled: boolean;
dyslexiaFont: boolean;
}
/** Tarea del día (mañana o tarde). Lleva texto ES y CA. */
export interface TaskView {
id: number;
labelEs: string;
labelCa: string;
icon: string;
color: string;
done: boolean;
coinsReward: number;
orderIndex: number;
}
/** Evento del día (examen/deberes) para el banner. */
export interface EventView {
id: number;
type: 'EXAM' | 'HOMEWORK';
titleEs: string;
titleCa: string;
icon: string;
color: string;
}
export interface ProgressView {
morningDone: number;
morningTotal: number;
afternoonDone: number;
afternoonTotal: number;
totalDone: number;
total: number;
}
export interface WalletInfo {
coins: number;
}
export interface TimerInfo {
departureTime: string | null;
minutesUntilDeparture: number | null;
}
/** Payload completo de GET /api/children/{id}/today. */
export interface TodayResponse {
child: ChildInfo;
morning: TaskView[];
afternoon: TaskView[];
specialEvents: EventView[];
progress: ProgressView;
wallet: WalletInfo;
timer: TimerInfo;
}
/** Resultado de marcar/desmarcar una tarea. */
export interface ToggleResult {
taskId: number;
done: boolean;
coinsEarned: number;
newBalance: number;
progress: ProgressView;
}
/** Ajustes editables del niño (todos opcionales). */
export interface SettingsRequest {
viewMode?: ViewMode;
soundEnabled?: boolean;
ttsEnabled?: boolean;
language?: Language;
dyslexiaFont?: boolean;
departureTime?: string;
}
/** Premio visible en la tienda (Fase 5). */
export interface RewardView {
id: number;
labelEs: string;
labelCa: string;
icon: string;
color: string;
cost: number;
affordable: boolean;
missing: number;
}
export interface RedeemResult {
rewardId: number;
cost: number;
newBalance: number;
}
// ----- Panel de padres: vistas de lectura -----
export interface RewardAdminView {
id: number;
labelEs: string;
labelCa: string;
icon: string;
color: string;
cost: number;
active: boolean;
}
export interface MaterialView {
id: number;
labelEs: string;
labelCa: string;
icon: string;
color: string;
category: string | null;
}
export interface ActivityView {
id: number;
labelEs: string;
labelCa: string;
icon: string;
color: string;
materialIds: number[];
}
export interface WeeklyEntryView {
id: number;
childId: number;
dayOfWeek: string;
activityId: number;
activityLabelEs: string;
icon: string;
color: string;
orderIndex: number;
coinsReward: number | null;
}
export interface RoutineView {
id: number;
childId: number;
dayOfWeek: string;
labelEs: string;
labelCa: string;
icon: string;
color: string;
orderIndex: number;
coinsReward: number | null;
}
export interface EventAdminView {
id: number;
childId: number;
date: string;
type: 'EXAM' | 'HOMEWORK';
titleEs: string;
titleCa: string;
icon: string;
color: string;
}
export interface GamificationView {
coinsPerTask: number;
coinsPerBlock: number;
coinsPerDay: number;
}
// ----- Auth / cuenta de familia -----
export interface MeResponse {
familyId: number;
email: string;
name: string;
uiLanguage: string;
defaultDyslexiaFont: boolean;
}
// ----- Panel de padres: peticiones -----
export interface ChildRequest {
name?: string;
mascot?: string;
accentColor?: string;
age?: number;
departureTime?: string;
coins?: number;
}
export interface GamificationRequest {
coinsPerTask?: number;
coinsPerBlock?: number;
coinsPerDay?: number;
}
export interface RewardRequest {
labelEs: string;
labelCa: string;
icon: string;
color: string;
cost: number;
active?: boolean;
}
export interface MaterialRequest {
labelEs: string;
labelCa: string;
icon: string;
color: string;
category?: string;
}
export interface ActivityRequest {
labelEs: string;
labelCa: string;
icon: string;
color: string;
materialIds: number[];
}
export interface WeeklyEntryRequest {
childId: number;
dayOfWeek: string;
activityId: number;
orderIndex?: number;
coinsReward?: number;
}
export interface AfternoonRoutineRequest {
childId: number;
dayOfWeek: string;
labelEs: string;
labelCa: string;
icon: string;
color: string;
orderIndex?: number;
coinsReward?: number;
}
export interface SpecialEventRequest {
childId: number;
date: string;
type: 'EXAM' | 'HOMEWORK';
titleEs: string;
titleCa: string;
icon: string;
color: string;
}