Added new NOTES feature

This commit is contained in:
2026-02-26 19:06:43 -06:00
parent e5c8e42709
commit 3907de048b
9 changed files with 698 additions and 35 deletions
+71 -2
View File
@@ -2,7 +2,7 @@ import { createStore, reconcile } from "solid-js/store";
import { createSignal, createEffect, createRoot } from "solid-js";
import { pb } from "@/lib/pocketbase";
import { toast } from "solid-sonner";
import { TASGRID_COLLECTION, TAGS_COLLECTION, SHARE_RULES_COLLECTION, BUCKETS_COLLECTION, URGENCY_HOURS, SIZE_HOURS } from "@/lib/constants";
import { TASGRID_COLLECTION, TAGS_COLLECTION, SHARE_RULES_COLLECTION, BUCKETS_COLLECTION, NOTES_COLLECTION, URGENCY_HOURS, SIZE_HOURS } from "@/lib/constants";
const LIST_FIELDS = 'id,collectionId,collectionName,created,updated,title,startDate,dueDate,priority,status,completed,tags,user,size,recurrence,sharedWith,deletedAt';
@@ -136,6 +136,18 @@ export interface TagDefinition {
isBucket?: boolean; // New flag to identify bucket-based tags
}
export interface Note {
id: string;
title: string;
content?: string;
tags: string[];
isPrivate: boolean;
user: string;
tasks: string[]; // List of related task IDs
created: string;
updated: string;
}
export interface FilterTag {
name: string;
excluded: boolean;
@@ -187,6 +199,8 @@ interface TaskStore {
filterTemplates: FilterTemplate[];
buckets: Bucket[];
subscribedBuckets: string[]; // IDs of buckets I'm subscribed to
notes: Note[];
isNotepadMode: boolean;
}
// Initial empty state
@@ -209,7 +223,9 @@ export const [store, setStore] = createStore<TaskStore>({
shareRules: [],
filterTemplates: [],
buckets: [],
subscribedBuckets: []
subscribedBuckets: [],
notes: [],
isNotepadMode: false
});
export const matchesFilter = (task: Task) => {
@@ -472,6 +488,20 @@ const mapRecordToShareRule = (r: any): ShareRule => {
};
};
const mapRecordToNote = (r: any): Note => {
return {
id: r.id,
title: r.title,
content: r.content,
tags: r.tags || [],
isPrivate: r.isPrivate || false,
user: r.user,
tasks: r.tasks || [],
created: r.created,
updated: r.updated
};
};
// Helper to check if a task should be visible based on ownership, shares, or rules
const shouldTaskBeVisible = (task: any, currentUserId: string): boolean => {
// Own task
@@ -627,6 +657,33 @@ export const subscribeToRealtime = async () => {
}
});
// Subscribe to Notes
await pb.collection(NOTES_COLLECTION).unsubscribe('*');
pb.collection(NOTES_COLLECTION).subscribe('*', (e) => {
const currentUserId = pb.authStore.model?.id;
// Only process if public or owned by current user
const isVisible = !e.record.isPrivate || e.record.user === currentUserId;
if (e.action === 'create' || e.action === 'update') {
if (isVisible) {
const updatedNote = mapRecordToNote(e.record);
setStore("notes", prev => {
const exists = prev.find(n => n.id === updatedNote.id);
if (exists) return prev.map(n => n.id === updatedNote.id ? updatedNote : n);
return [updatedNote, ...prev];
});
} else {
// If it became private and we're not the owner, remove it
setStore("notes", prev => prev.filter(n => n.id !== e.record.id));
}
}
if (e.action === 'delete') {
setStore("notes", prev => prev.filter(n => n.id !== e.record.id));
}
});
// Subscribe to Buckets
// We need to know if buckets are added/removed/renamed
await pb.collection(BUCKETS_COLLECTION).unsubscribe('*');
@@ -771,6 +828,18 @@ export const initStore = async () => {
console.warn("Failed to load buckets (collection might not exist yet):", bucketErr);
}
// 1.3 Fetch Notes
try {
const currentUserId = pb.authStore.model?.id;
const notesRecords = await pb.collection(NOTES_COLLECTION).getFullList({
filter: `isPrivate = false || user = "${currentUserId}"`,
sort: '-created'
});
setStore("notes", notesRecords.map(mapRecordToNote));
} catch (notesErr) {
console.warn("Failed to load notes (collection might not exist yet):", notesErr);
}
// 1.5. Fetch Tag Definitions
try {
const tagRecords = await pb.collection(TAGS_COLLECTION).getFullList({