diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d11eb4..10ba0cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), - **Smoother loading experience.** Pages now show a subtle preview of the layout while data loads instead of a blank screen or spinner. This applies everywhere — dashboards, settings, uptime, funnels, notifications, billing, and detail modals. - **No more loading flicker.** Fast-loading pages no longer flash a loading state for a split second before showing content. +- **Clearer error messages.** When something goes wrong, the error message now tells you what failed (e.g. "Failed to load uptime monitors") instead of a generic "Failed to load data". ## [0.10.0-alpha] - 2026-02-21 diff --git a/app/page.tsx b/app/page.tsx index 15cc2ae..ab4817e 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -170,7 +170,7 @@ export default function HomePage() { const data = await listSites() setSites(Array.isArray(data) ? data : []) } catch (error: any) { - toast.error(getAuthErrorMessage(error) || 'Failed to load sites: ' + ((error as Error)?.message || 'Unknown error')) + toast.error(getAuthErrorMessage(error) || 'Failed to load your sites') setSites([]) } finally { setSitesLoading(false) @@ -199,7 +199,7 @@ export default function HomePage() { toast.success('Site deleted successfully') loadSites() } catch (error: any) { - toast.error(getAuthErrorMessage(error) || 'Failed to delete site: ' + ((error as Error)?.message || 'Unknown error')) + toast.error(getAuthErrorMessage(error) || 'Failed to delete site') } } diff --git a/app/share/[id]/page.tsx b/app/share/[id]/page.tsx index 7a1b04f..d645fe7 100644 --- a/app/share/[id]/page.tsx +++ b/app/share/[id]/page.tsx @@ -166,7 +166,7 @@ export default function PublicDashboardPage() { } else if (error.status === 404 || error.response?.status === 404) { toast.error('Site not found') } else if (!silent) { - toast.error(getAuthErrorMessage(error) || 'Failed to load dashboard: ' + ((error as Error)?.message || 'Unknown error')) + toast.error(getAuthErrorMessage(error) || 'Failed to load public dashboard') } } finally { if (!silent) setLoading(false) diff --git a/app/sites/[id]/funnels/[funnelId]/page.tsx b/app/sites/[id]/funnels/[funnelId]/page.tsx index 7bcd8ea..4b7c0bc 100644 --- a/app/sites/[id]/funnels/[funnelId]/page.tsx +++ b/app/sites/[id]/funnels/[funnelId]/page.tsx @@ -64,7 +64,7 @@ export default function FunnelReportPage() { if (status === 404) setLoadError('not_found') else if (status === 403) setLoadError('forbidden') else setLoadError('error') - if (status !== 404 && status !== 403) toast.error('Failed to load funnel data') + if (status !== 404 && status !== 403) toast.error('Failed to load funnel details') } finally { setLoading(false) } diff --git a/app/sites/[id]/funnels/new/page.tsx b/app/sites/[id]/funnels/new/page.tsx index 187ad5a..50da204 100644 --- a/app/sites/[id]/funnels/new/page.tsx +++ b/app/sites/[id]/funnels/new/page.tsx @@ -84,7 +84,7 @@ export default function CreateFunnelPage() { toast.success('Funnel created') router.push(`/sites/${siteId}/funnels`) } catch (error) { - toast.error('Failed to create funnel') + toast.error('Failed to create funnel. Please try again.') } finally { setSaving(false) } diff --git a/app/sites/[id]/funnels/page.tsx b/app/sites/[id]/funnels/page.tsx index e1ab641..a7b5726 100644 --- a/app/sites/[id]/funnels/page.tsx +++ b/app/sites/[id]/funnels/page.tsx @@ -21,7 +21,7 @@ export default function FunnelsPage() { const data = await listFunnels(siteId) setFunnels(data) } catch (error) { - toast.error('Failed to load funnels') + toast.error('Failed to load your funnels') } finally { setLoading(false) } diff --git a/app/sites/[id]/page.tsx b/app/sites/[id]/page.tsx index 274b7ec..7010baa 100644 --- a/app/sites/[id]/page.tsx +++ b/app/sites/[id]/page.tsx @@ -191,7 +191,7 @@ export default function SiteDashboardPage() { setLastUpdatedAt(Date.now()) } catch (error: unknown) { if (!silent) { - toast.error(getAuthErrorMessage(error) || 'Failed to load data: ' + ((error as Error)?.message || 'Unknown error')) + toast.error(getAuthErrorMessage(error) || 'Failed to load dashboard analytics') } } finally { if (!silent) setLoading(false) diff --git a/app/sites/[id]/realtime/page.tsx b/app/sites/[id]/realtime/page.tsx index a8ed5ca..632045b 100644 --- a/app/sites/[id]/realtime/page.tsx +++ b/app/sites/[id]/realtime/page.tsx @@ -48,7 +48,7 @@ export default function RealtimePage() { handleSelectVisitor(visitorsData[0]) } } catch (error: unknown) { - toast.error(getAuthErrorMessage(error) || 'Failed to load data') + toast.error(getAuthErrorMessage(error) || 'Failed to load realtime visitors') } finally { setLoading(false) } @@ -85,7 +85,7 @@ export default function RealtimePage() { const events = await getSessionDetails(siteId, visitor.session_id) setSessionEvents(events || []) } catch (error: unknown) { - toast.error(getAuthErrorMessage(error) || 'Failed to load session details') + toast.error(getAuthErrorMessage(error) || 'Failed to load session events') } finally { setLoadingEvents(false) } diff --git a/app/sites/[id]/settings/page.tsx b/app/sites/[id]/settings/page.tsx index 5b10014..9c90e27 100644 --- a/app/sites/[id]/settings/page.tsx +++ b/app/sites/[id]/settings/page.tsx @@ -152,7 +152,7 @@ export default function SiteSettingsPage() { setIsPasswordEnabled(false) } } catch (error: any) { - toast.error(getAuthErrorMessage(error) || 'Failed to load site: ' + ((error as Error)?.message || 'Unknown error')) + toast.error(getAuthErrorMessage(error) || 'Failed to load site settings') } finally { setLoading(false) } @@ -266,7 +266,7 @@ export default function SiteSettingsPage() { toast.success('Site updated successfully') loadSite() } catch (error: any) { - toast.error(getAuthErrorMessage(error) || 'Failed to update site: ' + ((error as Error)?.message || 'Unknown error')) + toast.error(getAuthErrorMessage(error) || 'Failed to save site settings') } finally { setSaving(false) } @@ -281,7 +281,7 @@ export default function SiteSettingsPage() { await resetSiteData(siteId) toast.success('All site data has been reset') } catch (error: any) { - toast.error(getAuthErrorMessage(error) || 'Failed to reset data: ' + ((error as Error)?.message || 'Unknown error')) + toast.error(getAuthErrorMessage(error) || 'Failed to reset site data') } } @@ -297,7 +297,7 @@ export default function SiteSettingsPage() { toast.success('Site deleted successfully') router.push('/') } catch (error: any) { - toast.error(getAuthErrorMessage(error) || 'Failed to delete site: ' + ((error as Error)?.message || 'Unknown error')) + toast.error(getAuthErrorMessage(error) || 'Failed to delete site') } } diff --git a/app/sites/[id]/uptime/page.tsx b/app/sites/[id]/uptime/page.tsx index d746d93..2ead55b 100644 --- a/app/sites/[id]/uptime/page.tsx +++ b/app/sites/[id]/uptime/page.tsx @@ -615,7 +615,7 @@ export default function UptimePage() { setSite(siteData) setUptimeData(statusData) } catch (error: unknown) { - toast.error(getAuthErrorMessage(error) || 'Failed to load uptime data') + toast.error(getAuthErrorMessage(error) || 'Failed to load uptime monitors') } finally { setLoading(false) } diff --git a/app/sites/new/page.tsx b/app/sites/new/page.tsx index cdcd4d1..0dd1829 100644 --- a/app/sites/new/page.tsx +++ b/app/sites/new/page.tsx @@ -87,7 +87,7 @@ export default function NewSitePage() { sessionStorage.setItem(LAST_CREATED_SITE_KEY, JSON.stringify({ id: site.id })) } } catch (error: unknown) { - toast.error(getAuthErrorMessage(error) || 'Failed to create site: ' + ((error as Error)?.message || 'Unknown error')) + toast.error(getAuthErrorMessage(error) || 'Failed to create site. Please try again.') } finally { setLoading(false) } diff --git a/app/welcome/page.tsx b/app/welcome/page.tsx index 295b374..f7a6bac 100644 --- a/app/welcome/page.tsx +++ b/app/welcome/page.tsx @@ -162,7 +162,7 @@ function WelcomeContent() { setStep(3) } } catch (err) { - toast.error(getAuthErrorMessage(err) || 'Failed to switch organization') + toast.error(getAuthErrorMessage(err) || 'Failed to switch workspace') } finally { setSwitchingOrgId(null) } diff --git a/components/PricingSection.tsx b/components/PricingSection.tsx index 41e346f..81eb656 100644 --- a/components/PricingSection.tsx +++ b/components/PricingSection.tsx @@ -205,7 +205,7 @@ export default function PricingSection() { } catch (error: any) { console.error('Checkout error:', error) - toast.error('Failed to start checkout. Please try again.') + toast.error('Failed to start checkout — please try again') } finally { setLoadingPlan(null) } diff --git a/components/settings/OrganizationSettings.tsx b/components/settings/OrganizationSettings.tsx index bef72b3..28bd657 100644 --- a/components/settings/OrganizationSettings.tsx +++ b/components/settings/OrganizationSettings.tsx @@ -248,7 +248,7 @@ export default function OrganizationSettings() { setAuditTotal(typeof total === 'number' ? total : 0) } catch (error) { console.error('Failed to load audit log', error) - toast.error(getAuthErrorMessage(error as Error) || 'Failed to load audit log') + toast.error(getAuthErrorMessage(error as Error) || 'Failed to load audit log entries') } finally { setIsLoadingAudit(false) } @@ -333,7 +333,7 @@ export default function OrganizationSettings() { const { url } = await createPortalSession() window.location.href = url } catch (error: any) { - toast.error(getAuthErrorMessage(error) || error.message || 'Failed to redirect to billing portal') + toast.error(getAuthErrorMessage(error) || error.message || 'Failed to open billing portal') setIsRedirectingToPortal(false) } } @@ -398,7 +398,7 @@ export default function OrganizationSettings() { else throw new Error('No checkout URL') } } catch (error: any) { - toast.error(getAuthErrorMessage(error) || error.message || 'Something went wrong.') + toast.error(getAuthErrorMessage(error) || error.message || 'Failed to update member role') } finally { setIsChangingPlan(false) } @@ -484,7 +484,7 @@ export default function OrganizationSettings() { setIsEditing(false) loadMembers() } catch (error: any) { - toast.error(getAuthErrorMessage(error) || error.message || 'Failed to update organization') + toast.error(getAuthErrorMessage(error) || error.message || 'Failed to save organization settings') } finally { setIsSaving(false) } @@ -1145,7 +1145,7 @@ export default function OrganizationSettings() { toast.success('Notification settings updated') }) .catch((err) => { - toast.error(getAuthErrorMessage(err) || 'Failed to update settings') + toast.error(getAuthErrorMessage(err) || 'Failed to save notification preferences') setNotificationSettings(prev) }) .finally(() => setIsSavingNotificationSettings(false)) diff --git a/docs/DESIGN_SYSTEM.md b/docs/DESIGN_SYSTEM.md index b6cfa30..91f7bd2 100644 --- a/docs/DESIGN_SYSTEM.md +++ b/docs/DESIGN_SYSTEM.md @@ -405,8 +405,8 @@ toast.success('Site created successfully') **Error Toast:** ```tsx -toast.error('Failed to load data') -// Red toast with X icon +toast.error('Failed to load uptime monitors') +// Red toast with X icon — always mention what failed ``` **Error Display:**