Complete S03 runtime closure and S04 control loop
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { Box, Button, Chip, Divider, Paper, Typography } from "@mui/material";
|
||||
|
||||
@@ -6,8 +7,7 @@ import { api } from "../api";
|
||||
import { JobApplication } from "../types";
|
||||
import { useToast } from "../toast";
|
||||
import { useI18n } from "../i18n/I18nProvider";
|
||||
|
||||
import JobDetailsDialog from "./JobDetailsDialog";
|
||||
import { buildJobWorkspacePath, JOB_DETAILS_TABS } from "../jobWorkspaceRoute";
|
||||
|
||||
type ReminderGroups = {
|
||||
missingCv: JobApplication[];
|
||||
@@ -28,7 +28,7 @@ function groupItems(items: JobApplication[]): ReminderGroups {
|
||||
return groups;
|
||||
}
|
||||
|
||||
function ReminderSection({ title, items, onOpen, onSetFollowUp }: { title: string; items: JobApplication[]; onOpen: (id: number) => void; onSetFollowUp: (id: number, days: number | null) => void }) {
|
||||
function ReminderSection({ title, items, onOpen, onSetFollowUp }: { title: string; items: JobApplication[]; onOpen: (job: JobApplication) => void; onSetFollowUp: (id: number, days: number | null) => void }) {
|
||||
const { t } = useI18n();
|
||||
if (items.length === 0) return null;
|
||||
|
||||
@@ -49,7 +49,7 @@ function ReminderSection({ title, items, onOpen, onSetFollowUp }: { title: strin
|
||||
</Box>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", gap: 1, flexWrap: "wrap", justifyContent: "flex-end" }}>
|
||||
<Button size="small" variant="outlined" onClick={() => onOpen(j.id)}>{t("remindersOpen")}</Button>
|
||||
<Button size="small" variant="outlined" onClick={() => onOpen(j)}>{t("remindersOpen")}</Button>
|
||||
<Button size="small" variant="outlined" onClick={() => onSetFollowUp(j.id, 3)}>+3d</Button>
|
||||
<Button size="small" variant="outlined" onClick={() => onSetFollowUp(j.id, 7)}>+7d</Button>
|
||||
<Button size="small" onClick={() => onSetFollowUp(j.id, null)}>{t("remindersClear")}</Button>
|
||||
@@ -61,10 +61,10 @@ function ReminderSection({ title, items, onOpen, onSetFollowUp }: { title: strin
|
||||
}
|
||||
|
||||
export default function RemindersView() {
|
||||
const navigate = useNavigate();
|
||||
const { toast } = useToast();
|
||||
const { t } = useI18n();
|
||||
const [items, setItems] = useState<JobApplication[]>([]);
|
||||
const [openJobId, setOpenJobId] = useState<number | null>(null);
|
||||
|
||||
const load = async () => {
|
||||
const res = await api.get<JobApplication[]>("/jobapplications/reminders", { params: { upcomingDays: 14 } });
|
||||
@@ -77,6 +77,15 @@ export default function RemindersView() {
|
||||
|
||||
const grouped = useMemo(() => groupItems(items), [items]);
|
||||
|
||||
const openJob = (job: JobApplication) => {
|
||||
const reason = (job.followUpReason ?? '').toLowerCase();
|
||||
if (reason.includes('tailored cv')) {
|
||||
navigate(buildJobWorkspacePath(job.id, { tab: JOB_DETAILS_TABS.tailoredCv }));
|
||||
return;
|
||||
}
|
||||
navigate(buildJobWorkspacePath(job.id, { tab: JOB_DETAILS_TABS.followUp, followMode: 'waiting-update' }));
|
||||
};
|
||||
|
||||
const setFollowUp = async (id: number, daysFromNow: number | null) => {
|
||||
try {
|
||||
const d = daysFromNow === null ? null : new Date(Date.now() + daysFromNow * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
|
||||
@@ -96,10 +105,10 @@ export default function RemindersView() {
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
|
||||
<ReminderSection title={t("remindersMissingTailoredCv")} items={grouped.missingCv} onOpen={setOpenJobId} onSetFollowUp={setFollowUp} />
|
||||
<ReminderSection title={t("remindersMissingInterviewPrep")} items={grouped.missingInterviewNotes} onOpen={setOpenJobId} onSetFollowUp={setFollowUp} />
|
||||
<ReminderSection title={t("remindersFollowUpDue")} items={grouped.overdueFollowUp} onOpen={setOpenJobId} onSetFollowUp={setFollowUp} />
|
||||
<ReminderSection title={t("remindersOther")} items={grouped.other} onOpen={setOpenJobId} onSetFollowUp={setFollowUp} />
|
||||
<ReminderSection title={t("remindersMissingTailoredCv")} items={grouped.missingCv} onOpen={openJob} onSetFollowUp={setFollowUp} />
|
||||
<ReminderSection title={t("remindersMissingInterviewPrep")} items={grouped.missingInterviewNotes} onOpen={openJob} onSetFollowUp={setFollowUp} />
|
||||
<ReminderSection title={t("remindersFollowUpDue")} items={grouped.overdueFollowUp} onOpen={openJob} onSetFollowUp={setFollowUp} />
|
||||
<ReminderSection title={t("remindersOther")} items={grouped.other} onOpen={openJob} onSetFollowUp={setFollowUp} />
|
||||
|
||||
{items.length === 0 ? <Typography sx={{ color: "text.secondary", textAlign: "center", py: 3 }}>{t("remindersNothing")}</Typography> : null}
|
||||
</Box>
|
||||
@@ -108,8 +117,6 @@ export default function RemindersView() {
|
||||
<Typography variant="caption" sx={{ color: "text.secondary" }}>
|
||||
{t("remindersTip")}
|
||||
</Typography>
|
||||
|
||||
<JobDetailsDialog open={openJobId !== null} jobId={openJobId} onClose={() => setOpenJobId(null)} />
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user