feat: app completa recordaLexia (fases 1-5)
App web familiar de rutinas visuales para niños con TDAH: muestra cada día el material del cole y las rutinas de tarde, con gamificación por monedas y tienda de recompensas. Multi-niño y bilingüe ES/CA. Uso doméstico/homelab. Backend (Spring Boot 3.5 / Java 21 / Gradle): - Dominio por capas, PostgreSQL + Liquibase, datos semilla. - API REST con DTOs: /today, toggle con monedas y bonos de bloque/día, monedero, tienda/canje, ajustes y CRUD del panel de padres. - Seguridad ligera por PIN (BCrypt + sesion en memoria), sin Keycloak. - Tests JUnit: generacion del dia, monedas/bonos con reversion, canje, seguridad. Frontend (Angular 19, standalone + signals): - Perfiles, Home (Tablero y Foco), Tienda y panel de padres (5 pestañas). - Tipografia OpenDyslexic conmutable (accesibilidad), i18n ES/CA, TTS y sonido. - Tokens de diseño fieles al handoff (paleta, animaciones, monedas voladoras). Empaquetado: - Docker multi-stage + docker-compose (PostgreSQL + backend + Nginx). - Decisiones de arquitectura documentadas en docs/adr.
This commit is contained in:
256
frontend/src/app/core/models.ts
Normal file
256
frontend/src/app/core/models.ts
Normal file
@@ -0,0 +1,256 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
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;
|
||||
}
|
||||
|
||||
// ----- 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;
|
||||
}
|
||||
Reference in New Issue
Block a user