diff --git a/public/js/modals/email-modal.js b/public/js/modals/email-modal.js
index 173114b..36be6c1 100644
--- a/public/js/modals/email-modal.js
+++ b/public/js/modals/email-modal.js
@@ -20,7 +20,11 @@ function ensureModalElement() {
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() {
const modal = document.getElementById('email-modal');
if (!modal) return;
@@ -28,7 +32,18 @@ function renderModalContent() {
const defaultEmail = currentInvoice.email || '';
const existingStripeUrl = currentInvoice.stripe_payment_link_url || '';
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
let stripeBadgeHtml = '';
if (existingStripeUrl && stripeStatus === 'paid') {
@@ -137,15 +152,6 @@ function renderModalContent() {
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 = '';
if (isOverdue) {
diff --git a/public/js/views/invoice-view.js b/public/js/views/invoice-view.js
index 7409528..61e50cd 100644
--- a/public/js/views/invoice-view.js
+++ b/public/js/views/invoice-view.js
@@ -171,6 +171,30 @@ function groupInvoices(filtered) {
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
// ============================================================
@@ -292,9 +316,15 @@ function renderInvoiceRow(invoice) {
const delBtn = ``;
- const stripeEmailBtn = (hasQbo && !paid && (invoice.email_status !== 'sent' || ((invoice.email_status === 'sent' && overdue))))
- ? ``
- : '';
+ const emailAction = getInvoiceEmailButtonLabel(invoice, overdue);
+
+ const stripeEmailBtn = (hasQbo && !paid)
+ ? ``
+ : '';
const stripeCheckBtn = (invoice.stripe_payment_link_id && !paid)
? ``