feat(jobs): integrate table and board workspace

This commit is contained in:
cesnimda
2026-09-29 23:01:05 +02:00
parent 6fc8937701
commit 384dfa8a4b
35 changed files with 1191 additions and 60 deletions
+10 -15
View File
@@ -3,7 +3,6 @@ import React, { useEffect, useMemo, useRef, useState } from "react";
import {
Alert,
Box,
Button,
Card,
CardContent,
Chip,
@@ -16,7 +15,7 @@ import {
} from "@mui/material";
import { useTheme } from "@mui/material/styles";
import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
import { Link as RouterLink, useLocation, useNavigate } from "react-router-dom";
import { useLocation, useNavigate } from "react-router-dom";
import { api, getApiErrorMessage } from "../api";
import ViewStateNotice from "./ViewStateNotice";
@@ -24,6 +23,7 @@ import { JobApplication } from "../types";
import { useI18n } from "../i18n/I18nProvider";
import { useViewResource } from "../hooks/useViewResource";
import { jobsQueryFromSearch } from "../jobsQuery";
import { useDebouncedValue } from "../hooks/useDebouncedValue";
import {
GROUP_ENTRY_STATUS,
PIPELINE_GROUPS,
@@ -73,12 +73,13 @@ function cardPill(job: JobApplication, t: (key: any, params?: any) => string, la
return null;
}
export default function KanbanBoard() {
export default function KanbanBoard({ refreshToken = 0, onResultCount }: { refreshToken?: number; onResultCount?: (count: number | null) => void }) {
const theme = useTheme();
const palette = theme.vars?.palette ?? theme.palette;
const { t, language } = useI18n();
const location = useLocation();
const params = useMemo(() => jobsQueryFromSearch(location.search), [location.search]);
const query = useMemo(() => jobsQueryFromSearch(location.search), [location.search]);
const params = useDebouncedValue(query, 250);
const boardRef = useRef<HTMLDivElement>(null);
const navigate = useNavigate();
const [focusAfterMoveId, setFocusAfterMoveId] = useState<number | null>(null);
@@ -98,11 +99,14 @@ export default function KanbanBoard() {
{
initialData: [],
errorMessage: t("kanbanLoadFailed"),
deps: [t, params],
deps: [t, params, refreshToken],
},
);
const jobs = jobsResource.data;
useEffect(() => {
onResultCount?.(jobsResource.loading || jobsResource.refreshing || jobsResource.error ? null : jobs.length);
}, [onResultCount, jobs.length, jobsResource.loading, jobsResource.refreshing, jobsResource.error]);
useEffect(() => {
if (jobsResource.loading || jobsResource.refreshing || jobsResource.error) return;
@@ -198,16 +202,7 @@ export default function KanbanBoard() {
return (
<Box ref={boardRef} sx={{ mt: 2, width: "100%", minWidth: 0, maxWidth: "100%", overflowX: "clip", contain: "inline-size" }}>
<Box sx={{ display: "flex", alignItems: { xs: "stretch", sm: "center" }, justifyContent: "space-between", gap: 1.5, flexDirection: { xs: "column", sm: "row" }, mb: 2 }}>
<Box>
<Typography variant="body2" sx={{ color: "text.secondary" }}>{t("kanbanHint")}</Typography>
<Typography variant="caption" sx={{ color: "text.secondary" }}>{t("kanbanSeparateViews")}</Typography>
</Box>
<Box sx={{ display: "flex", gap: 0.75, flexShrink: 0 }}>
<Button component={RouterLink} to={{ pathname: "/jobs", search: location.search }} variant="outlined" size="small">{t("jobApplications")}</Button>
<Button variant="contained" size="small" aria-current="page" disabled>{t("kanbanBoard")}</Button>
</Box>
</Box>
<Typography variant="body2" sx={{ color: "text.secondary", mb: 2 }}>{t("kanbanHint")}</Typography>
<ViewStateNotice
loading={jobsResource.loading || jobsResource.refreshing}