feat(B3): add tenant management UI (CRUD + tenant selector)
- frontend/src/api/tenants.ts: Tenant CRUD API client (getTenants, getTenant, createTenant, updateTenant, deleteTenant) - frontend/src/pages/Tenants.tsx: Admin page with table, create/edit modals, delete confirm, and cross-tenant selector persisted in localStorage - App.tsx: /tenants route (AdminRoute-guarded) - Layout.tsx: Tenants sidebar link (admin-only, Building2 icon) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import api from './client'
|
||||
|
||||
export interface Tenant {
|
||||
id: string
|
||||
name: string
|
||||
slug: string
|
||||
is_active: boolean
|
||||
user_count?: number
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface TenantCreate {
|
||||
name: string
|
||||
slug: string
|
||||
is_active?: boolean
|
||||
}
|
||||
|
||||
export interface TenantUpdate {
|
||||
name?: string
|
||||
slug?: string
|
||||
is_active?: boolean
|
||||
}
|
||||
|
||||
export async function getTenants(): Promise<Tenant[]> {
|
||||
const res = await api.get<Tenant[]>('/tenants')
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function getTenant(id: string): Promise<Tenant> {
|
||||
const res = await api.get<Tenant>(`/tenants/${id}`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function createTenant(data: TenantCreate): Promise<Tenant> {
|
||||
const res = await api.post<Tenant>('/tenants', data)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function updateTenant(id: string, data: TenantUpdate): Promise<Tenant> {
|
||||
const res = await api.patch<Tenant>(`/tenants/${id}`, data)
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function deleteTenant(id: string): Promise<void> {
|
||||
await api.delete(`/tenants/${id}`)
|
||||
}
|
||||
Reference in New Issue
Block a user