initial commit

This commit is contained in:
2025-11-20 14:06:59 -05:00
commit cb0f972a5f
77 changed files with 11579 additions and 0 deletions

View File

@@ -0,0 +1,174 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { isParentAuthenticated } from '../stores/auth'
import ChildDetailCard from './ChildDetailCard.vue'
import ChildTaskList from './ChildTaskList.vue'
import ChildRewardList from './ChildRewardList.vue'
import AssignTaskButton from './AssignTaskButton.vue' // <-- Import here
interface Child {
id: string | number
name: string
age: number
points?: number
}
const route = useRoute()
const child = ref<Child | null>(null)
const tasks = ref<string[]>([])
const loading = ref(true)
const error = ref<string | null>(null)
const rewardListRef = ref()
onMounted(async () => {
try {
const resp = await fetch(`/api/child/${route.params.id}`)
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
const data = await resp.json()
child.value = data.children ? data.children : data
tasks.value = data.tasks || []
} catch (err) {
error.value = err instanceof Error ? err.message : 'Failed to fetch child'
console.error(err)
} finally {
loading.value = false
}
})
const refreshRewards = () => {
rewardListRef.value?.refresh()
}
</script>
<template>
<div class="container">
<div v-if="loading" class="loading">Loading...</div>
<div v-else-if="error" class="error">Error: {{ error }}</div>
<div v-else class="layout">
<div class="main">
<ChildDetailCard :child="child" />
<ChildTaskList
:task-ids="tasks"
:child-id="child ? child.id : null"
:is-parent-authenticated="isParentAuthenticated"
@points-updated="
({ id, points }) => {
if (child && child.id === id) child.points = points
refreshRewards()
}
"
/>
<ChildRewardList
ref="rewardListRef"
:child-id="child ? child.id : null"
:is-parent-authenticated="isParentAuthenticated"
@points-updated="
({ id, points }) => {
if (child && child.id === id) child.points = points
refreshRewards()
}
"
/>
</div>
</div>
<!-- Place the AssignTaskButton here, outside .main but inside .container -->
<AssignTaskButton :child-id="child ? child.id : null" />
</div>
</template>
<style scoped>
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
min-height: 100vh;
padding: 2rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
box-sizing: border-box;
}
.back-btn {
background: white;
border: 0;
padding: 0.6rem 1rem;
border-radius: 8px;
cursor: pointer;
margin-bottom: 1.5rem;
color: #667eea;
font-weight: 600;
}
.loading,
.error {
color: white;
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.error {
color: #ff6b6b;
background: rgba(255, 107, 107, 0.1);
border-radius: 8px;
padding: 1rem;
}
.layout {
display: flex;
justify-content: center;
align-items: flex-start;
/* Remove grid styles */
/* grid-template-columns: 1fr 320px; */
/* gap: 1.5rem; */
}
.main {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.5rem;
width: 100%;
max-width: 600px; /* or whatever width fits your content best */
}
.side {
display: flex;
flex-direction: column;
gap: 1rem;
}
.placeholder {
background: rgba(255, 255, 255, 0.08);
color: white;
padding: 1rem;
border-radius: 8px;
min-height: 120px;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
/* Mobile adjustments */
@media (max-width: 900px) {
.layout {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.container {
padding: 1rem;
}
.back-btn {
padding: 0.45rem 0.75rem;
font-size: 0.95rem;
margin-bottom: 1rem;
}
.main {
gap: 1rem;
}
.placeholder {
padding: 0.75rem;
min-height: 80px;
}
}
</style>