Polish UI, harden company creation, and add error pages
This commit is contained in:
@@ -16,6 +16,7 @@ import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
|
||||
|
||||
import { api } from "../api";
|
||||
import { JobApplication } from "../types";
|
||||
import { useI18n } from "../i18n/I18nProvider";
|
||||
|
||||
const STATUSES = ["Applied", "Waiting", "Interview", "Offer", "Rejected", "Ghosted"] as const;
|
||||
type Status = (typeof STATUSES)[number];
|
||||
@@ -36,6 +37,7 @@ function toneColor(theme: any, status: Status | "Other"): string {
|
||||
|
||||
export default function KanbanBoard() {
|
||||
const theme = useTheme();
|
||||
const { t } = useI18n();
|
||||
const [jobs, setJobs] = useState<JobApplication[]>([]);
|
||||
const [dragJobId, setDragJobId] = useState<number | null>(null);
|
||||
const [menuAnchor, setMenuAnchor] = useState<null | HTMLElement>(null);
|
||||
@@ -64,9 +66,7 @@ export default function KanbanBoard() {
|
||||
if (!dragJobId) return;
|
||||
setDragJobId(null);
|
||||
await api.patch(`/jobapplications/${dragJobId}/status`, { status });
|
||||
setJobs((prev) =>
|
||||
prev.map((j) => (j.id === dragJobId ? { ...j, status } : j)),
|
||||
);
|
||||
setJobs((prev) => prev.map((j) => (j.id === dragJobId ? { ...j, status } : j)));
|
||||
};
|
||||
|
||||
const setStatus = async (id: number, status: Status) => {
|
||||
@@ -74,9 +74,7 @@ export default function KanbanBoard() {
|
||||
setJobs((prev) => prev.map((j) => (j.id === id ? { ...j, status } : j)));
|
||||
};
|
||||
|
||||
const currentMenuStatus = menuJobId == null
|
||||
? null
|
||||
: normalizeStatus(jobs.find((j) => j.id === menuJobId)?.status ?? "");
|
||||
const currentMenuStatus = menuJobId == null ? null : normalizeStatus(jobs.find((j) => j.id === menuJobId)?.status ?? "");
|
||||
|
||||
return (
|
||||
<Box sx={{ mt: 2 }}>
|
||||
@@ -84,14 +82,7 @@ export default function KanbanBoard() {
|
||||
Drag cards between columns to update status.
|
||||
</Typography>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: { xs: "1fr", md: "repeat(3, 1fr)", xl: "repeat(6, 1fr)" },
|
||||
gap: 2,
|
||||
alignItems: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: { xs: "1fr", md: "repeat(3, 1fr)", xl: "repeat(6, 1fr)" }, gap: 2, alignItems: "start" }}>
|
||||
{STATUSES.map((status) => {
|
||||
const c = toneColor(theme, status);
|
||||
const list = groups.get(status) ?? [];
|
||||
@@ -178,28 +169,14 @@ export default function KanbanBoard() {
|
||||
})}
|
||||
</Box>
|
||||
|
||||
<Menu
|
||||
anchorEl={menuAnchor}
|
||||
open={Boolean(menuAnchor)}
|
||||
onClose={() => {
|
||||
setMenuAnchor(null);
|
||||
setMenuJobId(null);
|
||||
}}
|
||||
>
|
||||
<Menu anchorEl={menuAnchor} open={Boolean(menuAnchor)} onClose={() => { setMenuAnchor(null); setMenuJobId(null); }}>
|
||||
{(["Applied", "Waiting", "Interview", "Offer", "Rejected", "Ghosted"] as const)
|
||||
.filter((s) => s !== currentMenuStatus)
|
||||
.map((s) => (
|
||||
<MenuItem
|
||||
key={s}
|
||||
onClick={() => {
|
||||
if (menuJobId) void setStatus(menuJobId, s);
|
||||
setMenuAnchor(null);
|
||||
setMenuJobId(null);
|
||||
}}
|
||||
>
|
||||
Set {s}
|
||||
</MenuItem>
|
||||
))}
|
||||
<MenuItem key={s} onClick={() => { if (menuJobId) void setStatus(menuJobId, s); setMenuAnchor(null); setMenuJobId(null); }}>
|
||||
{t("jobTableSetStatus", { status: s })}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
</Box>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user