fiddy/apps/web/lib/client/recurring-entries.ts
Nico f8e426542d
Some checks failed
Build & Deploy Fiddy (Dokploy) / build (push) Has been cancelled
Build & Deploy Fiddy (Dokploy) / deploy (push) Has been cancelled
feat: implement schedules pivot, scheduler service, and dokploy deploy flow
2026-02-15 17:10:58 -08:00

94 lines
3.1 KiB
TypeScript

import { fetchJson } from "@/lib/client/fetch-json";
export type RecurringEntryCompat = {
id: number;
entryType: "SPENDING" | "INCOME";
amountDollars: number;
occurredAt: string;
necessity: "NECESSARY" | "BOTH" | "UNNECESSARY";
purchaseType: string;
notes: string | null;
receiptId: number | null;
bucketId: number | null;
tags: string[];
isRecurring: true;
frequency: "DAILY" | "WEEKLY" | "MONTHLY" | "YEARLY";
intervalCount: number;
endCondition: "NEVER" | "AFTER_COUNT" | "BY_DATE";
endCount: number | null;
endDate: string | null;
nextRunAt: string | null;
lastExecutedAt: string | null;
};
export async function recurringEntriesList() {
return fetchJson<{ entries: RecurringEntryCompat[] }>("/api/recurring-entries", { method: "GET" });
}
export async function recurringEntriesCreate(input: {
entryType: "SPENDING" | "INCOME";
amountDollars: number;
occurredAt: string;
necessity: "NECESSARY" | "BOTH" | "UNNECESSARY";
purchaseType: string;
notes?: string;
tags?: string[];
bucketId?: number | null;
frequency?: "DAILY" | "WEEKLY" | "MONTHLY" | "YEARLY" | null;
intervalCount?: number;
endCondition?: "NEVER" | "AFTER_COUNT" | "BY_DATE" | null;
endCount?: number | null;
endDate?: string | null;
nextRunAt?: string | null;
}) {
return fetchJson<{ entry: RecurringEntryCompat }>("/api/recurring-entries", {
method: "POST",
body: JSON.stringify(input)
});
}
export async function recurringEntriesUpdate(input: {
id: number;
entryType: "SPENDING" | "INCOME";
amountDollars: number;
occurredAt: string;
necessity: "NECESSARY" | "BOTH" | "UNNECESSARY";
purchaseType: string;
notes?: string;
tags?: string[];
bucketId?: number | null;
frequency?: "DAILY" | "WEEKLY" | "MONTHLY" | "YEARLY" | null;
intervalCount?: number;
endCondition?: "NEVER" | "AFTER_COUNT" | "BY_DATE" | null;
endCount?: number | null;
endDate?: string | null;
nextRunAt?: string | null;
}) {
return fetchJson<{ entry: RecurringEntryCompat }>(`/api/recurring-entries/${input.id}`, {
method: "PATCH",
body: JSON.stringify({
entryType: input.entryType,
amountDollars: input.amountDollars,
occurredAt: input.occurredAt,
necessity: input.necessity,
purchaseType: input.purchaseType,
notes: input.notes,
tags: input.tags,
bucketId: input.bucketId,
frequency: input.frequency,
intervalCount: input.intervalCount,
endCondition: input.endCondition,
endCount: input.endCount,
endDate: input.endDate,
nextRunAt: input.nextRunAt
})
});
}
export async function recurringEntriesDelete(input: { id: number | string }) {
const numericId = Number(input.id);
if (!Number.isFinite(numericId) || numericId <= 0)
return { error: { code: "INVALID_ID", message: "Invalid id" } } as const;
return fetchJson<{ ok: true }>(`/api/recurring-entries/${numericId}`, { method: "DELETE" });
}