migrate from hono

This commit is contained in:
JCEEE
2026-08-17 07:41:26 +01:00
parent e2b99c45b6
commit 5204e7bdbc
56 changed files with 1815 additions and 3357 deletions
@@ -0,0 +1,68 @@
import { todayInTz, resolveTz } from '@shared/timezone';
import { famMeta } from './fam';
function resolveServerTz(tz?: string): string {
return resolveTz(tz || 'auto');
}
export function assertPaydayUnlocked(reward: any, tz?: string) {
if (!reward || reward.claimable !== 'payday' || !reward.settleDate) return;
const today = todayInTz(resolveServerTz(tz));
if (today < reward.settleDate) {
throw new Error(`This bonus pays out on payday (${reward.settleDate}) — hang tight!`);
}
}
// Member claim → status 'requested' (pending parent approval).
export async function claim(pb: any, famId: string, id: string) {
const now = new Date().toISOString();
const { tz } = await famMeta(pb, famId);
const found = await pb
.collection('rewards')
.getFullList({ filter: `famId = '${famId}' && id = '${id}'` });
const reward = found?.[0];
if (!reward) throw new Error('Reward not found');
assertPaydayUnlocked(reward, tz);
return pb.collection('rewards').update(id, { status: 'requested', requestedAt: now });
}
// Admin approval → status 'claimed'.
export async function approve(pb: any, famId: string, id: string) {
return pb.collection('rewards').update(id, {
status: 'claimed',
claimedAt: new Date().toISOString()
});
}
export async function requestAll(pb: any, famId: string, memberId: string) {
const now = new Date().toISOString();
const { tz } = await famMeta(pb, famId);
const rewards = await pb.collection('rewards').getFullList({
filter: `famId = '${famId}' && memberId = '${memberId}' && status = 'unclaimed'`
});
let count = 0;
for (const r of rewards) {
try {
assertPaydayUnlocked(r, tz);
} catch {
continue;
}
await pb.collection('rewards').update(r.id, { status: 'requested', requestedAt: now });
count++;
}
return { count };
}
export async function issueAll(pb: any, famId: string, memberId: string) {
if (!memberId) throw new Error('memberId required');
const now = new Date().toISOString();
const rewards = await pb.collection('rewards').getFullList({
filter: `famId = '${famId}' && memberId = '${memberId}' && rewardType = 'cash' && (status = 'unclaimed' || status = 'requested')`
});
let count = 0;
for (const r of rewards) {
await pb.collection('rewards').update(r.id, { status: 'claimed', claimedAt: now });
count++;
}
return { count };
}