147 lines
4.2 KiB
Plaintext
147 lines
4.2 KiB
Plaintext
import supa from '@/components/supadb/aksupainstance.uts'
|
|
|
|
export type AnalyticsReport = {
|
|
id: string
|
|
title: string
|
|
type: string
|
|
period: string
|
|
generated_at: string
|
|
description: string
|
|
}
|
|
|
|
export type AnalyticsReportMetric = {
|
|
key: string
|
|
label: string
|
|
value: number
|
|
format: string
|
|
icon: string
|
|
color: string
|
|
change: number
|
|
}
|
|
|
|
export type AnalyticsReportRow = {
|
|
row_date: string
|
|
gmv: number
|
|
orders: number
|
|
users: number
|
|
conversion: number
|
|
avg_order_amount: number
|
|
}
|
|
|
|
export type AnalyticsInsight = {
|
|
id: string
|
|
type: string
|
|
title: string
|
|
content: string
|
|
impact: string
|
|
}
|
|
|
|
export type AnalyticsRelatedReport = AnalyticsReport
|
|
|
|
function safeNumber(v: any): number {
|
|
const n = Number(v)
|
|
return isFinite(n) ? n : 0
|
|
}
|
|
|
|
export async function fetchReport(reportId: string): Promise<AnalyticsReport | null> {
|
|
const reportRes: any = await supa
|
|
.from('analytics_reports')
|
|
.select('id, title, type, period, generated_at, description')
|
|
.eq('id', reportId)
|
|
|
|
if (reportRes?.error != null) throw reportRes.error
|
|
|
|
const rows: Array<any> = Array.isArray(reportRes.data) ? (reportRes.data as Array<any>) : []
|
|
if (rows.length === 0) return null
|
|
const r = rows[0]
|
|
return {
|
|
id: `${r.id}`,
|
|
title: `${r.title}`,
|
|
type: `${r.type}`,
|
|
period: `${r.period}`,
|
|
generated_at: `${r.generated_at}`,
|
|
description: `${r.description || ''}`
|
|
}
|
|
}
|
|
|
|
export async function fetchReportMetrics(reportId: string): Promise<Array<AnalyticsReportMetric>> {
|
|
const metricRes: any = await supa
|
|
.from('analytics_report_metrics')
|
|
.select('metric_key, metric_label, metric_value_num, format, icon, color, change_pct')
|
|
.eq('report_id', reportId)
|
|
|
|
if (metricRes?.error != null) throw metricRes.error
|
|
|
|
const metricRows: Array<any> = Array.isArray(metricRes.data) ? (metricRes.data as Array<any>) : []
|
|
return metricRows.map((m: any) => ({
|
|
key: `${m.metric_key}`,
|
|
label: `${m.metric_label}`,
|
|
value: safeNumber(m.metric_value_num),
|
|
format: `${m.format || 'number'}`,
|
|
icon: `${m.icon || '📊'}`,
|
|
color: `${m.color || '#4caf50'}`,
|
|
change: safeNumber(m.change_pct)
|
|
}))
|
|
}
|
|
|
|
export async function fetchReportRows(reportId: string): Promise<Array<AnalyticsReportRow>> {
|
|
const rowsRes: any = await supa
|
|
.from('analytics_report_rows')
|
|
.select('row_date, gmv, orders, users, conversion, avg_order_amount')
|
|
.eq('report_id', reportId)
|
|
.order('row_date', { ascending: true } as any)
|
|
|
|
if (rowsRes?.error != null) throw rowsRes.error
|
|
|
|
const rows: Array<any> = Array.isArray(rowsRes.data) ? (rowsRes.data as Array<any>) : []
|
|
return rows.map((row: any) => ({
|
|
row_date: `${row.row_date}`,
|
|
gmv: safeNumber(row.gmv),
|
|
orders: safeNumber(row.orders),
|
|
users: safeNumber(row.users),
|
|
conversion: safeNumber(row.conversion),
|
|
avg_order_amount: safeNumber(row.avg_order_amount)
|
|
}))
|
|
}
|
|
|
|
export async function fetchReportInsights(reportId: string): Promise<Array<AnalyticsInsight>> {
|
|
const insightRes: any = await supa
|
|
.from('analytics_insights')
|
|
.select('id, type, title, content, impact')
|
|
.eq('report_id', reportId)
|
|
.order('created_at', { ascending: false } as any)
|
|
|
|
if (insightRes?.error != null) throw insightRes.error
|
|
|
|
const insRows: Array<any> = Array.isArray(insightRes.data) ? (insightRes.data as Array<any>) : []
|
|
return insRows.map((it: any) => ({
|
|
id: `${it.id}`,
|
|
type: `${it.type || 'info'}`,
|
|
title: `${it.title}`,
|
|
content: `${it.content}`,
|
|
impact: `${it.impact || 'medium'}`
|
|
}))
|
|
}
|
|
|
|
export async function fetchRelatedReports(reportType: string, excludeReportId: string): Promise<Array<AnalyticsRelatedReport>> {
|
|
const relatedRes: any = await supa
|
|
.from('analytics_reports')
|
|
.select('id, title, type, period, generated_at, description')
|
|
.eq('type', reportType)
|
|
.neq('id', excludeReportId)
|
|
.order('generated_at', { ascending: false } as any)
|
|
.limit(3 as any)
|
|
|
|
if (relatedRes?.error != null) throw relatedRes.error
|
|
|
|
const relRows: Array<any> = Array.isArray(relatedRes.data) ? (relatedRes.data as Array<any>) : []
|
|
return relRows.map((it: any) => ({
|
|
id: `${it.id}`,
|
|
title: `${it.title}`,
|
|
type: `${it.type}`,
|
|
period: `${it.period}`,
|
|
generated_at: `${it.generated_at}`,
|
|
description: `${it.description || ''}`
|
|
}))
|
|
}
|