diff --git a/backend/src/main/java/es/asepeyo/recordalexia/web/ParentRoutineCatalogController.java b/backend/src/main/java/es/asepeyo/recordalexia/web/ParentRoutineCatalogController.java new file mode 100644 index 0000000..0c143ec --- /dev/null +++ b/backend/src/main/java/es/asepeyo/recordalexia/web/ParentRoutineCatalogController.java @@ -0,0 +1,85 @@ +package es.asepeyo.recordalexia.web; + +import es.asepeyo.recordalexia.domain.RoutineTask; +import es.asepeyo.recordalexia.exception.NotFoundException; +import es.asepeyo.recordalexia.repository.FamilyRepository; +import es.asepeyo.recordalexia.repository.RoutineTaskRepository; +import es.asepeyo.recordalexia.security.FamilyContext; +import es.asepeyo.recordalexia.web.dto.ParentDtos.RoutineTaskRequest; +import es.asepeyo.recordalexia.web.dto.ParentViews.RoutineTaskView; +import java.util.List; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * CRUD del catálogo de rutinas de tarde, por familia (panel de padres). Es el gemelo de + * {@link ParentCatalogController} para las actividades de mañana: aquí se define una + * rutina una sola vez y luego se asigna a días desde {@link ParentScheduleController}. + */ +@RestController +@RequestMapping("/api/parents/routine-tasks") +public class ParentRoutineCatalogController { + + private final RoutineTaskRepository routineTaskRepository; + private final FamilyRepository familyRepository; + private final FamilyContext familyContext; + + public ParentRoutineCatalogController(RoutineTaskRepository routineTaskRepository, + FamilyRepository familyRepository, + FamilyContext familyContext) { + this.routineTaskRepository = routineTaskRepository; + this.familyRepository = familyRepository; + this.familyContext = familyContext; + } + + private Long fid() { + return familyContext.currentFamilyId(); + } + + @GetMapping + public List list() { + return routineTaskRepository.findByFamilyId(fid()).stream().map(this::toView).toList(); + } + + @PostMapping + public ResponseEntity create(@RequestBody RoutineTaskRequest req) { + RoutineTask task = new RoutineTask(req.labelEs(), req.labelCa(), req.icon(), req.color()); + task.setFamily(familyRepository.getReferenceById(fid())); + task.setCoinsReward(req.coinsReward()); + return ResponseEntity.ok(toView(routineTaskRepository.save(task))); + } + + /** Editar la definición se refleja en todos los días que usan esta rutina. */ + @PutMapping("/{id}") + public ResponseEntity update(@PathVariable Long id, + @RequestBody RoutineTaskRequest req) { + RoutineTask task = routineTaskRepository.findByIdAndFamilyId(id, fid()) + .orElseThrow(() -> new NotFoundException("No existe la rutina con id " + id)); + task.setLabelEs(req.labelEs()); + task.setLabelCa(req.labelCa()); + task.setIcon(req.icon()); + task.setColor(req.color()); + task.setCoinsReward(req.coinsReward()); + return ResponseEntity.ok(toView(routineTaskRepository.save(task))); + } + + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable Long id) { + routineTaskRepository.findByIdAndFamilyId(id, fid()) + .orElseThrow(() -> new NotFoundException("No existe la rutina con id " + id)); + routineTaskRepository.deleteById(id); + return ResponseEntity.noContent().build(); + } + + private RoutineTaskView toView(RoutineTask t) { + return new RoutineTaskView(t.getId(), t.getLabelEs(), t.getLabelCa(), t.getIcon(), + t.getColor(), t.getCoinsReward()); + } +} diff --git a/backend/src/main/java/es/asepeyo/recordalexia/web/ParentScheduleController.java b/backend/src/main/java/es/asepeyo/recordalexia/web/ParentScheduleController.java index 2d0f71f..f435194 100644 --- a/backend/src/main/java/es/asepeyo/recordalexia/web/ParentScheduleController.java +++ b/backend/src/main/java/es/asepeyo/recordalexia/web/ParentScheduleController.java @@ -3,11 +3,13 @@ package es.asepeyo.recordalexia.web; import es.asepeyo.recordalexia.domain.Activity; import es.asepeyo.recordalexia.domain.AfternoonRoutine; import es.asepeyo.recordalexia.domain.Child; +import es.asepeyo.recordalexia.domain.RoutineTask; import es.asepeyo.recordalexia.domain.WeeklyTemplateEntry; import es.asepeyo.recordalexia.exception.NotFoundException; import es.asepeyo.recordalexia.repository.ActivityRepository; import es.asepeyo.recordalexia.repository.AfternoonRoutineRepository; import es.asepeyo.recordalexia.repository.ChildRepository; +import es.asepeyo.recordalexia.repository.RoutineTaskRepository; import es.asepeyo.recordalexia.repository.WeeklyTemplateEntryRepository; import es.asepeyo.recordalexia.security.FamilyContext; import es.asepeyo.recordalexia.web.dto.ParentDtos.AfternoonRoutineRequest; @@ -36,17 +38,20 @@ public class ParentScheduleController { private final WeeklyTemplateEntryRepository templateRepository; private final AfternoonRoutineRepository routineRepository; + private final RoutineTaskRepository routineTaskRepository; private final ChildRepository childRepository; private final ActivityRepository activityRepository; private final FamilyContext familyContext; public ParentScheduleController(WeeklyTemplateEntryRepository templateRepository, AfternoonRoutineRepository routineRepository, + RoutineTaskRepository routineTaskRepository, ChildRepository childRepository, ActivityRepository activityRepository, FamilyContext familyContext) { this.templateRepository = templateRepository; this.routineRepository = routineRepository; + this.routineTaskRepository = routineTaskRepository; this.childRepository = childRepository; this.activityRepository = activityRepository; this.familyContext = familyContext; @@ -97,14 +102,20 @@ public class ParentScheduleController { .map(this::toRoutineView).toList(); } + /** Asigna una rutina del catálogo a uno o varios días de una vez (sin duplicar definición). */ @PostMapping("/routines") - public ResponseEntity createRoutine(@RequestBody AfternoonRoutineRequest req) { + @Transactional + public ResponseEntity> createRoutine(@RequestBody AfternoonRoutineRequest req) { Child child = requireChild(req.childId()); - AfternoonRoutine routine = new AfternoonRoutine(child, DayOfWeek.valueOf(req.dayOfWeek()), - req.labelEs(), req.labelCa(), req.icon(), req.color(), - req.orderIndex() != null ? req.orderIndex() : 0); - routine.setCoinsReward(req.coinsReward()); - return ResponseEntity.ok(toRoutineView(routineRepository.save(routine))); + RoutineTask task = routineTaskRepository.findByIdAndFamilyId(req.routineTaskId(), fid()) + .orElseThrow(() -> new NotFoundException("No existe la rutina con id " + req.routineTaskId())); + int orderIndex = req.orderIndex() != null ? req.orderIndex() : 0; + List created = req.daysOfWeek().stream().map(day -> { + AfternoonRoutine routine = new AfternoonRoutine(child, DayOfWeek.valueOf(day), task, orderIndex); + routine.setCoinsReward(req.coinsReward()); + return toRoutineView(routineRepository.save(routine)); + }).toList(); + return ResponseEntity.ok(created); } /** Reordena rutinas (solo las de la familia): orderIndex según la posición recibida. */ @@ -143,8 +154,9 @@ public class ParentScheduleController { } private RoutineView toRoutineView(AfternoonRoutine r) { + RoutineTask t = r.getRoutineTask(); return new RoutineView(r.getId(), r.getChild().getId(), r.getDayOfWeek().name(), - r.getLabelEs(), r.getLabelCa(), r.getIcon(), r.getColor(), r.getOrderIndex(), + t.getId(), t.getLabelEs(), t.getLabelCa(), t.getIcon(), t.getColor(), r.getOrderIndex(), r.getCoinsReward()); } } diff --git a/backend/src/main/java/es/asepeyo/recordalexia/web/dto/ParentDtos.java b/backend/src/main/java/es/asepeyo/recordalexia/web/dto/ParentDtos.java index 5a0259b..0e122eb 100644 --- a/backend/src/main/java/es/asepeyo/recordalexia/web/dto/ParentDtos.java +++ b/backend/src/main/java/es/asepeyo/recordalexia/web/dto/ParentDtos.java @@ -32,14 +32,23 @@ public final class ParentDtos { String labelEs, String labelCa, String icon, String color, String category) { } + /** Alta/edición de una rutina del catálogo de la familia (definición reutilizable). */ + public record RoutineTaskRequest( + String labelEs, String labelCa, String icon, String color, Integer coinsReward) { + } + // --- Horario / rutinas --- public record WeeklyEntryRequest( Long childId, String dayOfWeek, Long activityId, Integer orderIndex, Integer coinsReward) { } + /** + * Asigna una rutina del catálogo a un niño para varios días de una vez. El orden y + * las monedas son opcionales (override por día). + */ public record AfternoonRoutineRequest( - Long childId, String dayOfWeek, String labelEs, String labelCa, String icon, String color, - Integer orderIndex, Integer coinsReward) { + Long childId, Long routineTaskId, List daysOfWeek, Integer orderIndex, + Integer coinsReward) { } /** Reordenación de rutinas: lista de ids en el nuevo orden deseado. */ diff --git a/backend/src/main/java/es/asepeyo/recordalexia/web/dto/ParentViews.java b/backend/src/main/java/es/asepeyo/recordalexia/web/dto/ParentViews.java index a5ff6e2..87ef3ae 100644 --- a/backend/src/main/java/es/asepeyo/recordalexia/web/dto/ParentViews.java +++ b/backend/src/main/java/es/asepeyo/recordalexia/web/dto/ParentViews.java @@ -21,14 +21,20 @@ public final class ParentViews { Long id, String labelEs, String labelCa, String icon, String color, List materialIds) { } + /** Rutina del catálogo de la familia (definición reutilizable). */ + public record RoutineTaskView( + Long id, String labelEs, String labelCa, String icon, String color, Integer coinsReward) { + } + public record WeeklyEntryView( Long id, Long childId, String dayOfWeek, Long activityId, String activityLabelEs, String icon, String color, int orderIndex, Integer coinsReward) { } + /** Asignación de una rutina a un día; labels/icon/color derivan del catálogo. */ public record RoutineView( - Long id, Long childId, String dayOfWeek, String labelEs, String labelCa, String icon, - String color, int orderIndex, Integer coinsReward) { + Long id, Long childId, String dayOfWeek, Long routineTaskId, String labelEs, String labelCa, + String icon, String color, int orderIndex, Integer coinsReward) { } public record EventAdminView(