feat: personal notes on bill detail pages

- bill_notes table (migration 0014): user_id, bill_id, content, pinned,
  created_at, updated_at; unique constraint (user_id, bill_id)
- BillNote SQLAlchemy model with back-refs on User and Bill
- GET/PUT/DELETE /api/notes/{bill_id} — auth-required, one note per (user, bill)
- NotesPanel component: collapsible, auto-resize textarea, pin toggle,
  save + delete; shows last-saved date and pin indicator in collapsed header
- Pinned notes render above BriefPanel; unpinned render below DraftLetterPanel
- Guests see nothing (token guard in component + query disabled)

Co-Authored-By: Jack Levy
This commit is contained in:
Jack Levy
2026-03-01 22:14:52 -05:00
parent 128c8e9257
commit 62a217cb22
13 changed files with 393 additions and 30 deletions

View File

@@ -86,6 +86,16 @@ export const billsAPI = {
apiClient.post<{ draft: string }>(`/api/bills/${id}/draft-letter`, body).then((r) => r.data),
};
// Notes
export const notesAPI = {
get: (billId: string) =>
apiClient.get<import("./types").BillNote>(`/api/notes/${billId}`).then((r) => r.data),
upsert: (billId: string, content: string, pinned: boolean) =>
apiClient.put<import("./types").BillNote>(`/api/notes/${billId}`, { content, pinned }).then((r) => r.data),
delete: (billId: string) =>
apiClient.delete(`/api/notes/${billId}`),
};
// Members
export const membersAPI = {
list: (params?: Record<string, unknown>) =>