Spaces:
Running
Running
| "use client"; | |
| import { ScoreBar } from "@/components/ScoreBar"; | |
| import { AccessibilityBadge } from "@/components/AccessibilityBadge"; | |
| import { VisaSponsorshipNote } from "@/components/VisaSponsorshipNote"; | |
| import { isScoreResult, type ScoreResult } from "@/lib/types"; | |
| function verdictStyle(verdict: ScoreResult["verdict"]): { color: string; bg: string } { | |
| if (verdict === "Strong Match") return { color: "#1D9E75", bg: "#E1F5EE" }; | |
| if (verdict === "Possible") return { color: "#BA7517", bg: "#FAEEDA" }; | |
| return { color: "#E24B4A", bg: "#FCEBEB" }; | |
| } | |
| function safeBarScore(n: unknown): number { | |
| return typeof n === "number" && Number.isFinite(n) ? n : 0; | |
| } | |
| /** Two-stage session + profile bars (above standard dimensions). */ | |
| export function TwoStageSessionProfileScoreRows({ result }: { result: ScoreResult }) { | |
| if (!result.session_fit || !result.profile_fit) return null; | |
| return ( | |
| <> | |
| <div> | |
| <div | |
| style={{ | |
| display: "flex", | |
| justifyContent: "space-between", | |
| marginBottom: 4, | |
| gap: 8, | |
| }} | |
| > | |
| <span style={{ fontSize: 12, color: "var(--muted, #666)" }}>Search fit</span> | |
| </div> | |
| <ScoreBar | |
| score={safeBarScore(result.session_fit.score)} | |
| reason={typeof result.session_fit.reason === "string" ? result.session_fit.reason : undefined} | |
| /> | |
| </div> | |
| <div> | |
| <div | |
| style={{ | |
| display: "flex", | |
| justifyContent: "space-between", | |
| marginBottom: 4, | |
| gap: 8, | |
| }} | |
| > | |
| <span style={{ fontSize: 12, color: "var(--muted, #666)" }}>Profile fit</span> | |
| </div> | |
| <ScoreBar | |
| score={safeBarScore(result.profile_fit.score)} | |
| reason={typeof result.profile_fit.reason === "string" ? result.profile_fit.reason : undefined} | |
| /> | |
| </div> | |
| </> | |
| ); | |
| } | |
| export function BatchStyleScoreBreakdown({ result }: { result: ScoreResult }) { | |
| if (!isScoreResult(result)) { | |
| return ( | |
| <p className="muted" style={{ marginTop: 8, fontSize: 12 }}> | |
| Stored score is incomplete. | |
| </p> | |
| ); | |
| } | |
| const verdict = | |
| result.verdict === "Strong Match" || result.verdict === "Possible" || result.verdict === "Skip" | |
| ? result.verdict | |
| : "Skip"; | |
| const { color, bg } = verdictStyle(verdict); | |
| const dims = [ | |
| { label: "Role & skill fit", key: "role_fit" as const }, | |
| { label: "Global remote", key: "global_remote" as const }, | |
| { label: "Async culture", key: "culture_async" as const }, | |
| { label: "Contractor friendly", key: "contractor_friendly" as const }, | |
| ]; | |
| return ( | |
| <div style={{ display: "flex", flexDirection: "column", gap: 10, marginTop: 8 }}> | |
| <div | |
| style={{ | |
| display: "flex", | |
| alignItems: "center", | |
| gap: 10, | |
| padding: "10px 12px", | |
| background: bg, | |
| borderRadius: 10, | |
| border: `0.5px solid ${color}55`, | |
| }} | |
| > | |
| <span style={{ fontSize: 14, fontWeight: 600, color }}>{verdict}</span> | |
| <span style={{ fontSize: 12, color: "#555", flex: 1, lineHeight: 1.35 }}> | |
| {typeof result.verdict_reason === "string" ? result.verdict_reason : ""} | |
| </span> | |
| </div> | |
| <AccessibilityBadge assessment={result.accessibility} /> | |
| <VisaSponsorshipNote assessment={result.accessibility} /> | |
| <div | |
| style={{ | |
| background: "var(--surface, #fff)", | |
| border: "0.5px solid var(--hairline, #e0e0e0)", | |
| borderRadius: 10, | |
| padding: "10px 12px", | |
| display: "flex", | |
| flexDirection: "column", | |
| gap: 12, | |
| }} | |
| > | |
| <TwoStageSessionProfileScoreRows result={result} /> | |
| {dims.map((d) => { | |
| const dim = result[d.key]; | |
| return ( | |
| <div key={d.key}> | |
| <div | |
| style={{ | |
| display: "flex", | |
| justifyContent: "space-between", | |
| marginBottom: 4, | |
| gap: 8, | |
| }} | |
| > | |
| <span style={{ fontSize: 12, color: "var(--muted, #666)" }}>{d.label}</span> | |
| </div> | |
| <ScoreBar | |
| score={safeBarScore(dim?.score)} | |
| reason={typeof dim?.reason === "string" ? dim.reason : undefined} | |
| /> | |
| </div> | |
| ); | |
| })} | |
| {result.semantic_score && | |
| typeof result.semantic_score === "object" && | |
| result.semantic_score !== null ? ( | |
| <div> | |
| <div | |
| style={{ | |
| display: "flex", | |
| justifyContent: "space-between", | |
| marginBottom: 4, | |
| }} | |
| > | |
| <span style={{ fontSize: 12, color: "var(--muted, #666)" }}>Semantic match</span> | |
| </div> | |
| <ScoreBar | |
| score={safeBarScore(result.semantic_score.score)} | |
| reason={ | |
| typeof result.semantic_score.reason === "string" | |
| ? result.semantic_score.reason | |
| : undefined | |
| } | |
| /> | |
| </div> | |
| ) : null} | |
| </div> | |
| </div> | |
| ); | |
| } | |