remove old messaging system
This commit is contained in:
+1
-97
@@ -1877,7 +1877,7 @@ app.post("/api/admin/:famId/rewards/issue-all", requireAdmin, async (c) => {
|
||||
try {
|
||||
const { famId } = c.req.param();
|
||||
const body = await c.req.json();
|
||||
const { memberId, message } = body;
|
||||
const { memberId } = body;
|
||||
if (!memberId) return c.json({ error: "memberId required" }, 400);
|
||||
const now = new Date().toISOString();
|
||||
// Find all claimable rewards for this member (unclaimed or requested)
|
||||
@@ -1890,15 +1890,6 @@ app.post("/api/admin/:famId/rewards/issue-all", requireAdmin, async (c) => {
|
||||
await pb.update("rewards", r.id, { status: "claimed", claimedAt: now });
|
||||
count++;
|
||||
}
|
||||
// Send notification to member if message provided
|
||||
if (message && count > 0) {
|
||||
await pb.create("notifications", {
|
||||
famId,
|
||||
memberId,
|
||||
message,
|
||||
read: false,
|
||||
});
|
||||
}
|
||||
return c.json({ count });
|
||||
} catch (err) {
|
||||
return handleError(c, err);
|
||||
@@ -1928,8 +1919,6 @@ app.post(
|
||||
},
|
||||
);
|
||||
|
||||
// ── Admin: Send notification message ────────────────────
|
||||
|
||||
app.get("/api/admin/:famId/profile", requireAdmin, async (c) => {
|
||||
try {
|
||||
const { famId } = c.req.param();
|
||||
@@ -1978,25 +1967,6 @@ app.patch("/api/admin/:famId/profile", requireAdmin, async (c) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/api/admin/:famId/send-message", requireAdmin, async (c) => {
|
||||
try {
|
||||
const { famId } = c.req.param();
|
||||
const body = await c.req.json();
|
||||
if (!body.memberId || !body.message) {
|
||||
return c.json({ error: "memberId and message required" }, 400);
|
||||
}
|
||||
const record = await pb.create("notifications", {
|
||||
famId,
|
||||
memberId: body.memberId,
|
||||
message: body.message,
|
||||
read: false,
|
||||
});
|
||||
return c.json(record);
|
||||
} catch (err) {
|
||||
return handleError(c, err);
|
||||
}
|
||||
});
|
||||
|
||||
// ── Member: Claim a reward ─────────────────────────────
|
||||
|
||||
app.post("/api/members/rewards/:id/claim", requireDeviceToken, async (c) => {
|
||||
@@ -2024,19 +1994,6 @@ app.post("/api/members/rewards/:id/claim", requireDeviceToken, async (c) => {
|
||||
status: "requested",
|
||||
requestedAt: now,
|
||||
});
|
||||
// Create notification for admin
|
||||
const members = await pb.getList(
|
||||
"members",
|
||||
`famId = '${famId}' && id = '${memberId}'`,
|
||||
);
|
||||
const memberName = members.items?.[0]?.name || "Unknown";
|
||||
const msg = `Claim requested by ${memberName}`;
|
||||
await pb.create("notifications", {
|
||||
famId,
|
||||
memberId,
|
||||
message: msg,
|
||||
read: false,
|
||||
});
|
||||
return c.json(record);
|
||||
} catch (err) {
|
||||
return handleError(c, err);
|
||||
@@ -2069,56 +2026,12 @@ app.post("/api/members/rewards/request-all", requireDeviceToken, async (c) => {
|
||||
});
|
||||
count++;
|
||||
}
|
||||
if (count > 0) {
|
||||
const members = await pb.getList(
|
||||
"members",
|
||||
`famId = '${famId}' && id = '${memberId}'`,
|
||||
);
|
||||
const memberName = members.items?.[0]?.name || "Unknown";
|
||||
const msg = `${count} claim(s) requested by ${memberName}`;
|
||||
await pb.create("notifications", {
|
||||
famId,
|
||||
memberId,
|
||||
message: msg,
|
||||
read: false,
|
||||
});
|
||||
}
|
||||
return c.json({ count });
|
||||
} catch (err) {
|
||||
return handleError(c, err);
|
||||
}
|
||||
});
|
||||
|
||||
// ── Member: Notifications ──────────────────────────────
|
||||
|
||||
app.get("/api/members/notifications", requireDeviceToken, async (c) => {
|
||||
try {
|
||||
const famId = c.get("famId");
|
||||
const memberId = c.get("memberId");
|
||||
const data = await pb.getList(
|
||||
"notifications",
|
||||
`famId = '${famId}' && memberId = '${memberId}'`,
|
||||
);
|
||||
return c.json(data.items);
|
||||
} catch (err) {
|
||||
return handleError(c, err);
|
||||
}
|
||||
});
|
||||
|
||||
app.post(
|
||||
"/api/members/notifications/:id/dismiss",
|
||||
requireDeviceToken,
|
||||
async (c) => {
|
||||
try {
|
||||
const { id } = c.req.param();
|
||||
const record = await pb.update("notifications", id, { read: true });
|
||||
return c.json(record);
|
||||
} catch (err) {
|
||||
return handleError(c, err);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// ── Payday: release this period's unpaid cash as an auto-claimed ask ──
|
||||
|
||||
async function releaseWeek(famId: string) {
|
||||
@@ -2178,15 +2091,6 @@ async function releaseWeek(famId: string) {
|
||||
});
|
||||
}
|
||||
}
|
||||
// Kid notice: the fun moment.
|
||||
try {
|
||||
await pb.create("notifications", {
|
||||
famId,
|
||||
memberId: m.id,
|
||||
message: `You've earned £${total.toFixed(2)}! Go get it from your parent ⭐`,
|
||||
read: false,
|
||||
});
|
||||
} catch {}
|
||||
breakdown.push({
|
||||
memberId: m.id,
|
||||
name: m.name,
|
||||
|
||||
+89
-113
@@ -302,7 +302,9 @@ export async function migrate(): Promise<void> {
|
||||
missing.push({ name: "settleDate", type: "text", required: false });
|
||||
}
|
||||
if (missing.length) {
|
||||
console.log("[migrate] Adding rewards.claimable/settleDate (payday gating)...");
|
||||
console.log(
|
||||
"[migrate] Adding rewards.claimable/settleDate (payday gating)...",
|
||||
);
|
||||
rewardsCol2.fields.push(...missing);
|
||||
await updateCollection(rewardsCol2.id, {
|
||||
name: "rewards",
|
||||
@@ -370,47 +372,6 @@ export async function migrate(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
// ── 4. Create notifications collection if missing ──
|
||||
const notifCol = await getCollection("notifications");
|
||||
if (!notifCol) {
|
||||
const famsCol = await getCollection("fams");
|
||||
if (!famsCol) throw new Error("fams collection not found");
|
||||
const membersCol = await getCollection("members");
|
||||
if (!membersCol) throw new Error("members collection not found");
|
||||
console.log("[migrate] Creating notifications collection...");
|
||||
await createCollection({
|
||||
name: "notifications",
|
||||
type: "base",
|
||||
listRule: "",
|
||||
viewRule: "",
|
||||
createRule: null,
|
||||
updateRule: null,
|
||||
deleteRule: null,
|
||||
fields: [
|
||||
{
|
||||
name: "famId",
|
||||
type: "relation",
|
||||
required: true,
|
||||
collectionId: famsCol.id,
|
||||
maxSelect: 1,
|
||||
cascadeDelete: false,
|
||||
},
|
||||
{
|
||||
name: "memberId",
|
||||
type: "relation",
|
||||
required: true,
|
||||
collectionId: membersCol.id,
|
||||
maxSelect: 1,
|
||||
cascadeDelete: false,
|
||||
},
|
||||
{ name: "message", type: "text", required: true },
|
||||
{ name: "read", type: "bool", required: false },
|
||||
],
|
||||
});
|
||||
} else {
|
||||
console.log(` ↳ notifications already exists`);
|
||||
}
|
||||
|
||||
// ── 5. Add payday field to fams if missing ──
|
||||
const famsCol = await getCollection("fams");
|
||||
if (famsCol) {
|
||||
@@ -547,10 +508,15 @@ export async function migrate(): Promise<void> {
|
||||
});
|
||||
}
|
||||
if (fams.length) {
|
||||
console.log(` ✓ Backfilled timezone="auto" for ${fams.length} fam${fams.length > 1 ? "s" : ""}`);
|
||||
console.log(
|
||||
` ✓ Backfilled timezone="auto" for ${fams.length} fam${fams.length > 1 ? "s" : ""}`,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(" ↳ timezone backfill skipped:", err instanceof Error ? err.message : err);
|
||||
console.log(
|
||||
" ↳ timezone backfill skipped:",
|
||||
err instanceof Error ? err.message : err,
|
||||
);
|
||||
}
|
||||
|
||||
// ── 6. Backfill completions.date — strip timestamps to YYYY-MM-DD ──
|
||||
@@ -1334,78 +1300,88 @@ export async function migrate(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
// ── 7. Add todo fields to assigned_chores if missing ──
|
||||
const assignedCol = await getCollection("assigned_chores");
|
||||
if (assignedCol) {
|
||||
let needsUpdate = false;
|
||||
// ── 7. Add todo fields to assigned_chores if missing ──
|
||||
const assignedCol = await getCollection("assigned_chores");
|
||||
if (assignedCol) {
|
||||
let needsUpdate = false;
|
||||
|
||||
// 7a. Make templateId non-required (todos don't use templates)
|
||||
const tplField = assignedCol.fields.find((f: any) => f.name === "templateId");
|
||||
if (tplField && tplField.required) {
|
||||
console.log("[migrate] Making assigned_chores.templateId non-required...");
|
||||
tplField.required = false;
|
||||
needsUpdate = true;
|
||||
}
|
||||
// 7a. Make templateId non-required (todos don't use templates)
|
||||
const tplField = assignedCol.fields.find(
|
||||
(f: any) => f.name === "templateId",
|
||||
);
|
||||
if (tplField && tplField.required) {
|
||||
console.log(
|
||||
"[migrate] Making assigned_chores.templateId non-required...",
|
||||
);
|
||||
tplField.required = false;
|
||||
needsUpdate = true;
|
||||
}
|
||||
|
||||
// 7b. Add isTodo, startDate, completeBy fields
|
||||
const hasIsTodo = assignedCol.fields.some((f: any) => f.name === "isTodo");
|
||||
if (!hasIsTodo) {
|
||||
console.log("[migrate] Adding todo fields to assigned_chores...");
|
||||
assignedCol.fields.push(
|
||||
{ name: "isTodo", type: "bool" },
|
||||
{ name: "startDate", type: "text" },
|
||||
{ name: "completeBy", type: "text" }
|
||||
);
|
||||
needsUpdate = true;
|
||||
} else {
|
||||
console.log(` ↳ assigned_chores.isTodo already exists`);
|
||||
}
|
||||
// 7b. Add isTodo, startDate, completeBy fields
|
||||
const hasIsTodo = assignedCol.fields.some((f: any) => f.name === "isTodo");
|
||||
if (!hasIsTodo) {
|
||||
console.log("[migrate] Adding todo fields to assigned_chores...");
|
||||
assignedCol.fields.push(
|
||||
{ name: "isTodo", type: "bool" },
|
||||
{ name: "startDate", type: "text" },
|
||||
{ name: "completeBy", type: "text" },
|
||||
);
|
||||
needsUpdate = true;
|
||||
} else {
|
||||
console.log(` ↳ assigned_chores.isTodo already exists`);
|
||||
}
|
||||
|
||||
if (needsUpdate) {
|
||||
await updateCollection(assignedCol.id, {
|
||||
name: "assigned_chores",
|
||||
type: "base",
|
||||
listRule: assignedCol.listRule,
|
||||
viewRule: assignedCol.viewRule,
|
||||
createRule: assignedCol.createRule,
|
||||
updateRule: assignedCol.updateRule,
|
||||
deleteRule: assignedCol.deleteRule,
|
||||
fields: assignedCol.fields,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log(` ↳ assigned_chores collection not found (will be created by seed)`);
|
||||
}
|
||||
if (needsUpdate) {
|
||||
await updateCollection(assignedCol.id, {
|
||||
name: "assigned_chores",
|
||||
type: "base",
|
||||
listRule: assignedCol.listRule,
|
||||
viewRule: assignedCol.viewRule,
|
||||
createRule: assignedCol.createRule,
|
||||
updateRule: assignedCol.updateRule,
|
||||
deleteRule: assignedCol.deleteRule,
|
||||
fields: assignedCol.fields,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
` ↳ assigned_chores collection not found (will be created by seed)`,
|
||||
);
|
||||
}
|
||||
|
||||
// ── 8. Add completedAt timestamp to completions ──
|
||||
const complCol = await getCollection("completions");
|
||||
if (complCol) {
|
||||
const hasCompletedAt = complCol.fields.some((f: any) => f.name === "completedAt");
|
||||
if (!hasCompletedAt) {
|
||||
console.log("[migrate] Adding completions.completedAt...");
|
||||
complCol.fields.push({
|
||||
name: "completedAt",
|
||||
type: "date",
|
||||
required: false,
|
||||
hidden: false,
|
||||
});
|
||||
await updateCollection(complCol.id, {
|
||||
name: "completions",
|
||||
type: "base",
|
||||
listRule: complCol.listRule,
|
||||
viewRule: complCol.viewRule,
|
||||
createRule: complCol.createRule,
|
||||
updateRule: complCol.updateRule,
|
||||
deleteRule: complCol.deleteRule,
|
||||
fields: complCol.fields,
|
||||
});
|
||||
console.log(" ✓ completions.completedAt added");
|
||||
} else {
|
||||
console.log(` ↳ completions.completedAt already exists`);
|
||||
}
|
||||
} else {
|
||||
console.log(` ↳ completions collection not found (will be created by seed)`);
|
||||
}
|
||||
// ── 8. Add completedAt timestamp to completions ──
|
||||
const complCol = await getCollection("completions");
|
||||
if (complCol) {
|
||||
const hasCompletedAt = complCol.fields.some(
|
||||
(f: any) => f.name === "completedAt",
|
||||
);
|
||||
if (!hasCompletedAt) {
|
||||
console.log("[migrate] Adding completions.completedAt...");
|
||||
complCol.fields.push({
|
||||
name: "completedAt",
|
||||
type: "date",
|
||||
required: false,
|
||||
hidden: false,
|
||||
});
|
||||
await updateCollection(complCol.id, {
|
||||
name: "completions",
|
||||
type: "base",
|
||||
listRule: complCol.listRule,
|
||||
viewRule: complCol.viewRule,
|
||||
createRule: complCol.createRule,
|
||||
updateRule: complCol.updateRule,
|
||||
deleteRule: complCol.deleteRule,
|
||||
fields: complCol.fields,
|
||||
});
|
||||
console.log(" ✓ completions.completedAt added");
|
||||
} else {
|
||||
console.log(` ↳ completions.completedAt already exists`);
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
` ↳ completions collection not found (will be created by seed)`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log("[migrate] Done");
|
||||
console.log("[migrate] Done");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user