This commit is contained in:
2026-04-25 15:00:05 -05:00
parent 93db2f237f
commit 6638030e2e
2 changed files with 49 additions and 13 deletions

View File

@@ -20,7 +20,11 @@ function ensureModalElement() {
document.body.appendChild(modal); document.body.appendChild(modal);
} }
} }
function getEmailModalTitle(invoice, isOverdue) {
if (isOverdue) return `⏰ Send Reminder for Invoice #${invoice.invoice_number || invoice.id}`;
if (invoice.email_status === 'sent') return `🔁 Resend Invoice #${invoice.invoice_number || invoice.id}`;
return `📤 Send Invoice #${invoice.invoice_number || invoice.id}`;
}
function renderModalContent() { function renderModalContent() {
const modal = document.getElementById('email-modal'); const modal = document.getElementById('email-modal');
if (!modal) return; if (!modal) return;
@@ -29,6 +33,17 @@ function renderModalContent() {
const existingStripeUrl = currentInvoice.stripe_payment_link_url || ''; const existingStripeUrl = currentInvoice.stripe_payment_link_url || '';
const stripeStatus = currentInvoice.stripe_payment_status || ''; const stripeStatus = currentInvoice.stripe_payment_status || '';
// Detect overdue: unpaid + older than 30 days
const invoiceDateParsed = currentInvoice.invoice_date
? new Date(currentInvoice.invoice_date.split('T')[0])
: null;
const daysSinceInvoice = invoiceDateParsed
? Math.floor((new Date() - invoiceDateParsed) / 86400000)
: 0;
const isOverdue = !currentInvoice.paid_date && daysSinceInvoice > 30;
const modalTitle = getEmailModalTitle(currentInvoice, isOverdue);
// Status indicator for existing link // Status indicator for existing link
let stripeBadgeHtml = ''; let stripeBadgeHtml = '';
if (existingStripeUrl && stripeStatus === 'paid') { if (existingStripeUrl && stripeStatus === 'paid') {
@@ -137,15 +152,6 @@ function renderModalContent() {
paymentText = 'Our terms are Net 30.'; paymentText = 'Our terms are Net 30.';
} }
// Detect overdue: unpaid + older than 30 days
const invoiceDateParsed = currentInvoice.invoice_date
? new Date(currentInvoice.invoice_date.split('T')[0])
: null;
const daysSinceInvoice = invoiceDateParsed
? Math.floor((new Date() - invoiceDateParsed) / 86400000)
: 0;
const isOverdue = !currentInvoice.paid_date && daysSinceInvoice > 30;
let defaultHtml = ''; let defaultHtml = '';
if (isOverdue) { if (isOverdue) {

View File

@@ -171,6 +171,30 @@ function groupInvoices(filtered) {
return new Map([...groups.entries()].sort((a, b) => b[0].localeCompare(a[0]))); return new Map([...groups.entries()].sort((a, b) => b[0].localeCompare(a[0])));
} }
function getInvoiceEmailButtonLabel(invoice, overdue) {
if (overdue) {
return {
text: '⏰ Send Reminder',
title: 'Send overdue reminder with invoice PDF and optional Stripe payment link',
className: 'bg-red-100 text-red-700 hover:bg-red-200'
};
}
if (invoice.email_status === 'sent') {
return {
text: '🔁 Resend Invoice',
title: 'Resend invoice with PDF and optional Stripe payment link',
className: 'bg-purple-100 text-purple-700 hover:bg-purple-200'
};
}
return {
text: '📤 Send Invoice',
title: 'Send invoice with PDF and optional Stripe payment link',
className: 'bg-blue-100 text-blue-700 hover:bg-blue-200'
};
}
// ============================================================ // ============================================================
// Render // Render
// ============================================================ // ============================================================
@@ -292,8 +316,14 @@ function renderInvoiceRow(invoice) {
const delBtn = `<button onclick="window.invoiceView.remove(${invoice.id})" class="text-red-600 hover:text-red-900">Del</button>`; const delBtn = `<button onclick="window.invoiceView.remove(${invoice.id})" class="text-red-600 hover:text-red-900">Del</button>`;
const stripeEmailBtn = (hasQbo && !paid && (invoice.email_status !== 'sent' || ((invoice.email_status === 'sent' && overdue)))) const emailAction = getInvoiceEmailButtonLabel(invoice, overdue);
? `<button onclick="window.emailModal.open(${invoice.id})" title="Email with Stripe Payment Link" class="px-2 py-1 bg-purple-100 text-purple-700 rounded hover:bg-purple-200 text-xs font-semibold">💳 Pay Link</button>`
const stripeEmailBtn = (hasQbo && !paid)
? `<button onclick="window.emailModal.open(${invoice.id})"
title="${emailAction.title}"
class="px-2 py-1 ${emailAction.className} rounded text-xs font-semibold">
${emailAction.text}
</button>`
: ''; : '';
const stripeCheckBtn = (invoice.stripe_payment_link_id && !paid) const stripeCheckBtn = (invoice.stripe_payment_link_id && !paid)