Added serial number to entries table, and button to remove desk assignments.
This commit is contained in:
parent
ae33f57a36
commit
b5808d68f2
|
@ -19,6 +19,7 @@ void registerApiEndpoints(PathHandler handler) {
|
||||||
handler.addMapping(Method.GET, CLASS_PATH ~ "/notes", &getClassNotes);
|
handler.addMapping(Method.GET, CLASS_PATH ~ "/notes", &getClassNotes);
|
||||||
handler.addMapping(Method.POST, CLASS_PATH ~ "/notes", &createClassNote);
|
handler.addMapping(Method.POST, CLASS_PATH ~ "/notes", &createClassNote);
|
||||||
handler.addMapping(Method.DELETE, CLASS_PATH ~ "/notes/:noteId:ulong", &deleteClassNote);
|
handler.addMapping(Method.DELETE, CLASS_PATH ~ "/notes/:noteId:ulong", &deleteClassNote);
|
||||||
|
handler.addMapping(Method.PUT, CLASS_PATH ~ "/reset-desk-numbers", &resetStudentDesks);
|
||||||
|
|
||||||
handler.addMapping(Method.POST, CLASS_PATH ~ "/students", &createStudent);
|
handler.addMapping(Method.POST, CLASS_PATH ~ "/students", &createStudent);
|
||||||
handler.addMapping(Method.GET, CLASS_PATH ~ "/students", &getStudents);
|
handler.addMapping(Method.GET, CLASS_PATH ~ "/students", &getStudents);
|
||||||
|
|
|
@ -141,3 +141,12 @@ void deleteClassNote(ref HttpRequestContext ctx) {
|
||||||
const query = "DELETE FROM classroom_compliance_class_note WHERE class_id = ? AND id = ?";
|
const query = "DELETE FROM classroom_compliance_class_note WHERE class_id = ? AND id = ?";
|
||||||
update(conn, query, cls.id, noteId);
|
update(conn, query, cls.id, noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetStudentDesks(ref HttpRequestContext ctx) {
|
||||||
|
Connection conn = getDb();
|
||||||
|
scope(exit) conn.close();
|
||||||
|
User user = getUserOrThrow(ctx, conn);
|
||||||
|
auto cls = getClassOrThrow(ctx, conn, user);
|
||||||
|
const query = "UPDATE classroom_compliance_student SET desk_number = 0 WHERE class_id = ?";
|
||||||
|
update(conn, query, cls.id);
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { APIClient, type APIResponse, type AuthStoreType } from './base'
|
import { APIClient, APIResponse, type AuthStoreType } from './base'
|
||||||
|
|
||||||
export const BASE_URL = import.meta.env.VITE_API_URL + '/classroom-compliance'
|
export const BASE_URL = import.meta.env.VITE_API_URL + '/classroom-compliance'
|
||||||
|
|
||||||
|
@ -140,6 +140,15 @@ export class ClassroomComplianceAPIClient extends APIClient {
|
||||||
return super.delete(`/classes/${classId}/notes/${noteId}`)
|
return super.delete(`/classes/${classId}/notes/${noteId}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetStudentDesks(classId: number): APIResponse<void> {
|
||||||
|
const url = `/classes/${classId}/reset-desk-numbers`
|
||||||
|
const promise = fetch(this.baseUrl + url, {
|
||||||
|
headers: this.getAuthHeaders(),
|
||||||
|
method: 'PUT',
|
||||||
|
})
|
||||||
|
return new APIResponse(this.handleAPIResponseWithNoBody(promise))
|
||||||
|
}
|
||||||
|
|
||||||
getStudents(classId: number): APIResponse<Student[]> {
|
getStudents(classId: number): APIResponse<Student[]> {
|
||||||
return super.get(`/classes/${classId}/students`)
|
return super.get(`/classes/${classId}/students`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,17 @@ const router = useRouter()
|
||||||
const cls: Ref<Class | null> = ref(null)
|
const cls: Ref<Class | null> = ref(null)
|
||||||
const notes: Ref<ClassNote[]> = ref([])
|
const notes: Ref<ClassNote[]> = ref([])
|
||||||
const noteContent: Ref<string> = ref('')
|
const noteContent: Ref<string> = ref('')
|
||||||
|
|
||||||
|
const entriesTable = useTemplateRef('entries-table')
|
||||||
|
|
||||||
const apiClient = new ClassroomComplianceAPIClient(authStore)
|
const apiClient = new ClassroomComplianceAPIClient(authStore)
|
||||||
|
|
||||||
const deleteClassDialog = useTemplateRef('deleteClassDialog')
|
const deleteClassDialog = useTemplateRef('deleteClassDialog')
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
loadClass()
|
||||||
|
})
|
||||||
|
|
||||||
|
function loadClass() {
|
||||||
const idNumber = parseInt(props.id, 10)
|
const idNumber = parseInt(props.id, 10)
|
||||||
apiClient.getClass(idNumber).handleErrorsWithAlert().then(result => {
|
apiClient.getClass(idNumber).handleErrorsWithAlert().then(result => {
|
||||||
if (result) {
|
if (result) {
|
||||||
|
@ -28,7 +35,7 @@ onMounted(() => {
|
||||||
router.back();
|
router.back();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
async function deleteThisClass() {
|
async function deleteThisClass() {
|
||||||
if (!cls.value || !(await deleteClassDialog.value?.show())) return
|
if (!cls.value || !(await deleteClassDialog.value?.show())) return
|
||||||
|
@ -61,6 +68,13 @@ function refreshNotes() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function resetStudentDesks() {
|
||||||
|
if (!cls.value) return
|
||||||
|
await apiClient.resetStudentDesks(cls.value.id).handleErrorsWithAlert()
|
||||||
|
// Reload the table!
|
||||||
|
await entriesTable.value?.loadEntries()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div v-if="cls">
|
<div v-if="cls">
|
||||||
|
@ -71,6 +85,7 @@ function refreshNotes() {
|
||||||
Student</button>
|
Student</button>
|
||||||
<button type="button" @click="router.push(`/classroom-compliance/classes/${cls.id}/import-students`)">Import
|
<button type="button" @click="router.push(`/classroom-compliance/classes/${cls.id}/import-students`)">Import
|
||||||
Students</button>
|
Students</button>
|
||||||
|
<button type="button" @click="resetStudentDesks">Clear Assigned Desks</button>
|
||||||
<button type="button" @click="deleteThisClass">Delete this Class</button>
|
<button type="button" @click="deleteThisClass">Delete this Class</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -82,7 +97,7 @@ function refreshNotes() {
|
||||||
</form>
|
</form>
|
||||||
<ClassNoteItem v-for="note in notes" :key="note.id" :note="note" @noteDeleted="refreshNotes()" />
|
<ClassNoteItem v-for="note in notes" :key="note.id" :note="note" @noteDeleted="refreshNotes()" />
|
||||||
|
|
||||||
<EntriesTable :classId="cls.id" />
|
<EntriesTable :classId="cls.id" ref="entries-table" />
|
||||||
|
|
||||||
<!-- Confirmation dialog used for attempts at deleting this class. -->
|
<!-- Confirmation dialog used for attempts at deleting this class. -->
|
||||||
<ConfirmDialog ref="deleteClassDialog">
|
<ConfirmDialog ref="deleteClassDialog">
|
||||||
|
|
|
@ -237,6 +237,10 @@ function addAllEntriesForDate(dateStr: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
loadEntries
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
@ -272,6 +276,7 @@ function addAllEntriesForDate(dateStr: string) {
|
||||||
<table class="entries-table" :class="{ 'entries-table-reduced-view': selectedView !== TableView.FULL }">
|
<table class="entries-table" :class="{ 'entries-table-reduced-view': selectedView !== TableView.FULL }">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th v-if="selectedView !== TableView.WHITEBOARD">#</th>
|
||||||
<th>Student</th>
|
<th>Student</th>
|
||||||
<th v-if="assignedDesks">Desk</th>
|
<th v-if="assignedDesks">Desk</th>
|
||||||
<DateHeaderCell v-for="date in getVisibleDates()" :key="date" :date-str="date"
|
<DateHeaderCell v-for="date in getVisibleDates()" :key="date" :date-str="date"
|
||||||
|
@ -280,7 +285,9 @@ function addAllEntriesForDate(dateStr: string) {
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="student in students" :key="student.id">
|
<tr v-for="(student, idx) in students" :key="student.id" style="height: 2em;">
|
||||||
|
<td v-if="selectedView !== TableView.WHITEBOARD" style="text-align: right; padding-right: 0.5em;">{{ idx + 1
|
||||||
|
}}.</td>
|
||||||
<StudentNameCell :student="student" :class-id="classId" />
|
<StudentNameCell :student="student" :class-id="classId" />
|
||||||
<!-- Desk Number: -->
|
<!-- Desk Number: -->
|
||||||
<td v-if="assignedDesks" v-text="student.deskNumber"></td>
|
<td v-if="assignedDesks" v-text="student.deskNumber"></td>
|
||||||
|
|
|
@ -6,19 +6,29 @@ defineProps<{
|
||||||
}>()
|
}>()
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<td :class="{ 'student-removed': student.removed }">
|
<td class="student-name-cell" :class="{ 'student-removed': student.removed }">
|
||||||
<RouterLink :to="'/classroom-compliance/classes/' + classId + '/students/' + student.id" class="student-link">
|
<RouterLink :to="'/classroom-compliance/classes/' + classId + '/students/' + student.id" class="student-link">
|
||||||
<span v-text="student.name"></span>
|
{{ student.name }}
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</td>
|
</td>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.student-name-cell {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
.student-link {
|
.student-link {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.student-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
.student-removed {
|
.student-removed {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
|
color: gray;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue