feat: Système de persistance des notes amélioré avec fichier unique par agent

- Un seul fichier notes_{agentId}.json par agent (plus d'accumulation)
- Auto-save après 2 secondes d'inactivité
- Restauration automatique au démarrage depuis fichier ou localStorage
- Historique des 50 dernières versions intégré dans le fichier
- Synchronisation transparente fichier/localStorage
- Notifications visuelles lors de la restauration
This commit is contained in:
Pierre Marx
2025-09-04 16:49:07 -04:00
parent 0aaa3e63f2
commit 06b4e2819d
3 changed files with 199 additions and 8 deletions

View File

@@ -1,5 +1,35 @@
# Changelog - SimpleConnect Electron
## [1.2.14] - 2025-09-04
### Ajouté
- **Système de persistance des notes amélioré** : Sauvegarde et restauration automatiques
- Auto-save après 2 secondes d'inactivité
- Restauration automatique des notes au démarrage
- Synchronisation localStorage + fichier serveur
- Notification visuelle lors de la restauration
- Historique local des 20 dernières notes dans localStorage
### Modifié
- **Gestion des fichiers de notes** : Un seul fichier par agent au lieu de multiples
- Format `notes_{agentId}.json` unique par agent
- Mise à jour du même fichier à chaque sauvegarde
- Historique des 50 dernières versions intégré dans le fichier
- Plus d'accumulation de fichiers datés
### Amélioré
- **Expérience utilisateur des notes** : Persistance transparente
- Chargement prioritaire depuis le fichier serveur
- Fallback sur localStorage si fichier absent
- Bouton "Effacer" vide aussi localStorage
- Messages de confirmation et notifications
### Technique
- Nouvelle fonction `loadSavedNotes()` asynchrone
- Handler IPC `get-notes` pour récupérer depuis le serveur
- Auto-save avec debouncing de 2 secondes
- Structure JSON avec note courante + historique
## [1.2.13] - 2025-09-04
### Corrigé

60
main.js
View File

@@ -471,25 +471,73 @@ ipcMain.handle('get-simulated-calls', () => {
});
});
// Sauvegarder les notes de l'agent
// Sauvegarder les notes de l'agent (un seul fichier par agent)
ipcMain.handle('save-notes', (event, noteData) => {
const notesDir = path.join(__dirname, 'notes');
if (!fs.existsSync(notesDir)) {
fs.mkdirSync(notesDir);
}
const fileName = `notes_${currentAgent.id}_${Date.now()}.json`;
// Un seul fichier par agent, mis à jour à chaque sauvegarde
const fileName = `notes_${currentAgent.id}.json`;
const filePath = path.join(notesDir, fileName);
fs.writeFileSync(filePath, JSON.stringify({
// Lire l'historique existant si le fichier existe
let notesData = {
agent: currentAgent.id,
timestamp: new Date().toISOString(),
...noteData
}, null, 2));
agentName: currentAgent.name,
currentNote: noteData.content,
lastModified: new Date().toISOString(),
centre: noteData.centre,
history: []
};
// Si le fichier existe, préserver l'historique
if (fs.existsSync(filePath)) {
try {
const existingData = JSON.parse(fs.readFileSync(filePath, 'utf8'));
// Ajouter l'ancienne note à l'historique si elle a changé
if (existingData.currentNote && existingData.currentNote !== noteData.content) {
notesData.history = existingData.history || [];
notesData.history.unshift({
content: existingData.currentNote,
date: existingData.lastModified,
centre: existingData.centre
});
// Limiter l'historique à 50 entrées
notesData.history = notesData.history.slice(0, 50);
}
} catch (error) {
console.error('Erreur lecture notes existantes:', error);
}
}
fs.writeFileSync(filePath, JSON.stringify(notesData, null, 2));
return { success: true, file: fileName };
});
// Récupérer les notes de l'agent
ipcMain.handle('get-notes', () => {
if (!currentAgent) return null;
const notesDir = path.join(__dirname, 'notes');
const fileName = `notes_${currentAgent.id}.json`;
const filePath = path.join(notesDir, fileName);
if (fs.existsSync(filePath)) {
try {
const data = fs.readFileSync(filePath, 'utf8');
return JSON.parse(data);
} catch (error) {
console.error('Erreur lecture notes:', error);
return null;
}
}
return null;
});
// Obtenir l'historique des appels
ipcMain.handle('get-call-history', () => {
const historyFile = path.join(__dirname, 'call_history.json');

View File

@@ -40,6 +40,7 @@ document.addEventListener('DOMContentLoaded', async () => {
currentAgent = agentData.agent;
currentCentres = agentData.centres;
showMainPage();
// Les notes seront chargées dans showMainPage()
} else {
// S'assurer que le formulaire est propre au démarrage
resetLoginForm();
@@ -437,6 +438,12 @@ function showMainPage() {
});
selectCenter(sortedCentres[0].id);
}
// Charger les notes sauvegardées APRÈS que la page soit affichée
setTimeout(() => {
loadSavedNotes();
setupAutoSave();
}, 100);
}
// === GESTION DES CENTRES ===
@@ -692,6 +699,11 @@ async function saveNotes() {
return;
}
// Sauvegarder dans localStorage pour persistance immédiate
localStorage.setItem('currentNotes', notes);
localStorage.setItem('currentNotesDate', new Date().toISOString());
// Sauvegarder aussi dans un fichier pour historique
const result = await ipcRenderer.invoke('save-notes', {
content: notes,
centre: activeCenter
@@ -699,11 +711,89 @@ async function saveNotes() {
if (result.success) {
showNotification('Notes sauvegardées avec succès !', 'success');
// Optionnel : garder les notes ou les effacer
// document.getElementById('quickNotes').value = '';
// Ajouter à l'historique local
addToNotesHistory(notes, activeCenter);
}
}
// Charger les notes sauvegardées au démarrage
async function loadSavedNotes() {
const textarea = document.getElementById('quickNotes');
if (!textarea) return;
// D'abord essayer de charger depuis le fichier serveur
try {
const serverNotes = await ipcRenderer.invoke('get-notes');
if (serverNotes && serverNotes.currentNote) {
textarea.value = serverNotes.currentNote;
// Sauvegarder aussi dans localStorage pour synchronisation
localStorage.setItem('currentNotes', serverNotes.currentNote);
localStorage.setItem('currentNotesDate', serverNotes.lastModified);
const date = new Date(serverNotes.lastModified);
const formattedDate = date.toLocaleString('fr-FR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
showNotification(`Notes restaurées (${formattedDate})`, 'info');
console.log(`Notes chargées depuis le serveur (${formattedDate})`);
return;
}
} catch (error) {
console.error('Erreur chargement notes serveur:', error);
}
// Sinon, charger depuis localStorage
const savedNotes = localStorage.getItem('currentNotes');
const savedDate = localStorage.getItem('currentNotesDate');
if (savedNotes) {
textarea.value = savedNotes;
if (savedDate) {
const date = new Date(savedDate);
const formattedDate = date.toLocaleString('fr-FR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
console.log(`Notes restaurées depuis localStorage (${formattedDate})`);
}
} else {
textarea.value = '';
console.log('Aucune note sauvegardée à restaurer');
}
}
// Ajouter à l'historique des notes
function addToNotesHistory(content, centre) {
let history = JSON.parse(localStorage.getItem('notesHistory') || '[]');
history.unshift({
content: content,
centre: centre,
date: new Date().toISOString(),
id: Date.now()
});
// Garder seulement les 20 dernières notes
history = history.slice(0, 20);
localStorage.setItem('notesHistory', JSON.stringify(history));
}
// Récupérer l'historique des notes
function getNotesHistory() {
return JSON.parse(localStorage.getItem('notesHistory') || '[]');
}
// === GESTION DES TERMINAUX ===
let availableTerminals = []; // Stocker les terminaux disponibles
let terminalChoices = null; // Instance Choices.js
@@ -931,7 +1021,30 @@ function clearNotes() {
const textarea = document.getElementById('quickNotes');
if (textarea && confirm('Êtes-vous sûr de vouloir effacer toutes les notes ?')) {
textarea.value = '';
// Effacer aussi de localStorage
localStorage.removeItem('currentNotes');
localStorage.removeItem('currentNotesDate');
textarea.focus();
showNotification('Notes effacées', 'info');
}
}
// Sauvegarder automatiquement les notes en cours de frappe (debounced)
let autoSaveTimeout;
function setupAutoSave() {
const textarea = document.getElementById('quickNotes');
if (textarea) {
textarea.addEventListener('input', () => {
clearTimeout(autoSaveTimeout);
autoSaveTimeout = setTimeout(() => {
const notes = textarea.value;
if (notes.trim()) {
localStorage.setItem('currentNotes', notes);
localStorage.setItem('currentNotesDate', new Date().toISOString());
console.log('Notes auto-sauvegardées');
}
}, 2000); // Sauvegarder après 2 secondes d'inactivité
});
}
}