From 41f2299fe2cd877ba2919e77bf7b7957df93a647 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:58:37 +0000 Subject: [PATCH 1/3] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- bun.lockb | Bin 339791 -> 359432 bytes package.json | 3 +++ 2 files changed, 3 insertions(+) diff --git a/bun.lockb b/bun.lockb index e560d2fd65c5189f75c4365a18052f096f99a30e..2045680b0a7ab39e9a1f38cf62a9221feb9504e1 100755 GIT binary patch delta 69500 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 PHf9$eo<1?1KNbByh}Jrf delta 58165 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 diff --git a/package.json b/package.json index 10c5f52..6d7d167 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "@tiptap/react": "^3.22.3", "@tiptap/starter-kit": "^3.22.3", "@types/file-saver": "^2.0.7", + "@types/mailparser": "3.4.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -61,10 +62,12 @@ "docx": "^9.6.1", "embla-carousel-react": "^8.6.0", "file-saver": "^2.0.5", + "imapflow": "1.0.171", "input-otp": "^1.4.2", "jspdf": "^4.2.1", "jspdf-autotable": "^5.0.7", "lucide-react": "^0.575.0", + "mailparser": "3.7.1", "react": "^19.2.0", "react-day-picker": "^9.14.0", "react-dom": "^19.2.0", From c8f250715f2cb0b8fb5bfab4c22d2cf3cfc221d6 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 01:00:08 +0000 Subject: [PATCH 2/3] Changes Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com> --- src/components/app-shell.tsx | 3 +- src/routes/hooks/poll-imap.ts | 157 ++++++++++++++++++ src/routes/inbox.index.tsx | 299 ++++++++++++++++++++++++++++++++++ src/routes/settings.imap.tsx | 281 ++++++++++++++++++++++++++++++++ src/routes/settings.tsx | 1 + 5 files changed, 740 insertions(+), 1 deletion(-) create mode 100644 src/routes/hooks/poll-imap.ts create mode 100644 src/routes/inbox.index.tsx create mode 100644 src/routes/settings.imap.tsx diff --git a/src/components/app-shell.tsx b/src/components/app-shell.tsx index 65e7e89..da0c777 100644 --- a/src/components/app-shell.tsx +++ b/src/components/app-shell.tsx @@ -1,7 +1,7 @@ import { Link, useLocation, useNavigate } from "@tanstack/react-router"; import { useAuth } from "@/lib/auth"; import { Button } from "@/components/ui/button"; -import { Briefcase, Users, FileText, Receipt, ShieldCheck, LogOut, Scale, LayoutDashboard, Calendar as CalendarIcon, CheckSquare, MessageSquare, Activity, DollarSign, FolderOpen, Files as FilesIcon, Settings as SettingsIcon, ClipboardList, UserPlus, User as UserIcon } from "lucide-react"; +import { Briefcase, Users, FileText, Receipt, ShieldCheck, LogOut, Scale, LayoutDashboard, Calendar as CalendarIcon, CheckSquare, MessageSquare, Activity, DollarSign, FolderOpen, Files as FilesIcon, Settings as SettingsIcon, ClipboardList, UserPlus, User as UserIcon, Inbox as InboxIcon } from "lucide-react"; import { cn } from "@/lib/utils"; import type { ReactNode } from "react"; import { HeaderTimer } from "@/components/timer/header-timer"; @@ -24,6 +24,7 @@ const NAV: NavItem[] = [ { to: "/cases", label: "Cases", icon: Briefcase }, { to: "/tasks", label: "Tasks", icon: CheckSquare }, { to: "/messages", label: "Messages", icon: MessageSquare }, + { to: "/inbox", label: "Inbox", icon: InboxIcon }, { to: "/status", label: "Status Updates", icon: Activity }, { to: "/collections", label: "Collections", icon: DollarSign }, { to: "/documents", label: "Documents", icon: FolderOpen }, diff --git a/src/routes/hooks/poll-imap.ts b/src/routes/hooks/poll-imap.ts new file mode 100644 index 0000000..3a99242 --- /dev/null +++ b/src/routes/hooks/poll-imap.ts @@ -0,0 +1,157 @@ +// Server route that connects to the configured IMAP mailbox, fetches new +// messages since the last polled UID, and stores them in incoming_emails. +// Triggered by pg_cron and by the "Poll now" button in settings. +import { createFileRoute } from "@tanstack/react-router"; +import { supabaseAdmin } from "@/integrations/supabase/client.server"; +import { ImapFlow } from "imapflow"; +import { simpleParser } from "mailparser"; + +const MAX_MESSAGES_PER_RUN = 50; + +export const Route = createFileRoute("/hooks/poll-imap")({ + server: { + handlers: { + POST: async () => { + try { + const { data: settings, error: setErr } = await supabaseAdmin + .from("imap_settings") + .select("*") + .eq("enabled", true) + .order("updated_at", { ascending: false }) + .limit(1) + .maybeSingle(); + + if (setErr) return json({ error: setErr.message }, 500); + if (!settings) return json({ error: "No IMAP settings configured" }, 400); + + const password = process.env.IMAP_PASSWORD; + if (!password) { + return json({ error: "IMAP_PASSWORD secret is not set" }, 400); + } + + const client = new ImapFlow({ + host: settings.host, + port: settings.port, + secure: !!settings.secure, + auth: { user: settings.username, pass: password }, + logger: false, + }); + + let imported = 0; + let highestUid = settings.last_uid ?? 0; + let errorMessage: string | null = null; + + try { + await client.connect(); + const lock = await client.getMailboxLock(settings.folder ?? "INBOX"); + + try { + const sinceUid = (settings.last_uid ?? 0) + 1; + const range = `${sinceUid}:*`; + + for await (const msg of client.fetch( + range, + { uid: true, source: true, envelope: true, size: true }, + { uid: true }, + )) { + if (imported >= MAX_MESSAGES_PER_RUN) break; + if (msg.uid <= (settings.last_uid ?? 0)) continue; + + let parsed; + try { + parsed = await simpleParser(msg.source as Buffer); + } catch (e) { + console.error("Failed to parse message uid", msg.uid, e); + continue; + } + + const fromAddr = parsed.from?.value?.[0]?.address ?? null; + const fromName = parsed.from?.value?.[0]?.name ?? null; + const toAddrs = + Array.isArray(parsed.to) + ? parsed.to.flatMap((a: any) => a.value.map((v: any) => v.address).filter(Boolean)) + : (parsed.to?.value?.map((v: any) => v.address).filter(Boolean) ?? []); + const ccAddrs = + Array.isArray(parsed.cc) + ? parsed.cc.flatMap((a: any) => a.value.map((v: any) => v.address).filter(Boolean)) + : (parsed.cc?.value?.map((v: any) => v.address).filter(Boolean) ?? []); + + const text = parsed.text ?? null; + const snippet = text + ? text.replace(/\s+/g, " ").trim().slice(0, 280) + : null; + const attachments = parsed.attachments ?? []; + + const insertRow = { + message_id: parsed.messageId ?? null, + imap_uid: msg.uid, + received_at: (parsed.date ?? new Date()).toISOString(), + from_address: fromAddr, + from_name: fromName, + to_addresses: toAddrs, + cc_addresses: ccAddrs, + subject: parsed.subject ?? null, + body_text: text, + body_html: parsed.html || null, + snippet, + has_attachments: attachments.length > 0, + attachment_count: attachments.length, + raw_size_bytes: msg.size ?? null, + }; + + // Upsert by message_id to avoid duplicates if mailbox is re-polled + const { error: insErr } = await supabaseAdmin + .from("incoming_emails") + .upsert(insertRow, { onConflict: "message_id", ignoreDuplicates: true }); + + if (insErr && !insErr.message.includes("duplicate")) { + console.error("Insert failed for uid", msg.uid, insErr.message); + } else { + imported++; + } + + if (msg.uid > highestUid) highestUid = msg.uid; + } + } finally { + lock.release(); + } + await client.logout(); + } catch (e) { + errorMessage = e instanceof Error ? e.message : String(e); + console.error("IMAP poll error:", errorMessage); + try { + await client.close(); + } catch (_) { + /* ignore */ + } + } + + await supabaseAdmin + .from("imap_settings") + .update({ + last_uid: highestUid, + last_polled_at: new Date().toISOString(), + last_error: errorMessage, + }) + .eq("id", settings.id); + + if (errorMessage) { + return json({ ok: false, imported, error: errorMessage }, 500); + } + return json({ ok: true, imported, last_uid: highestUid }); + } catch (e) { + const message = e instanceof Error ? e.message : String(e); + console.error("poll-imap fatal", message); + return json({ error: message }, 500); + } + }, + }, + }, +}); + +function json(data: unknown, status = 200) { + return new Response(JSON.stringify(data), { + status, + headers: { "Content-Type": "application/json" }, + }); +} diff --git a/src/routes/inbox.index.tsx b/src/routes/inbox.index.tsx new file mode 100644 index 0000000..6baef28 --- /dev/null +++ b/src/routes/inbox.index.tsx @@ -0,0 +1,299 @@ +import { createFileRoute } from "@tanstack/react-router"; +import { useEffect, useState } from "react"; +import { supabase } from "@/integrations/supabase/client"; +import { ProtectedLayout } from "@/components/protected-layout"; +import { PageContainer, PageHeader } from "@/components/app-shell"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Input } from "@/components/ui/input"; +import { Loader2, Inbox as InboxIcon, RefreshCcw, Search, Mail, MailOpen, Archive, ArchiveRestore, Trash2 } from "lucide-react"; +import { toast } from "sonner"; +import { useAuth } from "@/lib/auth"; + +export const Route = createFileRoute("/inbox/")({ + component: InboxPage, +}); + +interface IncomingEmail { + id: string; + received_at: string; + from_address: string | null; + from_name: string | null; + to_addresses: string[]; + subject: string | null; + snippet: string | null; + body_text: string | null; + body_html: string | null; + is_read: boolean; + is_archived: boolean; + has_attachments: boolean; + attachment_count: number; +} + +function InboxPage() { + const { isAdmin } = useAuth(); + const [emails, setEmails] = useState([]); + const [loading, setLoading] = useState(true); + const [polling, setPolling] = useState(false); + const [showArchived, setShowArchived] = useState(false); + const [search, setSearch] = useState(""); + const [selectedId, setSelectedId] = useState(null); + + const load = async () => { + setLoading(true); + let query = supabase + .from("incoming_emails") + .select("id, received_at, from_address, from_name, to_addresses, subject, snippet, body_text, body_html, is_read, is_archived, has_attachments, attachment_count") + .order("received_at", { ascending: false }) + .limit(200); + query = showArchived ? query.eq("is_archived", true) : query.eq("is_archived", false); + const { data, error } = await query; + if (error) { + toast.error("Failed to load inbox", { description: error.message }); + } else { + setEmails((data as IncomingEmail[]) ?? []); + } + setLoading(false); + }; + + useEffect(() => { + load(); + }, [showArchived]); + + const pollNow = async () => { + setPolling(true); + try { + const res = await fetch("/hooks/poll-imap", { method: "POST" }); + const body = await res.json(); + if (!res.ok || body.error) { + toast.error("Poll failed", { description: body.error }); + } else { + toast.success(`Imported ${body.imported ?? 0} new email(s)`); + load(); + } + } catch (e) { + toast.error("Poll failed", { + description: e instanceof Error ? e.message : String(e), + }); + } finally { + setPolling(false); + } + }; + + const markRead = async (id: string, isRead: boolean) => { + await supabase.from("incoming_emails").update({ is_read: isRead }).eq("id", id); + setEmails((prev) => + prev.map((e) => (e.id === id ? { ...e, is_read: isRead } : e)), + ); + }; + + const toggleArchive = async (id: string, archive: boolean) => { + await supabase.from("incoming_emails").update({ is_archived: archive }).eq("id", id); + setEmails((prev) => prev.filter((e) => e.id !== id)); + if (selectedId === id) setSelectedId(null); + toast.success(archive ? "Archived" : "Restored"); + }; + + const deleteEmail = async (id: string) => { + if (!confirm("Delete this email permanently?")) return; + const { error } = await supabase.from("incoming_emails").delete().eq("id", id); + if (error) { + toast.error("Delete failed", { description: error.message }); + return; + } + setEmails((prev) => prev.filter((e) => e.id !== id)); + if (selectedId === id) setSelectedId(null); + }; + + const filtered = emails.filter((e) => { + if (!search.trim()) return true; + const q = search.toLowerCase(); + return ( + (e.subject ?? "").toLowerCase().includes(q) || + (e.from_address ?? "").toLowerCase().includes(q) || + (e.from_name ?? "").toLowerCase().includes(q) || + (e.snippet ?? "").toLowerCase().includes(q) + ); + }); + + const selected = emails.find((e) => e.id === selectedId) ?? null; + const unreadCount = emails.filter((e) => !e.is_read).length; + + return ( + + + + {polling ? ( + + ) : ( + + )} + Check for new mail + + } + /> + +
+
+ + setSearch(e.target.value)} + className="pl-8" + /> +
+ +
+ + {loading ? ( +
+ +
+ ) : filtered.length === 0 ? ( + + + + {showArchived ? "No archived emails." : "No emails yet. "} + {!showArchived && ( + <>Configure IMAP in
Settings → Email (IMAP) and click "Check for new mail". + )} + + + ) : ( +
+ +
+ {filtered.map((email) => ( + + ))} +
+
+ + + {selected ? ( + +
+
+

+ {selected.subject || "(no subject)"} +

+
+ From: + {selected.from_name + ? `${selected.from_name} <${selected.from_address}>` + : selected.from_address} + +
+
+ To: {selected.to_addresses.join(", ")} +
+
+ {new Date(selected.received_at).toLocaleString()} +
+
+
+ + + {isAdmin && ( + + )} +
+
+
+ {selected.body_html ? ( +