diff --git a/Dockerfile b/Dockerfile index fd8f30c..6615438 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM denoland/deno:alpine WORKDIR /app COPY . . -RUN deno cache main.ts +RUN deno cache main.ts --allow-import flag RUN deno task build USER deno diff --git a/deno.json b/deno.json index e9dcaca..344187a 100644 --- a/deno.json +++ b/deno.json @@ -26,6 +26,7 @@ "@db/sqlite": "jsr:@db/sqlite@^0.12.0", "@melvdouc/xml-parser": "jsr:@melvdouc/xml-parser@^0.1.1", "@popov/jwt": "jsr:@popov/jwt@^1.0.1", + "@psych/sheet": "jsr:@psych/sheet@^1.0.6", "@std/cli": "jsr:@std/cli@^1.0.10", "preact": "https://esm.sh/preact@10.22.0", "preact/": "https://esm.sh/preact@10.22.0/", diff --git a/fresh.gen.ts b/fresh.gen.ts index a01fa4e..a256829 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -27,6 +27,12 @@ import * as $login from "./routes/login.tsx"; 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 type { Manifest } from "$fresh/server.ts"; const manifest = { @@ -66,6 +72,18 @@ const manifest = { islands: { "./routes/(_islands)/AppNavigator.tsx": $_islands_AppNavigator, "./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, }, baseUrl: import.meta.url, } satisfies Manifest; diff --git a/routes/(apps)/mobility/(_components)/ConsultStudents.tsx b/routes/(apps)/mobility/(_components)/ConsultStudents.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/routes/(apps)/mobility/(_components)/ConsultMobility.tsx b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx similarity index 100% rename from routes/(apps)/mobility/(_components)/ConsultMobility.tsx rename to routes/(apps)/mobility/(_islands)/ConsultMobility.tsx diff --git a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx new file mode 100644 index 0000000..552b88b --- /dev/null +++ b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx @@ -0,0 +1,67 @@ +import { useEffect, useState } from "preact/hooks"; + +interface Student { + id: number; + firstName: string; + lastName: string; + email: string; + promotion: string; +} + +export default function ConsultStudents() { + const [students, setStudents] = useState([]); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchStudents = async () => { + try { + const response = await fetch("/mobility/api/insert_students"); + + if (!response.ok) { + throw new Error(`Error fetching students: ${response.statusText}`); + } + + const data: Student[] = await response.json(); + setStudents(data); + } catch (err) { + console.error("Error fetching students:", err); + setError("Failed to load students. Please try again later."); + } + }; + + fetchStudents(); + }, []); + + 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}
+ )} +
+ ); +} diff --git a/routes/(apps)/mobility/(_components)/EditMobility.tsx b/routes/(apps)/mobility/(_islands)/EditMobility.tsx similarity index 100% rename from routes/(apps)/mobility/(_components)/EditMobility.tsx rename to routes/(apps)/mobility/(_islands)/EditMobility.tsx diff --git a/routes/(apps)/mobility/(_components)/EditStudents.tsx b/routes/(apps)/mobility/(_islands)/EditStudents.tsx similarity index 100% rename from routes/(apps)/mobility/(_components)/EditStudents.tsx rename to routes/(apps)/mobility/(_islands)/EditStudents.tsx diff --git a/routes/(apps)/mobility/(_components)/ImportFile.tsx b/routes/(apps)/mobility/(_islands)/ImportFile.tsx similarity index 100% rename from routes/(apps)/mobility/(_components)/ImportFile.tsx rename to routes/(apps)/mobility/(_islands)/ImportFile.tsx diff --git a/routes/(apps)/mobility/(_components)/UploadStudents.tsx b/routes/(apps)/mobility/(_islands)/UploadStudents.tsx similarity index 87% rename from routes/(apps)/mobility/(_components)/UploadStudents.tsx rename to routes/(apps)/mobility/(_islands)/UploadStudents.tsx index d8db47a..2400c35 100644 --- a/routes/(apps)/mobility/(_components)/UploadStudents.tsx +++ b/routes/(apps)/mobility/(_islands)/UploadStudents.tsx @@ -11,6 +11,7 @@ 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"; @@ -18,8 +19,10 @@ export default function UploadStudents() { }; const confirmUpload = async () => { + console.log("Confirm Upload"); if (!fileData.value) { statusMessage.value = "Please select a file before confirming upload."; + console.error("Error: No file selected."); return; } @@ -34,11 +37,13 @@ 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: ["Nom", "Prénom", "Mail"], range: 1, // Ignorer les en-têtes }); - const response = await fetch("/api/insert_students", { + 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 }), diff --git a/routes/(apps)/mobility/api/insert_students.ts b/routes/(apps)/mobility/api/insert_students.ts index 790dce0..e75882d 100644 --- a/routes/(apps)/mobility/api/insert_students.ts +++ b/routes/(apps)/mobility/api/insert_students.ts @@ -1,14 +1,13 @@ import { Handlers } from "$fresh/server.ts"; -import { Database } from "@db/sqlite"; +import { Database } from "@db/sqlite"; export const handler: Handlers = { async GET(_request, context) { try { - // Ouvre ou crée la base de données SQLite const db = new Database("databases/data/mobility.db"); - // Crée la table si elle n'existe pas - db.execute(` + db.prepare( + ` CREATE TABLE IF NOT EXISTS students ( id INTEGER PRIMARY KEY AUTOINCREMENT, firstName TEXT NOT NULL, @@ -16,19 +15,16 @@ export const handler: Handlers = { email TEXT NOT NULL, promotion TEXT NOT NULL ); - `); + ` + ).run(); - // Récupère toutes les données - const students = []; - for (const [id, firstName, lastName, email, promotion] of db.query( + const rows = db.prepare( "SELECT id, firstName, lastName, email, promotion FROM students" - )) { - students.push({ id, firstName, lastName, email, promotion }); - } + ).all(); db.close(); - return new Response(JSON.stringify(students), { + return new Response(JSON.stringify(rows), { status: 200, headers: { "Content-Type": "application/json" }, }); @@ -39,15 +35,24 @@ export const handler: Handlers = { }, async POST(request) { + console.log("API /mobility/api/insert_students called"); + try { const body = await request.json(); const { data, promoName } = body; - // Ouvre ou crée la base de données SQLite + console.log("Received data:", { promoName, data }); + + if (!promoName || !Array.isArray(data)) { + throw new Error("Invalid request body"); + } + const db = new Database("databases/data/mobility.db"); - // Crée la table si elle n'existe pas - db.execute(` + console.log("Database opened successfully"); + + db.prepare( + ` CREATE TABLE IF NOT EXISTS students ( id INTEGER PRIMARY KEY AUTOINCREMENT, firstName TEXT NOT NULL, @@ -55,20 +60,21 @@ export const handler: Handlers = { email TEXT NOT NULL, promotion TEXT NOT NULL ); - `); + ` + ).run(); + + console.log("Table ensured successfully"); + + const insertQuery = db.prepare( + "INSERT INTO students (firstName, lastName, email, promotion) VALUES (?, ?, ?, ?)" + ); - // Prépare et insère les données - const insertQuery = - "INSERT INTO students (firstName, lastName, email, promotion) VALUES (?, ?, ?, ?)"; for (const student of data) { - db.query(insertQuery, [ - student.firstName, - student.lastName, - student.email, - promoName, - ]); + console.log("Inserting student:", student); + insertQuery.run(student.Nom, student["Prénom"], student.Mail, promoName); } + console.log("All students inserted successfully"); db.close(); return new Response("Students inserted successfully", { status: 201 }); diff --git a/routes/(apps)/mobility/partials/students.tsx b/routes/(apps)/mobility/partials/students.tsx index c156c61..f3c7cb9 100644 --- a/routes/(apps)/mobility/partials/students.tsx +++ b/routes/(apps)/mobility/partials/students.tsx @@ -1,7 +1,7 @@ import { RouteConfig } from "$fresh/server.ts"; -import UploadStudents from "../(_components)/UploadStudents.tsx"; -//import ConsultStudents from "../(_components)/ConsultStudents.tsx"; -//import EditStudents from "../(_components)/EditStudents.tsx"; +import UploadStudents from "../(_islands)/UploadStudents.tsx"; +import ConsultStudents from "../(_islands)/ConsultStudents.tsx"; +//import EditStudents from "../(_islands)/EditStudents.tsx"; export const config: RouteConfig = { skipAppWrapper: false, @@ -14,6 +14,7 @@ export default function Students() {

Manage Promotions


+ ); }