refactor(cv): remove abandoned profile builder
This commit is contained in:
+5
-3
@@ -2,12 +2,11 @@
|
|||||||
|
|
||||||
## Current
|
## Current
|
||||||
|
|
||||||
- [ ] Commit and deploy the centralized job-specific CV compatibility catalog; verify live release health.
|
- [ ] Complete authenticated production CV Builder editing/PDF smoke when a safe signed-in test session is available.
|
||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
- [ ] Complete authenticated production CV Builder editing/PDF smoke when a safe signed-in test session is available.
|
- [ ] No further repository-only CV work is known; resume from production findings if the authenticated smoke identifies a regression.
|
||||||
- [ ] Remove the two temporary Gitea credential-transfer files after explicit deletion confirmation.
|
|
||||||
|
|
||||||
## Completed
|
## Completed
|
||||||
|
|
||||||
@@ -26,6 +25,9 @@
|
|||||||
- [x] Deployed release 266 and verified public health plus the Career and CV Builder application routes.
|
- [x] Deployed release 266 and verified public health plus the Career and CV Builder application routes.
|
||||||
- [x] Audited CV TODOs and obsolete-code candidates; confirmed the remaining old renderer is an active job-specific compatibility path rather than dead Builder code.
|
- [x] Audited CV TODOs and obsolete-code candidates; confirmed the remaining old renderer is an active job-specific compatibility path rather than dead Builder code.
|
||||||
- [x] Centralized the compatibility path's template IDs, aliases, accents, chooser metadata and AI rewrite guidance while preserving saved IDs and HTML rendering.
|
- [x] Centralized the compatibility path's template IDs, aliases, accents, chooser metadata and AI rewrite guidance while preserving saved IDs and HTML rendering.
|
||||||
|
- [x] Deployed the centralized compatibility catalog as release 267 and verified live health plus both Career routes.
|
||||||
|
- [x] Permanently deleted and verified removal of both temporary Gitea credential-transfer files after explicit approval.
|
||||||
|
- [x] Removed the abandoned account-page CV builder/extraction types, controls and duplicate six-template registry; focused tests, TypeScript, the full frontend suite and production build pass.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
|
||||||
import { Accordion, AccordionDetails, AccordionSummary, Alert, Avatar, Box, Button, Chip, Dialog, DialogContent, DialogTitle, Divider, FormControl, IconButton, InputLabel, LinearProgress, MenuItem, Paper, Select, TextField, Typography } from "@mui/material";
|
import { Alert, Avatar, Box, Button, Chip, Divider, Paper, TextField, Typography } from "@mui/material";
|
||||||
|
|
||||||
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
|
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
||||||
import PhotoCameraOutlinedIcon from "@mui/icons-material/PhotoCameraOutlined";
|
import PhotoCameraOutlinedIcon from "@mui/icons-material/PhotoCameraOutlined";
|
||||||
import ZoomInOutlinedIcon from "@mui/icons-material/ZoomInOutlined";
|
|
||||||
|
|
||||||
import { api, getApiErrorMessage } from "../api";
|
import { api, getApiErrorMessage } from "../api";
|
||||||
import GoogleAuthCard from "../components/GoogleAuthCard";
|
import GoogleAuthCard from "../components/GoogleAuthCard";
|
||||||
@@ -16,97 +14,9 @@ import SessionsSettingsCard from "../components/SessionsSettingsCard";
|
|||||||
import CropImageDialog from "../components/CropImageDialog";
|
import CropImageDialog from "../components/CropImageDialog";
|
||||||
import { useToast } from "../toast";
|
import { useToast } from "../toast";
|
||||||
import { useI18n } from "../i18n/I18nProvider";
|
import { useI18n } from "../i18n/I18nProvider";
|
||||||
import {
|
import { parseStructuredCvJson } from "../profileCv";
|
||||||
emptyStructuredCv,
|
|
||||||
getStructuredCvFieldMetadata,
|
|
||||||
joinLines,
|
|
||||||
normalizeStructuredCv,
|
|
||||||
parseStructuredCvJson,
|
|
||||||
splitLines,
|
|
||||||
StructuredCvFieldMetadata,
|
|
||||||
StructuredCvProfile,
|
|
||||||
} from "../profileCv";
|
|
||||||
import { JobApplication } from "../types";
|
|
||||||
import { getUserScopedStorageKey } from "../auth";
|
import { getUserScopedStorageKey } from "../auth";
|
||||||
|
|
||||||
|
|
||||||
type CvSectionOption = "" | "Professional Summary" | "Core Skills" | "Experience Highlights" | "Selected Achievements" | "Projects";
|
|
||||||
type CvSectionStyle = "ats-minimal" | "harvard" | "auckland" | "edinburgh" | "monarch" | "fjord";
|
|
||||||
|
|
||||||
type CvBuilderTone = "Concise and direct" | "Executive and polished" | "Technical and detailed" | "Warm and people-focused";
|
|
||||||
type CvBuilderLanguage = "English" | "Norwegian" | "Spanish" | "French" | "German";
|
|
||||||
|
|
||||||
type ExtractionRun = {
|
|
||||||
id: number;
|
|
||||||
trigger: string;
|
|
||||||
status: string;
|
|
||||||
artifactFileName?: string;
|
|
||||||
startedAtUtc: string;
|
|
||||||
completedAtUtc?: string;
|
|
||||||
appliedAtUtc?: string;
|
|
||||||
parserVersion: string;
|
|
||||||
normalizerVersion: string;
|
|
||||||
llmPromptVersion: string;
|
|
||||||
errorMessage?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type QueuedCvRunResponse = {
|
|
||||||
queued: boolean;
|
|
||||||
extractionRunId: number;
|
|
||||||
status: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type JobListResponse = {
|
|
||||||
items: JobApplication[];
|
|
||||||
total: number;
|
|
||||||
page: number;
|
|
||||||
pageSize: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type RewriteTemplateOption = {
|
|
||||||
id: CvSectionStyle;
|
|
||||||
title: string;
|
|
||||||
eyebrow: string;
|
|
||||||
accent: string;
|
|
||||||
blurb: string;
|
|
||||||
sampleHeading: string;
|
|
||||||
sampleMeta: string;
|
|
||||||
sampleBullets: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
type CvBuilderPreview = {
|
|
||||||
templateId: CvSectionStyle;
|
|
||||||
html: string;
|
|
||||||
suggestedFileName: string;
|
|
||||||
fullText: string;
|
|
||||||
rewrittenText: string;
|
|
||||||
structuredCv: StructuredCvProfile;
|
|
||||||
sectionName?: string | null;
|
|
||||||
targetRole?: string | null;
|
|
||||||
jobApplicationId?: number | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
type PdfCarouselItem = {
|
|
||||||
templateId: CvSectionStyle;
|
|
||||||
title: string;
|
|
||||||
fileName: string;
|
|
||||||
pdfUrl?: string;
|
|
||||||
status: "loading" | "ready" | "error";
|
|
||||||
error?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type RewriteRequestPayload = {
|
|
||||||
sectionName: string | null;
|
|
||||||
style: CvSectionStyle;
|
|
||||||
templateId: CvSectionStyle;
|
|
||||||
targetRole: string | null;
|
|
||||||
jobApplicationId: number | null;
|
|
||||||
sourceText: string | null;
|
|
||||||
promptBackground: string | null;
|
|
||||||
tone: string | null;
|
|
||||||
language: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MeResponse = {
|
type MeResponse = {
|
||||||
provider?: "local" | "google" | "external";
|
provider?: "local" | "google" | "external";
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -131,70 +41,7 @@ type PendingEmailChange = {
|
|||||||
requestedAtUtc?: string | null;
|
requestedAtUtc?: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CV_UPLOAD_ACCEPT = ".pdf,.docx,.txt,.md,image/png,image/jpeg,image/webp,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,text/plain,text/markdown";
|
|
||||||
const AVATAR_UPLOAD_ACCEPT = "image/png,image/jpeg,image/webp";
|
const AVATAR_UPLOAD_ACCEPT = "image/png,image/jpeg,image/webp";
|
||||||
const REWRITE_TEMPLATES: RewriteTemplateOption[] = [
|
|
||||||
{
|
|
||||||
id: "ats-minimal",
|
|
||||||
title: "ATS Minimal",
|
|
||||||
eyebrow: "Scanner-friendly",
|
|
||||||
accent: "#0f172a",
|
|
||||||
blurb: "Compact, direct, and easy for screening systems to parse.",
|
|
||||||
sampleHeading: "Senior Backend Engineer",
|
|
||||||
sampleMeta: "Acme Systems · Oslo · 2021 - Present",
|
|
||||||
sampleBullets: ["Built API workflows with measurable delivery outcomes.", "Kept skills and achievements easy to scan."]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "harvard",
|
|
||||||
title: "Harvard",
|
|
||||||
eyebrow: "Traditional",
|
|
||||||
accent: "#7f1d1d",
|
|
||||||
blurb: "Formal hierarchy and restrained tone for conservative hiring flows.",
|
|
||||||
sampleHeading: "Professional Summary",
|
|
||||||
sampleMeta: "Clear structure · precise dates · credible language",
|
|
||||||
sampleBullets: ["Emphasizes polished summaries.", "Works well for broad professional roles."]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "auckland",
|
|
||||||
title: "Auckland",
|
|
||||||
eyebrow: "Modern sidebar",
|
|
||||||
accent: "#0f766e",
|
|
||||||
blurb: "Sharper highlights with a more contemporary, design-forward rhythm.",
|
|
||||||
sampleHeading: "Selected Impact",
|
|
||||||
sampleMeta: "Focused strengths · compact highlights",
|
|
||||||
sampleBullets: ["Pulls skills into stronger highlight clusters.", "Good when you want a fresher feel."]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "edinburgh",
|
|
||||||
title: "Edinburgh",
|
|
||||||
eyebrow: "Editorial",
|
|
||||||
accent: "#5b21b6",
|
|
||||||
blurb: "More personality and stronger section contrast without losing clarity.",
|
|
||||||
sampleHeading: "Experience Highlights",
|
|
||||||
sampleMeta: "Refined spacing · stronger visual voice",
|
|
||||||
sampleBullets: ["Useful when the CV should feel more distinctive.", "Still keeps wording grounded and factual."]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "monarch",
|
|
||||||
title: "Monarch",
|
|
||||||
eyebrow: "Executive",
|
|
||||||
accent: "#7c2d12",
|
|
||||||
blurb: "High-contrast presentation for leadership-heavy applications.",
|
|
||||||
sampleHeading: "Executive Profile",
|
|
||||||
sampleMeta: "Leadership clarity · refined hierarchy",
|
|
||||||
sampleBullets: ["Adds more top-level summary emphasis.", "Well suited to senior strategic roles."]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "fjord",
|
|
||||||
title: "Fjord",
|
|
||||||
eyebrow: "Technical",
|
|
||||||
accent: "#0f4c5c",
|
|
||||||
blurb: "Calm, high-density layout for engineering resumes and project-heavy CVs.",
|
|
||||||
sampleHeading: "Projects & Systems",
|
|
||||||
sampleMeta: "Technical depth · practical readability",
|
|
||||||
sampleBullets: ["Gives projects and skills more weight.", "Better for technical detail without chaos."]
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function initialsFrom(values: Array<string | undefined>) {
|
function initialsFrom(values: Array<string | undefined>) {
|
||||||
const joined = values.map((x) => (x ?? "").trim()).filter(Boolean);
|
const joined = values.map((x) => (x ?? "").trim()).filter(Boolean);
|
||||||
@@ -207,31 +54,6 @@ function initialsFrom(values: Array<string | undefined>) {
|
|||||||
return (joined[0][0] + joined[1][0]).toUpperCase();
|
return (joined[0][0] + joined[1][0]).toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
function confidenceTone(confidence?: number) {
|
|
||||||
if (typeof confidence !== "number") return { label: "Review", color: "default" as const };
|
|
||||||
if (confidence >= 0.8) return { label: `High ${Math.round(confidence * 100)}%`, color: "success" as const };
|
|
||||||
if (confidence >= 0.65) return { label: `Medium ${Math.round(confidence * 100)}%`, color: "warning" as const };
|
|
||||||
return { label: `Low ${Math.round(confidence * 100)}%`, color: "error" as const };
|
|
||||||
}
|
|
||||||
|
|
||||||
function FieldReviewNote({ metadata }: { metadata?: StructuredCvFieldMetadata }) {
|
|
||||||
if (!metadata) return null;
|
|
||||||
const tone = confidenceTone(metadata.confidence);
|
|
||||||
return (
|
|
||||||
<Box sx={{ display: "flex", gap: 0.75, flexWrap: "wrap", mt: 0.75, alignItems: "center" }}>
|
|
||||||
<Chip size="small" color={tone.color} variant={tone.color === "default" ? "outlined" : "filled"} label={tone.label} />
|
|
||||||
{metadata.method ? <Chip size="small" variant="outlined" label={metadata.method} /> : null}
|
|
||||||
{metadata.sourceBlockId ? <Chip size="small" variant="outlined" label={metadata.sourceBlockId} /> : null}
|
|
||||||
{metadata.reviewState ? <Chip size="small" variant="outlined" label={metadata.reviewState} /> : null}
|
|
||||||
{metadata.sourceSnippet ? (
|
|
||||||
<Typography variant="caption" sx={{ color: "text.secondary" }}>
|
|
||||||
{metadata.sourceSnippet}
|
|
||||||
</Typography>
|
|
||||||
) : null}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProfilePage backs /profile: account identity + security + preferences. The master career
|
// ProfilePage backs /profile: account identity + security + preferences. The master career
|
||||||
// profile lives in CareerProfilePage (/career). Split in Phase 2.2. Saves only identity fields
|
// profile lives in CareerProfilePage (/career). Split in Phase 2.2. Saves only identity fields
|
||||||
// (partial update), never the master profile.
|
// (partial update), never the master profile.
|
||||||
|
|||||||
Reference in New Issue
Block a user