feat: admin panel and invite acceptance UI

This commit is contained in:
2026-01-28 21:40:13 +00:00
parent ab402da7fd
commit 6e451e0795
6 changed files with 619 additions and 3 deletions

View File

@@ -1,4 +1,4 @@
import type { Profile, Client, ClientCreate, Event, EventCreate, Email, EmailGenerate, User } from '@/types';
import type { Profile, Client, ClientCreate, Event, EventCreate, Email, EmailGenerate, User, Invite } from '@/types';
const API_BASE = import.meta.env.PROD
? 'https://api.thenetwork.donovankelly.xyz/api'
@@ -223,6 +223,60 @@ class ApiClient {
async deleteEmail(id: string): Promise<void> {
await this.fetch(`/emails/${id}`, { method: 'DELETE' });
}
// Admin
async getUsers(): Promise<User[]> {
return this.fetch('/admin/users');
}
async updateUserRole(userId: string, role: string): Promise<void> {
await this.fetch(`/admin/users/${userId}/role`, {
method: 'PUT',
body: JSON.stringify({ role }),
});
}
async deleteUser(userId: string): Promise<void> {
await this.fetch(`/admin/users/${userId}`, { method: 'DELETE' });
}
async createInvite(data: { email: string; name: string; role?: string }): Promise<Invite & { setupUrl: string }> {
return this.fetch('/admin/invites', {
method: 'POST',
body: JSON.stringify(data),
});
}
async getInvites(): Promise<Invite[]> {
return this.fetch('/admin/invites');
}
async deleteInvite(id: string): Promise<void> {
await this.fetch(`/admin/invites/${id}`, { method: 'DELETE' });
}
// Invite acceptance (public - no auth)
async validateInvite(token: string): Promise<{ id: string; email: string; name: string; role: string; expiresAt: string }> {
const response = await fetch(`${AUTH_BASE}/auth/invite/${token}`);
if (!response.ok) {
const error = await response.json().catch(() => ({ error: 'Invalid invite' }));
throw new Error(error.error || 'Invalid invite');
}
return response.json();
}
async acceptInvite(token: string, password: string, name?: string): Promise<{ success: boolean; token?: string }> {
const response = await fetch(`${AUTH_BASE}/auth/invite/${token}/accept`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ password, name }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ error: 'Failed to accept invite' }));
throw new Error(error.error || 'Failed to accept invite');
}
return response.json();
}
}
export const api = new ApiClient();