feat: Implement routines feature with CRUD operations and child assignment
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m0s
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m0s
- Add backend routines management with add, get, update, delete, and list functionalities. - Create models for Routine, RoutineItem, RoutineSchedule, and RoutineExtension. - Develop event types for routine confirmation and modification. - Implement frontend components for routine assignment, confirmation dialog, and routine management views. - Add unit tests for routine API and integration tests for routine CRUD flow. - Create end-to-end test plan for routines feature covering parent and child interactions.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ModalDialog :image-url="task.image_url" :title="'Schedule Chore'" :subtitle="task.name">
|
||||
<ModalDialog :image-url="entity.image_url" :title="scheduleTitle" :subtitle="entity.name">
|
||||
<!-- Enable/disable toggle row -->
|
||||
<div class="schedule-toggle-row">
|
||||
<span class="toggle-label">{{ scheduleEnabled ? 'Enabled' : 'Paused' }}</span>
|
||||
@@ -165,8 +165,20 @@ import { ref, computed } from 'vue'
|
||||
import ModalDialog from './ModalDialog.vue'
|
||||
import TimePickerPopover from './TimePickerPopover.vue'
|
||||
import DateInputField from './DateInputField.vue'
|
||||
import { setChoreSchedule, deleteChoreSchedule, parseErrorResponse } from '@/common/api'
|
||||
import type { ChildTask, ChoreSchedule, DayConfig } from '@/common/models'
|
||||
import {
|
||||
setChoreSchedule,
|
||||
deleteChoreSchedule,
|
||||
setRoutineSchedule,
|
||||
deleteRoutineSchedule,
|
||||
parseErrorResponse,
|
||||
} from '@/common/api'
|
||||
import type {
|
||||
ChildTask,
|
||||
ChildRoutine,
|
||||
ChoreSchedule,
|
||||
RoutineSchedule,
|
||||
DayConfig,
|
||||
} from '@/common/models'
|
||||
|
||||
interface TimeValue {
|
||||
hour: number
|
||||
@@ -174,11 +186,16 @@ interface TimeValue {
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
task: ChildTask
|
||||
entity: ChildTask | ChildRoutine
|
||||
entityType: 'task' | 'routine'
|
||||
childId: string
|
||||
schedule: ChoreSchedule | null
|
||||
schedule: ChoreSchedule | RoutineSchedule | null
|
||||
}>()
|
||||
|
||||
const scheduleTitle = computed(() =>
|
||||
props.entityType === 'task' ? 'Schedule Chore' : 'Schedule Routine',
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'saved'): void
|
||||
(e: 'cancelled'): void
|
||||
@@ -386,10 +403,20 @@ async function save() {
|
||||
errorMsg.value = null
|
||||
saving.value = true
|
||||
|
||||
const entityId = props.entity.id
|
||||
const saveEntitySchedule = (payload: object) =>
|
||||
props.entityType === 'task'
|
||||
? setChoreSchedule(props.childId, entityId, payload)
|
||||
: setRoutineSchedule(props.childId, entityId, payload)
|
||||
const deleteEntitySchedule = () =>
|
||||
props.entityType === 'task'
|
||||
? deleteChoreSchedule(props.childId, entityId)
|
||||
: deleteRoutineSchedule(props.childId, entityId)
|
||||
|
||||
let res: Response
|
||||
if (mode.value === 'days' && selectedDays.value.size === 0) {
|
||||
// 0 days = remove schedule entirely → chore becomes always active
|
||||
res = await deleteChoreSchedule(props.childId, props.task.id)
|
||||
// 0 days = remove schedule entirely so the item becomes always active
|
||||
res = await deleteEntitySchedule()
|
||||
} else if (mode.value === 'days') {
|
||||
const day_configs: DayConfig[] = Array.from(selectedDays.value).map((day) => {
|
||||
const override = exceptions.value.get(day)
|
||||
@@ -399,7 +426,7 @@ async function save() {
|
||||
minute: override?.minute ?? defaultTime.value.minute,
|
||||
}
|
||||
})
|
||||
res = await setChoreSchedule(props.childId, props.task.id, {
|
||||
res = await saveEntitySchedule({
|
||||
mode: 'days',
|
||||
enabled: scheduleEnabled.value,
|
||||
day_configs,
|
||||
@@ -408,7 +435,7 @@ async function save() {
|
||||
default_has_deadline: hasDefaultDeadline.value,
|
||||
})
|
||||
} else {
|
||||
res = await setChoreSchedule(props.childId, props.task.id, {
|
||||
res = await saveEntitySchedule({
|
||||
mode: 'interval',
|
||||
enabled: scheduleEnabled.value,
|
||||
interval_days: intervalDays.value,
|
||||
|
||||
Reference in New Issue
Block a user