From 32bf09551b47f5f3d6f7539eb4635d933c5371c3 Mon Sep 17 00:00:00 2001 From: DaKheera47 Date: Thu, 15 Jan 2026 23:25:43 +0000 Subject: [PATCH] removing unused code --- orchestrator/src/client/api/client.ts | 4 - .../src/client/components/JobCard.tsx | 265 ------ .../src/client/components/JobList.tsx | 782 ------------------ .../src/client/components/JobTable.tsx | 387 --------- 4 files changed, 1438 deletions(-) delete mode 100644 orchestrator/src/client/components/JobCard.tsx delete mode 100644 orchestrator/src/client/components/JobList.tsx delete mode 100644 orchestrator/src/client/components/JobTable.tsx diff --git a/orchestrator/src/client/api/client.ts b/orchestrator/src/client/api/client.ts index 6fe30d4..ccb0769 100644 --- a/orchestrator/src/client/api/client.ts +++ b/orchestrator/src/client/api/client.ts @@ -100,10 +100,6 @@ export async function getPipelineStatus(): Promise { return fetchApi('/pipeline/status'); } -export async function getPipelineRuns(): Promise { - return fetchApi('/pipeline/runs'); -} - export async function runPipeline(config?: { topN?: number; minSuitabilityScore?: number; diff --git a/orchestrator/src/client/components/JobCard.tsx b/orchestrator/src/client/components/JobCard.tsx deleted file mode 100644 index 0ac9a67..0000000 --- a/orchestrator/src/client/components/JobCard.tsx +++ /dev/null @@ -1,265 +0,0 @@ -/** - * Individual job card component. - */ - -import React from "react"; -import { - Calendar, - CheckCircle2, - Clock, - Copy, - DollarSign, - Download, - Edit2, - ExternalLink, - GraduationCap, - Loader2, - MapPin, - RefreshCcw, - XCircle, -} from "lucide-react"; -import { toast } from "sonner"; - -import { Badge } from "@/components/ui/badge"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; -import { copyTextToClipboard, formatJobForWebhook } from "@client/lib/jobCopy"; -import type { Job } from "../../shared/types"; -import { ScoreIndicator } from "./ScoreIndicator"; -import { StatusBadge } from "./StatusBadge"; - -interface JobCardProps { - job: Job; - onApply: (id: string) => void | Promise; - onSkip: (id: string) => void | Promise; - onProcess: (id: string) => void | Promise; - onEditDescription?: (id: string) => void; - isProcessing: boolean; - highlightedJobId?: string | null; - onHighlightChange?: (jobId: string | null) => void; -} - -const formatDate = (dateStr: string | null) => { - if (!dateStr) return null; - try { - return new Date(dateStr).toLocaleDateString("en-GB", { - day: "numeric", - month: "short", - year: "numeric", - }); - } catch { - return dateStr; - } -}; - -const formatDateTime = (dateStr: string | null) => { - if (!dateStr) return null; - try { - const normalized = dateStr.includes("T") ? dateStr : dateStr.replace(" ", "T"); - const parsed = new Date(normalized); - if (Number.isNaN(parsed.getTime())) return dateStr; - const date = parsed.toLocaleDateString("en-GB", { - day: "numeric", - month: "short", - year: "numeric", - }); - const time = parsed.toLocaleTimeString("en-GB", { - hour: "2-digit", - minute: "2-digit", - }); - return `${date} ${time}`; - } catch { - return dateStr; - } -}; - -const safeFilenamePart = (value: string) => value.replace(/[^a-z0-9]/gi, "_"); - -export const JobCard: React.FC = ({ - job, - onApply, - onSkip, - onProcess, - onEditDescription, - isProcessing, - highlightedJobId, - onHighlightChange, -}) => { - const sourceLabel: Record = { - gradcracker: "Gradcracker", - indeed: "Indeed", - linkedin: "LinkedIn", - ukvisajobs: "UK Visa Jobs", - }; - - const hasPdf = !!job.pdfPath; - const canApply = job.status === "ready"; - const canProcess = ["discovered", "ready"].includes(job.status); - const canSkip = ["discovered", "ready"].includes(job.status); - - const jobLink = job.applicationLink || job.jobUrl; - const pdfHref = `/pdfs/resume_${job.id}.pdf?v=${encodeURIComponent(job.updatedAt)}`; - const deadline = formatDate(job.deadline); - const discoveredAt = formatDateTime(job.discoveredAt); - const isHighlighted = highlightedJobId === job.id; - - const handleCopyInfo = async () => { - try { - await copyTextToClipboard(formatJobForWebhook(job)); - toast.success("Copied job info", { description: "Webhook payload copied to clipboard." }); - } catch { - toast.error("Could not copy job info"); - } - }; - - return ( - - -
-
- {job.title} -
{job.employer}
-
- -
- - - {sourceLabel[job.source]} - - -
-
- -
- {job.location && ( - - - {job.location} - - )} - {deadline && ( - - - {deadline} - - )} - {discoveredAt && ( - - - Discovered {discoveredAt} - - )} - {job.salary && ( - - - {job.salary} - - )} - {job.degreeRequired && ( - - - {job.degreeRequired} - - )} -
-
- - {(job.suitabilityReason || canApply || canSkip || canProcess || hasPdf) && ( - - {job.suitabilityReason && ( -

- "{job.suitabilityReason}" -

- )} -
- )} - - - - - - - {onEditDescription && ( - - )} - - {onHighlightChange && ( - - )} - - {hasPdf && ( - - )} - - {hasPdf && ( - - )} - - {canProcess && ( - - )} - - {canSkip && ( - - )} - - {canApply && ( - - )} - -
- ); -}; diff --git a/orchestrator/src/client/components/JobList.tsx b/orchestrator/src/client/components/JobList.tsx deleted file mode 100644 index 179dbe5..0000000 --- a/orchestrator/src/client/components/JobList.tsx +++ /dev/null @@ -1,782 +0,0 @@ -/** - * Job list with filtering tabs. - */ - -import React, { useEffect, useMemo, useState } from "react"; -import { ArrowUpDown, Edit2, Filter, LayoutGrid, Save, Search, Sparkles, Table2, Undo, X } from "lucide-react"; -import ReactMarkdown from "react-markdown"; -import remarkGfm from "remark-gfm"; -import { toast } from "sonner"; - -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Textarea } from "@/components/ui/textarea"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuRadioGroup, - DropdownMenuRadioItem, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { Input } from "@/components/ui/input"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { - Accordion, - AccordionContent, - AccordionItem, - AccordionTrigger, -} from "@/components/ui/accordion"; -import { cn } from "@/lib/utils"; -import * as api from "../api"; -import type { Job, JobStatus, JobSource } from "../../shared/types"; -import { JobCard } from "./JobCard"; -import { JobTable, type JobSort } from "./JobTable"; -import { TailoringEditor } from "./TailoringEditor"; - -interface JobListProps { - jobs: Job[]; - onApply: (id: string) => void | Promise; - onSkip: (id: string) => void | Promise; - onProcess: (id: string) => void | Promise; - onUpdate: () => void | Promise; - processingJobId: string | null; -} - -type FilterTab = "ready" | "discovered" | "applied" | "all"; -type ViewMode = "cards" | "table"; - -const JOB_LIST_VIEW_STORAGE_KEY = "jobops.jobs.viewMode"; -const DEFAULT_SORT: JobSort = { key: "discoveredAt", direction: "desc" }; - -const sortLabels: Record = { - discoveredAt: "Discovered", - score: "Score", - title: "Title", - employer: "Company", - source: "Source", - location: "Location", - status: "Status", -}; - -const sourceLabels: Record = { - gradcracker: "Gradcracker", - indeed: "Indeed", - linkedin: "LinkedIn", - ukvisajobs: "UK Visa Jobs", -}; - -const tabs: Array<{ id: FilterTab; label: string; statuses: JobStatus[] }> = [ - { id: "ready", label: "Ready", statuses: ["ready"] }, - { id: "discovered", label: "Discovered", statuses: ["discovered", "processing"] }, - { id: "applied", label: "Applied", statuses: ["applied"] }, - { id: "all", label: "All Jobs", statuses: [] }, -]; - -const emptyStateCopy: Record = { - ready: "Run the pipeline to discover and process new jobs.", - discovered: "All discovered jobs have been processed.", - applied: "You haven't applied to any jobs yet.", - all: "No jobs in the system yet. Run the pipeline to get started!", -}; - -const statusRank: Record = { - discovered: 0, - processing: 1, - ready: 2, - applied: 3, - skipped: 4, - expired: 5, -}; - -const dateValue = (value: string | null) => { - if (!value) return null; - const parsed = Date.parse(value); - return Number.isFinite(parsed) ? parsed : null; -}; - -const compareNullable = ( - a: T | null | undefined, - b: T | null | undefined, - compare: (left: T, right: T) => number, -) => { - const left = a ?? null; - const right = b ?? null; - if (left === null && right === null) return 0; - if (left === null) return 1; - if (right === null) return -1; - return compare(left, right); -}; - -const compareString = (a: string, b: string) => a.localeCompare(b, undefined, { sensitivity: "base" }); - -const compareNumber = (a: number, b: number) => a - b; - -const compareJobs = (a: Job, b: Job, sort: JobSort) => { - let value = 0; - - switch (sort.key) { - case "title": - value = compareString(a.title, b.title); - break; - case "employer": - value = compareString(a.employer, b.employer); - break; - case "source": - value = compareString(a.source, b.source); - break; - case "location": - value = compareNullable(a.location, b.location, compareString); - break; - case "status": - value = statusRank[a.status] - statusRank[b.status]; - break; - case "score": - const aScore = a.suitabilityScore; - const bScore = b.suitabilityScore; - - if (aScore == null && bScore == null) { - value = 0; - break; - } - if (aScore == null) return 1; - if (bScore == null) return -1; - value = compareNumber(aScore, bScore); - break; - case "discoveredAt": - value = compareNullable(dateValue(a.discoveredAt), dateValue(b.discoveredAt), compareNumber); - break; - default: - value = 0; - } - - if (value !== 0) return sort.direction === "asc" ? value : -value; - - const tieByDiscovered = compareNullable( - dateValue(b.discoveredAt), - dateValue(a.discoveredAt), - compareNumber, - ); - if (tieByDiscovered !== 0) return tieByDiscovered; - - return a.id.localeCompare(b.id); -}; - -const jobMatchesQuery = (job: Job, query: string) => { - const normalized = query.trim().toLowerCase(); - if (!normalized) return true; - - const haystack = [ - job.title, - job.employer, - job.location, - job.disciplines, - job.salary, - job.degreeRequired, - job.starting, - job.source, - job.status, - job.jobType, - job.jobFunction, - job.jobLevel, - ] - .filter(Boolean) - .join(" ") - .toLowerCase(); - - return haystack.includes(normalized); -}; - -const stripHtml = (value: string) => value.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim(); - -export const JobList: React.FC = ({ - jobs, - onApply, - onSkip, - onProcess, - onUpdate, - processingJobId, -}) => { - const [activeTab, setActiveTab] = useState("ready"); - const [searchQuery, setSearchQuery] = useState(""); - const [sourceFilter, setSourceFilter] = useState("all"); - const [sort, setSort] = useState(DEFAULT_SORT); - const [selectedJobIds, setSelectedJobIds] = useState>(() => new Set()); - const [batchAction, setBatchAction] = useState(null); - const [highlightedJobId, setHighlightedJobId] = useState(null); - const [isHighlightVisible, setIsHighlightVisible] = useState(false); - const [isEditingDescription, setIsEditingDescription] = useState(false); - const [editedDescription, setEditedDescription] = useState(""); - const [isSavingDescription, setIsSavingDescription] = useState(false); - const [viewMode, setViewMode] = useState(() => { - try { - const raw = localStorage.getItem(JOB_LIST_VIEW_STORAGE_KEY); - if (raw === "cards" || raw === "table") return raw; - return "cards"; - } catch { - return "cards"; - } - }); - - useEffect(() => { - try { - localStorage.setItem(JOB_LIST_VIEW_STORAGE_KEY, viewMode); - } catch { - // Ignore localStorage errors - } - }, [viewMode]); - - useEffect(() => { - setSelectedJobIds(new Set()); - }, [activeTab, viewMode]); - - useEffect(() => { - if (!highlightedJobId) return; - - const prevOverflow = document.body.style.overflow; - document.body.style.overflow = "hidden"; - setIsHighlightVisible(false); - const raf = requestAnimationFrame(() => setIsHighlightVisible(true)); - - const onKeyDown = (event: KeyboardEvent) => { - if (event.key === "Escape") setHighlightedJobId(null); - }; - - window.addEventListener("keydown", onKeyDown); - return () => { - cancelAnimationFrame(raf); - window.removeEventListener("keydown", onKeyDown); - document.body.style.overflow = prevOverflow; - setIsHighlightVisible(false); - }; - }, [highlightedJobId]); - - const counts = useMemo(() => { - const byTab: Record = { - ready: 0, - discovered: 0, - applied: 0, - all: jobs.length, - }; - - for (const job of jobs) { - if (job.status === "ready") byTab.ready += 1; - if (job.status === "applied") byTab.applied += 1; - if (job.status === "discovered" || job.status === "processing") byTab.discovered += 1; - } - - return byTab; - }, [jobs]); - - const jobsForTab = useMemo(() => { - const map = new Map(); - - for (const tab of tabs) { - if (tab.statuses.length === 0) { - map.set(tab.id, jobs); - } else { - map.set(tab.id, jobs.filter((job) => tab.statuses.includes(job.status))); - } - } - - return map; - }, [jobs]); - - const visibleJobsForTab = useMemo(() => { - const map = new Map(); - const normalizedQuery = searchQuery.trim().toLowerCase(); - - for (const tab of tabs) { - let filtered = jobsForTab.get(tab.id) ?? []; - - if (sourceFilter !== "all") { - filtered = filtered.filter((job) => job.source === sourceFilter); - } - - if (normalizedQuery) { - filtered = filtered.filter((job) => jobMatchesQuery(job, normalizedQuery)); - } - - const sorted = [...filtered].sort((a, b) => compareJobs(a, b, sort)); - map.set(tab.id, sorted); - } - - return map; - }, [jobsForTab, searchQuery, sourceFilter, sort]); - - const activeTabJobs = visibleJobsForTab.get(activeTab) ?? []; - const highlightedJob = useMemo( - () => (highlightedJobId ? jobs.find((job) => job.id === highlightedJobId) ?? null : null), - [highlightedJobId, jobs], - ); - - const highlightedJobDescription = useMemo(() => { - if (!highlightedJob) return "No description available."; - const jd = highlightedJob.jobDescription || "No description available."; - if (jd.includes("<") && jd.includes(">")) return stripHtml(jd); - return jd; - }, [highlightedJob]); - - useEffect(() => { - if (!highlightedJobId) { - setIsEditingDescription(false); - setEditedDescription(""); - } else if (highlightedJob && !isEditingDescription) { - setEditedDescription(highlightedJob.jobDescription || ""); - } - }, [highlightedJobId, highlightedJob, isEditingDescription]); - - const handleSaveDescription = async () => { - if (!highlightedJobId) return; - try { - setIsSavingDescription(true); - await api.updateJob(highlightedJobId, { jobDescription: editedDescription }); - toast.success("Job description updated"); - setIsEditingDescription(false); - await onUpdate(); - } catch (error) { - const message = error instanceof Error ? error.message : "Failed to update description"; - toast.error(message); - } finally { - setIsSavingDescription(false); - } - }; - - useEffect(() => { - setSelectedJobIds((current) => { - const visibleIds = new Set(activeTabJobs.map((job) => job.id)); - const next = new Set(); - for (const id of current) { - if (visibleIds.has(id)) next.add(id); - } - return next.size === current.size ? current : next; - }); - }, [activeTabJobs]); - - const activeResultsCount = visibleJobsForTab.get(activeTab)?.length ?? 0; - const hasActiveFilters = - searchQuery.trim().length > 0 || - sourceFilter !== "all" || - sort.key !== DEFAULT_SORT.key || - sort.direction !== DEFAULT_SORT.direction; - - const selectedJobs = useMemo(() => { - if (selectedJobIds.size === 0) return []; - return activeTabJobs.filter((job) => selectedJobIds.has(job.id)); - }, [activeTabJobs, selectedJobIds]); - - const selectedCount = selectedJobIds.size; - - const runBatch = async (action: "process" | "skip" | "apply") => { - if (selectedJobs.length === 0) return; - - const eligible = selectedJobs.filter((job) => { - if (action === "process") return job.status === "discovered"; - if (action === "apply") return job.status === "ready"; - return job.status === "discovered" || job.status === "ready"; - }); - - const skipped = selectedJobs.length - eligible.length; - if (eligible.length === 0) { - toast.message("No eligible jobs selected"); - return; - } - - setBatchAction(action); - try { - for (const job of eligible) { - if (action === "process") await Promise.resolve(onProcess(job.id)); - if (action === "apply") await Promise.resolve(onApply(job.id)); - if (action === "skip") await Promise.resolve(onSkip(job.id)); - } - - setSelectedJobIds(new Set()); - const actionLabel = action === "process" ? "Processed" : action === "apply" ? "Applied" : "Skipped"; - toast.success(`${actionLabel} ${eligible.length} jobs`, skipped > 0 ? { description: `Skipped ${skipped} ineligible.` } : undefined); - } finally { - setBatchAction(null); - } - }; - - return ( - <> - {highlightedJob && ( - <> -
setHighlightedJobId(null)} - /> -
setHighlightedJobId(null)} - > -
event.stopPropagation()} - > -
-
-
Highlighted job
-
{highlightedJob.title}
-
- -
- - - - - - -
- - Resume Tailoring -
-
- - - -
-
- - - -
- Job description - {!isEditingDescription && ( -
Press Esc or click outside to exit highlight.
- )} -
- {!isEditingDescription ? ( - - ) : ( -
- - -
- )} -
- - {isEditingDescription ? ( -