Jobseeker Dashboard Enhancement & Boost CV Feature
Overview
This document covers three interconnected changes to the jobseeker experience:
- Dashboard Enhancement — Full rewrite of the jobseeker dashboard with KPIs, pipeline visualization, charts, and quality metrics
- Boost CV Feature — When a job's match score is below 70%, the "Apply" button is replaced with "Boost My CV" across all surfaces
- Boost CV Edit Context — Clicking "Boost My CV" navigates directly to the CV edit page with job-specific recommendations displayed
1. Dashboard Enhancement
File: components/reusable/dashboard/jobseeker/JobSeekerDashboardSlim.tsx
The dashboard was rewritten from a minimal 3-section layout into a comprehensive 7-section dashboard:
| Section | Description |
|---|---|
| Profile Completion | Enhanced card with circular progress, quick-win field suggestions, and next group suggestion |
| KPI Row | 4 colored stat cards using Kpi from ChartBits: Applications, Avg Match %, Profile Views, Recommended Jobs |
| Application Pipeline | Horizontal funnel: Submitted → In Review → Interview → Approved, with counts and percentages |
| Charts Row | Weekly Recommendations Trend (AreaChart) + Match Score Distribution (BarChart) |
| Quality Metrics | 5 circular progress indicators: Profile Completion, Response Rate, Offer Rate, In Review %, Interview % |
| Recommended Jobs | Existing RecommendedGrid component with job cards |
| Upcoming Deadlines | Table of jobs with approaching due dates |
Key Design Decisions
- Reuses
ChartBitsutilities (Kpi,DefaultTooltip,COLORS,GRADIENTS) from the company dashboard for visual consistency - All data comes from the existing
GET_JOBSEEKER_DASHBOARDquery — no new GraphQL queries needed - Derived metrics (avg match, pipeline rates, trend data, match distribution) computed via
useMemo - Uses Recharts (
AreaChart,BarChart) for data visualization
File: app/jobseeker/dashboard/page.tsx
- Added personalized hero with time-of-day greeting (Good Morning/Afternoon/Evening)
- Improved loading skeleton to match new layout
2. Boost CV Feature (Match Score < 70%)
Threshold Logic
When a job's match score is below 70%, the user should improve their CV instead of applying directly. The "Apply" button is replaced with "Boost My CV" across three surfaces.
Affected Surfaces
A. Dashboard Cards (components/reusable/jobs/JobSeekerCard.tsx)
- When
matchScore < 70and the card is on an authenticated page (not landing), the Apply button is replaced with a "Boost Your CV" button - Clicking it opens a modal showing:
- Match percentage indicator
- Parsed recommendations from
matchDetails - Missing must-have skills
- The modal's "Boost My CV" button navigates to the CV edit page with boost context
B. Jobs Listing Page (app/jobseeker/jobs/page.tsx)
- Uses the
TWResponsiveCarddeclarative card system isLowMatch: booleanflag is added toUiJobData(set whenmatchScore < 70)- Card config in
jobSeekerJobConfig.tsuses conditional visibility:{ key: "apply", hideIf: "hasApplied", requireAll: ["!isLowMatch"] }
{ key: "boostCv", showIf: "isLowMatch", requireAll: ["!hasApplied"] } boostCvaction registered inactionConfigs.tsxwithResumeIconand amber color
C. Job Detail Page (app/jobseeker/jobs/[jobId]/page.tsx + components/reusable/jobs/JobDetails.tsx)
JobDetailBodyacceptsmatchScoreprop- When
matchScore < 70(and not in withdraw mode), the bottom CTA shows "Boost My CV" (warning color) instead of "Apply Now" - The "Boost Your CV to Match This Role" section's button also triggers the boost navigation
- Match score qualifications fetched via
GET_USER_JOB_MATCH_SCORElazy query
Match Data Parsing
Recommendations and missing skills are parsed from the match score response:
matchScoreData.getUserJobMatchScore
├── qualifications (preferred) OR details.unified_report
│ ├── recommendations: string[]
│ └── component_scores[]
│ └── find(c => c.component_name === "skills")
│ └── analysis[]
│ └── filter(!matched && is_must_have)
│ └── map(s => s.job_skill_name)
3. Boost CV Edit Context
Problem
When a user clicks "Boost My CV", they should go directly to CV edit mode with the job-specific recommendations visible, so they know exactly what to improve.
Solution: sessionStorage + URL query param + lazy query
Flow
- Source page (job detail / listing / dashboard card) calls
setBoostCvContext()to store recommendations insessionStorage - Navigation goes to
/jobseeker/resume/edit/{activeCvId}?boost=true - CV edit page reads
?boost=true, loads context fromsessionStorage, displays a dismissible amber banner - If the source only had a
jobId(no detailed recommendations), the edit page fires a lazy query toGET_USER_JOB_MATCH_SCORE - Context is cleared on unmount — truly temporary
Utility: lib/utils/cv/boostCvContext.ts
type BoostCvSessionData = {
jobId: string
jobTitle?: string
recommendations: string[]
missingSkills: string[]
matchScore?: number
}
setBoostCvContext(data) // Store in sessionStorage
getBoostCvContext() // Read from sessionStorage (returns null if absent)
clearBoostCvContext() // Remove from sessionStorage
Source Page Changes
| File | Change |
|---|---|
app/jobseeker/jobs/[jobId]/page.tsx | handleBoostCv() stores full context (recommendations, missingSkills, jobTitle, matchScore), navigates to edit page |
components/reusable/jobs/JobDetails.tsx | New onBoostCv?: () => void prop; both Boost buttons delegate to parent handler |
components/reusable/jobs/JobSeekerCard.tsx | Modal's "Boost My CV" button stores context from parsed matchDetails, navigates to edit page |
app/jobseeker/jobs/page.tsx | onBoostCvClick stores minimal context (jobId, title, matchScore), navigates to edit page |
All sources fall back to /jobseeker/resume if user.activeCvId is not available (user needs to create/select a CV first).
CV Edit Page Changes (app/jobseeker/resume/edit/[cvId]/page.tsx)
- Reads
?boost=truefrom URL search params - Reads
BoostCvSessionDatafrom sessionStorage on mount - If
recommendationsarray is empty, firesGET_USER_JOB_MATCH_SCORElazy query using the storedjobId - Parses match details into
boostPointers(recommendations + missingSkills) viauseMemo - Renders a dismissible amber banner above the
ProfileForm:- Job title ("Boost your CV for: {title}")
- Recommendations (bulleted list)
- Missing skills (amber-bordered pills)
- Dismiss button (clears sessionStorage)
- Calls
clearBoostCvContext()on component unmount
Banner UI
┌──────────────────────────────────────────────────────┐
│ 📄 Boost your CV for: "Senior React Developer" [X] │
│ │
│ RECOMMENDATIONS │
│ • Add more detail to your React experience │
│ • Highlight TypeScript proficiency │
│ │
│ MISSING SKILLS │
│ [GraphQL] [Docker] [AWS] │
└──────────────────────────────────────────────────────┘
Styled with bg-amber-50 border-amber-200 to match the existing boost section in the job detail page.
File Index
| File | Role |
|---|---|
lib/utils/cv/boostCvContext.ts | sessionStorage utility for boost context |
components/reusable/jobs/JobDetails.tsx | Job detail body with onBoostCv prop |
components/reusable/jobs/JobSeekerCard.tsx | Dashboard/search job card with boost modal |
app/jobseeker/jobs/page.tsx | Jobs listing page with card system |
app/jobseeker/jobs/[jobId]/page.tsx | Job detail page with boost handlers |
app/jobseeker/resume/edit/[cvId]/page.tsx | CV edit page with boost banner |
app/jobseeker/dashboard/page.tsx | Dashboard page with hero |
components/reusable/dashboard/jobseeker/JobSeekerDashboardSlim.tsx | Dashboard component |
components/ux/TWResponsiveCard/cardBuilder/actions/actionConfigs.tsx | boostCv action config |
components/ux/TWResponsiveCard/cardBuilder/configs/jobSeekerJobConfig.ts | Conditional action visibility |