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:
@@ -15,6 +15,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select"
|
||||
import { toast } from "sonner"
|
||||
|
||||
export default function ProposalDetailPage() {
|
||||
const { id } = useParams<{ id: string }>()
|
||||
@@ -35,6 +36,7 @@ export default function ProposalDetailPage() {
|
||||
setProposal(await pRes.json())
|
||||
setStatuses(await sRes.json())
|
||||
} catch (e) {
|
||||
toast.error("Failed to load proposal")
|
||||
console.error("Failed to load proposal", e)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
@@ -44,12 +46,17 @@ export default function ProposalDetailPage() {
|
||||
useEffect(() => { fetchProposal() }, [fetchProposal])
|
||||
|
||||
const updateStatus = async (statusId: string) => {
|
||||
await fetch(`/api/proposals/${id}`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ statusId }),
|
||||
})
|
||||
fetchProposal()
|
||||
try {
|
||||
await fetch(`/api/proposals/${id}`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ statusId }),
|
||||
})
|
||||
fetchProposal()
|
||||
} catch (e) {
|
||||
console.error("Failed to update proposal status", e)
|
||||
toast.error("Failed to update proposal status")
|
||||
}
|
||||
}
|
||||
|
||||
const handleSign = async () => {
|
||||
@@ -62,6 +69,9 @@ export default function ProposalDetailPage() {
|
||||
body: JSON.stringify({ name: signName, email: signEmail }),
|
||||
})
|
||||
if (res.ok) fetchProposal()
|
||||
} catch (e) {
|
||||
console.error("Failed to sign proposal", e)
|
||||
toast.error("Failed to sign proposal")
|
||||
} finally {
|
||||
setSigning(false)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select"
|
||||
import { toast } from "sonner"
|
||||
|
||||
interface LineItem {
|
||||
id: string
|
||||
@@ -39,8 +40,8 @@ export default function NewProposalPage() {
|
||||
const [saving, setSaving] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/leads?limit=100").then((r) => r.json()).then(setLeads).catch(() => {})
|
||||
fetch("/api/customers?limit=100").then((r) => r.json()).then(setCustomers).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((e) => { console.error("Failed to load customers", e); toast.error("Failed to load customers") })
|
||||
}, [])
|
||||
|
||||
const addItem = () => {
|
||||
@@ -107,6 +108,7 @@ export default function NewProposalPage() {
|
||||
|
||||
router.push(`/proposals/${data.id}`)
|
||||
} catch (e) {
|
||||
toast.error("Failed to create proposal")
|
||||
console.error("Failed to create proposal", e)
|
||||
} finally {
|
||||
setSaving(false)
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select"
|
||||
import { toast } from "sonner"
|
||||
|
||||
export default function ProposalsPage() {
|
||||
const router = useRouter()
|
||||
@@ -31,12 +32,12 @@ export default function ProposalsPage() {
|
||||
fetch(`/api/proposals?${params}`)
|
||||
.then((r) => r.json())
|
||||
.then(setProposals)
|
||||
.catch(() => {})
|
||||
.catch((e) => { console.error("Failed to load proposals", e); toast.error("Failed to load proposals") })
|
||||
.finally(() => setLoading(false))
|
||||
}, [search, statusFilter])
|
||||
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user