added todos | payday time settings | refactor payment scheduling

This commit is contained in:
JCEEE
2026-08-04 08:34:14 +01:00
parent ccbbd302d4
commit 85ea97ae96
16 changed files with 2877 additions and 659 deletions
+3
View File
@@ -39,4 +39,7 @@ export const memberApi = {
async requestAllRewards(token: string, famId: string) {
return memberFetch<{ count: number }>('POST', '/api/members/rewards/request-all', token, famId);
},
async payday(token: string, famId: string) {
return memberFetch('POST', `/api/fam/${famId}/payday`, token, famId);
},
};
+38 -4
View File
@@ -24,8 +24,17 @@ async function request(
headers: headers || { 'Content-Type': 'application/json' },
body: body ? JSON.stringify(body) : undefined
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || `${method} ${path} failed`);
const text = await res.text();
let data: any = {};
try {
data = text ? JSON.parse(text) : {};
} catch {
data = { raw: text };
}
if (!res.ok) {
const msg = data?.error || data?.message || `${method} ${path} failed (HTTP ${res.status})`;
throw new Error(msg);
}
return data;
}
@@ -62,8 +71,19 @@ export const hono = {
async renameFam(event: RequestEvent, famId: string, name: string) {
return request('PATCH', `/api/admin/${famId}/fam`, { name }, sessionHeaders(event));
},
async updatePayday(event: RequestEvent, famId: string, payday: number) {
return request('PATCH', `/api/admin/${famId}/fam`, { payday }, sessionHeaders(event));
async updatePayday(
event: RequestEvent,
famId: string,
payday: number,
paydayTime?: string,
timezone?: string
) {
return request(
'PATCH',
`/api/admin/${famId}/fam`,
{ payday, ...(paydayTime !== undefined ? { paydayTime } : {}), ...(timezone !== undefined ? { timezone } : {}) },
sessionHeaders(event)
);
},
async fam(event: RequestEvent, famId: string) {
return request('GET', `/api/admin/${famId}/fam`, undefined, sessionHeaders(event));
@@ -216,6 +236,20 @@ export const hono = {
},
async request(event: RequestEvent, method: string, path: string, body?: unknown) {
return request(method, path, body, sessionHeaders(event));
},
async settings(event: RequestEvent, famId: string) {
return request('GET', `/api/admin/${famId}/settings`, undefined, sessionHeaders(event));
},
async updateSettings(event: RequestEvent, famId: string, data: Record<string, unknown>) {
return request('PATCH', `/api/admin/${famId}/settings`, data, sessionHeaders(event));
},
async eowPreview(event: RequestEvent, famId: string) {
return request(
'GET',
`/api/admin/${famId}/debug/eow-preview`,
undefined,
sessionHeaders(event)
);
}
}
};
+11 -3
View File
@@ -1,5 +1,5 @@
export type Frequency = 'daily' | 'weekly';
export type RewardType = 'points' | 'money';
export type RewardType = 'points' | 'money' | 'emoji';
export type BonusTarget = 'individual' | 'competitive' | 'collaborative';
export type BonusType = 'threshold' | 'count' | 'manual';
export type BonusOccurrence = 'recurring' | 'once';
@@ -43,6 +43,10 @@ export interface Fam {
inviteCode: string;
stripeCustomerId?: string;
featureFlags: Record<string, boolean>;
payday?: number;
paydayTime?: string;
timezone?: string;
lastIssued?: string;
created: string;
updated: string;
}
@@ -70,16 +74,19 @@ export interface ChoreTemplate {
updated: string;
}
export interface AssignedChore {
export interface AssignedChore {
id: string;
famId: string;
memberId: string;
templateId: string;
templateId?: string;
frequency: Frequency;
type: RewardType;
value: number;
customName?: string;
seasonIds?: string[];
isTodo?: boolean;
startDate?: string;
completeBy?: string;
created: string;
updated: string;
}
@@ -160,6 +167,7 @@ export interface Settings {
id: string;
famId: string;
webhookUrl?: string;
simulateEow?: boolean;
}
export interface Session {