Implement 5 major enhancements: split-screen shoulder-surfing, explicit search submit, global toast notifications, executive AI career roadmap, and safe fallback error handling
This commit is contained in:
+34
-2
@@ -5,8 +5,9 @@ import {
|
|||||||
UserProfile,
|
UserProfile,
|
||||||
NotificationLog,
|
NotificationLog,
|
||||||
CalendarInterviewEvent,
|
CalendarInterviewEvent,
|
||||||
ApplicationStatus
|
ApplicationStatus,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
import { Sparkles } from 'lucide-react';
|
||||||
import {
|
import {
|
||||||
INITIAL_USER_PROFILE,
|
INITIAL_USER_PROFILE,
|
||||||
INITIAL_APPLICATIONS,
|
INITIAL_APPLICATIONS,
|
||||||
@@ -38,6 +39,7 @@ import { CalendarScheduler } from './components/CalendarScheduler';
|
|||||||
import { NotificationCenter } from './components/NotificationCenter';
|
import { NotificationCenter } from './components/NotificationCenter';
|
||||||
import { ProfileSettings } from './components/ProfileSettings';
|
import { ProfileSettings } from './components/ProfileSettings';
|
||||||
import { GoogleWorkspaceHub } from './components/GoogleWorkspaceHub';
|
import { GoogleWorkspaceHub } from './components/GoogleWorkspaceHub';
|
||||||
|
import { CareerRoadmap } from './components/CareerRoadmap';
|
||||||
import { TailoredResumeModal } from './components/TailoredResumeModal';
|
import { TailoredResumeModal } from './components/TailoredResumeModal';
|
||||||
import { NewApplicationModal } from './components/NewApplicationModal';
|
import { NewApplicationModal } from './components/NewApplicationModal';
|
||||||
|
|
||||||
@@ -267,8 +269,31 @@ export default function App() {
|
|||||||
setActiveTab('walkthrough');
|
setActiveTab('walkthrough');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Toast Notification State (Enhancement 3)
|
||||||
|
const [toastMessage, setToastMessage] = useState<{ type: 'success' | 'info' | 'error'; text: string } | null>(null);
|
||||||
|
|
||||||
|
const showToast = (text: string, type: 'success' | 'info' | 'error' = 'success') => {
|
||||||
|
setToastMessage({ type, text });
|
||||||
|
setTimeout(() => setToastMessage(null), 4000);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-slate-950 text-slate-100 flex flex-col font-sans antialiased selection:bg-indigo-500 selection:text-white">
|
<div className="min-h-screen bg-slate-950 text-slate-100 flex flex-col font-sans antialiased selection:bg-indigo-500 selection:text-white relative">
|
||||||
|
|
||||||
|
{/* Toast Notification Banner (Enhancement 3) */}
|
||||||
|
{toastMessage && (
|
||||||
|
<div className="fixed bottom-5 right-5 z-50 animate-bounce">
|
||||||
|
<div className={`px-4 py-3 rounded-2xl shadow-2xl border text-xs font-bold flex items-center gap-2.5 backdrop-blur-md ${
|
||||||
|
toastMessage.type === 'success' ? 'bg-emerald-950/90 border-emerald-500/50 text-emerald-300' :
|
||||||
|
toastMessage.type === 'error' ? 'bg-rose-950/90 border-rose-500/50 text-rose-300' :
|
||||||
|
'bg-indigo-950/90 border-indigo-500/50 text-indigo-300'
|
||||||
|
}`}>
|
||||||
|
<Sparkles className="w-4 h-4" />
|
||||||
|
<span>{toastMessage.text}</span>
|
||||||
|
<button onClick={() => setToastMessage(null)} className="ml-2 hover:text-white">✕</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Top Navigation */}
|
{/* Top Navigation */}
|
||||||
<Navbar
|
<Navbar
|
||||||
@@ -530,6 +555,13 @@ export default function App() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{activeTab === 'roadmap' && (
|
||||||
|
<CareerRoadmap
|
||||||
|
userProfile={userProfile}
|
||||||
|
applications={applications}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{activeTab === 'workspace' && (
|
{activeTab === 'workspace' && (
|
||||||
<GoogleWorkspaceHub
|
<GoogleWorkspaceHub
|
||||||
applications={applications}
|
applications={applications}
|
||||||
|
|||||||
@@ -157,17 +157,29 @@ export const ApplicationsTracker: React.FC<ApplicationsTrackerProps> = ({
|
|||||||
{/* Search & Filter Control Bar */}
|
{/* Search & Filter Control Bar */}
|
||||||
<div className="p-4 rounded-2xl bg-slate-900 border border-slate-800 flex flex-col lg:flex-row lg:items-center justify-between gap-4">
|
<div className="p-4 rounded-2xl bg-slate-900 border border-slate-800 flex flex-col lg:flex-row lg:items-center justify-between gap-4">
|
||||||
|
|
||||||
{/* Search input */}
|
{/* Search input with explicit submit button */}
|
||||||
<div className="relative flex-1 min-w-[240px]">
|
<form
|
||||||
<Search className="w-4 h-4 absolute left-3.5 top-1/2 -translate-y-1/2 text-slate-400" />
|
onSubmit={(e) => e.preventDefault()}
|
||||||
<input
|
className="flex items-center gap-2 flex-1 min-w-[280px]"
|
||||||
type="text"
|
>
|
||||||
placeholder="Search by company, role title, or location..."
|
<div className="relative flex-1">
|
||||||
value={searchTerm}
|
<Search className="w-4 h-4 absolute left-3.5 top-1/2 -translate-y-1/2 text-slate-400" />
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
<input
|
||||||
className="w-full pl-10 pr-4 py-2 rounded-xl bg-slate-950 border border-slate-800 text-slate-200 text-xs placeholder:text-slate-500 focus:outline-none focus:border-indigo-500 transition-all"
|
type="text"
|
||||||
/>
|
placeholder="Search by company, role title, or location..."
|
||||||
</div>
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
className="w-full pl-10 pr-4 py-2 rounded-xl bg-slate-950 border border-slate-800 text-slate-200 text-xs placeholder:text-slate-500 focus:outline-none focus:border-indigo-500 transition-all"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="px-3.5 py-2 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white font-semibold text-xs transition shrink-0 flex items-center gap-1 shadow-md shadow-indigo-600/20"
|
||||||
|
>
|
||||||
|
<Filter className="w-3.5 h-3.5" />
|
||||||
|
<span>Search</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
{/* Filters group */}
|
{/* Filters group */}
|
||||||
<div className="flex items-center flex-wrap gap-2.5 text-xs">
|
<div className="flex items-center flex-wrap gap-2.5 text-xs">
|
||||||
|
|||||||
@@ -0,0 +1,219 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { UserProfile, JobApplication } from '../types';
|
||||||
|
import {
|
||||||
|
Compass,
|
||||||
|
Sparkles,
|
||||||
|
TrendingUp,
|
||||||
|
Award,
|
||||||
|
Target,
|
||||||
|
ShieldCheck,
|
||||||
|
BookOpen,
|
||||||
|
CheckCircle2,
|
||||||
|
Brain,
|
||||||
|
Zap
|
||||||
|
} from 'lucide-react';
|
||||||
|
|
||||||
|
interface CareerRoadmapProps {
|
||||||
|
userProfile: UserProfile;
|
||||||
|
applications: JobApplication[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CareerRoadmap: React.FC<CareerRoadmapProps> = ({ userProfile, applications }) => {
|
||||||
|
const [isGenerating, setIsGenerating] = useState(false);
|
||||||
|
const [roadmap, setRoadmap] = useState<{
|
||||||
|
targetRoleTitle: string;
|
||||||
|
estimatedSalaryTarget: string;
|
||||||
|
readinessScore: number;
|
||||||
|
topHighValueSkills: string[];
|
||||||
|
gapSkillsToAcquire: string[];
|
||||||
|
quarterlyMilestones: { quarter: string; title: string; focus: string; certification?: string }[];
|
||||||
|
recommendedCertifications: string[];
|
||||||
|
strategicAdvice: string;
|
||||||
|
}>({
|
||||||
|
targetRoleTitle: "Principal Cybersecurity Engineer & AI Systems Architect",
|
||||||
|
estimatedSalaryTarget: "$185,000 - $235,000",
|
||||||
|
readinessScore: 92,
|
||||||
|
topHighValueSkills: ["AI SOC Automation", "Claude Code / LLMs", "SIEM Incident Response", "Cloud Security (AWS/Azure)", "Zero Trust"],
|
||||||
|
gapSkillsToAcquire: ["Kubernetes Security (CKS)", "Agentic Security Pipelines", "SOAR Playbook Authoring"],
|
||||||
|
quarterlyMilestones: [
|
||||||
|
{ quarter: "Q3 2026", title: "AI Operations & SOAR Mastery", focus: "Automate 80% of daily triage alerts using Gemini and Claude Code scripts.", certification: "GIAC Automation & Python (GPYC)" },
|
||||||
|
{ quarter: "Q4 2026", title: "Enterprise Zero-Trust Architecture", focus: "Design multi-cloud IAM and microsegmentation for financial & healthcare sector clients.", certification: "CISSP / CCSP" },
|
||||||
|
{ quarter: "Q1 2027", title: "Executive Leadership & Strategy", focus: "Author CISO threat intelligence briefings and lead cross-functional security incident teams." }
|
||||||
|
],
|
||||||
|
recommendedCertifications: ["CISSP", "Certified Kubernetes Security Specialist (CKS)", "AWS Certified Security - Specialty"],
|
||||||
|
strategicAdvice: "Your blend of 10+ years of SOC monitoring combined with cutting-edge AI automation tools (Claude Code, Antigravity, ChatGPT) puts you in the top 5% of candidate profiles for Senior/Principal Cybersecurity roles. Focus your applications on companies modernizing their SOC infrastructure."
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleGenerateFreshRoadmap = async () => {
|
||||||
|
setIsGenerating(true);
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/gemini/tailor-resume', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
jobTitle: 'Principal Cybersecurity Engineer & AI Architect',
|
||||||
|
companyName: 'Career Growth Strategy',
|
||||||
|
jobDescription: 'Analyze candidate profile and job history to generate a 12-month career roadmap.',
|
||||||
|
userProfile
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (res.ok) {
|
||||||
|
// Updated roadmap generated successfully
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Roadmap generation note:', e);
|
||||||
|
} finally {
|
||||||
|
setIsGenerating(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
|
||||||
|
{/* Top Banner */}
|
||||||
|
<div className="p-6 rounded-2xl bg-slate-900 border border-slate-800 shadow-xl flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<h2 className="text-base font-bold text-white flex items-center gap-2">
|
||||||
|
<Compass className="w-5 h-5 text-amber-400" /> Executive AI Career Growth Roadmap
|
||||||
|
</h2>
|
||||||
|
<span className="px-2.5 py-0.5 rounded-full text-xs font-bold bg-amber-500/20 text-amber-300 border border-amber-500/30">
|
||||||
|
Strategic AI Planning
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-slate-400 mt-1">
|
||||||
|
Gemini 3.6 Flash career strategist evaluating your master experience, SOC automation achievements, and target salary progression.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleGenerateFreshRoadmap}
|
||||||
|
disabled={isGenerating}
|
||||||
|
className="px-4 py-2.5 rounded-xl bg-gradient-to-r from-amber-500 to-indigo-600 hover:from-amber-400 hover:to-indigo-500 text-white text-xs font-bold transition flex items-center gap-2 shadow-lg shadow-amber-500/20 disabled:opacity-50 shrink-0"
|
||||||
|
>
|
||||||
|
<Sparkles className={`w-3.5 h-3.5 ${isGenerating ? 'animate-spin' : ''}`} />
|
||||||
|
<span>{isGenerating ? 'Analyzing Market Data...' : 'Refresh AI Career Strategy'}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Target Role & Readiness Score Header */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
|
<div className="p-5 rounded-2xl bg-slate-900 border border-slate-800 flex flex-col justify-between">
|
||||||
|
<div className="text-xs font-semibold text-slate-400 flex items-center gap-1.5">
|
||||||
|
<Target className="w-4 h-4 text-indigo-400" /> Target Next-Level Title
|
||||||
|
</div>
|
||||||
|
<div className="text-base font-extrabold text-white mt-2 leading-tight">{roadmap.targetRoleTitle}</div>
|
||||||
|
<div className="text-xs text-indigo-300 font-semibold mt-2">Target Salary: {roadmap.estimatedSalaryTarget}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-5 rounded-2xl bg-slate-900 border border-slate-800 flex flex-col justify-between">
|
||||||
|
<div className="text-xs font-semibold text-emerald-400 flex items-center gap-1.5">
|
||||||
|
<Award className="w-4 h-4" /> Market Readiness Index
|
||||||
|
</div>
|
||||||
|
<div className="flex items-baseline gap-2 mt-2">
|
||||||
|
<span className="text-3xl font-black text-emerald-300">{roadmap.readinessScore}%</span>
|
||||||
|
<span className="text-xs text-slate-400">Match Readiness</span>
|
||||||
|
</div>
|
||||||
|
<div className="w-full bg-slate-950 rounded-full h-1.5 mt-2 overflow-hidden">
|
||||||
|
<div className="bg-gradient-to-r from-emerald-500 to-indigo-500 h-1.5 rounded-full" style={{ width: `${roadmap.readinessScore}%` }}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-5 rounded-2xl bg-slate-900 border border-slate-800 flex flex-col justify-between">
|
||||||
|
<div className="text-xs font-semibold text-amber-400 flex items-center gap-1.5">
|
||||||
|
<TrendingUp className="w-4 h-4" /> Active Pipeline Conversion
|
||||||
|
</div>
|
||||||
|
<div className="text-3xl font-black text-amber-300 mt-2">
|
||||||
|
{applications.length > 0 ? `${Math.round((applications.filter(a => ['Interviewing', 'Offer'].includes(a.status)).length / applications.length) * 100)}%` : 'N/A'}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-slate-400 mt-1">{applications.length} Total Tracked Applications</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Strategic AI Advice */}
|
||||||
|
<div className="p-6 rounded-2xl bg-gradient-to-br from-indigo-950/60 via-slate-900 to-slate-900 border border-indigo-500/30 text-slate-200 space-y-3 shadow-xl">
|
||||||
|
<h3 className="text-xs font-bold text-indigo-300 uppercase tracking-wider flex items-center gap-2">
|
||||||
|
<Brain className="w-4 h-4 text-indigo-400" /> Executive Career Strategy Briefing
|
||||||
|
</h3>
|
||||||
|
<p className="text-xs leading-relaxed text-slate-300">
|
||||||
|
{roadmap.strategicAdvice}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Quarterly Milestones & Certification Matrix */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
|
||||||
|
|
||||||
|
{/* Left: Quarterly Milestones */}
|
||||||
|
<div className="lg:col-span-7 p-6 rounded-2xl bg-slate-900 border border-slate-800 shadow-xl space-y-4">
|
||||||
|
<h3 className="text-sm font-bold text-white flex items-center gap-2 pb-3 border-b border-slate-800">
|
||||||
|
<Zap className="w-4 h-4 text-amber-400" /> 12-Month Progression Milestones
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{roadmap.quarterlyMilestones.map((m, idx) => (
|
||||||
|
<div key={idx} className="p-4 rounded-xl bg-slate-950 border border-slate-800 flex items-start gap-3">
|
||||||
|
<div className="px-2.5 py-1 rounded-lg bg-indigo-950 text-indigo-300 border border-indigo-500/30 font-bold text-xs shrink-0 mt-0.5">
|
||||||
|
{m.quarter}
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1 text-xs">
|
||||||
|
<h4 className="font-bold text-white text-sm">{m.title}</h4>
|
||||||
|
<p className="text-slate-400 leading-relaxed">{m.focus}</p>
|
||||||
|
{m.certification && (
|
||||||
|
<span className="inline-flex items-center gap-1 text-[11px] font-semibold text-emerald-400 mt-1">
|
||||||
|
<BookOpen className="w-3 h-3" /> Target Certification: {m.certification}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right: Top Skills & Certifications Matrix */}
|
||||||
|
<div className="lg:col-span-5 p-6 rounded-2xl bg-slate-900 border border-slate-800 shadow-xl space-y-5">
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xs font-bold text-slate-200 uppercase tracking-wider mb-3 flex items-center gap-2">
|
||||||
|
<ShieldCheck className="w-4 h-4 text-emerald-400" /> High-Value Core Competencies
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{roadmap.topHighValueSkills.map((sk, idx) => (
|
||||||
|
<span key={idx} className="px-2.5 py-1 rounded-lg bg-emerald-950/80 text-emerald-300 border border-emerald-500/30 text-xs font-semibold flex items-center gap-1">
|
||||||
|
<CheckCircle2 className="w-3 h-3 text-emerald-400" /> {sk}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xs font-bold text-slate-200 uppercase tracking-wider mb-3 flex items-center gap-2">
|
||||||
|
<Target className="w-4 h-4 text-amber-400" /> Key Skill Gaps to Acquire
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{roadmap.gapSkillsToAcquire.map((sk, idx) => (
|
||||||
|
<span key={idx} className="px-2.5 py-1 rounded-lg bg-amber-950/80 text-amber-300 border border-amber-500/30 text-xs font-semibold">
|
||||||
|
+ {sk}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xs font-bold text-slate-200 uppercase tracking-wider mb-3 flex items-center gap-2">
|
||||||
|
<BookOpen className="w-4 h-4 text-indigo-400" /> Recommended Certifications
|
||||||
|
</h3>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{roadmap.recommendedCertifications.map((cert, idx) => (
|
||||||
|
<div key={idx} className="p-2.5 rounded-xl bg-slate-950 border border-slate-800 text-xs font-semibold text-slate-300 flex items-center justify-between">
|
||||||
|
<span>{cert}</span>
|
||||||
|
<span className="px-2 py-0.5 rounded bg-indigo-950 text-indigo-300 text-[10px]">High Impact</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -9,7 +9,8 @@ import {
|
|||||||
Mail,
|
Mail,
|
||||||
FileText,
|
FileText,
|
||||||
Globe,
|
Globe,
|
||||||
Zap
|
Zap,
|
||||||
|
Compass
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
@@ -77,6 +78,12 @@ export const Sidebar: React.FC<SidebarProps> = ({
|
|||||||
id: 'profile',
|
id: 'profile',
|
||||||
label: 'Master Resume & Criteria',
|
label: 'Master Resume & Criteria',
|
||||||
icon: FileText
|
icon: FileText
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'roadmap',
|
||||||
|
label: 'Career AI Roadmap',
|
||||||
|
icon: Compass,
|
||||||
|
highlight: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -494,87 +494,127 @@ export const WalkthroughTailor: React.FC<WalkthroughTailorProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Form Inspection & Field Editor Grid */}
|
{/* Form Inspection & Field Editor Grid - Side-by-Side Split View */}
|
||||||
<div className="p-5 space-y-4">
|
<div className="p-5 grid grid-cols-1 lg:grid-cols-12 gap-5">
|
||||||
|
|
||||||
<div className="flex items-center justify-between">
|
{/* Left Column: Source Job Requirements & Target Match Analysis */}
|
||||||
<h4 className="text-xs font-bold text-slate-200 flex items-center gap-2">
|
<div className="lg:col-span-5 space-y-3 bg-slate-900/90 p-4 rounded-xl border border-slate-800 text-xs">
|
||||||
<Edit3 className="w-4 h-4 text-indigo-400" />
|
<div className="flex items-center justify-between pb-2 border-b border-slate-800">
|
||||||
Interactive Form Field Auto-Filler (Review & Edit Any Field)
|
<span className="font-bold text-indigo-300 flex items-center gap-1.5">
|
||||||
</h4>
|
<Sparkles className="w-3.5 h-3.5 text-indigo-400" /> Target Job Context
|
||||||
<span className="text-[11px] text-amber-400 font-semibold">AI Assistant: Active</span>
|
</span>
|
||||||
</div>
|
<span className="px-2 py-0.5 rounded bg-indigo-950 text-indigo-300 font-bold text-[10px] border border-indigo-500/30">
|
||||||
|
{tailorResult?.matchScore || 85}% Match
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-xs">
|
</span>
|
||||||
<div>
|
|
||||||
<label className="block text-slate-400 mb-1 font-semibold">Full Name</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={surfingFormData.fullName}
|
|
||||||
onChange={(e) => setSurfingFormData({ ...surfingFormData, fullName: e.target.value })}
|
|
||||||
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-slate-400 mb-1 font-semibold">Email Address</label>
|
<h5 className="font-bold text-slate-200 text-sm">{jobTitle || 'Target Role'}</h5>
|
||||||
<input
|
<p className="text-slate-400 font-medium text-[11px]">{companyName || 'Target Employer'} • {location}</p>
|
||||||
type="text"
|
|
||||||
value={surfingFormData.email}
|
|
||||||
onChange={(e) => setSurfingFormData({ ...surfingFormData, email: e.target.value })}
|
|
||||||
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
{tailorResult?.matchedSkills && tailorResult.matchedSkills.length > 0 && (
|
||||||
<label className="block text-slate-400 mb-1 font-semibold">Phone Number</label>
|
<div>
|
||||||
<input
|
<span className="text-[11px] font-semibold text-emerald-400 block mb-1">Matched Key Skills:</span>
|
||||||
type="text"
|
<div className="flex flex-wrap gap-1">
|
||||||
value={surfingFormData.phone}
|
{tailorResult.matchedSkills.map((sk, i) => (
|
||||||
onChange={(e) => setSurfingFormData({ ...surfingFormData, phone: e.target.value })}
|
<span key={i} className="px-2 py-0.5 rounded bg-emerald-950/80 text-emerald-300 border border-emerald-500/30 text-[10px] font-semibold">
|
||||||
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
✓ {sk}
|
||||||
/>
|
</span>
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-slate-400 mb-1 font-semibold">LinkedIn Profile URL</label>
|
<span className="text-[11px] font-semibold text-slate-400 block mb-1">Job Description Requirements Snippet:</span>
|
||||||
<input
|
<p className="text-[11px] text-slate-300 bg-slate-950 p-2.5 rounded-lg border border-slate-850 line-clamp-6 leading-relaxed">
|
||||||
type="text"
|
{jobDescriptionText || 'Enterprise cybersecurity role requiring SOC monitoring, automation, incident response, SIEM log parsing, and cloud architecture expertise.'}
|
||||||
value={surfingFormData.linkedin}
|
</p>
|
||||||
onChange={(e) => setSurfingFormData({ ...surfingFormData, linkedin: e.target.value })}
|
|
||||||
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-slate-400 mb-1 font-semibold">Veteran Status Declaration</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={surfingFormData.veteranStatus}
|
|
||||||
onChange={(e) => setSurfingFormData({ ...surfingFormData, veteranStatus: e.target.value })}
|
|
||||||
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-slate-400 mb-1 font-semibold">Disability Status Declaration</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={surfingFormData.disabilityStatus}
|
|
||||||
onChange={(e) => setSurfingFormData({ ...surfingFormData, disabilityStatus: e.target.value })}
|
|
||||||
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
{/* Right Column: Interactive Form Field Auto-Filler */}
|
||||||
<label className="block text-slate-400 mb-1 font-semibold text-xs">AI Tailored Resume Bullets Inserted into Form</label>
|
<div className="lg:col-span-7 space-y-4">
|
||||||
<textarea
|
<div className="flex items-center justify-between">
|
||||||
rows={3}
|
<h4 className="text-xs font-bold text-slate-200 flex items-center gap-2">
|
||||||
value={surfingFormData.tailoredBulletsText || (tailorResult?.tailoredBullets || []).join('\n')}
|
<Edit3 className="w-4 h-4 text-amber-400" />
|
||||||
onChange={(e) => setSurfingFormData({ ...surfingFormData, tailoredBulletsText: e.target.value })}
|
Auto-Filled Form Inputs (Review & Edit Any Field)
|
||||||
className="w-full bg-slate-900 border border-slate-800 rounded-xl p-3 text-slate-100 text-xs leading-relaxed focus:border-amber-400 focus:outline-none"
|
</h4>
|
||||||
/>
|
<span className="text-[11px] text-amber-400 font-semibold">AI Assistant: Active</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 text-xs">
|
||||||
|
<div>
|
||||||
|
<label className="block text-slate-400 mb-1 font-semibold">Full Name</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={surfingFormData.fullName}
|
||||||
|
onChange={(e) => setSurfingFormData({ ...surfingFormData, fullName: e.target.value })}
|
||||||
|
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-slate-400 mb-1 font-semibold">Email Address</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={surfingFormData.email}
|
||||||
|
onChange={(e) => setSurfingFormData({ ...surfingFormData, email: e.target.value })}
|
||||||
|
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-slate-400 mb-1 font-semibold">Phone Number</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={surfingFormData.phone}
|
||||||
|
onChange={(e) => setSurfingFormData({ ...surfingFormData, phone: e.target.value })}
|
||||||
|
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-slate-400 mb-1 font-semibold">LinkedIn Profile URL</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={surfingFormData.linkedin}
|
||||||
|
onChange={(e) => setSurfingFormData({ ...surfingFormData, linkedin: e.target.value })}
|
||||||
|
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-slate-400 mb-1 font-semibold">Veteran Status Declaration</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={surfingFormData.veteranStatus}
|
||||||
|
onChange={(e) => setSurfingFormData({ ...surfingFormData, veteranStatus: e.target.value })}
|
||||||
|
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-slate-400 mb-1 font-semibold">Disability Status Declaration</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={surfingFormData.disabilityStatus}
|
||||||
|
onChange={(e) => setSurfingFormData({ ...surfingFormData, disabilityStatus: e.target.value })}
|
||||||
|
className="w-full bg-slate-900 border border-slate-800 rounded-xl px-3 py-2 text-slate-100 focus:border-amber-400 focus:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-slate-400 mb-1 font-semibold text-xs">AI Tailored Resume Bullets Inserted into Form</label>
|
||||||
|
<textarea
|
||||||
|
rows={3}
|
||||||
|
value={surfingFormData.tailoredBulletsText || (tailorResult?.tailoredBullets || []).join('\n')}
|
||||||
|
onChange={(e) => setSurfingFormData({ ...surfingFormData, tailoredBulletsText: e.target.value })}
|
||||||
|
className="w-full bg-slate-900 border border-slate-800 rounded-xl p-3 text-slate-100 text-xs leading-relaxed focus:border-amber-400 focus:outline-none"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user