Initial commit: EFINTEL ERP Django Port
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
// App Logic for Control de Gastos
|
||||
|
||||
// Toast notification system
|
||||
function showToast(message, type = 'info') {
|
||||
const container = document.getElementById('toast-container');
|
||||
if (!container) return;
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = 'toast';
|
||||
|
||||
if (type === 'success') {
|
||||
toast.style.borderLeftColor = 'var(--accent-secondary)';
|
||||
} else if (type === 'danger') {
|
||||
toast.style.borderLeftColor = 'var(--danger)';
|
||||
}
|
||||
|
||||
toast.innerHTML = `<div>${message}</div>`;
|
||||
container.appendChild(toast);
|
||||
|
||||
// Trigger animation
|
||||
setTimeout(() => {
|
||||
toast.classList.add('show');
|
||||
}, 10);
|
||||
|
||||
// Remove toast after 5 seconds
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
if (container.contains(toast)) {
|
||||
container.removeChild(toast);
|
||||
}
|
||||
}, 300);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// WebSocket connection for real-time updates
|
||||
let wsReconnectAttempts = 0;
|
||||
const maxWsReconnectAttempts = 5;
|
||||
|
||||
function connectWebSocket() {
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const wsUrl = `${protocol}//${window.location.host}/ws/expenses/`;
|
||||
|
||||
// We only connect if we are not on the login page
|
||||
if (document.querySelector('.login-page')) return;
|
||||
|
||||
const ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onopen = function(e) {
|
||||
console.log('WebSocket connected');
|
||||
wsReconnectAttempts = 0;
|
||||
};
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
const data = JSON.parse(e.data);
|
||||
const action = data.action;
|
||||
const expense = data.expense;
|
||||
const tbody = document.getElementById('expenses-table-body');
|
||||
|
||||
if (!tbody || !expense) return;
|
||||
|
||||
if (action === 'created') {
|
||||
const tr = document.createElement('tr');
|
||||
tr.id = `expense-row-${expense.id}`;
|
||||
tr.innerHTML = `
|
||||
<td>${expense.date}</td>
|
||||
<td>${expense.project}</td>
|
||||
<td>${expense.category}</td>
|
||||
${document.querySelector('th:nth-child(4)') && document.querySelector('th:nth-child(4)').textContent === 'Descripción' ? `<td>${expense.description || ''}</td>` : ''}
|
||||
<td>$${expense.amount}</td>
|
||||
<td>${expense.user}</td>
|
||||
${document.querySelector('th:nth-child(7)') ? `
|
||||
<td>
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
<span style="font-size:0.8rem; color:var(--text-secondary);">Recarga para ver acciones</span>
|
||||
</div>
|
||||
</td>` : ''}
|
||||
`;
|
||||
|
||||
// Add animation class
|
||||
tr.style.backgroundColor = 'rgba(0, 212, 170, 0.2)';
|
||||
tr.style.transition = 'background-color 2s ease';
|
||||
|
||||
tbody.insertBefore(tr, tbody.firstChild);
|
||||
|
||||
// Remove highlight after animation
|
||||
setTimeout(() => {
|
||||
tr.style.backgroundColor = '';
|
||||
}, 2000);
|
||||
|
||||
showToast('Nuevo gasto registrado', 'success');
|
||||
}
|
||||
else if (action === 'updated') {
|
||||
const row = document.getElementById(`expense-row-${expense.id}`);
|
||||
if (row) {
|
||||
// Flash the row
|
||||
row.style.backgroundColor = 'rgba(108, 99, 255, 0.2)';
|
||||
row.style.transition = 'background-color 2s ease';
|
||||
|
||||
setTimeout(() => {
|
||||
row.style.backgroundColor = '';
|
||||
}, 2000);
|
||||
|
||||
showToast('Gasto actualizado', 'info');
|
||||
}
|
||||
}
|
||||
else if (action === 'deleted') {
|
||||
const row = document.getElementById(`expense-row-${expense.id}`);
|
||||
if (row) {
|
||||
row.style.transform = 'translateX(100%)';
|
||||
row.style.opacity = '0';
|
||||
row.style.transition = 'all 0.3s ease';
|
||||
|
||||
setTimeout(() => {
|
||||
if (row.parentNode) {
|
||||
row.parentNode.removeChild(row);
|
||||
}
|
||||
}, 300);
|
||||
|
||||
showToast('Gasto eliminado', 'danger');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ws.onclose = function(e) {
|
||||
console.error('WebSocket closed unexpectedly');
|
||||
|
||||
if (wsReconnectAttempts < maxWsReconnectAttempts) {
|
||||
wsReconnectAttempts++;
|
||||
const timeout = Math.min(1000 * Math.pow(2, wsReconnectAttempts), 30000);
|
||||
console.log(`Attempting reconnect in ${timeout}ms...`);
|
||||
setTimeout(connectWebSocket, timeout);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
connectWebSocket();
|
||||
|
||||
// Convert CSRF token for fetch requests if needed later
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
||||
});
|
||||
Reference in New Issue
Block a user