API & UI Menu Inovasi, SubMenu Layanan Online Desa
This commit is contained in:
@@ -53,6 +53,7 @@
|
|||||||
"framer-motion": "^12.23.5",
|
"framer-motion": "^12.23.5",
|
||||||
"get-port": "^7.1.0",
|
"get-port": "^7.1.0",
|
||||||
"jotai": "^2.12.3",
|
"jotai": "^2.12.3",
|
||||||
|
"list": "^2.0.19",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"motion": "^12.4.1",
|
"motion": "^12.4.1",
|
||||||
"nanoid": "^5.1.5",
|
"nanoid": "^5.1.5",
|
||||||
|
|||||||
@@ -263,6 +263,59 @@ const berita = proxy({
|
|||||||
berita.edit.form = { ...defaultForm };
|
berita.edit.form = { ...defaultForm };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
findFirst: {
|
||||||
|
data: null as Prisma.BeritaGetPayload<{
|
||||||
|
include: {
|
||||||
|
image: true;
|
||||||
|
kategoriBerita: true;
|
||||||
|
};
|
||||||
|
}> | null,
|
||||||
|
loading: false,
|
||||||
|
async load() {
|
||||||
|
this.loading = true;
|
||||||
|
try {
|
||||||
|
const res = await ApiFetch.api.desa.berita["find-first"].get();
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
// Add type assertion to ensure type safety
|
||||||
|
berita.findFirst.data = res.data.data as Prisma.BeritaGetPayload<{
|
||||||
|
include: {
|
||||||
|
image: true;
|
||||||
|
kategoriBerita: true;
|
||||||
|
};
|
||||||
|
}> | null;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch berita terbaru:", err);
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
findRecent: {
|
||||||
|
data: [] as Prisma.BeritaGetPayload<{
|
||||||
|
include: {
|
||||||
|
image: true;
|
||||||
|
kategoriBerita: true;
|
||||||
|
};
|
||||||
|
}>[],
|
||||||
|
loading: false,
|
||||||
|
|
||||||
|
async load() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
const res = await ApiFetch.api.desa.berita["find-recent"].get();
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
this.data = res.data.data ?? [];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gagal fetch berita recent:", error);
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -68,11 +68,11 @@ const pengumuman = proxy({
|
|||||||
},
|
},
|
||||||
findMany: {
|
findMany: {
|
||||||
data: null as
|
data: null as
|
||||||
| Prisma.PengumumanGetPayload<{
|
| Prisma.PengumumanGetPayload<{
|
||||||
include: {
|
include: {
|
||||||
CategoryPengumuman: true;
|
CategoryPengumuman: true;
|
||||||
}
|
};
|
||||||
}>[]
|
}>[]
|
||||||
| null,
|
| null,
|
||||||
async load() {
|
async load() {
|
||||||
const res = await ApiFetch.api.desa.pengumuman["find-many"].get();
|
const res = await ApiFetch.api.desa.pengumuman["find-many"].get();
|
||||||
@@ -82,30 +82,28 @@ const pengumuman = proxy({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// findUnique: {
|
findUnique: {
|
||||||
// data: null as
|
data: null as Prisma.PengumumanGetPayload<{
|
||||||
// | Prisma.PengumumanGetPayload<{
|
include: {
|
||||||
// include: {
|
CategoryPengumuman: true;
|
||||||
// CategoryPengumuman: true;
|
};
|
||||||
// }
|
}> | null,
|
||||||
// }>
|
async load(id: string) {
|
||||||
// | null,
|
try {
|
||||||
// async load(id: string) {
|
const res = await fetch(`/api/desa/pengumuman/${id}`);
|
||||||
// try {
|
if (res.ok) {
|
||||||
// const res = await fetch(`/api/desa/pengumuman/${id}`);
|
const data = await res.json();
|
||||||
// if (res.ok) {
|
pengumuman.findUnique.data = data.data ?? null;
|
||||||
// const data = await res.json();
|
} else {
|
||||||
// pengumuman.findUnique.data = data.data ?? null;
|
console.error("Failed to fetch pengumuman:", res.statusText);
|
||||||
// } else {
|
pengumuman.findUnique.data = null;
|
||||||
// console.error('Failed to fetch pengumuman:', res.statusText);
|
}
|
||||||
// pengumuman.findUnique.data = null;
|
} catch (error) {
|
||||||
// }
|
console.error("Error fetching pengumuman:", error);
|
||||||
// } catch (error) {
|
pengumuman.findUnique.data = null;
|
||||||
// console.error('Error fetching pengumuman:', error);
|
}
|
||||||
// pengumuman.findUnique.data = null;
|
},
|
||||||
// }
|
},
|
||||||
// },
|
|
||||||
// },
|
|
||||||
delete: {
|
delete: {
|
||||||
loading: false,
|
loading: false,
|
||||||
async byId(id: string) {
|
async byId(id: string) {
|
||||||
@@ -237,6 +235,55 @@ const pengumuman = proxy({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
findFirst: {
|
||||||
|
data: null as Prisma.PengumumanGetPayload<{
|
||||||
|
include: {
|
||||||
|
CategoryPengumuman: true;
|
||||||
|
};
|
||||||
|
}> | null,
|
||||||
|
loading: false,
|
||||||
|
async load() {
|
||||||
|
this.loading = true;
|
||||||
|
try {
|
||||||
|
const res = await ApiFetch.api.desa.pengumuman["find-first"].get();
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
// Add type assertion to ensure type safety
|
||||||
|
pengumuman.findFirst.data = res.data
|
||||||
|
.data as Prisma.PengumumanGetPayload<{
|
||||||
|
include: {
|
||||||
|
CategoryPengumuman: true;
|
||||||
|
};
|
||||||
|
}> | null;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Gagal fetch pengumuman terbaru:", err);
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
findRecent: {
|
||||||
|
data: [] as Prisma.PengumumanGetPayload<{
|
||||||
|
include: {
|
||||||
|
CategoryPengumuman: true;
|
||||||
|
};
|
||||||
|
}>[],
|
||||||
|
loading: false,
|
||||||
|
|
||||||
|
async load() {
|
||||||
|
try {
|
||||||
|
this.loading = true;
|
||||||
|
const res = await ApiFetch.api.desa.pengumuman["find-recent"].get();
|
||||||
|
if (res.status === 200 && res.data?.success) {
|
||||||
|
this.data = res.data.data ?? [];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Gagal fetch pengumuman recent:", error);
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const stateDesaPengumuman = proxy({
|
const stateDesaPengumuman = proxy({
|
||||||
|
|||||||
30
src/app/api/[[...slugs]]/_lib/desa/berita/findFirst.ts
Normal file
30
src/app/api/[[...slugs]]/_lib/desa/berita/findFirst.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import prisma from '@/lib/prisma';
|
||||||
|
|
||||||
|
export default async function beritaFindFirst() {
|
||||||
|
try {
|
||||||
|
const result = await prisma.berita.findFirst({
|
||||||
|
where: {
|
||||||
|
isActive: true, // opsional kalau kamu punya field ini
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: 'desc', // ambil yang paling terbaru
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
image: true,
|
||||||
|
kategoriBerita: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: 'Berhasil ambil berita terbaru',
|
||||||
|
data: result,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[findFirstBerita] Error:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: 'Gagal ambil berita terbaru',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/app/api/[[...slugs]]/_lib/desa/berita/findRecent.ts
Normal file
19
src/app/api/[[...slugs]]/_lib/desa/berita/findRecent.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import prisma from "@/lib/prisma";
|
||||||
|
|
||||||
|
export default async function findRecentBerita() {
|
||||||
|
const result = await prisma.berita.findMany({
|
||||||
|
orderBy: {
|
||||||
|
createdAt: "desc",
|
||||||
|
},
|
||||||
|
take: 4, // ambil 4 data terbaru
|
||||||
|
include: {
|
||||||
|
image: true,
|
||||||
|
kategoriBerita: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: result,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ import beritaCreate from "./create";
|
|||||||
import beritaDelete from "./del";
|
import beritaDelete from "./del";
|
||||||
import beritaUpdate from "./updt";
|
import beritaUpdate from "./updt";
|
||||||
import findBeritaById from "./find-by-id";
|
import findBeritaById from "./find-by-id";
|
||||||
|
import beritaFindFirst from "./findFirst";
|
||||||
|
import findRecentBerita from "./findRecent";
|
||||||
|
|
||||||
const Berita = new Elysia({ prefix: "/berita", tags: ["Desa/Berita"] })
|
const Berita = new Elysia({ prefix: "/berita", tags: ["Desa/Berita"] })
|
||||||
.get("/category/find-many", kategoriBeritaFindMany)
|
.get("/category/find-many", kategoriBeritaFindMany)
|
||||||
@@ -22,6 +24,8 @@ const Berita = new Elysia({ prefix: "/berita", tags: ["Desa/Berita"] })
|
|||||||
kategoriBeritaId: t.Union([t.String(), t.Null()]),
|
kategoriBeritaId: t.Union([t.String(), t.Null()]),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
.get("/find-first", beritaFindFirst)
|
||||||
|
.get("/find-recent", findRecentBerita)
|
||||||
.delete("/delete/:id", beritaDelete)
|
.delete("/delete/:id", beritaDelete)
|
||||||
.put(
|
.put(
|
||||||
"/:id",
|
"/:id",
|
||||||
@@ -39,5 +43,6 @@ const Berita = new Elysia({ prefix: "/berita", tags: ["Desa/Berita"] })
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
export default Berita;
|
export default Berita;
|
||||||
|
|||||||
29
src/app/api/[[...slugs]]/_lib/desa/pengumuman/findFirst.ts
Normal file
29
src/app/api/[[...slugs]]/_lib/desa/pengumuman/findFirst.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import prisma from '@/lib/prisma';
|
||||||
|
|
||||||
|
export default async function pengumumanFindFirst() {
|
||||||
|
try {
|
||||||
|
const result = await prisma.pengumuman.findFirst({
|
||||||
|
where: {
|
||||||
|
isActive: true, // opsional kalau kamu punya field ini
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: 'desc', // ambil yang paling terbaru
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
CategoryPengumuman: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: 'Berhasil ambil pengumuman terbaru',
|
||||||
|
data: result,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[findFirstPengumuman] Error:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: 'Gagal ambil pengumuman terbaru',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/app/api/[[...slugs]]/_lib/desa/pengumuman/findRecent.ts
Normal file
18
src/app/api/[[...slugs]]/_lib/desa/pengumuman/findRecent.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import prisma from "@/lib/prisma";
|
||||||
|
|
||||||
|
export default async function pengumumanFindRecent() {
|
||||||
|
const result = await prisma.pengumuman.findMany({
|
||||||
|
orderBy: {
|
||||||
|
createdAt: "desc",
|
||||||
|
},
|
||||||
|
take: 4, // ambil 4 data terbaru
|
||||||
|
include: {
|
||||||
|
CategoryPengumuman: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: result,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -6,6 +6,8 @@ import pengumumanCategoryFindMany from "./category";
|
|||||||
import pengumumanDelete from "./del";
|
import pengumumanDelete from "./del";
|
||||||
import pengumumanFindById from "./find-by-id";
|
import pengumumanFindById from "./find-by-id";
|
||||||
import pengumumanUpdate from "./updt";
|
import pengumumanUpdate from "./updt";
|
||||||
|
import pengumumanFindFirst from "./findFirst";
|
||||||
|
import pengumumanFindRecent from "./findRecent";
|
||||||
|
|
||||||
const Pengumuman = new Elysia({ prefix: "/pengumuman", tags: ["Desa/Pengumuman"] })
|
const Pengumuman = new Elysia({ prefix: "/pengumuman", tags: ["Desa/Pengumuman"] })
|
||||||
.get("/category/find-many", pengumumanCategoryFindMany)
|
.get("/category/find-many", pengumumanCategoryFindMany)
|
||||||
@@ -20,6 +22,8 @@ const Pengumuman = new Elysia({ prefix: "/pengumuman", tags: ["Desa/Pengumuman"]
|
|||||||
categoryPengumumanId: t.Union([t.String(), t.Null()]),
|
categoryPengumumanId: t.Union([t.String(), t.Null()]),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
.get("/find-first", pengumumanFindFirst)
|
||||||
|
.get("/find-recent", pengumumanFindRecent)
|
||||||
.put("/:id", pengumumanUpdate, {
|
.put("/:id", pengumumanUpdate, {
|
||||||
body: t.Object({
|
body: t.Object({
|
||||||
id: t.String(),
|
id: t.String(),
|
||||||
|
|||||||
@@ -1,27 +1,136 @@
|
|||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
'use client'
|
'use client'
|
||||||
|
import stateDashboardBerita from '@/app/admin/(dashboard)/_state/desa/berita';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Paper, Stack, Text } from '@mantine/core';
|
import { Box, Card, Divider, Grid, GridCol, Image, Paper, Stack, Text, Title } from '@mantine/core';
|
||||||
import { IconBell } from '@tabler/icons-react';
|
import dayjs from 'dayjs';
|
||||||
import { motion } from 'framer-motion';
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useProxy } from 'valtio/utils';
|
||||||
|
import BackButton from '../../../desa/layanan/_com/BackButto';
|
||||||
|
import stateDesaPengumuman from '@/app/admin/(dashboard)/_state/desa/pengumuman';
|
||||||
|
|
||||||
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
function InformasiDesa() {
|
function InformasiDesa() {
|
||||||
|
const stateBerita = useProxy(stateDashboardBerita.berita)
|
||||||
|
const statePengumuman = useProxy(stateDesaPengumuman.pengumuman)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
stateBerita.findFirst.load();
|
||||||
|
stateBerita.findRecent.load();
|
||||||
|
statePengumuman.findFirst.load();
|
||||||
|
statePengumuman.findRecent.load();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const dataBerita = stateBerita.findFirst.data
|
||||||
|
const dataPengumuman = statePengumuman.findFirst.data
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
<Stack >
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
<motion.div
|
<BackButton />
|
||||||
whileHover={{ scale: 1.05 }}
|
</Box>
|
||||||
whileTap={{ scale: 0.8 }}
|
<Box px={{ base: 'md', md: 100 }} >
|
||||||
>
|
<Text ta={"center"} fz={{ base: "h1", md: "2.5rem" }} c={colors["blue-button"]} fw={"bold"}>
|
||||||
<Paper p={'xl'} >
|
Informasi Desa
|
||||||
<Box>
|
</Text>
|
||||||
<IconBell size={50} color={colors['blue-button']} />,
|
</Box>
|
||||||
</Box>
|
<Box px={{ base: "md", md: 100 }}>
|
||||||
<Text fz={'h3'} fw={'bold'} c={colors['blue-button']}>Informasi Desa</Text>
|
<Stack gap={10}>
|
||||||
<Text fz={'lg'} c={'black'}>Akses berita dan pengumuman terbaru seputar kegiatan desa</Text>
|
{dataBerita && (
|
||||||
</Paper>
|
<Paper shadow="md" radius="md" p="md">
|
||||||
</motion.div>
|
<Grid>
|
||||||
|
<GridCol span={{ md: 6, base: 12 }}>
|
||||||
|
<Image
|
||||||
|
src={dataBerita.image?.link || "/fallback.jpg"}
|
||||||
|
alt={dataBerita.judul}
|
||||||
|
radius="md"
|
||||||
|
fit="cover"
|
||||||
|
height={250}
|
||||||
|
maw={600}
|
||||||
|
/>
|
||||||
|
</GridCol>
|
||||||
|
<GridCol span={{ md: 6, base: 12 }}>
|
||||||
|
<Box>
|
||||||
|
<Text fz="sm" c="dimmed">{dataBerita.kategoriBerita?.name} • {dayjs(dataBerita.createdAt).fromNow()}</Text>
|
||||||
|
<Title order={1} fw="bold">{dataBerita.judul}</Title>
|
||||||
|
<Text ta={"justify"} mt="xs" fz="md" dangerouslySetInnerHTML={{ __html: dataBerita.content }} />
|
||||||
|
</Box>
|
||||||
|
</GridCol>
|
||||||
|
</Grid>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
<Stack py={10}>
|
||||||
|
<Title order={3}>Berita Terbaru</Title>
|
||||||
|
<Grid>
|
||||||
|
{stateBerita.findRecent.data.map((item) => (
|
||||||
|
<GridCol span={{ base: 12, sm: 6, md: 3 }} key={item.id}>
|
||||||
|
<Card shadow="sm" radius="md" withBorder h="100%">
|
||||||
|
<Card.Section>
|
||||||
|
<Image
|
||||||
|
src={item.image?.link || "/placeholder.jpg"}
|
||||||
|
alt={item.judul}
|
||||||
|
height={160} // gambar fix height
|
||||||
|
fit="cover"
|
||||||
|
/>
|
||||||
|
</Card.Section>
|
||||||
|
<Stack gap="xs" mt="sm">
|
||||||
|
<Text fw={600} lineClamp={2}>
|
||||||
|
{item.judul}
|
||||||
|
</Text>
|
||||||
|
<Text size="sm" color="dimmed" lineClamp={2}>
|
||||||
|
{item.deskripsi}
|
||||||
|
</Text>
|
||||||
|
<Text size="xs" c="gray">
|
||||||
|
{dayjs(item.createdAt).fromNow()}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
</GridCol>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Stack>
|
||||||
|
<Divider color={colors['blue-button']} my="md" />
|
||||||
|
{dataPengumuman && (
|
||||||
|
<Paper shadow="md" radius="md" p="md">
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Title order={1} fw="bold">{dataPengumuman.judul}</Title>
|
||||||
|
<Text fz="sm" c="dimmed">{dataPengumuman.CategoryPengumuman?.name} • {dayjs(dataPengumuman.createdAt).fromNow()}</Text>
|
||||||
|
<Box>
|
||||||
|
<Text ta={"justify"} mt="xs" fz="md" dangerouslySetInnerHTML={{ __html: dataPengumuman.content }} />
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
<Stack py={10}>
|
||||||
|
<Title order={3}>Pengumuman Terbaru</Title>
|
||||||
|
<Grid>
|
||||||
|
{statePengumuman.findRecent.data.map((item) => (
|
||||||
|
<GridCol span={{ base: 12, sm: 6, md: 3 }} key={item.id}>
|
||||||
|
<Card shadow="sm" radius="md" withBorder h="100%">
|
||||||
|
<Stack gap="xs" mt="sm">
|
||||||
|
<Text fw={600} lineClamp={2}>
|
||||||
|
{item.judul}
|
||||||
|
</Text>
|
||||||
|
<Text size="sm" color="dimmed" lineClamp={2}>
|
||||||
|
{item.deskripsi}
|
||||||
|
</Text>
|
||||||
|
<Text size="xs" c="gray">
|
||||||
|
{dayjs(item.createdAt).fromNow()}
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
</GridCol>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
|
|
||||||
'use client'
|
'use client'
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, SimpleGrid, Stack, Text } from '@mantine/core';
|
import { Box, Paper, SimpleGrid, Stack, Text } from '@mantine/core';
|
||||||
|
import { IconBell } from '@tabler/icons-react';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
import AdministrasiOnline from './administrasi-online/page';
|
import AdministrasiOnline from './administrasi-online/page';
|
||||||
import InformasiDesa from './informasi-desa/page';
|
|
||||||
import PengaduanMasyarakat from './pengaduan-masyarakat/page';
|
import PengaduanMasyarakat from './pengaduan-masyarakat/page';
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
|
const router = useRouter()
|
||||||
return (
|
return (
|
||||||
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
<Stack pos={"relative"} bg={colors.Bg} py={"xl"} gap={"22"}>
|
||||||
<Box px={{ base: 'md', md: 100 }}>
|
<Box px={{ base: 'md', md: 100 }}>
|
||||||
@@ -29,7 +32,23 @@ function Page() {
|
|||||||
<Stack gap={'lg'}>
|
<Stack gap={'lg'}>
|
||||||
<AdministrasiOnline />
|
<AdministrasiOnline />
|
||||||
<PengaduanMasyarakat />
|
<PengaduanMasyarakat />
|
||||||
<InformasiDesa />
|
<Box>
|
||||||
|
<Stack>
|
||||||
|
<motion.div
|
||||||
|
whileHover={{ scale: 1.05 }}
|
||||||
|
whileTap={{ scale: 0.8 }}
|
||||||
|
onClick={() => router.push('/darmasaba/inovasi/layanan-online-desa/informasi-desa')}
|
||||||
|
>
|
||||||
|
<Paper p={'xl'} >
|
||||||
|
<Box>
|
||||||
|
<IconBell size={50} color={colors['blue-button']} />
|
||||||
|
</Box>
|
||||||
|
<Text fz={'h3'} fw={'bold'} c={colors['blue-button']}>Informasi Desa</Text>
|
||||||
|
<Text fz={'lg'} c={'black'}>Akses berita dan pengumuman terbaru seputar kegiatan desa</Text>
|
||||||
|
</Paper>
|
||||||
|
</motion.div>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ function PengaduanMasyarakat() {
|
|||||||
>
|
>
|
||||||
<Paper p={'xl'} >
|
<Paper p={'xl'} >
|
||||||
<Box>
|
<Box>
|
||||||
<IconMessageCircleQuestion size={50} color={colors['blue-button']} />,
|
<IconMessageCircleQuestion size={50} color={colors['blue-button']} />
|
||||||
</Box>
|
</Box>
|
||||||
<Text fz={'h3'} fw={'bold'} c={colors['blue-button']}>Pengaduan Masyarakat</Text>
|
<Text fz={'h3'} fw={'bold'} c={colors['blue-button']}>Pengaduan Masyarakat</Text>
|
||||||
<Text fz={'lg'} c={'black'}>Sampaikan keluhan dan aspirasi Anda melalui platform digital kami</Text>
|
<Text fz={'lg'} c={'black'}>Sampaikan keluhan dan aspirasi Anda melalui platform digital kami</Text>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export function Navbar() {
|
|||||||
}}
|
}}
|
||||||
size={80} radius={"xl"}
|
size={80} radius={"xl"}
|
||||||
>
|
>
|
||||||
<Image src="/api/img/darmasaba-icon.png" alt="Logo Desa" width={50} height={50} />
|
<Image src="/darmasaba-icon.png" alt="Logo Desa" width={50} height={50} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<Burger onClick={() => stateNav.mobileOpen = !stateNav.mobileOpen} color={colors["blue-button"]} opened={mobileOpen} />
|
<Burger onClick={() => stateNav.mobileOpen = !stateNav.mobileOpen} color={colors["blue-button"]} opened={mobileOpen} />
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
Reference in New Issue
Block a user