fixed urgency-date connection and added urgency-date guidance. fixed password extension break. fixed template saving.

This commit is contained in:
2026-01-31 19:19:33 -06:00
parent 8f7a067b75
commit b2c197454d
7 changed files with 154 additions and 142 deletions
+28 -92
View File
@@ -2,6 +2,7 @@ import { createStore, reconcile, produce } from "solid-js/store";
import { createSignal, createEffect, createRoot } from "solid-js";
import { pb, TASGRID_COLLECTION } from "@/lib/pocketbase";
import { toast } from "solid-sonner";
import { URGENCY_HOURS } from "@/lib/constants";
const getStorageKey = () => {
const userId = pb.authStore.model?.id;
@@ -117,25 +118,31 @@ export const calculateUrgencyScore = (dueDateStr: string): number => {
const due = new Date(dueDateStr).getTime();
const diffHours = (due - now()) / (1000 * 60 * 60);
// Geometric formulation
// Base is derived so that urgency 1 ~ matrixScaleDays
const base = Math.pow(Math.max(1, store.matrixScaleDays), 1 / 9);
if (diffHours <= URGENCY_HOURS[10]) return 10;
if (diffHours >= URGENCY_HOURS[1]) return 1;
// Reverse formula: Level = 10 - (ln(hours/24) / ln(base))
// If hours <= 24, log(<=1) is negative or 0, so Level >= 10.
if (diffHours <= 24) return 10;
// Linear interpolation between breakpoints
const levels = Object.keys(URGENCY_HOURS).map(Number).sort((a, b) => b - a); // 10, 9, 8...
for (let i = 0; i < levels.length - 1; i++) {
const highLevel = levels[i];
const lowLevel = levels[i + 1];
const highHours = URGENCY_HOURS[highLevel];
const lowHours = URGENCY_HOURS[lowLevel];
const level = 10 - (Math.log(diffHours / 24) / Math.log(base));
return Math.max(1, Math.min(10, level));
if (diffHours >= highHours && diffHours <= lowHours) {
// Level decreases as hours increase
const range = lowHours - highHours;
const progress = (diffHours - highHours) / range;
return highLevel - progress * (highLevel - lowLevel);
}
}
return 1;
};
export const calculateDateFromUrgency = (level: number): string => {
// Inverse of above
if (level >= 10) {
return new Date(now() + 24 * 60 * 60 * 1000).toISOString();
}
const base = Math.pow(Math.max(1, store.matrixScaleDays), 1 / 9);
const hours = 24 * Math.pow(base, 10 - level);
const roundedLevel = Math.max(1, Math.min(10, Math.round(level)));
const hours = URGENCY_HOURS[roundedLevel] || 24;
return new Date(now() + hours * 60 * 60 * 1000).toISOString();
};
@@ -400,24 +407,7 @@ export const updateTaskField = (id: string, field: keyof Task, value: any) => {
export const setMatrixScaleDays = async (days: number) => {
setStore("matrixScaleDays", days);
// Sync to users collection
if (store.prefId) {
try {
const prefs = {
pWeight: store.pWeight,
uWeight: store.uWeight,
matrixScaleDays: days
};
await pb.collection('users').update(store.prefId, {
Taskgrid_pref: prefs
});
} catch (err) {
console.error("Failed to update preferences", err);
}
}
await syncPreferences();
};
export const toggleTask = (id: string) => {
@@ -491,27 +481,7 @@ export const upsertMultipleTagDefinitions = async (updates: Record<string, numbe
setStore("tagDefinitions", (defs) => ({ ...(defs || {}), ...updates }));
// Persist
const map = { ...store.tagDefinitions };
const userId = pb.authStore.model?.id;
if (userId) {
try {
const prefs = {
pWeight: store.pWeight,
uWeight: store.uWeight,
matrixScaleDays: store.matrixScaleDays,
tagDefinitions: map
};
await pb.collection('users').update(userId, {
Taskgrid_pref: prefs
}, { requestKey: null });
} catch (e: any) {
// Ignore abort errors
if (e.isAbort) return;
console.error("Failed to persist tag definitions", e);
toast.error("Failed to save tag definitions");
}
}
await syncPreferences();
};
export const removeTagDefinition = async (name: string) => {
@@ -528,25 +498,8 @@ export const removeTagDefinition = async (name: string) => {
}));
// 3. Persist
const map = { ...store.tagDefinitions };
const userId = pb.authStore.model?.id;
if (userId) {
try {
const prefs = {
pWeight: store.pWeight,
uWeight: store.uWeight,
matrixScaleDays: store.matrixScaleDays,
tagDefinitions: map
};
await pb.collection('users').update(userId, {
Taskgrid_pref: prefs
});
toast.success(`Tag "${name}" deleted`);
} catch (e) {
console.error("Failed to delete tag definition", e);
toast.error("Failed to delete tag");
}
}
await syncPreferences();
toast.success(`Tag "${name}" deleted`);
};
export const renameTagDefinition = async (oldName: string, newName: string) => {
@@ -574,31 +527,13 @@ export const renameTagDefinition = async (oldName: string, newName: string) => {
}));
// 4. Persist
const map = { ...store.tagDefinitions };
const userId = pb.authStore.model?.id;
if (userId) {
try {
const prefs = {
pWeight: store.pWeight,
uWeight: store.uWeight,
matrixScaleDays: store.matrixScaleDays,
tagDefinitions: map
};
await pb.collection('users').update(userId, {
Taskgrid_pref: prefs
});
toast.success(`Tag renamed to "${finalName}"`);
} catch (e) {
console.error("Failed to rename tag", e);
toast.error("Failed to rename tag");
}
}
await syncPreferences();
};
// -- Templates --
const syncPreferences = async () => {
export const syncPreferences = async () => {
const userId = pb.authStore.model?.id;
if (!userId) return;
@@ -617,6 +552,7 @@ const syncPreferences = async () => {
} catch (e: any) {
if (e.isAbort) return;
console.error("Failed to sync preferences", e);
// We could toast here, but many of these are background syncs
}
};