mirror of
https://git.coastit.co.za/caitlin/CRM_ENVR.git
synced 2026-07-10 11:15:43 +02:00
88 lines
3.5 KiB
TypeScript
88 lines
3.5 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useEffect } from "react"
|
|
import { Briefcase, ChevronDown, Loader2, Search } from "lucide-react"
|
|
|
|
interface Job {
|
|
job_title: string
|
|
keywords: string[]
|
|
industry: string
|
|
description: string
|
|
}
|
|
|
|
interface JobSelectorProps {
|
|
onSelect: (job: Job | null) => void
|
|
onSearch?: (job: Job) => void
|
|
searching?: boolean
|
|
}
|
|
|
|
export function JobSelector({ onSelect, onSearch, searching }: JobSelectorProps) {
|
|
const [jobs, setJobs] = useState<Job[]>([])
|
|
const [loading, setLoading] = useState(true)
|
|
const [open, setOpen] = useState(false)
|
|
const [selected, setSelected] = useState<Job | null>(null)
|
|
|
|
useEffect(() => {
|
|
fetch("/api/ai/jobs")
|
|
.then((r) => r.json())
|
|
.then((data) => setJobs(data.jobs || []))
|
|
.catch(() => setJobs([]))
|
|
.finally(() => setLoading(false))
|
|
}, [])
|
|
|
|
const handleSelect = (job: Job) => {
|
|
setSelected(job)
|
|
setOpen(false)
|
|
onSelect(job)
|
|
}
|
|
|
|
return (
|
|
<div className="relative">
|
|
<button
|
|
type="button"
|
|
onClick={() => setOpen(!open)}
|
|
className="w-full flex items-center gap-2.5 bg-card/50 border border-border hover:border-primary/20 rounded-xl px-4 py-3 text-sm text-muted-foreground hover:text-foreground transition-all duration-200"
|
|
>
|
|
<Briefcase className="h-4 w-4 text-[#f97316] flex-none" />
|
|
<span className="flex-1 text-left truncate">
|
|
{selected ? selected.job_title : loading ? "Loading jobs..." : "Select a job category"}
|
|
</span>
|
|
{loading ? <Loader2 className="h-3.5 w-3.5 animate-spin text-primary" /> : <ChevronDown className={`h-3.5 w-3.5 text-muted-foreground/60 transition-transform duration-200 ${open ? "rotate-180" : ""}`} />}
|
|
</button>
|
|
|
|
{open && (
|
|
<>
|
|
<div className="fixed inset-0 z-10" onClick={() => setOpen(false)} />
|
|
<div className="absolute top-full left-0 right-0 mt-1.5 z-20 bg-card border border-border rounded-xl shadow-xl max-h-60 overflow-y-auto">
|
|
{jobs.map((job, i) => (
|
|
<button
|
|
key={i}
|
|
type="button"
|
|
onClick={() => handleSelect(job)}
|
|
className="w-full text-left px-4 py-3 text-sm text-muted-foreground hover:bg-muted hover:text-foreground transition-all duration-150 border-b border-border/20 last:border-0 border-l-2 border-l-transparent hover:border-l-primary/40"
|
|
>
|
|
<div className="font-medium">{job.job_title}</div>
|
|
<div className="text-xs text-muted-foreground/60 mt-0.5">{job.industry} — {job.description}</div>
|
|
</button>
|
|
))}
|
|
{jobs.length === 0 && !loading && (
|
|
<div className="px-4 py-4 text-xs text-muted-foreground/60 text-center">No job categories loaded</div>
|
|
)}
|
|
</div>
|
|
</>
|
|
)}
|
|
{selected && onSearch && (
|
|
<button
|
|
type="button"
|
|
onClick={() => onSearch(selected)}
|
|
disabled={searching}
|
|
className="w-full flex items-center justify-center gap-2 mt-3 bg-gradient-to-r from-[#f97316] to-[#ea580c] hover:from-[#ea580c] hover:to-[#dc2626] disabled:opacity-50 disabled:cursor-not-allowed text-white text-sm font-semibold rounded-xl px-4 py-3 transition-all duration-200 shadow-lg shadow-[#f97316]/20"
|
|
>
|
|
{searching ? <Loader2 className="h-4 w-4 animate-spin" /> : <Search className="h-4 w-4" />}
|
|
{searching ? "Searching..." : "Search Facebook"}
|
|
</button>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|