344 lines
12 KiB
TypeScript
344 lines
12 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
import { Users, UserPlus, Shield, Settings, Mail, Activity } from 'lucide-react';
|
|
import { UsersTable } from '@/components/users/UsersTable';
|
|
import { PendingUsersTable } from '@/components/users/PendingUsersTable';
|
|
import { FunctionsManager } from '@/components/users/FunctionsManager';
|
|
import { PrivilegesManager } from '@/components/users/PrivilegesManager';
|
|
import { PasswordResetRequests } from '@/components/users/PasswordResetRequests';
|
|
import { SessionLogsSimple } from '@/components/users/SessionLogsSimple';
|
|
import { UserModal } from '@/components/users/UserModal';
|
|
import { useUserManagement, UserProfile } from '@/hooks/useUserManagement';
|
|
import { usePermissionControl } from '@/hooks/usePermissionControl';
|
|
|
|
const UserManagement = () => {
|
|
const [isUserModalOpen, setIsUserModalOpen] = useState(false);
|
|
const [selectedUser, setSelectedUser] = useState<UserProfile | null>(null);
|
|
const [activeTab, setActiveTab] = useState('users');
|
|
|
|
const {
|
|
canView,
|
|
canCreate,
|
|
canEdit,
|
|
canDelete,
|
|
canAdmin,
|
|
isDisabled,
|
|
canInteractWithSpecialMenus
|
|
} = usePermissionControl();
|
|
|
|
const {
|
|
users,
|
|
pendingUsers,
|
|
functions,
|
|
privileges,
|
|
createUser,
|
|
approveUser,
|
|
rejectUser,
|
|
createFunction,
|
|
updateFunction,
|
|
deleteFunction,
|
|
createPrivilege: createPrivilegeBase,
|
|
updatePrivilege: updatePrivilegeBase,
|
|
deletePrivilege,
|
|
updateUser,
|
|
toggleUserStatus,
|
|
deleteUser,
|
|
canDeleteUser,
|
|
getUserDependencies
|
|
} = useUserManagement();
|
|
|
|
// Verificar se pode acessar esta página - somente admins ou usuários com permissões especiais
|
|
if (!canView() || !canInteractWithSpecialMenus()) {
|
|
return (
|
|
<div className="flex items-center justify-center min-h-screen">
|
|
<div className="text-center space-y-4">
|
|
<div className="text-6xl">🔒</div>
|
|
<h2 className="text-2xl font-semibold text-muted-foreground">
|
|
Acesso Negado
|
|
</h2>
|
|
<p className="text-muted-foreground max-w-md">
|
|
Você não tem permissão para acessar o gerenciamento de usuários.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Wrapper functions to match expected signatures
|
|
const createPrivilege = async (data: { name: string; description?: string; permissions: Record<string, boolean> }): Promise<void> => {
|
|
await createPrivilegeBase(data);
|
|
};
|
|
|
|
const updatePrivilege = async (id: string, data: { name: string; description?: string; permissions: Record<string, boolean> }): Promise<void> => {
|
|
await updatePrivilegeBase(id, data);
|
|
};
|
|
|
|
const handleEditUser = (user: UserProfile) => {
|
|
if (!canEdit()) return;
|
|
setSelectedUser(user);
|
|
setIsUserModalOpen(true);
|
|
};
|
|
|
|
const handleCreateUser = () => {
|
|
if (!canCreate()) return;
|
|
setSelectedUser(null);
|
|
setIsUserModalOpen(true);
|
|
};
|
|
|
|
const handleToggleStatus = (userId: string) => {
|
|
if (!canEdit()) return;
|
|
const user = users.find(u => u.id === userId);
|
|
if (user) {
|
|
toggleUserStatus(userId, user.status);
|
|
}
|
|
};
|
|
|
|
const handleDeleteUser = async (userId: string, replaceReferences: boolean = false) => {
|
|
if (!canDelete()) return;
|
|
return await deleteUser(userId, replaceReferences);
|
|
};
|
|
|
|
const handleApproveUser = (userId: string) => {
|
|
if (!canEdit()) return;
|
|
approveUser(userId);
|
|
};
|
|
|
|
const handleRejectUser = (userId: string) => {
|
|
if (!canDelete()) return;
|
|
rejectUser(userId);
|
|
};
|
|
|
|
const handleSaveUser = (userId: string, data: Partial<UserProfile>) => {
|
|
if (!canEdit()) return;
|
|
updateUser(userId, data);
|
|
setSelectedUser(null);
|
|
setIsUserModalOpen(false);
|
|
};
|
|
|
|
const handleCreateNewUser = async (data: {
|
|
email: string;
|
|
full_name?: string;
|
|
function_id?: string;
|
|
privilege_id?: string;
|
|
}) => {
|
|
if (!canCreate()) return;
|
|
try {
|
|
await createUser(data);
|
|
setIsUserModalOpen(false);
|
|
} catch (error) {
|
|
// Error is already handled in the hook
|
|
}
|
|
};
|
|
|
|
const handleCloseModal = () => {
|
|
setSelectedUser(null);
|
|
setIsUserModalOpen(false);
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4 md:space-y-6 p-2 md:p-0">
|
|
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 sm:gap-4">
|
|
<div>
|
|
<h1 className="text-2xl md:text-3xl font-bold text-foreground">Usuários e Privilégios</h1>
|
|
<p className="text-sm md:text-base text-muted-foreground">Gerenciamento de usuários, funções e privilégios do sistema</p>
|
|
</div>
|
|
{canCreate() && (
|
|
<Button
|
|
onClick={handleCreateUser}
|
|
className="mobile-full-width"
|
|
disabled={isDisabled('create')}
|
|
>
|
|
<UserPlus className="w-4 h-4 mr-2" />
|
|
<span className="text-sm md:text-base">Novo Usuário</span>
|
|
</Button>
|
|
)}
|
|
</div>
|
|
|
|
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
|
|
<TabsList className="grid w-full grid-cols-2 md:grid-cols-6 bg-muted h-auto p-1">
|
|
<TabsTrigger
|
|
value="users"
|
|
className="flex items-center gap-1 md:gap-2 text-xs md:text-sm p-2 md:p-3"
|
|
>
|
|
<Users className="h-3 w-3 md:h-4 md:w-4" />
|
|
<span className="hidden sm:inline">Usuários</span>
|
|
<span className="sm:hidden">Users</span>
|
|
</TabsTrigger>
|
|
|
|
{canEdit() && (
|
|
<TabsTrigger
|
|
value="pending"
|
|
className="flex items-center gap-1 md:gap-2 text-xs md:text-sm p-2 md:p-3"
|
|
>
|
|
<UserPlus className="h-3 w-3 md:h-4 md:w-4" />
|
|
<span className="hidden sm:inline">Pendentes</span>
|
|
<span className="sm:hidden">Pend</span>
|
|
</TabsTrigger>
|
|
)}
|
|
|
|
{canAdmin() && (
|
|
<TabsTrigger
|
|
value="password-reset"
|
|
className="flex items-center gap-1 md:gap-2 text-xs md:text-sm p-2 md:p-3"
|
|
>
|
|
<Mail className="h-3 w-3 md:h-4 md:w-4" />
|
|
<span className="hidden sm:inline">Redefinições</span>
|
|
<span className="sm:hidden">Reset</span>
|
|
</TabsTrigger>
|
|
)}
|
|
|
|
{canEdit() && (
|
|
<TabsTrigger
|
|
value="functions"
|
|
className="flex items-center gap-1 md:gap-2 text-xs md:text-sm p-2 md:p-3"
|
|
>
|
|
<Settings className="h-3 w-3 md:h-4 md:w-4" />
|
|
<span className="hidden sm:inline">Funções</span>
|
|
<span className="sm:hidden">Func</span>
|
|
</TabsTrigger>
|
|
)}
|
|
|
|
{canEdit() && (
|
|
<TabsTrigger
|
|
value="privileges"
|
|
className="flex items-center gap-1 md:gap-2 text-xs md:text-sm p-2 md:p-3"
|
|
>
|
|
<Shield className="h-3 w-3 md:h-4 md:w-4" />
|
|
<span className="hidden sm:inline">Privilégios</span>
|
|
<span className="sm:hidden">Priv</span>
|
|
</TabsTrigger>
|
|
)}
|
|
|
|
{canView() && (
|
|
<TabsTrigger
|
|
value="session-logs"
|
|
className="flex items-center gap-1 md:gap-2 text-xs md:text-sm p-2 md:p-3"
|
|
>
|
|
<Activity className="h-3 w-3 md:h-4 md:w-4" />
|
|
<span className="hidden sm:inline">Logs de Sessão</span>
|
|
<span className="sm:hidden">Logs</span>
|
|
</TabsTrigger>
|
|
)}
|
|
</TabsList>
|
|
|
|
<TabsContent value="users" className="space-y-4 mt-4">
|
|
<Card className="card-mobile">
|
|
<CardHeader className="card-header-mobile">
|
|
<CardTitle className="text-lg md:text-xl flex items-center gap-2">
|
|
<Users className="h-4 w-4 md:h-5 md:w-5" />
|
|
Usuários Ativos
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="card-content-mobile">
|
|
<div className="overflow-x-auto custom-scrollbar">
|
|
<UsersTable
|
|
users={users}
|
|
functions={functions}
|
|
privileges={privileges}
|
|
onEditUser={canEdit() ? handleEditUser : undefined}
|
|
onToggleStatus={canEdit() ? handleToggleStatus : undefined}
|
|
onDeleteUser={canDelete() ? handleDeleteUser : undefined}
|
|
canDeleteUser={canDeleteUser}
|
|
getUserDependencies={getUserDependencies}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
|
|
{canEdit() && (
|
|
<TabsContent value="pending" className="space-y-4 mt-4">
|
|
<Card className="card-mobile">
|
|
<CardHeader className="card-header-mobile">
|
|
<CardTitle className="text-lg md:text-xl flex items-center gap-2">
|
|
<UserPlus className="h-4 w-4 md:h-5 md:w-5" />
|
|
Usuários Pendentes
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="card-content-mobile">
|
|
<div className="overflow-x-auto custom-scrollbar">
|
|
<PendingUsersTable
|
|
users={pendingUsers}
|
|
onApprove={handleApproveUser}
|
|
onReject={handleRejectUser}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
)}
|
|
|
|
{canAdmin() && (
|
|
<TabsContent value="password-reset" className="space-y-4 mt-4">
|
|
<PasswordResetRequests />
|
|
</TabsContent>
|
|
)}
|
|
|
|
{canEdit() && (
|
|
<TabsContent value="functions" className="space-y-4 mt-4">
|
|
<Card className="card-mobile">
|
|
<CardHeader className="card-header-mobile">
|
|
<CardTitle className="text-lg md:text-xl flex items-center gap-2">
|
|
<Settings className="h-4 w-4 md:h-5 md:w-5" />
|
|
Gerenciar Funções
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="card-content-mobile">
|
|
<FunctionsManager
|
|
functions={functions}
|
|
onCreate={canCreate() ? createFunction : undefined}
|
|
onUpdate={canEdit() ? updateFunction : undefined}
|
|
onDelete={canDelete() ? deleteFunction : undefined}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
)}
|
|
|
|
{canEdit() && (
|
|
<TabsContent value="privileges" className="space-y-4 mt-4">
|
|
<Card className="card-mobile">
|
|
<CardHeader className="card-header-mobile">
|
|
<CardTitle className="text-lg md:text-xl flex items-center gap-2">
|
|
<Shield className="h-4 w-4 md:h-5 md:w-5" />
|
|
Gerenciar Privilégios
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="card-content-mobile">
|
|
<PrivilegesManager
|
|
privileges={privileges}
|
|
onCreate={canCreate() ? createPrivilege : undefined}
|
|
onUpdate={canEdit() ? updatePrivilege : undefined}
|
|
onDelete={canDelete() ? deletePrivilege : undefined}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
</TabsContent>
|
|
)}
|
|
|
|
{canView() && (
|
|
<TabsContent value="session-logs" className="space-y-4 mt-4">
|
|
<SessionLogsSimple users={users} />
|
|
</TabsContent>
|
|
)}
|
|
</Tabs>
|
|
|
|
{isUserModalOpen && (
|
|
<UserModal
|
|
user={selectedUser}
|
|
functions={functions}
|
|
privileges={privileges}
|
|
onSave={canEdit() ? handleSaveUser : undefined}
|
|
onCreate={canCreate() ? handleCreateNewUser : undefined}
|
|
onClose={handleCloseModal}
|
|
readOnly={!canEdit() && !canCreate()}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default UserManagement;
|