Tampilan Layout sudah sesuai dengan roleIdnya

Sudah sessionnya
Sudah disesuaikan juga semisal superadmin ngubah role admin, maka admin tersebut akan logOut dan diarahkan ke halama login
sudah bisa logOut
This commit is contained in:
2025-11-21 17:26:38 +08:00
parent 0dff8f3254
commit a291bdfb51
16 changed files with 965 additions and 275 deletions

View File

@@ -2,14 +2,13 @@
import colors from '@/con/colors';
import { Box, Button, Center, Group, Pagination, Paper, Select, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text, Title, Tooltip } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { IconCheck, IconSearch, IconX } from '@tabler/icons-react';
import { IconCheck, IconSearch, IconTrash, IconX } from '@tabler/icons-react';
import { useState } from 'react';
import { useProxy } from 'valtio/utils';
import HeaderSearch from '../../_com/header';
import { ModalKonfirmasiHapus } from '../../_com/modalKonfirmasiHapus';
import user from '../../_state/user/user-state';
function User() {
const [search, setSearch] = useState("");
return (
@@ -27,10 +26,10 @@ function User() {
}
function ListUser({ search }: { search: string }) {
const stateUser = useProxy(user.userState)
const stateRole = useProxy(user.roleState)
const [modalHapus, setModalHapus] = useState(false)
const [selectedId, setSelectedId] = useState<string | null>(null)
const stateUser = useProxy(user.userState);
const stateRole = useProxy(user.roleState);
const [modalHapus, setModalHapus] = useState(false);
const [selectedId, setSelectedId] = useState<string | null>(null);
const {
data,
@@ -42,21 +41,80 @@ function ListUser({ search }: { search: string }) {
const handleDelete = () => {
if (selectedId) {
stateUser.delete.submit(selectedId)
setModalHapus(false)
setSelectedId(null)
stateUser.findMany.load()
stateUser.deleteUser.delete(selectedId);
setModalHapus(false);
setSelectedId(null);
stateUser.findMany.load();
}
}
};
useShallowEffect(() => {
stateRole.findMany.load()
load(page, 10, search)
}, [page, search])
stateRole.findMany.load();
load(page, 10, search);
}, [page, search]);
const filteredData = data || []
// ✅ Helper function untuk nama role
const getRoleName = (roleId: string) => {
// Cari dari data role yang sudah diload
const role = stateRole.findMany.data.find((r) => r.id === roleId);
return role?.name || "Unknown Role";
};
// ✅ Handler untuk perubahan role dengan konfirmasi
const handleRoleChange = async (
userId: string,
username: string,
oldRoleId: string,
newRoleId: string
) => {
// Skip jika sama
if (oldRoleId === newRoleId) {
return true;
}
// ✅ Konfirmasi perubahan role
const confirmed = window.confirm(
`⚠️ PERINGATAN\n\n` +
`Mengubah role untuk "${username}" akan:\n` +
`• Logout user otomatis dari semua device\n` +
`• Mengubah akses menu sesuai role baru\n\n` +
`Role: ${getRoleName(oldRoleId)}${getRoleName(newRoleId)}\n\n` +
`Lanjutkan?`
);
if (!confirmed) {
// Reload data untuk reset dropdown ke nilai lama
stateUser.findMany.load(page, 10, search);
return false;
}
// ✅ Submit update
const success = await stateUser.update.submit({
id: userId,
roleId: newRoleId,
});
if (success) {
// Reload data setelah berhasil update
stateUser.findMany.load(page, 10, search);
}
return success;
};
// ✅ Handler untuk toggle isActive
const handleToggleActive = async (userId: string, currentStatus: boolean) => {
const success = await stateUser.update.submit({
id: userId,
isActive: !currentStatus,
});
if (success) {
stateUser.findMany.load(page, 10, search);
}
};
const filteredData = data || [];
if (loading || !data) {
return (
@@ -80,16 +138,19 @@ function ListUser({ search }: { search: string }) {
<TableTh style={{ width: '20%' }}>Nomor</TableTh>
<TableTh style={{ width: '20%' }}>Role</TableTh>
<TableTh style={{ width: '15%' }}>Aktif / Nonaktif</TableTh>
<TableTh style={{ width: '15%' }}>Hapus</TableTh>
</TableTr>
</TableThead>
<TableTbody>
{filteredData.length > 0 ? (
filteredData.map((item) => (
<TableTr key={item.id}>
<TableTd style={{ width: '25%', }}>
<Text fw={500} truncate="end" lineClamp={1}>{item.username}</Text>
<TableTd style={{ width: '25%' }}>
<Text fw={500} truncate="end" lineClamp={1}>
{item.username}
</Text>
</TableTd>
<TableTd style={{ width: '20%', }}>
<TableTd style={{ width: '20%' }}>
<Text truncate fz="sm" c="dimmed">
{item.nomor}
</Text>
@@ -101,21 +162,22 @@ function ListUser({ search }: { search: string }) {
label: r.name,
value: r.id,
}))}
value={item.roleId} // ⬅ role milik user ini
onChange={async (val) => {
value={item.roleId}
onChange={(val) => {
if (!val) return;
await stateUser.update.submit({
id: item.id,
roleId: val, // ⬅ kirim roleId
});
// reload data supaya UI up-to-date
stateUser.findMany.load(page, 10, search);
// ✅ Panggil handleRoleChange dengan konfirmasi
handleRoleChange(
item.id,
item.username,
item.roleId,
val
);
}}
searchable
clearable={false} // role harus ada
clearable={false}
nothingFoundMessage="Role tidak ditemukan"
disabled={stateUser.update.loading}
/>
</TableTd>
@@ -127,26 +189,34 @@ function ListUser({ search }: { search: string }) {
<Button
variant="light"
color={item.isActive ? "green" : "red"}
onClick={async () => {
await stateUser.update.submit({
id: item.id,
isActive: !item.isActive, // toggle
});
stateUser.findMany.load(page, 10, search);
}}
onClick={() => handleToggleActive(item.id, item.isActive)}
disabled={stateUser.update.loading}
>
{item.isActive ? <IconCheck size={20} /> : <IconX size={20} />}
</Button>
</Tooltip>
</TableTd>
<TableTd style={{ width: '15%' }}>
<Button
variant="light"
color='red'
disabled={stateUser.deleteUser.loading}
onClick={() => {
setSelectedId(item.id);
setModalHapus(true);
}}
>
<IconTrash size={20} />
</Button>
</TableTd>
</TableTr>
))
) : (
<TableTr>
<TableTd colSpan={4}>
<TableTd colSpan={5}>
<Center py={20}>
<Text color="dimmed">Tidak ada data user yang cocok</Text>
<Text c="dimmed">Tidak ada data user yang cocok</Text>
</Center>
</TableTd>
</TableTr>
@@ -155,6 +225,7 @@ function ListUser({ search }: { search: string }) {
</Table>
</Box>
</Paper>
<Center>
<Pagination
value={page}
@@ -169,6 +240,7 @@ function ListUser({ search }: { search: string }) {
radius="md"
/>
</Center>
{/* Modal Konfirmasi Hapus */}
<ModalKonfirmasiHapus
opened={modalHapus}
@@ -180,4 +252,4 @@ function ListUser({ search }: { search: string }) {
);
}
export default User;
export default User;