Updated the to use targeted jobs but its weird

This commit is contained in:
Ace
2026-07-01 12:15:37 +02:00
parent 878627a6ba
commit e920d4925a
5 changed files with 434 additions and 134 deletions
+17 -1
View File
@@ -57,7 +57,12 @@ const commandPills = [
{ icon: "✉️", label: "Templates", prompt: "Show me email templates" },
]
export const AIChat = forwardRef<{ fillInput: (text: string) => void }, AIChatProps>(({ onMessageSent }, ref) => {
export interface AIChatHandle {
fillInput: (text: string) => void
addAssistantMessage: (content: string) => void
}
export const AIChat = forwardRef<AIChatHandle, AIChatProps>(({ onMessageSent }, ref) => {
const [messages, setMessages] = useState<ChatMessage[]>([])
const [input, setInput] = useState("")
const [loading, setLoading] = useState(false)
@@ -72,6 +77,17 @@ export const AIChat = forwardRef<{ fillInput: (text: string) => void }, AIChatPr
setInput(text)
setTimeout(() => textareaRef.current?.focus(), 50)
},
addAssistantMessage(content: string) {
setMessages((prev) => {
if (!prev.some((m) => m.role === "user")) {
return [
{ role: "user", content: "Search Facebook" },
{ role: "assistant", content },
]
}
return [...prev, { role: "assistant", content }]
})
},
}), [])
const checkServer = useCallback(async () => {
+50 -34
View File
@@ -1,7 +1,7 @@
"use client"
import { useState, useEffect } from "react"
import { Briefcase, ChevronDown, Loader2 } from "lucide-react"
import { Briefcase, ChevronDown, Loader2, Search } from "lucide-react"
interface Job {
job_title: string
@@ -12,9 +12,11 @@ interface Job {
interface JobSelectorProps {
onSelect: (job: Job | null) => void
onSearch?: (job: Job) => void
searching?: boolean
}
export function JobSelector({ onSelect }: JobSelectorProps) {
export function JobSelector({ onSelect, onSearch, searching }: JobSelectorProps) {
const [jobs, setJobs] = useState<Job[]>([])
const [loading, setLoading] = useState(true)
const [open, setOpen] = useState(false)
@@ -35,39 +37,53 @@ export function JobSelector({ onSelect }: JobSelectorProps) {
}
return (
<div className="relative">
<button
type="button"
onClick={() => setOpen(!open)}
className="w-full flex items-center gap-2.5 bg-[#1a1d2e] border border-[#ffffff0f] hover:border-[#f97316]/30 rounded-xl px-4 py-3 text-sm text-[#9ca3af] hover:text-[#e5e7eb] 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-[#f97316]" /> : <ChevronDown className={`h-3.5 w-3.5 text-[#4b5563] transition-transform duration-200 ${open ? "rotate-180" : ""}`} />}
</button>
<div>
<div className="relative">
<button
type="button"
onClick={() => setOpen(!open)}
className="w-full flex items-center gap-2.5 bg-[#1a1d2e] border border-[#ffffff0f] hover:border-[#f97316]/30 rounded-xl px-4 py-3 text-sm text-[#9ca3af] hover:text-[#e5e7eb] 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 to target"}
</span>
{loading ? <Loader2 className="h-3.5 w-3.5 animate-spin text-[#f97316]" /> : <ChevronDown className={`h-3.5 w-3.5 text-[#4b5563] 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-[#1a1d2e] border border-[#ffffff0f] rounded-xl shadow-xl shadow-black/40 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-[#9ca3af] hover:bg-[#1f2437] hover:text-[#e5e7eb] transition-all duration-150 border-b border-[#ffffff08] last:border-0 border-l-2 border-l-transparent hover:border-l-[#f97316]/40"
>
<div className="font-medium">{job.job_title}</div>
<div className="text-xs text-[#4b5563] mt-0.5">{job.industry} &mdash; {job.description}</div>
</button>
))}
{jobs.length === 0 && !loading && (
<div className="px-4 py-4 text-xs text-[#4b5563] text-center">No job categories loaded</div>
)}
</div>
</>
{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-[#1a1d2e] border border-[#ffffff0f] rounded-xl shadow-xl shadow-black/40 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-[#9ca3af] hover:bg-[#1f2437] hover:text-[#e5e7eb] transition-all duration-150 border-b border-[#ffffff08] last:border-0 border-l-2 border-l-transparent hover:border-l-[#f97316]/40"
>
<div className="font-medium">{job.job_title}</div>
<div className="text-xs text-[#4b5563] mt-0.5">{job.industry} &mdash; {job.description}</div>
</button>
))}
{jobs.length === 0 && !loading && (
<div className="px-4 py-4 text-xs text-[#4b5563] text-center">No job categories loaded</div>
)}
</div>
</>
)}
</div>
{selected && (
<button
type="button"
onClick={() => onSearch?.(selected)}
disabled={searching}
className="w-full mt-2 flex items-center justify-center gap-2 bg-gradient-to-br from-[#f97316] to-[#ea580c] hover:from-[#ea580c] hover:to-[#d97706] disabled:opacity-50 disabled:cursor-not-allowed rounded-xl px-4 py-2.5 text-sm font-semibold text-white transition-all duration-200 shadow-[0_0_20px_rgba(249,115,22,0.2)]"
>
{searching ? <Loader2 className="h-4 w-4 animate-spin" /> : <Search className="h-4 w-4" />}
{searching ? "Searching Facebook..." : "Search Facebook"}
</button>
)}
</div>
)