94 lines
2.8 KiB
Vue
94 lines
2.8 KiB
Vue
<template>
|
||
<div class="p-6">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<h2 class="text-2xl font-bold">👨🎓 Students List</h2>
|
||
<NuxtLink to="/students/add" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
|
||
➕ Add Student
|
||
</NuxtLink>
|
||
</div>
|
||
|
||
<div v-if="loading" class="text-gray-500">Loading students...</div>
|
||
|
||
<div v-else-if="students.length">
|
||
<table class="min-w-full bg-white shadow-md rounded overflow-hidden">
|
||
<thead class="bg-gray-100">
|
||
<tr>
|
||
<th class="text-left px-4 py-2">#</th>
|
||
<th class="text-left px-4 py-2">Name</th>
|
||
<th class="text-left px-4 py-2">Email</th>
|
||
<th class="text-left px-4 py-2">Class</th>
|
||
<th class="text-left px-4 py-2">Actions</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-for="(student, index) in students" :key="student.id" class="border-t">
|
||
<td class="px-4 py-2">{{ index + 1 }}</td>
|
||
<td class="px-4 py-2">{{ student.name }}</td>
|
||
<td class="px-4 py-2">{{ student.email }}</td>
|
||
<td class="px-4 py-2">
|
||
{{ student.class_id?.name }} - {{ student.class_id?.section }}
|
||
</td>
|
||
<td class="px-4 py-2 flex gap-2">
|
||
<NuxtLink :to="`/students?id=${student.id}`" class="text-sm text-blue-600 hover:underline">View</NuxtLink>
|
||
|
||
<NuxtLink :to="`/students/edit?id=${student.id}`" class="text-sm text-yellow-600 hover:underline">Edit
|
||
</NuxtLink>
|
||
|
||
<button @click="deleteStudent(student.id)" class="text-sm text-red-600 hover:underline">Delete</button>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div v-else class="text-gray-500">No students found.</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted } from 'vue'
|
||
import { useDirectus } from '../../app/composables/useDirectus'
|
||
|
||
const { fetchCollection, deleteItem } = useDirectus()
|
||
const students = ref([])
|
||
const loading = ref(true)
|
||
|
||
const fetchStudents = async () => {
|
||
try {
|
||
students.value = await fetchCollection('students', {
|
||
fields: ['id', 'name', 'email', 'class_id.name', 'class_id.section'],
|
||
sort: ['name']
|
||
})
|
||
} catch (err) {
|
||
console.error('Failed to fetch students:', err)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
const deleteStudent = async (id) => {
|
||
if (!confirm('Are you sure you want to delete this student?')) return
|
||
|
||
try {
|
||
await deleteItem('students', id)
|
||
students.value = students.value.filter((s) => s.id !== id)
|
||
alert('Student deleted!')
|
||
} catch (err) {
|
||
console.error('Error deleting student:', err)
|
||
alert('Failed to delete student.')
|
||
}
|
||
}
|
||
|
||
onMounted(fetchStudents)
|
||
</script>
|
||
|
||
<style scoped>
|
||
table {
|
||
border-collapse: collapse;
|
||
}
|
||
|
||
th,
|
||
td {
|
||
border-bottom: 1px solid #e5e7eb;
|
||
}
|
||
</style> |