diff --git a/databases/init/mobility.sql b/databases/init/mobility.sql index e69de29..98ac5ae 100644 --- a/databases/init/mobility.sql +++ b/databases/init/mobility.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS students ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + firstName TEXT NOT NULL, + lastName TEXT NOT NULL, + email TEXT NOT NULL, + promotion TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS promotions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + year INTEGER NOT NULL +); diff --git a/databases/mobility.ts b/databases/mobility.ts new file mode 100644 index 0000000..13055f0 --- /dev/null +++ b/databases/mobility.ts @@ -0,0 +1,22 @@ +import { Database } from "@db/sqlite"; + +export default async function insertIntoMobility(data: Array<{ firstName: string; lastName: string; email: string }>, promoName: string) { + try { + const databasePath = "databases/data/mobility.db"; + const db = new Database(databasePath); + + db.transaction(() => { + for (const student of data) { + db.query( + "INSERT INTO students (firstName, lastName, email, promotion) VALUES (?, ?, ?, ?)", + [student.firstName, student.lastName, student.email, promoName] + ); + } + })(); + + db.close(); + console.log(`Data for promotion ${promoName} inserted successfully.`); + } catch (error) { + console.error("Error inserting data into mobility database:", error); + } +} diff --git a/fresh.gen.ts b/fresh.gen.ts index 1cfe548..460b0a4 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -23,7 +23,7 @@ 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_SaveStudents from "./routes/(apps)/mobility/(_islands)/SaveStudents.tsx"; +import * as $_apps_mobility_islands_ConsultStudents from "./routes/(apps)/mobility/(_islands)/ConsultStudents.tsx"; import * as $_apps_mobility_islands_UploadStudents from "./routes/(apps)/mobility/(_islands)/UploadStudents.tsx"; import type { Manifest } from "$fresh/server.ts"; @@ -58,8 +58,8 @@ const manifest = { islands: { "./routes/(_islands)/AppNavigator.tsx": $_islands_AppNavigator, "./routes/(_islands)/Navbar.tsx": $_islands_Navbar, - "./routes/(apps)/mobility/(_islands)/SaveStudents.tsx": - $_apps_mobility_islands_SaveStudents, + "./routes/(apps)/mobility/(_islands)/ConsultStudents.tsx": + $_apps_mobility_islands_ConsultStudents, "./routes/(apps)/mobility/(_islands)/UploadStudents.tsx": $_apps_mobility_islands_UploadStudents, }, diff --git a/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx b/routes/(apps)/mobility/(_islands)/ConsultMobility.tsx new file mode 100644 index 0000000..e69de29 diff --git a/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx b/routes/(apps)/mobility/(_islands)/ConsultStudents.tsx new file mode 100644 index 0000000..e69de29 diff --git a/routes/(apps)/mobility/(_islands)/EditMobility.tsx b/routes/(apps)/mobility/(_islands)/EditMobility.tsx new file mode 100644 index 0000000..e69de29 diff --git a/routes/(apps)/mobility/(_islands)/EditStudents.tsx b/routes/(apps)/mobility/(_islands)/EditStudents.tsx new file mode 100644 index 0000000..e69de29 diff --git a/routes/(apps)/mobility/(_islands)/ImportFile.tsx b/routes/(apps)/mobility/(_islands)/ImportFile.tsx new file mode 100644 index 0000000..e69de29 diff --git a/routes/(apps)/mobility/(_islands)/SaveStudents.tsx b/routes/(apps)/mobility/(_islands)/SaveStudents.tsx deleted file mode 100644 index 01d1cc3..0000000 --- a/routes/(apps)/mobility/(_islands)/SaveStudents.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { useSignal } from "@preact/signals"; -import Papa from "https://cdn.skypack.dev/papaparse"; - -type Student = { - firstName: string; - lastName: string; - email: string; -}; - -type Promotion = { - name: string; - students: Student[]; -}; - -export default function SaveStudents() { - const promotions = useSignal([]); - const statusMessage = useSignal(""); - - const loadCSV = async () => { - try { - const response = await fetch("/api/students"); // Assurez-vous que l'API est appelée correctement - if (!response.ok) { - throw new Error("Failed to load CSV file"); - } - const csvText = await response.text(); // Lire le contenu en texte - - const parsedData = Papa.parse(csvText, { - header: true, - skipEmptyLines: true, - }); - - const groupedPromotions: Record = {}; - parsedData.data.forEach((row: any) => { - const { promotion, firstName, lastName, email } = row; - if (!groupedPromotions[promotion]) { - groupedPromotions[promotion] = []; - } - groupedPromotions[promotion].push({ firstName, lastName, email }); - }); - - const loadedPromotions = Object.entries(groupedPromotions).map( - ([name, students]) => ({ - name, - students, - }) - ); - - promotions.value = loadedPromotions; - statusMessage.value = "Data loaded successfully!"; - } catch (error) { - console.error("Error loading CSV file:", error); - statusMessage.value = "Failed to load data. Please try again."; - } - }; - - - - // Charger les données CSV dès le chargement du composant - loadCSV(); - - return ( -
-

Loaded Promotions

- -

{statusMessage.value}

-
    - {promotions.value.map((promotion) => ( -
  • - {promotion.name} -
      - {promotion.students.map((student, index) => ( -
    • - {student.firstName} {student.lastName} - {student.email} -
    • - ))} -
    -
  • - ))} -
-
- ); -} diff --git a/routes/(apps)/mobility/(_islands)/UploadStudents.tsx b/routes/(apps)/mobility/(_islands)/UploadStudents.tsx index c1e717d..ea87ce1 100644 --- a/routes/(apps)/mobility/(_islands)/UploadStudents.tsx +++ b/routes/(apps)/mobility/(_islands)/UploadStudents.tsx @@ -1,123 +1,74 @@ // @deno-types="https://cdn.sheetjs.com/xlsx-0.20.3/package/types/index.d.ts" import * as XLSX from "https://cdn.sheetjs.com/xlsx-0.20.3/package/xlsx.mjs"; import { useSignal } from "@preact/signals"; -import Papa from "https://cdn.skypack.dev/papaparse"; // Bibliothèque pour manipuler CSVs - -type Student = { - firstName: string; - lastName: string; - email: string; -}; - -type Promotion = { - name: string; - students: Student[]; -}; +import insertIntoMobility from "../../../../databases/mobility.ts"; export default function UploadStudents() { - const promotions = useSignal([]); - const tempPromotions = useSignal([]); const statusMessage = useSignal(""); + const fileData = useSignal(null); - const handleFileUpload = async (event: Event) => { + const handleFileChange = (event: Event) => { const input = event.target as HTMLInputElement; - if (!input.files || input.files.length === 0) { + if (input.files && input.files.length > 0) { + fileData.value = input.files[0]; + statusMessage.value = "File selected: " + input.files[0].name; + } else { + fileData.value = null; statusMessage.value = "No file selected"; + } + }; + + const handleUpload = async () => { + if (!fileData.value) { + statusMessage.value = "Please select a file before confirming upload."; return; } - const file = input.files[0]; - const reader = new FileReader(); + try { + const reader = new FileReader(); + reader.onload = async (e) => { + try { + const arrayBuffer = e.target?.result as ArrayBuffer; + const workbook = XLSX.read(arrayBuffer, { type: "array" }); - reader.onload = async (e) => { - try { - const arrayBuffer = e.target?.result as ArrayBuffer; + for (const sheetName of workbook.SheetNames) { + const sheet = workbook.Sheets[sheetName]; + const data = XLSX.utils.sheet_to_json(sheet, { + header: ["firstName", "lastName", "email"], + range: 1, // Ignorer les en-têtes + }); - // Lire le classeur Excel - const workbook = XLSX.read(arrayBuffer, { type: "array" }); + console.log(`Data from sheet ${sheetName}:`, data); - const newPromotions: Promotion[] = []; - workbook.SheetNames.forEach((sheetName) => { - const worksheet = workbook.Sheets[sheetName]; - const students: Student[] = XLSX.utils.sheet_to_json(worksheet, { - header: ["firstName", "lastName", "email"], - range: 1, // Skip header row - }); + // Insérer les données dans la base de données + await insertIntoMobility(data as Array<{ firstName: string; lastName: string; email: string }>, sheetName); + } - newPromotions.push({ name: sheetName, students }); - }); + statusMessage.value = "File uploaded and data inserted successfully!"; + } catch (error) { + console.error("Error reading or inserting file:", error); + statusMessage.value = "Error processing the file. Please check its format."; + } + }; - tempPromotions.value = newPromotions; // Charger temporairement les promotions - statusMessage.value = "File loaded. Please confirm to save."; - } catch (error) { - statusMessage.value = "Error processing file"; - console.error(error); - } - }; + reader.onerror = (e) => { + console.error("FileReader error:", e); + statusMessage.value = "Error reading the file."; + }; - reader.readAsArrayBuffer(file); - }; - - const confirmFileUpload = () => { - if (tempPromotions.value.length > 0) { - promotions.value = tempPromotions.value; // Mettre à jour les promotions - tempPromotions.value = []; // Réinitialiser le tampon temporaire - statusMessage.value = "Promotions updated successfully!"; - savePromotionsToCSV(promotions.value); // Enregistrer dans un fichier CSV - } else { - statusMessage.value = "No data to confirm."; + reader.readAsArrayBuffer(fileData.value); + } catch (error) { + console.error("Error uploading file:", error); + statusMessage.value = "An unexpected error occurred during upload."; } }; - const savePromotionsToCSV = (data: Promotion[]) => { - const csvData = data.map((promotion) => { - return promotion.students.map((student) => ({ - promotion: promotion.name, - firstName: student.firstName, - lastName: student.lastName, - email: student.email, - })); - }); - - const flatData = csvData.flat(); - const csv = Papa.unparse(flatData); - const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" }); - const url = URL.createObjectURL(blob); - - // Télécharger le fichier - const link = document.createElement("a"); - link.setAttribute("href", url); - link.setAttribute("download", "students.csv"); - link.style.visibility = "hidden"; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - }; - return (
-

Upload Promotions

- - +

Upload Students

+ +

{statusMessage.value}

- -
-

Available Promotions

-
    - {promotions.value.map((promotion) => ( -
  • - {promotion.name} -
      - {promotion.students.map((student, index) => ( -
    • - {student.firstName} {student.lastName} - {student.email} -
    • - ))} -
    -
  • - ))} -
-
); } diff --git a/routes/(apps)/mobility/partials/students.tsx b/routes/(apps)/mobility/partials/students.tsx index 9f40c20..bef23ec 100644 --- a/routes/(apps)/mobility/partials/students.tsx +++ b/routes/(apps)/mobility/partials/students.tsx @@ -1,20 +1,20 @@ -import { Partial } from "$fresh/runtime.ts"; import { RouteConfig } from "$fresh/server.ts"; import UploadStudents from "../(_islands)/UploadStudents.tsx"; -import SaveStudents from "../(_islands)/SaveStudents.tsx"; +//import ConsultStudents from "../(_islands)/ConsultStudents.tsx"; +//import EditStudents from "../(_islands)/EditStudents.tsx"; export const config: RouteConfig = { - skipAppWrapper: true, - skipInheritedLayouts: true, + skipAppWrapper: false, + skipInheritedLayouts: false, }; export default function Students() { return ( - +

Manage Promotions


- - + +
); }