import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import { Box, Chip, CircularProgress, FormControl, InputLabel, MenuItem, Paper, Select, Stack, TextField, Typography, Button, } from "@mui/material"; import MailOutlineIcon from "@mui/icons-material/MailOutline"; import { api, getApiErrorMessage } from "../api"; import { useToast } from "../toast"; export type CorrespondenceInboxItem = { id: number; jobApplicationId: number; companyName?: string | null; jobTitle?: string | null; from: string; direction?: string | null; subject?: string | null; channel?: string | null; date: string; contentPreview: string; externalThreadId?: string | null; externalFrom?: string | null; externalTo?: string | null; labelCount: number; attachmentCount: number; }; export default function CorrespondenceInboxPage() { const navigate = useNavigate(); const { toast } = useToast(); const [items, setItems] = useState([]); const [loading, setLoading] = useState(false); const [query, setQuery] = useState(""); const [direction, setDirection] = useState("all"); const [linkState, setLinkState] = useState("all"); const load = useCallback(async () => { setLoading(true); try { const res = await api.get("/correspondence", { params: { q: query.trim() || undefined, direction: direction === "all" ? undefined : direction, linkState: linkState === "all" ? undefined : linkState, }, }); setItems(res.data ?? []); } catch (error) { toast(getApiErrorMessage(error, "Failed to load correspondence inbox."), "error"); } finally { setLoading(false); } }, [direction, linkState, query, toast]); useEffect(() => { void load(); }, [load]); const filteredSummary = useMemo(() => { const linked = items.filter((item) => item.externalThreadId).length; const inbound = items.filter((item) => item.direction === "inbound").length; return { linked, inbound }; }, [items]); return ( Correspondence inbox Cross-job view of imported correspondence and Gmail-linked history. } label={`${items.length} items`} variant="outlined" /> 0 ? "success" : "default"} /> setQuery(e.target.value)} placeholder="Company, role, recruiter, subject" /> Direction Link state {loading ? : null} {!loading && items.length === 0 ? ( No correspondence matches the current filters. ) : null} {items.map((item) => ( {item.companyName || "Unknown company"} • {item.jobTitle || "Unknown role"} {item.subject || item.contentPreview} {item.externalFrom || item.from} {item.externalTo ? `→ ${item.externalTo}` : ""} · {new Date(item.date).toLocaleString()} {item.direction ? : null} {item.externalThreadId ? : } {item.labelCount > 0 ? : null} {item.attachmentCount > 0 ? : null} ))} ); }