Files
wgBill/frontend/src/api.ts
T
dodox d97aac0e17 Initial scaffold: Flask/SQLite backend, React/Vite PWA frontend
Backend: receipt upload -> LLM vision extraction (OpenAI-compatible,
provider-agnostic), item review/edit, per-group splitting against
Cospend projects/members, highlight+upload via WebDAV, public share
link, bill creation via Cospend's OCS API (verified against real
source, not just doc summaries).

Frontend: capture -> review -> group -> summary flow as an installable
PWA.

install.sh / run.sh (venv + npm, tmux session) instead of Docker, per
the ~/Projects/gain pattern.
2026-08-30 15:02:18 +02:00

67 lines
2.1 KiB
TypeScript

import type { CospendProject, Group, Item, Member, Receipt, SubmitResult } from './types'
const BASE = import.meta.env.VITE_API_BASE_URL ?? ''
async function req<T>(path: string, init?: RequestInit): Promise<T> {
const res = await fetch(`${BASE}/api${path}`, {
...init,
headers: init?.body instanceof FormData ? init.headers : { 'Content-Type': 'application/json', ...init?.headers },
})
if (!res.ok) {
const body = await res.json().catch(() => ({}))
throw new Error(body.error || `${res.status} ${res.statusText}`)
}
return res.json()
}
export const api = {
uploadReceipt(
file: File | Blob,
): Promise<{ id: string; items: Item[]; store_name: string | null; date: string }> {
const form = new FormData()
form.append('image', file, 'receipt.jpg')
return req('/receipts', { method: 'POST', body: form })
},
getReceipt(id: string): Promise<Receipt> {
return req(`/receipts/${id}`)
},
updateItems(id: string, items: Item[]): Promise<Receipt> {
return req(`/receipts/${id}/items`, { method: 'PATCH', body: JSON.stringify({ items }) })
},
updateMeta(id: string, meta: { store_name?: string; date?: string }): Promise<Receipt> {
return req(`/receipts/${id}/meta`, { method: 'PATCH', body: JSON.stringify(meta) })
},
getProjects(): Promise<{ projects: CospendProject[]; default_project_id: string | null }> {
return req('/cospend/projects')
},
getMembers(projectId: string): Promise<Member[]> {
return req(`/cospend/projects/${projectId}/members`)
},
createGroup(
receiptId: string,
group: {
name: string
cospend_project_id: string
payer_member_id: string
member_ids: string[]
item_ids: string[]
},
): Promise<{ id: string }> {
return req(`/receipts/${receiptId}/groups`, { method: 'POST', body: JSON.stringify(group) })
},
submitGroup(receiptId: string, groupId: string): Promise<SubmitResult> {
return req(`/receipts/${receiptId}/groups/${groupId}/submit`, { method: 'POST' })
},
listGroups(receiptId: string): Promise<Group[]> {
return req(`/receipts/${receiptId}/groups`)
},
}