Refactor New Ui Semua Pengaturan

This commit is contained in:
2026-03-25 14:38:37 +08:00
parent 1ba4643e23
commit 687ce11a81
6 changed files with 203 additions and 300 deletions

View File

@@ -1,12 +1,15 @@
import { import {
ActionIcon, ActionIcon,
Alert, Alert,
Box,
Button, Button,
Card, Card,
Group, Group,
Modal, Modal,
Select, Select,
Space, Space,
Stack,
Switch,
Table, Table,
Text, Text,
TextInput, TextInput,
@@ -23,167 +26,63 @@ import {
import { useState } from "react"; import { useState } from "react";
const AksesDanTimSettings = () => { const AksesDanTimSettings = () => {
const [opened, setOpened] = useState(false);
const { colorScheme } = useMantineColorScheme();
const dark = colorScheme === "dark";
// Sample team members data
const teamMembers = [
{
id: 1,
name: "Admin Utama",
email: "admin@desa.go.id",
role: "Administrator",
status: "Aktif",
},
{
id: 2,
name: "Operator Desa",
email: "operator@desa.go.id",
role: "Operator",
status: "Aktif",
},
{
id: 3,
name: "Staff Keuangan",
email: "keuangan@desa.go.id",
role: "Keuangan",
status: "Aktif",
},
{
id: 4,
name: "Staff Umum",
email: "umum@desa.go.id",
role: "Umum",
status: "Nonaktif",
},
];
const roles = [
{ value: "administrator", label: "Administrator" },
{ value: "operator", label: "Operator" },
{ value: "keuangan", label: "Keuangan" },
{ value: "umum", label: "Umum" },
{ value: "keamanan", label: "Keamanan" },
];
return ( return (
<Card <Stack
withBorder pr={"50%"}
radius="md" gap={"xl"}
p="xl"
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
> >
<Modal <Box>
opened={opened} <Stack gap={"xs"}>
onClose={() => setOpened(false)} <Title order={2}>
title="Tambah Anggota Tim" Manajemen Tim
size="lg" </Title>
> <Button bg={"#1E3A5F"} radius={"md"} c={"white"} fullWidth >Undangan Anggota Baru</Button>
<TextInput <Button bg={"#1E3A5F"} radius={"md"} c={"white"} fullWidth>Kelola Role & Permission</Button>
label="Nama Lengkap" <Group justify="space-between">
placeholder="Masukkan nama lengkap anggota tim" <Text fw={"bold"} fz={"sm"}>Daftar Anggota Teraktif</Text>
mb="md" <Text fw={"bold"} fz={"sm"}>12 Anggota</Text>
/> </Group>
<TextInput </Stack>
label="Alamat Email" </Box>
placeholder="Masukkan alamat email" <Box>
mb="md" <Stack gap={"xs"}>
/> <Title order={2}>
<Select Hak Akses
label="Peran" </Title>
placeholder="Pilih peran anggota tim" <Group justify="space-between">
data={roles} <Text fw={"bold"} fz={"sm"}>Administrator</Text>
mb="md" <Text fw={"bold"} fz={"sm"}>2 Orang</Text>
/> </Group>
<Group justify="flex-end" mt="xl"> <Group justify="space-between">
<Button variant="outline" onClick={() => setOpened(false)}> <Text fw={"bold"} fz={"sm"}>Editor</Text>
Batal <Text fw={"bold"} fz={"sm"}>5 Orang</Text>
</Button> </Group>
<Button>Undang Anggota</Button> <Group justify="space-between">
</Group> <Text fw={"bold"} fz={"sm"}>Viewer</Text>
</Modal> <Text fw={"bold"} fz={"sm"}>5 Orang</Text>
</Group>
<Title order={2} mb="lg"> </Stack>
Akses & Tim </Box>
</Title> <Box>
<Text color="dimmed" mb="xl"> <Stack gap={"xs"}>
Kelola akses dan anggota tim Anda <Title order={2}>
</Text> Kolaborasi
</Title>
<Space h="lg" /> <Group mb="md" justify="space-between">
<Text fw={"bold"} fz={"sm"}>Izin Export Data</Text>
<Group justify="space-between" mb="md"> <Switch defaultChecked />
<Title order={4}>Anggota Tim</Title> </Group>
<Button <Group mb="md" justify="space-between">
leftSection={<IconUserPlus size={16} />} <Text fw={"bold"} fz={"sm"}>Require Approval Untuk Perubahan</Text>
onClick={() => setOpened(true)} <Switch defaultChecked />
> </Group>
Tambah Anggota </Stack>
</Button> </Box>
</Group> <Group justify="flex-start" mt="xl">
<Table highlightOnHover>
<Table.Thead>
<Table.Tr>
<Table.Th>Nama</Table.Th>
<Table.Th>Email</Table.Th>
<Table.Th>Peran</Table.Th>
<Table.Th>Status</Table.Th>
<Table.Th>Aksi</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{teamMembers.map((member) => (
<Table.Tr key={member.id}>
<Table.Td>
<Group gap="sm">
<IconUser size={20} />
<Text>{member.name}</Text>
</Group>
</Table.Td>
<Table.Td>{member.email}</Table.Td>
<Table.Td>
<Text fw={500}>{member.role}</Text>
</Table.Td>
<Table.Td>
<Text c={member.status === "Aktif" ? "green" : "red"} fw={500}>
{member.status}
</Text>
</Table.Td>
<Table.Td>
<Group>
<ActionIcon variant="subtle" color="blue">
<IconEdit size={16} />
</ActionIcon>
<ActionIcon variant="subtle" color="red">
<IconTrash size={16} />
</ActionIcon>
</Group>
</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
<Space h="xl" />
<Alert
icon={<IconInfoCircle size={16} />}
title="Informasi"
color="blue"
mb="md"
>
Administrator memiliki akses penuh ke semua fitur. Peran lainnya
memiliki akses terbatas sesuai kebutuhan.
</Alert>
<Group justify="flex-end" mt="xl">
<Button variant="outline">Batal</Button> <Button variant="outline">Batal</Button>
<Button>Simpan Perubahan</Button> <Button>Simpan Perubahan</Button>
</Group> </Group>
</Card> </Stack>
); );
}; };

View File

@@ -1,89 +1,65 @@
import { import {
Alert,
Button, Button,
Card, Box,
Group, Group,
PasswordInput, Stack,
Space,
Switch, Switch,
Text, Text,
Title, Title
useMantineColorScheme,
} from "@mantine/core"; } from "@mantine/core";
import { IconInfoCircle, IconLock } from "@tabler/icons-react";
const KeamananSettings = () => { const KeamananSettings = () => {
const { colorScheme } = useMantineColorScheme();
const dark = colorScheme === "dark";
return ( return (
<Card <Stack
withBorder pr={"50%"}
radius="md" gap={"xl"}
p="xl"
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
> >
<Title order={2} mb="lg"> <Box>
Pengaturan Keamanan <Stack gap={"xs"}>
</Title> <Title order={2}>
<Text color="dimmed" mb="xl"> Autentikasi
Kelola keamanan akun Anda </Title>
</Text> <Group mb="md" justify="space-between">
<Text fw={"bold"} fz={"sm"}>Two-Factor Authentication</Text>
<Space h="lg" /> <Switch defaultChecked />
</Group>
<PasswordInput <Group mb="md" justify="space-between">
label="Kata Sandi Saat Ini" <Text fw={"bold"} fz={"sm"}>Biometrik Login</Text>
placeholder="Masukkan kata sandi saat ini" <Switch defaultChecked />
mb="md" </Group>
/> <Group mb="md" justify="space-between">
<Text fw={"bold"} fz={"sm"}>IP Whitelist</Text>
<PasswordInput <Switch defaultChecked />
label="Kata Sandi Baru" </Group>
placeholder="Masukkan kata sandi baru" </Stack>
mb="md" </Box>
/> <Box>
<Stack gap={"xs"}>
<PasswordInput <Title order={2}>
label="Konfirmasi Kata Sandi Baru" Password
placeholder="Konfirmasi kata sandi baru" </Title>
mb="md" <Button bg={"#1E3A5F"} radius={"md"} c={"white"} fullWidth >Ubah Password</Button>
/> <Button bg={"#1E3A5F"} radius={"md"} c={"white"} fullWidth>Riwayat Login</Button>
<Button bg={"#1E3A5F"} radius={"md"} c={"white"} fullWidth>Perangkat Terdaftar</Button>
<Space h="md" /> </Stack>
</Box>
<Group mb="md"> <Box>
<Switch label="Verifikasi Dua Langkah" /> <Stack gap={"xs"}>
<Switch label="Login Otentikasi Aplikasi" /> <Title order={2}>
</Group> Audit & Log
</Title>
<Space h="md" /> <Group mb="md" justify="space-between">
<Text fw={"bold"} fz={"sm"}>Log Aktivitas</Text>
<Alert <Switch defaultChecked />
icon={<IconLock size={16} />} </Group>
title="Keamanan" <Button bg={"#1E3A5F"} radius={"md"} c={"white"} fullWidth>Download Log</Button>
color="orange" </Stack>
mb="md" </Box>
> <Group justify="flex-start" mt="xl">
Gunakan kata sandi yang kuat dan unik. Hindari menggunakan kata sandi
yang sama di banyak layanan.
</Alert>
<Alert
icon={<IconInfoCircle size={16} />}
title="Informasi"
color="blue"
mb="md"
>
Setelah mengganti kata sandi, Anda akan diminta logout dari semua
perangkat.
</Alert>
<Group justify="flex-end" mt="xl">
<Button variant="outline">Batal</Button> <Button variant="outline">Batal</Button>
<Button>Perbarui Kata Sandi</Button> <Button>Simpan Perubahan</Button>
</Group> </Group>
</Card> </Stack>
); );
}; };

View File

@@ -1,10 +1,14 @@
import { import {
Alert, Alert,
Box,
Button, Button,
Card, Card,
Checkbox, Checkbox,
Grid,
GridCol,
Group, Group,
Space, Space,
Stack,
Switch, Switch,
Text, Text,
Title, Title,
@@ -16,70 +20,82 @@ const NotifikasiSettings = () => {
const { colorScheme } = useMantineColorScheme(); const { colorScheme } = useMantineColorScheme();
const dark = colorScheme === "dark"; const dark = colorScheme === "dark";
return ( return (
<Card <Stack
withBorder pr={"20%"}
radius="md" gap={"xs"}
p="xl"
bg={dark ? "#141D34" : "white"}
style={{ borderColor: dark ? "#141D34" : "white" }}
> >
<Title order={2} mb="lg"> <Grid gutter={{ base: 5, xs: 'md', md: 'xl', xl: 50 }}>
Pengaturan Notifikasi <GridCol span={6}>
</Title> <Stack gap={"xs"}>
<Text color="dimmed" mb="xl"> <Title order={3} mb="sm">
Kelola preferensi notifikasi Anda Metode Notifikasi
</Text> </Title>
<Group mb="md" justify="space-between">
<Space h="lg" /> <Text fw={"bold"} fz={"sm"}>Laporan Harian</Text>
<Switch defaultChecked />
<Checkbox.Group defaultValue={["email", "push"]} mb="md"> </Group>
<Title order={4} mb="sm"> <Group mb="md" justify="space-between">
Metode Notifikasi <Text fw={"bold"} fz={"sm"}>Alert Sistem</Text>
</Title> <Switch defaultChecked />
<Group> </Group>
<Checkbox value="email" label="Email" /> <Group mb="md" justify="space-between">
<Checkbox value="push" label="Notifikasi Push" /> <Text fw={"bold"} fz={"sm"}>Update Keamanan</Text>
<Checkbox value="sms" label="SMS" /> <Switch defaultChecked />
</Group> </Group>
</Checkbox.Group> <Group mb="md" justify="space-between">
<Text fw={"bold"} fz={"sm"}>Newsletter Bulanan</Text>
<Space h="md" /> <Switch defaultChecked />
</Group>
<Group mb="md"> </Stack>
<Switch label="Notifikasi Email" defaultChecked /> </GridCol>
<Switch label="Notifikasi Push" defaultChecked /> <GridCol span={6}>
</Group> <Stack gap={"xs"}>
<Title order={3} mb="sm">
<Space h="md" /> Preferensi Alert
</Title>
<Title order={4} mb="sm"> <Group mb="md" justify="space-between">
Jenis Notifikasi <Text fw={"bold"} fz={"sm"}>Treshold Memori</Text>
</Title> <Switch defaultChecked />
<Group align="start"> </Group>
<Switch label="Pengaduan Baru" defaultChecked /> <Group mb="md" justify="space-between">
<Switch label="Update Status Pengaduan" defaultChecked /> <Text fw={"bold"} fz={"sm"}>Treshold CPU</Text>
<Switch label="Laporan Mingguan" /> <Switch defaultChecked />
<Switch label="Pemberitahuan Keamanan" defaultChecked /> </Group>
<Switch label="Aktivitas Akun" defaultChecked /> <Group mb="md" justify="space-between">
</Group> <Text fw={"bold"} fz={"sm"}>Treshold Disk</Text>
<Switch defaultChecked />
<Space h="md" /> </Group>
</Stack>
<Alert </GridCol>
icon={<IconInfoCircle size={16} />} <GridCol span={6}>
title="Tip" <Stack gap={"xs"}>
color="blue" <Title order={3} mb="sm">
mb="md" Notifikasi Push
> </Title>
Anda dapat menyesuaikan frekuensi notifikasi mingguan sesuai kebutuhan <Group mb="md" justify="space-between">
Anda. <Text fw={"bold"} fz={"sm"}>Alert Kritis</Text>
</Alert> <Switch defaultChecked />
</Group>
<Group justify="flex-end" mt="xl"> <Group mb="md" justify="space-between">
<Text fw={"bold"} fz={"sm"}>Aktivitas Tim</Text>
<Switch defaultChecked />
</Group>
<Group mb="md" justify="space-between">
<Text fw={"bold"} fz={"sm"}>Komentar & Mention</Text>
<Switch defaultChecked />
</Group>
<Group mb="md" justify="space-between">
<Text fw={"bold"} fz={"sm"}>Bunyi Notifikasi</Text>
<Switch defaultChecked />
</Group>
</Stack>
</GridCol>
</Grid>
<Group justify="flex-start" mt="xl">
<Button variant="outline">Batal</Button> <Button variant="outline">Batal</Button>
<Button>Simpan Preferensi</Button> <Button>Simpan Preferensi</Button>
</Group> </Group>
</Card> </Stack>
); );
}; };

View File

@@ -1,23 +1,15 @@
import { import {
Alert,
Box, Box,
Button, Button,
Card,
Group, Group,
Select, Select,
Space,
Switch, Switch,
Text, Text,
TextInput,
Title, Title,
useMantineColorScheme,
} from "@mantine/core"; } from "@mantine/core";
import { DateInput } from "@mantine/dates"; import { DateInput } from "@mantine/dates";
import { IconInfoCircle } from "@tabler/icons-react";
const UmumSettings = () => { const UmumSettings = () => {
const { colorScheme } = useMantineColorScheme();
const dark = colorScheme === "dark";
return ( return (
<Box <Box
pr={"50%"} pr={"50%"}

View File

@@ -1,16 +1,26 @@
import { useDisclosure } from "@mantine/hooks"; import { useDisclosure } from "@mantine/hooks";
import { useState } from "react";
export function useSidebarFullscreen() { export function useSidebarFullscreen() {
const [opened, { toggle: toggleMobile }] = useDisclosure(); const [opened, { toggle: toggleMobile }] = useDisclosure();
const [sidebarCollapsed, setSidebarCollapsed] = useDisclosure(false); const [sidebarCollapsed, setSidebarCollapsed] = useDisclosure(false);
const [clickCount, setClickCount] = useState(0);
const toggleSidebar = () => { const toggleSidebar = () => {
setSidebarCollapsed.toggle(); setSidebarCollapsed.toggle();
setClickCount(0);
}; };
const handleMainClick = () => { const handleMainClick = () => {
if (!sidebarCollapsed) { if (!sidebarCollapsed) {
toggleSidebar(); const newCount = clickCount + 1;
setClickCount(newCount);
if (newCount === 2) {
toggleSidebar();
} else {
setTimeout(() => setClickCount(0), 300);
}
} }
}; };

View File

@@ -1,6 +1,7 @@
import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core"; import { AppShell, Burger, Group, useMantineColorScheme } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks"; import { useDisclosure } from "@mantine/hooks";
import { createFileRoute } from "@tanstack/react-router"; import { createFileRoute } from "@tanstack/react-router";
import { useState } from "react";
import { DashboardContent } from "@/components/dashboard-content"; import { DashboardContent } from "@/components/dashboard-content";
import { Header } from "@/components/header"; import { Header } from "@/components/header";
import { Sidebar } from "@/components/sidebar"; import { Sidebar } from "@/components/sidebar";
@@ -12,6 +13,7 @@ export const Route = createFileRoute("/")({
function DashboardPage() { function DashboardPage() {
const [opened, { toggle }] = useDisclosure(); const [opened, { toggle }] = useDisclosure();
const [sidebarCollapsed, setSidebarCollapsed] = useDisclosure(false); const [sidebarCollapsed, setSidebarCollapsed] = useDisclosure(false);
const [clickCount, setClickCount] = useState(0);
const { colorScheme } = useMantineColorScheme(); const { colorScheme } = useMantineColorScheme();
const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E"; const headerBgColor = colorScheme === "dark" ? "#11192D" : "#19355E";
const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white"; const navbarBgColor = colorScheme === "dark" ? "#11192D" : "white";
@@ -19,7 +21,15 @@ function DashboardPage() {
const handleMainClick = () => { const handleMainClick = () => {
if (!sidebarCollapsed) { if (!sidebarCollapsed) {
setSidebarCollapsed.toggle(); const newCount = clickCount + 1;
setClickCount(newCount);
if (newCount === 2) {
setSidebarCollapsed.toggle();
setClickCount(0);
} else {
setTimeout(() => setClickCount(0), 300);
}
} }
}; };