add staff managment permission modal window
This commit is contained in:
@@ -112,7 +112,6 @@ export async function authorization(
|
||||
|
||||
export async function logout() {
|
||||
const token = await getSessionData('token');
|
||||
console.log('logout');
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api/admin`, {
|
||||
@@ -133,7 +132,6 @@ export async function logout() {
|
||||
|
||||
if (response.ok) {
|
||||
let parsed = await response.json();
|
||||
console.log(parsed);
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
|
||||
@@ -130,3 +130,57 @@ export async function removeStuff(id: number) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
type Permissions = {
|
||||
subscriptions: number;
|
||||
mailings: number;
|
||||
complaints: number;
|
||||
agreements: number;
|
||||
staff: number;
|
||||
content_moderation: number;
|
||||
users: number;
|
||||
money: number;
|
||||
kyc: number;
|
||||
claims: number;
|
||||
api: number;
|
||||
dash: number;
|
||||
tariffs: number;
|
||||
};
|
||||
|
||||
export async function updateStuffPermissions(id: number, permissions: Permissions) {
|
||||
const token = await getSessionData('token');
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/api/admin`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
version: 2,
|
||||
msg_id: 100,
|
||||
token: token,
|
||||
message_body: {
|
||||
action: 'update_permissions',
|
||||
admin_id: id,
|
||||
permissions: permissions
|
||||
}
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const parsed = await response.json();
|
||||
|
||||
if (parsed.message_code === 0) {
|
||||
return parsed.message_body;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
.edit-permissions-modal {
|
||||
padding: 24px;
|
||||
max-width: 900px;
|
||||
width: 100%;
|
||||
max-height: 85vh;
|
||||
overflow-y: auto;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
|
||||
.modal-header {
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
|
||||
.modal-title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.permissions-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
margin-bottom: 28px;
|
||||
|
||||
.permission-item {
|
||||
/* border: 1px solid #e9ecef; */
|
||||
border-radius: 12px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
/* &:hover {
|
||||
border-color: #dee2e6;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
} */
|
||||
|
||||
.permission-header {
|
||||
/* padding: 20px; */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.permission-info {
|
||||
flex: 1;
|
||||
|
||||
.permission-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #212529;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.permission-description {
|
||||
font-size: 13px;
|
||||
color: #6c757d;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.permission-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.permission-level-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
background: #f8f9fa;
|
||||
padding: 4px;
|
||||
border-radius: 8px;
|
||||
|
||||
.permission-level-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
font-size: 13px;
|
||||
color: #6c757d;
|
||||
|
||||
.btn-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: white;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&.no-access {
|
||||
color: #dc3545;
|
||||
background: #fff5f5;
|
||||
}
|
||||
|
||||
&.read-only {
|
||||
color: #0d6efd;
|
||||
background: #f0f7ff;
|
||||
}
|
||||
|
||||
&.full-access {
|
||||
color: #198754;
|
||||
background: #f0fff4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e9ecef;
|
||||
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: #5a6268;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-primary {
|
||||
background: #0d6efd;
|
||||
color: white;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: #0b5ed7;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: white;
|
||||
animation: spin 0.6s linear infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
// Scrollbar styling
|
||||
.edit-permissions-modal::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.edit-permissions-modal::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.edit-permissions-modal::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
border-radius: 10px;
|
||||
|
||||
&:hover {
|
||||
background: #555;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
@use './variable.scss' as v;
|
||||
@use './edit-permissions-modal.scss';
|
||||
|
||||
:root {
|
||||
--primary-color: #2563eb;
|
||||
|
||||
@@ -227,7 +227,6 @@ async function createStuffAction(
|
||||
} catch (error) {
|
||||
const errors: Record<string, string> = {}
|
||||
|
||||
// Обработка различных ошибок от сервера
|
||||
switch (error) {
|
||||
case 'email-already-exists':
|
||||
errors['email'] = 'email-already-exists';
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { StaffMember } from './tanstak-stuff-table';
|
||||
|
||||
export function EditPermissionsModal({
|
||||
staff,
|
||||
setWindowClose,
|
||||
onSave,
|
||||
isLoading
|
||||
}: {
|
||||
staff: StaffMember;
|
||||
setWindowClose: (state: boolean) => void;
|
||||
onSave: (permissions: StaffMember['permissions']) => Promise<void>;
|
||||
isLoading: boolean;
|
||||
}) {
|
||||
const t = useTranslations("Global");
|
||||
const tPermissions = useTranslations("Permissions");
|
||||
|
||||
const [permissions, setPermissions] = useState<StaffMember['permissions']>(staff.permissions);
|
||||
|
||||
const permissionsConfig = [
|
||||
{ key: 'subscriptions', label: tPermissions('subscriptions'), description: tPermissions('subscriptions-desc') },
|
||||
{ key: 'mailings', label: tPermissions('mailings'), description: tPermissions('mailings-desc') },
|
||||
{ key: 'complaints', label: tPermissions('complaints'), description: tPermissions('complaints-desc') },
|
||||
{ key: 'agreements', label: tPermissions('agreements'), description: tPermissions('agreements-desc') },
|
||||
{ key: 'staff', label: tPermissions('staff'), description: tPermissions('staff-desc') },
|
||||
{ key: 'content_moderation', label: tPermissions('content_moderation'), description: tPermissions('content_moderation-desc') },
|
||||
{ key: 'users', label: tPermissions('users'), description: tPermissions('users-desc') },
|
||||
{ key: 'kyc', label: tPermissions('kyc'), description: tPermissions('kyc-desc') },
|
||||
{ key: 'money', label: tPermissions('money'), description: tPermissions('money-desc') },
|
||||
{ key: 'claims', label: tPermissions('claims'), description: tPermissions('claims-desc') },
|
||||
{ key: 'api', label: tPermissions('api'), description: tPermissions('api-desc') },
|
||||
{ key: 'dash', label: tPermissions('dash'), description: tPermissions('dash-desc') },
|
||||
{ key: 'tariffs', label: tPermissions('tariffs'), description: tPermissions('tariffs-desc') },
|
||||
];
|
||||
|
||||
const handlePermissionChange = (key: keyof StaffMember['permissions'], value: number) => {
|
||||
setPermissions(prev => ({
|
||||
...prev,
|
||||
[key]: value
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
await onSave(permissions);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="edit-permissions-modal">
|
||||
<div className="modal-header">
|
||||
<h2 className="modal-title">
|
||||
{tPermissions('edit-permissions')}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="permissions-list">
|
||||
{permissionsConfig.map((perm) => {
|
||||
const currentValue = permissions[perm.key as keyof StaffMember['permissions']];
|
||||
|
||||
return (
|
||||
<div key={perm.key} className="permission-item">
|
||||
<div className="permission-header">
|
||||
<div className="permission-info">
|
||||
<h3 className="permission-title">{perm.label}</h3>
|
||||
{/* <p className="permission-description">{perm.description}</p> */}
|
||||
</div>
|
||||
<div className="permission-controls">
|
||||
<div className="permission-level-buttons">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handlePermissionChange(perm.key as keyof StaffMember['permissions'], 0)}
|
||||
className={`permission-level-btn ${currentValue === 0 ? 'active no-access' : ''}`}
|
||||
title={tPermissions('no-access')}
|
||||
>
|
||||
<span className="btn-text">{tPermissions('no-access')}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handlePermissionChange(perm.key as keyof StaffMember['permissions'], 1)}
|
||||
className={`permission-level-btn ${currentValue === 1 ? 'active read-only' : ''}`}
|
||||
title={tPermissions('read-only')}
|
||||
>
|
||||
<span className="btn-text">{tPermissions('read-only')}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handlePermissionChange(perm.key as keyof StaffMember['permissions'], 3)}
|
||||
className={`permission-level-btn ${currentValue === 3 ? 'active full-access' : ''}`}
|
||||
title={tPermissions('full-access')}
|
||||
>
|
||||
<span className="btn-text">{tPermissions('full-access')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="modal-footer">
|
||||
<button
|
||||
onClick={() => setWindowClose(false)}
|
||||
className="btn btn-secondary"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{t('cancel')}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleSave}
|
||||
className="btn btn-primary"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<span className="spinner"></span>
|
||||
{t('saving')}
|
||||
</>
|
||||
) : t('save-changes')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { StaffMember } from '@/app/ui/staff-management/tanstak-stuff-table';
|
||||
import { formatDate, formatDateTime } from '@/app/lib/formatDate';
|
||||
|
||||
export function StaffInfoModal({
|
||||
staff,
|
||||
setWindowClose,
|
||||
setWindowChildren
|
||||
}: {
|
||||
staff: StaffMember;
|
||||
setWindowClose: (state: boolean) => void;
|
||||
setWindowChildren: (children: ReactNode) => void;
|
||||
}) {
|
||||
const t = useTranslations("Global");
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-2xl">
|
||||
<h2 className="text-2xl font-bold mb-4">Информация о сотруднике</h2>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<strong>ID:</strong> {staff.id}
|
||||
</div>
|
||||
<div>
|
||||
<strong>ФИО:</strong> {staff.full_name}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Email:</strong> {staff.email}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Статус:</strong> {staff.is_active ? 'Активен' : 'Неактивен'}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Роль:</strong> {staff.is_super_admin ? 'Super Admin' : 'Staff'}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Дата создания:</strong> {formatDateTime(staff.created_at)} {formatDate(staff.created_at)}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Активный пароль:</strong> {staff.active_password ? 'Да' : 'Нет'}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong className="block mb-2">Права доступа:</strong>
|
||||
<div className="grid grid-cols-2 gap-2 bg-gray-50 p-3 rounded">
|
||||
{Object.entries(staff.permissions).map(([key, value]) => (
|
||||
<div key={key} className="flex justify-between">
|
||||
<span className="capitalize">{key}:</span>
|
||||
<span className="font-semibold">
|
||||
{value === 1 ? 'Чтение' : value === 2 ? 'Запись' : value === 3 ? 'Полный доступ' : value}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex justify-end">
|
||||
<button
|
||||
onClick={() => setWindowClose(false)}
|
||||
className="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600"
|
||||
>
|
||||
{t('close')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -19,9 +19,12 @@ import ModalWindow from '@/app/components/modalWindow';
|
||||
import { toast } from 'sonner';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import { useStuffList } from '@/app/hooks/react-query/stuff/useStuffList';
|
||||
import { removeStuff } from '@/app/actions/stuffActions';
|
||||
import { removeStuff, updateStuffPermissions } from '@/app/actions/stuffActions';
|
||||
import { EditPermissionsModal } from './EditPermissionsModal'
|
||||
import { StaffInfoModal } from '@/app/ui/staff-management/StaffInfoModal';
|
||||
import { formatDate, formatDateTime } from '@/app/lib/formatDate';
|
||||
|
||||
interface StaffMember {
|
||||
export interface StaffMember {
|
||||
id: number;
|
||||
full_name: string;
|
||||
email: string;
|
||||
@@ -46,24 +49,6 @@ interface StaffMember {
|
||||
};
|
||||
}
|
||||
|
||||
// Форматирование даты из ISO строки
|
||||
const formatDate = (dateString: string) => {
|
||||
const date = new Date(dateString);
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const year = date.getFullYear();
|
||||
|
||||
return `${day}.${month}.${year}`;
|
||||
};
|
||||
|
||||
const formatDateTime = (dateString: string) => {
|
||||
const date = new Date(dateString);
|
||||
const hours = date.getHours().toString().padStart(2, '0');
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||
|
||||
return `${hours}:${minutes}`;
|
||||
};
|
||||
|
||||
export default function TanstakStuffTable() {
|
||||
// Состояния
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
@@ -128,10 +113,6 @@ export default function TanstakStuffTable() {
|
||||
const totalItems = staffList?.length || 0;
|
||||
const totalPages = Math.ceil(totalItems / pagination.pageSize);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(staffList);
|
||||
}, [staffList])
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const removeMutation = useMutation({
|
||||
mutationFn: (id: number) => removeStuff(id),
|
||||
@@ -147,6 +128,19 @@ export default function TanstakStuffTable() {
|
||||
}
|
||||
});
|
||||
|
||||
const updatePermissionsMutation = useMutation({
|
||||
mutationFn: ({ id, permissions }: { id: number; permissions: StaffMember['permissions'] }) =>
|
||||
updateStuffPermissions(id, permissions),
|
||||
onSuccess: () => {
|
||||
toast.success(tStaff('permissions-updated-successfully'));
|
||||
queryClient.invalidateQueries({ queryKey: ['stuffList'] });
|
||||
setOpenWindow(false);
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.error(tStaff(error.message || 'permissions-update-failed'));
|
||||
}
|
||||
});
|
||||
|
||||
// Определение колонок для сотрудников
|
||||
const columns = useMemo<ColumnDef<StaffMember>[]>(
|
||||
() => [
|
||||
@@ -308,6 +302,13 @@ export default function TanstakStuffTable() {
|
||||
>
|
||||
<IconEye />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleEditPermissions(row.original)}
|
||||
className="bg-green-500 hover:bg-green-600"
|
||||
title="Редактировать права доступа"
|
||||
>
|
||||
<IconShieldExclamation />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleRemove(row.original.id, row.original.full_name)}
|
||||
className="bg-red-500 hover:bg-red-600"
|
||||
@@ -343,13 +344,28 @@ export default function TanstakStuffTable() {
|
||||
setConfirmRemove({ id, name });
|
||||
};
|
||||
|
||||
// Фильтрация данных (если нужна клиентская фильтрация)
|
||||
const handleEditPermissions = (staff: StaffMember) => {
|
||||
setSelectedStaff(staff);
|
||||
setOpenWindowChildren(() => {
|
||||
return (
|
||||
<EditPermissionsModal
|
||||
staff={staff}
|
||||
setWindowClose={setOpenWindow}
|
||||
onSave={async (permissions) => {
|
||||
await updatePermissionsMutation.mutateAsync({ id: staff.id, permissions });
|
||||
}}
|
||||
isLoading={updatePermissionsMutation.isPending}
|
||||
/>
|
||||
)
|
||||
})
|
||||
setOpenWindow(true);
|
||||
};
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (!staffList) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Если серверная фильтрация уже применена, возвращаем как есть
|
||||
return staffList;
|
||||
}, [staffList]);
|
||||
|
||||
@@ -587,69 +603,3 @@ export default function TanstakStuffTable() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Компонент модального окна с информацией о сотруднике
|
||||
function StaffInfoModal({
|
||||
staff,
|
||||
setWindowClose,
|
||||
setWindowChildren
|
||||
}: {
|
||||
staff: StaffMember;
|
||||
setWindowClose: (state: boolean) => void;
|
||||
setWindowChildren: (children: ReactNode) => void;
|
||||
}) {
|
||||
const t = useTranslations("Global");
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-2xl">
|
||||
<h2 className="text-2xl font-bold mb-4">Информация о сотруднике</h2>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<strong>ID:</strong> {staff.id}
|
||||
</div>
|
||||
<div>
|
||||
<strong>ФИО:</strong> {staff.full_name}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Email:</strong> {staff.email}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Статус:</strong> {staff.is_active ? 'Активен' : 'Неактивен'}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Роль:</strong> {staff.is_super_admin ? 'Super Admin' : 'Staff'}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Дата создания:</strong> {formatDateTime(staff.created_at)} {formatDate(staff.created_at)}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Активный пароль:</strong> {staff.active_password ? 'Да' : 'Нет'}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong className="block mb-2">Права доступа:</strong>
|
||||
<div className="grid grid-cols-2 gap-2 bg-gray-50 p-3 rounded">
|
||||
{Object.entries(staff.permissions).map(([key, value]) => (
|
||||
<div key={key} className="flex justify-between">
|
||||
<span className="capitalize">{key}:</span>
|
||||
<span className="font-semibold">
|
||||
{value === 1 ? 'Чтение' : value === 2 ? 'Запись' : value === 3 ? 'Полный доступ' : value}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex justify-end">
|
||||
<button
|
||||
onClick={() => setWindowClose(false)}
|
||||
className="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600"
|
||||
>
|
||||
{t('close')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -188,7 +188,9 @@
|
||||
"storageInformation": "Storage Information",
|
||||
"diskUsage": "Disk Usage",
|
||||
"diskUsagePercent": "Usage",
|
||||
"fileCount": "Files"
|
||||
"fileCount": "Files",
|
||||
"employee": "Employee",
|
||||
"role": "Role"
|
||||
},
|
||||
"Login-register-form": {
|
||||
"and": "and",
|
||||
@@ -269,6 +271,40 @@
|
||||
"passwords-do-not-match": "Passwords do not match",
|
||||
"email-already-exists": "User with this email already exists",
|
||||
"staff-removed-successfully": "The employee has been successfully removed",
|
||||
"removal-failed": "Error deleting employee"
|
||||
"removal-failed": "Error deleting employee",
|
||||
"permissions-updated-successfully": "Permissions updated successfully",
|
||||
"permissions-update-failed": "Failed to update permissions"
|
||||
},
|
||||
"Permissions": {
|
||||
"edit-permissions": "Edit Permissions",
|
||||
"no-access": "No Access",
|
||||
"read-only": "Read Only",
|
||||
"full-access": "Full Access",
|
||||
"subscriptions": "Subscriptions",
|
||||
"subscriptions-desc": "Manage user subscriptions",
|
||||
"mailings": "Mailings",
|
||||
"mailings-desc": "Manage email mailings",
|
||||
"complaints": "Complaints",
|
||||
"complaints-desc": "Process user complaints",
|
||||
"agreements": "Agreements",
|
||||
"agreements-desc": "Manage user agreements",
|
||||
"staff": "Staff",
|
||||
"staff-desc": "Manage staff members",
|
||||
"content_moderation": "Content Moderation",
|
||||
"content_moderation-desc": "Moderate content",
|
||||
"users": "Users",
|
||||
"users-desc": "Manage users",
|
||||
"kyc": "Verification",
|
||||
"kyc-desc": "Manage user verification",
|
||||
"money": "Money",
|
||||
"money-desc": "Manage financial operations",
|
||||
"claims": "Claims",
|
||||
"claims-desc": "Process claims",
|
||||
"api": "API",
|
||||
"api-desc": "Manage API access",
|
||||
"dash": "Dashboard",
|
||||
"dash-desc": "Access to dashboard",
|
||||
"tariffs": "Tariffs",
|
||||
"tariffs-desc": "Manage tariffs"
|
||||
}
|
||||
}
|
||||
@@ -188,7 +188,9 @@
|
||||
"storageInformation": "Информация о хранилище",
|
||||
"diskUsage": "Использование диска",
|
||||
"diskUsagePercent": "Заполнение",
|
||||
"fileCount": "Файлы"
|
||||
"fileCount": "Файлы",
|
||||
"employee": "Сотрудник",
|
||||
"role": "Роль"
|
||||
},
|
||||
"Login-register-form": {
|
||||
"and": "и",
|
||||
@@ -269,6 +271,40 @@
|
||||
"passwords-do-not-match": "Пароли не совпадают",
|
||||
"email-already-exists": "Пользователь с таким адресом электронной почты уже существует",
|
||||
"staff-removed-successfully": "Сотрудник успешно удален",
|
||||
"removal-failed": "Ошибка при удалении сотрудника"
|
||||
"removal-failed": "Ошибка при удалении сотрудника",
|
||||
"permissions-updated-successfully": "Права доступа успешно обновлены",
|
||||
"permissions-update-failed": "Не удалось обновить права доступа"
|
||||
},
|
||||
"Permissions": {
|
||||
"edit-permissions": "Редактирование прав доступа",
|
||||
"no-access": "Нет доступа",
|
||||
"read-only": "Только чтение",
|
||||
"full-access": "Полный доступ",
|
||||
"subscriptions": "Подписки",
|
||||
"subscriptions-desc": "Управление подписками пользователей",
|
||||
"mailings": "Рассылки",
|
||||
"mailings-desc": "Управление email рассылками",
|
||||
"complaints": "Жалобы",
|
||||
"complaints-desc": "Обработка жалоб пользователей",
|
||||
"agreements": "Соглашения",
|
||||
"agreements-desc": "Управление пользовательскими соглашениями",
|
||||
"staff": "Сотрудники",
|
||||
"staff-desc": "Управление сотрудниками",
|
||||
"content_moderation": "Модерация контента",
|
||||
"content_moderation-desc": "Модерация контента",
|
||||
"users": "Пользователи",
|
||||
"users-desc": "Управление пользователями",
|
||||
"kyc": "Верификация",
|
||||
"kyc-desc": "Управление верификацией пользователей",
|
||||
"money": "Финансы",
|
||||
"money-desc": "Управление финансовыми операциями",
|
||||
"claims": "Претензии",
|
||||
"claims-desc": "Обработка претензий",
|
||||
"api": "API",
|
||||
"api-desc": "Управление API доступами",
|
||||
"dash": "Панель управления",
|
||||
"dash-desc": "Доступ к панеле управления",
|
||||
"tariffs": "Тарифы",
|
||||
"tariffs-desc": "Управление тарифами"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user