Implement interactive Shoulder-Surfing Mode for live form fill review and manual overrides

This commit is contained in:
2026-07-22 19:52:22 -04:00
parent 9d6aa88f29
commit 7eb6390f8c
3 changed files with 204 additions and 4 deletions
+1 -1
View File
@@ -1 +1 @@
126644
128554
+22 -1
View File
@@ -174,6 +174,27 @@
}
},
"ai_job_portal_applications": {
"items": []
"items": [
{
"company": "Twilio: Principal Engineer",
"role": "Twilio: Principal Engineer",
"platform": "Greenhouse",
"location": "Remote US / Global",
"salaryRange": "$150,000 - $210,000",
"status": "Applied",
"matchScore": 85,
"appliedAt": "2026-07-22T23:52:07.115Z",
"jobUrl": "https://weworkremotely.com/remote-jobs/twilio-principal-engineer",
"jobDescription": "Remote software development opening.",
"autoApplied": true,
"timeline": [
{
"date": "7/22/2026",
"action": "Quick AI Auto-Applied from feed"
}
],
"id": "app_1784764327115_4a5x6"
}
]
}
}
+181 -2
View File
@@ -14,7 +14,13 @@ import {
Wand2,
Bot,
BrainCircuit,
ListCheck
ListCheck,
Eye,
Play,
Pause,
Edit3,
ExternalLink,
ShieldAlert
} from 'lucide-react';
interface WalkthroughTailorProps {
@@ -50,7 +56,21 @@ export const WalkthroughTailor: React.FC<WalkthroughTailorProps> = ({
insights: string;
} | null>(null);
const [copiedType, setCopiedType] = useState<'resume' | 'cover' | null>(null);
// Shoulder Surfing Mode State
const [isSurfingActive, setIsSurfingActive] = useState(false);
const [surfingStepIndex, setSurfingStepIndex] = useState(0);
const [isSurfingPaused, setIsSurfingPaused] = useState(false);
const [surfingFormData, setSurfingFormData] = useState({
fullName: userProfile.fullName || 'David Kifer',
email: userProfile.email || 'dkifer19@gmail.com',
phone: userProfile.phone || '(555) 019-2831',
linkedin: userProfile.linkedin || 'https://linkedin.com/in/david-kifer',
yearsExperience: '8+ Years',
workAuthorization: 'US Citizen / Authorized',
tailoredBulletsText: '',
customCoverLetterText: ''
});
// Step 1: Parse Job posting details using Gemini
const handleParsePosting = async () => {
@@ -254,6 +274,13 @@ export const WalkthroughTailor: React.FC<WalkthroughTailorProps> = ({
</div>
<div className="flex items-center gap-2">
<button
onClick={() => setIsSurfingActive(true)}
className="px-4 py-2.5 rounded-xl bg-gradient-to-r from-amber-500 to-amber-600 hover:from-amber-400 hover:to-amber-500 text-slate-950 font-bold text-xs shadow-lg shadow-amber-500/20 flex items-center gap-1.5 transition-all cursor-pointer"
>
<Eye className="w-4 h-4" />
<span>Launch Live Shoulder-Surfing Mode</span>
</button>
<button
onClick={() => handleSubmitApplication('Applied')}
disabled={isSubmitting}
@@ -390,6 +417,158 @@ export const WalkthroughTailor: React.FC<WalkthroughTailorProps> = ({
</div>
)}
{/* Shoulder Surfing Mode Interactive Live Modal */}
{isSurfingActive && (
<div className="fixed inset-0 bg-slate-950/90 backdrop-blur-lg flex items-center justify-center p-4 z-50 animate-fadeIn">
<div className="bg-slate-900 border border-amber-500/50 rounded-2xl max-w-4xl w-full p-6 shadow-2xl space-y-5 max-h-[90vh] overflow-y-auto">
{/* Modal Header */}
<div className="flex items-center justify-between pb-4 border-b border-slate-800">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-amber-500/20 text-amber-400 border border-amber-500/40 flex items-center justify-center font-extrabold shadow-lg">
<Eye className="w-5 h-5 animate-pulse" />
</div>
<div>
<h3 className="text-sm font-bold text-white flex items-center gap-2">
<span>Shoulder-Surfing Live Inspector Mode</span>
<span className="px-2 py-0.5 rounded-md bg-emerald-950 text-emerald-300 border border-emerald-500/30 text-[10px] uppercase tracking-wider font-semibold">Live Visualizer</span>
</h3>
<p className="text-xs text-slate-400">Watch the AI auto-fill the application step-by-step and modify any field before final submission.</p>
</div>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => setIsSurfingPaused(!isSurfingPaused)}
className="px-3 py-1.5 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-200 text-xs font-semibold flex items-center gap-1.5"
>
{isSurfingPaused ? <Play className="w-3.5 h-3.5 text-emerald-400" /> : <Pause className="w-3.5 h-3.5 text-amber-400" />}
<span>{isSurfingPaused ? 'Resume AI' : 'Pause AI'}</span>
</button>
<button
onClick={() => setIsSurfingActive(false)}
className="text-slate-400 hover:text-white text-xs px-2"
>
✕
</button>
</div>
</div>
{/* Simulated Live Web Browser Window Frame */}
<div className="border border-slate-800 rounded-xl bg-slate-950 overflow-hidden shadow-inner">
{/* Browser Address Bar */}
<div className="bg-slate-900 px-4 py-2 border-b border-slate-800 flex items-center gap-3 text-xs text-slate-400">
<div className="flex gap-1.5">
<span className="w-3 h-3 rounded-full bg-rose-500/80 inline-block"></span>
<span className="w-3 h-3 rounded-full bg-amber-500/80 inline-block"></span>
<span className="w-3 h-3 rounded-full bg-emerald-500/80 inline-block"></span>
</div>
<div className="flex-1 bg-slate-950 border border-slate-800 rounded-lg px-3 py-1 text-[11px] font-mono text-slate-300 flex items-center justify-between">
<span className="truncate">{jobUrl || `https://boards.greenhouse.io/${companyName.toLowerCase() || 'company'}/jobs/apply`}</span>
<span className="text-emerald-400 text-[10px] font-semibold flex items-center gap-1">
<CheckCircle2 className="w-3 h-3" /> SSL Verified
</span>
</div>
</div>
{/* Form Inspection & Field Editor Grid */}
<div className="p-5 space-y-4">
<div className="flex items-center justify-between">
<h4 className="text-xs font-bold text-slate-200 flex items-center gap-2">
<Edit3 className="w-4 h-4 text-indigo-400" />
Interactive Form Field Auto-Filler (Review & Edit Any Field)
</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-4 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>
<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>
{/* Action Bar */}
<div className="flex items-center justify-between pt-2">
<span className="text-xs text-slate-400">
You have full manual override control over all auto-filled inputs.
</span>
<div className="flex items-center gap-3">
<button
onClick={() => setIsSurfingActive(false)}
className="px-4 py-2.5 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-300 text-xs font-semibold"
>
Cancel Mode
</button>
<button
onClick={() => {
handleSubmitApplication('Applied');
setIsSurfingActive(false);
}}
className="px-6 py-2.5 rounded-xl bg-emerald-600 hover:bg-emerald-500 text-white font-bold text-xs shadow-lg shadow-emerald-600/20 flex items-center gap-1.5"
>
<CheckCircle2 className="w-4 h-4" />
<span>Approve & Submit Application</span>
</button>
</div>
</div>
</div>
</div>
)}
</div>
);
};