diff --git a/web/src/routes/contractor/WorkItemDetail.tsx b/web/src/routes/contractor/WorkItemDetail.tsx
index c286a5a..95148bc 100644
--- a/web/src/routes/contractor/WorkItemDetail.tsx
+++ b/web/src/routes/contractor/WorkItemDetail.tsx
@@ -18,8 +18,6 @@ import {
updateInvoiceStatus,
unlinkTimeEntriesForLineItem,
} from '../../services/firestore';
-import { httpsCallable } from 'firebase/functions';
-import { functions } from '../../lib/firebase';
import { buildChangeOrderPdf } from '../../lib/buildPdf';
import { IconClose } from '../../components/icons';
@@ -198,75 +196,6 @@ export default function WorkItemDetail({
setItem(updated);
}
- async function handleSendToClient() {
- if (!item?.id) return;
-
- // Use original sender email if available (from forwarded emails), else client email
- const recipientEmail = item.senderEmail || client?.email;
- const recipientName = item.senderName || client?.name || '';
- if (!recipientEmail) return;
-
- try {
- // Generate a magic link — use client if assigned, otherwise create for sender
- const linkEmail = client?.email || recipientEmail;
- const linkClientId = client?.id || 'unassigned';
-
- const gen = httpsCallable<
- { clientId: string; email: string; workItemId: string },
- { token: string }
- >(functions, 'generateMagicLink');
- const { data: { token } } = await gen({
- clientId: linkClientId,
- email: linkEmail,
- workItemId: item.id,
- });
-
- const portalLink = `${window.location.origin}/portal/auth?token=${token}`;
-
- const subject = encodeURIComponent(
- `Invoice: ${item.subject}`
- );
-
- const snapshot = buildSnapshotItem();
- const lineItemsBlock = snapshot.lineItems
- .map(
- (li, i) =>
- ` ${i + 1}. ${li.description || '(no description)'}\n` +
- ` Hours: ${li.hours.toFixed(1)} | Cost: ${formatCurrency(li.cost)}`
- )
- .join('\n\n');
-
- const billingNote = item.deductFromRetainer
- ? `\nBilling: ${snapshot.totalHours.toFixed(1)} hours will be deducted from your retainer balance.\n`
- : '';
-
- const body = encodeURIComponent(
- `Hello ${recipientName || 'there'},\n\n` +
- `A new work order is ready for your review.\n\n` +
- `————————————————————————————————\n` +
- `WORK ORDER SUMMARY\n` +
- `————————————————————————————————\n\n` +
- `Subject: ${item.subject}\n` +
- `Type: ${item.type.charAt(0).toUpperCase() + item.type.slice(1)}\n\n` +
- `Line Items:\n\n` +
- `${lineItemsBlock}\n\n` +
- `————————————————————————————————\n` +
- `Total Hours: ${snapshot.totalHours.toFixed(1)} hrs\n` +
- `Total Cost: ${formatCurrency(snapshot.totalCost)}\n` +
- `————————————————————————————————\n` +
- `${billingNote}\n` +
- `Review and approve this work order:\n` +
- `${portalLink}\n\n` +
- `This link expires in 7 days. Reply to this email with any questions.\n\n\n` +
- `Thank you for your business.\n\n` +
- `Best regards`
- );
- window.open(`mailto:${recipientEmail}?subject=${subject}&body=${body}`, '_self');
- } catch (err) {
- console.error('Send to client error:', err);
- }
- }
-
const labelClass = 'block text-[10px] font-semibold text-[var(--text-secondary)] uppercase tracking-wider mb-1.5';
const inputClass = 'w-full h-10 px-3 rounded-xl border border-[var(--border)] bg-[var(--bg-input)] text-sm text-[var(--text-primary)] outline-none focus:border-[var(--accent)] focus:ring-2 focus:ring-[var(--accent)]/15 transition-all';
@@ -671,10 +600,10 @@ export default function WorkItemDetail({
- {/* Invoice Tracking */}
+ {/* Invoice Status */}
- Invoice
+ Invoice Status
{/* Draft / No invoice */}
@@ -791,9 +720,13 @@ export default function WorkItemDetail({
)}
- {/* ── Email Actions ── */}
+ {/* Email */}
{client?.email && (
-
+
+
+ Email
+
+
{/* Send Work Order */}
+
)}
- {/* ── Invoice Status Actions ── */}
- {(item.invoiceStatus === 'sent' || item.invoiceStatus === 'overdue') && (
-
-
- {item.invoiceStatus === 'sent' && (
-
- )}
-
- )}
-
- {/* Actions */}
+ {/* Primary Actions */}
- {item.status !== 'completed' && item.status !== 'archived' && (
-
- )}
{item.status !== 'completed' && item.status !== 'archived' && (