Fix QC Kak Inno 19 Des
Fix QC Kak Ayu 19 Des Fix Tampilan Admin Mobile Menu Keamanan Fix Search Debounce Menu Keamanan
This commit is contained in:
@@ -1,8 +1,30 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LayoutTabsBerita from './_com/layoutTabs';
|
import LayoutTabsBerita from './_com/layoutTabs';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
import { Box } from '@mantine/core';
|
||||||
|
|
||||||
function Layout({ children }: { children: React.ReactNode }) {
|
function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutTabsBerita>
|
<LayoutTabsBerita>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,7 +1,29 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
import LayoutTabsGallery from "./lib/layoutTabs"
|
import LayoutTabsGallery from "./lib/layoutTabs"
|
||||||
|
import { Box } from "@mantine/core";
|
||||||
|
|
||||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutTabsGallery>
|
<LayoutTabsGallery>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,10 +1,31 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
import LayoutTabsLayanan from "../_com/layoutTabLayanan";
|
import LayoutTabsLayanan from "../_com/layoutTabLayanan";
|
||||||
|
import { Box } from "@mantine/core";
|
||||||
|
|
||||||
export default function Layout({children} : {children: React.ReactNode}) {
|
export default function Layout({children} : {children: React.ReactNode}) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/layanan/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/layanan/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/layanan/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
return (
|
return (
|
||||||
<LayoutTabsLayanan>
|
<Box>
|
||||||
{children}
|
{children}
|
||||||
</LayoutTabsLayanan>
|
</Box>
|
||||||
)
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LayoutTabsLayanan>
|
||||||
|
{children}
|
||||||
|
</LayoutTabsLayanan>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,29 @@
|
|||||||
|
'use client'
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LayoutTabs from './_com/layoutTabs';
|
import LayoutTabs from './_com/layoutTabs';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
import { Box } from '@mantine/core';
|
||||||
|
|
||||||
function Layout({ children }: { children: React.ReactNode }) {
|
function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/pengumuman/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/pengumuman/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/pengumuman/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutTabs>
|
<LayoutTabs>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,8 +1,29 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LayoutTabsPotensi from './_lib/layoutTabs';
|
import LayoutTabsPotensi from './_lib/layoutTabs';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
import { Box } from '@mantine/core';
|
||||||
|
|
||||||
function Layout({ children }: { children: React.ReactNode }) {
|
function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutTabsPotensi>
|
<LayoutTabsPotensi>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,8 +1,30 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
import LayoutTabsDetail from "./_lib/layoutTabsDetail"
|
import LayoutTabsDetail from "./_lib/layoutTabsDetail"
|
||||||
|
import { Box } from "@mantine/core";
|
||||||
|
|
||||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutTabsDetail>
|
<LayoutTabsDetail>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ function EditKeamananLingkungan() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: "sm", md: "lg" }} py="md">
|
<Box px={{ base: 0, md: 'lg' }} py="xs">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ function DetailKeamananLingkungan() {
|
|||||||
const data = keamananState.findUnique.data
|
const data = keamananState.findUnique.data
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box px={{ base: 0, md: 'lg' }} py="xs">
|
||||||
{/* Tombol Back */}
|
{/* Tombol Back */}
|
||||||
<Button
|
<Button
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
@@ -58,7 +58,7 @@ function DetailKeamananLingkungan() {
|
|||||||
{/* Wrapper Detail */}
|
{/* Wrapper Detail */}
|
||||||
<Paper
|
<Paper
|
||||||
withBorder
|
withBorder
|
||||||
w={{ base: "100%", md: "50%" }}
|
w={{ base: "100%", md: "70%" }}
|
||||||
bg={colors['white-1']}
|
bg={colors['white-1']}
|
||||||
p="lg"
|
p="lg"
|
||||||
radius="md"
|
radius="md"
|
||||||
@@ -88,7 +88,9 @@ function DetailKeamananLingkungan() {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
<Text fz="lg" fw="bold">Deskripsi</Text>
|
||||||
<Text fz="md" c="dimmed" dangerouslySetInnerHTML={{ __html: data?.deskripsi }} style={{ wordBreak: "break-word", whiteSpace: "normal" }} />
|
<Box pl={8}>
|
||||||
|
<Text fz="md" c="dimmed" dangerouslySetInnerHTML={{ __html: data?.deskripsi }} style={{ wordBreak: "break-word", whiteSpace: "normal" }} />
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Aksi */}
|
{/* Aksi */}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ function CreateKeamananLingkungan() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'lg' }} py="xs">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
Title
|
Title
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -48,6 +48,7 @@ function KeamananLingkungan() {
|
|||||||
function ListKeamananLingkungan({ search }: { search: string }) {
|
function ListKeamananLingkungan({ search }: { search: string }) {
|
||||||
const keamananState = useProxy(keamananLingkunganState)
|
const keamananState = useProxy(keamananLingkunganState)
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 1000)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@@ -58,25 +59,27 @@ function ListKeamananLingkungan({ search }: { search: string }) {
|
|||||||
} = keamananState.findMany;
|
} = keamananState.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10, search)
|
load(page, 10, debouncedSearch)
|
||||||
}, [page, search])
|
}, [page, debouncedSearch])
|
||||||
|
|
||||||
const filteredData = data || []
|
const filteredData = data || []
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={{ base: 'sm', md: 'md' }}>
|
||||||
<Skeleton height={600} radius="md" />
|
<Skeleton height={600} radius="md" />
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py={{ base: 'sm', md: 'md' }}>
|
||||||
<Paper withBorder bg={colors['white-1']} p={'lg'} shadow="md" radius="md">
|
<Paper withBorder bg={colors['white-1']} p={{ base: 'md', md: 'lg' }} shadow="md" radius="md">
|
||||||
{/* Judul + Tombol Tambah */}
|
{/* Judul + Tombol Tambah */}
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between" mb={{ base: 'sm', md: 'md' }}>
|
||||||
<Title order={4}>Daftar Keamanan Lingkungan</Title>
|
<Title order={4} lh={1.2}>
|
||||||
|
Daftar Keamanan Lingkungan
|
||||||
|
</Title>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconPlus size={18} />}
|
leftSection={<IconPlus size={18} />}
|
||||||
color="blue"
|
color="blue"
|
||||||
@@ -89,14 +92,18 @@ function ListKeamananLingkungan({ search }: { search: string }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Tabel */}
|
{/* Desktop Table */}
|
||||||
<Box style={{ overflowX: "auto" }}>
|
<Box visibleFrom="md">
|
||||||
<Table highlightOnHover>
|
<Table highlightOnHover
|
||||||
|
miw={0}
|
||||||
|
style={{ tableLayout: 'fixed', width: '100%' }}>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh>Nama</TableTh>
|
<TableTh>Nama</TableTh>
|
||||||
<TableTh>Deskripsi</TableTh>
|
<TableTh>Deskripsi</TableTh>
|
||||||
<TableTh>Aksi</TableTh>
|
<TableTh style={{ width: 140, textAlign: 'center' }}>
|
||||||
|
Aksi
|
||||||
|
</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
@@ -104,25 +111,32 @@ function ListKeamananLingkungan({ search }: { search: string }) {
|
|||||||
filteredData.map((item) => (
|
filteredData.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box w={200}>
|
<Text fz="md" fw={500} lh={1.5} truncate="end" lineClamp={1}>
|
||||||
<Text fw={500} truncate="end" lineClamp={1}>
|
{item.name}
|
||||||
{item.name}
|
</Text>
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd style={{ overflow: 'hidden' }}>
|
||||||
<Box w={200}>
|
<Text
|
||||||
<Text fz="sm" c="dimmed" truncate lineClamp={1} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
fz="sm"
|
||||||
</Box>
|
c="dimmed"
|
||||||
|
lh={1.5}
|
||||||
|
lineClamp={1}
|
||||||
|
style={{
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
|
/>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd style={{ width: 140, textAlign: 'center' }}>
|
||||||
<Button
|
<Button
|
||||||
variant="light"
|
variant="light"
|
||||||
color="blue"
|
color="blue"
|
||||||
onClick={() => router.push(`/admin/keamanan/keamanan-lingkungan-pecalang-patwal/${item.id}`)}
|
onClick={() => router.push(`/admin/keamanan/keamanan-lingkungan-pecalang-patwal/${item.id}`)}
|
||||||
|
leftSection={<IconDeviceImacCog size={20} />}
|
||||||
>
|
>
|
||||||
<IconDeviceImacCog size={20} />
|
Detail
|
||||||
<Text ml={5}>Detail</Text>
|
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -130,8 +144,8 @@ function ListKeamananLingkungan({ search }: { search: string }) {
|
|||||||
) : (
|
) : (
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTd colSpan={3}>
|
<TableTd colSpan={3}>
|
||||||
<Center py={20}>
|
<Center py={{ base: 'sm', md: 'lg' }}>
|
||||||
<Text color="dimmed">
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
Tidak ada data keamanan lingkungan yang cocok
|
Tidak ada data keamanan lingkungan yang cocok
|
||||||
</Text>
|
</Text>
|
||||||
</Center>
|
</Center>
|
||||||
@@ -141,6 +155,49 @@ function ListKeamananLingkungan({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Mobile Cards */}
|
||||||
|
<Box hiddenFrom="md">
|
||||||
|
<Stack gap="sm">
|
||||||
|
{filteredData.length > 0 ? (
|
||||||
|
filteredData.map((item) => (
|
||||||
|
<Paper key={item.id} withBorder radius="md" p="sm">
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>Nama</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.5}>{item.name}</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>Deskripsi</Text>
|
||||||
|
<Box pl={8}>
|
||||||
|
<Text fz="sm" lineClamp={3} style={{ wordBreak: 'break-word' }} fw={500} lh={1.5} c="dimmed" dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
variant="light"
|
||||||
|
color="blue"
|
||||||
|
fullWidth
|
||||||
|
onClick={() => router.push(`/admin/keamanan/keamanan-lingkungan-pecalang-patwal/${item.id}`)}
|
||||||
|
>
|
||||||
|
<IconDeviceImacCog size={18} />
|
||||||
|
<Text ml={5} fz="sm" fw={500} lh={1.4}>
|
||||||
|
Detail
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Center py="lg">
|
||||||
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
|
Tidak ada data keamanan lingkungan yang cocok
|
||||||
|
</Text>
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Pagination */}
|
{/* Pagination */}
|
||||||
@@ -152,8 +209,8 @@ function ListKeamananLingkungan({ search }: { search: string }) {
|
|||||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
}}
|
}}
|
||||||
total={totalPages}
|
total={totalPages}
|
||||||
mt="md"
|
mt={{ base: 'sm', md: 'md' }}
|
||||||
mb="md"
|
mb={{ base: 'sm', md: 'md' }}
|
||||||
color="blue"
|
color="blue"
|
||||||
radius="md"
|
radius="md"
|
||||||
/>
|
/>
|
||||||
@@ -162,4 +219,4 @@ function ListKeamananLingkungan({ search }: { search: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default KeamananLingkungan;
|
export default KeamananLingkungan;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core';
|
import { Box, ScrollArea, Stack, Tabs, TabsList, TabsPanel, TabsTab, Title } from '@mantine/core';
|
||||||
import { IconPhone, IconTag } from '@tabler/icons-react';
|
import { IconPhone, IconTag } from '@tabler/icons-react';
|
||||||
import { usePathname, useRouter } from 'next/navigation';
|
import { usePathname, useRouter } from 'next/navigation';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
@@ -57,35 +57,76 @@ function LayoutTabs({ children }: { children: React.ReactNode }) {
|
|||||||
keepMounted={false}
|
keepMounted={false}
|
||||||
>
|
>
|
||||||
{/* ✅ Scroll horizontal wrapper */}
|
{/* ✅ Scroll horizontal wrapper */}
|
||||||
<ScrollArea type="auto" offsetScrollbars>
|
<Box visibleFrom='md' pb={10}>
|
||||||
<TabsList
|
<ScrollArea type="auto" offsetScrollbars>
|
||||||
p="sm"
|
<TabsList
|
||||||
style={{
|
p="sm"
|
||||||
background: "linear-gradient(135deg, #e7ebf7, #f9faff)",
|
style={{
|
||||||
borderRadius: "1rem",
|
background: "linear-gradient(135deg, #e7ebf7, #f9faff)",
|
||||||
boxShadow: "inset 0 0 10px rgba(0,0,0,0.05)",
|
borderRadius: "1rem",
|
||||||
display: "flex",
|
boxShadow: "inset 0 0 10px rgba(0,0,0,0.05)",
|
||||||
flexWrap: "nowrap",
|
display: "flex",
|
||||||
gap: "0.5rem",
|
flexWrap: "nowrap",
|
||||||
paddingInline: "0.5rem", // ✅ biar nggak nempel ke tepi
|
gap: "0.5rem",
|
||||||
}}
|
paddingInline: "0.5rem", // ✅ biar nggak nempel ke tepi
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tabs.map((tab, i) => (
|
||||||
|
<TabsTab
|
||||||
|
key={i}
|
||||||
|
value={tab.value}
|
||||||
|
leftSection={tab.icon}
|
||||||
|
style={{
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: "0.9rem",
|
||||||
|
transition: "all 0.2s ease",
|
||||||
|
flexShrink: 0, // ✅ jangan mengecil aneh-aneh
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tab.label}
|
||||||
|
</TabsTab>
|
||||||
|
))}
|
||||||
|
</TabsList>
|
||||||
|
</ScrollArea>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box hiddenFrom='md' pb={10}>
|
||||||
|
<ScrollArea
|
||||||
|
type="auto"
|
||||||
|
offsetScrollbars={false}
|
||||||
|
w="100%"
|
||||||
>
|
>
|
||||||
{tabs.map((tab, i) => (
|
|
||||||
<TabsTab
|
<TabsList
|
||||||
key={i}
|
p="xs" // lebih kecil
|
||||||
value={tab.value}
|
style={{
|
||||||
leftSection={tab.icon}
|
background: "linear-gradient(135deg, #e7ebf7, #f9faff)",
|
||||||
style={{
|
borderRadius: "1rem",
|
||||||
fontWeight: 600,
|
display: "flex",
|
||||||
fontSize: "0.9rem",
|
flexWrap: "nowrap",
|
||||||
transition: "all 0.2s ease",
|
gap: "0.5rem",
|
||||||
}}
|
width: "max-content", // ⬅️ kunci
|
||||||
>
|
maxWidth: "100%", // ⬅️ penting
|
||||||
{tab.label}
|
}}
|
||||||
</TabsTab>
|
>
|
||||||
))}
|
{tabs.map((tab, i) => (
|
||||||
</TabsList>
|
<TabsTab
|
||||||
</ScrollArea>
|
key={i}
|
||||||
|
value={tab.value}
|
||||||
|
leftSection={tab.icon}
|
||||||
|
style={{
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: "0.9rem",
|
||||||
|
paddingInline: "0.75rem", // ⬅️ lebih ramping
|
||||||
|
flexShrink: 0, // ✅ jangan mengecil aneh-aneh
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tab.label}
|
||||||
|
</TabsTab>
|
||||||
|
))}
|
||||||
|
</TabsList>
|
||||||
|
</ScrollArea>
|
||||||
|
</Box>
|
||||||
|
|
||||||
{tabs.map((tab, i) => (
|
{tabs.map((tab, i) => (
|
||||||
<TabsPanel
|
<TabsPanel
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ function EditKontakItem() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ function DetailKontakDarurat() {
|
|||||||
const data = kontakState.findUnique.data;
|
const data = kontakState.findUnique.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Tombol Back */}
|
{/* Tombol Back */}
|
||||||
<Button
|
<Button
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
@@ -55,7 +55,7 @@ function DetailKontakDarurat() {
|
|||||||
{/* Wrapper Detail */}
|
{/* Wrapper Detail */}
|
||||||
<Paper
|
<Paper
|
||||||
withBorder
|
withBorder
|
||||||
w={{ base: "100%", md: "50%" }}
|
w={{ base: "100%", md: "70%" }}
|
||||||
bg={colors['white-1']}
|
bg={colors['white-1']}
|
||||||
p="lg"
|
p="lg"
|
||||||
radius="md"
|
radius="md"
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ function CreateKontakItem() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
Title
|
Title
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -26,7 +26,6 @@ import { useProxy } from 'valtio/utils';
|
|||||||
import HeaderSearch from '../../../_com/header';
|
import HeaderSearch from '../../../_com/header';
|
||||||
import kontakDarurat from '../../../_state/keamanan/kontak-darurat-keamanan';
|
import kontakDarurat from '../../../_state/keamanan/kontak-darurat-keamanan';
|
||||||
|
|
||||||
|
|
||||||
function KontakItem() {
|
function KontakItem() {
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
|
|
||||||
@@ -49,6 +48,7 @@ function KontakItem() {
|
|||||||
function ListKontakItem({ search }: { search: string }) {
|
function ListKontakItem({ search }: { search: string }) {
|
||||||
const kontakState = useProxy(kontakDarurat.kontakDaruratItem);
|
const kontakState = useProxy(kontakDarurat.kontakDaruratItem);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@@ -59,43 +59,54 @@ function ListKontakItem({ search }: { search: string }) {
|
|||||||
} = kontakState.findMany;
|
} = kontakState.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10, search);
|
load(page, 10, debouncedSearch);
|
||||||
}, [page, search]);
|
}, [page, debouncedSearch]);
|
||||||
|
|
||||||
const filteredData = data || []
|
const filteredData = data || [];
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={{ base: 'sm', md: 'md' }}>
|
||||||
<Skeleton height={600} radius="md" />
|
<Skeleton height={600} radius="md" />
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py={{ base: 'sm', md: 'md' }}>
|
||||||
<Paper withBorder bg={colors['white-1']} p={'lg'} shadow="md" radius="md">
|
<Paper withBorder bg={colors['white-1']} p={{ base: 'md', md: 'lg' }} shadow="md" radius="md">
|
||||||
{/* Judul + Tombol Tambah */}
|
{/* Judul + Tombol Tambah */}
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between" mb={{ base: 'sm', md: 'md' }}>
|
||||||
<Title order={4}>Daftar Kontak Darurat Item</Title>
|
<Title order={4} lh={1.2}>
|
||||||
|
Daftar Kontak Darurat Item
|
||||||
|
</Title>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconPlus size={18} />}
|
leftSection={<IconPlus size={18} />}
|
||||||
color="blue"
|
color="blue"
|
||||||
variant="light"
|
variant="light"
|
||||||
onClick={() => router.push('/admin/keamanan/kontak-darurat/kontak-darurat-item/create')}
|
onClick={() =>
|
||||||
|
router.push('/admin/keamanan/kontak-darurat/kontak-darurat-item/create')
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Tambah Baru
|
Tambah Baru
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Tabel */}
|
{/* Desktop: Table */}
|
||||||
<Box style={{ overflowX: "auto" }}>
|
<Box visibleFrom="md">
|
||||||
<Table highlightOnHover>
|
<Table
|
||||||
|
highlightOnHover
|
||||||
|
miw={0}
|
||||||
|
style={{
|
||||||
|
tableLayout: 'fixed',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh>Nama Kontak</TableTh>
|
<TableTh style={{ width: '45%' }}>Nama Kontak</TableTh>
|
||||||
<TableTh>Nomor Telepon</TableTh>
|
<TableTh style={{ width: '35%' }}>Nomor Telepon</TableTh>
|
||||||
<TableTh>Aksi</TableTh>
|
<TableTh style={{ width: '20%' }}>Aksi</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
@@ -103,12 +114,12 @@ function ListKontakItem({ search }: { search: string }) {
|
|||||||
filteredData.map((item) => (
|
filteredData.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Text fw={500} truncate="end" lineClamp={1}>
|
<Text fz="md" fw={500} lh={1.5} truncate="end">
|
||||||
{item.nama}
|
{item.nama}
|
||||||
</Text>
|
</Text>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Text fz="sm" c="dimmed">
|
<Text fz="sm" c="dimmed" lh={1.5}>
|
||||||
{item.nomorTelepon || "-"}
|
{item.nomorTelepon || "-"}
|
||||||
</Text>
|
</Text>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
@@ -116,19 +127,26 @@ function ListKontakItem({ search }: { search: string }) {
|
|||||||
<Button
|
<Button
|
||||||
variant="light"
|
variant="light"
|
||||||
color="blue"
|
color="blue"
|
||||||
onClick={() => router.push(`/admin/keamanan/kontak-darurat/kontak-darurat-item/${item.id}`)}
|
onClick={() =>
|
||||||
|
router.push(
|
||||||
|
`/admin/keamanan/kontak-darurat/kontak-darurat-item/${item.id}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
size="xs"
|
||||||
>
|
>
|
||||||
<IconDeviceImacCog size={20} />
|
<IconDeviceImacCog size={16} />
|
||||||
<Text ml={5}>Detail</Text>
|
<Text ml={4} fz="sm" fw={500}>
|
||||||
|
Detail
|
||||||
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTd colSpan={4}>
|
<TableTd colSpan={3}>
|
||||||
<Center py={20}>
|
<Center py={24}>
|
||||||
<Text color="dimmed">
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
Tidak ada data kontak darurat item yang cocok
|
Tidak ada data kontak darurat item yang cocok
|
||||||
</Text>
|
</Text>
|
||||||
</Center>
|
</Center>
|
||||||
@@ -138,6 +156,58 @@ function ListKontakItem({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Mobile: Card */}
|
||||||
|
<Stack hiddenFrom="md" gap="xs">
|
||||||
|
{filteredData.length > 0 ? (
|
||||||
|
filteredData.map((item) => (
|
||||||
|
<Paper key={item.id} p="sm" withBorder radius="sm">
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Nama Kontak
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.4}>
|
||||||
|
{item.nama}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Nomor Telepon
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.4} c="dimmed">
|
||||||
|
{item.nomorTelepon || "-"}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
variant="light"
|
||||||
|
color="blue"
|
||||||
|
size="xs"
|
||||||
|
fullWidth
|
||||||
|
onClick={() =>
|
||||||
|
router.push(
|
||||||
|
`/admin/keamanan/kontak-darurat/kontak-darurat-item/${item.id}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<IconDeviceImacCog size={16} />
|
||||||
|
<Text ml={4} fz="sm" fw={500}>
|
||||||
|
Detail
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Center py={24}>
|
||||||
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
|
Tidak ada data kontak darurat item yang cocok
|
||||||
|
</Text>
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Pagination */}
|
{/* Pagination */}
|
||||||
@@ -159,4 +229,4 @@ function ListKontakItem({ search }: { search: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default KontakItem;
|
export default KontakItem;
|
||||||
@@ -147,7 +147,7 @@ export default function EditKontakDaruratKeamanan() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
||||||
<IconArrowBack color={colors['blue-button']} size={24} />
|
<IconArrowBack color={colors['blue-button']} size={24} />
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ function DetailKontakDaruratKeamanan() {
|
|||||||
const data = kontakState.findUnique.data;
|
const data = kontakState.findUnique.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Tombol Back */}
|
{/* Tombol Back */}
|
||||||
<Button
|
<Button
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
@@ -56,7 +56,7 @@ function DetailKontakDaruratKeamanan() {
|
|||||||
{/* Wrapper Detail */}
|
{/* Wrapper Detail */}
|
||||||
<Paper
|
<Paper
|
||||||
withBorder
|
withBorder
|
||||||
w={{ base: "100%", md: "50%" }}
|
w={{ base: "100%", md: "70%" }}
|
||||||
bg={colors['white-1']}
|
bg={colors['white-1']}
|
||||||
p="lg"
|
p="lg"
|
||||||
radius="md"
|
radius="md"
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ function CreateKontakDaruratKeamanan() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
Title
|
Title
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -48,6 +48,7 @@ function KontakDaruratKeamanan() {
|
|||||||
function ListKontakDaruratKeamanan({ search }: { search: string }) {
|
function ListKontakDaruratKeamanan({ search }: { search: string }) {
|
||||||
const kontakState = useProxy(kontakDarurat.kontakDaruratKeamananState);
|
const kontakState = useProxy(kontakDarurat.kontakDaruratKeamananState);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@@ -58,26 +59,28 @@ function ListKontakDaruratKeamanan({ search }: { search: string }) {
|
|||||||
} = kontakState.findMany;
|
} = kontakState.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10, search);
|
load(page, 10, debouncedSearch);
|
||||||
kontakDarurat.kontakDaruratItem.findMany.load();
|
kontakDarurat.kontakDaruratItem.findMany.load();
|
||||||
}, [page, search]);
|
}, [page, debouncedSearch]);
|
||||||
|
|
||||||
const filteredData = data || []
|
const filteredData = data || [];
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={{ base: 'md', md: 'lg' }}>
|
||||||
<Skeleton height={600} radius="md" />
|
<Skeleton height={600} radius="md" />
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py={{ base: 'md', md: 'lg' }}>
|
||||||
<Paper withBorder bg={colors['white-1']} p={'lg'} shadow="md" radius="md">
|
<Paper withBorder bg={colors['white-1']} p={{ base: 'md', md: 'lg' }} shadow="md" radius="md">
|
||||||
{/* Judul + Tombol Tambah */}
|
{/* Judul + Tombol Tambah */}
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between" mb={{ base: 'sm', md: 'md' }}>
|
||||||
<Title order={4}>Daftar Kontak Darurat Keamanan</Title>
|
<Title order={4} lh={1.2}>
|
||||||
|
Daftar Kontak Darurat Keamanan
|
||||||
|
</Title>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconPlus size={18} />}
|
leftSection={<IconPlus size={18} />}
|
||||||
color="blue"
|
color="blue"
|
||||||
@@ -88,15 +91,22 @@ function ListKontakDaruratKeamanan({ search }: { search: string }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Tabel */}
|
{/* Desktop Table */}
|
||||||
<Box style={{ overflowX: "auto" }}>
|
<Box visibleFrom="md">
|
||||||
<Table highlightOnHover>
|
<Table
|
||||||
|
highlightOnHover
|
||||||
|
miw={0}
|
||||||
|
style={{
|
||||||
|
tableLayout: 'fixed',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh>Kontak Darurat</TableTh>
|
<TableTh style={{ width: '30%' }}>Kontak Darurat</TableTh>
|
||||||
<TableTh>Nama Kontak</TableTh>
|
<TableTh style={{ width: '25%' }}>Nama Kontak</TableTh>
|
||||||
<TableTh>Nomor Telepon</TableTh>
|
<TableTh style={{ width: '25%' }}>Nomor Telepon</TableTh>
|
||||||
<TableTh>Aksi</TableTh>
|
<TableTh style={{ width: '20%' }}>Aksi</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
@@ -104,17 +114,17 @@ function ListKontakDaruratKeamanan({ search }: { search: string }) {
|
|||||||
filteredData.map((item) => (
|
filteredData.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Text fw={500} truncate="end" lineClamp={1}>
|
<Text fz="md" fw={500} lh={1.5} truncate="end" lineClamp={1}>
|
||||||
{item.nama}
|
{item.nama}
|
||||||
</Text>
|
</Text>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Text fz="sm" c="dimmed" truncate lineClamp={1}>
|
<Text fz="sm" c="dimmed" lh={1.5} truncate lineClamp={1}>
|
||||||
{item.kategori?.nama}
|
{item.kategori?.nama}
|
||||||
</Text>
|
</Text>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Text fz="sm" c="dimmed">
|
<Text fz="sm" c="dimmed" lh={1.5}>
|
||||||
{item.kategori?.nomorTelepon || "-"}
|
{item.kategori?.nomorTelepon || "-"}
|
||||||
</Text>
|
</Text>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
@@ -125,7 +135,7 @@ function ListKontakDaruratKeamanan({ search }: { search: string }) {
|
|||||||
onClick={() => router.push(`/admin/keamanan/kontak-darurat/kontak-darurat-keamanan/${item.id}`)}
|
onClick={() => router.push(`/admin/keamanan/kontak-darurat/kontak-darurat-keamanan/${item.id}`)}
|
||||||
>
|
>
|
||||||
<IconDeviceImacCog size={20} />
|
<IconDeviceImacCog size={20} />
|
||||||
<Text ml={5}>Detail</Text>
|
<Text ml={5} fz="sm" fw={500}>Detail</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -134,7 +144,7 @@ function ListKontakDaruratKeamanan({ search }: { search: string }) {
|
|||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTd colSpan={4}>
|
<TableTd colSpan={4}>
|
||||||
<Center py={20}>
|
<Center py={20}>
|
||||||
<Text color="dimmed">
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
Tidak ada data kontak darurat keamanan yang cocok
|
Tidak ada data kontak darurat keamanan yang cocok
|
||||||
</Text>
|
</Text>
|
||||||
</Center>
|
</Center>
|
||||||
@@ -144,6 +154,55 @@ function ListKontakDaruratKeamanan({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Mobile Cards */}
|
||||||
|
<Box hiddenFrom="md">
|
||||||
|
<Stack gap="md">
|
||||||
|
{filteredData.length > 0 ? (
|
||||||
|
filteredData.map((item) => (
|
||||||
|
<Paper key={item.id} withBorder radius="md" p="md">
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>Kontak Darurat</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.45}>
|
||||||
|
{item.nama}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>Nama Kontak</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.45} c="dimmed">
|
||||||
|
{item.kategori?.nama}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>Nomor Telepon</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.45} c="dimmed">
|
||||||
|
{item.kategori?.nomorTelepon || "-"}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
variant="light"
|
||||||
|
color="blue"
|
||||||
|
onClick={() => router.push(`/admin/keamanan/kontak-darurat/kontak-darurat-keamanan/${item.id}`)}
|
||||||
|
>
|
||||||
|
<IconDeviceImacCog size={18} />
|
||||||
|
<Text ml={5} fz="sm" fw={500}>Detail</Text>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Center py={20}>
|
||||||
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
|
Tidak ada data kontak darurat keamanan yang cocok
|
||||||
|
</Text>
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Pagination */}
|
{/* Pagination */}
|
||||||
@@ -165,4 +224,4 @@ function ListKontakDaruratKeamanan({ search }: { search: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default KontakDaruratKeamanan;
|
export default KontakDaruratKeamanan;
|
||||||
@@ -1,8 +1,29 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LayoutTabs from './_lib/layoutTabs';
|
import LayoutTabs from './_lib/layoutTabs';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
import { Box } from '@mantine/core';
|
||||||
|
|
||||||
function Layout({ children }: { children: React.ReactNode }) {
|
function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutTabs>
|
<LayoutTabs>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ function EditLaporanPublik() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ function DetailLaporanPublik() {
|
|||||||
const data = stateLaporan.findUnique.data;
|
const data = stateLaporan.findUnique.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Tombol Kembali */}
|
{/* Tombol Kembali */}
|
||||||
<Button
|
<Button
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
@@ -61,7 +61,7 @@ function DetailLaporanPublik() {
|
|||||||
|
|
||||||
<Paper
|
<Paper
|
||||||
withBorder
|
withBorder
|
||||||
w={{ base: '100%', md: '60%' }}
|
w={{ base: '100%', md: '70%' }}
|
||||||
bg={colors['white-1']}
|
bg={colors['white-1']}
|
||||||
p="lg"
|
p="lg"
|
||||||
radius="md"
|
radius="md"
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ function CreateLaporanPublik() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Header with Back Button */}
|
{/* Header with Back Button */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
Title
|
Title
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconDeviceImac, IconPlus, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImac, IconPlus, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -45,6 +45,7 @@ function LaporanPublik() {
|
|||||||
function ListLaporanPublik({ search }: { search: string }) {
|
function ListLaporanPublik({ search }: { search: string }) {
|
||||||
const stateLaporan = useProxy(laporanPublikState);
|
const stateLaporan = useProxy(laporanPublikState);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@@ -55,42 +56,54 @@ function ListLaporanPublik({ search }: { search: string }) {
|
|||||||
} = stateLaporan.findMany;
|
} = stateLaporan.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10, search);
|
load(page, 10, debouncedSearch);
|
||||||
}, [page, search]);
|
}, [page, debouncedSearch]);
|
||||||
|
|
||||||
const filteredData = data || [];
|
const filteredData = data || [];
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={{ base: 'sm', md: 'md' }}>
|
||||||
<Skeleton height={600} radius="md" />
|
<Skeleton height={600} radius="md" />
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py={{ base: 'sm', md: 'md' }}>
|
||||||
<Paper withBorder bg={colors['white-1']} p="lg" shadow="md" radius="md">
|
<Paper withBorder bg={colors['white-1']} p={{ base: 'md', md: 'lg' }} shadow="md" radius="md">
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between" mb={{ base: 'sm', md: 'md' }}>
|
||||||
<Title order={4}>Daftar Laporan Publik</Title>
|
<Title order={4} lh={1.2}>
|
||||||
|
Daftar Laporan Publik
|
||||||
|
</Title>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconPlus size={18} />}
|
leftSection={<IconPlus size={18} />}
|
||||||
color="blue"
|
color="blue"
|
||||||
variant="light"
|
variant="light"
|
||||||
onClick={() => router.push('/admin/keamanan/laporan-publik/create')}
|
onClick={() => router.push('/admin/keamanan/laporan-publik/create')}
|
||||||
|
visibleFrom="md"
|
||||||
>
|
>
|
||||||
Tambah Baru
|
Tambah Baru
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
<Box style={{ overflowX: "auto" }}>
|
|
||||||
<Table highlightOnHover>
|
{/* Desktop Table */}
|
||||||
|
<Box visibleFrom="md">
|
||||||
|
<Table
|
||||||
|
highlightOnHover
|
||||||
|
miw={0}
|
||||||
|
style={{
|
||||||
|
tableLayout: 'fixed',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh style={{ width: '25%' }}>Judul Laporan Publik</TableTh>
|
<TableTh style={{ width: '25%' }}><Text fz="sm" fw={600} lh={1.4}>Judul Laporan Publik</Text></TableTh>
|
||||||
<TableTh style={{ width: '20%' }}>Tanggal</TableTh>
|
<TableTh style={{ width: '20%' }}><Text fz="sm" fw={600} lh={1.4}>Tanggal</Text></TableTh>
|
||||||
<TableTh style={{ width: '15%' }}>Status</TableTh>
|
<TableTh style={{ width: '15%' }}><Text fz="sm" fw={600} lh={1.4}>Status</Text></TableTh>
|
||||||
<TableTh style={{ width: '25%' }}>Deskripsi</TableTh>
|
<TableTh style={{ width: '25%' }}><Text fz="sm" fw={600} lh={1.4}>Deskripsi</Text></TableTh>
|
||||||
<TableTh style={{ width: '15%' }}>Aksi</TableTh>
|
<TableTh style={{ width: '15%' }}><Text fz="sm" fw={600} lh={1.4}>Aksi</Text></TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
@@ -98,12 +111,12 @@ function ListLaporanPublik({ search }: { search: string }) {
|
|||||||
filteredData.map((item) => (
|
filteredData.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Text fw={500} truncate="end" lineClamp={1}>
|
<Text fw={500} fz="md" lh={1.5} truncate="end" lineClamp={1}>
|
||||||
{item.judul}
|
{item.judul}
|
||||||
</Text>
|
</Text>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Text fz="sm" c="dimmed">
|
<Text fz="sm" c="gray.7" lh={1.5}>
|
||||||
{new Date(item.tanggalWaktu).toLocaleDateString('id-ID')}
|
{new Date(item.tanggalWaktu).toLocaleDateString('id-ID')}
|
||||||
</Text>
|
</Text>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
@@ -131,9 +144,7 @@ function ListLaporanPublik({ search }: { search: string }) {
|
|||||||
</Box>
|
</Box>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box w={200}>
|
<Text truncate fz="sm" c="gray.7" lineClamp={1} dangerouslySetInnerHTML={{ __html: item.kronologi || '' }} />
|
||||||
<Text truncate fz="sm" c="dimmed" lineClamp={1} dangerouslySetInnerHTML={{ __html: item.kronologi || '' }} />
|
|
||||||
</Box>
|
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Button
|
<Button
|
||||||
@@ -144,7 +155,7 @@ function ListLaporanPublik({ search }: { search: string }) {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<IconDeviceImac size={20} />
|
<IconDeviceImac size={20} />
|
||||||
<Text ml={5}>Detail</Text>
|
<Text ml={5} fz="sm" fw={500}>Detail</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -153,7 +164,7 @@ function ListLaporanPublik({ search }: { search: string }) {
|
|||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTd colSpan={5}>
|
<TableTd colSpan={5}>
|
||||||
<Center py={20}>
|
<Center py={20}>
|
||||||
<Text color="dimmed">
|
<Text c="gray.6" fz="sm" lh={1.5}>
|
||||||
Tidak ada data laporan publik yang cocok
|
Tidak ada data laporan publik yang cocok
|
||||||
</Text>
|
</Text>
|
||||||
</Center>
|
</Center>
|
||||||
@@ -163,7 +174,88 @@ function ListLaporanPublik({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Mobile Cards */}
|
||||||
|
<Stack hiddenFrom="md" gap="xs">
|
||||||
|
{filteredData.length > 0 ? (
|
||||||
|
filteredData.map((item) => (
|
||||||
|
<Paper key={item.id} withBorder p="sm" radius="md">
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>Judul Laporan Publik</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.5}>{item.judul}</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>Tanggal</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.5} c="gray.7">
|
||||||
|
{new Date(item.tanggalWaktu).toLocaleDateString('id-ID')}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>Status</Text>
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
padding: '4px 12px',
|
||||||
|
borderRadius: '16px',
|
||||||
|
backgroundColor:
|
||||||
|
item.status === 'Selesai' ? '#94EF95FF' :
|
||||||
|
item.status === 'Proses' ? '#F1D295FF' :
|
||||||
|
'#F38E8EFF',
|
||||||
|
color:
|
||||||
|
item.status === 'Selesai' ? '#01BA01FF' :
|
||||||
|
item.status === 'Proses' ? '#B67A00FF' :
|
||||||
|
'#AE1700FF',
|
||||||
|
fontWeight: 900,
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
textAlign: 'center',
|
||||||
|
minWidth: '80px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.status}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="xs" fw={600} lh={1.4}>Deskripsi</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.5} c="gray.7" lineClamp={2} dangerouslySetInnerHTML={{ __html: item.kronologi || '' }} />
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
variant="light"
|
||||||
|
color="blue"
|
||||||
|
fullWidth
|
||||||
|
onClick={() =>
|
||||||
|
router.push(`/admin/keamanan/laporan-publik/${item.id}`)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<IconDeviceImac size={20} />
|
||||||
|
<Text ml={5} fz="sm" fw={500}>Detail</Text>
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Center py={20}>
|
||||||
|
<Text c="gray.6" fz="sm" lh={1.5}>
|
||||||
|
Tidak ada data laporan publik yang cocok
|
||||||
|
</Text>
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
{/* Tambah Baru (Mobile only) */}
|
||||||
|
<Button
|
||||||
|
leftSection={<IconPlus size={18} />}
|
||||||
|
color="blue"
|
||||||
|
variant="light"
|
||||||
|
onClick={() => router.push('/admin/keamanan/laporan-publik/create')}
|
||||||
|
hiddenFrom="md"
|
||||||
|
fullWidth
|
||||||
|
mt="sm"
|
||||||
|
>
|
||||||
|
Tambah Baru
|
||||||
|
</Button>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
<Pagination
|
<Pagination
|
||||||
value={page}
|
value={page}
|
||||||
@@ -182,4 +274,4 @@ function ListLaporanPublik({ search }: { search: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default LaporanPublik;
|
export default LaporanPublik;
|
||||||
@@ -120,7 +120,7 @@ function EditPencegahanKriminalitas() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Back button + Title */}
|
{/* Back button + Title */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function DetailPencegahanKriminalitas() {
|
|||||||
const data = kriminalitasState.findUnique.data;
|
const data = kriminalitasState.findUnique.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Tombol Kembali */}
|
{/* Tombol Kembali */}
|
||||||
<Button
|
<Button
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
@@ -54,7 +54,7 @@ function DetailPencegahanKriminalitas() {
|
|||||||
{/* Detail */}
|
{/* Detail */}
|
||||||
<Paper
|
<Paper
|
||||||
withBorder
|
withBorder
|
||||||
w={{ base: "100%", md: "50%" }}
|
w={{ base: "100%", md: "70%" }}
|
||||||
bg={colors['white-1']}
|
bg={colors['white-1']}
|
||||||
p="lg"
|
p="lg"
|
||||||
radius="md"
|
radius="md"
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ function CreatePencegahanKriminalitas() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Header Back Button + Title */}
|
{/* Header Back Button + Title */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ import {
|
|||||||
TableThead,
|
TableThead,
|
||||||
TableTr,
|
TableTr,
|
||||||
Text,
|
Text,
|
||||||
Title
|
Title,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImacCog, IconPlus, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -46,8 +46,9 @@ function PencegahanKriminalitas() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ListPencegahanKriminalitas({ search }: { search: string }) {
|
function ListPencegahanKriminalitas({ search }: { search: string }) {
|
||||||
const kriminalitasState = useProxy(pencegahanKriminalitasState)
|
const kriminalitasState = useProxy(pencegahanKriminalitasState);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@@ -58,24 +59,28 @@ function ListPencegahanKriminalitas({ search }: { search: string }) {
|
|||||||
} = kriminalitasState.findMany;
|
} = kriminalitasState.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10, search);
|
load(page, 10, debouncedSearch);
|
||||||
}, [page, search]);
|
}, [page, debouncedSearch]);
|
||||||
|
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={{ base: 'sm', md: 'md' }}>
|
||||||
<Skeleton height={600} radius="md" />
|
<Skeleton height={600} radius="md" />
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Stack py={{ base: 'sm', md: 'md' }}>
|
||||||
<Paper withBorder bg={colors['white-1']} p={'lg'} shadow="md" radius="md">
|
<Paper withBorder bg={colors['white-1']} p={{ base: 'sm', md: 'lg' }} shadow="md" radius="md">
|
||||||
{/* Judul + Tombol Tambah */}
|
{/* Judul + Tombol Tambah */}
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between" mb={{ base: 'sm', md: 'md' }}>
|
||||||
<Title order={4}>Daftar Pencegahan Kriminalitas</Title>
|
<Title
|
||||||
|
order={4}
|
||||||
|
lh={{ base: 1.2, md: 1.1 }}
|
||||||
|
>
|
||||||
|
Daftar Pencegahan Kriminalitas
|
||||||
|
</Title>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconPlus size={18} />}
|
leftSection={<IconPlus size={18} />}
|
||||||
color="blue"
|
color="blue"
|
||||||
@@ -86,15 +91,22 @@ function ListPencegahanKriminalitas({ search }: { search: string }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Tabel */}
|
{/* Desktop Table */}
|
||||||
<Box style={{ overflowX: "auto" }}>
|
<Box visibleFrom="md">
|
||||||
<Table highlightOnHover>
|
<Table
|
||||||
|
highlightOnHover
|
||||||
|
miw={0}
|
||||||
|
style={{
|
||||||
|
tableLayout: 'fixed',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh>Nama Pencegahan</TableTh>
|
<TableTh style={{ width: '25%' }}>Nama Pencegahan</TableTh>
|
||||||
<TableTh>Deskripsi</TableTh>
|
<TableTh style={{ width: '35%' }}>Deskripsi</TableTh>
|
||||||
<TableTh>Deskripsi Singkat</TableTh>
|
<TableTh style={{ width: '25%' }}>Deskripsi Singkat</TableTh>
|
||||||
<TableTh>Aksi</TableTh>
|
<TableTh style={{ width: '15%' }}>Aksi</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
@@ -102,35 +114,29 @@ function ListPencegahanKriminalitas({ search }: { search: string }) {
|
|||||||
data.map((item) => (
|
data.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box w={200}>
|
<Text fz="md" fw={500} lh={1.45} truncate="end" lineClamp={1}>
|
||||||
<Text fw={500} truncate="end" lineClamp={1}>
|
{item.judul}
|
||||||
{item.judul}
|
</Text>
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box w={200}>
|
<Text
|
||||||
<Text
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
fz="sm"
|
||||||
fz="sm"
|
lh={1.45}
|
||||||
c="dimmed"
|
truncate
|
||||||
truncate
|
lineClamp={1}
|
||||||
lineClamp={1}
|
/>
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box w={200}>
|
<Text
|
||||||
<Text
|
fz="sm"
|
||||||
fz="sm"
|
lh={1.45}
|
||||||
c="dimmed"
|
truncate
|
||||||
truncate
|
lineClamp={1}
|
||||||
lineClamp={1}
|
dangerouslySetInnerHTML={{
|
||||||
dangerouslySetInnerHTML={{
|
__html: item.deskripsiSingkat || ''
|
||||||
__html: item.deskripsiSingkat || ''
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Button
|
<Button
|
||||||
@@ -139,7 +145,9 @@ function ListPencegahanKriminalitas({ search }: { search: string }) {
|
|||||||
onClick={() => router.push(`/admin/keamanan/pencegahan-kriminalitas/${item.id}`)}
|
onClick={() => router.push(`/admin/keamanan/pencegahan-kriminalitas/${item.id}`)}
|
||||||
>
|
>
|
||||||
<IconDeviceImacCog size={20} />
|
<IconDeviceImacCog size={20} />
|
||||||
<Text ml={5}>Detail</Text>
|
<Text ml={5} fz="sm" fw={500} lh={1.4}>
|
||||||
|
Detail
|
||||||
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -148,7 +156,7 @@ function ListPencegahanKriminalitas({ search }: { search: string }) {
|
|||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTd colSpan={4}>
|
<TableTd colSpan={4}>
|
||||||
<Center py={20}>
|
<Center py={20}>
|
||||||
<Text color="dimmed">
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
Tidak ada data pencegahan kriminalitas yang cocok
|
Tidak ada data pencegahan kriminalitas yang cocok
|
||||||
</Text>
|
</Text>
|
||||||
</Center>
|
</Center>
|
||||||
@@ -158,6 +166,71 @@ function ListPencegahanKriminalitas({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Mobile Card View */}
|
||||||
|
<Stack hiddenFrom="md" gap="xs">
|
||||||
|
{data.length > 0 ? (
|
||||||
|
data.map((item) => (
|
||||||
|
<Paper key={item.id} withBorder p="sm" radius="sm">
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Nama Pencegahan
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.4}>
|
||||||
|
{item.judul}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Deskripsi Singkat
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.deskripsiSingkat || '' }}
|
||||||
|
fz="sm"
|
||||||
|
fw={500}
|
||||||
|
lh={1.4}
|
||||||
|
lineClamp={3}
|
||||||
|
ta="justify"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Deskripsi
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
|
fz="sm"
|
||||||
|
fw={500}
|
||||||
|
lh={1.4}
|
||||||
|
lineClamp={3}
|
||||||
|
ta="justify"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
variant="light"
|
||||||
|
color="blue"
|
||||||
|
fullWidth
|
||||||
|
onClick={() => router.push(`/admin/keamanan/pencegahan-kriminalitas/${item.id}`)}
|
||||||
|
>
|
||||||
|
<IconDeviceImacCog size={20} />
|
||||||
|
<Text ml={5} fz="sm" fw={500} lh={1.4}>
|
||||||
|
Detail
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Center py={20}>
|
||||||
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
|
Tidak ada data pencegahan kriminalitas yang cocok
|
||||||
|
</Text>
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Pagination */}
|
{/* Pagination */}
|
||||||
@@ -175,8 +248,8 @@ function ListPencegahanKriminalitas({ search }: { search: string }) {
|
|||||||
radius="md"
|
radius="md"
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Box>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PencegahanKriminalitas;
|
export default PencegahanKriminalitas;
|
||||||
@@ -247,7 +247,7 @@ function EditPolsekTerdekat() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: "sm", md: "lg" }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Modal Tambah */}
|
{/* Modal Tambah */}
|
||||||
<Modal
|
<Modal
|
||||||
opened={modalOpen}
|
opened={modalOpen}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function DetailPolsekTerdekat() {
|
|||||||
const data = polsekState.findUnique.data;
|
const data = polsekState.findUnique.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Tombol Back */}
|
{/* Tombol Back */}
|
||||||
<Button
|
<Button
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
@@ -54,7 +54,7 @@ function DetailPolsekTerdekat() {
|
|||||||
{/* Wrapper Detail */}
|
{/* Wrapper Detail */}
|
||||||
<Paper
|
<Paper
|
||||||
withBorder
|
withBorder
|
||||||
w={{ base: "100%", md: "50%" }}
|
w={{ base: "100%", md: "70%" }}
|
||||||
bg={colors['white-1']}
|
bg={colors['white-1']}
|
||||||
p="lg"
|
p="lg"
|
||||||
radius="md"
|
radius="md"
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ function CreatePolsekTerdekat() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Modal Tambah Layanan */}
|
{/* Modal Tambah Layanan */}
|
||||||
<Modal
|
<Modal
|
||||||
opened={modalOpen}
|
opened={modalOpen}
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ import {
|
|||||||
TableThead,
|
TableThead,
|
||||||
TableTr,
|
TableTr,
|
||||||
Text,
|
Text,
|
||||||
Title
|
Title,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconDeviceImac, IconPlus, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImac, IconPlus, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -45,8 +45,9 @@ function PolsekTerdekat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ListPolsekTerdekat({ search }: { search: string }) {
|
function ListPolsekTerdekat({ search }: { search: string }) {
|
||||||
const polsekState = useProxy(polsekTerdekat)
|
const polsekState = useProxy(polsekTerdekat);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@@ -57,24 +58,26 @@ function ListPolsekTerdekat({ search }: { search: string }) {
|
|||||||
} = polsekState.findMany;
|
} = polsekState.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10, search)
|
load(page, 10, debouncedSearch);
|
||||||
}, [page, search])
|
}, [page, debouncedSearch]);
|
||||||
|
|
||||||
const filteredData = data || []
|
const filteredData = data || [];
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py={{ base: 'sm', md: 'lg' }}>
|
||||||
<Skeleton height={600} radius="md" />
|
<Skeleton height={600} radius="md" />
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py={{ base: 'sm', md: 'lg' }}>
|
||||||
<Paper withBorder bg={colors['white-1']} p={'lg'} shadow="md" radius="md">
|
<Paper withBorder bg={colors['white-1']} p={{ base: 'md', md: 'lg' }} shadow="md" radius="md">
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between" mb={{ base: 'md', md: 'lg' }}>
|
||||||
<Title order={4}>Daftar Polsek Terdekat</Title>
|
<Title order={4} lh={{ base: 1.2, md: 1.2 }}>
|
||||||
|
Daftar Polsek Terdekat
|
||||||
|
</Title>
|
||||||
<Button
|
<Button
|
||||||
leftSection={<IconPlus size={18} />}
|
leftSection={<IconPlus size={18} />}
|
||||||
color="blue"
|
color="blue"
|
||||||
@@ -85,14 +88,38 @@ function ListPolsekTerdekat({ search }: { search: string }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Box style={{ overflowX: "auto" }}>
|
{/* Desktop Table */}
|
||||||
<Table highlightOnHover>
|
<Box visibleFrom="md">
|
||||||
|
<Table
|
||||||
|
highlightOnHover
|
||||||
|
miw={0}
|
||||||
|
style={{
|
||||||
|
tableLayout: 'fixed',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh>Nama Polsek</TableTh>
|
<TableTh style={{ width: '25%' }}>
|
||||||
<TableTh>Jarak</TableTh>
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
<TableTh>Alamat</TableTh>
|
Nama Polsek
|
||||||
<TableTh>Aksi</TableTh>
|
</Text>
|
||||||
|
</TableTh>
|
||||||
|
<TableTh style={{ width: '15%' }}>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Jarak
|
||||||
|
</Text>
|
||||||
|
</TableTh>
|
||||||
|
<TableTh style={{ width: '25%' }}>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Alamat
|
||||||
|
</Text>
|
||||||
|
</TableTh>
|
||||||
|
<TableTh style={{ width: '10%' }}>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Aksi
|
||||||
|
</Text>
|
||||||
|
</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
@@ -100,26 +127,31 @@ function ListPolsekTerdekat({ search }: { search: string }) {
|
|||||||
filteredData.map((item) => (
|
filteredData.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box w={150}>
|
<Text fz="md" fw={500} lh={1.5} truncate="end">
|
||||||
<Text fw={500} truncate="end" lineClamp={1}>
|
{item.nama}
|
||||||
{item.nama}
|
</Text>
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>{item.jarakKeDesa}</TableTd>
|
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Box w={150}>
|
<Text fz="md" fw={500} lh={1.5}>
|
||||||
<Text truncate="end" lineClamp={1}>{item.alamat}</Text>
|
{item.jarakKeDesa}
|
||||||
</Box>
|
</Text>
|
||||||
|
</TableTd>
|
||||||
|
<TableTd>
|
||||||
|
<Text fz="md" fw={500} lh={1.5} truncate="end">
|
||||||
|
{item.alamat}
|
||||||
|
</Text>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd>
|
<TableTd>
|
||||||
<Button
|
<Button
|
||||||
variant="light"
|
variant="light"
|
||||||
color="blue"
|
color="blue"
|
||||||
onClick={() => router.push(`/admin/keamanan/polsek-terdekat/${item.id}`)}
|
onClick={() => router.push(`/admin/keamanan/polsek-terdekat/${item.id}`)}
|
||||||
|
w="100%"
|
||||||
>
|
>
|
||||||
<IconDeviceImac size={18} />
|
<IconDeviceImac size={18} />
|
||||||
<Text ml={5}>Detail</Text>
|
<Text ml={5} fz="sm" fw={500} lh={1.4}>
|
||||||
|
Detail
|
||||||
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -127,8 +159,8 @@ function ListPolsekTerdekat({ search }: { search: string }) {
|
|||||||
) : (
|
) : (
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTd colSpan={4}>
|
<TableTd colSpan={4}>
|
||||||
<Center py={20}>
|
<Center py={24}>
|
||||||
<Text color="dimmed">
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
Tidak ada data Polsek yang cocok
|
Tidak ada data Polsek yang cocok
|
||||||
</Text>
|
</Text>
|
||||||
</Center>
|
</Center>
|
||||||
@@ -138,6 +170,63 @@ function ListPolsekTerdekat({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Mobile Cards */}
|
||||||
|
<Box hiddenFrom="md">
|
||||||
|
<Stack gap="sm">
|
||||||
|
{filteredData.length > 0 ? (
|
||||||
|
filteredData.map((item) => (
|
||||||
|
<Paper key={item.id} withBorder p="sm" radius="sm">
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Nama Polsek
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.45}>
|
||||||
|
{item.nama}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Jarak
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.45}>
|
||||||
|
{item.jarakKeDesa}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Alamat
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.45}>
|
||||||
|
{item.alamat}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
variant="light"
|
||||||
|
color="blue"
|
||||||
|
fullWidth
|
||||||
|
onClick={() => router.push(`/admin/keamanan/polsek-terdekat/${item.id}`)}
|
||||||
|
>
|
||||||
|
<IconDeviceImac size={18} />
|
||||||
|
<Text ml={5} fz="sm" fw={500} lh={1.4}>
|
||||||
|
Detail
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Center py={24}>
|
||||||
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
|
Tidak ada data Polsek yang cocok
|
||||||
|
</Text>
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Pagination */}
|
{/* Pagination */}
|
||||||
@@ -149,8 +238,8 @@ function ListPolsekTerdekat({ search }: { search: string }) {
|
|||||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
}}
|
}}
|
||||||
total={totalPages}
|
total={totalPages}
|
||||||
mt="md"
|
mt={{ base: 'lg', md: 'xl' }}
|
||||||
mb="md"
|
mb={{ base: 'lg', md: 'xl' }}
|
||||||
color="blue"
|
color="blue"
|
||||||
radius="md"
|
radius="md"
|
||||||
/>
|
/>
|
||||||
@@ -159,4 +248,4 @@ function ListPolsekTerdekat({ search }: { search: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PolsekTerdekat;
|
export default PolsekTerdekat;
|
||||||
@@ -132,7 +132,7 @@ function EditTipsKeamanan() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: "sm", md: "lg" }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ function DetailTipsKeamanan() {
|
|||||||
const data = stateKeamanan.findUnique.data;
|
const data = stateKeamanan.findUnique.data;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
<Button
|
<Button
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
onClick={() => router.back()}
|
onClick={() => router.back()}
|
||||||
@@ -53,7 +53,7 @@ function DetailTipsKeamanan() {
|
|||||||
|
|
||||||
<Paper
|
<Paper
|
||||||
withBorder
|
withBorder
|
||||||
w={{ base: "100%", md: "60%" }}
|
w={{ base: "100%", md: "70%" }}
|
||||||
bg={colors['white-1']}
|
bg={colors['white-1']}
|
||||||
p="lg"
|
p="lg"
|
||||||
radius="md"
|
radius="md"
|
||||||
@@ -73,12 +73,14 @@ function DetailTipsKeamanan() {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Text fz="lg" fw="bold">Deskripsi</Text>
|
<Text fz="lg" fw="bold">Deskripsi</Text>
|
||||||
<Text
|
<Box pl={8}>
|
||||||
|
<Text
|
||||||
fz="md"
|
fz="md"
|
||||||
c="dimmed"
|
c="dimmed"
|
||||||
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
|
||||||
dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}
|
dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}
|
||||||
/>
|
/>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ function CreateKeamananLingkungan() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box px={{ base: 'sm', md: 'lg' }} py="md">
|
<Box px={{ base: 0, md: 'xs' }} py="xs">
|
||||||
{/* Header Back + Title */}
|
{/* Header Back + Title */}
|
||||||
<Group mb="md">
|
<Group mb="md">
|
||||||
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ import {
|
|||||||
TableThead,
|
TableThead,
|
||||||
TableTr,
|
TableTr,
|
||||||
Text,
|
Text,
|
||||||
Title
|
Title,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useShallowEffect } from '@mantine/hooks';
|
import { useDebouncedValue, useShallowEffect } from '@mantine/hooks';
|
||||||
import { IconDeviceImac, IconPlus, IconSearch } from '@tabler/icons-react';
|
import { IconDeviceImac, IconPlus, IconSearch } from '@tabler/icons-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@@ -43,8 +43,9 @@ function TipsKeamanan() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ListTipsKeamanan({ search }: { search: string }) {
|
function ListTipsKeamanan({ search }: { search: string }) {
|
||||||
const stateKeamanan = useProxy(tipsKeamananState)
|
const stateKeamanan = useProxy(tipsKeamananState);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const [debouncedSearch] = useDebouncedValue(search, 1000);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data,
|
data,
|
||||||
@@ -52,24 +53,24 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
|||||||
totalPages,
|
totalPages,
|
||||||
loading,
|
loading,
|
||||||
load,
|
load,
|
||||||
} = stateKeamanan.findMany
|
} = stateKeamanan.findMany;
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
load(page, 10, search)
|
load(page, 10, debouncedSearch);
|
||||||
}, [page, search])
|
}, [page, debouncedSearch]);
|
||||||
|
|
||||||
const filteredData = data || []
|
const filteredData = data || [];
|
||||||
|
|
||||||
if (loading || !data) {
|
if (loading || !data) {
|
||||||
return (
|
return (
|
||||||
<Stack py={10}>
|
<Stack py="lg">
|
||||||
<Skeleton height={600} radius="md" />
|
<Skeleton height={600} radius="md" />
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box py={10}>
|
<Box py="lg">
|
||||||
<Paper withBorder bg={colors['white-1']} p="lg" shadow="md" radius="md">
|
<Paper withBorder bg={colors['white-1']} p="lg" shadow="md" radius="md">
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between" mb="md">
|
||||||
<Title order={4}>Daftar Tips Keamanan</Title>
|
<Title order={4}>Daftar Tips Keamanan</Title>
|
||||||
@@ -82,39 +83,64 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
|||||||
Tambah Baru
|
Tambah Baru
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
<Box style={{ overflowX: "auto" }}>
|
|
||||||
<Table highlightOnHover>
|
{/* Desktop Table */}
|
||||||
|
<Box visibleFrom="md">
|
||||||
|
<Table
|
||||||
|
highlightOnHover
|
||||||
|
miw={0}
|
||||||
|
style={{
|
||||||
|
tableLayout: 'fixed',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TableThead>
|
<TableThead>
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTh style={{ width: '25%' }}>Judul</TableTh>
|
<TableTh style={{ width: '25%' }}>
|
||||||
<TableTh style={{ width: '45%' }}>Deskripsi</TableTh>
|
<Text fz="sm" fw={600} lh={1.2}>
|
||||||
<TableTh style={{ width: '15%' }}>Aksi</TableTh>
|
Judul
|
||||||
|
</Text>
|
||||||
|
</TableTh>
|
||||||
|
<TableTh style={{ width: '45%' }}>
|
||||||
|
<Text fz="sm" fw={600} lh={1.2}>
|
||||||
|
Deskripsi
|
||||||
|
</Text>
|
||||||
|
</TableTh>
|
||||||
|
<TableTh style={{ width: '30%' }}>
|
||||||
|
<Text fz="sm" fw={600} lh={1.2}>
|
||||||
|
Aksi
|
||||||
|
</Text>
|
||||||
|
</TableTh>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
</TableThead>
|
</TableThead>
|
||||||
<TableTbody>
|
<TableTbody>
|
||||||
{filteredData.length > 0 ? (
|
{filteredData.length > 0 ? (
|
||||||
filteredData.map((item) => (
|
filteredData.map((item) => (
|
||||||
<TableTr key={item.id}>
|
<TableTr key={item.id}>
|
||||||
<TableTd style={{ width: '25%' }}>
|
<TableTd>
|
||||||
<Box w={200}>
|
<Text fz="md" fw={500} lh={1.5} truncate="end" lineClamp={1}>
|
||||||
<Text fw={500} truncate="end" lineClamp={1}>
|
{item.judul}
|
||||||
{item.judul}
|
</Text>
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd style={{ width: '45%' }}>
|
<TableTd>
|
||||||
<Box w={200}>
|
<Text
|
||||||
<Text fz="sm" c="dimmed" lineClamp={1} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
fz="sm"
|
||||||
</Box>
|
c="dimmed"
|
||||||
|
lh={1.5}
|
||||||
|
lineClamp={1}
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
|
/>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
<TableTd style={{ width: '15%' }}>
|
<TableTd>
|
||||||
<Button
|
<Button
|
||||||
variant="light"
|
variant="light"
|
||||||
color="blue"
|
color="blue"
|
||||||
onClick={() => router.push(`/admin/keamanan/tips-keamanan/${item.id}`)}
|
onClick={() =>
|
||||||
|
router.push(`/admin/keamanan/tips-keamanan/${item.id}`)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<IconDeviceImac size={20} />
|
<IconDeviceImac size={20} />
|
||||||
<Text ml={5}>Detail</Text>
|
<Text ml="xs">Detail</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -122,8 +148,10 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
|||||||
) : (
|
) : (
|
||||||
<TableTr>
|
<TableTr>
|
||||||
<TableTd colSpan={3}>
|
<TableTd colSpan={3}>
|
||||||
<Center py={20}>
|
<Center py="xl">
|
||||||
<Text color="dimmed">Tidak ada data tips keamanan yang cocok</Text>
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
|
Tidak ada data tips keamanan yang cocok
|
||||||
|
</Text>
|
||||||
</Center>
|
</Center>
|
||||||
</TableTd>
|
</TableTd>
|
||||||
</TableTr>
|
</TableTr>
|
||||||
@@ -131,13 +159,66 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
|||||||
</TableTbody>
|
</TableTbody>
|
||||||
</Table>
|
</Table>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Mobile Cards */}
|
||||||
|
<Stack gap="sm" hiddenFrom="md">
|
||||||
|
{filteredData.length > 0 ? (
|
||||||
|
filteredData.map((item) => (
|
||||||
|
<Paper key={item.id} withBorder p="md" radius="md">
|
||||||
|
<Stack gap={'xs'}>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Judul
|
||||||
|
</Text>
|
||||||
|
<Text fz="sm" fw={500} lh={1.45}>
|
||||||
|
{item.judul}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" fw={600} lh={1.4}>
|
||||||
|
Deskripsi
|
||||||
|
</Text>
|
||||||
|
<Box pl={8}>
|
||||||
|
<Text
|
||||||
|
fz="sm"
|
||||||
|
fw={500}
|
||||||
|
lh={1.45}
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Button
|
||||||
|
variant="light"
|
||||||
|
color="blue"
|
||||||
|
fullWidth
|
||||||
|
onClick={() =>
|
||||||
|
router.push(`/admin/keamanan/tips-keamanan/${item.id}`)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<IconDeviceImac size={20} />
|
||||||
|
<Text ml="xs">Detail</Text>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Center py="xl">
|
||||||
|
<Text c="dimmed" fz="sm" lh={1.4}>
|
||||||
|
Tidak ada data tips keamanan yang cocok
|
||||||
|
</Text>
|
||||||
|
</Center>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
<Center>
|
<Center>
|
||||||
<Pagination
|
<Pagination
|
||||||
value={page}
|
value={page}
|
||||||
onChange={(newPage) => {
|
onChange={(newPage) => {
|
||||||
load(newPage, 10)
|
load(newPage, 10);
|
||||||
window.scrollTo({ top: 0, behavior: 'smooth' })
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
}}
|
}}
|
||||||
total={totalPages}
|
total={totalPages}
|
||||||
mt="md"
|
mt="md"
|
||||||
@@ -150,4 +231,4 @@ function ListTipsKeamanan({ search }: { search: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TipsKeamanan;
|
export default TipsKeamanan;
|
||||||
@@ -1,9 +1,29 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
import LayoutTabs from "./_lib/layoutTabs"
|
import LayoutTabs from "./_lib/layoutTabs"
|
||||||
|
import { Box } from "@mantine/core";
|
||||||
|
|
||||||
|
|
||||||
export default function Layout({children} : {children: React.ReactNode}) {
|
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<LayoutTabs>
|
<LayoutTabs>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -204,17 +204,34 @@ function GrafikPersentaseKelahiranKematian() {
|
|||||||
|
|
||||||
{selectedYearData && (
|
{selectedYearData && (
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Flex align="center" gap="sm">
|
<Group visibleFrom='md' align="center" justify='space-between'>
|
||||||
<Title order={4} fw={600} fz={{ base: 'xs', md: 'sm' }} lh={1.2}>
|
<Title order={4} fw={600} fz={{ base: 'xs', md: 'sm' }} lh={1.2}>
|
||||||
Rincian Tahun {selectedYear}
|
Rincian Tahun {selectedYear}
|
||||||
</Title>
|
</Title>
|
||||||
<Badge variant="light" color="blue" fz={{ base: 'xs', md: 'sm' }}>
|
<Group gap={"sm"}>
|
||||||
{formatNumber(selectedYearData.totalKelahiran)} kelahiran
|
<Badge variant="light" color="blue" fz={{ base: 'xs', md: 'sm' }}>
|
||||||
</Badge>
|
{formatNumber(selectedYearData.totalKelahiran)} kelahiran
|
||||||
<Badge variant="light" color="red" fz={{ base: 'xs', md: 'sm' }}>
|
</Badge>
|
||||||
{formatNumber(selectedYearData.totalKematian)} kematian
|
<Badge variant="light" color="red" fz={{ base: 'xs', md: 'sm' }}>
|
||||||
</Badge>
|
{formatNumber(selectedYearData.totalKematian)} kematian
|
||||||
</Flex>
|
</Badge>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Stack hiddenFrom='md' gap="sm">
|
||||||
|
<Title order={4} fw={600} fz={{ base: 'xs', md: 'sm' }} lh={1.2}>
|
||||||
|
Rincian Tahun {selectedYear}
|
||||||
|
</Title>
|
||||||
|
<Group>
|
||||||
|
<Badge variant="light" color="blue" fz={{ base: 'xs', md: 'sm' }}>
|
||||||
|
{formatNumber(selectedYearData.totalKelahiran)} kelahiran
|
||||||
|
</Badge>
|
||||||
|
<Badge variant="light" color="red" fz={{ base: 'xs', md: 'sm' }}>
|
||||||
|
{formatNumber(selectedYearData.totalKematian)} kematian
|
||||||
|
</Badge>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
|
||||||
{/* Desktop: Table */}
|
{/* Desktop: Table */}
|
||||||
<Box visibleFrom="md">
|
<Box visibleFrom="md">
|
||||||
|
|||||||
@@ -1,7 +1,29 @@
|
|||||||
|
'use client'
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LayoutTabs from './_lib/layouTabs';
|
import LayoutTabs from './_lib/layouTabs';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
import { Box } from '@mantine/core';
|
||||||
|
|
||||||
function Layout({ children }: { children: React.ReactNode }) {
|
function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<LayoutTabs>
|
<LayoutTabs>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,7 +1,29 @@
|
|||||||
|
'use client'
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LayoutTabsKepuasan from './_lib/layoutTab';
|
import LayoutTabsKepuasan from './_lib/layoutTab';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
import { Box } from '@mantine/core';
|
||||||
|
|
||||||
function Layout({ children }: { children: React.ReactNode }) {
|
function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutTabsKepuasan>
|
<LayoutTabsKepuasan>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,7 +1,29 @@
|
|||||||
|
'use client'
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LayoutTabs from './_lib/layoutTabs';
|
import LayoutTabs from './_lib/layoutTabs';
|
||||||
|
import { Box } from '@mantine/core';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
|
||||||
function Layout({children} : {children: React.ReactNode}) {
|
function Layout({children} : {children: React.ReactNode}) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutTabs>
|
<LayoutTabs>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,7 +1,29 @@
|
|||||||
|
'use client'
|
||||||
|
import { Box } from '@mantine/core';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LayoutTabs from './_lib/layoutTabs';
|
import LayoutTabs from './_lib/layoutTabs';
|
||||||
|
|
||||||
function Layout({ children }: { children: React.ReactNode }) {
|
function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutTabs>
|
<LayoutTabs>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,8 +1,28 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import LayoutTabsIKM from './_lib/layoutTabs';
|
import LayoutTabsIKM from './_lib/layoutTabs';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
import { Box } from '@mantine/core';
|
||||||
|
|
||||||
function Layout({ children }: { children: React.ReactNode }) {
|
function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<LayoutTabsIKM>
|
<LayoutTabsIKM>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,9 +1,31 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
import LayoutTabs from "./_lib/layoutTabs"
|
import LayoutTabs from "./_lib/layoutTabs"
|
||||||
|
import { Box } from "@mantine/core";
|
||||||
|
|
||||||
|
|
||||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
// Contoh path:
|
||||||
|
// - /darmasaba/desa/berita/semua → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan → panjang 5 → list
|
||||||
|
// - /darmasaba/desa/berita/Pemerintahan/123 → panjang 6 → detail
|
||||||
|
|
||||||
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
|
const isDetailPage = segments.length >= 5;
|
||||||
|
|
||||||
|
if (isDetailPage) {
|
||||||
|
// Tampilkan tanpa tab menu
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
{children}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutTabs>
|
<LayoutTabs>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
Reference in New Issue
Block a user