render_meta_box_body_html( $order_id, $selected_template, $is_premium, $status_label, $nonce, $ajax_url, $order ); $this->render_meta_box_inline_script(); } /** * Renders the meta box main body HTML (template info + action buttons). * * @param int $order_id WooCommerce order ID. * @param array|null $selected_template Template data array, or null if none assigned. * @param bool $is_premium True if the current license is premium. * @param string $status_label Human-readable order status label. * @param string $nonce WordPress nonce for AJAX security. * @param string $ajax_url Admin AJAX URL. * @param object $order WooCommerce WC_Order instance. */ private function render_meta_box_body_html( int $order_id, ?array $selected_template, bool $is_premium, string $status_label, string $nonce, string $ajax_url, object $order ): void { ?>
Gratuit Premium
đź“„
render_meta_box_pdf_mail_buttons( $order_id, $selected_template, $is_premium, $nonce, $ajax_url, $order ); ?> render_meta_box_mail_modal(); ?> render_meta_box_queue_modal(); ?>
(function($) { render_meta_box_js_utils(); $this->render_meta_box_js_action_handlers(); $this->render_meta_box_js_mail_handlers(); ?> })(jQuery); render_meta_box_js_generate_pdf(); $this->render_meta_box_js_queue_functions(); } /** * Outputs the doGeneratePdf() JavaScript function that fetches and opens the PDF blob. */ private function render_meta_box_js_generate_pdf(): void { ?> /** Fetch le PDF et l'ouvre en blob */ function doGeneratePdf(ajaxUrl, orderId, templateId, nonce, btn, orig, callback) { _generateAbortController = new AbortController(); var fd = new FormData(); fd.append('action', 'pdfib_stream_pdf'); fd.append('order_id', orderId); fd.append('template_id', templateId); fd.append('nonce', nonce); fetch(ajaxUrl, { method: 'POST', body: fd, signal: _generateAbortController.signal }) .then(function(res) { var ct = res.headers.get('Content-Type') || ''; if (!res.ok || ct.indexOf('application/pdf') === -1) { return res.text().then(function(t) { throw new Error(t || 'Erreur ' + res.status); }); } return res.blob(); }) .then(function(blob) { btn.prop('disabled', false).html(orig); openPdfBlob(blob, orderId); if (callback) callback(null); }) .catch(function(err) { if (err.name === 'AbortError') return; // Annulé par l'utilisateur btn.prop('disabled', false).html(orig); alert('Erreur génération PDF :\n' + err.message); if (callback) callback(err); }); } function pollQueue(ajaxUrl, nonce, onReady) { if (_queueCancelled) return; var fd = new FormData(); fd.append('action', 'pdfib_pdf_queue_poll'); fd.append('nonce', nonce); fetch(ajaxUrl, { method: 'POST', body: fd }) .then(function(r) { return r.json(); }) .then(function(data) { if (_queueCancelled) return; if (data.success) { var pos = data.data.position; var size = data.data.queue_size; updateQueueModal(pos, size); if (pos === 0) { onReady(); } else { _queuePollTimer = setTimeout(function() { pollQueue(ajaxUrl, nonce, onReady); }, 3000); } } else { _queuePollTimer = setTimeout(function() { pollQueue(ajaxUrl, nonce, onReady); }, 3000); } }) .catch(function() { if (!_queueCancelled) { _queuePollTimer = setTimeout(function() { pollQueue(ajaxUrl, nonce, onReady); }, 5000); } }); } function leaveQueue(ajaxUrl, nonce) { var fd = new FormData(); fd.append('action', 'pdfib_pdf_queue_leave'); fd.append('nonce', nonce); fetch(ajaxUrl, { method: 'POST', body: fd }); } function startCountdown(onDone) { var remaining = 10; $('#pdfb-queue-section').hide(); $('#pdfb-countdown-section').show(); $('#pdfb-countdown-num').text(remaining); $('#pdfb-queue-status-text').text(''); _countdownTimer = setInterval(function() { if (_queueCancelled) { clearInterval(_countdownTimer); _countdownTimer = null; return; } remaining--; $('#pdfb-countdown-num').text(remaining); if (remaining <= 0) { clearInterval(_countdownTimer); _countdownTimer = null; onDone(); } }, 1000); } // Bouton Annuler du modal $('#pdfb-queue-cancel').on('click', function() { _queueCancelled = true; if (_queueBtn) { _queueBtn.prop('disabled', false).html(_queueBtnOrig); } if (_queueAjaxUrl) { leaveQueue(_queueAjaxUrl, _queueNonce); } hideQueueModal(); }); $('.pdf-builder-action-btn').on('click', function() { var btn = $(this); var type = btn.data('action-type'); // pdf | png | jpg var orderId = btn.data('order-id'); var templateId = btn.data('template-id'); var nonce = btn.data('nonce'); var ajaxUrl = btn.data('ajax'); var isPremium = btn.data('is-premium') === 1 || btn.data('is-premium') === '1'; var orig = btn.html(); _queueBtn = btn; _queueBtnOrig = orig; _queueAjaxUrl = ajaxUrl; _queueNonce = nonce; btn.prop('disabled', true).html('⏳'); if (type === 'pdf') { if (isPremium) { doGeneratePdf(ajaxUrl, orderId, templateId, nonce, btn, orig); } else { render_meta_box_js_free_queue_flow(); ?> } } else { render_meta_box_js_image_handler(); ?> } }); var fd = new FormData(); fd.append('action', 'pdfib_pdf_queue_join'); fd.append('nonce', nonce); fetch(ajaxUrl, { method: 'POST', body: fd }) .then(function(r) { return r.json(); }) .then(function(data) { if (!data.success) { btn.prop('disabled', false).html(orig); alert('' + (data.data && data.data.message ? data.data.message : '')); return; } var pos = data.data.position; if (pos === 0) { showQueueModal(0); updateQueueModal(0, 1); // Laisser 1 s pour que l'utilisateur voie sa position (#1) avant le compte à rebours setTimeout(function() { if (_queueCancelled) return; startCountdown(function() { doGeneratePdf(ajaxUrl, orderId, templateId, nonce, btn, orig, function() { leaveQueue(ajaxUrl, nonce); hideQueueModal(); }); }); }, 1000); } else { showQueueModal(pos); pollQueue(ajaxUrl, nonce, function() { startCountdown(function() { doGeneratePdf(ajaxUrl, orderId, templateId, nonce, btn, orig, function() { leaveQueue(ajaxUrl, nonce); hideQueueModal(); }); }); }); } }) .catch(function(err) { btn.prop('disabled', false).html(orig); alert('' + err.message); }); var formData = new FormData(); formData.append('action', 'pdfib_generate_image'); formData.append('template_id', templateId); formData.append('order_id', orderId); formData.append('format', type); formData.append('nonce', nonce); fetch(ajaxUrl, { method: 'POST', body: formData }) .then(function(response) { if (!response.ok) { return response.text().then(function(text) { var message = text || ('Erreur ' + response.status); try { var err = JSON.parse(text); if (err && err.data) { message = err.data.details || err.data.message || err.message || message; } } catch (parseError) { message = text.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim() || message; } throw new Error(message); }); } return response.blob(); }) .then(function(blob) { btn.prop('disabled', false).html(orig); openImageInTab(blob, type, orderId); }) .catch(function(err) { btn.prop('disabled', false).html(orig); alert('Erreur lors de la génération ' + type.toUpperCase() + '\n\n' + err.message); }); // --- Modal Mail --- var $modal = $('#pdf-builder-mail-modal'); var $mstatus = $('#pdf-builder-mail-status'); $('#pdf-builder-mail-btn').on('click', function() { var btn = $(this); var num = btn.data('order-number'); var email = btn.data('order-email'); $('#pdf-builder-mail-to').val(email); $('#pdf-builder-mail-subject').val(' #' + num); $('#pdf-builder-mail-message').val('' + num + '.\n\n'); $mstatus.hide(); $modal.fadeIn(200); }); function closeModal() { $modal.fadeOut(150); } $('#pdf-builder-mail-close, #pdf-builder-mail-cancel').on('click', closeModal); $modal.on('click', function(e) { if ($(e.target).is($modal)) closeModal(); }); $(document).on('keydown.pdfBuilderMail', function(e) { if (e.key === 'Escape') closeModal(); }); render_meta_box_js_mail_send_handler(); ?> $('#pdf-builder-mail-send').on('click', function() { var sendBtn = $(this); var mailBtn = $('#pdf-builder-mail-btn'); var to = $('#pdf-builder-mail-to').val().trim(); var subject = $('#pdf-builder-mail-subject').val().trim(); var message = $('#pdf-builder-mail-message').val().trim(); var orderId = mailBtn.data('order-id'); var templateId = mailBtn.data('template-id'); var nonce = mailBtn.data('nonce'); var ajaxUrl = mailBtn.data('ajax'); if (!to || !subject) { $mstatus.css({ display: 'block', background: '#f8d7da', color: '#721c24', border: '1px solid #f5c6cb' }) .text(''); return; } $mstatus.css({ display: 'block', background: '#d1ecf1', color: '#0c5460', border: '1px solid #bee5eb' }) .text('⏳ '); sendBtn.prop('disabled', true).text('⏳'); $.post(ajaxUrl, { action: 'pdfib_send_order_email', order_id: orderId, template_id: templateId, nonce: nonce, to: to, subject: subject, message: message }, function(response) { sendBtn.prop('disabled', false).html('✉️ '); if (response.success) { $mstatus.css({ background: '#d4edda', color: '#155724', border: '1px solid #c3e6cb' }) .text('✅ ' + (response.data.message || '')); setTimeout(closeModal, 2500); } else { var msg = (response.data && response.data.message) ? response.data.message : ''; $mstatus.css({ background: '#f8d7da', color: '#721c24', border: '1px solid #f5c6cb' }).text('❌ ' + msg); } }).fail(function() { sendBtn.prop('disabled', false).html('✉️ '); $mstatus.css({ display: 'block', background: '#f8d7da', color: '#721c24', border: '1px solid #f5c6cb' }) .text('❌ '); }); }); // ----- File d'attente (utilisateurs gratuits) ----- var _queuePollTimer = null; var _queueCancelled = false; var _generateAbortController = null; var _countdownTimer = null; var _queueBtn = null; var _queueBtnOrig = ''; var _queueAjaxUrl = ''; var _queueNonce = ''; function showQueueModal(position) { _queueCancelled = false; $('#pdfb-queue-section').show(); $('#pdfb-countdown-section').hide(); $('#pdfb-queue-pos-num').text(position + 1); $('#pdfb-queue-progress-bar').css('width', '0%'); $('#pdfb-queue-status-text').text(''); $('#pdfb-queue-modal').fadeIn(200); } var updateQueueModal = function(position, queueSize) { $('#pdfb-queue-pos-num').text(position + 1); var pct = queueSize > 1 ? Math.max(5, Math.round((1 - position / queueSize) * 100)) : 80; $('#pdfb-queue-progress-bar').css('width', pct + '%'); if (position === 0) { $('#pdfb-queue-status-text').text(''); } } function hideQueueModal() { $('#pdfb-queue-modal').fadeOut(150); if (_queuePollTimer) { clearTimeout(_queuePollTimer); _queuePollTimer = null; } if (_countdownTimer) { clearInterval(_countdownTimer); _countdownTimer = null; } if (_generateAbortController) { _generateAbortController.abort(); _generateAbortController = null; } } render_meta_box_js_queue_poll_leave(); ?>