feat: add notifications and project shares features

- Backend: notifications + shares routes, DB tables, SqliteAdapter methods
- Frontend: NotificationPanel (bell icon + dropdown), ShareDialog, Dashboard integration
- Styles: notification + share dialog CSS
This commit is contained in:
2026-06-28 13:52:54 +02:00
parent a4371ca3ce
commit 20432f4b47
11 changed files with 655 additions and 7 deletions
+75
View File
@@ -387,6 +387,81 @@ export async function loadProjectDataTyped(token: string, projectId: string): Pr
return promise;
}
// ─── Notifications ───────────────────────────────────────
export interface NotificationItem {
id: string;
user_id: string;
type: string;
title: string;
message: string;
read: number;
created_at: string;
}
export async function getNotifications(token: string): Promise<NotificationItem[]> {
const res = await fetch(`${API_BASE}/api/notifications`, { headers: authHeaders(token) });
if (!res.ok) throw new Error('Failed to load notifications');
return res.json();
}
export async function createNotification(token: string, data: { type?: string; title: string; message: string; user_id?: string }): Promise<NotificationItem> {
const res = await fetch(`${API_BASE}/api/notifications`, {
method: 'POST',
headers: authHeaders(token),
body: JSON.stringify(data),
});
if (!res.ok) throw new Error('Failed to create notification');
return res.json();
}
export async function markNotificationRead(token: string, id: string): Promise<void> {
await fetch(`${API_BASE}/api/notifications/${id}/read`, {
method: 'PATCH',
headers: authHeaders(token),
});
}
export async function deleteNotification(token: string, id: string): Promise<void> {
await fetch(`${API_BASE}/api/notifications/${id}`, {
method: 'DELETE',
headers: authHeaders(token),
});
}
// ─── Project Shares ──────────────────────────────────────
export interface ProjectShare {
id: string;
project_id: string;
shared_with_email: string;
shared_by: string;
permission: string;
share_token: string | null;
created_at: string;
}
export async function getProjectShares(token: string, projectId: string): Promise<ProjectShare[]> {
const res = await fetch(`${API_BASE}/api/projects/${projectId}/shares`, { headers: authHeaders(token) });
if (!res.ok) throw new Error('Failed to load shares');
return res.json();
}
export async function createProjectShare(token: string, projectId: string, data: { shared_with_email: string; permission?: string }): Promise<ProjectShare> {
const res = await fetch(`${API_BASE}/api/projects/${projectId}/shares`, {
method: 'POST',
headers: authHeaders(token),
body: JSON.stringify(data),
});
if (!res.ok) throw new Error('Failed to create share');
return res.json();
}
export async function deleteProjectShare(token: string, shareId: string): Promise<void> {
await fetch(`${API_BASE}/api/shares/${shareId}`, {
method: 'DELETE',
headers: authHeaders(token),
});
}
export { API_BASE };
// ─── AI Copilot ─────────────────────────────────────────