This commit is contained in:
2025-12-05 17:40:57 -05:00
parent 6423d1c1a2
commit fa9fabcd9f
43 changed files with 1506 additions and 529 deletions

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, nextTick, computed } from 'vue'
import { ref, watch, onBeforeUnmount, nextTick, computed } from 'vue'
import { defineProps, defineEmits } from 'vue'
import { getCachedImageUrl, revokeAllImageUrls } from '../../common/imageCache'
import type { Task } from '@/common/models'
@@ -14,7 +14,6 @@ const props = defineProps<{
filterType?: number | null
}>()
const emit = defineEmits<{
(e: 'points-updated', payload: { id: string; points: number }): void
(e: 'trigger-task', task: Task): void
}>()
@@ -119,7 +118,18 @@ const filteredTasks = computed(() => {
return tasks.value
})
onMounted(fetchTasks)
watch(
() => props.taskIds,
(newTaskIds) => {
if (newTaskIds && newTaskIds.length > 0) {
fetchTasks()
} else {
tasks.value = []
loading.value = false
}
},
{ immediate: true },
)
// revoke all created object URLs when component unmounts
onBeforeUnmount(() => {

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import { ref, watch, onMounted, computed } from 'vue'
import { getCachedImageUrl } from '../../common/imageCache'
import type { Task } from '@/common/models'
const props = defineProps<{
childId?: string | number
@@ -9,7 +10,7 @@ const props = defineProps<{
deletable?: boolean
selectable?: boolean
}>()
const emit = defineEmits(['edit-task', 'delete-task'])
const emit = defineEmits(['edit-task', 'delete-task', 'loading-complete'])
const tasks = ref<
{
@@ -36,12 +37,15 @@ const fetchTasks = async () => {
const resp = await fetch(url)
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
const data = await resp.json()
const assigned = (data.assigned_tasks || []).map((task: any) => ({ ...task, assigned: true }))
const assignable = (data.assignable_tasks || []).map((task: any) => ({
const assigned = (data.assigned_tasks || []).map((task: Task) => ({
...task,
assigned: true,
}))
const assignable = (data.assignable_tasks || []).map((task: Task) => ({
...task,
assigned: false,
}))
let taskList: any[] = []
let taskList: Task[] = []
if (props.assignFilter === 'assignable') {
taskList = assignable
} else if (props.assignFilter === 'assigned') {
@@ -53,7 +57,7 @@ const fetchTasks = async () => {
}
// Fetch images for each task if image_id is present
await Promise.all(
taskList.map(async (task: any) => {
taskList.map(async (task: Task) => {
if (task.image_id) {
try {
task.image_url = await getCachedImageUrl(task.image_id)
@@ -67,7 +71,7 @@ const fetchTasks = async () => {
// If selectable, pre-select assigned tasks
if (props.selectable) {
selectedTasks.value = assigned.map((task: any) => String(task.id))
selectedTasks.value = assigned.map((task: Task) => String(task.id))
}
} catch (err) {
error.value = err instanceof Error ? err.message : 'Failed to fetch tasks'
@@ -84,7 +88,7 @@ const fetchTasks = async () => {
const data = await resp.json()
const taskList = data.tasks || []
await Promise.all(
taskList.map(async (task: any) => {
taskList.map(async (task: Task) => {
if (task.image_id) {
try {
task.image_url = await getCachedImageUrl(task.image_id)
@@ -101,6 +105,7 @@ const fetchTasks = async () => {
tasks.value = []
if (props.selectable) selectedTasks.value = []
} finally {
emit('loading-complete', tasks.value.length)
loading.value = false
}
}

View File

@@ -1,10 +1,19 @@
<template>
<div class="task-view">
<div v-if="taskCountRef === 0" class="no-tasks-message">
<div>No Tasks</div>
<div class="sub-message">
<button class="create-btn" @click="createTask">Create</button> a task
</div>
</div>
<TaskList
v-else
ref="taskListRef"
:deletable="true"
@edit-task="(taskId) => $router.push({ name: 'EditTask', params: { id: taskId } })"
@delete-task="confirmDeleteTask"
@loading-complete="(count) => (taskCountRef = count)"
/>
<!-- Floating Action Button -->
@@ -37,6 +46,7 @@ const $router = useRouter()
const showConfirm = ref(false)
const taskToDelete = ref<string | null>(null)
const taskListRef = ref()
const taskCountRef = ref<number>(0)
function confirmDeleteTask(taskId: string) {
taskToDelete.value = taskId
@@ -145,4 +155,37 @@ const createTask = () => {
.fab:hover {
background: #5a67d8;
}
.no-tasks-message {
margin: 2rem 0;
font-size: 1.15rem;
font-weight: 600;
text-align: center;
color: #fdfdfd;
line-height: 1.5;
}
.sub-message {
margin-top: 0.3rem;
font-size: 1rem;
font-weight: 400;
color: #b5ccff;
}
.create-btn {
background: #fff;
color: #2563eb;
border: 2px solid #2563eb;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 600;
padding: 0.2rem 0.5rem;
margin-right: 0.1rem;
cursor: pointer;
transition:
background 0.18s,
color 0.18s;
}
.create-btn:hover {
background: #2563eb;
color: #fff;
}
</style>