refactoring majeur (code dupliqué, mort, ...)
- Économie : ~1240 lignes de code dupliqué - Réduction : ~60% du code modal - Amélioration : Cohérence et maintenabilité
This commit is contained in:
120
src/lib/file-utils.ts
Normal file
120
src/lib/file-utils.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
/**
|
||||
* Utilitaires centralisés pour le traitement des fichiers
|
||||
*/
|
||||
|
||||
export interface ParsedFileData {
|
||||
data: any[];
|
||||
headers: string[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export function parseCSV(file: File): Promise<ParsedFileData> {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
try {
|
||||
const text = e.target?.result as string;
|
||||
const lines = text.split('\n').filter(line => line.trim());
|
||||
|
||||
if (lines.length < 2) {
|
||||
resolve({ data: [], headers: [], error: 'Le fichier doit contenir au moins un en-tête et une ligne de données.' });
|
||||
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] || '';
|
||||
});
|
||||
return row;
|
||||
});
|
||||
|
||||
resolve({ data, headers });
|
||||
} catch (error) {
|
||||
resolve({ data: [], headers: [], error: 'Erreur lors de la lecture du fichier CSV.' });
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
});
|
||||
}
|
||||
|
||||
export function parseExcel(file: File): Promise<ParsedFileData> {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
try {
|
||||
const fileData = new Uint8Array(e.target?.result as ArrayBuffer);
|
||||
const workbook = XLSX.read(fileData, { type: 'array' });
|
||||
|
||||
// Prendre la première feuille
|
||||
const sheetName = workbook.SheetNames[0];
|
||||
const worksheet = workbook.Sheets[sheetName];
|
||||
|
||||
// Convertir en JSON
|
||||
const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
|
||||
|
||||
if (jsonData.length < 2) {
|
||||
resolve({ data: [], headers: [], error: 'Le fichier doit contenir au moins un en-tête et une ligne de données.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = jsonData[0] as string[];
|
||||
const rows = jsonData.slice(1) as any[][];
|
||||
|
||||
const parsedData = rows.map(row => {
|
||||
const rowData: any = {};
|
||||
headers.forEach((header, index) => {
|
||||
rowData[header] = row[index] || '';
|
||||
});
|
||||
return rowData;
|
||||
});
|
||||
|
||||
resolve({ data: parsedData, headers });
|
||||
} catch (error) {
|
||||
resolve({ data: [], headers: [], error: 'Erreur lors de la lecture du fichier Excel.' });
|
||||
}
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
}
|
||||
|
||||
export function getExpectedColumns(type: 'propositions' | 'participants'): string[] {
|
||||
if (type === 'propositions') {
|
||||
return ['title', 'description', 'author_first_name', 'author_last_name', 'author_email'];
|
||||
} else {
|
||||
return ['first_name', 'last_name', 'email'];
|
||||
}
|
||||
}
|
||||
|
||||
export function downloadTemplate(type: 'propositions' | 'participants'): 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);
|
||||
}
|
||||
|
||||
export function validateFileType(file: File): { isValid: boolean; error?: string } {
|
||||
const isCSV = file.type === 'text/csv' || file.name.toLowerCase().endsWith('.csv');
|
||||
const isExcel = file.type === 'application/vnd.oasis.opendocument.spreadsheet' ||
|
||||
file.name.toLowerCase().endsWith('.ods') ||
|
||||
file.name.toLowerCase().endsWith('.xlsx') ||
|
||||
file.name.toLowerCase().endsWith('.xls');
|
||||
|
||||
if (!isCSV && !isExcel) {
|
||||
return {
|
||||
isValid: false,
|
||||
error: 'Veuillez sélectionner un fichier valide (CSV, ODS, XLSX ou XLS).'
|
||||
};
|
||||
}
|
||||
|
||||
return { isValid: true };
|
||||
}
|
||||
30
src/lib/form-utils.ts
Normal file
30
src/lib/form-utils.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Utilitaires centralisés pour la gestion des formulaires
|
||||
*/
|
||||
|
||||
export function handleFormError(err: any, operation: string): string {
|
||||
const errorMessage = err?.message || err?.details || `Erreur lors de ${operation}`;
|
||||
console.error(`Erreur lors de ${operation}:`, err);
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
export function validateRequiredFields(data: Record<string, any>, requiredFields: string[]): string[] {
|
||||
const errors: string[] = [];
|
||||
|
||||
for (const field of requiredFields) {
|
||||
if (!data[field] || (typeof data[field] === 'string' && data[field].trim() === '')) {
|
||||
errors.push(`Le champ "${field}" est requis`);
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
export function validateEmail(email: string): boolean {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
}
|
||||
|
||||
export function formatErrorMessage(errors: string[]): string {
|
||||
return errors.join('. ');
|
||||
}
|
||||
@@ -637,19 +637,6 @@ export const settingsService = {
|
||||
|
||||
async testSmtpConnection(smtpSettings: SmtpSettings): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
// Validation basique des paramètres
|
||||
if (!smtpSettings.host || !smtpSettings.port || !smtpSettings.username || !smtpSettings.password) {
|
||||
return { success: false, error: 'Paramètres SMTP incomplets' };
|
||||
}
|
||||
|
||||
if (smtpSettings.port < 1 || smtpSettings.port > 65535) {
|
||||
return { success: false, error: 'Port SMTP invalide' };
|
||||
}
|
||||
|
||||
if (!smtpSettings.from_email.includes('@')) {
|
||||
return { success: false, error: 'Adresse email d\'expédition invalide' };
|
||||
}
|
||||
|
||||
// Test de connexion via API route
|
||||
return await emailService.testConnection(smtpSettings);
|
||||
} catch (error) {
|
||||
@@ -659,11 +646,6 @@ export const settingsService = {
|
||||
|
||||
async sendTestEmail(smtpSettings: SmtpSettings, toEmail: string): Promise<{ success: boolean; error?: string; messageId?: string }> {
|
||||
try {
|
||||
// Validation de l'email de destination
|
||||
if (!emailService.validateEmail(toEmail)) {
|
||||
return { success: false, error: 'Adresse email de destination invalide' };
|
||||
}
|
||||
|
||||
// Envoi de l'email de test via API route
|
||||
return await emailService.sendTestEmail(smtpSettings, toEmail);
|
||||
} catch (error) {
|
||||
|
||||
47
src/lib/smtp-utils.ts
Normal file
47
src/lib/smtp-utils.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { SmtpSettings } from '@/types';
|
||||
|
||||
/**
|
||||
* Utilitaires centralisés pour la validation et la gestion SMTP
|
||||
*/
|
||||
|
||||
export function validateSmtpSettings(smtpSettings: SmtpSettings): { isValid: boolean; error?: string } {
|
||||
// Validation basique des paramètres
|
||||
if (!smtpSettings.host || !smtpSettings.port || !smtpSettings.username || !smtpSettings.password) {
|
||||
return { isValid: false, error: 'Paramètres SMTP incomplets' };
|
||||
}
|
||||
|
||||
if (smtpSettings.port < 1 || smtpSettings.port > 65535) {
|
||||
return { isValid: false, error: 'Port SMTP invalide' };
|
||||
}
|
||||
|
||||
if (!smtpSettings.from_email.includes('@')) {
|
||||
return { isValid: false, error: 'Adresse email d\'expédition invalide' };
|
||||
}
|
||||
|
||||
return { isValid: true };
|
||||
}
|
||||
|
||||
export function validateEmail(email: string): boolean {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
}
|
||||
|
||||
export function createSmtpTransporterConfig(smtpSettings: SmtpSettings) {
|
||||
return {
|
||||
host: smtpSettings.host,
|
||||
port: smtpSettings.port,
|
||||
secure: smtpSettings.secure, // true pour 465, false pour les autres ports
|
||||
auth: {
|
||||
user: smtpSettings.username,
|
||||
pass: smtpSettings.password,
|
||||
},
|
||||
// Options pour résoudre les problèmes DNS
|
||||
tls: {
|
||||
rejectUnauthorized: false, // Accepte les certificats auto-signés
|
||||
},
|
||||
// Timeout pour éviter les blocages
|
||||
connectionTimeout: 10000, // 10 secondes
|
||||
greetingTimeout: 10000,
|
||||
socketTimeout: 10000,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user