From 462205cdc14111d10a17fa1f309b3b32fe4fc0cd Mon Sep 17 00:00:00 2001 From: derekc Date: Sat, 28 Feb 2026 00:59:01 -0800 Subject: [PATCH] Merge Schedules into Admin, remove standalone ScheduleView - Move schedule template management into AdminView under a new Schedules section - Remove ScheduleView.vue and its route, drop Schedules link from NavBar - Delete docker-compose.override.yml (dev override no longer needed) - Fix CORS_ORIGINS default to port 8057 in docker-compose.yml Co-Authored-By: Claude Sonnet 4.6 --- docker-compose.override.yml | 17 -- docker-compose.yml | 2 +- frontend/src/components/NavBar.vue | 3 +- frontend/src/router/index.js | 8 +- frontend/src/views/AdminView.vue | 197 ++++++++++++++++++++++- frontend/src/views/ScheduleView.vue | 233 ---------------------------- 6 files changed, 193 insertions(+), 267 deletions(-) delete mode 100644 docker-compose.override.yml delete mode 100644 frontend/src/views/ScheduleView.vue diff --git a/docker-compose.override.yml b/docker-compose.override.yml deleted file mode 100644 index 39bea69..0000000 --- a/docker-compose.override.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Development overrides โ€” hot reload for backend, Vite dev server for frontend -services: - backend: - volumes: - - ./backend/app:/app/app - command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload - - frontend: - build: - context: ./frontend - target: builder - ports: - - "8054:5173" - volumes: - - ./frontend/src:/app/src - - ./frontend/index.html:/app/index.html - command: npm run dev -- --host 0.0.0.0 --port 5173 diff --git a/docker-compose.yml b/docker-compose.yml index 93b1236..c8bf445 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,7 +28,7 @@ services: ALGORITHM: ${ALGORITHM:-HS256} ACCESS_TOKEN_EXPIRE_MINUTES: ${ACCESS_TOKEN_EXPIRE_MINUTES:-30} REFRESH_TOKEN_EXPIRE_DAYS: ${REFRESH_TOKEN_EXPIRE_DAYS:-30} - CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:8054} + CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:8057} depends_on: db: condition: service_healthy diff --git a/frontend/src/components/NavBar.vue b/frontend/src/components/NavBar.vue index 32aa83a..5c999ab 100644 --- a/frontend/src/components/NavBar.vue +++ b/frontend/src/components/NavBar.vue @@ -3,8 +3,7 @@ ๐Ÿ  Homeschool + + +
+
+

Schedules

+ +
+ + +
+

New Schedule Template

+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+
{{ template.name }}
+
+ {{ template.child_id ? childName(template.child_id) : 'All children' }} + ยท {{ template.blocks.length }} blocks +
+
+
+ + +
+
+ + +
+
+
+ {{ block.time_start }} โ€“ {{ block.time_end }} + {{ block.label || subjectName(block.subject_id) || 'Unnamed' }} + +
+
No blocks yet.
+
+ + +
+ + + to + + + +
+
+
+ +
+ No schedule templates yet. Create one to get started. +
+
+
@@ -97,12 +177,10 @@ import NavBar from '@/components/NavBar.vue' const childrenStore = useChildrenStore() const subjects = ref([]) +// Children const showChildForm = ref(false) -const showSubjectForm = ref(false) const newChild = ref({ name: '', color: '#4F46E5' }) -const newSubject = ref({ name: '', icon: '๐Ÿ“š', color: '#10B981' }) const editingChild = ref(null) -const editingSubject = ref(null) async function createChild() { await childrenStore.createChild(newChild.value) @@ -133,6 +211,11 @@ async function deleteChild(id) { } } +// Subjects +const showSubjectForm = ref(false) +const newSubject = ref({ name: '', icon: '๐Ÿ“š', color: '#10B981' }) +const editingSubject = ref(null) + async function loadSubjects() { const res = await api.get('/api/subjects') subjects.value = res.data @@ -168,15 +251,64 @@ async function deleteSubject(id) { } } +// Schedules +const templates = ref([]) +const showCreateForm = ref(false) +const editingTemplate = ref(null) +const newTemplate = ref({ name: '', child_id: null, is_default: false }) +const newBlock = ref({ subject_id: null, time_start: '', time_end: '', label: '', order_index: 0 }) + +function childName(id) { + return childrenStore.children.find((c) => c.id === id)?.name || 'Unknown' +} + +function subjectName(id) { + return subjects.value.find((s) => s.id === id)?.name || null +} + +async function loadTemplates() { + const res = await api.get('/api/schedules') + templates.value = res.data +} + +async function createTemplate() { + await api.post('/api/schedules', newTemplate.value) + newTemplate.value = { name: '', child_id: null, is_default: false } + showCreateForm.value = false + await loadTemplates() +} + +async function deleteTemplate(id) { + if (confirm('Delete this template and all its blocks?')) { + await api.delete(`/api/schedules/${id}`) + await loadTemplates() + } +} + +async function addBlock(templateId) { + const payload = { + ...newBlock.value, + order_index: templates.value.find((t) => t.id === templateId)?.blocks.length || 0, + } + await api.post(`/api/schedules/${templateId}/blocks`, payload) + newBlock.value = { subject_id: null, time_start: '', time_end: '', label: '', order_index: 0 } + await loadTemplates() +} + +async function deleteBlock(templateId, blockId) { + await api.delete(`/api/schedules/${templateId}/blocks/${blockId}`) + await loadTemplates() +} + onMounted(async () => { await childrenStore.fetchChildren() - await loadSubjects() + await Promise.all([loadSubjects(), loadTemplates()]) }) diff --git a/frontend/src/views/ScheduleView.vue b/frontend/src/views/ScheduleView.vue deleted file mode 100644 index 032b1cb..0000000 --- a/frontend/src/views/ScheduleView.vue +++ /dev/null @@ -1,233 +0,0 @@ - - - - -