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
Dashboard
- Schedules
- Logs
+Logs
Admin
diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js
index c78653b..4109adf 100644
--- a/frontend/src/router/index.js
+++ b/frontend/src/router/index.js
@@ -24,13 +24,7 @@ const routes = [
component: () => import('@/views/DashboardView.vue'),
meta: { requiresAuth: true },
},
- {
- path: '/schedules',
- name: 'schedules',
- component: () => import('@/views/ScheduleView.vue'),
- meta: { requiresAuth: true },
- },
- {
+{
path: '/logs',
name: 'logs',
component: () => import('@/views/LogView.vue'),
diff --git a/frontend/src/views/AdminView.vue b/frontend/src/views/AdminView.vue
index 7c31c12..64c87bb 100644
--- a/frontend/src/views/AdminView.vue
+++ b/frontend/src/views/AdminView.vue
@@ -84,6 +84,86 @@
No subjects added yet.
+
+
+
+
+
+
+
+
New Schedule Template
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ block.time_start }} โ {{ block.time_end }}
+ {{ block.label || subjectName(block.subject_id) || 'Unnamed' }}
+
+
+
No blocks yet.
+
+
+
+
+
+
+
+
+ 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 @@
-
-
-
-
-
-
-
-
-
New Schedule Template
-
-
-
-
-
-
-
-
-
-
-
-
- {{ block.time_start }} โ {{ block.time_end }}
- {{ block.label || subjectName(block.subject_id) || 'Unnamed' }}
-
-
-
No blocks yet.
-
-
-
-
-
-
-
-
- No schedule templates yet. Create one to get started.
-
-
-
-
-
-
-
-
-