Add open job listing action to discovered jobs (#274)

* feat: add open job listing action to discovered jobs

* chore: add skills lockfile

* impeccable
This commit is contained in:
Shaheer Sarfaraz
2026-03-15 21:13:57 +00:00
committed by GitHub
parent 6ae2cd38c1
commit a0220df17f
49 changed files with 4082 additions and 26 deletions
@@ -0,0 +1,27 @@
import { ExternalLink } from "lucide-react";
import type React from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { KbdHint } from "./KbdHint";
interface OpenJobListingButtonProps {
href: string;
className?: string;
shortcut?: string;
}
export const OpenJobListingButton: React.FC<OpenJobListingButtonProps> = ({
href,
className,
shortcut,
}) => {
return (
<Button asChild variant="outline" className={cn("gap-1", className)}>
<a href={href} target="_blank" rel="noopener noreferrer">
<ExternalLink className="h-3.5 w-3.5 shrink-0" />
<span className="truncate">Open Job Listing</span>
{shortcut ? <KbdHint shortcut={shortcut} className="ml-auto" /> : null}
</a>
</Button>
);
};
@@ -52,6 +52,7 @@ import { TailorMode } from "./discovered-panel/TailorMode";
import { GhostwriterDrawer } from "./ghostwriter/GhostwriterDrawer";
import { JobDetailsEditDrawer } from "./JobDetailsEditDrawer";
import { KbdHint } from "./KbdHint";
import { OpenJobListingButton } from "./OpenJobListingButton";
import { ReadySummaryAccordion } from "./ReadySummaryAccordion";
import { buildReadyPanelGoogleDorks } from "./ready-panel-google-dorks";
@@ -397,17 +398,11 @@ export const ReadyPanel: React.FC<ReadyPanelProps> = ({
</Button>
{/* Open job - to verify before applying */}
<Button
asChild
variant="outline"
className="h-9 w-full gap-1 px-2 text-xs"
>
<a href={jobLink} target="_blank" rel="noopener noreferrer">
<ExternalLink className="h-3.5 w-3.5 shrink-0" />
<span className="truncate">Open Job Listing</span>
<KbdHint shortcut="o" className="ml-auto" />
</a>
</Button>
<OpenJobListingButton
href={jobLink}
className="h-9 w-full px-2 text-xs"
shortcut="o"
/>
{/* Primary CTA: Mark Applied */}
<Button
@@ -2,7 +2,6 @@ import type { Job } from "@shared/types.js";
import {
ChevronUp,
Edit2,
ExternalLink,
Loader2,
RefreshCcw,
Sparkles,
@@ -20,6 +19,7 @@ import {
import { Separator } from "@/components/ui/separator";
import { FitAssessment, JobHeader, TailoredSummary } from "..";
import { KbdHint } from "../KbdHint";
import { OpenJobListingButton } from "../OpenJobListingButton";
import { CollapsibleSection } from "./CollapsibleSection";
import { getPlainDescription } from "./helpers";
@@ -58,6 +58,12 @@ export const DecideMode: React.FC<DecideModeProps> = ({
<JobHeader job={job} onCheckSponsor={onCheckSponsor} />
<div className="flex flex-col gap-2.5 pt-2 sm:flex-row">
{jobLink ? (
<OpenJobListingButton
href={jobLink}
className="flex-1 h-11 text-sm sm:h-10 sm:text-xs"
/>
) : null}
<Button
variant="outline"
size="default"
@@ -133,20 +139,6 @@ export const DecideMode: React.FC<DecideModeProps> = ({
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
{jobLink ? (
<div className="flex justify-center">
<a
href={jobLink}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 text-[11px] font-medium text-muted-foreground hover:text-foreground transition-colors"
>
<ExternalLink className="h-3.5 w-3.5" />
Original Job Listing
</a>
</div>
) : null}
</div>
</div>
);
@@ -140,4 +140,26 @@ describe("DiscoveredPanel", () => {
screen.queryByTestId("job-details-edit-drawer"),
).not.toBeInTheDocument();
});
it("shows an open job listing link when the discovered job has an external url", () => {
const job = createJob({
id: "job-3",
jobUrl: "https://example.com/jobs/visit-me",
applicationLink: null,
});
render(
<MemoryRouter>
<DiscoveredPanel
job={job}
onJobUpdated={vi.fn()}
onJobMoved={vi.fn()}
/>
</MemoryRouter>,
);
expect(
screen.getByRole("link", { name: /open job listing/i }),
).toHaveAttribute("href", "https://example.com/jobs/visit-me");
});
});
@@ -3,6 +3,7 @@ export { FitAssessment } from "./FitAssessment";
export { JobHeader } from "./JobHeader";
export * from "./layout";
export { ManualImportSheet } from "./ManualImportSheet";
export { OpenJobListingButton } from "./OpenJobListingButton";
export { PipelineProgress } from "./PipelineProgress";
export { ReadyPanel } from "./ReadyPanel";
export { ScoreIndicator } from "./ScoreIndicator";