import React, { useEffect, useMemo, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Paper, Stack, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, } from "@mui/material"; import useMediaQuery from "@mui/material/useMediaQuery"; import { api, getApiErrorMessage } from "../api"; import ViewStateNotice from "./ViewStateNotice"; import { Company } from "../types"; import EditOutlinedIcon from "@mui/icons-material/EditOutlined"; import { useToast } from "../toast"; import { useI18n } from "../i18n/I18nProvider"; import { useViewResource } from "../hooks/useViewResource"; export default function CompaniesTable() { const isMobile = useMediaQuery("(max-width:767.95px)"); const { toast } = useToast(); const { t } = useI18n(); const location = useLocation(); const navigate = useNavigate(); const [editOpen, setEditOpen] = useState(false); const [editing, setEditing] = useState(null); const [recruiterName, setRecruiterName] = useState(""); const [recruiterEmail, setRecruiterEmail] = useState(""); const [recruiterLinkedIn, setRecruiterLinkedIn] = useState(""); const [pipelineStage, setPipelineStage] = useState(""); const [lastContactedAt, setLastContactedAt] = useState(""); const [nextContactAt, setNextContactAt] = useState(""); const companiesResource = useViewResource( async () => { const response = await api.get("/companies"); return response.data; }, { initialData: [], errorMessage: t("companiesUpdateFailed"), deps: [t], }, ); const companies = companiesResource.data; useEffect(() => { const params = new URLSearchParams(location.search); const editId = Number(params.get("edit") || 0); if (!editId || companies.length === 0) return; const company = companies.find((c) => c.id === editId); if (!company) return; openEdit(company); params.delete("edit"); navigate({ pathname: location.pathname, search: params.toString() ? `?${params.toString()}` : "" }, { replace: true }); }, [companies, location.pathname, location.search, navigate]); const openEdit = (c: Company) => { setEditing(c); setRecruiterName(c.recruiterName ?? ""); setRecruiterEmail(c.recruiterEmail ?? ""); setRecruiterLinkedIn(c.recruiterLinkedIn ?? ""); setPipelineStage(c.pipelineStage ?? ""); setLastContactedAt((c.lastContactedAt ?? "").slice(0, 10)); setNextContactAt((c.nextContactAt ?? "").slice(0, 10)); setEditOpen(true); }; const canSave = useMemo(() => !!editing?.id, [editing]); const save = async () => { if (!editing?.id) return; try { const res = await api.put(`/companies/${editing.id}`, { name: editing.name, location: editing.location ?? null, source: editing.source ?? null, recruiterName: recruiterName.trim() || null, recruiterEmail: recruiterEmail.trim() || null, recruiterLinkedIn: recruiterLinkedIn.trim() || null, pipelineStage: pipelineStage.trim() || null, lastContactedAt: lastContactedAt || null, nextContactAt: nextContactAt || null, }); companiesResource.setData((prev) => prev.map((x) => (x.id === res.data.id ? res.data : x))); toast(t("companiesUpdated"), "success"); setEditOpen(false); setEditing(null); } catch (error) { toast(getApiErrorMessage(error, t("companiesUpdateFailed")), "error"); } }; const renderCompanyMeta = (label: string, value?: string | null) => ( {label} {value || "—"} ); return ( {!companiesResource.loading && !companiesResource.error ? ( isMobile ? ( {companies.map((c) => ( {c.name} {c.location || t("companiesLocation")} openEdit(c)}> {renderCompanyMeta(t("companiesSource"), c.source)} {renderCompanyMeta(t("companiesPipeline"), c.pipelineStage)} {renderCompanyMeta(t("companiesRecruiter"), [c.recruiterName, c.recruiterEmail].filter(Boolean).join(" · "))} {renderCompanyMeta(t("companiesNextContact"), c.nextContactAt ? new Date(c.nextContactAt).toLocaleDateString() : null)} ))} {companies.length === 0 ? ( {t("companiesEmpty")} ) : null} ) : ( {t("companiesName")} {t("companiesLocation")} {t("companiesSource")} {t("companiesPipeline")} {t("companiesRecruiter")} {t("companiesNextContact")} {companies.map((c) => ( {c.name} {c.location ?? ""} {c.source ?? ""} {c.pipelineStage ?? ""} {c.recruiterName ?? ""} {c.recruiterEmail ? ` (${c.recruiterEmail})` : ""} {c.nextContactAt ? new Date(c.nextContactAt).toLocaleDateString() : ""} openEdit(c)}> ))} {companies.length === 0 && ( {t("companiesEmpty")} )}
) ) : null} setEditOpen(false)} fullWidth fullScreen={isMobile} maxWidth="sm"> {t("companiesEdit")} setEditing((p) => (p ? { ...p, name: e.target.value } : p))} sx={{ gridColumn: { xs: "1 / -1", md: "1 / -1" } }} /> setEditing((p) => (p ? { ...p, location: e.target.value } : p))} /> setEditing((p) => (p ? { ...p, source: e.target.value } : p))} /> setPipelineStage(e.target.value)} /> setRecruiterName(e.target.value)} /> setRecruiterEmail(e.target.value)} /> setRecruiterLinkedIn(e.target.value)} sx={{ gridColumn: { xs: "1 / -1", md: "1 / -1" } }} /> setLastContactedAt(e.target.value)} InputLabelProps={{ shrink: true }} /> setNextContactAt(e.target.value)} InputLabelProps={{ shrink: true }} />
); }