added todos | payday time settings | refactor payment scheduling
This commit is contained in:
+178
-1
@@ -311,6 +311,27 @@ export async function migrate(): Promise<void> {
|
||||
} else {
|
||||
console.log(` ↳ settings schema is current`);
|
||||
}
|
||||
|
||||
// Ensure simulateEow debug flag exists (read-only EOW preview toggle)
|
||||
const simField = settingsCol.fields.some(
|
||||
(f: any) => f.name === "simulateEow",
|
||||
);
|
||||
if (!simField) {
|
||||
console.log("[migrate] Adding settings.simulateEow (debug toggle)...");
|
||||
settingsCol.fields.push({ name: "simulateEow", type: "bool" });
|
||||
await updateCollection(settingsCol.id, {
|
||||
name: "settings",
|
||||
type: "base",
|
||||
listRule: settingsCol.listRule,
|
||||
viewRule: settingsCol.viewRule,
|
||||
createRule: settingsCol.createRule,
|
||||
updateRule: settingsCol.updateRule,
|
||||
deleteRule: settingsCol.deleteRule,
|
||||
fields: settingsCol.fields,
|
||||
});
|
||||
} else {
|
||||
console.log(` ↳ settings.simulateEow already exists`);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 4. Create notifications collection if missing ──
|
||||
@@ -383,6 +404,119 @@ export async function migrate(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
// ── 5b. Add lastIssued (payday heartbeat) field to fams if missing ──
|
||||
{
|
||||
const fc = famsCol || (await getCollection("fams"));
|
||||
if (fc) {
|
||||
const hasLastIssued = fc.fields.some((f: any) => f.name === "lastIssued");
|
||||
if (!hasLastIssued) {
|
||||
console.log("[migrate] Adding lastIssued field to fams...");
|
||||
fc.fields.push({ name: "lastIssued", type: "text" });
|
||||
await updateCollection(fc.id, {
|
||||
name: "fams",
|
||||
type: "base",
|
||||
listRule: fc.listRule,
|
||||
viewRule: fc.viewRule,
|
||||
createRule: fc.createRule,
|
||||
updateRule: fc.updateRule,
|
||||
deleteRule: fc.deleteRule,
|
||||
fields: fc.fields,
|
||||
});
|
||||
} else {
|
||||
console.log(` ↳ fams.lastIssued already exists`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 5c. Add paydayTime (HH:MM) field to fams if missing ──
|
||||
{
|
||||
const fc = famsCol || (await getCollection("fams"));
|
||||
if (fc) {
|
||||
const hasPaydayTime = fc.fields.some((f: any) => f.name === "paydayTime");
|
||||
if (!hasPaydayTime) {
|
||||
console.log("[migrate] Adding paydayTime field to fams...");
|
||||
fc.fields.push({ name: "paydayTime", type: "text" });
|
||||
await updateCollection(fc.id, {
|
||||
name: "fams",
|
||||
type: "base",
|
||||
listRule: fc.listRule,
|
||||
viewRule: fc.viewRule,
|
||||
createRule: fc.createRule,
|
||||
updateRule: fc.updateRule,
|
||||
deleteRule: fc.deleteRule,
|
||||
fields: fc.fields,
|
||||
});
|
||||
} else {
|
||||
console.log(` ↳ fams.paydayTime already exists`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 5d. Add timezone (IANA name or "auto") field to fams if missing ──
|
||||
{
|
||||
const fc = famsCol || (await getCollection("fams"));
|
||||
if (fc) {
|
||||
const hasTz = fc.fields.some((f: any) => f.name === "timezone");
|
||||
if (!hasTz) {
|
||||
console.log("[migrate] Adding timezone field to fams...");
|
||||
fc.fields.push({
|
||||
name: "timezone",
|
||||
type: "text",
|
||||
max: 64,
|
||||
pattern: "",
|
||||
autogeneratePattern: "",
|
||||
primaryKey: false,
|
||||
system: false,
|
||||
required: false,
|
||||
unique: false,
|
||||
hidden: false,
|
||||
presentable: false,
|
||||
noDecimal: false,
|
||||
});
|
||||
await updateCollection(fc.id, {
|
||||
name: "fams",
|
||||
type: "base",
|
||||
listRule: fc.listRule,
|
||||
viewRule: fc.viewRule,
|
||||
createRule: fc.createRule,
|
||||
updateRule: fc.updateRule,
|
||||
deleteRule: fc.deleteRule,
|
||||
fields: fc.fields,
|
||||
});
|
||||
} else {
|
||||
console.log(` ↳ fams.timezone already exists`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 5e. Backfill fams.timezone = "auto" for any existing fams ──
|
||||
try {
|
||||
const t = await auth();
|
||||
const res = await fetch(
|
||||
`${PB_ENDPOINT}/api/collections/fams/records?perPage=200&filter=${encodeURIComponent(
|
||||
`timezone = "" || timezone = null`,
|
||||
)}`,
|
||||
{ headers: { Authorization: `Bearer ${t}` } },
|
||||
);
|
||||
const data = await res.json();
|
||||
const fams = data?.items || [];
|
||||
for (const f of fams) {
|
||||
await fetch(`${PB_ENDPOINT}/api/collections/fams/records/${f.id}`, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${t}`,
|
||||
},
|
||||
body: JSON.stringify({ timezone: "auto" }),
|
||||
});
|
||||
}
|
||||
if (fams.length) {
|
||||
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);
|
||||
}
|
||||
|
||||
// ── 6. Backfill completions.date — strip timestamps to YYYY-MM-DD ──
|
||||
// PB v0.25 doesn't allow changing field type (date→text), so we keep it as `date`
|
||||
// and just normalise existing records. The frontend reads with .slice(0, 10) either way.
|
||||
@@ -1164,5 +1298,48 @@ export async function migrate(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
console.log("[migrate] Done");
|
||||
// ── 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;
|
||||
}
|
||||
|
||||
// 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)`);
|
||||
}
|
||||
|
||||
console.log("[migrate] Done");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user