From db6669901b15f0191902004ecb740ea7362c3ff6 Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Tue, 21 Jan 2025 16:31:08 +0100 Subject: [PATCH 01/18] Adding table promotion (consult not working yet) --- .../mobility/(_islands)/ConsultStudents.tsx | 101 ++++++++++++------ routes/(apps)/mobility/api/insert_students.ts | 53 ++++++--- routes/(apps)/mobility/api/promo.ts | 31 ++++++ 3 files changed, 133 insertions(+), 52 deletions(-) create mode 100644 routes/(apps)/mobility/api/promo.ts diff --git a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx index 4ca3459..8513a6b 100644 --- a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx +++ b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx @@ -1,64 +1,95 @@ import { useEffect, useState } from "preact/hooks"; +interface Promotion { + id: number; + name: string; +} + interface Student { id: number; firstName: string; lastName: string; email: string; - promotion: string; + promotionId: number; } export default function ConsultStudents() { - const [students, setStudents] = useState([]); + const [promotions, setPromotions] = useState([]); + const [studentsByPromotion, setStudentsByPromotion] = useState>({}); const [error, setError] = useState(null); useEffect(() => { - const fetchStudents = async () => { + const fetchPromotionsAndStudents = async () => { try { - const response = await fetch("/mobility/api/insert_students"); - - if (!response.ok) { - throw new Error(`Error fetching students: ${response.statusText}`); + // Récupérer toutes les promotions + const promoResponse = await fetch("/mobility/api/promotions"); + if (!promoResponse.ok) { + throw new Error(`Error fetching promotions: ${promoResponse.statusText}`); } + const promos: Promotion[] = await promoResponse.json(); + setPromotions(promos); - const data: Student[] = await response.json(); - setStudents(data); + // Récupérer les étudiants + const studentsResponse = await fetch("/mobility/api/insert_students"); + if (!studentsResponse.ok) { + throw new Error(`Error fetching students: ${studentsResponse.statusText}`); + } + const students: Student[] = await studentsResponse.json(); + + // Grouper les étudiants par promotionId + const grouped: Record = {}; + for (const student of students) { + if (!grouped[student.promotionId]) { + grouped[student.promotionId] = []; + } + grouped[student.promotionId].push(student); + } + setStudentsByPromotion(grouped); } catch (err) { - console.error("Error fetching students:", err); - setError("Failed to load students. Please try again later."); + console.error("Error fetching promotions or students:", err); + setError("Failed to load data. Please try again later."); } }; - fetchStudents(); + fetchPromotionsAndStudents(); }, []); return (

Consult Students

{error &&

{error}

} - {students.length === 0 ?

No students found.

: ( - - - - - - - - - - - - {students.map((student) => ( - - - - - - - - ))} - -
IDFirst NameLast NameEmailPromotion
{student.id}{student.firstName}{student.lastName}{student.email}{student.promotion}
+ {promotions.length === 0 ? ( +

No promotions found.

+ ) : ( + promotions.map((promo) => ( +
+

Promotion: {promo.name}

+ {studentsByPromotion[promo.id]?.length ? ( + + + + + + + + + + + {studentsByPromotion[promo.id].map((student) => ( + + + + + + + ))} + +
IDFirst NameLast NameEmail
{student.id}{student.firstName}{student.lastName}{student.email}
+ ) : ( +

No students in this promotion.

+ )} +
+ )) )}
); diff --git a/routes/(apps)/mobility/api/insert_students.ts b/routes/(apps)/mobility/api/insert_students.ts index e8af2fe..6fac691 100644 --- a/routes/(apps)/mobility/api/insert_students.ts +++ b/routes/(apps)/mobility/api/insert_students.ts @@ -2,8 +2,7 @@ import { Handlers } from "$fresh/server.ts"; import { Database } from "@db/sqlite"; export const handler: Handlers = { - // deno-lint-ignore require-await - async GET(_request, _context) { + async GET(_request, context) { try { const db = new Database("databases/data/mobility.db"); @@ -14,14 +13,17 @@ export const handler: Handlers = { firstName TEXT NOT NULL, lastName TEXT NOT NULL, email TEXT NOT NULL, - promotion TEXT NOT NULL + promotionId INTEGER NOT NULL, + FOREIGN KEY (promotionId) REFERENCES promotions (id) ); - `, + ` ).run(); - const rows = db.prepare( - "SELECT id, firstName, lastName, email, promotion FROM students", - ).all(); + const rows = db + .prepare( + "SELECT students.id, firstName, lastName, email, promotionId FROM students" + ) + .all(); db.close(); @@ -52,6 +54,15 @@ export const handler: Handlers = { console.log("Database opened successfully"); + db.prepare( + ` + CREATE TABLE IF NOT EXISTS promotions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT UNIQUE NOT NULL + ); + ` + ).run(); + db.prepare( ` CREATE TABLE IF NOT EXISTS students ( @@ -59,25 +70,33 @@ export const handler: Handlers = { firstName TEXT NOT NULL, lastName TEXT NOT NULL, email TEXT NOT NULL, - promotion TEXT NOT NULL + promotionId INTEGER NOT NULL, + FOREIGN KEY (promotionId) REFERENCES promotions (id) ); - `, + ` ).run(); - console.log("Table ensured successfully"); + console.log("Tables ensured successfully"); + + // Insérer ou récupérer l'ID de la promotion + db.prepare( + "INSERT OR IGNORE INTO promotions (name) VALUES (?)" + ).run(promoName); + + const promoIdRow = db + .prepare("SELECT id FROM promotions WHERE name = ?") + .get(promoName); + const promoId = promoIdRow.id; + + console.log(`Promotion ID for "${promoName}":`, promoId); const insertQuery = db.prepare( - "INSERT INTO students (firstName, lastName, email, promotion) VALUES (?, ?, ?, ?)", + "INSERT INTO students (firstName, lastName, email, promotionId) VALUES (?, ?, ?, ?)" ); for (const student of data) { console.log("Inserting student:", student); - insertQuery.run( - student.Nom, - student["Prénom"], - student.Mail, - promoName, - ); + insertQuery.run(student.Nom, student["Prénom"], student.Mail, promoId); } console.log("All students inserted successfully"); diff --git a/routes/(apps)/mobility/api/promo.ts b/routes/(apps)/mobility/api/promo.ts new file mode 100644 index 0000000..288524b --- /dev/null +++ b/routes/(apps)/mobility/api/promo.ts @@ -0,0 +1,31 @@ +import { Handlers } from "$fresh/server.ts"; +import { Database } from "@db/sqlite"; + +export const handler: Handlers = { + async GET() { + try { + const db = new Database("databases/data/mobility.db"); + + db.prepare( + ` + CREATE TABLE IF NOT EXISTS promotions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT UNIQUE NOT NULL + ); + ` + ).run(); + + const promotions = db.prepare("SELECT id, name FROM promotions").all(); + + db.close(); + + return new Response(JSON.stringify(promotions), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + } catch (error) { + console.error("Error fetching promotions:", error); + return new Response("Failed to fetch promotions", { status: 500 }); + } + }, +}; From 661b59645bd62feea01b95cdc1ea8f589d7d040e Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Tue, 21 Jan 2025 16:32:00 +0100 Subject: [PATCH 02/18] Minor fix --- routes/(apps)/mobility/(_islands)/ConsultStudents.tsx | 3 --- routes/(apps)/mobility/api/{promo.ts => promotions.ts} | 0 2 files changed, 3 deletions(-) rename routes/(apps)/mobility/api/{promo.ts => promotions.ts} (100%) diff --git a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx index 8513a6b..e1a758b 100644 --- a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx +++ b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx @@ -21,7 +21,6 @@ export default function ConsultStudents() { useEffect(() => { const fetchPromotionsAndStudents = async () => { try { - // Récupérer toutes les promotions const promoResponse = await fetch("/mobility/api/promotions"); if (!promoResponse.ok) { throw new Error(`Error fetching promotions: ${promoResponse.statusText}`); @@ -29,14 +28,12 @@ export default function ConsultStudents() { const promos: Promotion[] = await promoResponse.json(); setPromotions(promos); - // Récupérer les étudiants const studentsResponse = await fetch("/mobility/api/insert_students"); if (!studentsResponse.ok) { throw new Error(`Error fetching students: ${studentsResponse.statusText}`); } const students: Student[] = await studentsResponse.json(); - // Grouper les étudiants par promotionId const grouped: Record = {}; for (const student of students) { if (!grouped[student.promotionId]) { diff --git a/routes/(apps)/mobility/api/promo.ts b/routes/(apps)/mobility/api/promotions.ts similarity index 100% rename from routes/(apps)/mobility/api/promo.ts rename to routes/(apps)/mobility/api/promotions.ts From c04505e95defbfd08dec2b9118091bc2c4c91abe Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Tue, 21 Jan 2025 16:46:19 +0100 Subject: [PATCH 03/18] Working DB with table promotions --- .../mobility/(_islands)/ConsultStudents.tsx | 92 ++++++++----------- .../mobility/(_islands)/UploadStudents.tsx | 52 ++++------- routes/(apps)/mobility/api/insert_students.ts | 73 +++++++-------- routes/(apps)/mobility/api/promotions.ts | 31 ------- 4 files changed, 87 insertions(+), 161 deletions(-) delete mode 100644 routes/(apps)/mobility/api/promotions.ts diff --git a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx index e1a758b..deeb2e6 100644 --- a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx +++ b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx @@ -11,83 +11,63 @@ interface Student { lastName: string; email: string; promotionId: number; + promotionName: string; } export default function ConsultStudents() { - const [promotions, setPromotions] = useState([]); - const [studentsByPromotion, setStudentsByPromotion] = useState>({}); + const [data, setData] = useState<{ promotions: Promotion[]; students: Student[] } | null>(null); const [error, setError] = useState(null); useEffect(() => { - const fetchPromotionsAndStudents = async () => { + const fetchData = async () => { try { - const promoResponse = await fetch("/mobility/api/promotions"); - if (!promoResponse.ok) { - throw new Error(`Error fetching promotions: ${promoResponse.statusText}`); + const response = await fetch("/mobility/api/insert_students"); + if (!response.ok) { + throw new Error(`Error fetching data: ${response.statusText}`); } - const promos: Promotion[] = await promoResponse.json(); - setPromotions(promos); - const studentsResponse = await fetch("/mobility/api/insert_students"); - if (!studentsResponse.ok) { - throw new Error(`Error fetching students: ${studentsResponse.statusText}`); - } - const students: Student[] = await studentsResponse.json(); - - const grouped: Record = {}; - for (const student of students) { - if (!grouped[student.promotionId]) { - grouped[student.promotionId] = []; - } - grouped[student.promotionId].push(student); - } - setStudentsByPromotion(grouped); + const result = await response.json(); + setData(result); } catch (err) { - console.error("Error fetching promotions or students:", err); + console.error("Error fetching data:", err); setError("Failed to load data. Please try again later."); } }; - fetchPromotionsAndStudents(); + fetchData(); }, []); return (

Consult Students

{error &&

{error}

} - {promotions.length === 0 ? ( -

No promotions found.

- ) : ( - promotions.map((promo) => ( -
-

Promotion: {promo.name}

- {studentsByPromotion[promo.id]?.length ? ( - - - - - - - + {data?.promotions.map((promo) => ( +
+

Promotion: {promo.name}

+
IDFirst NameLast NameEmail
+ + + + + + + + + + {data.students + .filter((student) => student.promotionId === promo.id) + .map((student) => ( + + + + + - - - {studentsByPromotion[promo.id].map((student) => ( - - - - - - - ))} - -
IDFirst NameLast NameEmail
{student.id}{student.firstName}{student.lastName}{student.email}
{student.id}{student.firstName}{student.lastName}{student.email}
- ) : ( -

No students in this promotion.

- )} -
- )) - )} + ))} + + + + ))}
); } diff --git a/routes/(apps)/mobility/(_islands)/UploadStudents.tsx b/routes/(apps)/mobility/(_islands)/UploadStudents.tsx index 763cdc4..bb9129b 100644 --- a/routes/(apps)/mobility/(_islands)/UploadStudents.tsx +++ b/routes/(apps)/mobility/(_islands)/UploadStudents.tsx @@ -11,18 +11,15 @@ export default function UploadStudents() { if (input.files && input.files.length > 0) { fileData.value = input.files[0]; statusMessage.value = "File selected: " + input.files[0].name; - console.log("File selected:", input.files[0].name); } else { fileData.value = null; statusMessage.value = "No file selected"; } }; - const confirmUpload = () => { - console.log("Confirm Upload"); + const confirmUpload = async () => { if (!fileData.value) { statusMessage.value = "Please select a file before confirming upload."; - console.error("Error: No file selected."); return; } @@ -30,42 +27,31 @@ export default function UploadStudents() { const reader = new FileReader(); reader.onload = async (e) => { - try { - const arrayBuffer = e.target?.result as ArrayBuffer; - const workbook = XLSX.read(arrayBuffer, { type: "array" }); + const arrayBuffer = e.target?.result as ArrayBuffer; + const workbook = XLSX.read(arrayBuffer, { type: "array" }); - for (const sheetName of workbook.SheetNames) { - const sheet = workbook.Sheets[sheetName]; - const data = XLSX.utils.sheet_to_json(sheet, { - header: ["Nom", "Prénom", "Mail"], - range: 1, // Ignorer les en-têtes - }); + for (const sheetName of workbook.SheetNames) { + const sheet = workbook.Sheets[sheetName]; + const data = XLSX.utils.sheet_to_json(sheet, { + header: ["Nom", "Prénom", "Mail"], + range: 1, // Ignorer les en-têtes + }); - console.log(`Data from sheet ${sheetName}:`, data); + const response = await fetch("/mobility/api/insert_students", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ promoName: sheetName, data }), + }); - const response = await fetch("/mobility/api/insert_students", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ promoName: sheetName, data }), - }); - - if (!response.ok) { - throw new Error( - `Failed to insert data for promotion ${sheetName}`, - ); - } + if (!response.ok) { + throw new Error(`Failed to insert data for promotion ${sheetName}`); } - - statusMessage.value = "Data uploaded and inserted successfully!"; - } catch (error) { - console.error("Error processing the file:", error); - statusMessage.value = - "Error processing the file. Please check its format."; } + + statusMessage.value = "Data uploaded and inserted successfully!"; }; - reader.onerror = (e) => { - console.error("FileReader error:", e); + reader.onerror = () => { statusMessage.value = "Error reading the file."; }; diff --git a/routes/(apps)/mobility/api/insert_students.ts b/routes/(apps)/mobility/api/insert_students.ts index 6fac691..d6e5fef 100644 --- a/routes/(apps)/mobility/api/insert_students.ts +++ b/routes/(apps)/mobility/api/insert_students.ts @@ -2,10 +2,19 @@ import { Handlers } from "$fresh/server.ts"; import { Database } from "@db/sqlite"; export const handler: Handlers = { - async GET(_request, context) { + async GET() { try { const db = new Database("databases/data/mobility.db"); + db.prepare( + ` + CREATE TABLE IF NOT EXISTS promotions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT UNIQUE NOT NULL + ); + ` + ).run(); + db.prepare( ` CREATE TABLE IF NOT EXISTS students ( @@ -16,24 +25,33 @@ export const handler: Handlers = { promotionId INTEGER NOT NULL, FOREIGN KEY (promotionId) REFERENCES promotions (id) ); - ` + ` ).run(); - const rows = db + const promotions = db.prepare("SELECT id, name FROM promotions").all(); + + const students = db .prepare( - "SELECT students.id, firstName, lastName, email, promotionId FROM students" + ` + SELECT students.id, firstName, lastName, email, promotionId, promotions.name AS promotionName + FROM students + JOIN promotions ON students.promotionId = promotions.id + ` ) .all(); db.close(); - return new Response(JSON.stringify(rows), { - status: 200, - headers: { "Content-Type": "application/json" }, - }); + return new Response( + JSON.stringify({ promotions, students }), + { + status: 200, + headers: { "Content-Type": "application/json" }, + } + ); } catch (error) { - console.error("Error fetching students:", error); - return new Response("Failed to fetch students", { status: 500 }); + console.error("Error fetching data:", error); + return new Response("Failed to fetch data", { status: 500 }); } }, @@ -52,33 +70,6 @@ export const handler: Handlers = { const db = new Database("databases/data/mobility.db"); - console.log("Database opened successfully"); - - db.prepare( - ` - CREATE TABLE IF NOT EXISTS promotions ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT UNIQUE NOT NULL - ); - ` - ).run(); - - db.prepare( - ` - CREATE TABLE IF NOT EXISTS students ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - firstName TEXT NOT NULL, - lastName TEXT NOT NULL, - email TEXT NOT NULL, - promotionId INTEGER NOT NULL, - FOREIGN KEY (promotionId) REFERENCES promotions (id) - ); - ` - ).run(); - - console.log("Tables ensured successfully"); - - // Insérer ou récupérer l'ID de la promotion db.prepare( "INSERT OR IGNORE INTO promotions (name) VALUES (?)" ).run(promoName); @@ -99,13 +90,13 @@ export const handler: Handlers = { insertQuery.run(student.Nom, student["Prénom"], student.Mail, promoId); } - console.log("All students inserted successfully"); db.close(); - return new Response("Students inserted successfully", { status: 201 }); + console.log("All data inserted successfully"); + return new Response("Data inserted successfully", { status: 201 }); } catch (error) { - console.error("Error inserting students:", error); - return new Response("Failed to insert students", { status: 500 }); + console.error("Error inserting data:", error); + return new Response("Failed to insert data", { status: 500 }); } }, }; diff --git a/routes/(apps)/mobility/api/promotions.ts b/routes/(apps)/mobility/api/promotions.ts deleted file mode 100644 index 288524b..0000000 --- a/routes/(apps)/mobility/api/promotions.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Handlers } from "$fresh/server.ts"; -import { Database } from "@db/sqlite"; - -export const handler: Handlers = { - async GET() { - try { - const db = new Database("databases/data/mobility.db"); - - db.prepare( - ` - CREATE TABLE IF NOT EXISTS promotions ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT UNIQUE NOT NULL - ); - ` - ).run(); - - const promotions = db.prepare("SELECT id, name FROM promotions").all(); - - db.close(); - - return new Response(JSON.stringify(promotions), { - status: 200, - headers: { "Content-Type": "application/json" }, - }); - } catch (error) { - console.error("Error fetching promotions:", error); - return new Response("Failed to fetch promotions", { status: 500 }); - } - }, -}; From b5fedbb4259b9fe03600b809ef920e8934fd7f7a Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Tue, 21 Jan 2025 17:29:59 +0100 Subject: [PATCH 04/18] Moved all student management tools into student app for global uses (working) --- fresh.gen.ts | 38 ++++++++++--------- routes/(apps)/mobility/(_props)/props.ts | 3 +- routes/(apps)/mobility/partials/students.tsx | 20 ---------- .../(_islands)/ConsultStudents.tsx | 2 +- .../(_islands)/EditStudents.tsx | 0 .../(_islands)/UploadStudents.tsx | 2 +- routes/(apps)/students/(_props)/props.ts | 6 ++- routes/(apps)/students/api/example.ts | 22 ----------- .../api/insert_students.ts | 0 .../students/partials/(admin)/consult.tsx | 17 +++++++++ .../students/partials/(admin)/upload.tsx | 17 +++++++++ routes/(apps)/students/partials/overview.tsx | 17 +++++++++ 12 files changed, 79 insertions(+), 65 deletions(-) delete mode 100644 routes/(apps)/mobility/partials/students.tsx rename routes/(apps)/{mobility => students}/(_islands)/ConsultStudents.tsx (96%) rename routes/(apps)/{mobility => students}/(_islands)/EditStudents.tsx (100%) rename routes/(apps)/{mobility => students}/(_islands)/UploadStudents.tsx (97%) delete mode 100644 routes/(apps)/students/api/example.ts rename routes/(apps)/{mobility => students}/api/insert_students.ts (100%) create mode 100644 routes/(apps)/students/partials/(admin)/consult.tsx create mode 100644 routes/(apps)/students/partials/(admin)/upload.tsx create mode 100644 routes/(apps)/students/partials/overview.tsx diff --git a/fresh.gen.ts b/fresh.gen.ts index a256829..be51c53 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -3,20 +3,21 @@ // This file is automatically updated during development when running `dev.ts`. import * as $_apps_layout from "./routes/(apps)/_layout.tsx"; -import * as $_apps_mobility_api_insert_students from "./routes/(apps)/mobility/api/insert_students.ts"; import * as $_apps_mobility_index from "./routes/(apps)/mobility/index.tsx"; import * as $_apps_mobility_partials_admin_mobility from "./routes/(apps)/mobility/partials/(admin)/mobility.tsx"; import * as $_apps_mobility_partials_index from "./routes/(apps)/mobility/partials/index.tsx"; import * as $_apps_mobility_partials_overview from "./routes/(apps)/mobility/partials/overview.tsx"; -import * as $_apps_mobility_partials_students from "./routes/(apps)/mobility/partials/students.tsx"; import * as $_apps_notes_index from "./routes/(apps)/notes/index.tsx"; import * as $_apps_notes_partials_admin_courses from "./routes/(apps)/notes/partials/(admin)/courses.tsx"; import * as $_apps_notes_partials_admin_students from "./routes/(apps)/notes/partials/(admin)/students.tsx"; import * as $_apps_notes_partials_index from "./routes/(apps)/notes/partials/index.tsx"; import * as $_apps_notes_partials_notes from "./routes/(apps)/notes/partials/notes.tsx"; -import * as $_apps_students_api_example from "./routes/(apps)/students/api/example.ts"; +import * as $_apps_students_api_insert_students from "./routes/(apps)/students/api/insert_students.ts"; import * as $_apps_students_index from "./routes/(apps)/students/index.tsx"; +import * as $_apps_students_partials_admin_consult from "./routes/(apps)/students/partials/(admin)/consult.tsx"; +import * as $_apps_students_partials_admin_upload from "./routes/(apps)/students/partials/(admin)/upload.tsx"; import * as $_apps_students_partials_index from "./routes/(apps)/students/partials/index.tsx"; +import * as $_apps_students_partials_overview from "./routes/(apps)/students/partials/overview.tsx"; import * as $_404 from "./routes/_404.tsx"; import * as $_app from "./routes/_app.tsx"; import * as $_middleware from "./routes/_middleware.ts"; @@ -28,18 +29,16 @@ import * as $logout from "./routes/logout.tsx"; import * as $_islands_AppNavigator from "./routes/(_islands)/AppNavigator.tsx"; import * as $_islands_Navbar from "./routes/(_islands)/Navbar.tsx"; import * as $_apps_mobility_islands_ConsultMobility from "./routes/(apps)/mobility/(_islands)/ConsultMobility.tsx"; -import * as $_apps_mobility_islands_ConsultStudents from "./routes/(apps)/mobility/(_islands)/ConsultStudents.tsx"; import * as $_apps_mobility_islands_EditMobility from "./routes/(apps)/mobility/(_islands)/EditMobility.tsx"; -import * as $_apps_mobility_islands_EditStudents from "./routes/(apps)/mobility/(_islands)/EditStudents.tsx"; import * as $_apps_mobility_islands_ImportFile from "./routes/(apps)/mobility/(_islands)/ImportFile.tsx"; -import * as $_apps_mobility_islands_UploadStudents from "./routes/(apps)/mobility/(_islands)/UploadStudents.tsx"; +import * as $_apps_students_islands_ConsultStudents from "./routes/(apps)/students/(_islands)/ConsultStudents.tsx"; +import * as $_apps_students_islands_EditStudents from "./routes/(apps)/students/(_islands)/EditStudents.tsx"; +import * as $_apps_students_islands_UploadStudents from "./routes/(apps)/students/(_islands)/UploadStudents.tsx"; import type { Manifest } from "$fresh/server.ts"; const manifest = { routes: { "./routes/(apps)/_layout.tsx": $_apps_layout, - "./routes/(apps)/mobility/api/insert_students.ts": - $_apps_mobility_api_insert_students, "./routes/(apps)/mobility/index.tsx": $_apps_mobility_index, "./routes/(apps)/mobility/partials/(admin)/mobility.tsx": $_apps_mobility_partials_admin_mobility, @@ -47,8 +46,6 @@ const manifest = { $_apps_mobility_partials_index, "./routes/(apps)/mobility/partials/overview.tsx": $_apps_mobility_partials_overview, - "./routes/(apps)/mobility/partials/students.tsx": - $_apps_mobility_partials_students, "./routes/(apps)/notes/index.tsx": $_apps_notes_index, "./routes/(apps)/notes/partials/(admin)/courses.tsx": $_apps_notes_partials_admin_courses, @@ -56,10 +53,17 @@ const manifest = { $_apps_notes_partials_admin_students, "./routes/(apps)/notes/partials/index.tsx": $_apps_notes_partials_index, "./routes/(apps)/notes/partials/notes.tsx": $_apps_notes_partials_notes, - "./routes/(apps)/students/api/example.ts": $_apps_students_api_example, + "./routes/(apps)/students/api/insert_students.ts": + $_apps_students_api_insert_students, "./routes/(apps)/students/index.tsx": $_apps_students_index, + "./routes/(apps)/students/partials/(admin)/consult.tsx": + $_apps_students_partials_admin_consult, + "./routes/(apps)/students/partials/(admin)/upload.tsx": + $_apps_students_partials_admin_upload, "./routes/(apps)/students/partials/index.tsx": $_apps_students_partials_index, + "./routes/(apps)/students/partials/overview.tsx": + $_apps_students_partials_overview, "./routes/_404.tsx": $_404, "./routes/_app.tsx": $_app, "./routes/_middleware.ts": $_middleware, @@ -74,16 +78,16 @@ const manifest = { "./routes/(_islands)/Navbar.tsx": $_islands_Navbar, "./routes/(apps)/mobility/(_islands)/ConsultMobility.tsx": $_apps_mobility_islands_ConsultMobility, - "./routes/(apps)/mobility/(_islands)/ConsultStudents.tsx": - $_apps_mobility_islands_ConsultStudents, "./routes/(apps)/mobility/(_islands)/EditMobility.tsx": $_apps_mobility_islands_EditMobility, - "./routes/(apps)/mobility/(_islands)/EditStudents.tsx": - $_apps_mobility_islands_EditStudents, "./routes/(apps)/mobility/(_islands)/ImportFile.tsx": $_apps_mobility_islands_ImportFile, - "./routes/(apps)/mobility/(_islands)/UploadStudents.tsx": - $_apps_mobility_islands_UploadStudents, + "./routes/(apps)/students/(_islands)/ConsultStudents.tsx": + $_apps_students_islands_ConsultStudents, + "./routes/(apps)/students/(_islands)/EditStudents.tsx": + $_apps_students_islands_EditStudents, + "./routes/(apps)/students/(_islands)/UploadStudents.tsx": + $_apps_students_islands_UploadStudents, }, baseUrl: import.meta.url, } satisfies Manifest; diff --git a/routes/(apps)/mobility/(_props)/props.ts b/routes/(apps)/mobility/(_props)/props.ts index b324ead..6003875 100644 --- a/routes/(apps)/mobility/(_props)/props.ts +++ b/routes/(apps)/mobility/(_props)/props.ts @@ -8,9 +8,8 @@ const properties: AppProperties = { index: "Homepage", overview: "Mobility overview", mobility: "Mobility management", - students: "Students management", }, - adminOnly: ["students"], + adminOnly: ["mobility"], }; export default properties; diff --git a/routes/(apps)/mobility/partials/students.tsx b/routes/(apps)/mobility/partials/students.tsx deleted file mode 100644 index f3c7cb9..0000000 --- a/routes/(apps)/mobility/partials/students.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { RouteConfig } from "$fresh/server.ts"; -import UploadStudents from "../(_islands)/UploadStudents.tsx"; -import ConsultStudents from "../(_islands)/ConsultStudents.tsx"; -//import EditStudents from "../(_islands)/EditStudents.tsx"; - -export const config: RouteConfig = { - skipAppWrapper: false, - skipInheritedLayouts: false, -}; - -export default function Students() { - return ( -
-

Manage Promotions

- -
- -
- ); -} diff --git a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx b/routes/(apps)/students/(_islands)/ConsultStudents.tsx similarity index 96% rename from routes/(apps)/mobility/(_islands)/ConsultStudents.tsx rename to routes/(apps)/students/(_islands)/ConsultStudents.tsx index deeb2e6..7b097db 100644 --- a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx +++ b/routes/(apps)/students/(_islands)/ConsultStudents.tsx @@ -21,7 +21,7 @@ export default function ConsultStudents() { useEffect(() => { const fetchData = async () => { try { - const response = await fetch("/mobility/api/insert_students"); + const response = await fetch("/students/api/insert_students"); if (!response.ok) { throw new Error(`Error fetching data: ${response.statusText}`); } diff --git a/routes/(apps)/mobility/(_islands)/EditStudents.tsx b/routes/(apps)/students/(_islands)/EditStudents.tsx similarity index 100% rename from routes/(apps)/mobility/(_islands)/EditStudents.tsx rename to routes/(apps)/students/(_islands)/EditStudents.tsx diff --git a/routes/(apps)/mobility/(_islands)/UploadStudents.tsx b/routes/(apps)/students/(_islands)/UploadStudents.tsx similarity index 97% rename from routes/(apps)/mobility/(_islands)/UploadStudents.tsx rename to routes/(apps)/students/(_islands)/UploadStudents.tsx index bb9129b..10ed4e2 100644 --- a/routes/(apps)/mobility/(_islands)/UploadStudents.tsx +++ b/routes/(apps)/students/(_islands)/UploadStudents.tsx @@ -37,7 +37,7 @@ export default function UploadStudents() { range: 1, // Ignorer les en-têtes }); - const response = await fetch("/mobility/api/insert_students", { + const response = await fetch("/students/api/insert_students", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ promoName: sheetName, data }), diff --git a/routes/(apps)/students/(_props)/props.ts b/routes/(apps)/students/(_props)/props.ts index 0a7a522..54ecaab 100644 --- a/routes/(apps)/students/(_props)/props.ts +++ b/routes/(apps)/students/(_props)/props.ts @@ -5,10 +5,12 @@ const properties: AppProperties = { icon: "badge", pages: { index: "Homepage", + overview: "Students overview", upload: "Upload students", + consult: "Consult students" }, - adminOnly: ["upload"], - hint: "See student information", + adminOnly: ["upload", "consult"], + hint: "Create students promotion and see informations", }; export default properties; diff --git a/routes/(apps)/students/api/example.ts b/routes/(apps)/students/api/example.ts deleted file mode 100644 index 9f04cd1..0000000 --- a/routes/(apps)/students/api/example.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Handlers } from "$fresh/server.ts"; - -export const handler: Handlers = { - async POST(request, context) { - if (request.headers.get("content-type") != "application/json") { - return new Response(null, { - status: 400, - }); - } - - const responseBody = { - requestBody: await request.json(), - context, - }; - - return new Response(JSON.stringify(responseBody), { - headers: { - "content-type": "application/json", - }, - }); - }, -}; diff --git a/routes/(apps)/mobility/api/insert_students.ts b/routes/(apps)/students/api/insert_students.ts similarity index 100% rename from routes/(apps)/mobility/api/insert_students.ts rename to routes/(apps)/students/api/insert_students.ts diff --git a/routes/(apps)/students/partials/(admin)/consult.tsx b/routes/(apps)/students/partials/(admin)/consult.tsx new file mode 100644 index 0000000..7106daf --- /dev/null +++ b/routes/(apps)/students/partials/(admin)/consult.tsx @@ -0,0 +1,17 @@ +import ConsultStudents from "$root/routes/(apps)/students/(_islands)/ConsultStudents.tsx"; +import { getPartialsConfig, makePartials } from "$root/defaults/makePartials.tsx"; +import { FreshContext } from "$fresh/server.ts"; +import { State } from "$root/routes/_middleware.ts"; +//import EditStudents from "../(_islands)/EditStudents.tsx"; + +async function Students(_request: Request, _context: FreshContext) { + return ( + <> +

Manage Promotions

+ + + ); +} + +export const config = getPartialsConfig(); +export default makePartials(Students); diff --git a/routes/(apps)/students/partials/(admin)/upload.tsx b/routes/(apps)/students/partials/(admin)/upload.tsx new file mode 100644 index 0000000..0010328 --- /dev/null +++ b/routes/(apps)/students/partials/(admin)/upload.tsx @@ -0,0 +1,17 @@ +import UploadStudents from "$root/routes/(apps)/students/(_islands)/UploadStudents.tsx"; +import { getPartialsConfig, makePartials } from "$root/defaults/makePartials.tsx"; +import { FreshContext } from "$fresh/server.ts"; +import { State } from "$root/routes/_middleware.ts"; +//import EditStudents from "../(_islands)/EditStudents.tsx"; + +async function Students(_request: Request, _context: FreshContext) { + return ( + <> +

Manage Promotions

+ + + ); +} + +export const config = getPartialsConfig(); +export default makePartials(Students); diff --git a/routes/(apps)/students/partials/overview.tsx b/routes/(apps)/students/partials/overview.tsx new file mode 100644 index 0000000..ceac77c --- /dev/null +++ b/routes/(apps)/students/partials/overview.tsx @@ -0,0 +1,17 @@ +import { Partial } from "$fresh/runtime.ts"; +import { RouteConfig } from "$fresh/server.ts"; + +type ModulesProps = Record; + +export const config: RouteConfig = { + skipAppWrapper: true, + skipInheritedLayouts: true, +}; + +export default function Modules(_props: ModulesProps) { + return ( + + students + + ); +} From 5e75c688c8acedc2ef7e1e8c5aae8c941af48fb6 Mon Sep 17 00:00:00 2001 From: Kevin FEDYNA Date: Tue, 21 Jan 2025 23:49:52 +0100 Subject: [PATCH 05/18] Added layer of abstraction for database connection --- databases/connect.ts | 20 +++++++ databases/init/students.sql | 12 ++-- routes/(apps)/students/api/insert_students.ts | 58 +++++-------------- 3 files changed, 41 insertions(+), 49 deletions(-) create mode 100644 databases/connect.ts diff --git a/databases/connect.ts b/databases/connect.ts new file mode 100644 index 0000000..7836dcd --- /dev/null +++ b/databases/connect.ts @@ -0,0 +1,20 @@ +import { Database } from "@db/sqlite"; + +interface DatabaseConnection extends Disposable { + database: Database; +} + +export default function connect(database: string): DatabaseConnection { + const connection = new Database(`databases/data/${database}.db`, { + create: false, + }); + + connection.run("attach database 'databases/data/students.db' as students"); + + return { + database: connection, + [Symbol.dispose]: () => { + connection.close(); + }, + }; +} diff --git a/databases/init/students.sql b/databases/init/students.sql index b503221..44ed2d3 100644 --- a/databases/init/students.sql +++ b/databases/init/students.sql @@ -1,3 +1,9 @@ +create table promotions ( + id integer primary key autoincrement, + endyear integer, + current integer +); + create table students ( userId text primary key, firstName text, @@ -5,10 +11,4 @@ create table students ( mail text, promo integer, foreign key(promo) references promo(id) -); - -create table promo ( - id integer, - endyear integer, - current integer ); \ No newline at end of file diff --git a/routes/(apps)/students/api/insert_students.ts b/routes/(apps)/students/api/insert_students.ts index d6e5fef..df81011 100644 --- a/routes/(apps)/students/api/insert_students.ts +++ b/routes/(apps)/students/api/insert_students.ts @@ -1,53 +1,27 @@ import { Handlers } from "$fresh/server.ts"; -import { Database } from "@db/sqlite"; +import connect from "$root/databases/connect.ts"; export const handler: Handlers = { async GET() { try { - const db = new Database("databases/data/mobility.db"); + using connection = connect("students"); - db.prepare( - ` - CREATE TABLE IF NOT EXISTS promotions ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT UNIQUE NOT NULL - ); - ` - ).run(); + const promotions = connection.database.prepare( + "select id from promotions", + ).all(); - db.prepare( - ` - CREATE TABLE IF NOT EXISTS students ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - firstName TEXT NOT NULL, - lastName TEXT NOT NULL, - email TEXT NOT NULL, - promotionId INTEGER NOT NULL, - FOREIGN KEY (promotionId) REFERENCES promotions (id) - ); - ` - ).run(); - - const promotions = db.prepare("SELECT id, name FROM promotions").all(); - - const students = db + const students = connection.database .prepare( - ` - SELECT students.id, firstName, lastName, email, promotionId, promotions.name AS promotionName - FROM students - JOIN promotions ON students.promotionId = promotions.id - ` + `select userId, firstName, lastName, mail, promo from students`, ) .all(); - db.close(); - return new Response( JSON.stringify({ promotions, students }), { status: 200, headers: { "Content-Type": "application/json" }, - } + }, ); } catch (error) { console.error("Error fetching data:", error); @@ -68,21 +42,21 @@ export const handler: Handlers = { throw new Error("Invalid request body"); } - const db = new Database("databases/data/mobility.db"); + using connection = connect("students"); - db.prepare( - "INSERT OR IGNORE INTO promotions (name) VALUES (?)" + connection.database.prepare( + "INSERT OR IGNORE INTO promotions (name) VALUES (?)", ).run(promoName); - const promoIdRow = db + const promoIdRow: {id: string} = connection.database .prepare("SELECT id FROM promotions WHERE name = ?") - .get(promoName); + .get(promoName)!; const promoId = promoIdRow.id; console.log(`Promotion ID for "${promoName}":`, promoId); - const insertQuery = db.prepare( - "INSERT INTO students (firstName, lastName, email, promotionId) VALUES (?, ?, ?, ?)" + const insertQuery = connection.database.prepare( + "INSERT INTO students (firstName, lastName, email, promotionId) VALUES (?, ?, ?, ?)", ); for (const student of data) { @@ -90,8 +64,6 @@ export const handler: Handlers = { insertQuery.run(student.Nom, student["Prénom"], student.Mail, promoId); } - db.close(); - console.log("All data inserted successfully"); return new Response("Data inserted successfully", { status: 201 }); } catch (error) { From d767cb089894fb09b87ea403cd7fa1ea54e9dc3a Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Wed, 22 Jan 2025 11:00:18 +0100 Subject: [PATCH 06/18] Minor fix for DB (working) --- databases/init/students.sql | 5 +++-- routes/(apps)/students/(_islands)/ConsultStudents.tsx | 6 +++--- routes/(apps)/students/api/insert_students.ts | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/databases/init/students.sql b/databases/init/students.sql index 44ed2d3..63fffe4 100644 --- a/databases/init/students.sql +++ b/databases/init/students.sql @@ -1,5 +1,6 @@ create table promotions ( id integer primary key autoincrement, + name text, endyear integer, current integer ); @@ -9,6 +10,6 @@ create table students ( firstName text, lastName text, mail text, - promo integer, - foreign key(promo) references promo(id) + promotionId integer, + foreign key(promotionId) references promotions(id) ); \ No newline at end of file diff --git a/routes/(apps)/students/(_islands)/ConsultStudents.tsx b/routes/(apps)/students/(_islands)/ConsultStudents.tsx index 7b097db..da24056 100644 --- a/routes/(apps)/students/(_islands)/ConsultStudents.tsx +++ b/routes/(apps)/students/(_islands)/ConsultStudents.tsx @@ -9,7 +9,7 @@ interface Student { id: number; firstName: string; lastName: string; - email: string; + mail: string; promotionId: number; promotionName: string; } @@ -43,7 +43,7 @@ export default function ConsultStudents() { {error &&

{error}

} {data?.promotions.map((promo) => (
-

Promotion: {promo.name}

+

Promotion: {promo.id}

@@ -61,7 +61,7 @@ export default function ConsultStudents() { - + ))} diff --git a/routes/(apps)/students/api/insert_students.ts b/routes/(apps)/students/api/insert_students.ts index df81011..98b11cb 100644 --- a/routes/(apps)/students/api/insert_students.ts +++ b/routes/(apps)/students/api/insert_students.ts @@ -12,7 +12,7 @@ export const handler: Handlers = { const students = connection.database .prepare( - `select userId, firstName, lastName, mail, promo from students`, + `select userId, firstName, lastName, mail, promotionId from students`, ) .all(); @@ -56,7 +56,7 @@ export const handler: Handlers = { console.log(`Promotion ID for "${promoName}":`, promoId); const insertQuery = connection.database.prepare( - "INSERT INTO students (firstName, lastName, email, promotionId) VALUES (?, ?, ?, ?)", + "INSERT INTO students (firstName, lastName, mail, promotionId) VALUES (?, ?, ?, ?)", ); for (const student of data) { From 36c5c9cf39ce086abf5272cf2287bc65ca2b6edb Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Wed, 22 Jan 2025 11:35:47 +0100 Subject: [PATCH 07/18] Test to access student DB in other apps (working) --- fresh.gen.ts | 6 ++ .../(_islands)/ConsultStudents_test.tsx | 73 +++++++++++++++++++ routes/(apps)/mobility/(_props)/props.ts | 3 +- .../mobility/api/insert_students_test.ts | 31 ++++++++ .../(admin)/consult_students_test.tsx | 17 +++++ routes/(apps)/mobility/partials/index.tsx | 10 +-- 6 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx create mode 100644 routes/(apps)/mobility/api/insert_students_test.ts create mode 100644 routes/(apps)/mobility/partials/(admin)/consult_students_test.tsx diff --git a/fresh.gen.ts b/fresh.gen.ts index be51c53..654e3be 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -5,6 +5,7 @@ import * as $_apps_layout from "./routes/(apps)/_layout.tsx"; import * as $_apps_mobility_index from "./routes/(apps)/mobility/index.tsx"; import * as $_apps_mobility_partials_admin_mobility from "./routes/(apps)/mobility/partials/(admin)/mobility.tsx"; +import * as $_apps_mobility_partials_admin_consult_students_test from "./routes/(apps)/mobility/partials/(admin)/consult_students_test.tsx"; import * as $_apps_mobility_partials_index from "./routes/(apps)/mobility/partials/index.tsx"; import * as $_apps_mobility_partials_overview from "./routes/(apps)/mobility/partials/overview.tsx"; import * as $_apps_notes_index from "./routes/(apps)/notes/index.tsx"; @@ -29,6 +30,7 @@ import * as $logout from "./routes/logout.tsx"; import * as $_islands_AppNavigator from "./routes/(_islands)/AppNavigator.tsx"; import * as $_islands_Navbar from "./routes/(_islands)/Navbar.tsx"; import * as $_apps_mobility_islands_ConsultMobility from "./routes/(apps)/mobility/(_islands)/ConsultMobility.tsx"; +import * as $_apps_mobility_islands_ConsultStudents_test from "./routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx"; import * as $_apps_mobility_islands_EditMobility from "./routes/(apps)/mobility/(_islands)/EditMobility.tsx"; import * as $_apps_mobility_islands_ImportFile from "./routes/(apps)/mobility/(_islands)/ImportFile.tsx"; import * as $_apps_students_islands_ConsultStudents from "./routes/(apps)/students/(_islands)/ConsultStudents.tsx"; @@ -42,6 +44,8 @@ const manifest = { "./routes/(apps)/mobility/index.tsx": $_apps_mobility_index, "./routes/(apps)/mobility/partials/(admin)/mobility.tsx": $_apps_mobility_partials_admin_mobility, + "./routes/(apps)/mobility/partials/(admin)/consult_students_test.tsx": + $_apps_mobility_partials_admin_consult_students_test, "./routes/(apps)/mobility/partials/index.tsx": $_apps_mobility_partials_index, "./routes/(apps)/mobility/partials/overview.tsx": @@ -78,6 +82,8 @@ const manifest = { "./routes/(_islands)/Navbar.tsx": $_islands_Navbar, "./routes/(apps)/mobility/(_islands)/ConsultMobility.tsx": $_apps_mobility_islands_ConsultMobility, + "./routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx": + $_apps_mobility_islands_ConsultStudents_test, "./routes/(apps)/mobility/(_islands)/EditMobility.tsx": $_apps_mobility_islands_EditMobility, "./routes/(apps)/mobility/(_islands)/ImportFile.tsx": diff --git a/routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx b/routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx new file mode 100644 index 0000000..f05ba34 --- /dev/null +++ b/routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx @@ -0,0 +1,73 @@ +import { useEffect, useState } from "preact/hooks"; + +interface Promotion { + id: number; + name: string; +} + +interface Student { + id: number; + firstName: string; + lastName: string; + mail: string; + promotionId: number; + promotionName: string; +} + +export default function ConsultStudents_test() { + const [data, setData] = useState<{ promotions: Promotion[]; students: Student[] } | null>(null); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await fetch("/students/api/insert_students"); + if (!response.ok) { + throw new Error(`Error fetching data: ${response.statusText}`); + } + + const result = await response.json(); + setData(result); + } catch (err) { + console.error("Error fetching data:", err); + setError("Failed to load data. Please try again later."); + } + }; + + fetchData(); + }, []); + + return ( +
+

Consult Students

+ {error &&

{error}

} + {data?.promotions.map((promo) => ( +
+

Promotion: {promo.id}

+
{student.id} {student.firstName} {student.lastName}{student.email}{student.mail}
+ + + + + + + + + + {data.students + .filter((student) => student.promotionId === promo.id) + .map((student) => ( + + + + + + + ))} + +
IDFirst NameLast NameEmail
{student.id}{student.firstName}{student.lastName}{student.mail}
+
+ ))} + + ); +} diff --git a/routes/(apps)/mobility/(_props)/props.ts b/routes/(apps)/mobility/(_props)/props.ts index 6003875..82165f2 100644 --- a/routes/(apps)/mobility/(_props)/props.ts +++ b/routes/(apps)/mobility/(_props)/props.ts @@ -8,8 +8,9 @@ const properties: AppProperties = { index: "Homepage", overview: "Mobility overview", mobility: "Mobility management", + consult_students_test: "Test consult students", }, - adminOnly: ["mobility"], + adminOnly: ["mobility", "consult_students_test"], }; export default properties; diff --git a/routes/(apps)/mobility/api/insert_students_test.ts b/routes/(apps)/mobility/api/insert_students_test.ts new file mode 100644 index 0000000..d0123af --- /dev/null +++ b/routes/(apps)/mobility/api/insert_students_test.ts @@ -0,0 +1,31 @@ +import { Handlers } from "$fresh/server.ts"; +import connect from "$root/databases/connect.ts"; + +export const handler: Handlers = { + async GET() { + try { + using connection = connect("students"); + + const promotions = connection.database.prepare( + "select id from promotions", + ).all(); + + const students = connection.database + .prepare( + `select userId, firstName, lastName, mail, promotionId from students`, + ) + .all(); + + return new Response( + JSON.stringify({ promotions, students }), + { + status: 200, + headers: { "Content-Type": "application/json" }, + }, + ); + } catch (error) { + console.error("Error fetching data:", error); + return new Response("Failed to fetch data", { status: 500 }); + } + }, +}; diff --git a/routes/(apps)/mobility/partials/(admin)/consult_students_test.tsx b/routes/(apps)/mobility/partials/(admin)/consult_students_test.tsx new file mode 100644 index 0000000..ee5d9c1 --- /dev/null +++ b/routes/(apps)/mobility/partials/(admin)/consult_students_test.tsx @@ -0,0 +1,17 @@ +import ConsultStudents_test from "$root/routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx"; +import { getPartialsConfig, makePartials } from "$root/defaults/makePartials.tsx"; +import { FreshContext } from "$fresh/server.ts"; +import { State } from "$root/routes/_middleware.ts"; +//import EditStudents from "../(_islands)/EditStudents.tsx"; + +async function Mobility(_request: Request, _context: FreshContext) { + return ( + <> +

Test consult students

+ + + ); +} + +export const config = getPartialsConfig(); +export default makePartials(Mobility); diff --git a/routes/(apps)/mobility/partials/index.tsx b/routes/(apps)/mobility/partials/index.tsx index a5cffdb..2971e0e 100644 --- a/routes/(apps)/mobility/partials/index.tsx +++ b/routes/(apps)/mobility/partials/index.tsx @@ -2,12 +2,12 @@ import { getPartialsConfig, makePartials, } from "$root/defaults/makePartials.tsx"; -import { EmptyObject } from "$root/defaults/interfaces.ts"; +import { FreshContext } from "$fresh/server.ts"; +import { State } from "$root/routes/_middleware.ts"; -type MobilityIndexProps = EmptyObject; - -export function Index(_props: MobilityIndexProps) { - return

Nothing to see here...

; +// deno-lint-ignore require-await +export async function Index(_request: Request, context: FreshContext) { + return

Welcome to {context.state.session?.displayName}.

; } export const config = getPartialsConfig(); From 6456529b7f0e9973bc58fd38a102ea133018ff0e Mon Sep 17 00:00:00 2001 From: Kevin FEDYNA Date: Wed, 22 Jan 2025 14:48:00 +0100 Subject: [PATCH 08/18] Added documentation for connect file --- databases/connect.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/databases/connect.ts b/databases/connect.ts index 7836dcd..1a6bbdc 100644 --- a/databases/connect.ts +++ b/databases/connect.ts @@ -4,6 +4,11 @@ interface DatabaseConnection extends Disposable { database: Database; } +/** + * Connect to the given database and attach `students.db`. + * @param database The database name. + * @returns The database connection as disposable. + */ export default function connect(database: string): DatabaseConnection { const connection = new Database(`databases/data/${database}.db`, { create: false, From 4abf5405589b3a61bcef180962fee448d41bc11c Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Wed, 22 Jan 2025 15:09:22 +0100 Subject: [PATCH 09/18] Init mobility DB --- databases/init/mobility.sql | 11 ++ databases/init/students.sql | 2 +- fresh.gen.ts | 6 +- .../mobility/(_islands)/EditMobility.tsx | 157 ++++++++++++++++++ routes/(apps)/mobility/(_props)/props.ts | 4 +- routes/(apps)/mobility/api/insert_mobility.ts | 96 +++++++++++ .../partials/(admin)/edit_mobility.tsx | 16 ++ .../mobility/partials/(admin)/mobility.tsx | 17 -- 8 files changed, 286 insertions(+), 23 deletions(-) create mode 100644 routes/(apps)/mobility/api/insert_mobility.ts create mode 100644 routes/(apps)/mobility/partials/(admin)/edit_mobility.tsx delete mode 100644 routes/(apps)/mobility/partials/(admin)/mobility.tsx diff --git a/databases/init/mobility.sql b/databases/init/mobility.sql index e69de29..fe503d4 100644 --- a/databases/init/mobility.sql +++ b/databases/init/mobility.sql @@ -0,0 +1,11 @@ +CREATE TABLE mobility ( + id integer primary key autoincrement, + studentId text, + startDate date, + endDate date, + weeksCount integer, + destinationCountry text, + destinationName text, + mobilityStatus text default 'N/A', + foreign key (studentId) references students(userId) +); \ No newline at end of file diff --git a/databases/init/students.sql b/databases/init/students.sql index 63fffe4..4dbc7e8 100644 --- a/databases/init/students.sql +++ b/databases/init/students.sql @@ -1,6 +1,6 @@ create table promotions ( id integer primary key autoincrement, - name text, + name text, endyear integer, current integer ); diff --git a/fresh.gen.ts b/fresh.gen.ts index 654e3be..58412fb 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -4,7 +4,7 @@ import * as $_apps_layout from "./routes/(apps)/_layout.tsx"; import * as $_apps_mobility_index from "./routes/(apps)/mobility/index.tsx"; -import * as $_apps_mobility_partials_admin_mobility from "./routes/(apps)/mobility/partials/(admin)/mobility.tsx"; +import * as $_apps_mobility_partials_admin_edit_mobility from "./routes/(apps)/mobility/partials/(admin)/edit_mobility.tsx"; import * as $_apps_mobility_partials_admin_consult_students_test from "./routes/(apps)/mobility/partials/(admin)/consult_students_test.tsx"; import * as $_apps_mobility_partials_index from "./routes/(apps)/mobility/partials/index.tsx"; import * as $_apps_mobility_partials_overview from "./routes/(apps)/mobility/partials/overview.tsx"; @@ -42,8 +42,8 @@ const manifest = { routes: { "./routes/(apps)/_layout.tsx": $_apps_layout, "./routes/(apps)/mobility/index.tsx": $_apps_mobility_index, - "./routes/(apps)/mobility/partials/(admin)/mobility.tsx": - $_apps_mobility_partials_admin_mobility, + "./routes/(apps)/mobility/partials/(admin)/edit_mobility.tsx": + $_apps_mobility_partials_admin_edit_mobility, "./routes/(apps)/mobility/partials/(admin)/consult_students_test.tsx": $_apps_mobility_partials_admin_consult_students_test, "./routes/(apps)/mobility/partials/index.tsx": diff --git a/routes/(apps)/mobility/(_islands)/EditMobility.tsx b/routes/(apps)/mobility/(_islands)/EditMobility.tsx index e69de29..43b80ef 100644 --- a/routes/(apps)/mobility/(_islands)/EditMobility.tsx +++ b/routes/(apps)/mobility/(_islands)/EditMobility.tsx @@ -0,0 +1,157 @@ +import { useEffect, useState } from "preact/hooks"; + +interface MobilityData { + id: number; + studentId: string; + firstName: string; + lastName: string; + startDate: string | null; + endDate: string | null; + weeksCount: number | null; + destinationCountry: string | null; + destinationName: string | null; + mobilityStatus: string; +} + +export default function EditMobility() { + const [mobilityData, setMobilityData] = useState([]); + const [isSaving, setIsSaving] = useState(false); + + useEffect(() => { + async function fetchMobilityData() { + const response = await fetch("/mobility/api/insert_mobility"); + const data = await response.json(); + setMobilityData(data.mobilities || []); + } + + fetchMobilityData(); + }, []); + + const handleChange = ( + id: number, + field: keyof MobilityData, + value: string | number | null, + ) => { + setMobilityData((prev) => + prev.map((entry) => + entry.id === id ? { ...entry, [field]: value } : entry, + ) + ); + }; + + const handleSave = async () => { + setIsSaving(true); + + try { + const response = await fetch("/mobility/api/insert_mobility", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ data: mobilityData }), + }); + + if (response.ok) { + alert("Data saved successfully!"); + } else { + alert("Failed to save data."); + } + } catch (error) { + console.error("Error saving data:", error); + alert("An error occurred while saving data."); + } finally { + setIsSaving(false); + } + }; + + return ( +
+ + + + + + + + + + + + + + + {mobilityData.map((mobility) => ( + + + + + + + + + + + ))} + +
First NameLast NameStart DateEnd DateWeeks CountDestination CountryDestination NameStatus
{mobility.firstName}{mobility.lastName} + + handleChange(mobility.id, "startDate", e.target.value) + } + /> + + + handleChange(mobility.id, "endDate", e.target.value) + } + /> + + + handleChange( + mobility.id, + "weeksCount", + Number(e.target.value) || null, + ) + } + /> + + + handleChange(mobility.id, "destinationCountry", e.target.value) + } + /> + + + handleChange(mobility.id, "destinationName", e.target.value) + } + /> + + +
+ +
+ ); +} diff --git a/routes/(apps)/mobility/(_props)/props.ts b/routes/(apps)/mobility/(_props)/props.ts index 82165f2..75a91b4 100644 --- a/routes/(apps)/mobility/(_props)/props.ts +++ b/routes/(apps)/mobility/(_props)/props.ts @@ -7,10 +7,10 @@ const properties: AppProperties = { pages: { index: "Homepage", overview: "Mobility overview", - mobility: "Mobility management", + edit_mobility: "Mobility management", consult_students_test: "Test consult students", }, - adminOnly: ["mobility", "consult_students_test"], + adminOnly: ["edit_mobility", "consult_students_test"], }; export default properties; diff --git a/routes/(apps)/mobility/api/insert_mobility.ts b/routes/(apps)/mobility/api/insert_mobility.ts new file mode 100644 index 0000000..2d5b3f9 --- /dev/null +++ b/routes/(apps)/mobility/api/insert_mobility.ts @@ -0,0 +1,96 @@ +import { Handlers } from "$fresh/server.ts"; +import connect from "$root/databases/connect.ts"; + +export const handler: Handlers = { + async GET() { + try { + using connection = connect("mobility"); + + const mobilities = connection.database.prepare( + `SELECT + mobility.id, + mobility.studentId, + students.firstName, + students.lastName, + mobility.startDate, + mobility.endDate, + mobility.weeksCount, + mobility.destinationCountry, + mobility.destinationName, + mobility.mobilityStatus + FROM mobility + LEFT JOIN students ON mobility.studentId = students.userId`, + ).all(); + + return new Response( + JSON.stringify({ mobilities }), + { + status: 200, + headers: { "Content-Type": "application/json" }, + }, + ); + } catch (error) { + console.error("Error fetching mobility data:", error); + return new Response("Failed to fetch data", { status: 500 }); + } + }, + + async POST(request) { + console.log("API /mobility/api/update_mobility called"); + + try { + const body = await request.json(); + const { data } = body; + + if (!Array.isArray(data)) { + throw new Error("Invalid request body"); + } + + using connection = connect("mobility"); + + const updateQuery = connection.database.prepare( + `INSERT INTO mobility ( + id, studentId, startDate, endDate, weeksCount, destinationCountry, destinationName, mobilityStatus + ) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(id) DO UPDATE SET + startDate = excluded.startDate, + endDate = excluded.endDate, + weeksCount = excluded.weeksCount, + destinationCountry = excluded.destinationCountry, + destinationName = excluded.destinationName, + mobilityStatus = excluded.mobilityStatus` + ); + + for (const mobility of data) { + const { + id, + studentId, + startDate, + endDate, + weeksCount, + destinationCountry, + destinationName, + mobilityStatus = "N/A", + } = mobility; + + updateQuery.run( + id, + studentId, + startDate, + endDate, + weeksCount, + destinationCountry, + destinationName, + mobilityStatus + ); + } + + console.log("Mobility data updated successfully"); + return new Response("Data updated successfully", { status: 200 }); + } catch (error) { + console.error("Error updating mobility data:", error); + return new Response("Failed to update data", { status: 500 }); + } + }, +}; diff --git a/routes/(apps)/mobility/partials/(admin)/edit_mobility.tsx b/routes/(apps)/mobility/partials/(admin)/edit_mobility.tsx new file mode 100644 index 0000000..e7a1df1 --- /dev/null +++ b/routes/(apps)/mobility/partials/(admin)/edit_mobility.tsx @@ -0,0 +1,16 @@ +import EditMobility from "$root/routes/(apps)/mobility/(_islands)/EditMobility.tsx"; +import { getPartialsConfig, makePartials } from "$root/defaults/makePartials.tsx"; +import { FreshContext } from "$fresh/server.ts"; +import { State } from "$root/routes/_middleware.ts"; + +async function Mobility(_request: Request, _context: FreshContext) { + return ( + <> +

Edit mobility

+ + + ); +} + +export const config = getPartialsConfig(); +export default makePartials(Mobility); diff --git a/routes/(apps)/mobility/partials/(admin)/mobility.tsx b/routes/(apps)/mobility/partials/(admin)/mobility.tsx deleted file mode 100644 index a73c859..0000000 --- a/routes/(apps)/mobility/partials/(admin)/mobility.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Partial } from "$fresh/runtime.ts"; -import { RouteConfig } from "$fresh/server.ts"; - -type ModulesProps = Record; - -export const config: RouteConfig = { - skipAppWrapper: true, - skipInheritedLayouts: true, -}; - -export default function Modules(_props: ModulesProps) { - return ( - - mobility - - ); -} From b835495e15569e744d06a6955b06021b157adb48 Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Wed, 22 Jan 2025 17:06:42 +0100 Subject: [PATCH 10/18] Consult mobility (not working yet) --- .../mobility/(_islands)/ConsultMobility.tsx | 87 +++++++++++++++++++ routes/(apps)/mobility/partials/overview.tsx | 25 +++--- 2 files changed, 99 insertions(+), 13 deletions(-) diff --git a/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx index e69de29..0f78e87 100644 --- a/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx +++ b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx @@ -0,0 +1,87 @@ +import { useEffect, useState } from "preact/hooks"; + +interface Promotion { + id: number; + name: string; +} + +interface Mobility { + id: number; + studentId: string; + firstName: string; + lastName: string; + startDate: string | null; + endDate: string | null; + weeksCount: number | null; + destinationCountry: string | null; + destinationName: string | null; + mobilityStatus: string; +} + +export default function ConsultMobility() { + const [data, setData] = useState<{ promotions: Promotion[]; mobilities: Mobility[] } | null>(null); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await fetch("/mobility/api/insert_mobility"); + if (!response.ok) { + throw new Error(`Error fetching data: ${response.statusText}`); + } + + const result = await response.json(); + setData(result); + } catch (err) { + console.error("Error fetching mobility data:", err); + setError("Failed to load mobility data. Please try again later."); + } + }; + + fetchData(); + }, []); + + return ( +
+

Consult Mobility

+ {error &&

{error}

} + {data?.promotions.map((promo) => ( +
+

Promotion: {promo.id}

+ + + + + + + + + + + + + + + + {data.mobilities + .filter((mobility) => mobility.studentId.startsWith(String(promo.id))) + .map((mobility) => ( + + + + + + + + + + + + ))} + +
IDFirst NameLast NameStart DateEnd DateWeeks CountDestination CountryDestination NameStatus
{mobility.id}{mobility.firstName}{mobility.lastName}{mobility.startDate || "N/A"}{mobility.endDate || "N/A"}{mobility.weeksCount ?? "N/A"}{mobility.destinationCountry || "N/A"}{mobility.destinationName || "N/A"}{mobility.mobilityStatus}
+
+ ))} +
+ ); +} diff --git a/routes/(apps)/mobility/partials/overview.tsx b/routes/(apps)/mobility/partials/overview.tsx index a73c859..1ed1b2d 100644 --- a/routes/(apps)/mobility/partials/overview.tsx +++ b/routes/(apps)/mobility/partials/overview.tsx @@ -1,17 +1,16 @@ -import { Partial } from "$fresh/runtime.ts"; -import { RouteConfig } from "$fresh/server.ts"; +import ConsultMobility from "$root/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx"; +import { getPartialsConfig, makePartials } from "$root/defaults/makePartials.tsx"; +import { FreshContext } from "$fresh/server.ts"; +import { State } from "$root/routes/_middleware.ts"; -type ModulesProps = Record; - -export const config: RouteConfig = { - skipAppWrapper: true, - skipInheritedLayouts: true, -}; - -export default function Modules(_props: ModulesProps) { +async function Mobility(_request: Request, _context: FreshContext) { return ( - - mobility - + <> +

Edit mobility

+ + ); } + +export const config = getPartialsConfig(); +export default makePartials(Mobility); \ No newline at end of file From cc26ec9445787a3f8ffb7e37abbfbef93990b93c Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Wed, 22 Jan 2025 22:45:34 +0100 Subject: [PATCH 11/18] Trying to make mobility works --- routes/(apps)/mobility/api/insert_mobility.ts | 41 ++++++++----------- .../mobility/api/insert_students_test.ts | 31 -------------- 2 files changed, 18 insertions(+), 54 deletions(-) delete mode 100644 routes/(apps)/mobility/api/insert_students_test.ts diff --git a/routes/(apps)/mobility/api/insert_mobility.ts b/routes/(apps)/mobility/api/insert_mobility.ts index 2d5b3f9..ec9048e 100644 --- a/routes/(apps)/mobility/api/insert_mobility.ts +++ b/routes/(apps)/mobility/api/insert_mobility.ts @@ -1,12 +1,12 @@ import { Handlers } from "$fresh/server.ts"; -import connect from "$root/databases/connect.ts"; +import { Database } from "@db/sqlite"; export const handler: Handlers = { async GET() { try { - using connection = connect("mobility"); + const connection = new Database("databases/data/mobility.db", { create: false }); - const mobilities = connection.database.prepare( + const mobilities = connection.prepare( `SELECT mobility.id, mobility.studentId, @@ -19,9 +19,11 @@ export const handler: Handlers = { mobility.destinationName, mobility.mobilityStatus FROM mobility - LEFT JOIN students ON mobility.studentId = students.userId`, + LEFT JOIN students ON mobility.studentId = students.userId` ).all(); + connection.close(); + return new Response( JSON.stringify({ mobilities }), { @@ -36,7 +38,7 @@ export const handler: Handlers = { }, async POST(request) { - console.log("API /mobility/api/update_mobility called"); + console.log("API /mobility/api/insert_mobility called"); try { const body = await request.json(); @@ -46,25 +48,17 @@ export const handler: Handlers = { throw new Error("Invalid request body"); } - using connection = connect("mobility"); + const connection = new Database("databases/data/mobility.db", { create: false }); - const updateQuery = connection.database.prepare( + const insertQuery = connection.prepare( `INSERT INTO mobility ( - id, studentId, startDate, endDate, weeksCount, destinationCountry, destinationName, mobilityStatus + studentId, startDate, endDate, weeksCount, destinationCountry, destinationName, mobilityStatus ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) - ON CONFLICT(id) DO UPDATE SET - startDate = excluded.startDate, - endDate = excluded.endDate, - weeksCount = excluded.weeksCount, - destinationCountry = excluded.destinationCountry, - destinationName = excluded.destinationName, - mobilityStatus = excluded.mobilityStatus` + VALUES (?, ?, ?, ?, ?, ?, ?)` ); for (const mobility of data) { const { - id, studentId, startDate, endDate, @@ -74,8 +68,7 @@ export const handler: Handlers = { mobilityStatus = "N/A", } = mobility; - updateQuery.run( - id, + insertQuery.run( studentId, startDate, endDate, @@ -86,11 +79,13 @@ export const handler: Handlers = { ); } - console.log("Mobility data updated successfully"); - return new Response("Data updated successfully", { status: 200 }); + connection.close(); + + console.log("Mobility data inserted successfully"); + return new Response("Data inserted successfully", { status: 201 }); } catch (error) { - console.error("Error updating mobility data:", error); - return new Response("Failed to update data", { status: 500 }); + console.error("Error inserting mobility data:", error); + return new Response("Failed to insert data", { status: 500 }); } }, }; diff --git a/routes/(apps)/mobility/api/insert_students_test.ts b/routes/(apps)/mobility/api/insert_students_test.ts deleted file mode 100644 index d0123af..0000000 --- a/routes/(apps)/mobility/api/insert_students_test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Handlers } from "$fresh/server.ts"; -import connect from "$root/databases/connect.ts"; - -export const handler: Handlers = { - async GET() { - try { - using connection = connect("students"); - - const promotions = connection.database.prepare( - "select id from promotions", - ).all(); - - const students = connection.database - .prepare( - `select userId, firstName, lastName, mail, promotionId from students`, - ) - .all(); - - return new Response( - JSON.stringify({ promotions, students }), - { - status: 200, - headers: { "Content-Type": "application/json" }, - }, - ); - } catch (error) { - console.error("Error fetching data:", error); - return new Response("Failed to fetch data", { status: 500 }); - } - }, -}; From a867f67fd9c808e57a5fda28ac73e285846963f7 Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Fri, 24 Jan 2025 16:17:51 +0100 Subject: [PATCH 12/18] Trying to fix DB mobility --- fresh.gen.ts | 9 +- .../mobility/(_islands)/ConsultMobility.tsx | 8 +- .../mobility/(_islands)/EditMobility.tsx | 94 +++++++++++++------ routes/(apps)/mobility/api/insert_mobility.ts | 17 ++-- 4 files changed, 81 insertions(+), 47 deletions(-) diff --git a/fresh.gen.ts b/fresh.gen.ts index 58412fb..dd2f589 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -3,9 +3,9 @@ // This file is automatically updated during development when running `dev.ts`. import * as $_apps_layout from "./routes/(apps)/_layout.tsx"; +import * as $_apps_mobility_api_insert_mobility from "./routes/(apps)/mobility/api/insert_mobility.ts"; import * as $_apps_mobility_index from "./routes/(apps)/mobility/index.tsx"; import * as $_apps_mobility_partials_admin_edit_mobility from "./routes/(apps)/mobility/partials/(admin)/edit_mobility.tsx"; -import * as $_apps_mobility_partials_admin_consult_students_test from "./routes/(apps)/mobility/partials/(admin)/consult_students_test.tsx"; import * as $_apps_mobility_partials_index from "./routes/(apps)/mobility/partials/index.tsx"; import * as $_apps_mobility_partials_overview from "./routes/(apps)/mobility/partials/overview.tsx"; import * as $_apps_notes_index from "./routes/(apps)/notes/index.tsx"; @@ -30,7 +30,6 @@ import * as $logout from "./routes/logout.tsx"; import * as $_islands_AppNavigator from "./routes/(_islands)/AppNavigator.tsx"; import * as $_islands_Navbar from "./routes/(_islands)/Navbar.tsx"; import * as $_apps_mobility_islands_ConsultMobility from "./routes/(apps)/mobility/(_islands)/ConsultMobility.tsx"; -import * as $_apps_mobility_islands_ConsultStudents_test from "./routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx"; import * as $_apps_mobility_islands_EditMobility from "./routes/(apps)/mobility/(_islands)/EditMobility.tsx"; import * as $_apps_mobility_islands_ImportFile from "./routes/(apps)/mobility/(_islands)/ImportFile.tsx"; import * as $_apps_students_islands_ConsultStudents from "./routes/(apps)/students/(_islands)/ConsultStudents.tsx"; @@ -41,11 +40,11 @@ import type { Manifest } from "$fresh/server.ts"; const manifest = { routes: { "./routes/(apps)/_layout.tsx": $_apps_layout, + "./routes/(apps)/mobility/api/insert_mobility.ts": + $_apps_mobility_api_insert_mobility, "./routes/(apps)/mobility/index.tsx": $_apps_mobility_index, "./routes/(apps)/mobility/partials/(admin)/edit_mobility.tsx": $_apps_mobility_partials_admin_edit_mobility, - "./routes/(apps)/mobility/partials/(admin)/consult_students_test.tsx": - $_apps_mobility_partials_admin_consult_students_test, "./routes/(apps)/mobility/partials/index.tsx": $_apps_mobility_partials_index, "./routes/(apps)/mobility/partials/overview.tsx": @@ -82,8 +81,6 @@ const manifest = { "./routes/(_islands)/Navbar.tsx": $_islands_Navbar, "./routes/(apps)/mobility/(_islands)/ConsultMobility.tsx": $_apps_mobility_islands_ConsultMobility, - "./routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx": - $_apps_mobility_islands_ConsultStudents_test, "./routes/(apps)/mobility/(_islands)/EditMobility.tsx": $_apps_mobility_islands_EditMobility, "./routes/(apps)/mobility/(_islands)/ImportFile.tsx": diff --git a/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx index 0f78e87..0138de4 100644 --- a/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx +++ b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx @@ -24,16 +24,20 @@ export default function ConsultMobility() { useEffect(() => { const fetchData = async () => { + console.log("ConsultMobility: Fetching data from API..."); try { const response = await fetch("/mobility/api/insert_mobility"); + console.log("ConsultMobility: API response status:", response.status); + if (!response.ok) { throw new Error(`Error fetching data: ${response.statusText}`); } const result = await response.json(); + console.log("ConsultMobility: Data fetched successfully:", result); setData(result); } catch (err) { - console.error("Error fetching mobility data:", err); + console.error("ConsultMobility: Error fetching data:", err); setError("Failed to load mobility data. Please try again later."); } }; @@ -47,7 +51,7 @@ export default function ConsultMobility() { {error &&

{error}

} {data?.promotions.map((promo) => (
-

Promotion: {promo.id}

+

Promotion: {promo.name}

diff --git a/routes/(apps)/mobility/(_islands)/EditMobility.tsx b/routes/(apps)/mobility/(_islands)/EditMobility.tsx index 43b80ef..2970a81 100644 --- a/routes/(apps)/mobility/(_islands)/EditMobility.tsx +++ b/routes/(apps)/mobility/(_islands)/EditMobility.tsx @@ -18,44 +18,48 @@ export default function EditMobility() { const [isSaving, setIsSaving] = useState(false); useEffect(() => { - async function fetchMobilityData() { - const response = await fetch("/mobility/api/insert_mobility"); - const data = await response.json(); - setMobilityData(data.mobilities || []); - } + const fetchMobilityData = async () => { + console.log("EditMobility: Fetching mobility data..."); + try { + const response = await fetch("/mobility/api/insert_mobility"); + console.log("EditMobility: API response status:", response.status); + + if (!response.ok) { + throw new Error(`Error fetching data: ${response.statusText}`); + } + + const data = await response.json(); + console.log("EditMobility: Data fetched successfully:", data); + setMobilityData(data.mobilities || []); + } catch (err) { + console.error("EditMobility: Error fetching data:", err); + } + }; fetchMobilityData(); }, []); - const handleChange = ( - id: number, - field: keyof MobilityData, - value: string | number | null, - ) => { - setMobilityData((prev) => - prev.map((entry) => - entry.id === id ? { ...entry, [field]: value } : entry, - ) - ); - }; - const handleSave = async () => { + console.log("EditMobility: Saving data..."); setIsSaving(true); try { - const response = await fetch("/mobility/api/insert_mobility", { + const response = await fetch("/mobility/api/insert_mobility", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ data: mobilityData }), }); + console.log("EditMobility: Save response status:", response.status); + if (response.ok) { + console.log("EditMobility: Data saved successfully."); alert("Data saved successfully!"); } else { - alert("Failed to save data."); + throw new Error(`Failed to save data: ${response.statusText}`); } } catch (error) { - console.error("Error saving data:", error); + console.error("EditMobility: Error saving data:", error); alert("An error occurred while saving data."); } finally { setIsSaving(false); @@ -87,7 +91,13 @@ export default function EditMobility() { type="date" value={mobility.startDate || ""} onChange={(e) => - handleChange(mobility.id, "startDate", e.target.value) + setMobilityData((prev) => + prev.map((entry) => + entry.id === mobility.id + ? { ...entry, startDate: e.target.value } + : entry + ) + ) } /> @@ -96,7 +106,13 @@ export default function EditMobility() { type="date" value={mobility.endDate || ""} onChange={(e) => - handleChange(mobility.id, "endDate", e.target.value) + setMobilityData((prev) => + prev.map((entry) => + entry.id === mobility.id + ? { ...entry, endDate: e.target.value } + : entry + ) + ) } /> @@ -105,10 +121,12 @@ export default function EditMobility() { type="number" value={mobility.weeksCount || ""} onChange={(e) => - handleChange( - mobility.id, - "weeksCount", - Number(e.target.value) || null, + setMobilityData((prev) => + prev.map((entry) => + entry.id === mobility.id + ? { ...entry, weeksCount: Number(e.target.value) || null } + : entry + ) ) } /> @@ -118,7 +136,13 @@ export default function EditMobility() { type="text" value={mobility.destinationCountry || ""} onChange={(e) => - handleChange(mobility.id, "destinationCountry", e.target.value) + setMobilityData((prev) => + prev.map((entry) => + entry.id === mobility.id + ? { ...entry, destinationCountry: e.target.value } + : entry + ) + ) } /> @@ -127,7 +151,13 @@ export default function EditMobility() { type="text" value={mobility.destinationName || ""} onChange={(e) => - handleChange(mobility.id, "destinationName", e.target.value) + setMobilityData((prev) => + prev.map((entry) => + entry.id === mobility.id + ? { ...entry, destinationName: e.target.value } + : entry + ) + ) } /> @@ -135,7 +165,13 @@ export default function EditMobility() {
diff --git a/routes/(apps)/mobility/api/insert_mobility.ts b/routes/(apps)/mobility/api/insert_mobility.ts index ae88eda..9a1e985 100644 --- a/routes/(apps)/mobility/api/insert_mobility.ts +++ b/routes/(apps)/mobility/api/insert_mobility.ts @@ -6,10 +6,10 @@ export const handler: Handlers = { try { console.log("Connecting to mobility database..."); const connection = new Database("databases/data/mobility.db", { create: false }); - - console.log("Connected to student database."); connection.run("ATTACH DATABASE 'databases/data/students.db' AS students"); + console.log("Connected to databases."); + // Récupération des mobilités const mobilities = connection.prepare( `SELECT mobility.id, @@ -26,8 +26,20 @@ export const handler: Handlers = { LEFT JOIN students.students ON mobility.studentId = students.userId` ).all(); + // Récupération des promotions + const promotions = connection.prepare( + `SELECT id, name FROM students.promotions` + ).all(); + connection.close(); - return new Response(JSON.stringify({ mobilities }), { status: 200, headers: { "Content-Type": "application/json" } }); + + return new Response( + JSON.stringify({ mobilities, promotions }), + { + status: 200, + headers: { "Content-Type": "application/json" }, + }, + ); } catch (error) { console.error("Error fetching mobility data:", error); return new Response("Failed to fetch data", { status: 500 }); From f07b4dc616863483245bd671e525741f9fb0612e Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Fri, 24 Jan 2025 17:09:51 +0100 Subject: [PATCH 14/18] Consult mobility working --- .../mobility/(_islands)/ConsultMobility.tsx | 44 +++++++++++-------- routes/(apps)/mobility/api/insert_mobility.ts | 20 ++++++--- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx index 9b31a73..607dbd6 100644 --- a/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx +++ b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx @@ -5,11 +5,16 @@ interface Promotion { name: string; } +interface Student { + id: string; + firstName: string; + lastName: string; + promotionId: number; +} + interface Mobility { id: number; studentId: string; - firstName: string; - lastName: string; startDate: string | null; endDate: string | null; weeksCount: number | null; @@ -19,7 +24,7 @@ interface Mobility { } export default function ConsultMobility() { - const [data, setData] = useState<{ promotions?: Promotion[]; mobilities: Mobility[] } | null>(null); + const [data, setData] = useState<{ promotions?: Promotion[]; students?: Student[]; mobilities?: Mobility[] } | null>(null); const [error, setError] = useState(null); useEffect(() => { @@ -74,21 +79,24 @@ export default function ConsultMobility() { - {data.mobilities - .filter((mobility) => mobility.studentId.startsWith(String(promo.id))) - .map((mobility) => ( - - - - - - - - - - - - ))} + {data.students + ?.filter((student) => student.promotionId === promo.id) + .map((student) => { + const mobility = data.mobilities?.find((mob) => mob.studentId === student.id); + return ( + + + + + + + + + + + + ); + })}
{mobility.id}{mobility.firstName}{mobility.lastName}{mobility.startDate || "N/A"}{mobility.endDate || "N/A"}{mobility.weeksCount ?? "N/A"}{mobility.destinationCountry || "N/A"}{mobility.destinationName || "N/A"}{mobility.mobilityStatus}
{student.id}{student.firstName}{student.lastName}{mobility?.startDate || "N/A"}{mobility?.endDate || "N/A"}{mobility?.weeksCount ?? "N/A"}{mobility?.destinationCountry || "N/A"}{mobility?.destinationName || "N/A"}{mobility?.mobilityStatus || "N/A"}
diff --git a/routes/(apps)/mobility/api/insert_mobility.ts b/routes/(apps)/mobility/api/insert_mobility.ts index 9a1e985..365e79b 100644 --- a/routes/(apps)/mobility/api/insert_mobility.ts +++ b/routes/(apps)/mobility/api/insert_mobility.ts @@ -9,24 +9,30 @@ export const handler: Handlers = { connection.run("ATTACH DATABASE 'databases/data/students.db' AS students"); console.log("Connected to databases."); - // Récupération des mobilités + const students = connection.prepare( + `SELECT + students.userId AS id, + students.firstName, + students.lastName, + students.promotionId AS promotionId, + promotions.name AS promotionName + FROM students.students + LEFT JOIN students.promotions ON students.promotionId = promotions.id` + ).all(); + const mobilities = connection.prepare( `SELECT mobility.id, mobility.studentId, - students.firstName, - students.lastName, mobility.startDate, mobility.endDate, mobility.weeksCount, mobility.destinationCountry, mobility.destinationName, mobility.mobilityStatus - FROM mobility - LEFT JOIN students.students ON mobility.studentId = students.userId` + FROM mobility` ).all(); - // Récupération des promotions const promotions = connection.prepare( `SELECT id, name FROM students.promotions` ).all(); @@ -34,7 +40,7 @@ export const handler: Handlers = { connection.close(); return new Response( - JSON.stringify({ mobilities, promotions }), + JSON.stringify({ mobilities, students, promotions }), { status: 200, headers: { "Content-Type": "application/json" }, From c3d33545372ed73b740153917907bf3d16554887 Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Fri, 24 Jan 2025 19:46:53 +0100 Subject: [PATCH 15/18] Trying to make EditMobility works --- .../mobility/(_islands)/EditMobility.tsx | 282 +++++++++--------- 1 file changed, 149 insertions(+), 133 deletions(-) diff --git a/routes/(apps)/mobility/(_islands)/EditMobility.tsx b/routes/(apps)/mobility/(_islands)/EditMobility.tsx index 2970a81..7438518 100644 --- a/routes/(apps)/mobility/(_islands)/EditMobility.tsx +++ b/routes/(apps)/mobility/(_islands)/EditMobility.tsx @@ -1,10 +1,20 @@ import { useEffect, useState } from "preact/hooks"; -interface MobilityData { - id: number; - studentId: string; +interface Student { + id: string; firstName: string; lastName: string; + promotionId: number; +} + +interface Promotion { + id: number; + name: string; +} + +interface Mobility { + id: number; + studentId: string; startDate: string | null; endDate: string | null; weeksCount: number | null; @@ -14,12 +24,13 @@ interface MobilityData { } export default function EditMobility() { - const [mobilityData, setMobilityData] = useState([]); + const [data, setData] = useState<{ promotions?: Promotion[]; students?: Student[]; mobilities?: Mobility[] } | null>(null); + const [error, setError] = useState(null); const [isSaving, setIsSaving] = useState(false); useEffect(() => { - const fetchMobilityData = async () => { - console.log("EditMobility: Fetching mobility data..."); + const fetchData = async () => { + console.log("EditMobility: Fetching data from API..."); try { const response = await fetch("/mobility/api/insert_mobility"); console.log("EditMobility: API response status:", response.status); @@ -28,33 +39,54 @@ export default function EditMobility() { throw new Error(`Error fetching data: ${response.statusText}`); } - const data = await response.json(); - console.log("EditMobility: Data fetched successfully:", data); - setMobilityData(data.mobilities || []); + const result = await response.json(); + console.log("EditMobility: Data fetched successfully:", result); + setData(result); } catch (err) { console.error("EditMobility: Error fetching data:", err); + setError("Failed to load mobility data. Please try again later."); } }; - fetchMobilityData(); + fetchData(); }, []); + const handleChange = ( + studentId: string, + field: keyof Mobility, + value: string | number | null, + ) => { + if (!data) return; + + setData((prevData) => { + if (!prevData) return null; + + const updatedMobilities = prevData.mobilities?.map((mobility) => { + if (mobility.studentId === studentId) { + return { ...mobility, [field]: value }; + } + return mobility; + }) || []; + + return { ...prevData, mobilities: updatedMobilities }; + }); + }; + const handleSave = async () => { - console.log("EditMobility: Saving data..."); setIsSaving(true); try { const response = await fetch("/mobility/api/insert_mobility", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ data: mobilityData }), + body: JSON.stringify({ data: data?.mobilities }), }); console.log("EditMobility: Save response status:", response.status); if (response.ok) { - console.log("EditMobility: Data saved successfully."); alert("Data saved successfully!"); + window.location.reload(); // Refresh the page to load updated data } else { throw new Error(`Failed to save data: ${response.statusText}`); } @@ -66,128 +98,112 @@ export default function EditMobility() { } }; + if (error) { + return

{error}

; + } + + if (!data?.promotions) { + return

Loading data...

; + } + return ( -
- - - - - - - - - - - - - - - {mobilityData.map((mobility) => ( - - - - - - - - - - - ))} - -
First NameLast NameStart DateEnd DateWeeks CountDestination CountryDestination NameStatus
{mobility.firstName}{mobility.lastName} - - setMobilityData((prev) => - prev.map((entry) => - entry.id === mobility.id - ? { ...entry, startDate: e.target.value } - : entry - ) - ) - } - /> - - - setMobilityData((prev) => - prev.map((entry) => - entry.id === mobility.id - ? { ...entry, endDate: e.target.value } - : entry - ) - ) - } - /> - - - setMobilityData((prev) => - prev.map((entry) => - entry.id === mobility.id - ? { ...entry, weeksCount: Number(e.target.value) || null } - : entry - ) - ) - } - /> - - - setMobilityData((prev) => - prev.map((entry) => - entry.id === mobility.id - ? { ...entry, destinationCountry: e.target.value } - : entry - ) - ) - } - /> - - - setMobilityData((prev) => - prev.map((entry) => - entry.id === mobility.id - ? { ...entry, destinationName: e.target.value } - : entry - ) - ) - } - /> - - -
+
+

Edit Mobility

+ {data.promotions.map((promo) => ( +
+

Promotion: {promo.name}

+ + + + + + + + + + + + + + + + {data.students + ?.filter((student) => student.promotionId === promo.id) + .map((student) => { + const mobility = data.mobilities?.find((mob) => mob.studentId === student.id) || { + studentId: student.id, + startDate: null, + endDate: null, + weeksCount: null, + destinationCountry: null, + destinationName: null, + mobilityStatus: "N/A", + }; + + return ( + + + + + + + + + + + + ); + })} + +
IDFirst NameLast NameStart DateEnd DateWeeks CountDestination CountryDestination NameStatus
{student.id}{student.firstName}{student.lastName} + handleChange(student.id, "startDate", e.target.value)} + /> + + handleChange(student.id, "endDate", e.target.value)} + /> + + + handleChange(student.id, "weeksCount", Number(e.target.value) || null) + } + /> + + handleChange(student.id, "destinationCountry", e.target.value)} + /> + + handleChange(student.id, "destinationName", e.target.value)} + /> + + +
+
+ ))} -
+ ); } From fcc0a4413c4ea0654752c1fd2de556301fc5999d Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Fri, 24 Jan 2025 20:48:33 +0100 Subject: [PATCH 16/18] Update student to have an ID --- .../mobility/(_islands)/EditMobility.tsx | 30 ++++++---- routes/(apps)/mobility/api/insert_mobility.ts | 57 +++++++++++++++---- .../students/(_islands)/ConsultStudents.tsx | 10 ++-- .../students/(_islands)/UploadStudents.tsx | 4 +- routes/(apps)/students/api/insert_students.ts | 19 +++++-- 5 files changed, 87 insertions(+), 33 deletions(-) diff --git a/routes/(apps)/mobility/(_islands)/EditMobility.tsx b/routes/(apps)/mobility/(_islands)/EditMobility.tsx index 7438518..fe3f9ef 100644 --- a/routes/(apps)/mobility/(_islands)/EditMobility.tsx +++ b/routes/(apps)/mobility/(_islands)/EditMobility.tsx @@ -13,7 +13,7 @@ interface Promotion { } interface Mobility { - id: number; + id: number | null; studentId: string; startDate: string | null; endDate: string | null; @@ -63,7 +63,20 @@ export default function EditMobility() { const updatedMobilities = prevData.mobilities?.map((mobility) => { if (mobility.studentId === studentId) { - return { ...mobility, [field]: value }; + const updatedMobility = { ...mobility, [field]: value }; + + if (field === "startDate" || field === "endDate") { + const startDate = new Date(updatedMobility.startDate || ""); + const endDate = new Date(updatedMobility.endDate || ""); + if (startDate && endDate && startDate <= endDate) { + const weeks = Math.ceil((endDate.getTime() - startDate.getTime()) / (7 * 24 * 60 * 60 * 1000)); + updatedMobility.weeksCount = weeks; + } else { + updatedMobility.weeksCount = null; + } + } + + return updatedMobility; } return mobility; }) || []; @@ -86,7 +99,7 @@ export default function EditMobility() { if (response.ok) { alert("Data saved successfully!"); - window.location.reload(); // Refresh the page to load updated data + window.location.reload(); } else { throw new Error(`Failed to save data: ${response.statusText}`); } @@ -131,6 +144,7 @@ export default function EditMobility() { ?.filter((student) => student.promotionId === promo.id) .map((student) => { const mobility = data.mobilities?.find((mob) => mob.studentId === student.id) || { + id: null, studentId: student.id, startDate: null, endDate: null, @@ -159,15 +173,7 @@ export default function EditMobility() { onChange={(e) => handleChange(student.id, "endDate", e.target.value)} /> - - - handleChange(student.id, "weeksCount", Number(e.target.value) || null) - } - /> - + {mobility.weeksCount ?? "N/A"} {error}

} {data?.promotions.map((promo) => (
-

Promotion: {promo.id}

+

Promotion: {promo.name}

@@ -57,8 +57,8 @@ export default function ConsultStudents() { {data.students .filter((student) => student.promotionId === promo.id) .map((student) => ( - - + + diff --git a/routes/(apps)/students/(_islands)/UploadStudents.tsx b/routes/(apps)/students/(_islands)/UploadStudents.tsx index 10ed4e2..e84e951 100644 --- a/routes/(apps)/students/(_islands)/UploadStudents.tsx +++ b/routes/(apps)/students/(_islands)/UploadStudents.tsx @@ -33,10 +33,12 @@ export default function UploadStudents() { for (const sheetName of workbook.SheetNames) { const sheet = workbook.Sheets[sheetName]; const data = XLSX.utils.sheet_to_json(sheet, { - header: ["Nom", "Prénom", "Mail"], + header: ["Identifiant", "Nom", "Prénom", "Mail"], range: 1, // Ignorer les en-têtes }); + console.log(`Data from sheet ${sheetName}:`, data); + const response = await fetch("/students/api/insert_students", { method: "POST", headers: { "Content-Type": "application/json" }, diff --git a/routes/(apps)/students/api/insert_students.ts b/routes/(apps)/students/api/insert_students.ts index 98b11cb..c6c70fc 100644 --- a/routes/(apps)/students/api/insert_students.ts +++ b/routes/(apps)/students/api/insert_students.ts @@ -1,4 +1,5 @@ import { Handlers } from "$fresh/server.ts"; +import { Database } from "@db/sqlite"; import connect from "$root/databases/connect.ts"; export const handler: Handlers = { @@ -7,7 +8,7 @@ export const handler: Handlers = { using connection = connect("students"); const promotions = connection.database.prepare( - "select id from promotions", + "select id, name from promotions", ).all(); const students = connection.database @@ -30,7 +31,7 @@ export const handler: Handlers = { }, async POST(request) { - console.log("API /mobility/api/insert_students called"); + console.log("API /students/api/insert_students called"); try { const body = await request.json(); @@ -48,7 +49,7 @@ export const handler: Handlers = { "INSERT OR IGNORE INTO promotions (name) VALUES (?)", ).run(promoName); - const promoIdRow: {id: string} = connection.database + const promoIdRow: { id: number } = connection.database .prepare("SELECT id FROM promotions WHERE name = ?") .get(promoName)!; const promoId = promoIdRow.id; @@ -56,12 +57,20 @@ export const handler: Handlers = { console.log(`Promotion ID for "${promoName}":`, promoId); const insertQuery = connection.database.prepare( - "INSERT INTO students (firstName, lastName, mail, promotionId) VALUES (?, ?, ?, ?)", + `INSERT INTO students + (userId, firstName, lastName, mail, promotionId) + VALUES (?, ?, ?, ?, ?)`, ); for (const student of data) { console.log("Inserting student:", student); - insertQuery.run(student.Nom, student["Prénom"], student.Mail, promoId); + insertQuery.run( + student.Identifiant, + student.Nom, + student["Prénom"], + student.Mail, + promoId, + ); } console.log("All data inserted successfully"); From 16b7579e10301a85d0c187ee9d3fadb3b234b130 Mon Sep 17 00:00:00 2001 From: Clayzxr Date: Fri, 24 Jan 2025 21:38:53 +0100 Subject: [PATCH 17/18] Trying to make EditStudents works --- routes/(apps)/mobility/api/insert_mobility.ts | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/routes/(apps)/mobility/api/insert_mobility.ts b/routes/(apps)/mobility/api/insert_mobility.ts index 5eb0f0e..bf16cd7 100644 --- a/routes/(apps)/mobility/api/insert_mobility.ts +++ b/routes/(apps)/mobility/api/insert_mobility.ts @@ -62,16 +62,13 @@ export const handler: Handlers = { if (!Array.isArray(data)) { throw new Error("Invalid request body"); } - + console.log("Connecting to mobility database..."); const connection = new Database("databases/data/mobility.db", { create: false }); console.log("Attaching students database..."); connection.run("ATTACH DATABASE 'databases/data/students.db' AS students"); console.log("Students database attached successfully."); - const testStudents = connection.prepare("SELECT COUNT(*) AS count FROM students.students").get(); - console.log(`Students table accessible, total records: ${testStudents.count}`); - const insertQuery = connection.prepare( `INSERT INTO mobility ( id, studentId, startDate, endDate, weeksCount, destinationCountry, destinationName, mobilityStatus @@ -85,10 +82,10 @@ export const handler: Handlers = { destinationName = excluded.destinationName, mobilityStatus = excluded.mobilityStatus` ); - + for (const mobility of data) { const { - id = null, + id, studentId, startDate, endDate, @@ -97,7 +94,20 @@ export const handler: Handlers = { destinationName, mobilityStatus = "N/A", } = mobility; - + + console.log("Processing mobility data:", mobility); + + const studentExists = connection + .prepare(`SELECT COUNT(*) AS count FROM students.students WHERE userId = ?`) + .get(studentId); + + console.log(`Student ${studentId} exists:`, studentExists.count > 0); + + if (studentExists.count === 0) { + console.warn(`Skipping mobility for unknown studentId: ${studentId}`); + continue; + } + let calculatedWeeksCount = weeksCount; if (startDate && endDate) { const start = new Date(startDate); @@ -108,18 +118,18 @@ export const handler: Handlers = { calculatedWeeksCount = null; } } - - console.log(`Inserting/Updating mobility for studentId: ${studentId}`); - - const studentExists = connection - .prepare(`SELECT COUNT(*) AS count FROM students.students WHERE userId = ?`) - .get(studentId); - - if (studentExists.count === 0) { - console.warn(`Skipping mobility for unknown studentId: ${studentId}`); - continue; - } - + + console.log("Executing SQL insert/update query for:", { + id, + studentId, + startDate, + endDate, + calculatedWeeksCount, + destinationCountry, + destinationName, + mobilityStatus, + }); + insertQuery.run( id, studentId, From 6d4d36e0895c1bc5a371ccd05b34adc8be167254 Mon Sep 17 00:00:00 2001 From: Kevin FEDYNA Date: Sat, 25 Jan 2025 10:48:04 +0100 Subject: [PATCH 18/18] Fixed linting and formatting errors --- .../mobility/(_islands)/ConsultMobility.tsx | 13 ++++- .../(_islands)/ConsultStudents_test.tsx | 6 ++- .../mobility/(_islands)/EditMobility.tsx | 51 +++++++++++++++---- routes/(apps)/mobility/api/insert_mobility.ts | 41 ++++++++++----- .../(admin)/consult_students_test.tsx | 6 ++- .../partials/(admin)/edit_mobility.tsx | 6 ++- routes/(apps)/mobility/partials/overview.tsx | 8 ++- .../students/(_islands)/ConsultStudents.tsx | 4 +- .../students/(_islands)/UploadStudents.tsx | 2 +- routes/(apps)/students/(_props)/props.ts | 2 +- routes/(apps)/students/api/insert_students.ts | 3 +- .../students/partials/(admin)/consult.tsx | 6 ++- .../students/partials/(admin)/upload.tsx | 6 ++- 13 files changed, 118 insertions(+), 36 deletions(-) diff --git a/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx index 607dbd6..7befa63 100644 --- a/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx +++ b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx @@ -24,7 +24,14 @@ interface Mobility { } export default function ConsultMobility() { - const [data, setData] = useState<{ promotions?: Promotion[]; students?: Student[]; mobilities?: Mobility[] } | null>(null); + const [data, setData] = useState< + | { + promotions?: Promotion[]; + students?: Student[]; + mobilities?: Mobility[]; + } + | null + >(null); const [error, setError] = useState(null); useEffect(() => { @@ -82,7 +89,9 @@ export default function ConsultMobility() { {data.students ?.filter((student) => student.promotionId === promo.id) .map((student) => { - const mobility = data.mobilities?.find((mob) => mob.studentId === student.id); + const mobility = data.mobilities?.find((mob) => + mob.studentId === student.id + ); return ( diff --git a/routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx b/routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx index f05ba34..3e008bc 100644 --- a/routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx +++ b/routes/(apps)/mobility/(_islands)/ConsultStudents_test.tsx @@ -15,7 +15,9 @@ interface Student { } export default function ConsultStudents_test() { - const [data, setData] = useState<{ promotions: Promotion[]; students: Student[] } | null>(null); + const [data, setData] = useState< + { promotions: Promotion[]; students: Student[] } | null + >(null); const [error, setError] = useState(null); useEffect(() => { @@ -43,7 +45,7 @@ export default function ConsultStudents_test() { {error &&

{error}

} {data?.promotions.map((promo) => (
-

Promotion: {promo.id}

+

Promotion: {promo.id}

{student.id}
{student.userId} {student.firstName} {student.lastName} {student.mail}
{student.id}
diff --git a/routes/(apps)/mobility/(_islands)/EditMobility.tsx b/routes/(apps)/mobility/(_islands)/EditMobility.tsx index fe3f9ef..ef3a485 100644 --- a/routes/(apps)/mobility/(_islands)/EditMobility.tsx +++ b/routes/(apps)/mobility/(_islands)/EditMobility.tsx @@ -24,7 +24,14 @@ interface Mobility { } export default function EditMobility() { - const [data, setData] = useState<{ promotions?: Promotion[]; students?: Student[]; mobilities?: Mobility[] } | null>(null); + const [data, setData] = useState< + | { + promotions?: Promotion[]; + students?: Student[]; + mobilities?: Mobility[]; + } + | null + >(null); const [error, setError] = useState(null); const [isSaving, setIsSaving] = useState(false); @@ -69,7 +76,10 @@ export default function EditMobility() { const startDate = new Date(updatedMobility.startDate || ""); const endDate = new Date(updatedMobility.endDate || ""); if (startDate && endDate && startDate <= endDate) { - const weeks = Math.ceil((endDate.getTime() - startDate.getTime()) / (7 * 24 * 60 * 60 * 1000)); + const weeks = Math.ceil( + (endDate.getTime() - startDate.getTime()) / + (7 * 24 * 60 * 60 * 1000), + ); updatedMobility.weeksCount = weeks; } else { updatedMobility.weeksCount = null; @@ -99,7 +109,7 @@ export default function EditMobility() { if (response.ok) { alert("Data saved successfully!"); - window.location.reload(); + globalThis.location.reload(); } else { throw new Error(`Failed to save data: ${response.statusText}`); } @@ -143,7 +153,9 @@ export default function EditMobility() { {data.students ?.filter((student) => student.promotionId === promo.id) .map((student) => { - const mobility = data.mobilities?.find((mob) => mob.studentId === student.id) || { + const mobility = data.mobilities?.find((mob) => + mob.studentId === student.id + ) || { id: null, studentId: student.id, startDate: null, @@ -163,14 +175,20 @@ export default function EditMobility() { handleChange(student.id, "startDate", e.target.value)} + onChange={(e) => + handleChange( + student.id, + "startDate", + e.target.value, + )} /> @@ -178,20 +196,35 @@ export default function EditMobility() { handleChange(student.id, "destinationCountry", e.target.value)} + onChange={(e) => + handleChange( + student.id, + "destinationCountry", + e.target.value, + )} />
handleChange(student.id, "endDate", e.target.value)} + onChange={(e) => + handleChange(student.id, "endDate", e.target.value)} /> {mobility.weeksCount ?? "N/A"} handleChange(student.id, "destinationName", e.target.value)} + onChange={(e) => + handleChange( + student.id, + "destinationName", + e.target.value, + )} />