/** * SMS compose modal for Job Details — Admin/Manager path. * * Entry points: * - Auto-opens after CompleteJob when TempData contains a pending preview. * - Opened manually via the "Send SMS" button; fetches a fresh template first. * * Requires window.__smsCompose to be set by the inline Razor script before this file loads. */ (function () { 'use strict'; const MODAL_ID = 'smsComposeModal'; const TEXTAREA = 'smsMessageText'; const CHAR_COUNT = 'smsCharCount'; const STOP_WARN = 'smsStopWarning'; const SEND_BTN = 'smsSendBtn'; const ERROR_DIV = 'smsSendError'; const MAX_CHARS = 160; const STOP_TOKEN = 'STOP'; function antiForgeryToken() { return document.querySelector('input[name="__RequestVerificationToken"]')?.value ?? ''; } function el(id) { return document.getElementById(id); } function openModal(prefilledText) { const modal = bootstrap.Modal.getOrCreateInstance(el(MODAL_ID)); const textarea = el(TEXTAREA); if (textarea) textarea.value = prefilledText ?? ''; updateCharCount(); el(ERROR_DIV)?.classList.add('d-none'); modal.show(); } function updateCharCount() { const textarea = el(TEXTAREA); if (!textarea) return; const text = textarea.value; const len = text.length; const charEl = el(CHAR_COUNT); const warnEl = el(STOP_WARN); if (charEl) charEl.textContent = len; if (warnEl) { const hasStop = text.toUpperCase().includes(STOP_TOKEN); warnEl.classList.toggle('d-none', hasStop); } } function showError(msg) { const div = el(ERROR_DIV); if (!div) return; div.textContent = msg; div.classList.remove('d-none'); } async function sendSms() { const cfg = window.__smsCompose ?? {}; const btn = el(SEND_BTN); let message = el(TEXTAREA)?.value?.trim() ?? ''; if (!message) { showError('Please enter a message.'); return; } if (btn) { btn.disabled = true; btn.innerHTML = 'Sending…'; } el(ERROR_DIV)?.classList.add('d-none'); try { const resp = await fetch(cfg.sendUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'RequestVerificationToken': antiForgeryToken() }, body: JSON.stringify({ jobId: cfg.jobIdForSms, message }) }); const data = await resp.json(); if (data.success) { bootstrap.Modal.getInstance(el(MODAL_ID))?.hide(); // Show a quick success toast using existing toastSuccess pattern if available const toastEl = document.getElementById('successToast'); const toastMsg = document.getElementById('successToastMessage'); if (toastEl && toastMsg) { toastMsg.textContent = 'SMS sent successfully.'; bootstrap.Toast.getOrCreateInstance(toastEl).show(); } } else { showError(data.error ?? 'Failed to send SMS. Please try again.'); } } catch { showError('A network error occurred. Please check your connection and try again.'); } finally { if (btn) { btn.disabled = false; btn.innerHTML = 'Send SMS'; } } } document.addEventListener('DOMContentLoaded', () => { const cfg = window.__smsCompose ?? {}; // Character counter el(TEXTAREA)?.addEventListener('input', updateCharCount); // Send button el(SEND_BTN)?.addEventListener('click', sendSms); // "Send SMS" button on the job details action bar document.getElementById('btnSendSms')?.addEventListener('click', async () => { if (!cfg.customerOptedIn) { alert('This customer has not opted in to SMS notifications.'); return; } // Fetch a fresh render of the template try { const resp = await fetch(`${cfg.renderUrl}?jobId=${cfg.jobIdForSms}`); const data = await resp.json(); openModal(data.eligible ? data.message : ''); } catch { openModal(''); } }); // Auto-open after CompleteJob if server passed a pending preview if (cfg.pendingPreview) { // Small delay so the page has fully rendered setTimeout(() => openModal(cfg.pendingPreview), 400); } }); })();