Added more info to classes API endpoint.
Build and Test App / Build-and-test-App (push) Successful in 34s Details
Build and Test API / Build-and-test-API (push) Successful in 52s Details

This commit is contained in:
Andrew Lalis 2025-01-28 21:12:41 -05:00
parent 39e0c9ee6e
commit 490806aaee
4 changed files with 50 additions and 9 deletions

View File

@ -46,10 +46,38 @@ void getClasses(ref HttpRequestContext ctx) {
Connection conn = getDb();
scope(exit) conn.close();
User user = getUserOrThrow(ctx, conn);
auto classes = findAll(
const query = "
SELECT
c.id, c.number, c.school_year,
COUNT(DISTINCT s.id) AS student_count,
COUNT(DISTINCT e.id) AS entry_count,
MAX(e.date) AS last_entry_date
FROM classroom_compliance_class c
LEFT JOIN classroom_compliance_student s ON c.id = s.class_id
LEFT JOIN classroom_compliance_entry e ON c.id = e.class_id
WHERE c.user_id = ?
GROUP BY c.id
ORDER BY school_year DESC, number ASC
";
struct ClassResponse {
ulong id;
ushort number;
string schoolYear;
uint studentCount;
uint entryCount;
string lastEntryDate;
}
ClassResponse[] classes = findAll(
conn,
"SELECT * FROM classroom_compliance_class WHERE user_id = ? ORDER BY school_year DESC, number ASC",
&ClassroomComplianceClass.parse,
query,
r => ClassResponse(
r.getUlong(1),
r.getUshort(2),
r.getString(3),
r.getUint(4),
r.getUint(5),
r.getDate(6).toISOExtString()
),
user.id
);
writeJsonBody(ctx, classes);

View File

@ -16,6 +16,15 @@ export interface Class {
schoolYear: string
}
export interface ClassesResponseClass {
id: number
number: number
schoolYear: string
studentCount: number
entryCount: number
lastEntryDate: string
}
export interface Student {
id: number
name: string
@ -100,7 +109,7 @@ export class ClassroomComplianceAPIClient extends APIClient {
return super.post('/classes', { number: number, schoolYear: schoolYear })
}
getClasses(): APIResponse<Class[]> {
getClasses(): APIResponse<ClassesResponseClass[]> {
return super.get('/classes')
}

View File

@ -1,16 +1,20 @@
<script setup lang="ts">
import { type Class } from '@/api/classroom_compliance'
import { type ClassesResponseClass } from '@/api/classroom_compliance'
import { useRouter } from 'vue-router';
defineProps<{
cls: Class
cls: ClassesResponseClass
}>()
const router = useRouter()
</script>
<template>
<div class="class-item" @click="router.push(`/classroom-compliance/classes/${cls.id}`)">
<h3>Class <span v-text="cls.number"></span></h3>
<p v-text="cls.schoolYear"></p>
<p>
{{ cls.studentCount }} students,
{{ cls.entryCount }} entries.
<span v-if="cls.entryCount > 0">Last entry from {{ cls.lastEntryDate }}.</span>
</p>
</div>
</template>
<style scoped>

View File

@ -1,11 +1,11 @@
<script setup lang="ts">
import { ClassroomComplianceAPIClient, type Class } from '@/api/classroom_compliance'
import { ClassroomComplianceAPIClient, type ClassesResponseClass } from '@/api/classroom_compliance'
import { useAuthStore } from '@/stores/auth'
import { type Ref, ref, onMounted } from 'vue'
import ClassItem from '@/apps/classroom_compliance/ClassItem.vue'
import { useRouter } from 'vue-router'
const classes: Ref<Class[]> = ref([])
const classes: Ref<ClassesResponseClass[]> = ref([])
const authStore = useAuthStore()
const router = useRouter()