- améliore l'export/import (format de fichiers en paramètres, amélioration de la robustesse, )

- ajout bouton tout effacer des propositions et participants
This commit is contained in:
Yannick Le Duc
2025-09-16 15:45:28 +02:00
parent 6aead108d7
commit 2a2738f5c0
16 changed files with 1455 additions and 81 deletions

View File

@@ -23,15 +23,34 @@ export function parseCSV(file: File): Promise<ParsedFileData> {
return;
}
const headers = lines[0].split(',').map(h => h.trim().replace(/"/g, ''));
const data = lines.slice(1).map(line => {
const values = line.split(',').map(v => v.trim().replace(/"/g, ''));
const row: any = {};
headers.forEach((header, index) => {
row[header] = values[index] || '';
// Trouver la ligne d'en-têtes (ignorer les lignes de titre et vides)
let headerLineIndex = 0;
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
// Si la ligne contient des virgules et ressemble à des en-têtes
if (line.includes(',') && !line.toLowerCase().includes('modèle') && !line.toLowerCase().includes('liste')) {
headerLineIndex = i;
break;
}
}
const headers = lines[headerLineIndex].split(',').map(h => h.trim().replace(/"/g, ''));
const dataLines = lines.slice(headerLineIndex + 1);
const data = dataLines
.filter(line => line.trim()) // Ignorer les lignes vides
.map(line => {
const values = line.split(',').map(v => v.trim().replace(/"/g, ''));
const row: any = {};
headers.forEach((header, index) => {
row[header] = values[index] || '';
});
return row;
})
.filter(row => {
// Ignorer les lignes où tous les champs sont vides
return Object.values(row).some(value => value && value.toString().trim());
});
return row;
});
resolve({ data, headers });
} catch (error) {
@@ -62,16 +81,39 @@ export function parseExcel(file: File): Promise<ParsedFileData> {
return;
}
const headers = jsonData[0] as string[];
const rows = jsonData.slice(1) as any[][];
// Trouver la ligne d'en-têtes (ignorer les lignes de titre et vides)
let headerLineIndex = 0;
for (let i = 0; i < jsonData.length; i++) {
const row = jsonData[i] as any[];
if (row && row.length > 0) {
const firstCell = row[0];
// Si la première cellule ressemble à un en-tête et pas à un titre
if (firstCell && typeof firstCell === 'string' &&
!firstCell.toLowerCase().includes('modèle') &&
!firstCell.toLowerCase().includes('liste') &&
!firstCell.toLowerCase().includes('propositions')) {
headerLineIndex = i;
break;
}
}
}
const headers = (jsonData[headerLineIndex] as string[]).filter(h => h && h.toString().trim());
const rows = jsonData.slice(headerLineIndex + 1) as any[][];
const parsedData = rows.map(row => {
const rowData: any = {};
headers.forEach((header, index) => {
rowData[header] = row[index] || '';
const parsedData = rows
.filter(row => row && row.length > 0) // Ignorer les lignes vides
.map(row => {
const rowData: any = {};
headers.forEach((header, index) => {
rowData[header] = row[index] || '';
});
return rowData;
})
.filter(rowData => {
// Ignorer les lignes où tous les champs sont vides
return Object.values(rowData).some(value => value && value.toString().trim());
});
return rowData;
});
resolve({ data: parsedData, headers });
} catch (error) {
@@ -84,22 +126,47 @@ export function parseExcel(file: File): Promise<ParsedFileData> {
export function getExpectedColumns(type: 'propositions' | 'participants'): string[] {
if (type === 'propositions') {
return ['title', 'description', 'author_first_name', 'author_last_name', 'author_email'];
return ['Titre', 'Description', 'Prénom', 'Nom', 'Email'];
} else {
return ['first_name', 'last_name', 'email'];
return ['Prénom', 'Nom', 'Email'];
}
}
export function downloadTemplate(type: 'propositions' | 'participants'): void {
export async function downloadTemplate(type: 'propositions' | 'participants'): Promise<void> {
const columns = getExpectedColumns(type);
const csvContent = columns.join(',') + '\n';
const blob = new Blob([csvContent], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `template_${type}.csv`;
a.click();
window.URL.revokeObjectURL(url);
// Importer dynamiquement la fonction pour éviter les dépendances circulaires
const { getExportFileFormat, generateExportFile, downloadExportFile } = await import('./export-utils');
const format = await getExportFileFormat();
// Créer la matrice de données avec les en-têtes
const matrix: string[][] = [];
// Pour les formats Excel/ODS, ajouter un titre
if (format !== 'csv') {
matrix.push([`Modèle d'import - ${type === 'propositions' ? 'Propositions' : 'Participants'}`]);
matrix.push([]); // Ligne vide
}
matrix.push(columns); // En-têtes des colonnes
// Ajouter quelques lignes d'exemple
if (type === 'propositions') {
matrix.push(['Exemple de proposition', 'Description de la proposition', 'Jean', 'Dupont', 'jean.dupont@example.com']);
matrix.push(['Autre proposition', 'Autre description', 'Marie', 'Martin', 'marie.martin@example.com']);
} else {
matrix.push(['Jean', 'Dupont', 'jean.dupont@example.com']);
matrix.push(['Marie', 'Martin', 'marie.martin@example.com']);
}
// Générer le fichier dans le format configuré
const data = generateExportFile(matrix, format);
// Créer le nom de fichier avec l'extension appropriée
const filename = `template_${type}.${format}`;
// Télécharger le fichier
downloadExportFile(data, filename, format);
}
export function validateFileType(file: File): { isValid: boolean; error?: string } {