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:
@@ -1,5 +1,35 @@
|
|||||||
# Changelog - SimpleConnect Electron
|
# 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
|
## [1.2.13] - 2025-09-04
|
||||||
|
|
||||||
### Corrigé
|
### Corrigé
|
||||||
|
|||||||
60
main.js
60
main.js
@@ -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) => {
|
ipcMain.handle('save-notes', (event, noteData) => {
|
||||||
const notesDir = path.join(__dirname, 'notes');
|
const notesDir = path.join(__dirname, 'notes');
|
||||||
if (!fs.existsSync(notesDir)) {
|
if (!fs.existsSync(notesDir)) {
|
||||||
fs.mkdirSync(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);
|
const filePath = path.join(notesDir, fileName);
|
||||||
|
|
||||||
fs.writeFileSync(filePath, JSON.stringify({
|
// Lire l'historique existant si le fichier existe
|
||||||
|
let notesData = {
|
||||||
agent: currentAgent.id,
|
agent: currentAgent.id,
|
||||||
timestamp: new Date().toISOString(),
|
agentName: currentAgent.name,
|
||||||
...noteData
|
currentNote: noteData.content,
|
||||||
}, null, 2));
|
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 };
|
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
|
// Obtenir l'historique des appels
|
||||||
ipcMain.handle('get-call-history', () => {
|
ipcMain.handle('get-call-history', () => {
|
||||||
const historyFile = path.join(__dirname, 'call_history.json');
|
const historyFile = path.join(__dirname, 'call_history.json');
|
||||||
|
|||||||
117
renderer.js
117
renderer.js
@@ -40,6 +40,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
currentAgent = agentData.agent;
|
currentAgent = agentData.agent;
|
||||||
currentCentres = agentData.centres;
|
currentCentres = agentData.centres;
|
||||||
showMainPage();
|
showMainPage();
|
||||||
|
// Les notes seront chargées dans showMainPage()
|
||||||
} else {
|
} else {
|
||||||
// S'assurer que le formulaire est propre au démarrage
|
// S'assurer que le formulaire est propre au démarrage
|
||||||
resetLoginForm();
|
resetLoginForm();
|
||||||
@@ -437,6 +438,12 @@ function showMainPage() {
|
|||||||
});
|
});
|
||||||
selectCenter(sortedCentres[0].id);
|
selectCenter(sortedCentres[0].id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Charger les notes sauvegardées APRÈS que la page soit affichée
|
||||||
|
setTimeout(() => {
|
||||||
|
loadSavedNotes();
|
||||||
|
setupAutoSave();
|
||||||
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === GESTION DES CENTRES ===
|
// === GESTION DES CENTRES ===
|
||||||
@@ -692,6 +699,11 @@ async function saveNotes() {
|
|||||||
return;
|
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', {
|
const result = await ipcRenderer.invoke('save-notes', {
|
||||||
content: notes,
|
content: notes,
|
||||||
centre: activeCenter
|
centre: activeCenter
|
||||||
@@ -699,11 +711,89 @@ async function saveNotes() {
|
|||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
showNotification('Notes sauvegardées avec succès !', 'success');
|
showNotification('Notes sauvegardées avec succès !', 'success');
|
||||||
// Optionnel : garder les notes ou les effacer
|
// Ajouter à l'historique local
|
||||||
// document.getElementById('quickNotes').value = '';
|
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 ===
|
// === GESTION DES TERMINAUX ===
|
||||||
let availableTerminals = []; // Stocker les terminaux disponibles
|
let availableTerminals = []; // Stocker les terminaux disponibles
|
||||||
let terminalChoices = null; // Instance Choices.js
|
let terminalChoices = null; // Instance Choices.js
|
||||||
@@ -931,7 +1021,30 @@ function clearNotes() {
|
|||||||
const textarea = document.getElementById('quickNotes');
|
const textarea = document.getElementById('quickNotes');
|
||||||
if (textarea && confirm('Êtes-vous sûr de vouloir effacer toutes les notes ?')) {
|
if (textarea && confirm('Êtes-vous sûr de vouloir effacer toutes les notes ?')) {
|
||||||
textarea.value = '';
|
textarea.value = '';
|
||||||
|
// Effacer aussi de localStorage
|
||||||
|
localStorage.removeItem('currentNotes');
|
||||||
|
localStorage.removeItem('currentNotesDate');
|
||||||
textarea.focus();
|
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é
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user