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:
@@ -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>) =>
|
||||
|
||||
@@ -158,6 +158,15 @@ export interface SettingsData {
|
||||
pytrends_enabled: boolean;
|
||||
}
|
||||
|
||||
export interface BillNote {
|
||||
id: number;
|
||||
bill_id: string;
|
||||
content: string;
|
||||
pinned: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface NotificationSettings {
|
||||
ntfy_topic_url: string;
|
||||
ntfy_auth_method: string; // "none" | "token" | "basic"
|
||||
|
||||
Reference in New Issue
Block a user