190 lines
6.6 KiB
TypeScript
190 lines
6.6 KiB
TypeScript
import { pb } from "@/lib/pocketbase";
|
|
import { toast } from "solid-sonner";
|
|
import {
|
|
createDefaultFilter,
|
|
type Filter,
|
|
type FilterTemplate,
|
|
readScopedPrefs,
|
|
setStore,
|
|
store,
|
|
writeScopedPrefs
|
|
} from "./state";
|
|
|
|
export const syncPreferences = async () => {
|
|
const userId = pb.authStore.model?.id;
|
|
if (!userId) return;
|
|
|
|
try {
|
|
const user = await pb.collection("users").getOne(userId, { requestKey: null });
|
|
const rawPrefs = user.Taskgrid_pref || {};
|
|
const prefs = {
|
|
pWeight: store.pWeight,
|
|
uWeight: store.uWeight,
|
|
matrixScaleDays: store.matrixScaleDays,
|
|
tagDefinitions: store.tagDefinitions.filter(def => !def.name.startsWith("@")),
|
|
filterTemplates: store.filterTemplates,
|
|
quickloadTasks: store.quickloadTasks,
|
|
dismissedTaskUpdateIndicators: store.dismissedTaskUpdateIndicators,
|
|
collapsedUntilUpdatedTasks: store.collapsedUntilUpdatedTasks,
|
|
subscribedBuckets: store.subscribedBuckets,
|
|
supervisorUserIds: store.personalContextSupervisorIds,
|
|
aiHelpTipHistory: store.aiHelpTipHistory,
|
|
lastCompletedTaskCleanupDate: store.lastCompletedTaskCleanupDate
|
|
};
|
|
|
|
await pb.collection("users").update(userId, {
|
|
Taskgrid_pref: writeScopedPrefs(rawPrefs, {
|
|
...readScopedPrefs(rawPrefs),
|
|
...prefs
|
|
})
|
|
}, { requestKey: null });
|
|
} catch (e: any) {
|
|
if (e.isAbort) return;
|
|
console.error("Failed to sync preferences", e);
|
|
}
|
|
};
|
|
|
|
export const setFilter = (update: Partial<Filter>) => {
|
|
setStore("filter", f => ({ ...f, ...update }));
|
|
};
|
|
|
|
export const loadFilterTemplates = async () => {
|
|
if (!pb.authStore.isValid) return;
|
|
const userId = pb.authStore.model?.id;
|
|
if (!userId) return;
|
|
const user = await pb.collection("users").getOne(userId, { requestKey: null });
|
|
const prefs = readScopedPrefs(user.Taskgrid_pref || {});
|
|
setStore("filterTemplates", prefs.filterTemplates || []);
|
|
};
|
|
|
|
export const saveFilterTemplate = async (name: string) => {
|
|
if (!pb.authStore.isValid) return;
|
|
try {
|
|
const newTemplate: FilterTemplate = {
|
|
id: `filter-${Date.now()}`,
|
|
name,
|
|
filter: store.filter
|
|
};
|
|
|
|
setStore("filterTemplates", prev => [...prev, newTemplate]);
|
|
await syncPreferences();
|
|
toast.success(`Filter template "${name}" saved`);
|
|
} catch (err) {
|
|
console.error("Failed to save filter template:", err);
|
|
toast.error("Failed to save filter template.");
|
|
}
|
|
};
|
|
|
|
export const applyFilterTemplate = (id: string) => {
|
|
const template = store.filterTemplates.find(t => t.id === id);
|
|
if (template) {
|
|
setFilter(template.filter);
|
|
toast.success(`Applied filter: ${template.name}`);
|
|
}
|
|
};
|
|
|
|
export const removeFilterTemplate = async (id: string) => {
|
|
if (!pb.authStore.isValid) return;
|
|
try {
|
|
setStore("filterTemplates", prev => prev.filter(t => t.id !== id));
|
|
await syncPreferences();
|
|
toast.success("Filter template deleted");
|
|
} catch (err) {
|
|
console.error("Failed to delete filter template:", err);
|
|
toast.error("Failed to delete filter template.");
|
|
}
|
|
};
|
|
|
|
export const clearFilter = () => {
|
|
setStore("filter", createDefaultFilter());
|
|
};
|
|
|
|
export const setNoteFilter = (update: Partial<Filter>) => {
|
|
setStore("noteFilter", f => ({ ...f, ...update }));
|
|
};
|
|
|
|
export const loadNoteFilterTemplates = async () => {
|
|
if (!pb.authStore.isValid) return;
|
|
const userId = pb.authStore.model?.id;
|
|
if (!userId) return;
|
|
const user = await pb.collection("users").getOne(userId, { requestKey: null });
|
|
const prefs = readScopedPrefs(user.Taskgrid_pref || {});
|
|
setStore("filterTemplates", prefs.noteFilterTemplates || []);
|
|
};
|
|
|
|
export const saveNoteFilterTemplate = async (name: string) => {
|
|
if (!pb.authStore.isValid) return;
|
|
try {
|
|
const newTemplate: FilterTemplate = {
|
|
id: `note-filter-${Date.now()}`,
|
|
name,
|
|
filter: store.noteFilter
|
|
};
|
|
|
|
setStore("filterTemplates", prev => [...prev, newTemplate]);
|
|
const userId = pb.authStore.model?.id;
|
|
if (userId) {
|
|
const user = await pb.collection("users").getOne(userId, { requestKey: null });
|
|
const rawPrefs = user.Taskgrid_pref || {};
|
|
const prefs = readScopedPrefs(rawPrefs);
|
|
await pb.collection("users").update(userId, {
|
|
Taskgrid_pref: writeScopedPrefs(rawPrefs, {
|
|
...prefs,
|
|
noteFilterTemplates: [...(prefs.noteFilterTemplates || []), newTemplate]
|
|
})
|
|
}, { requestKey: null });
|
|
}
|
|
toast.success(`Note filter template "${name}" saved`);
|
|
} catch (err) {
|
|
console.error("Failed to save note filter template:", err);
|
|
toast.error("Failed to save note filter template.");
|
|
}
|
|
};
|
|
|
|
export const applyNoteFilterTemplate = (id: string) => {
|
|
const template = store.filterTemplates.find(t => t.id === id);
|
|
if (template) {
|
|
setNoteFilter(template.filter);
|
|
toast.success(`Applied note filter: ${template.name}`);
|
|
}
|
|
};
|
|
|
|
export const removeNoteFilterTemplate = async (id: string) => {
|
|
if (!pb.authStore.isValid) return;
|
|
try {
|
|
setStore("filterTemplates", prev => prev.filter(t => t.id !== id));
|
|
const userId = pb.authStore.model?.id;
|
|
if (userId) {
|
|
const user = await pb.collection("users").getOne(userId, { requestKey: null });
|
|
const rawPrefs = user.Taskgrid_pref || {};
|
|
const prefs = readScopedPrefs(rawPrefs);
|
|
await pb.collection("users").update(userId, {
|
|
Taskgrid_pref: writeScopedPrefs(rawPrefs, {
|
|
...prefs,
|
|
noteFilterTemplates: (prefs.noteFilterTemplates || []).filter((template: FilterTemplate) => template.id !== id)
|
|
})
|
|
}, { requestKey: null });
|
|
}
|
|
toast.success("Note filter template deleted");
|
|
} catch (err) {
|
|
console.error("Failed to delete note filter template:", err);
|
|
toast.error("Failed to delete note filter template.");
|
|
}
|
|
};
|
|
|
|
export const clearNoteFilter = () => {
|
|
setStore("noteFilter", createDefaultFilter());
|
|
};
|
|
|
|
export const appendAIHelpTipHistory = async (tip: string) => {
|
|
const normalizedTip = tip.trim();
|
|
if (!normalizedTip) return;
|
|
|
|
setStore("aiHelpTipHistory", prev => {
|
|
const next = [...prev.filter(existing => existing !== normalizedTip), normalizedTip];
|
|
return next.slice(-10);
|
|
});
|
|
|
|
await syncPreferences();
|
|
};
|