diff --git a/src/app/dashboard/privacy/delegated/page.tsx b/src/app/dashboard/privacy/delegated/page.tsx new file mode 100644 index 0000000..ee5cb63 --- /dev/null +++ b/src/app/dashboard/privacy/delegated/page.tsx @@ -0,0 +1,169 @@ +'use client'; + +import { useState } from 'react'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { apiFetch } from '../../../../lib/api'; +import { useSession } from '../../../../components/session-provider'; + +interface Role { + id: string; name: string; description: string | null; + permissions: string[]; createdAt: string; isSystem: boolean | null; +} + +interface WorkspaceMember { + id: string; userId: string; email: string | null; role: string; joinedAt: string; +} + +const PERMISSION_LABELS: Record = { + read: 'Citire', write: 'Scriere', delete: 'Ștergere', admin: 'Admin', + ai: 'AI', export: 'Export', import: 'Import', billing: 'Facturare', +}; + +export default function DelegatedAccessPage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + const qc = useQueryClient(); + const [selected, setSelected] = useState(null); + const [showCreate, setShowCreate] = useState(false); + const [form, setForm] = useState({ name: '', description: '', permissions: [] as string[] }); + + const { data: roles = [], isLoading: rolesL } = useQuery({ + queryKey: ['roles-delegated', tenantId], + queryFn: () => apiFetch('/v1/roles', { tenantId }), + enabled: Boolean(tenantId), staleTime: 60_000, + }); + const { data: members = [] } = useQuery({ + queryKey: ['members-delegated', tenantId], + queryFn: () => apiFetch('/v1/workspace/members', { tenantId }), + enabled: Boolean(tenantId), staleTime: 60_000, + }); + + const createMut = useMutation({ + mutationFn: () => apiFetch('/v1/roles', { tenantId, method: 'POST', body: form }), + onSuccess: () => { qc.invalidateQueries({ queryKey: ['roles-delegated', tenantId] }); setShowCreate(false); setForm({ name: '', description: '', permissions: [] }); }, + }); + + function togglePerm(p: string) { + setForm((prev) => ({ ...prev, permissions: prev.permissions.includes(p) ? prev.permissions.filter((x) => x !== p) : [...prev.permissions, p] })); + } + + const PERMS = Object.keys(PERMISSION_LABELS); + const roleMembers = members.filter((m) => selected && m.role === selected.name); + + return ( +
+
+
+

Acces Delegat

+

+ {rolesL ? 'Se încarcă…' : `${roles.length} roluri · ${members.length} membri`} +

+
+ +
+ + {showCreate && ( +
+

Rol nou

+
+ setForm((p) => ({ ...p, name: e.target.value }))} + className="rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> + setForm((p) => ({ ...p, description: e.target.value }))} + className="rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> +
+
+

Permisiuni

+
+ {PERMS.map((p) => ( + + ))} +
+
+
+ + +
+
+ )} + +
+
+ {rolesL ?

Se încarcă…

+ : roles.length === 0 ?

Niciun rol.

+ : roles.map((role) => ( + + ))} +
+ +
+ {!selected ? ( +
+

🔑

+

Selectează un rol.

+
+ ) : ( +
+
+

{selected.name}

+ {selected.description &&

{selected.description}

} +
+ +
+

Permisiuni

+
+ {(selected.permissions ?? []).length === 0 ? ( +

Nicio permisiune.

+ ) : (selected.permissions ?? []).map((p) => ( + + {PERMISSION_LABELS[p] ?? p} + + ))} +
+
+ +
+

+ Membri cu acest rol ({roleMembers.length}) +

+ {roleMembers.length === 0 ? ( +

Niciun membru cu acest rol.

+ ) : roleMembers.map((m) => ( +
+
+ {(m.email ?? '?')[0].toUpperCase()} +
+ {m.email ?? m.userId} + + {new Date(m.joinedAt).toLocaleDateString('ro-RO')} + +
+ ))} +
+
+ )} +
+
+
+ ); +}