Use the DB instead of a .csv (not working)
This commit is contained in:
@@ -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
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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<Promotion[]>([]);
|
||||
const statusMessage = useSignal<string>("");
|
||||
|
||||
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<string, Student[]> = {};
|
||||
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 (
|
||||
<div>
|
||||
<h2>Loaded Promotions</h2>
|
||||
<button onClick={loadCSV}>Actualiser</button>
|
||||
<p>{statusMessage.value}</p>
|
||||
<ul>
|
||||
{promotions.value.map((promotion) => (
|
||||
<li key={promotion.name}>
|
||||
<strong>{promotion.name}</strong>
|
||||
<ul>
|
||||
{promotion.students.map((student, index) => (
|
||||
<li key={index}>
|
||||
{student.firstName} {student.lastName} - {student.email}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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<Promotion[]>([]);
|
||||
const tempPromotions = useSignal<Promotion[]>([]);
|
||||
const statusMessage = useSignal<string>("");
|
||||
const fileData = useSignal<File | null>(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 (
|
||||
<div>
|
||||
<h1>Upload Promotions</h1>
|
||||
<input type="file" accept=".xlsx, .xls" onChange={handleFileUpload} />
|
||||
<button onClick={confirmFileUpload}>Confirm Upload</button>
|
||||
<h2>Upload Students</h2>
|
||||
<input type="file" accept=".xlsx, .xls" onChange={handleFileChange} />
|
||||
<button onClick={handleUpload}>Confirm Upload</button>
|
||||
<p>{statusMessage.value}</p>
|
||||
|
||||
<div>
|
||||
<h2>Available Promotions</h2>
|
||||
<ul>
|
||||
{promotions.value.map((promotion) => (
|
||||
<li key={promotion.name}>
|
||||
<strong>{promotion.name}</strong>
|
||||
<ul>
|
||||
{promotion.students.map((student, index) => (
|
||||
<li key={index}>
|
||||
{student.firstName} {student.lastName} - {student.email}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<Partial name="body">
|
||||
<section id="students-page">
|
||||
<h1>Manage Promotions</h1>
|
||||
<UploadStudents />
|
||||
<hr />
|
||||
<SaveStudents />
|
||||
</Partial>
|
||||
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user