"use client" import { useState, useEffect } from "react" import Link from "next/link" interface Job { source: string title: string company: string location: string description: string url: string salary: string } interface Application { id: string job_title: string company: string location: string job_url: string status: string applied_at: string } type Tab = "search" | "applications" | "profile" | "settings" export default function DashboardPage() { const [tab, setTab] = useState("search") const [user, setUser] = useState(null) // Search state const [query, setQuery] = useState("") const [location, setLocation] = useState("") const [jobs, setJobs] = useState([]) const [searching, setSearching] = useState(false) const [searched, setSearched] = useState(false) // Applications state const [applications, setApplications] = useState([]) // Profile state const [profile, setProfile] = useState({ name: "", title: "", summary: "", skills: "", experience: [{ title: "", company: "", bullets: "" }], education: "", linkedin_url: "", job_keywords: "", job_locations: "" }) // API Keys state const [apiKeys, setApiKeys] = useState({ jooble: "", jsearch: "", perplexity: "" }) const [keysSaved, setKeysSaved] = useState(false) useEffect(() => { // Load user, profile, applications fetch("/api/users/me").then(r => r.ok && r.json()).then(d => d && setUser(d)).catch(() => {}) fetch("/api/users/me/profile").then(r => r.ok && r.json()).then(d => d && d.title && setProfile({ name: d.name || "", title: d.title || "", summary: d.summary || "", skills: Array.isArray(d.skills) ? d.skills.join(", ") : (d.skills || ""), experience: d.experience || [{ title: "", company: "", bullets: "" }], education: d.education || "", linkedin_url: d.linkedin_url || "", job_keywords: Array.isArray(d.job_keywords) ? d.job_keywords.join(", ") : (d.job_keywords || ""), job_locations: Array.isArray(d.job_locations) ? d.job_locations.join(", ") : (d.job_locations || "") })).catch(() => {}) fetch("/api/applications").then(r => r.ok && r.json()).then(d => d && setApplications(d)).catch(() => {}) fetch("/api/users/me/api-keys").then(r => r.ok && r.json()).then(d => d && setApiKeys({ jooble: d.jooble || "", jsearch: d.jsearch || "", perplexity: d.perplexity || "" })).catch(() => {}) }, []) const searchJobs = async () => { if (!query) return setSearching(true) setSearched(true) try { const res = await fetch("/api/jobs/search", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query, location }) }) const data = await res.json() setJobs(data.jobs || []) } catch {} setSearching(false) } const applyToJob = async (job: Job) => { try { await fetch("/api/ai/customize", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ job, profile }) }) await fetch("/api/applications", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ job, resume: "", cover_letter: "", status: "applied" }) }) // Refresh applications const res = await fetch("/api/applications") const data = await res.json() setApplications(data) setTab("applications") } catch {} } const saveProfile = async () => { const payload = { ...profile, skills: profile.skills.split(",").map(s => s.trim()).filter(Boolean), job_keywords: profile.job_keywords.split(",").map(s => s.trim()).filter(Boolean), job_locations: profile.job_locations.split(",").map(s => s.trim()).filter(Boolean) } await fetch("/api/users/me/profile", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }) alert("Profile saved!") } const saveApiKeys = async () => { await fetch("/api/users/me/api-keys", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(apiKeys) }) setKeysSaved(true) setTimeout(() => setKeysSaved(false), 2000) } const statusColor: Record = { pending: "bg-yellow-500/20 text-yellow-400", applied: "bg-blue-500/20 text-blue-400", interview: "bg-green-500/20 text-green-400", rejected: "bg-red-500/20 text-red-400", offer: "bg-purple-500/20 text-purple-400" } return (
{/* Header */}
AutoJobs
{user?.email || "Loading..."} Logout
{/* Tabs */}
{[ { key: "search", label: "๐Ÿ” Find Jobs", icon: "๐Ÿ”" }, { key: "applications", label: `๐Ÿ“‹ Applications (${applications.length})`, icon: "๐Ÿ“‹" }, { key: "profile", label: "๐Ÿ‘ค My Profile", icon: "๐Ÿ‘ค" }, { key: "settings", label: "โš™๏ธ API Keys", icon: "โš™๏ธ" } ].map(t => ( ))}
{/* Search Tab */} {tab === "search" && (

Search Jobs

AI will search across Jooble, JSearch, and more using your API keys.

setQuery(e.target.value)} onKeyDown={e => e.key === "Enter" && searchJobs()} className="flex-1 px-4 py-3 bg-slate-700 border border-slate-600 rounded-xl text-white placeholder-slate-400 focus:outline-none focus:border-blue-500" /> setLocation(e.target.value)} className="w-64 px-4 py-3 bg-slate-700 border border-slate-600 rounded-xl text-white placeholder-slate-400 focus:outline-none focus:border-blue-500" />
{!apiKeys.jooble && !apiKeys.jsearch ? (

โš ๏ธ No API keys found. to search jobs.

) : (

โœ“ API keys configured โ€” searches will use your keys

)}
{/* Results */} {searched && (

{jobs.length} jobs found

{jobs.length === 0 && !searching && (

No jobs found. Try different keywords.

Make sure you've added API keys in Settings.

)}
{jobs.map((job, i) => (

{job.title}

{job.company}

{job.location}

{job.description?.slice(0, 200)}...

{job.source} {job.salary && ( {job.salary} )}
View Job โ†—
))}
)}
)} {/* Applications Tab */} {tab === "applications" && (

My Applications

{applications.length === 0 ? (

No applications yet.

) : (
{applications.map(app => (

{app.job_title}

{app.company} ยท {app.location}

Applied {new Date(app.applied_at).toLocaleDateString()}

{app.job_url && ( View โ†— )}
))}
)}
)} {/* Profile Tab */} {tab === "profile" && (

My Profile

setProfile({...profile, name: e.target.value})} className="w-full px-4 py-2 bg-slate-700 border border-slate-600 rounded-xl text-white" />
setProfile({...profile, title: e.target.value})} placeholder="e.g. Senior Full-Stack Developer" className="w-full px-4 py-2 bg-slate-700 border border-slate-600 rounded-xl text-white" />