diff --git a/assets/css/woodoo.css b/assets/css/woodoo.css index 84a5ff8..300b097 100644 --- a/assets/css/woodoo.css +++ b/assets/css/woodoo.css @@ -72,9 +72,9 @@ } .woodoo-table { width: 100%; - min-width: 820px; /* never compress below this — scroll horizontally instead */ + min-width: 700px; /* never compress below this — scroll horizontally instead */ border-collapse: collapse; - font-size: .875rem; + font-size: .8rem; /* No table-layout:fixed — let the browser size columns to content */ } .woodoo-table th, @@ -92,13 +92,17 @@ white-space: nowrap; } /* Force key invoice columns to never wrap */ -.woodoo-invoices-table .col-number { white-space: nowrap; font-weight: 600; min-width: 160px; } -.woodoo-invoices-table .col-date { white-space: nowrap; min-width: 90px; } -.woodoo-invoices-table .col-due { white-space: nowrap; min-width: 110px; } -.woodoo-invoices-table .col-amount { white-space: nowrap; min-width: 100px; text-align: right; } -.woodoo-invoices-table .col-balance { white-space: nowrap; min-width: 120px; text-align: right; } -.woodoo-invoices-table .col-status { white-space: nowrap; min-width: 90px; } -.woodoo-invoices-table .col-download{ min-width: 60px; text-align: center; } +.woodoo-invoices-table .col-number { white-space: nowrap; font-weight: 600; min-width: 160px; } +.woodoo-invoices-table .col-date { white-space: nowrap; min-width: 90px; } +.woodoo-invoices-table .col-due { white-space: nowrap; min-width: 110px; } +.woodoo-invoices-table .col-amount { white-space: nowrap; min-width: 100px; text-align: right; } +.woodoo-invoices-table .col-status { white-space: nowrap; min-width: 90px; } +.woodoo-invoices-table .col-action { min-width: 90px; text-align: center; } + +/* Inline feedback rows (send invoice email) */ +.woodoo-inline-msg td { font-size: .8rem; padding: 6px 16px; } +.woodoo-inline-msg--ok { color: #065f46; background: #ecfdf5; } +.woodoo-inline-msg--err { color: #991b1b; background: #fef2f2; } /* Utility: never wrap content in a cell */ .woodoo-nowrap { white-space: nowrap; } diff --git a/assets/js/woodoo-frontend.js b/assets/js/woodoo-frontend.js index 3554c8e..e13d3e9 100644 --- a/assets/js/woodoo-frontend.js +++ b/assets/js/woodoo-frontend.js @@ -1,36 +1,112 @@ -/* WooDoo Frontend JS – Calendar Booking */ +/* WooDoo Frontend JS */ ( function () { 'use strict'; + // ══════════════════════════════════════════════════════════════════════ + // INVOICE EMAIL + // ══════════════════════════════════════════════════════════════════════ + const inv = window.WooDooInvoices; + if ( inv ) { + document.querySelectorAll( '.woodoo-send-invoice' ).forEach( function ( btn ) { + btn.addEventListener( 'click', function () { + const invoiceId = this.dataset.id; + const $btn = this; + const row = $btn.closest( 'tr' ); + + // Remove any previous feedback in this row + const prev = row.querySelector( '.woodoo-inline-msg' ); + if ( prev ) prev.remove(); + + $btn.disabled = true; + $btn.textContent = 'Enviando…'; + + const body = new URLSearchParams( { + action : 'woodoo_send_invoice_email', + nonce : inv.nonce, + invoice_id : invoiceId, + } ); + + fetch( inv.ajax_url, { method: 'POST', body } ) + .then( r => r.json() ) + .then( function ( res ) { + if ( res.success ) { + $btn.textContent = '✓ Enviado'; + $btn.style.color = '#065f46'; + // Show success message below the row + const td = document.createElement( 'td' ); + td.colSpan = 6; + td.className = 'woodoo-inline-msg woodoo-inline-msg--ok'; + td.textContent = res.data.message; + const msgRow = document.createElement( 'tr' ); + msgRow.className = 'woodoo-inline-msg'; + msgRow.appendChild( td ); + row.insertAdjacentElement( 'afterend', msgRow ); + // Auto-hide after 6s + setTimeout( function () { + msgRow.remove(); + $btn.disabled = false; + $btn.textContent = '✉ Reenviar'; + $btn.style.color = ''; + }, 6000 ); + } else { + showInvoiceError( row, res.data || 'Error desconocido.' ); + $btn.disabled = false; + $btn.textContent = '✉ Reenviar'; + } + } ) + .catch( function () { + showInvoiceError( row, 'Error de conexión. Inténtalo de nuevo.' ); + $btn.disabled = false; + $btn.textContent = '✉ Reenviar'; + } ); + } ); + } ); + + function showInvoiceError( row, msg ) { + const prev = row.querySelector( '.woodoo-inline-msg' ); + if ( prev ) prev.remove(); + const td = document.createElement( 'td' ); + td.colSpan = 6; + td.className = 'woodoo-inline-msg woodoo-inline-msg--err'; + td.textContent = msg; + const msgRow = document.createElement( 'tr' ); + msgRow.className = 'woodoo-inline-msg'; + msgRow.appendChild( td ); + row.insertAdjacentElement( 'afterend', msgRow ); + } + } + + // ══════════════════════════════════════════════════════════════════════ + // CALENDAR BOOKING + // ══════════════════════════════════════════════════════════════════════ const cfg = window.WooDooCalendar; - if ( ! cfg ) return; // not on calendar page + if ( ! cfg ) return; - const i18n = cfg.i18n; - const ajaxUrl = cfg.ajax_url; - const nonce = cfg.nonce; + const i18n = cfg.i18n; + const ajaxUrl = cfg.ajax_url; + const nonce = cfg.nonce; - // ── Element refs ──────────────────────────────────────────────────── - const dateInput = document.getElementById( 'woodoo-booking-date' ); - const slotsWrap = document.getElementById( 'woodoo-slots-wrap' ); - const slotsGrid = document.getElementById( 'woodoo-slots-grid' ); - const confirmBlock = document.getElementById( 'woodoo-booking-confirm' ); - const bookBtn = document.getElementById( 'woodoo-book-btn' ); - const notesArea = document.getElementById( 'woodoo-booking-notes' ); - const slotLabel = document.getElementById( 'woodoo-selected-slot-label' ); - const successMsg = document.getElementById( 'woodoo-booking-success' ); - const errorMsg = document.getElementById( 'woodoo-booking-error' ); + const dateInput = document.getElementById( 'woodoo-booking-date' ); + const slotsWrap = document.getElementById( 'woodoo-slots-wrap' ); + const slotsGrid = document.getElementById( 'woodoo-slots-grid' ); + const confirmBlock = document.getElementById( 'woodoo-booking-confirm' ); + const bookBtn = document.getElementById( 'woodoo-book-btn' ); + const notesArea = document.getElementById( 'woodoo-booking-notes' ); + const slotLabel = document.getElementById( 'woodoo-selected-slot-label' ); + const successMsg = document.getElementById( 'woodoo-booking-success' ); + const errorMsg = document.getElementById( 'woodoo-booking-error' ); let selectedStart = null; let selectedEnd = null; - // ── Date change → load slots ──────────────────────────────────────── + // ── Date change → load slots ───────────────────────────────────────── if ( dateInput ) { dateInput.addEventListener( 'change', function () { const date = this.value; if ( ! date ) return; slotsGrid.innerHTML = '' + esc( i18n.loading ) + ''; - slotsWrap.style.display = 'block'; + slotsWrap.style.display = 'block'; confirmBlock.style.display = 'none'; successMsg.style.display = 'none'; errorMsg.style.display = 'none'; @@ -43,19 +119,17 @@ slotsGrid.innerHTML = '' + esc( i18n.error ) + ''; return; } - const slots = res.data; if ( ! slots.length ) { slotsGrid.innerHTML = '' + esc( i18n.no_slots ) + ''; confirmBlock.style.display = 'none'; return; } - slotsGrid.innerHTML = ''; slots.forEach( slot => { const btn = document.createElement( 'button' ); - btn.type = 'button'; - btn.className = 'woodoo-slot'; + btn.type = 'button'; + btn.className = 'woodoo-slot'; btn.textContent = formatTime( slot.start ) + ' – ' + formatTime( slot.end ); btn.dataset.start = slot.start; btn.dataset.end = slot.end; @@ -63,27 +137,21 @@ slotsGrid.appendChild( btn ); } ); } ) - .catch( () => { - slotsGrid.innerHTML = '' + esc( i18n.error ) + ''; - } ); + .catch( () => { slotsGrid.innerHTML = '' + esc( i18n.error ) + ''; } ); } ); } - // ── Slot selection ─────────────────────────────────────────────────── function onSlotClick( e ) { - document.querySelectorAll( '.woodoo-slot' ) - .forEach( b => b.classList.remove( 'selected' ) ); - + document.querySelectorAll( '.woodoo-slot' ).forEach( b => b.classList.remove( 'selected' ) ); const btn = e.currentTarget; btn.classList.add( 'selected' ); - selectedStart = btn.dataset.start; selectedEnd = btn.dataset.end; slotLabel.textContent = - new Date( selectedStart ).toLocaleDateString( undefined, { + new Date( selectedStart ).toLocaleDateString( 'es-ES', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', - } ) + ' ' + formatTime( selectedStart ) + ' – ' + formatTime( selectedEnd ); + } ) + ', ' + formatTime( selectedStart ) + ' – ' + formatTime( selectedEnd ); confirmBlock.style.display = 'block'; bookBtn.disabled = false; @@ -95,8 +163,7 @@ if ( bookBtn ) { bookBtn.addEventListener( 'click', function () { if ( ! selectedStart || ! selectedEnd ) return; - - bookBtn.disabled = true; + bookBtn.disabled = true; bookBtn.textContent = i18n.booking; errorMsg.style.display = 'none'; @@ -107,24 +174,22 @@ } ) .then( res => { if ( res.success ) { - successMsg.textContent = res.data.message; + successMsg.textContent = res.data.message; successMsg.style.display = 'block'; confirmBlock.style.display = 'none'; slotsWrap.style.display = 'none'; - dateInput.value = ''; + dateInput.value = ''; selectedStart = selectedEnd = null; - - // Re-fetch meetings after booking refreshMeetings(); } else { - showError( res.data || i18n.error ); - bookBtn.disabled = false; + showCalError( res.data || i18n.error ); + bookBtn.disabled = false; bookBtn.textContent = i18n.book_btn; } } ) .catch( () => { - showError( i18n.error ); - bookBtn.disabled = false; + showCalError( i18n.error ); + bookBtn.disabled = false; bookBtn.textContent = i18n.book_btn; } ); } ); @@ -134,28 +199,26 @@ document.querySelectorAll( '.woodoo-cancel-meeting' ).forEach( btn => { btn.addEventListener( 'click', function () { if ( ! confirm( i18n.cancel_confirm ) ) return; - const eventId = this.dataset.eventId; const card = this.closest( '.woodoo-meeting-card' ); - - this.disabled = true; + this.disabled = true; this.textContent = i18n.cancelling; post( 'woodoo_cancel_meeting', { event_id: eventId } ) .then( res => { if ( res.success ) { - card.style.opacity = '0.4'; + card.style.opacity = '0.4'; card.style.transition = 'opacity .3s'; setTimeout( () => card.remove(), 350 ); } else { alert( res.data || i18n.error ); - this.disabled = false; - this.textContent = 'Cancel'; + this.disabled = false; + this.textContent = 'Cancelar'; } } ) .catch( () => { - this.disabled = false; - this.textContent = 'Cancel'; + this.disabled = false; + this.textContent = 'Cancelar'; } ); } ); } ); @@ -164,84 +227,59 @@ function refreshMeetings() { const listEl = document.getElementById( 'woodoo-meetings-list' ); if ( ! listEl ) return; - post( 'woodoo_get_meetings', {} ) .then( res => { - if ( ! res.success ) return; - const meetings = res.data; - if ( ! meetings.length ) { - listEl.innerHTML = '
' + esc( 'No upcoming meetings scheduled.' ) + '
'; + if ( ! res.success || ! res.data.length ) { + listEl.innerHTML = 'No tienes reuniones programadas.
'; return; } - + const meses = [ '', 'ene', 'feb', 'mar', 'abr', 'may', 'jun', + 'jul', 'ago', 'sep', 'oct', 'nov', 'dic' ]; let html = '