feat: add Notifications section to settings with Reports and Alerts

- Adds purpose field to report schedule API client
- Adds useAlertSchedules SWR hook
- Reorganizes settings: Reports tab becomes Notifications tab
- Groups existing Reports and new Alerts subsections
- Alert channels reuse report delivery infrastructure (email, Slack, Discord, webhooks)
This commit is contained in:
Usman Baig
2026-03-22 16:57:04 +01:00
parent 1d26819727
commit 6a1698b794
3 changed files with 460 additions and 126 deletions

View File

@@ -10,6 +10,7 @@ export interface ReportSchedule {
timezone: string
enabled: boolean
report_type: 'summary' | 'pages' | 'sources' | 'goals'
purpose: 'report' | 'alert'
send_hour: number
send_day: number | null
next_send_at: string | null
@@ -33,6 +34,7 @@ export interface CreateReportScheduleRequest {
frequency: string
timezone?: string
report_type?: string
purpose?: 'report' | 'alert'
send_hour?: number
send_day?: number
}
@@ -43,6 +45,7 @@ export interface UpdateReportScheduleRequest {
frequency?: string
timezone?: string
report_type?: string
purpose?: 'report' | 'alert'
enabled?: boolean
send_hour?: number
send_day?: number
@@ -73,6 +76,11 @@ export async function deleteReportSchedule(siteId: string, scheduleId: string):
})
}
export async function listAlertSchedules(siteId: string): Promise<ReportSchedule[]> {
const res = await apiRequest<{ report_schedules: ReportSchedule[] }>(`/sites/${siteId}/report-schedules?purpose=alert`)
return res?.report_schedules ?? []
}
export async function testReportSchedule(siteId: string, scheduleId: string): Promise<void> {
await apiRequest(`/sites/${siteId}/report-schedules/${scheduleId}/test`, {
method: 'POST',

View File

@@ -32,7 +32,7 @@ import type { Site } from '@/lib/api/sites'
import { listFunnels, type Funnel } from '@/lib/api/funnels'
import { getUptimeStatus, type UptimeStatusResponse } from '@/lib/api/uptime'
import { listGoals, type Goal } from '@/lib/api/goals'
import { listReportSchedules, type ReportSchedule } from '@/lib/api/report-schedules'
import { listReportSchedules, listAlertSchedules, type ReportSchedule } from '@/lib/api/report-schedules'
import { listSessions, getBotFilterStats, type SessionSummary, type BotFilterStats } from '@/lib/api/bot-filter'
import { getGSCStatus, getGSCOverview, getGSCTopQueries, getGSCTopPages, getGSCDailyTotals, getGSCNewQueries } from '@/lib/api/gsc'
import type { GSCStatus, GSCOverview, GSCQueryResponse, GSCPageResponse, GSCDailyTotal, GSCNewQueries } from '@/lib/api/gsc'
@@ -81,6 +81,7 @@ const fetchers = {
uptimeStatus: (siteId: string) => getUptimeStatus(siteId),
goals: (siteId: string) => listGoals(siteId),
reportSchedules: (siteId: string) => listReportSchedules(siteId),
alertSchedules: (siteId: string) => listAlertSchedules(siteId),
gscStatus: (siteId: string) => getGSCStatus(siteId),
gscOverview: (siteId: string, start: string, end: string) => getGSCOverview(siteId, start, end),
gscTopQueries: (siteId: string, start: string, end: string, limit: number, offset: number) => getGSCTopQueries(siteId, start, end, limit, offset),
@@ -411,6 +412,19 @@ export function useReportSchedules(siteId: string) {
)
}
// * Hook for alert schedules (uptime alerts)
export function useAlertSchedules(siteId: string) {
return useSWR<ReportSchedule[]>(
siteId ? ['alertSchedules', siteId] : null,
() => fetchers.alertSchedules(siteId),
{
...dashboardSWRConfig,
refreshInterval: 60 * 1000,
dedupingInterval: 10 * 1000,
}
)
}
// * Hook for GSC connection status
export function useGSCStatus(siteId: string) {
return useSWR<GSCStatus>(