useRescoreJob to reduce duplication

This commit is contained in:
DaKheera47 2026-01-25 12:06:14 +00:00
parent f491f4634e
commit 85976caf9c
4 changed files with 73 additions and 33 deletions

View File

@ -46,6 +46,7 @@ import * as api from "../api";
import { FitAssessment, JobHeader, TailoredSummary } from ".";
import { TailorMode } from "./discovered-panel/TailorMode";
import { useProfile } from "../hooks/useProfile";
import { useRescoreJob } from "../hooks/useRescoreJob";
import type { Job, ResumeProjectCatalogItem } from "../../shared/types";
type PanelMode = "ready" | "tailor";
@ -67,7 +68,7 @@ export const ReadyPanel: React.FC<ReadyPanelProps> = ({
const [mode, setMode] = useState<PanelMode>("ready");
const [isMarkingApplied, setIsMarkingApplied] = useState(false);
const [isRegenerating, setIsRegenerating] = useState(false);
const [isRescoring, setIsRescoring] = useState(false);
const { isRescoring, rescoreJob } = useRescoreJob(onJobUpdated);
const [catalog, setCatalog] = useState<ResumeProjectCatalogItem[]>([]);
const [recentlyApplied, setRecentlyApplied] = useState<{
jobId: string;
@ -182,21 +183,7 @@ export const ReadyPanel: React.FC<ReadyPanelProps> = ({
}
}, [job, onJobUpdated]);
const handleRescore = useCallback(async () => {
if (!job) return;
try {
setIsRescoring(true);
await api.rescoreJob(job.id);
toast.success("Match recalculated");
await onJobUpdated();
} catch (error) {
const message = error instanceof Error ? error.message : "Failed to recalculate match";
toast.error(message);
} finally {
setIsRescoring(false);
}
}, [job, onJobUpdated]);
const handleRescore = useCallback(() => rescoreJob(job?.id), [job?.id, rescoreJob]);
const handleSkip = useCallback(async () => {
if (!job) return;

View File

@ -7,6 +7,7 @@ import { DecideMode } from "./DecideMode";
import { EmptyState } from "./EmptyState";
import { ProcessingState } from "./ProcessingState";
import { TailorMode } from "./TailorMode";
import { useRescoreJob } from "../../hooks/useRescoreJob";
type PanelMode = "decide" | "tailor";
@ -24,13 +25,12 @@ export const DiscoveredPanel: React.FC<DiscoveredPanelProps> = ({
const [mode, setMode] = useState<PanelMode>("decide");
const [isSkipping, setIsSkipping] = useState(false);
const [isFinalizing, setIsFinalizing] = useState(false);
const [isRescoring, setIsRescoring] = useState(false);
const { isRescoring, rescoreJob } = useRescoreJob(onJobUpdated);
useEffect(() => {
setMode("decide");
setIsSkipping(false);
setIsFinalizing(false);
setIsRescoring(false);
}, [job?.id]);
const handleSkip = async () => {
@ -71,21 +71,7 @@ export const DiscoveredPanel: React.FC<DiscoveredPanelProps> = ({
}
};
const handleRescore = async () => {
if (!job) return;
try {
setIsRescoring(true);
await api.rescoreJob(job.id);
toast.success("Match recalculated");
await onJobUpdated();
} catch (error) {
const message =
error instanceof Error ? error.message : "Failed to recalculate match";
toast.error(message);
} finally {
setIsRescoring(false);
}
};
const handleRescore = () => rescoreJob(job?.id);
if (!job) {
return <EmptyState />;

View File

@ -0,0 +1,38 @@
import { act, renderHook } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { useRescoreJob } from "./useRescoreJob";
import * as api from "../api";
import { toast } from "sonner";
vi.mock("../api", () => ({
rescoreJob: vi.fn(),
}));
vi.mock("sonner", () => ({
toast: {
success: vi.fn(),
error: vi.fn(),
},
}));
describe("useRescoreJob", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("rescoring updates the job and shows a toast", async () => {
const onJobUpdated = vi.fn().mockResolvedValue(undefined);
vi.mocked(api.rescoreJob).mockResolvedValue({} as any);
const { result } = renderHook(() => useRescoreJob(onJobUpdated));
await act(async () => {
await result.current.rescoreJob("job-1");
});
expect(api.rescoreJob).toHaveBeenCalledWith("job-1");
expect(onJobUpdated).toHaveBeenCalled();
expect(toast.success).toHaveBeenCalledWith("Match recalculated");
});
});

View File

@ -0,0 +1,29 @@
import { useCallback, useState } from "react";
import { toast } from "sonner";
import * as api from "../api";
export function useRescoreJob(onJobUpdated: () => void | Promise<void>) {
const [isRescoring, setIsRescoring] = useState(false);
const rescoreJob = useCallback(
async (jobId?: string | null) => {
if (!jobId) return;
try {
setIsRescoring(true);
await api.rescoreJob(jobId);
toast.success("Match recalculated");
await onJobUpdated();
} catch (error) {
const message = error instanceof Error ? error.message : "Failed to recalculate match";
toast.error(message);
} finally {
setIsRescoring(false);
}
},
[onJobUpdated],
);
return { isRescoring, rescoreJob };
}