feat(family): deploy Single-Writer DuckDB backend, Mila parent cockpit & feeding analytics, and Moritz macro tracker
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import type { MilaDashboardData, DayDetailData } from './types'
|
||||
|
||||
const API_BASE = '/duckdb-api/v1'
|
||||
|
||||
export function getLocalDateString(): string {
|
||||
const d = new Date()
|
||||
const year = d.getFullYear()
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
export async function fetchMilaDashboard(asOf?: string): Promise<MilaDashboardData> {
|
||||
const url = asOf ? `${API_BASE}/mila/dashboard?as_of=${encodeURIComponent(asOf)}` : `${API_BASE}/mila/dashboard`
|
||||
const res = await fetch(url)
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to fetch dashboard: ${res.status} ${res.statusText}`)
|
||||
}
|
||||
return res.json()
|
||||
}
|
||||
|
||||
export async function fetchMilaDayDetail(date: string): Promise<DayDetailData> {
|
||||
const res = await fetch(`${API_BASE}/mila/day/${encodeURIComponent(date)}`)
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to fetch day detail for ${date}: ${res.statusText}`)
|
||||
}
|
||||
return res.json()
|
||||
}
|
||||
|
||||
export async function logEvent(payload: {
|
||||
kind: string
|
||||
subject: string
|
||||
payload: Record<string, any>
|
||||
start?: string
|
||||
end?: string
|
||||
date?: string
|
||||
since?: string
|
||||
note?: string
|
||||
actor?: string
|
||||
}): Promise<any> {
|
||||
const res = await fetch(`${API_BASE}/events`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({ detail: res.statusText }))
|
||||
throw new Error(err.detail || 'Failed to log event')
|
||||
}
|
||||
return res.json()
|
||||
}
|
||||
|
||||
export async function stopSleepEvent(payload: {
|
||||
subject: string
|
||||
end_time?: string
|
||||
since?: string
|
||||
event_id?: string
|
||||
}): Promise<any> {
|
||||
const res = await fetch(`${API_BASE}/events/stop`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
kind: 'sleep.session',
|
||||
...payload,
|
||||
}),
|
||||
})
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({ detail: res.statusText }))
|
||||
throw new Error(err.detail || 'Failed to stop sleep event')
|
||||
}
|
||||
return res.json()
|
||||
}
|
||||
|
||||
export async function deleteEvent(eventId: string): Promise<any> {
|
||||
const res = await fetch(`${API_BASE}/events/${encodeURIComponent(eventId)}`, {
|
||||
method: 'DELETE',
|
||||
})
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({ detail: res.statusText }))
|
||||
throw new Error(err.detail || 'Failed to delete event')
|
||||
}
|
||||
return res.json()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user