Version initiale
This commit is contained in:
395
renderer.js
Normal file
395
renderer.js
Normal file
@@ -0,0 +1,395 @@
|
||||
const { ipcRenderer } = require('electron');
|
||||
|
||||
// Variables globales
|
||||
let currentAgent = null;
|
||||
let currentCentres = [];
|
||||
let activeCenter = null;
|
||||
let webviews = {};
|
||||
let callStats = {
|
||||
calls: 0,
|
||||
appointments: 0
|
||||
};
|
||||
|
||||
// === GESTION DE LA CONNEXION ===
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Vérifier si un agent est déjà connecté
|
||||
const agentData = await ipcRenderer.invoke('get-current-agent');
|
||||
if (agentData) {
|
||||
currentAgent = agentData.agent;
|
||||
currentCentres = agentData.centres;
|
||||
showMainPage();
|
||||
}
|
||||
|
||||
// Gestionnaire du formulaire de connexion
|
||||
const loginForm = document.getElementById('loginForm');
|
||||
if (loginForm) {
|
||||
loginForm.addEventListener('submit', handleLogin);
|
||||
}
|
||||
|
||||
// Bouton de déconnexion
|
||||
const logoutBtn = document.getElementById('logoutBtn');
|
||||
if (logoutBtn) {
|
||||
logoutBtn.addEventListener('click', handleLogout);
|
||||
}
|
||||
|
||||
// Bouton simulation d'appel
|
||||
const simulateBtn = document.getElementById('simulateCallBtn');
|
||||
if (simulateBtn) {
|
||||
simulateBtn.addEventListener('click', showCallSimulation);
|
||||
}
|
||||
|
||||
// Bouton sauvegarder notes
|
||||
const saveNotesBtn = document.getElementById('saveNotesBtn');
|
||||
if (saveNotesBtn) {
|
||||
saveNotesBtn.addEventListener('click', saveNotes);
|
||||
}
|
||||
|
||||
// Écouter les appels entrants
|
||||
ipcRenderer.on('incoming-call', (event, callData) => {
|
||||
handleIncomingCall(callData);
|
||||
});
|
||||
});
|
||||
|
||||
// Connexion
|
||||
async function handleLogin(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const email = document.getElementById('email').value;
|
||||
const password = document.getElementById('password').value;
|
||||
const errorDiv = document.getElementById('loginError');
|
||||
|
||||
const result = await ipcRenderer.invoke('login-agent', { email, password });
|
||||
|
||||
if (result.success) {
|
||||
currentAgent = result.agent;
|
||||
currentCentres = result.centres;
|
||||
errorDiv.textContent = '';
|
||||
showMainPage();
|
||||
} else {
|
||||
errorDiv.textContent = result.message;
|
||||
}
|
||||
}
|
||||
|
||||
// Déconnexion
|
||||
async function handleLogout() {
|
||||
if (confirm('Voulez-vous vraiment vous déconnecter ?')) {
|
||||
await ipcRenderer.invoke('logout');
|
||||
currentAgent = null;
|
||||
currentCentres = [];
|
||||
activeCenter = null;
|
||||
webviews = {};
|
||||
showLoginPage();
|
||||
}
|
||||
}
|
||||
|
||||
// === GESTION DES PAGES ===
|
||||
function showLoginPage() {
|
||||
document.getElementById('loginPage').classList.add('active');
|
||||
document.getElementById('mainPage').classList.remove('active');
|
||||
}
|
||||
|
||||
function showMainPage() {
|
||||
document.getElementById('loginPage').classList.remove('active');
|
||||
document.getElementById('mainPage').classList.add('active');
|
||||
|
||||
// Afficher le nom de l'agent
|
||||
document.getElementById('agentName').textContent = currentAgent.name;
|
||||
|
||||
// Initialiser l'interface
|
||||
initializeCenters();
|
||||
updateStatus('available');
|
||||
}
|
||||
|
||||
// === GESTION DES CENTRES ===
|
||||
function initializeCenters() {
|
||||
const centersList = document.getElementById('centersList');
|
||||
const centerTabs = document.getElementById('centerTabs');
|
||||
const webviewContainer = document.getElementById('webviewContainer');
|
||||
|
||||
// Vider les contenus existants
|
||||
centersList.innerHTML = '';
|
||||
centerTabs.innerHTML = '';
|
||||
webviewContainer.innerHTML = '';
|
||||
|
||||
// Créer la liste des centres et les onglets
|
||||
currentCentres.forEach(centre => {
|
||||
// Élément dans la sidebar
|
||||
const centerItem = document.createElement('div');
|
||||
centerItem.className = 'center-item';
|
||||
centerItem.dataset.centerId = centre.id;
|
||||
centerItem.innerHTML = `
|
||||
<div class="center-indicator" style="background-color: ${centre.couleur}"></div>
|
||||
<div class="center-info">
|
||||
<div class="center-name">${centre.nom}</div>
|
||||
<div class="center-phone">${centre.telephone}</div>
|
||||
</div>
|
||||
<div class="center-status" id="status-${centre.id}">●</div>
|
||||
`;
|
||||
centerItem.addEventListener('click', () => selectCenter(centre.id));
|
||||
centersList.appendChild(centerItem);
|
||||
|
||||
// Onglet
|
||||
const tab = document.createElement('div');
|
||||
tab.className = 'tab';
|
||||
tab.dataset.centerId = centre.id;
|
||||
tab.style.borderBottomColor = centre.couleur;
|
||||
tab.textContent = centre.nom;
|
||||
tab.addEventListener('click', () => selectCenter(centre.id));
|
||||
centerTabs.appendChild(tab);
|
||||
|
||||
// Créer la webview
|
||||
const webviewWrapper = document.createElement('div');
|
||||
webviewWrapper.className = 'webview-wrapper';
|
||||
webviewWrapper.dataset.centerId = centre.id;
|
||||
webviewWrapper.style.display = 'none';
|
||||
|
||||
const webview = document.createElement('webview');
|
||||
webview.id = `webview-${centre.id}`;
|
||||
webview.src = centre.url;
|
||||
webview.className = 'planning-webview';
|
||||
webview.setAttribute('partition', `persist:${centre.id}`);
|
||||
webview.setAttribute('useragent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
|
||||
|
||||
// Barre d'outils pour la webview
|
||||
const toolbar = document.createElement('div');
|
||||
toolbar.className = 'webview-toolbar';
|
||||
toolbar.innerHTML = `
|
||||
<button onclick="navigateWebview('${centre.id}', 'back')">◀</button>
|
||||
<button onclick="navigateWebview('${centre.id}', 'forward')">▶</button>
|
||||
<button onclick="navigateWebview('${centre.id}', 'reload')">🔄</button>
|
||||
<span class="webview-url" id="url-${centre.id}">${centre.url}</span>
|
||||
`;
|
||||
|
||||
webviewWrapper.appendChild(toolbar);
|
||||
webviewWrapper.appendChild(webview);
|
||||
webviewContainer.appendChild(webviewWrapper);
|
||||
|
||||
// Stocker la référence de la webview
|
||||
webviews[centre.id] = webview;
|
||||
|
||||
// Gérer les événements de la webview
|
||||
webview.addEventListener('dom-ready', () => {
|
||||
console.log(`Webview ${centre.nom} prête`);
|
||||
document.getElementById(`status-${centre.id}`).style.color = '#4CAF50';
|
||||
|
||||
// Auto-connexion si credentials disponibles
|
||||
if (centre.credentials && centre.credentials.username) {
|
||||
// Injecter le script de connexion automatique (à adapter selon le site)
|
||||
const loginScript = `
|
||||
// Script générique de connexion - à adapter selon le planning
|
||||
console.log('Tentative de connexion automatique pour ${centre.nom}');
|
||||
`;
|
||||
webview.executeJavaScript(loginScript);
|
||||
}
|
||||
});
|
||||
|
||||
webview.addEventListener('did-navigate', (e) => {
|
||||
document.getElementById(`url-${centre.id}`).textContent = e.url;
|
||||
});
|
||||
|
||||
webview.addEventListener('did-fail-load', (e) => {
|
||||
console.error(`Erreur chargement ${centre.nom}:`, e);
|
||||
document.getElementById(`status-${centre.id}`).style.color = '#FF5252';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Sélectionner un centre
|
||||
function selectCenter(centerId) {
|
||||
// Mettre à jour le centre actif
|
||||
activeCenter = centerId;
|
||||
|
||||
// Mettre à jour l'UI
|
||||
document.querySelectorAll('.center-item').forEach(item => {
|
||||
item.classList.toggle('active', item.dataset.centerId === centerId);
|
||||
});
|
||||
|
||||
document.querySelectorAll('.tab').forEach(tab => {
|
||||
tab.classList.toggle('active', tab.dataset.centerId === centerId);
|
||||
});
|
||||
|
||||
// Afficher la bonne webview
|
||||
document.querySelectorAll('.webview-wrapper').forEach(wrapper => {
|
||||
wrapper.style.display = wrapper.dataset.centerId === centerId ? 'flex' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
// Navigation dans les webviews
|
||||
window.navigateWebview = function(centerId, action) {
|
||||
const webview = webviews[centerId];
|
||||
if (webview) {
|
||||
switch(action) {
|
||||
case 'back':
|
||||
webview.goBack();
|
||||
break;
|
||||
case 'forward':
|
||||
webview.goForward();
|
||||
break;
|
||||
case 'reload':
|
||||
webview.reload();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// === GESTION DES APPELS ===
|
||||
function handleIncomingCall(callData) {
|
||||
const centre = currentCentres.find(c => c.id === callData.centreId);
|
||||
if (!centre) return;
|
||||
|
||||
// Afficher l'alerte
|
||||
const alert = document.getElementById('incomingCallAlert');
|
||||
alert.classList.add('active');
|
||||
|
||||
document.getElementById('callCenterName').textContent = centre.nom;
|
||||
document.getElementById('callPatientInfo').textContent =
|
||||
`${callData.nom || 'Patient'} - ${callData.numero}`;
|
||||
|
||||
// Jouer un son (à implémenter)
|
||||
playNotificationSound();
|
||||
|
||||
// Gérer l'acceptation de l'appel
|
||||
const acceptBtn = document.getElementById('acceptCallBtn');
|
||||
acceptBtn.onclick = () => {
|
||||
acceptCall(callData, centre);
|
||||
};
|
||||
|
||||
// Auto-accepter après 3 secondes en mode démo
|
||||
setTimeout(() => {
|
||||
if (alert.classList.contains('active')) {
|
||||
acceptCall(callData, centre);
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function acceptCall(callData, centre) {
|
||||
// Masquer l'alerte
|
||||
document.getElementById('incomingCallAlert').classList.remove('active');
|
||||
|
||||
// Sélectionner automatiquement le bon centre
|
||||
selectCenter(centre.id);
|
||||
|
||||
// Mettre à jour le statut
|
||||
updateStatus('incall', centre.nom);
|
||||
|
||||
// Incrémenter les stats
|
||||
callStats.calls++;
|
||||
document.getElementById('callCount').textContent = callStats.calls;
|
||||
|
||||
// Sauvegarder l'appel dans l'historique
|
||||
ipcRenderer.invoke('save-call-history', {
|
||||
...callData,
|
||||
centreId: centre.id,
|
||||
centreName: centre.nom,
|
||||
status: 'answered'
|
||||
});
|
||||
|
||||
// Simuler la fin de l'appel après 30 secondes
|
||||
setTimeout(() => {
|
||||
endCall();
|
||||
}, 30000);
|
||||
}
|
||||
|
||||
function endCall() {
|
||||
updateStatus('available');
|
||||
callStats.appointments++;
|
||||
document.getElementById('appointmentCount').textContent = callStats.appointments;
|
||||
}
|
||||
|
||||
// === SIMULATION D'APPELS ===
|
||||
function showCallSimulation() {
|
||||
const modal = document.getElementById('callSimulationModal');
|
||||
modal.style.display = 'block';
|
||||
|
||||
// Charger les appels simulés
|
||||
loadSimulatedCalls();
|
||||
|
||||
// Fermer la modal
|
||||
modal.querySelector('.close').onclick = () => {
|
||||
modal.style.display = 'none';
|
||||
};
|
||||
|
||||
// Appel personnalisé
|
||||
document.getElementById('customCallBtn').onclick = () => {
|
||||
const customCall = {
|
||||
numero: prompt('Numéro de téléphone:'),
|
||||
nom: prompt('Nom du patient:'),
|
||||
centreId: currentCentres[0]?.id
|
||||
};
|
||||
if (customCall.numero) {
|
||||
ipcRenderer.invoke('simulate-call', customCall);
|
||||
modal.style.display = 'none';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function loadSimulatedCalls() {
|
||||
const calls = await ipcRenderer.invoke('get-simulated-calls');
|
||||
const listDiv = document.getElementById('simulatedCallsList');
|
||||
|
||||
listDiv.innerHTML = calls.map(call => `
|
||||
<div class="simulated-call-item" onclick="simulateThisCall('${JSON.stringify(call).replace(/'/g, "\\'")}')">
|
||||
<div class="call-name">${call.nom}</div>
|
||||
<div class="call-details">${call.numero} - ${call.centreNom}</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
window.simulateThisCall = function(callDataStr) {
|
||||
const callData = JSON.parse(callDataStr);
|
||||
ipcRenderer.invoke('simulate-call', callData);
|
||||
document.getElementById('callSimulationModal').style.display = 'none';
|
||||
};
|
||||
|
||||
// === UTILITAIRES ===
|
||||
function updateStatus(status, details = '') {
|
||||
const indicator = document.getElementById('statusIndicator');
|
||||
const text = document.getElementById('statusText');
|
||||
|
||||
switch(status) {
|
||||
case 'available':
|
||||
indicator.className = 'status-indicator available';
|
||||
text.textContent = 'Disponible';
|
||||
break;
|
||||
case 'incall':
|
||||
indicator.className = 'status-indicator busy';
|
||||
text.textContent = details ? `En appel - ${details}` : 'En appel';
|
||||
break;
|
||||
case 'offline':
|
||||
indicator.className = 'status-indicator offline';
|
||||
text.textContent = 'Hors ligne';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function playNotificationSound() {
|
||||
// Créer un bip simple avec l'API Web Audio
|
||||
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
const oscillator = audioContext.createOscillator();
|
||||
const gainNode = audioContext.createGain();
|
||||
|
||||
oscillator.connect(gainNode);
|
||||
gainNode.connect(audioContext.destination);
|
||||
|
||||
oscillator.frequency.value = 800;
|
||||
oscillator.type = 'sine';
|
||||
gainNode.gain.value = 0.3;
|
||||
|
||||
oscillator.start();
|
||||
oscillator.stop(audioContext.currentTime + 0.2);
|
||||
}
|
||||
|
||||
async function saveNotes() {
|
||||
const notes = document.getElementById('quickNotes').value;
|
||||
if (!notes.trim()) return;
|
||||
|
||||
const result = await ipcRenderer.invoke('save-notes', {
|
||||
content: notes,
|
||||
centre: activeCenter
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
alert('Notes sauvegardées !');
|
||||
document.getElementById('quickNotes').value = '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user