Add descriptive error messages across all API routes and toast notifications on client pages
Build & Auto-Repair / build (push) Has been cancelled
Build & Auto-Repair / build (push) Has been cancelled
- 86 catch blocks in 49 API route files now return the actual error message via error.message
- 14 campaign/lead/config catch blocks that lacked console.error now log errors
- 17 client pages/components now show toast.error notifications on API failures
- Silent .catch(() => {}) and finally-only try blocks now surface errors to users
This commit is contained in:
@@ -12,6 +12,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|||||||
import {
|
import {
|
||||||
ArrowLeft, Plus, Trash2, Send, Play, Pause, Users, Mail, Clock,
|
ArrowLeft, Plus, Trash2, Send, Play, Pause, Users, Mail, Clock,
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
export default function CampaignDetailPage({ params }: { params: Promise<{ id: string }> }) {
|
export default function CampaignDetailPage({ params }: { params: Promise<{ id: string }> }) {
|
||||||
const { id } = use(params)
|
const { id } = use(params)
|
||||||
@@ -29,7 +30,7 @@ export default function CampaignDetailPage({ params }: { params: Promise<{ id: s
|
|||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/campaigns/${id}`)
|
const res = await fetch(`/api/campaigns/${id}`)
|
||||||
if (res.ok) setCampaign(await res.json())
|
if (res.ok) setCampaign(await res.json())
|
||||||
} catch { /* ignore */ }
|
} catch (e) { console.error("Failed to load campaign", e); toast.error("Failed to load campaign") }
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ export default function CampaignDetailPage({ params }: { params: Promise<{ id: s
|
|||||||
})
|
})
|
||||||
setNewStep({ subject: "", bodyText: "", delayDays: 3 })
|
setNewStep({ subject: "", bodyText: "", delayDays: 3 })
|
||||||
fetchCampaign()
|
fetchCampaign()
|
||||||
} catch { /* ignore */ }
|
} catch (e) { console.error("Failed to add step", e); toast.error("Failed to add step") }
|
||||||
setAddingStep(false)
|
setAddingStep(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ export default function CampaignDetailPage({ params }: { params: Promise<{ id: s
|
|||||||
setLeadSearch("")
|
setLeadSearch("")
|
||||||
setSearchResults([])
|
setSearchResults([])
|
||||||
fetchCampaign()
|
fetchCampaign()
|
||||||
} catch { /* ignore */ }
|
} catch (e) { console.error("Failed to subscribe leads", e); toast.error("Failed to subscribe leads") }
|
||||||
setSubscribing(false)
|
setSubscribing(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +79,7 @@ export default function CampaignDetailPage({ params }: { params: Promise<{ id: s
|
|||||||
const res = await fetch(`/api/campaigns/${id}/send`, { method: "POST" })
|
const res = await fetch(`/api/campaigns/${id}/send`, { method: "POST" })
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
if (data.sent > 0) fetchCampaign()
|
if (data.sent > 0) fetchCampaign()
|
||||||
} catch { /* ignore */ }
|
} catch (e) { console.error("Failed to send campaign", e); toast.error("Failed to send campaign") }
|
||||||
setSending(false)
|
setSending(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Button } from "@/components/ui/button"
|
|||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Card } from "@/components/ui/card"
|
import { Card } from "@/components/ui/card"
|
||||||
import { ArrowLeft } from "lucide-react"
|
import { ArrowLeft } from "lucide-react"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
export default function NewCampaignPage() {
|
export default function NewCampaignPage() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -25,7 +26,7 @@ export default function NewCampaignPage() {
|
|||||||
})
|
})
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
if (data.id) router.push(`/campaigns/${data.id}`)
|
if (data.id) router.push(`/campaigns/${data.id}`)
|
||||||
} catch { /* ignore */ }
|
} catch (e) { console.error("Campaign create error:", e); toast.error("Failed to create campaign") }
|
||||||
setSaving(false)
|
setSaving(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Button } from "@/components/ui/button"
|
|||||||
import { Card } from "@/components/ui/card"
|
import { Card } from "@/components/ui/card"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { Plus, Mail, Users, Layers, Calendar } from "lucide-react"
|
import { Plus, Mail, Users, Layers, Calendar } from "lucide-react"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
const statusColors: Record<string, string> = {
|
const statusColors: Record<string, string> = {
|
||||||
draft: "bg-zinc-100 text-zinc-700 border-zinc-300",
|
draft: "bg-zinc-100 text-zinc-700 border-zinc-300",
|
||||||
@@ -24,7 +25,7 @@ export default function CampaignsPage() {
|
|||||||
fetch("/api/campaigns")
|
fetch("/api/campaigns")
|
||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(d => { if (Array.isArray(d)) setCampaigns(d); else setCampaigns([]) })
|
.then(d => { if (Array.isArray(d)) setCampaigns(d); else setCampaigns([]) })
|
||||||
.catch(() => setCampaigns([]))
|
.catch((e) => { console.error("Failed to load campaigns", e); toast.error("Failed to load campaigns"); setCampaigns([]) })
|
||||||
.finally(() => setLoading(false))
|
.finally(() => setLoading(false))
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Button } from "@/components/ui/button"
|
|||||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||||
import { Card } from "@/components/ui/card"
|
import { Card } from "@/components/ui/card"
|
||||||
import { GripVertical, Plus, User, Building2, Mail, Phone, Hash } from "lucide-react"
|
import { GripVertical, Plus, User, Building2, Mail, Phone, Hash } from "lucide-react"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
interface KanbanLead {
|
interface KanbanLead {
|
||||||
id: string
|
id: string
|
||||||
@@ -57,6 +58,7 @@ export default function KanbanPage() {
|
|||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
setColumns(data)
|
setColumns(data)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to load kanban data")
|
||||||
console.error("Failed to load kanban", e)
|
console.error("Failed to load kanban", e)
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
@@ -98,6 +100,7 @@ export default function KanbanPage() {
|
|||||||
body: JSON.stringify({ status: toStatus }),
|
body: JSON.stringify({ status: toStatus }),
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to update lead status")
|
||||||
console.error("Failed to update lead status", e)
|
console.error("Failed to update lead status", e)
|
||||||
fetchKanban()
|
fetchKanban()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { ArrowLeft } from "lucide-react"
|
|||||||
import { User } from "@/types"
|
import { User } from "@/types"
|
||||||
import { useNotifications } from "@/providers/notification-provider"
|
import { useNotifications } from "@/providers/notification-provider"
|
||||||
import { LEAD_SOURCES, LEAD_STATUSES } from "@/lib/constants"
|
import { LEAD_SOURCES, LEAD_STATUSES } from "@/lib/constants"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
const leadFormSchema = z.object({
|
const leadFormSchema = z.object({
|
||||||
companyName: z.string().min(1, "Company name is required"),
|
companyName: z.string().min(1, "Company name is required"),
|
||||||
@@ -53,7 +54,7 @@ export default function CreateLeadPage() {
|
|||||||
fetch("/api/users")
|
fetch("/api/users")
|
||||||
.then((r) => r.json())
|
.then((r) => r.json())
|
||||||
.then((data) => setUsers(data.users || []))
|
.then((data) => setUsers(data.users || []))
|
||||||
.catch(() => {})
|
.catch((e) => { console.error("Failed to load users", e); toast.error("Failed to load users") })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const form = useForm<LeadFormValues>({
|
const form = useForm<LeadFormValues>({
|
||||||
@@ -87,6 +88,7 @@ export default function CreateLeadPage() {
|
|||||||
addNotification("lead_created", "New Lead Created", `${values.companyName} — ${values.contactName}`, `/leads/${data.id}`)
|
addNotification("lead_created", "New Lead Created", `${values.companyName} — ${values.contactName}`, `/leads/${data.id}`)
|
||||||
router.push("/leads")
|
router.push("/leads")
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to create lead")
|
||||||
console.error("Create lead error:", e)
|
console.error("Create lead error:", e)
|
||||||
} finally {
|
} finally {
|
||||||
setSaving(false)
|
setSaving(false)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { LeadsTable } from "@/components/leads/leads-table"
|
|||||||
import { LeadsTableToolbar } from "@/components/leads/leads-table-toolbar"
|
import { LeadsTableToolbar } from "@/components/leads/leads-table-toolbar"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Columns3 } from "lucide-react"
|
import { Columns3 } from "lucide-react"
|
||||||
|
import { toast } from "sonner"
|
||||||
import { Lead } from "@/types"
|
import { Lead } from "@/types"
|
||||||
|
|
||||||
export default function LeadsPage() {
|
export default function LeadsPage() {
|
||||||
@@ -30,7 +31,7 @@ export default function LeadsPage() {
|
|||||||
setLeadsData(data)
|
setLeadsData(data)
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
})
|
})
|
||||||
.catch(() => setLoading(false))
|
.catch((e) => { console.error("Failed to load leads", e); toast.error("Failed to load leads"); setLoading(false) })
|
||||||
}, [search, statusFilter, periodFilter])
|
}, [search, statusFilter, periodFilter])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
interface Milestone {
|
interface Milestone {
|
||||||
id: string
|
id: string
|
||||||
@@ -82,6 +83,7 @@ export default function ProjectDetailPage() {
|
|||||||
setMilestones(await mRes.json())
|
setMilestones(await mRes.json())
|
||||||
setStatuses(await sRes.json())
|
setStatuses(await sRes.json())
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to load project")
|
||||||
console.error("Failed to load project", e)
|
console.error("Failed to load project", e)
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
@@ -91,21 +93,31 @@ export default function ProjectDetailPage() {
|
|||||||
useEffect(() => { fetchProject() }, [fetchProject])
|
useEffect(() => { fetchProject() }, [fetchProject])
|
||||||
|
|
||||||
const updateProjectStatus = async (statusId: string) => {
|
const updateProjectStatus = async (statusId: string) => {
|
||||||
await fetch(`/api/projects/${id}`, {
|
try {
|
||||||
method: "PATCH",
|
await fetch(`/api/projects/${id}`, {
|
||||||
headers: { "Content-Type": "application/json" },
|
method: "PATCH",
|
||||||
body: JSON.stringify({ statusId }),
|
headers: { "Content-Type": "application/json" },
|
||||||
})
|
body: JSON.stringify({ statusId }),
|
||||||
fetchProject()
|
})
|
||||||
|
fetchProject()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to update project status", e)
|
||||||
|
toast.error("Failed to update project status")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateMilestoneStatus = async (milestoneId: string, status: string) => {
|
const updateMilestoneStatus = async (milestoneId: string, status: string) => {
|
||||||
await fetch(`/api/milestones/${milestoneId}`, {
|
try {
|
||||||
method: "PATCH",
|
await fetch(`/api/milestones/${milestoneId}`, {
|
||||||
headers: { "Content-Type": "application/json" },
|
method: "PATCH",
|
||||||
body: JSON.stringify({ status }),
|
headers: { "Content-Type": "application/json" },
|
||||||
})
|
body: JSON.stringify({ status }),
|
||||||
fetchProject()
|
})
|
||||||
|
fetchProject()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to update milestone status", e)
|
||||||
|
toast.error("Failed to update milestone status")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const addMilestone = async () => {
|
const addMilestone = async () => {
|
||||||
@@ -119,6 +131,9 @@ export default function ProjectDetailPage() {
|
|||||||
})
|
})
|
||||||
setNewMilestoneName("")
|
setNewMilestoneName("")
|
||||||
fetchProject()
|
fetchProject()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to add milestone", e)
|
||||||
|
toast.error("Failed to add milestone")
|
||||||
} finally {
|
} finally {
|
||||||
setAddingMilestone(false)
|
setAddingMilestone(false)
|
||||||
}
|
}
|
||||||
@@ -140,6 +155,7 @@ export default function ProjectDetailPage() {
|
|||||||
setNewTaskInputs((prev) => ({ ...prev, [milestoneId]: "" }))
|
setNewTaskInputs((prev) => ({ ...prev, [milestoneId]: "" }))
|
||||||
fetchProject()
|
fetchProject()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to add task")
|
||||||
console.error("Failed to add task", e)
|
console.error("Failed to add task", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog"
|
} from "@/components/ui/dialog"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
interface Project {
|
interface Project {
|
||||||
id: string
|
id: string
|
||||||
@@ -65,6 +66,7 @@ export default function ProjectsPage() {
|
|||||||
const data = res.ok ? await res.json() : []
|
const data = res.ok ? await res.json() : []
|
||||||
setProjects(Array.isArray(data) ? data : [])
|
setProjects(Array.isArray(data) ? data : [])
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to load projects")
|
||||||
console.error("Failed to load projects", e)
|
console.error("Failed to load projects", e)
|
||||||
setProjects([])
|
setProjects([])
|
||||||
} finally {
|
} finally {
|
||||||
@@ -75,7 +77,7 @@ export default function ProjectsPage() {
|
|||||||
useEffect(() => { fetchProjects() }, [search, statusFilter])
|
useEffect(() => { fetchProjects() }, [search, statusFilter])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch("/api/project-statuses").then(r => r.json()).then((d) => setStatuses(Array.isArray(d) ? d : [])).catch(() => {})
|
fetch("/api/project-statuses").then(r => r.json()).then((d) => setStatuses(Array.isArray(d) ? d : [])).catch((e) => { console.error("Failed to load project statuses", e); toast.error("Failed to load project statuses") })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const formatDate = (d: string) => d ? new Date(d).toLocaleDateString() : "—"
|
const formatDate = (d: string) => d ? new Date(d).toLocaleDateString() : "—"
|
||||||
@@ -168,8 +170,8 @@ function NewProjectDialog({ statuses, onCreated }: { statuses: ProjectStatus[];
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!open) return
|
if (!open) return
|
||||||
fetch("/api/customers?limit=100").then(r => r.json()).then(d => setCustomers(Array.isArray(d) ? d : [])).catch(() => {})
|
fetch("/api/customers?limit=100").then(r => r.json()).then(d => setCustomers(Array.isArray(d) ? d : [])).catch((e) => { console.error("Failed to load customers", e); toast.error("Failed to load customers") })
|
||||||
fetch("/api/users").then(r => r.json()).then(d => setUsers(d.users || [])).catch(() => {})
|
fetch("/api/users").then(r => r.json()).then(d => setUsers(d.users || [])).catch((e) => { console.error("Failed to load users", e); toast.error("Failed to load users") })
|
||||||
}, [open])
|
}, [open])
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
@@ -194,6 +196,9 @@ function NewProjectDialog({ statuses, onCreated }: { statuses: ProjectStatus[];
|
|||||||
setName(""); setDescription(""); setCustomerId(""); setOwnerId(""); setStartDate(""); setTargetEndDate(""); setBudget("")
|
setName(""); setDescription(""); setCustomerId(""); setOwnerId(""); setStartDate(""); setTargetEndDate(""); setBudget("")
|
||||||
onCreated()
|
onCreated()
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to create project", e)
|
||||||
|
toast.error("Failed to create project")
|
||||||
} finally {
|
} finally {
|
||||||
setSaving(false)
|
setSaving(false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
export default function ProposalDetailPage() {
|
export default function ProposalDetailPage() {
|
||||||
const { id } = useParams<{ id: string }>()
|
const { id } = useParams<{ id: string }>()
|
||||||
@@ -35,6 +36,7 @@ export default function ProposalDetailPage() {
|
|||||||
setProposal(await pRes.json())
|
setProposal(await pRes.json())
|
||||||
setStatuses(await sRes.json())
|
setStatuses(await sRes.json())
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to load proposal")
|
||||||
console.error("Failed to load proposal", e)
|
console.error("Failed to load proposal", e)
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
@@ -44,12 +46,17 @@ export default function ProposalDetailPage() {
|
|||||||
useEffect(() => { fetchProposal() }, [fetchProposal])
|
useEffect(() => { fetchProposal() }, [fetchProposal])
|
||||||
|
|
||||||
const updateStatus = async (statusId: string) => {
|
const updateStatus = async (statusId: string) => {
|
||||||
await fetch(`/api/proposals/${id}`, {
|
try {
|
||||||
method: "PATCH",
|
await fetch(`/api/proposals/${id}`, {
|
||||||
headers: { "Content-Type": "application/json" },
|
method: "PATCH",
|
||||||
body: JSON.stringify({ statusId }),
|
headers: { "Content-Type": "application/json" },
|
||||||
})
|
body: JSON.stringify({ statusId }),
|
||||||
fetchProposal()
|
})
|
||||||
|
fetchProposal()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to update proposal status", e)
|
||||||
|
toast.error("Failed to update proposal status")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSign = async () => {
|
const handleSign = async () => {
|
||||||
@@ -62,6 +69,9 @@ export default function ProposalDetailPage() {
|
|||||||
body: JSON.stringify({ name: signName, email: signEmail }),
|
body: JSON.stringify({ name: signName, email: signEmail }),
|
||||||
})
|
})
|
||||||
if (res.ok) fetchProposal()
|
if (res.ok) fetchProposal()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to sign proposal", e)
|
||||||
|
toast.error("Failed to sign proposal")
|
||||||
} finally {
|
} finally {
|
||||||
setSigning(false)
|
setSigning(false)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
interface LineItem {
|
interface LineItem {
|
||||||
id: string
|
id: string
|
||||||
@@ -39,8 +40,8 @@ export default function NewProposalPage() {
|
|||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch("/api/leads?limit=100").then((r) => r.json()).then(setLeads).catch(() => {})
|
fetch("/api/leads?limit=100").then((r) => r.json()).then(setLeads).catch((e) => { console.error("Failed to load leads", e); toast.error("Failed to load leads") })
|
||||||
fetch("/api/customers?limit=100").then((r) => r.json()).then(setCustomers).catch(() => {})
|
fetch("/api/customers?limit=100").then((r) => r.json()).then(setCustomers).catch((e) => { console.error("Failed to load customers", e); toast.error("Failed to load customers") })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const addItem = () => {
|
const addItem = () => {
|
||||||
@@ -107,6 +108,7 @@ export default function NewProposalPage() {
|
|||||||
|
|
||||||
router.push(`/proposals/${data.id}`)
|
router.push(`/proposals/${data.id}`)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to create proposal")
|
||||||
console.error("Failed to create proposal", e)
|
console.error("Failed to create proposal", e)
|
||||||
} finally {
|
} finally {
|
||||||
setSaving(false)
|
setSaving(false)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
export default function ProposalsPage() {
|
export default function ProposalsPage() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -31,12 +32,12 @@ export default function ProposalsPage() {
|
|||||||
fetch(`/api/proposals?${params}`)
|
fetch(`/api/proposals?${params}`)
|
||||||
.then((r) => r.json())
|
.then((r) => r.json())
|
||||||
.then(setProposals)
|
.then(setProposals)
|
||||||
.catch(() => {})
|
.catch((e) => { console.error("Failed to load proposals", e); toast.error("Failed to load proposals") })
|
||||||
.finally(() => setLoading(false))
|
.finally(() => setLoading(false))
|
||||||
}, [search, statusFilter])
|
}, [search, statusFilter])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch("/api/proposal-statuses").then((r) => r.json()).then(setStatuses).catch(() => {})
|
fetch("/api/proposal-statuses").then((r) => r.json()).then(setStatuses).catch((e) => { console.error("Failed to load proposal statuses", e); toast.error("Failed to load proposal statuses") })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const formatCurrency = (n: number) => n ? `R${Number(n).toLocaleString()}` : "R0"
|
const formatCurrency = (n: number) => n ? `R${Number(n).toLocaleString()}` : "R0"
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select"
|
||||||
import { Users, Clock, Briefcase, AlertTriangle, TrendingUp } from "lucide-react"
|
import { Users, Clock, Briefcase, AlertTriangle, TrendingUp } from "lucide-react"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
interface Member {
|
interface Member {
|
||||||
id: string
|
id: string
|
||||||
@@ -81,7 +82,7 @@ export default function ResourcePlanningPage() {
|
|||||||
fetch(`/api/resource-planning?period=${period}`)
|
fetch(`/api/resource-planning?period=${period}`)
|
||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(d => { setMembers(d.members || []); setTotals(d.totals || null) })
|
.then(d => { setMembers(d.members || []); setTotals(d.totals || null) })
|
||||||
.catch(() => {})
|
.catch((e) => { console.error("Failed to load resource data", e); toast.error("Failed to load resource data") })
|
||||||
.finally(() => setLoading(false))
|
.finally(() => setLoading(false))
|
||||||
}, [period])
|
}, [period])
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Input } from "@/components/ui/input"
|
|||||||
import { Card } from "@/components/ui/card"
|
import { Card } from "@/components/ui/card"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { Play, Square, Plus, Trash2, Clock, Briefcase, User, TrendingUp, DollarSign } from "lucide-react"
|
import { Play, Square, Plus, Trash2, Clock, Briefcase, User, TrendingUp, DollarSign } from "lucide-react"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
interface TimeEntry {
|
interface TimeEntry {
|
||||||
id: string
|
id: string
|
||||||
@@ -59,6 +60,7 @@ export default function TimeTrackingPage() {
|
|||||||
setSummary(sData?.totals ? sData : null)
|
setSummary(sData?.totals ? sData : null)
|
||||||
setProjects(Array.isArray(pData) ? pData : [])
|
setProjects(Array.isArray(pData) ? pData : [])
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to load time data")
|
||||||
console.error("Failed to load time data", e)
|
console.error("Failed to load time data", e)
|
||||||
setEntries([])
|
setEntries([])
|
||||||
setProjects([])
|
setProjects([])
|
||||||
@@ -105,6 +107,7 @@ export default function TimeTrackingPage() {
|
|||||||
setTimerSeconds(0)
|
setTimerSeconds(0)
|
||||||
fetchData()
|
fetchData()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to save time entry")
|
||||||
console.error("Failed to save time entry", e)
|
console.error("Failed to save time entry", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,14 +138,22 @@ export default function TimeTrackingPage() {
|
|||||||
setManualRate("")
|
setManualRate("")
|
||||||
setShowManual(false)
|
setShowManual(false)
|
||||||
fetchData()
|
fetchData()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to save time entry", e)
|
||||||
|
toast.error("Failed to save time entry")
|
||||||
} finally {
|
} finally {
|
||||||
setSaving(false)
|
setSaving(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteEntry = async (id: string) => {
|
const deleteEntry = async (id: string) => {
|
||||||
await fetch(`/api/time-entries?id=${id}`, { method: "DELETE" })
|
try {
|
||||||
fetchData()
|
await fetch(`/api/time-entries?id=${id}`, { method: "DELETE" })
|
||||||
|
fetchData()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to delete time entry", e)
|
||||||
|
toast.error("Failed to delete time entry")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatDuration = (mins: number) => {
|
const formatDuration = (mins: number) => {
|
||||||
|
|||||||
@@ -141,8 +141,9 @@ export async function POST(request: NextRequest) {
|
|||||||
return response
|
return response
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Login error:", error)
|
console.error("Login error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Authentication service unavailable."
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Authentication service unavailable." },
|
{ error: message },
|
||||||
{ status: 503 }
|
{ status: 503 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ export async function POST() {
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Logout error:", error)
|
console.error("Logout error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Logout failed."
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ error: "Logout failed." }),
|
JSON.stringify({ error: message }),
|
||||||
{ status: 500, headers: { "Content-Type": "application/json" } }
|
{ status: 500, headers: { "Content-Type": "application/json" } }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ export async function GET() {
|
|||||||
return NextResponse.json({ user }, { status: 200 })
|
return NextResponse.json({ user }, { status: 200 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Auth me error:", error)
|
console.error("Auth me error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Authentication service unavailable."
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Authentication service unavailable." },
|
{ error: message },
|
||||||
{ status: 503 }
|
{ status: 503 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export async function POST(request: NextRequest) {
|
|||||||
}, { status: 200 })
|
}, { status: 200 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Password recovery error:", error)
|
console.error("Password recovery error:", error)
|
||||||
return NextResponse.json({ error: "Recovery service unavailable." }, { status: 503 })
|
const message = error instanceof Error ? error.message : "Recovery service unavailable."
|
||||||
|
return NextResponse.json({ error: message }, { status: 503 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ export async function PATCH(request: NextRequest, { params: routeParams }: { par
|
|||||||
return NextResponse.json({ success: true }, { status: 200 })
|
return NextResponse.json({ success: true }, { status: 200 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error updating bug report:", error)
|
console.error("Error updating bug report:", error)
|
||||||
return NextResponse.json({ error: "Failed to update bug report." }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to update bug report."
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ export async function POST(request: NextRequest) {
|
|||||||
}, { status: 201 })
|
}, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error creating bug report:", error)
|
console.error("Error creating bug report:", error)
|
||||||
return NextResponse.json({ error: "Failed to submit bug report." }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to submit bug report."
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +114,7 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json({ reports }, { status: 200 })
|
return NextResponse.json({ reports }, { status: 200 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching bug reports:", error)
|
console.error("Error fetching bug reports:", error)
|
||||||
return NextResponse.json({ error: "Failed to fetch bug reports." }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to fetch bug reports."
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|||||||
)
|
)
|
||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed" }, { status: 500 })
|
console.error("Campaign logs GET error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|||||||
|
|
||||||
return NextResponse.json({ ...campaign.rows[0], steps: steps.rows, subscribers: subscribers.rows })
|
return NextResponse.json({ ...campaign.rows[0], steps: steps.rows, subscribers: subscribers.rows })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed" }, { status: 500 })
|
console.error("Campaign GET error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +57,9 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
|||||||
await query(`UPDATE email_campaigns SET ${fields.join(", ")} WHERE id = $${idx}`, values)
|
await query(`UPDATE email_campaigns SET ${fields.join(", ")} WHERE id = $${idx}`, values)
|
||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed" }, { status: 500 })
|
console.error("Campaign PATCH error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +71,8 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise
|
|||||||
await query("UPDATE email_campaigns SET deleted_at = NOW() WHERE id = $1", [id])
|
await query("UPDATE email_campaigns SET deleted_at = NOW() WHERE id = $1", [id])
|
||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed" }, { status: 500 })
|
console.error("Campaign DELETE error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
|||||||
return NextResponse.json({ success: true, sent })
|
return NextResponse.json({ success: true, sent })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Campaign send error:", error)
|
console.error("Campaign send error:", error)
|
||||||
return NextResponse.json({ error: "Failed to send" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to send"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|||||||
const result = await query("SELECT * FROM email_campaign_steps WHERE campaign_id = $1 ORDER BY step_order", [id])
|
const result = await query("SELECT * FROM email_campaign_steps WHERE campaign_id = $1 ORDER BY step_order", [id])
|
||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed" }, { status: 500 })
|
console.error("Steps GET error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +33,8 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
|||||||
)
|
)
|
||||||
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed" }, { status: 500 })
|
console.error("Steps POST error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
|||||||
|
|
||||||
return NextResponse.json({ error: "leadIds array required" }, { status: 400 })
|
return NextResponse.json({ error: "leadIds array required" }, { status: 400 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed" }, { status: 500 })
|
console.error("Campaign subscribe POST error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ export async function GET() {
|
|||||||
)
|
)
|
||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed to load campaigns" }, { status: 500 })
|
console.error("Campaigns GET error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed to load campaigns"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +35,8 @@ export async function POST(request: NextRequest) {
|
|||||||
)
|
)
|
||||||
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed to create campaign" }, { status: 500 })
|
console.error("Campaigns POST error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed to create campaign"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ export async function DELETE(
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[voice-delete] Error:", error)
|
console.error("[voice-delete] Error:", error)
|
||||||
return NextResponse.json({ error: "Unable to delete voice note. Please try again." }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Unable to delete voice note. Please try again."
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ export async function GET(
|
|||||||
return NextResponse.json({ messages })
|
return NextResponse.json({ messages })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Messages error:", error)
|
console.error("Messages error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load messages" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load messages"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +161,8 @@ export async function POST(
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Send message error:", error)
|
console.error("Send message error:", error)
|
||||||
return NextResponse.json({ error: "Failed to send message" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to send message"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +200,8 @@ export async function DELETE(
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Delete message error:", error)
|
console.error("Delete message error:", error)
|
||||||
return NextResponse.json({ error: "Failed to delete message" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to delete message"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,6 +232,7 @@ export async function PATCH(
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Edit message error:", error)
|
console.error("Edit message error:", error)
|
||||||
return NextResponse.json({ error: "Failed to edit message" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to edit message"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export async function POST(
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Mark read error:", error)
|
console.error("Mark read error:", error)
|
||||||
return NextResponse.json({ error: "Failed to mark as read" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to mark as read"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ export async function GET() {
|
|||||||
return NextResponse.json({ conversations })
|
return NextResponse.json({ conversations })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Conversations error:", error)
|
console.error("Conversations error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load conversations" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load conversations"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +116,8 @@ export async function POST(request: NextRequest) {
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Create conversation error:", error)
|
console.error("Create conversation error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create conversation" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create conversation"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Custom fields API error:", error)
|
console.error("Custom fields API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load custom fields" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load custom fields"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +63,8 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ error: "A field with this key already exists for this entity" }, { status: 409 })
|
return NextResponse.json({ error: "A field with this key already exists for this entity" }, { status: 409 })
|
||||||
}
|
}
|
||||||
console.error("Custom fields POST error:", error)
|
console.error("Custom fields POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create custom field" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create custom field"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +108,8 @@ export async function PATCH(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Custom fields PATCH error:", error)
|
console.error("Custom fields PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to update custom field" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to update custom field"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +123,7 @@ export async function DELETE(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Custom fields DELETE error:", error)
|
console.error("Custom fields DELETE error:", error)
|
||||||
return NextResponse.json({ error: "Failed to delete custom field" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to delete custom field"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Customers API error:", error)
|
console.error("Customers API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load customers" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load customers"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json(stats)
|
return NextResponse.json(stats)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Dashboard API error:", error)
|
console.error("Dashboard API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load dashboard stats" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load dashboard stats"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export async function GET() {
|
|||||||
})) })
|
})) })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Emails GET error:", error)
|
console.error("Emails GET error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load sent emails" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load sent emails"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export async function GET() {
|
|||||||
return NextResponse.json({ users })
|
return NextResponse.json({ users })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Event users error:", error)
|
console.error("Event users error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load users" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load users"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ export async function GET(_request: NextRequest, { params }: { params: Promise<{
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("ICS GET error:", error)
|
console.error("ICS GET error:", error)
|
||||||
return NextResponse.json({ error: "Failed to generate calendar file" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to generate calendar file"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,7 +159,8 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Events PATCH error:", error)
|
console.error("Events PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to update event" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to update event"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +190,7 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Events DELETE error:", error)
|
console.error("Events DELETE error:", error)
|
||||||
return NextResponse.json({ error: "Failed to delete event" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to delete event"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,8 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json({ events })
|
return NextResponse.json({ events })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Events GET error:", error)
|
console.error("Events GET error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load events" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load events"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,6 +242,7 @@ export async function POST(request: NextRequest) {
|
|||||||
}, { status: 201 })
|
}, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Events POST error:", error)
|
console.error("Events POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create event" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create event"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ export async function POST(request: NextRequest) {
|
|||||||
const inviteUrl = `${origin}/join/${token}`
|
const inviteUrl = `${origin}/join/${token}`
|
||||||
|
|
||||||
return NextResponse.json({ token, inviteUrl })
|
return NextResponse.json({ token, inviteUrl })
|
||||||
} catch {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed to generate invite" }, { status: 500 })
|
console.error("Invite generate error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed to generate invite"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Create note error:", error)
|
console.error("Create note error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create note" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create note"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +82,7 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|||||||
return NextResponse.json(notes)
|
return NextResponse.json(notes)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Lead notes API error:", error)
|
console.error("Lead notes API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load notes" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load notes"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|||||||
return NextResponse.json(lead)
|
return NextResponse.json(lead)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Lead detail API error:", error)
|
console.error("Lead detail API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load lead" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load lead"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,6 +161,7 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
|||||||
return NextResponse.json({ success: true, id: result.rows[0].id })
|
return NextResponse.json({ success: true, id: result.rows[0].id })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Lead PATCH error:", error)
|
console.error("Lead PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to update lead" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to update lead"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json(columns)
|
return NextResponse.json(columns)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Kanban API error:", error)
|
console.error("Kanban API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load kanban data" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load kanban data"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,8 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json(leads)
|
return NextResponse.json(leads)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Leads API error:", error)
|
console.error("Leads API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load leads" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load leads"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +161,8 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Leads POST error:", error)
|
console.error("Leads POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create lead" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create lead"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +189,7 @@ export async function DELETE(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Leads DELETE error:", error)
|
console.error("Leads DELETE error:", error)
|
||||||
return NextResponse.json({ error: "Failed to delete lead" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to delete lead"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ export async function GET() {
|
|||||||
const result = await query("SELECT * FROM lead_scoring_config WHERE is_active = true ORDER BY weight DESC")
|
const result = await query("SELECT * FROM lead_scoring_config WHERE is_active = true ORDER BY weight DESC")
|
||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed to load scoring config" }, { status: 500 })
|
console.error("Scoring config GET error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed to load scoring config"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +32,9 @@ export async function POST(request: NextRequest) {
|
|||||||
if (error?.constraint === "lead_scoring_config_feature_name_key") {
|
if (error?.constraint === "lead_scoring_config_feature_name_key") {
|
||||||
return NextResponse.json({ error: "Feature name already exists" }, { status: 409 })
|
return NextResponse.json({ error: "Feature name already exists" }, { status: 409 })
|
||||||
}
|
}
|
||||||
return NextResponse.json({ error: "Failed to create feature" }, { status: 500 })
|
console.error("Scoring config POST error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed to create feature"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +60,9 @@ export async function PATCH(request: NextRequest) {
|
|||||||
await query(`UPDATE lead_scoring_config SET ${fields.join(", ")} WHERE id = $${idx}`, values)
|
await query(`UPDATE lead_scoring_config SET ${fields.join(", ")} WHERE id = $${idx}`, values)
|
||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed to update" }, { status: 500 })
|
console.error("Scoring config PATCH error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed to update"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +78,8 @@ export async function DELETE(request: NextRequest) {
|
|||||||
await query("DELETE FROM lead_scoring_config WHERE id = $1", [id])
|
await query("DELETE FROM lead_scoring_config WHERE id = $1", [id])
|
||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return NextResponse.json({ error: "Failed to delete" }, { status: 500 })
|
console.error("Scoring config DELETE error:", error)
|
||||||
|
const message = error instanceof Error ? error.message : "Failed to delete"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true, scored })
|
return NextResponse.json({ success: true, scored })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Lead scoring error:", error)
|
console.error("Lead scoring error:", error)
|
||||||
return NextResponse.json({ error: "Scoring failed" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Scoring failed"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
|||||||
return NextResponse.json({ success: true, id: result.rows[0].id })
|
return NextResponse.json({ success: true, id: result.rows[0].id })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Milestone PATCH error:", error)
|
console.error("Milestone PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to update milestone" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to update milestone"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Milestone DELETE error:", error)
|
console.error("Milestone DELETE error:", error)
|
||||||
return NextResponse.json({ error: "Failed to delete milestone" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to delete milestone"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Notification PATCH error:", error)
|
console.error("Notification PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to mark notification as read" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to mark notification as read"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Notification DELETE error:", error)
|
console.error("Notification DELETE error:", error)
|
||||||
return NextResponse.json({ error: "Failed to dismiss notification" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to dismiss notification"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ export async function GET() {
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Preferences GET error:", error)
|
console.error("Preferences GET error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load preferences" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load preferences"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ export async function PATCH(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Preferences PATCH error:", error)
|
console.error("Preferences PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to save preferences" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to save preferences"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ export async function GET() {
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Notifications GET error:", error)
|
console.error("Notifications GET error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load notifications" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load notifications"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +72,8 @@ export async function POST(request: NextRequest) {
|
|||||||
}, { status: 201 })
|
}, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Notifications POST error:", error)
|
console.error("Notifications POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create notification" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create notification"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +90,7 @@ export async function PATCH() {
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Notifications PATCH error:", error)
|
console.error("Notifications PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to mark all as read" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to mark all as read"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export async function GET() {
|
|||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Project statuses API error:", error)
|
console.error("Project statuses API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load statuses" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load statuses"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Milestones API error:", error)
|
console.error("Milestones API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load milestones" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load milestones"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
|||||||
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Milestones POST error:", error)
|
console.error("Milestones POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create milestone" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create milestone"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|||||||
return NextResponse.json(result.rows[0])
|
return NextResponse.json(result.rows[0])
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Project detail API error:", error)
|
console.error("Project detail API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load project" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load project"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +75,7 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
|||||||
return NextResponse.json({ success: true, id: result.rows[0].id })
|
return NextResponse.json({ success: true, id: result.rows[0].id })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Project PATCH error:", error)
|
console.error("Project PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to update project" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to update project"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Projects API error:", error)
|
console.error("Projects API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load projects" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load projects"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +82,8 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Projects POST error:", error)
|
console.error("Projects POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create project" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create project"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +100,7 @@ export async function DELETE(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Projects DELETE error:", error)
|
console.error("Projects DELETE error:", error)
|
||||||
return NextResponse.json({ error: "Failed to delete project" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to delete project"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export async function GET() {
|
|||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Proposal statuses API error:", error)
|
console.error("Proposal statuses API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load statuses" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load statuses"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
|||||||
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Proposal items POST error:", error)
|
console.error("Proposal items POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to add item" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to add item"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +50,8 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Proposal items DELETE error:", error)
|
console.error("Proposal items DELETE error:", error)
|
||||||
return NextResponse.json({ error: "Failed to delete item" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to delete item"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Proposal detail API error:", error)
|
console.error("Proposal detail API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load proposal" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load proposal"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +102,8 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Proposal PATCH error:", error)
|
console.error("Proposal PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to update proposal" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to update proposal"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +115,7 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Proposal DELETE error:", error)
|
console.error("Proposal DELETE error:", error)
|
||||||
return NextResponse.json({ error: "Failed to delete proposal" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to delete proposal"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
|||||||
return NextResponse.json({ success: true, id: signature.rows[0].id })
|
return NextResponse.json({ success: true, id: signature.rows[0].id })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Proposal sign error:", error)
|
console.error("Proposal sign error:", error)
|
||||||
return NextResponse.json({ error: "Failed to sign proposal" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to sign proposal"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Proposals API error:", error)
|
console.error("Proposals API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load proposals" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load proposals"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +81,7 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true, id: result.rows[0].id, proposalNumber }, { status: 201 })
|
return NextResponse.json({ success: true, id: result.rows[0].id, proposalNumber }, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Proposals POST error:", error)
|
console.error("Proposals POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create proposal" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create proposal"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json({ members, totals, period })
|
return NextResponse.json({ members, totals, period })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Resource planning API error:", error)
|
console.error("Resource planning API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load resource data" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load resource data"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ export async function GET() {
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Company settings GET error:", error)
|
console.error("Company settings GET error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load company settings" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load company settings"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ export async function PATCH(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Company settings PATCH error:", error)
|
console.error("Company settings PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to save company settings" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to save company settings"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ export async function PATCH(request: NextRequest, { params }: { params: Promise<
|
|||||||
return NextResponse.json(updated.rows[0] || { success: true })
|
return NextResponse.json(updated.rows[0] || { success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Facebook accounts PATCH error:", error)
|
console.error("Facebook accounts PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to update Facebook account" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to update Facebook account"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ export async function GET() {
|
|||||||
return NextResponse.json(accounts.rows)
|
return NextResponse.json(accounts.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Facebook accounts GET error:", error)
|
console.error("Facebook accounts GET error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load Facebook accounts" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load Facebook accounts"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +62,7 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json(result.rows[0], { status: 201 })
|
return NextResponse.json(result.rows[0], { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Facebook accounts POST error:", error)
|
console.error("Facebook accounts POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create Facebook account" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create Facebook account"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Facebook scrape logs GET error:", error)
|
console.error("Facebook scrape logs GET error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load scrape logs" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load scrape logs"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ export async function GET() {
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Preferences GET error:", error)
|
console.error("Preferences GET error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load preferences" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load preferences"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ export async function PATCH(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Preferences PATCH error:", error)
|
console.error("Preferences PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to save preferences" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to save preferences"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ export async function GET() {
|
|||||||
return NextResponse.json({ websiteTheme })
|
return NextResponse.json({ websiteTheme })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Website theme GET error:", error)
|
console.error("Website theme GET error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load website theme" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load website theme"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ export async function PUT(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true, websiteTheme: theme })
|
return NextResponse.json({ success: true, websiteTheme: theme })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Website theme PUT error:", error)
|
console.error("Website theme PUT error:", error)
|
||||||
return NextResponse.json({ error: "Failed to save website theme" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to save website theme"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Tasks POST error:", error)
|
console.error("Tasks POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create task" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create task"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +67,7 @@ export async function PATCH(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Tasks PATCH error:", error)
|
console.error("Tasks PATCH error:", error)
|
||||||
return NextResponse.json({ error: "Failed to update task" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to update task"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json(result.rows)
|
return NextResponse.json(result.rows)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Time entries API error:", error)
|
console.error("Time entries API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load time entries" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load time entries"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +82,8 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
return NextResponse.json({ success: true, id: result.rows[0].id }, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Time entries POST error:", error)
|
console.error("Time entries POST error:", error)
|
||||||
return NextResponse.json({ error: "Failed to create time entry" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to create time entry"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +97,7 @@ export async function DELETE(request: NextRequest) {
|
|||||||
return NextResponse.json({ success: true })
|
return NextResponse.json({ success: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Time entries DELETE error:", error)
|
console.error("Time entries DELETE error:", error)
|
||||||
return NextResponse.json({ error: "Failed to delete entry" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to delete entry"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ export async function GET() {
|
|||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Time summary API error:", error)
|
console.error("Time summary API error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load summary" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to load summary"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ url: `/uploads/voice/${filename}`, duration })
|
return NextResponse.json({ url: `/uploads/voice/${filename}`, duration })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Voice upload error:", error)
|
console.error("Voice upload error:", error)
|
||||||
return NextResponse.json({ error: "Upload failed" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Upload failed"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export async function DELETE(request: NextRequest, { params }: { params: Promise
|
|||||||
return NextResponse.json({ success: true }, { status: 200 })
|
return NextResponse.json({ success: true }, { status: 200 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error deleting user:", error)
|
console.error("Error deleting user:", error)
|
||||||
return NextResponse.json({ error: "Failed to delete user" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to delete user"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ avatar })
|
return NextResponse.json({ avatar })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Avatar upload error:", error)
|
console.error("Avatar upload error:", error)
|
||||||
return NextResponse.json({ error: "Failed to update avatar" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to update avatar"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json({ users }, { status: 200 })
|
return NextResponse.json({ users }, { status: 200 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching users:", error)
|
console.error("Error fetching users:", error)
|
||||||
return NextResponse.json({ error: "Failed to fetch users" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Failed to fetch users"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export async function GET(request: NextRequest) {
|
|||||||
return NextResponse.json({ users })
|
return NextResponse.json({ users })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("User search error:", error)
|
console.error("User search error:", error)
|
||||||
return NextResponse.json({ error: "Search failed" }, { status: 500 })
|
const message = error instanceof Error ? error.message : "Search failed"
|
||||||
|
return NextResponse.json({ error: message }, { status: 500 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
import { Lead, LeadStatus, User } from "@/types"
|
import { Lead, LeadStatus, User } from "@/types"
|
||||||
import { LEAD_SOURCES, LEAD_STATUSES } from "@/lib/constants"
|
import { LEAD_SOURCES, LEAD_STATUSES } from "@/lib/constants"
|
||||||
import { useNotifications } from "@/providers/notification-provider"
|
import { useNotifications } from "@/providers/notification-provider"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
const leadFormSchema = z.object({
|
const leadFormSchema = z.object({
|
||||||
companyName: z.string().min(1, "Company name is required"),
|
companyName: z.string().min(1, "Company name is required"),
|
||||||
@@ -64,7 +65,7 @@ export function LeadFormDialog({ open, onOpenChange, lead, onSuccess }: LeadForm
|
|||||||
fetch("/api/users")
|
fetch("/api/users")
|
||||||
.then((r) => r.json())
|
.then((r) => r.json())
|
||||||
.then((data) => setUsers(data.users || []))
|
.then((data) => setUsers(data.users || []))
|
||||||
.catch(() => {})
|
.catch((e) => { console.error("Failed to load users", e); toast.error("Failed to load users") })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const form = useForm<LeadFormValues>({
|
const form = useForm<LeadFormValues>({
|
||||||
@@ -134,6 +135,7 @@ export function LeadFormDialog({ open, onOpenChange, lead, onSuccess }: LeadForm
|
|||||||
onOpenChange(false)
|
onOpenChange(false)
|
||||||
onSuccess?.()
|
onSuccess?.()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
toast.error("Failed to save lead")
|
||||||
console.error("Lead save error:", e)
|
console.error("Lead save error:", e)
|
||||||
} finally {
|
} finally {
|
||||||
setSaving(false)
|
setSaving(false)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Badge } from "@/components/ui/badge"
|
|||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
import { ShieldAlert, RefreshCw } from "lucide-react"
|
import { ShieldAlert, RefreshCw } from "lucide-react"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
interface Account {
|
interface Account {
|
||||||
id: string
|
id: string
|
||||||
@@ -36,7 +37,7 @@ export function FacebookAccountsDialog({ open, onOpenChange }: { open: boolean;
|
|||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
setAccounts(await res.json())
|
setAccounts(await res.json())
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch (e) { console.error("Failed to load Facebook accounts", e); toast.error("Failed to load Facebook accounts") }
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Input } from "@/components/ui/input"
|
|||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { Plus, Trash2, RefreshCw, Gauge } from "lucide-react"
|
import { Plus, Trash2, RefreshCw, Gauge } from "lucide-react"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
interface ScoringFeature {
|
interface ScoringFeature {
|
||||||
id: string
|
id: string
|
||||||
@@ -33,26 +34,41 @@ export function LeadScoringSettings() {
|
|||||||
|
|
||||||
const addFeature = async () => {
|
const addFeature = async () => {
|
||||||
if (!newFeature.featureName) return
|
if (!newFeature.featureName) return
|
||||||
const res = await fetch("/api/leads/score/config", {
|
try {
|
||||||
method: "POST",
|
const res = await fetch("/api/leads/score/config", {
|
||||||
headers: { "Content-Type": "application/json" },
|
method: "POST",
|
||||||
body: JSON.stringify(newFeature),
|
headers: { "Content-Type": "application/json" },
|
||||||
})
|
body: JSON.stringify(newFeature),
|
||||||
if (res.ok) { setNewFeature({ featureName: "", fieldRef: "", featureType: "keyword", weight: 5 }); loadFeatures() }
|
})
|
||||||
|
if (res.ok) { setNewFeature({ featureName: "", fieldRef: "", featureType: "keyword", weight: 5 }); loadFeatures() }
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to add scoring feature", e)
|
||||||
|
toast.error("Failed to add scoring feature")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteFeature = async (id: string) => {
|
const deleteFeature = async (id: string) => {
|
||||||
await fetch(`/api/leads/score/config?id=${id}`, { method: "DELETE" })
|
try {
|
||||||
loadFeatures()
|
await fetch(`/api/leads/score/config?id=${id}`, { method: "DELETE" })
|
||||||
|
loadFeatures()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to delete scoring feature", e)
|
||||||
|
toast.error("Failed to delete scoring feature")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleFeature = async (f: ScoringFeature) => {
|
const toggleFeature = async (f: ScoringFeature) => {
|
||||||
await fetch("/api/leads/score/config", {
|
try {
|
||||||
method: "PATCH",
|
await fetch("/api/leads/score/config", {
|
||||||
headers: { "Content-Type": "application/json" },
|
method: "PATCH",
|
||||||
body: JSON.stringify({ id: f.id, isActive: !f.is_active }),
|
headers: { "Content-Type": "application/json" },
|
||||||
})
|
body: JSON.stringify({ id: f.id, isActive: !f.is_active }),
|
||||||
loadFeatures()
|
})
|
||||||
|
loadFeatures()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to toggle scoring feature", e)
|
||||||
|
toast.error("Failed to toggle scoring feature")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const runScoring = async () => {
|
const runScoring = async () => {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select"
|
||||||
import { Check, X, Pencil, Save } from "lucide-react"
|
import { Check, X, Pencil, Save } from "lucide-react"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
|
||||||
interface FieldDef {
|
interface FieldDef {
|
||||||
id: string
|
id: string
|
||||||
@@ -48,7 +49,7 @@ export function CustomFieldsSection({ entityType, customFields = {}, entityId, a
|
|||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/custom-fields?entityType=${entityType}`)
|
const res = await fetch(`/api/custom-fields?entityType=${entityType}`)
|
||||||
if (res.ok) setDefinitions(await res.json())
|
if (res.ok) setDefinitions(await res.json())
|
||||||
} catch { /* ignore */ }
|
} catch (e) { console.error("Failed to load custom fields", e); toast.error("Failed to load custom fields") }
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}, [entityType])
|
}, [entityType])
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ export function CustomFieldsSection({ entityType, customFields = {}, entityId, a
|
|||||||
body: JSON.stringify({ customFields: values }),
|
body: JSON.stringify({ customFields: values }),
|
||||||
})
|
})
|
||||||
setEditing(false)
|
setEditing(false)
|
||||||
} catch { /* ignore */ }
|
} catch (e) { console.error("Failed to save custom fields", e); toast.error("Failed to save custom fields") }
|
||||||
setSaving(false)
|
setSaving(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user