import * as api from "@client/api"; import type { UpdateSettingsInput } from "@shared/settings-schema.js"; import type { JobSearchProfile, SearchProfile } from "@shared/types.js"; import { Loader2, Plus, Sparkles, Trash2 } from "lucide-react"; import type React from "react"; import { useCallback, useEffect, useState } from "react"; import { useFormContext } from "react-hook-form"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; const EMPTY_PROFILE: JobSearchProfile = { targetRoles: [], experienceLevel: "", mustHaveSkills: [], niceToHaveSkills: [], dealBreakers: [], preferredWorkArrangement: [], preferredLocations: [], minimumSalary: "", industriesToTarget: [], industriesToAvoid: [], aboutMe: "", }; interface ProfileManagerProps { activeProfileId: string | null; disabled: boolean; } export const ProfileManager: React.FC = ({ activeProfileId, disabled, }) => { const { setValue } = useFormContext(); const [profiles, setProfiles] = useState([]); const [selectedId, setSelectedId] = useState(activeProfileId); const [loading, setLoading] = useState(false); const [generating, setGenerating] = useState(false); const [newProfileName, setNewProfileName] = useState(""); const [showCreate, setShowCreate] = useState(false); const loadProfiles = useCallback(async () => { try { const list = await api.listProfiles(); setProfiles(list); } catch { toast.error("Failed to load profiles"); } }, []); useEffect(() => { void loadProfiles(); }, [loadProfiles]); useEffect(() => { setSelectedId(activeProfileId); }, [activeProfileId]); const handleSelect = useCallback( async (profileId: string) => { setLoading(true); try { await api.activateProfile(profileId); setSelectedId(profileId); const profile = profiles.find((p) => p.id === profileId); if (profile) { setValue("jobSearchProfile", profile.data, { shouldDirty: false }); setValue("activeProfileId", profileId, { shouldDirty: false }); } toast.success("Profile activated"); } catch { toast.error("Failed to activate profile"); } finally { setLoading(false); } }, [profiles, setValue], ); const handleCreateBlank = useCallback(async () => { if (!newProfileName.trim()) { toast.error("Enter a profile name"); return; } setLoading(true); try { const profile = await api.createProfile({ name: newProfileName.trim(), data: EMPTY_PROFILE, }); await api.activateProfile(profile.id); setProfiles((prev) => [...prev, profile]); setSelectedId(profile.id); setValue("jobSearchProfile", profile.data, { shouldDirty: false }); setValue("activeProfileId", profile.id, { shouldDirty: false }); setNewProfileName(""); setShowCreate(false); toast.success(`Profile "${profile.name}" created`); } catch { toast.error("Failed to create profile"); } finally { setLoading(false); } }, [newProfileName, setValue]); const handleGenerateFromResume = useCallback(async () => { if (!newProfileName.trim()) { toast.error("Enter a profile name first"); return; } setGenerating(true); try { const generated = await api.generateProfileFromResume(); const profile = await api.createProfile({ name: newProfileName.trim(), data: generated, }); await api.activateProfile(profile.id); setProfiles((prev) => [...prev, profile]); setSelectedId(profile.id); setValue("jobSearchProfile", profile.data, { shouldDirty: false }); setValue("activeProfileId", profile.id, { shouldDirty: false }); setNewProfileName(""); setShowCreate(false); toast.success(`Profile "${profile.name}" created from your resume`); } catch (err) { const msg = err instanceof Error ? err.message : "Failed to generate profile"; toast.error(msg); } finally { setGenerating(false); } }, [newProfileName, setValue]); const handleDelete = useCallback( async (profileId: string) => { try { await api.deleteProfile(profileId); setProfiles((prev) => prev.filter((p) => p.id !== profileId)); if (selectedId === profileId) { setSelectedId(null); setValue("jobSearchProfile", EMPTY_PROFILE, { shouldDirty: false }); setValue("activeProfileId", null, { shouldDirty: false }); } toast.success("Profile deleted"); } catch { toast.error("Failed to delete profile"); } }, [selectedId, setValue], ); const activeProfile = profiles.find((p) => p.id === selectedId); return (
{activeProfile && ( )}
{showCreate && (
setNewProfileName(e.target.value)} placeholder="Profile name (e.g. QA Engineer, DevOps)" className="flex-1 h-8 text-sm" disabled={generating} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); void handleCreateBlank(); } }} />
)}
{!selectedId && profiles.length === 0 && (

Create a profile to get started. "Generate from resume" will analyse your Reactive Resume and fill in the fields automatically.

)}
); };