Añadir edición de presupuestos en la App (editar presupuesto + reenvío de enlace por WhatsApp)
This commit is contained in:
@@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
<main id="viewCreate" class="hidden flex-1 overflow-y-auto px-5 pt-6 main-content z-20 fade-in bg-[var(--app-bg)] absolute inset-0 mt-[6rem] rounded-t-[2.5rem] shadow-[0_-10px_40px_rgba(0,0,0,0.1)]">
|
<main id="viewCreate" class="hidden flex-1 overflow-y-auto px-5 pt-6 main-content z-20 fade-in bg-[var(--app-bg)] absolute inset-0 mt-[6rem] rounded-t-[2.5rem] shadow-[0_-10px_40px_rgba(0,0,0,0.1)]">
|
||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
<h2 class="text-lg font-black text-slate-800">Generar Nuevo</h2>
|
<h2 id="createViewTitle" class="text-lg font-black text-slate-800">Generar Nuevo</h2>
|
||||||
<button onclick="hideCreateView()" class="w-8 h-8 bg-slate-200 text-slate-600 rounded-full flex items-center justify-center active:scale-95"><i data-lucide="x" class="w-4 h-4"></i></button>
|
<button onclick="hideCreateView()" class="w-8 h-8 bg-slate-200 text-slate-600 rounded-full flex items-center justify-center active:scale-95"><i data-lucide="x" class="w-4 h-4"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -261,6 +261,7 @@
|
|||||||
let catalog = [];
|
let catalog = [];
|
||||||
let currentItems = [];
|
let currentItems = [];
|
||||||
let allBudgets = [];
|
let allBudgets = [];
|
||||||
|
let editingId = null; // null = modo crear, con valor = modo editar
|
||||||
|
|
||||||
// ------------------ INICIALIZACIÓN Y TEMA CORPORATIVO ------------------
|
// ------------------ INICIALIZACIÓN Y TEMA CORPORATIVO ------------------
|
||||||
async function applyTheme() {
|
async function applyTheme() {
|
||||||
@@ -295,6 +296,9 @@
|
|||||||
|
|
||||||
// ------------------ NAVEGACIÓN Y TOASTS ------------------
|
// ------------------ NAVEGACIÓN Y TOASTS ------------------
|
||||||
function showCreateView() {
|
function showCreateView() {
|
||||||
|
editingId = null;
|
||||||
|
document.getElementById('createViewTitle').textContent = 'Generar Nuevo';
|
||||||
|
document.getElementById('btnSave').innerHTML = '<i data-lucide="save" class="w-4 h-4"></i> Generar Presupuesto';
|
||||||
document.getElementById('viewList').classList.add('hidden');
|
document.getElementById('viewList').classList.add('hidden');
|
||||||
document.getElementById('viewCreate').classList.remove('hidden');
|
document.getElementById('viewCreate').classList.remove('hidden');
|
||||||
currentItems = [];
|
currentItems = [];
|
||||||
@@ -307,6 +311,21 @@
|
|||||||
document.getElementById('viewList').classList.remove('hidden');
|
document.getElementById('viewList').classList.remove('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function editBudget(id) {
|
||||||
|
const budget = allBudgets.find(b => b.id === id);
|
||||||
|
if (!budget) return showToast("Error: Presupuesto no encontrado");
|
||||||
|
editingId = id;
|
||||||
|
document.getElementById('c_name').value = budget.client_name || '';
|
||||||
|
document.getElementById('c_phone').value = budget.client_phone || '';
|
||||||
|
document.getElementById('c_address').value = budget.client_address || '';
|
||||||
|
currentItems = (budget.items || []).map(it => ({ concept: it.concept, qty: it.qty, price: it.price, total: (Number(it.qty) * Number(it.price)) }));
|
||||||
|
document.getElementById('createViewTitle').textContent = 'Editar Presupuesto #' + id;
|
||||||
|
document.getElementById('btnSave').innerHTML = '<i data-lucide="save" class="w-4 h-4"></i> Guardar Cambios';
|
||||||
|
document.getElementById('viewList').classList.add('hidden');
|
||||||
|
document.getElementById('viewCreate').classList.remove('hidden');
|
||||||
|
renderItems();
|
||||||
|
}
|
||||||
|
|
||||||
function showToast(msg) {
|
function showToast(msg) {
|
||||||
const toast = document.getElementById('toast');
|
const toast = document.getElementById('toast');
|
||||||
document.getElementById('toastMsg').innerText = msg;
|
document.getElementById('toastMsg').innerText = msg;
|
||||||
@@ -572,6 +591,7 @@
|
|||||||
${actionBtns}
|
${actionBtns}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
|
${(b.status !== 'converted' && b.status !== 'paid') ? `<button onclick="editBudget(${b.id})" class="w-9 h-9 bg-slate-50 border border-slate-200 text-blue-600 rounded-full flex items-center justify-center active:scale-95 transition-transform"><i data-lucide="pencil" class="w-4 h-4"></i></button>` : ''}
|
||||||
<button onclick="downloadPDF(${b.id})" class="w-9 h-9 bg-slate-50 border border-slate-200 text-slate-600 rounded-full flex items-center justify-center active:scale-95 transition-transform"><i data-lucide="download" class="w-4 h-4"></i></button>
|
<button onclick="downloadPDF(${b.id})" class="w-9 h-9 bg-slate-50 border border-slate-200 text-slate-600 rounded-full flex items-center justify-center active:scale-95 transition-transform"><i data-lucide="download" class="w-4 h-4"></i></button>
|
||||||
<button onclick="deleteBudget(${b.id})" class="w-9 h-9 bg-slate-50 border border-slate-200 text-rose-500 rounded-full flex items-center justify-center active:scale-95 transition-transform"><i data-lucide="trash-2" class="w-4 h-4"></i></button>
|
<button onclick="deleteBudget(${b.id})" class="w-9 h-9 bg-slate-50 border border-slate-200 text-rose-500 rounded-full flex items-center justify-center active:scale-95 transition-transform"><i data-lucide="trash-2" class="w-4 h-4"></i></button>
|
||||||
</div>
|
</div>
|
||||||
@@ -669,18 +689,20 @@
|
|||||||
btn.innerHTML = '<i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i> Generando...';
|
btn.innerHTML = '<i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i> Generando...';
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
|
|
||||||
|
const isEdit = !!editingId;
|
||||||
const totals = calcTotals();
|
const totals = calcTotals();
|
||||||
const payload = { client_name: cName, client_phone: cPhone, client_address: cAddress, items: currentItems, subtotal: totals.sub, tax: totals.tax, total: totals.tot };
|
const payload = { client_name: cName, client_phone: cPhone, client_address: cAddress, items: currentItems, subtotal: totals.sub, tax: totals.tax, total: totals.tot };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API_URL}/budgets`, {
|
const res = await fetch(isEdit ? `${API_URL}/budgets/${editingId}` : `${API_URL}/budgets`, {
|
||||||
method: 'POST',
|
method: isEdit ? 'PUT' : 'POST',
|
||||||
headers: { 'Content-Type': 'application/json', "Authorization": `Bearer ${localStorage.getItem("token")}` },
|
headers: { 'Content-Type': 'application/json', "Authorization": `Bearer ${localStorage.getItem("token")}` },
|
||||||
body: JSON.stringify(payload)
|
body: JSON.stringify(payload)
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if(data.ok) {
|
if(data.ok) {
|
||||||
showToast("¡Presupuesto Creado!");
|
showToast(isEdit ? "¡Presupuesto Actualizado!" : "¡Presupuesto Creado!");
|
||||||
|
editingId = null;
|
||||||
hideCreateView();
|
hideCreateView();
|
||||||
fetchBudgets();
|
fetchBudgets();
|
||||||
} else { showToast("Error al guardar."); }
|
} else { showToast("Error al guardar."); }
|
||||||
|
|||||||
Reference in New Issue
Block a user