fix(mail): search every owned job
CI and Deploy / test (pull_request) Successful in 5m13s
CI and Deploy / deploy (pull_request) Has been skipped

Replace ineffective pageSize=100 selectors with a bounded owner-filtered search endpoint for composing and moving linked threads.
This commit is contained in:
cesnimda
2026-08-15 20:13:14 +02:00
parent dc511296a4
commit a08ba9b45d
9 changed files with 167 additions and 57 deletions
@@ -3,6 +3,7 @@ import { useNavigate, useSearchParams } from "react-router-dom";
import {
Box,
Alert,
Autocomplete,
Chip,
CircularProgress,
FormControl,
@@ -53,7 +54,7 @@ type EmailProviderStatus = {
type JobChoice = {
id: number;
jobTitle: string;
company?: { name?: string | null } | null;
companyName: string;
};
export function emailProviderStatusLabel(provider: EmailProviderStatus) {
@@ -119,6 +120,8 @@ export default function CorrespondenceInboxPage() {
const [providerStatusLoaded, setProviderStatusLoaded] = useState(false);
const [jobs, setJobs] = useState<JobChoice[]>([]);
const [jobsLoaded, setJobsLoaded] = useState(false);
const [jobsLoading, setJobsLoading] = useState(false);
const [jobQuery, setJobQuery] = useState("");
const [composeSetupOpen, setComposeSetupOpen] = useState(false);
const [composeJobId, setComposeJobId] = useState<number | "">("");
const [composeProvider, setComposeProvider] = useState("");
@@ -178,11 +181,18 @@ export default function CorrespondenceInboxPage() {
}, []);
useEffect(() => {
api.get<{ items?: JobChoice[] }>("/jobapplications", { params: { page: 1, pageSize: 100, sortBy: "dateApplied", sortDir: "desc" } })
.then((response) => setJobs(Array.isArray(response.data?.items) ? response.data.items : []))
.catch(() => setJobs([]))
.finally(() => setJobsLoaded(true));
}, []);
const timer = window.setTimeout(() => {
setJobsLoading(true);
api.get<JobChoice[]>("/jobapplications/choices", { params: { q: jobQuery.trim() || undefined, limit: 20 } })
.then((response) => setJobs(Array.isArray(response.data) ? response.data : []))
.catch(() => setJobs([]))
.finally(() => {
setJobsLoaded(true);
setJobsLoading(false);
});
}, jobQuery.trim() ? 250 : 0);
return () => window.clearTimeout(timer);
}, [jobQuery]);
const loadStoredDrafts = useCallback(async () => {
try {
@@ -312,7 +322,7 @@ export default function CorrespondenceInboxPage() {
}))) return;
setDraft({
jobApplicationId: job.id,
companyName: job.company?.name || "Unknown company",
companyName: job.companyName || "Unknown company",
jobTitle: job.jobTitle || "Unknown role",
provider: provider.provider,
providerName: provider.displayName,
@@ -558,12 +568,18 @@ export default function CorrespondenceInboxPage() {
<Paper component="section" aria-labelledby="compose-new-title" variant="outlined" sx={{ p: 2, borderRadius: 3, mb: 2 }}>
<Typography id="compose-new-title" component="h2" variant="h6" sx={{ fontWeight: 900, mb: 1.5 }}>Compose new email</Typography>
<Box sx={{ display: "grid", gridTemplateColumns: { xs: "1fr", md: "1fr 1fr auto" }, gap: 1.25, alignItems: "center" }}>
<FormControl fullWidth>
<InputLabel id="compose-job-label">Job</InputLabel>
<Select labelId="compose-job-label" value={composeJobId} label="Job" onChange={(event) => setComposeJobId(Number(event.target.value))}>
{jobs.map((job) => <MenuItem key={job.id} value={job.id}>{job.company?.name || "Unknown company"} · {job.jobTitle}</MenuItem>)}
</Select>
</FormControl>
<Autocomplete
options={jobs}
loading={jobsLoading}
value={jobs.find((job) => job.id === composeJobId) ?? null}
onInputChange={(_, value, reason) => {
if (reason === "input" || reason === "clear") setJobQuery(value);
}}
onChange={(_, value) => setComposeJobId(value?.id ?? "")}
isOptionEqualToValue={(option, value) => option.id === value.id}
getOptionLabel={(job) => `${job.companyName || "Unknown company"} · ${job.jobTitle}`}
renderInput={(params) => <TextField {...params} label="Job" placeholder="Search every job" />}
/>
<FormControl fullWidth>
<InputLabel id="compose-provider-label">Sending provider</InputLabel>
<Select labelId="compose-provider-label" value={composeProvider} label="Sending provider" onChange={(event) => setComposeProvider(String(event.target.value))}>