Sinkronisasi UI & API Admin - User Submenu Penghargaan
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import ApiFetch from "@/lib/api-fetch";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -5,10 +6,10 @@ import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
const templateForm = z.object({
|
||||
name: z.string().min(1).max(50),
|
||||
juara: z.string().min(1).max(50),
|
||||
name: z.string().min(1).max(5000),
|
||||
juara: z.string().min(1).max(5000),
|
||||
deskripsi: z.string().min(1).max(5000),
|
||||
imageId: z.string().min(1).max(50),
|
||||
imageId: z.string().min(1).max(5000),
|
||||
});
|
||||
|
||||
const defaultForm = {
|
||||
@@ -50,17 +51,38 @@ const penghargaanState = proxy({
|
||||
},
|
||||
},
|
||||
findMany: {
|
||||
data: null as
|
||||
| Prisma.PenghargaanGetPayload<{
|
||||
include: {
|
||||
image: true;
|
||||
};
|
||||
}>[]
|
||||
| null,
|
||||
async load() {
|
||||
const res = await ApiFetch.api.desa.penghargaan["find-many"].get();
|
||||
if (res.status === 200) {
|
||||
penghargaanState.findMany.data = res.data?.data ?? [];
|
||||
data: null as any[] | null,
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
loading: false,
|
||||
load: async (page = 1, limit = 10) => { // Change to arrow function
|
||||
penghargaanState.findMany.loading = true; // Use the full path to access the property
|
||||
penghargaanState.findMany.page = page;
|
||||
try {
|
||||
const res = await ApiFetch.api.desa.penghargaan[
|
||||
"find-many"
|
||||
].get({
|
||||
query: { page, limit },
|
||||
});
|
||||
|
||||
if (res.status === 200 && res.data?.success) {
|
||||
penghargaanState.findMany.data = res.data.data || [];
|
||||
penghargaanState.findMany.total = res.data.total || 0;
|
||||
penghargaanState.findMany.totalPages = res.data.totalPages || 1;
|
||||
} else {
|
||||
console.error("Failed to load penghargaan:", res.data?.message);
|
||||
penghargaanState.findMany.data = [];
|
||||
penghargaanState.findMany.total = 0;
|
||||
penghargaanState.findMany.totalPages = 1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading penghargaan:", error);
|
||||
penghargaanState.findMany.data = [];
|
||||
penghargaanState.findMany.total = 0;
|
||||
penghargaanState.findMany.totalPages = 1;
|
||||
} finally {
|
||||
penghargaanState.findMany.loading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -51,7 +51,6 @@ function ListSuratKeterangan({ search }: { search: string }) {
|
||||
item.deskripsi?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
.sort((a, b) => a.posisi?.hierarki - b.posisi?.hierarki);
|
||||
}, [data, search]);
|
||||
|
||||
// Handle loading state
|
||||
|
||||
@@ -50,6 +50,10 @@ function DetailPenghargaan() {
|
||||
{statePenghargaan.findUnique.data ? (
|
||||
<Paper key={statePenghargaan.findUnique.data.id} bg={colors['BG-trans']} p={'md'}>
|
||||
<Stack gap={"xs"}>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Gambar</Text>
|
||||
<Image w={{ base: 400, md: 400, lg: 400 }} src={statePenghargaan.findUnique.data?.image?.link} alt="gambar" />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Judul</Text>
|
||||
<Text fz={"lg"}>{statePenghargaan.findUnique.data?.name}</Text>
|
||||
@@ -62,10 +66,6 @@ function DetailPenghargaan() {
|
||||
<Text fw={"bold"} fz={"lg"}>Deskripsi</Text>
|
||||
<Text fz={"lg"} dangerouslySetInnerHTML={{ __html: statePenghargaan.findUnique.data?.deskripsi }} />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text fw={"bold"} fz={"lg"}>Gambar</Text>
|
||||
<Image w={{ base: 150, md: 150, lg: 150 }} src={statePenghargaan.findUnique.data?.image?.link} alt="gambar" />
|
||||
</Box>
|
||||
<Flex gap={"xs"} mt={10}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
||||
@@ -1,61 +1,103 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import penghargaanState from '@/app/admin/(dashboard)/_state/desa/penghargaan';
|
||||
import colors from '@/con/colors';
|
||||
import { Box, Button, Image, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { useShallowEffect } from '@mantine/hooks';
|
||||
import { Box, Button, Center, Image, Pagination, Paper, Skeleton, Stack, Table, TableTbody, TableTd, TableTh, TableThead, TableTr, Text } from '@mantine/core';
|
||||
import { IconDeviceImac, IconSearch } from '@tabler/icons-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import JudulListTab from '../../_com/judulListTab';
|
||||
import { useState } from 'react';
|
||||
import HeaderSearch from '../../_com/header';
|
||||
import JudulList from '../../_com/judulList';
|
||||
|
||||
function Penghargaan() {
|
||||
const [search, setSearch] = useState("");
|
||||
return (
|
||||
<Box>
|
||||
<HeaderSearch
|
||||
title='Posisi Organisasi'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListPenghargaan search={search} />
|
||||
</Box>
|
||||
);
|
||||
const [search, setSearch] = useState("");
|
||||
return (
|
||||
<Box>
|
||||
<HeaderSearch
|
||||
title='Penghargaan'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={20} />}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
/>
|
||||
<ListPenghargaan search={search} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ListPenghargaan({ search }: { search: string }) {
|
||||
const state = useProxy(penghargaanState)
|
||||
const router = useRouter()
|
||||
useShallowEffect(() => {
|
||||
state.findMany.load()
|
||||
|
||||
const {
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
loading,
|
||||
load,
|
||||
} = state.findMany;
|
||||
|
||||
useEffect(() => {
|
||||
load(page, 10)
|
||||
}, [])
|
||||
|
||||
const filteredData = (state.findMany.data || []).filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi.toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
const filteredData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
return data.filter(item => {
|
||||
const keyword = search.toLowerCase();
|
||||
return (
|
||||
item.name?.toLowerCase().includes(keyword) ||
|
||||
item.deskripsi?.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
}, [data, search]);
|
||||
|
||||
if (!state.findMany.data) {
|
||||
return(
|
||||
// Handle loading state
|
||||
if (loading || !data) {
|
||||
return (
|
||||
<Stack py={10}>
|
||||
<Skeleton h={500} />
|
||||
<Skeleton height={300} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulList
|
||||
title='List Penghargaan'
|
||||
href='/admin/desa/penghargaan/create'
|
||||
/>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh>Nama</TableTh>
|
||||
<TableTh>Deskripsi</TableTh>
|
||||
<TableTh>Image</TableTh>
|
||||
<TableTh>Detail</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
<TableTr>
|
||||
<TableTd colSpan={4}>
|
||||
<Text ta="center">Tidak ada data</Text>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Box py={10}>
|
||||
<Paper bg={colors['white-1']} p={'md'}>
|
||||
<JudulListTab
|
||||
<JudulList
|
||||
title='List Penghargaan'
|
||||
href='/admin/desa/penghargaan/create'
|
||||
placeholder='pencarian'
|
||||
searchIcon={<IconSearch size={16} />}
|
||||
/>
|
||||
<Table striped withTableBorder withRowBorders>
|
||||
<TableThead>
|
||||
@@ -69,25 +111,43 @@ function ListPenghargaan({ search }: { search: string }) {
|
||||
<TableTbody>
|
||||
{filteredData.map((item) => (
|
||||
<TableTr key={item.id}>
|
||||
<TableTd>{item.name}</TableTd>
|
||||
<TableTd>
|
||||
<Text truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
<Box w={100}>
|
||||
<Text lineClamp={1} truncate="end" fz={"sm"}>{item.name}</Text>
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Box w={100}>
|
||||
<Text lineClamp={1} truncate="end" fz={"sm"} dangerouslySetInnerHTML={{ __html: item.deskripsi }} />
|
||||
</Box>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Image w={100} src={item.image?.link} alt="gambar" />
|
||||
</TableTd>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text>
|
||||
<Button onClick={() => router.push(`/admin/desa/penghargaan/${item.id}`)}>
|
||||
<IconDeviceImac size={20} />
|
||||
</Button>
|
||||
</Text>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
<IconDeviceImac size={20} />
|
||||
</Button>
|
||||
</Text>
|
||||
</TableTd>
|
||||
</TableTr>
|
||||
))}
|
||||
</TableTbody>
|
||||
</Table>
|
||||
</Paper>
|
||||
<Center>
|
||||
<Pagination
|
||||
value={page}
|
||||
onChange={(newPage) => {
|
||||
load(newPage, 10);
|
||||
window.scrollTo(0, 0);
|
||||
}}
|
||||
total={totalPages}
|
||||
mt="md"
|
||||
mb="md"
|
||||
/>
|
||||
</Center>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,46 @@
|
||||
import prisma from "@/lib/prisma";
|
||||
import { Context } from "elysia";
|
||||
|
||||
export default async function penghargaanFindMany(context: Context) {
|
||||
const page = Number(context.query.page) || 1;
|
||||
const limit = Number(context.query.limit) || 10;
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
export default async function penghargaanFindMany() {
|
||||
try {
|
||||
const data = await prisma.penghargaan.findMany({
|
||||
include: {
|
||||
image: true,
|
||||
},
|
||||
});
|
||||
const [data, total] = await Promise.all([
|
||||
prisma.penghargaan.findMany({
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
image: true,
|
||||
},
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
}),
|
||||
prisma.penghargaan.count({
|
||||
where: { isActive: true }
|
||||
})
|
||||
]);
|
||||
|
||||
const totalPages = Math.ceil(total / limit);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Success fetch penghargaan",
|
||||
message: "Success fetch penghargaan with pagination",
|
||||
data,
|
||||
page,
|
||||
totalPages,
|
||||
total,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Find many error:", error);
|
||||
} catch (e) {
|
||||
console.error("Find many paginated error:", e);
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed fetch penghargaan",
|
||||
message: "Failed fetch penghargaan with pagination",
|
||||
data: [],
|
||||
page: 1,
|
||||
totalPages: 1,
|
||||
total: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Container, Text, Image, ActionIcon, Box, Divider, Flex, Group } from '@mantine/core';
|
||||
import { IconBrandFacebook, IconBrandInstagram, IconBrandTwitter, IconBrandWhatsapp } from '@tabler/icons-react';
|
||||
import React from 'react';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.grey[1]} py={"xl"} gap={22}>
|
||||
<Group px={{ base: "md", md: 100 }}>
|
||||
<BackButton />
|
||||
</Group>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"3.4rem"} fw={"bold"}>
|
||||
Juara 2
|
||||
</Text>
|
||||
<Text
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
>
|
||||
Duta Invenstasi Kabupaten Badung 2024
|
||||
</Text>
|
||||
<Image py={20} src={"/api/img/penghargaan-3.png"} alt='' />
|
||||
</Stack>
|
||||
</Container>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Text
|
||||
pb={20}
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
>
|
||||
Desa Dramasaba Raih Juara 2 dalam Duta Invenstasi Kabupaten Badung 2024
|
||||
</Text>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
>
|
||||
Desa Dramasaba kembali menunjukkan eksistensinya dalam memajukan potensi desa dengan meraih Juara 2 dalam ajang Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024. Prestasi ini menjadi bukti nyata bahwa Desa Dramasaba memiliki daya tarik serta peluang investasi yang menjanjikan bagi para investor maupun masyarakat yang ingin berkontribusi dalam pengembangan desa.
|
||||
</Text>
|
||||
<Text
|
||||
py={5}
|
||||
ta={"justify"}
|
||||
>
|
||||
Dalam video pendek yang diikutsertakan dalam lomba ini, Desa Dramasaba menampilkan berbagai potensi unggulan yang dimiliki, mulai dari sektor pertanian, pariwisata berbasis budaya, hingga ekonomi kreatif yang sedang berkembang pesat. Dengan pengemasan yang menarik dan penyampaian informasi yang jelas, video tersebut berhasil memikat perhatian dewan juri serta menjadi inspirasi bagi desa-desa lain dalam mengembangkan potensi wilayahnya masing-masing.
|
||||
</Text>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
>
|
||||
Keberhasilan ini tidak lepas dari kerja keras seluruh tim kreatif, pemerintah desa, serta masyarakat yang turut berpartisipasi dalam produksi video. Kepala Desa Dramasaba, [Nama Kepala Desa], mengungkapkan rasa syukur dan bangganya atas pencapaian ini. Menurutnya, kemenangan ini bukan sekadar penghargaan, tetapi juga menjadi motivasi untuk terus mengembangkan desa agar semakin dikenal luas dan menarik lebih banyak peluang investasi.
|
||||
</Text>
|
||||
<Text
|
||||
py={5}
|
||||
ta={"justify"}
|
||||
>
|
||||
Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024 merupakan ajang yang diadakan oleh pemerintah daerah dengan tujuan untuk mendorong desa-desa dalam mengenalkan dan mempromosikan potensi investasi mereka. Dengan mengikuti lomba ini, Desa Dramasaba tidak hanya memperoleh apresiasi, tetapi juga membuka peluang lebih besar untuk berkolaborasi dengan investor maupun pihak lain yang tertarik dalam pengembangan desa.
|
||||
</Text>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
>
|
||||
Ke depan, Desa Dramasaba berkomitmen untuk terus meningkatkan daya saingnya, baik dalam sektor ekonomi, budaya, maupun infrastruktur, sehingga mampu memberikan manfaat yang lebih besar bagi masyarakat serta menarik perhatian lebih banyak pihak untuk berinvestasi dan berkontribusi dalam pembangunan desa.
|
||||
</Text>
|
||||
<Text
|
||||
py={5}
|
||||
ta={"justify"}
|
||||
>
|
||||
Dengan prestasi ini, diharapkan Desa Dramasaba dapat menjadi contoh bagi desa-desa lain dalam memanfaatkan media digital sebagai sarana promosi dan pengembangan potensi lokal.
|
||||
</Text>
|
||||
<Box py={20}>
|
||||
<Divider />
|
||||
<Flex justify={"space-between"} py={20}>
|
||||
<Text fz={"sm"}>25 May 2021 . Darmasaba</Text>
|
||||
<Box>
|
||||
<Flex gap={"lg"}>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandFacebook color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandInstagram color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandTwitter color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandWhatsapp color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider pb={50} />
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -1,97 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Container, Text, Image, ActionIcon, Box, Divider, Flex, Group } from '@mantine/core';
|
||||
import { IconBrandFacebook, IconBrandInstagram, IconBrandTwitter, IconBrandWhatsapp } from '@tabler/icons-react';
|
||||
import React from 'react';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.grey[1]} py={"xl"} gap={22}>
|
||||
<Group px={{ base: "md", md: 100 }}>
|
||||
<BackButton />
|
||||
</Group>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"3.4rem"} fw={"bold"}>
|
||||
Juara 2
|
||||
</Text>
|
||||
<Text
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
>
|
||||
Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024
|
||||
</Text>
|
||||
<Image py={20} src={"/api/img/penghargaan-2.png"} alt='' />
|
||||
</Stack>
|
||||
</Container>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Text
|
||||
pb={20}
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
>
|
||||
Desa Dramasaba Raih Juara 2 dalam Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024
|
||||
</Text>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
>
|
||||
Desa Dramasaba kembali menunjukkan eksistensinya dalam memajukan potensi desa dengan meraih Juara 2 dalam ajang Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024. Prestasi ini menjadi bukti nyata bahwa Desa Dramasaba memiliki daya tarik serta peluang investasi yang menjanjikan bagi para investor maupun masyarakat yang ingin berkontribusi dalam pengembangan desa.
|
||||
</Text>
|
||||
<Text
|
||||
py={5}
|
||||
ta={"justify"}
|
||||
>
|
||||
Dalam video pendek yang diikutsertakan dalam lomba ini, Desa Dramasaba menampilkan berbagai potensi unggulan yang dimiliki, mulai dari sektor pertanian, pariwisata berbasis budaya, hingga ekonomi kreatif yang sedang berkembang pesat. Dengan pengemasan yang menarik dan penyampaian informasi yang jelas, video tersebut berhasil memikat perhatian dewan juri serta menjadi inspirasi bagi desa-desa lain dalam mengembangkan potensi wilayahnya masing-masing.
|
||||
</Text>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
>
|
||||
Keberhasilan ini tidak lepas dari kerja keras seluruh tim kreatif, pemerintah desa, serta masyarakat yang turut berpartisipasi dalam produksi video. Kepala Desa Dramasaba, [Nama Kepala Desa], mengungkapkan rasa syukur dan bangganya atas pencapaian ini. Menurutnya, kemenangan ini bukan sekadar penghargaan, tetapi juga menjadi motivasi untuk terus mengembangkan desa agar semakin dikenal luas dan menarik lebih banyak peluang investasi.
|
||||
</Text>
|
||||
<Text
|
||||
py={5}
|
||||
ta={"justify"}
|
||||
>
|
||||
Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024 merupakan ajang yang diadakan oleh pemerintah daerah dengan tujuan untuk mendorong desa-desa dalam mengenalkan dan mempromosikan potensi investasi mereka. Dengan mengikuti lomba ini, Desa Dramasaba tidak hanya memperoleh apresiasi, tetapi juga membuka peluang lebih besar untuk berkolaborasi dengan investor maupun pihak lain yang tertarik dalam pengembangan desa.
|
||||
</Text>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
>
|
||||
Ke depan, Desa Dramasaba berkomitmen untuk terus meningkatkan daya saingnya, baik dalam sektor ekonomi, budaya, maupun infrastruktur, sehingga mampu memberikan manfaat yang lebih besar bagi masyarakat serta menarik perhatian lebih banyak pihak untuk berinvestasi dan berkontribusi dalam pembangunan desa.
|
||||
</Text>
|
||||
<Text
|
||||
py={5}
|
||||
ta={"justify"}
|
||||
>
|
||||
Dengan prestasi ini, diharapkan Desa Dramasaba dapat menjadi contoh bagi desa-desa lain dalam memanfaatkan media digital sebagai sarana promosi dan pengembangan potensi lokal.
|
||||
</Text>
|
||||
<Box py={20}>
|
||||
<Divider />
|
||||
<Flex justify={"space-between"} py={20}>
|
||||
<Text fz={"sm"}>25 May 2021 . Darmasaba</Text>
|
||||
<Box>
|
||||
<Flex gap={"lg"}>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandFacebook color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandInstagram color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandTwitter color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandWhatsapp color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider pb={50} />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
</Stack >
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -1,97 +0,0 @@
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Container, Text, Image, ActionIcon, Box, Divider, Flex } from '@mantine/core';
|
||||
import { IconBrandFacebook, IconBrandInstagram, IconBrandTwitter, IconBrandWhatsapp } from '@tabler/icons-react';
|
||||
import React from 'react';
|
||||
|
||||
function Page() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.grey[1]} py={"xl"} gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"3.4rem"} fw={"bold"}>
|
||||
Juara Favorit
|
||||
</Text>
|
||||
<Text
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
>
|
||||
Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024
|
||||
</Text>
|
||||
<Image py={20} src={"/api/img/penghargaan-1.png"} alt='' />
|
||||
</Stack>
|
||||
</Container>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Text
|
||||
pb={20}
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
>
|
||||
Desa Dramasaba Raih Juara Favorit dalam Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024
|
||||
</Text>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
>
|
||||
Desa Dramasaba kembali menunjukkan eksistensinya dalam memajukan potensi desa dengan meraih Juara 2 dalam ajang Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024. Prestasi ini menjadi bukti nyata bahwa Desa Dramasaba memiliki daya tarik serta peluang investasi yang menjanjikan bagi para investor maupun masyarakat yang ingin berkontribusi dalam pengembangan desa.
|
||||
</Text>
|
||||
<Text
|
||||
py={5}
|
||||
ta={"justify"}
|
||||
>
|
||||
Dalam video pendek yang diikutsertakan dalam lomba ini, Desa Dramasaba menampilkan berbagai potensi unggulan yang dimiliki, mulai dari sektor pertanian, pariwisata berbasis budaya, hingga ekonomi kreatif yang sedang berkembang pesat. Dengan pengemasan yang menarik dan penyampaian informasi yang jelas, video tersebut berhasil memikat perhatian dewan juri serta menjadi inspirasi bagi desa-desa lain dalam mengembangkan potensi wilayahnya masing-masing.
|
||||
</Text>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
>
|
||||
Keberhasilan ini tidak lepas dari kerja keras seluruh tim kreatif, pemerintah desa, serta masyarakat yang turut berpartisipasi dalam produksi video. Kepala Desa Dramasaba, [Nama Kepala Desa], mengungkapkan rasa syukur dan bangganya atas pencapaian ini. Menurutnya, kemenangan ini bukan sekadar penghargaan, tetapi juga menjadi motivasi untuk terus mengembangkan desa agar semakin dikenal luas dan menarik lebih banyak peluang investasi.
|
||||
</Text>
|
||||
<Text
|
||||
py={5}
|
||||
ta={"justify"}
|
||||
>
|
||||
Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024 merupakan ajang yang diadakan oleh pemerintah daerah dengan tujuan untuk mendorong desa-desa dalam mengenalkan dan mempromosikan potensi investasi mereka. Dengan mengikuti lomba ini, Desa Dramasaba tidak hanya memperoleh apresiasi, tetapi juga membuka peluang lebih besar untuk berkolaborasi dengan investor maupun pihak lain yang tertarik dalam pengembangan desa.
|
||||
</Text>
|
||||
<Text
|
||||
ta={"justify"}
|
||||
>
|
||||
Ke depan, Desa Dramasaba berkomitmen untuk terus meningkatkan daya saingnya, baik dalam sektor ekonomi, budaya, maupun infrastruktur, sehingga mampu memberikan manfaat yang lebih besar bagi masyarakat serta menarik perhatian lebih banyak pihak untuk berinvestasi dan berkontribusi dalam pembangunan desa.
|
||||
</Text>
|
||||
<Text
|
||||
py={5}
|
||||
ta={"justify"}
|
||||
>
|
||||
Dengan prestasi ini, diharapkan Desa Dramasaba dapat menjadi contoh bagi desa-desa lain dalam memanfaatkan media digital sebagai sarana promosi dan pengembangan potensi lokal.
|
||||
</Text>
|
||||
|
||||
<Box py={20}>
|
||||
<Divider />
|
||||
<Flex justify={"space-between"} py={20}>
|
||||
<Text fz={"sm"}>25 May 2021 . Darmasaba</Text>
|
||||
<Box>
|
||||
<Flex gap={"lg"}>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandFacebook color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandInstagram color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandTwitter color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandWhatsapp color={"gray"} size={"30"} />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider pb={50} />
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
103
src/app/darmasaba/(tambahan)/penghargaan/[id]/page.tsx
Normal file
103
src/app/darmasaba/(tambahan)/penghargaan/[id]/page.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client'
|
||||
import BackButton from '@/app/darmasaba/(pages)/desa/layanan/_com/BackButto';
|
||||
import colors from '@/con/colors';
|
||||
import { Stack, Container, Text, Image, ActionIcon, Box, Divider, Flex, Center, Skeleton } from '@mantine/core';
|
||||
import { IconBrandFacebook, IconBrandInstagram, IconBrandTwitter, IconBrandWhatsapp } from '@tabler/icons-react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useParams } from 'next/navigation';
|
||||
import { useProxy } from 'valtio/utils';
|
||||
import penghargaanState from '@/app/admin/(dashboard)/_state/desa/penghargaan';
|
||||
import { useState } from 'react';
|
||||
|
||||
function Page() {
|
||||
const params = useParams<{ id: string }>();
|
||||
const id = Array.isArray(params.id) ? params.id[0] : params.id;
|
||||
const state = useProxy(penghargaanState);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
if (!id) return;
|
||||
try {
|
||||
setLoading(true);
|
||||
await state.findUnique.load(id);
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
loadData()
|
||||
}, [id])
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Center>
|
||||
<Skeleton height={500} />
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
if (!state.findUnique.data) {
|
||||
return (
|
||||
<Center>
|
||||
<Text>Data tidak ditemukan</Text>
|
||||
</Center>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors['BG-trans']} py={"xl"} gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
fz={"2.3rem"}
|
||||
>
|
||||
{state.findUnique.data?.name}
|
||||
</Text>
|
||||
<Image py={20} src={state.findUnique.data?.image?.link || ''} alt='' />
|
||||
</Stack>
|
||||
</Container>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<Text
|
||||
pb={20}
|
||||
ta={"center"}
|
||||
fw={"bold"}
|
||||
dangerouslySetInnerHTML={{ __html: state.findUnique.data?.deskripsi || '' }}
|
||||
/>
|
||||
<Box py={20}>
|
||||
<Divider color={colors['blue-button']} />
|
||||
<Flex justify={"space-between"} py={20}>
|
||||
<Text fz={"sm"}>{new Date(state.findUnique.data?.createdAt).toLocaleDateString()}</Text>
|
||||
<Box>
|
||||
<Flex gap={"lg"}>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandFacebook color={colors['blue-button']} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandInstagram color={colors['blue-button']} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandTwitter color={colors['blue-button']} size={"30"} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant='transparent'>
|
||||
<IconBrandWhatsapp color={colors['blue-button']} size={"30"} />
|
||||
</ActionIcon>
|
||||
</Flex>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Divider color={colors['blue-button']} pb={50} />
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
@@ -1,63 +1,21 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client';
|
||||
import penghargaanState from "@/app/admin/(dashboard)/_state/desa/penghargaan";
|
||||
import colors from "@/con/colors";
|
||||
import { Carousel, CarouselSlide } from "@mantine/carousel";
|
||||
import { Box, Button, Container, Group, Paper, Stack, Text, useMantineTheme } from "@mantine/core";
|
||||
import { useMediaQuery } from "@mantine/hooks";
|
||||
import Autoplay from "embla-carousel-autoplay";
|
||||
import Link from "next/link";
|
||||
import { useRef } from "react";
|
||||
import { useTransitionRouter } from "next-view-transitions";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useProxy } from "valtio/utils";
|
||||
import BackButton from "../../(pages)/desa/layanan/_com/BackButto";
|
||||
|
||||
|
||||
const data = [
|
||||
{
|
||||
id: 1,
|
||||
images: "/api/img/penghargaan-2.png",
|
||||
juara: "Juara 2",
|
||||
deskripsi: "Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024",
|
||||
link: "/darmasaba/penghargaan/juara-2-lomba-video-pendek-potensi-dan-peluang-investasi-di-desa-kabupaten-badung-2024"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
images: "/api/img/penghargaan-3.png",
|
||||
juara: "Juara 2",
|
||||
deskripsi: "Duta Invenstasi Kabupaten Badung 2024",
|
||||
link: "/darmasaba/penghargaan/juara-2-duta-invenstasi-kabupaten-badung-2024"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
images: "/api/img/penghargaan-1.png",
|
||||
juara: "Juara Favorit",
|
||||
deskripsi: "Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024",
|
||||
link: "/darmasaba/penghargaan/juara-favorit-lomba-video-pendek-potensi-dan-peluang-investasi-di-desa-kabupaten-badung-2024"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
images: "/api/img/penghargaan-2.png",
|
||||
juara: "Juara 2",
|
||||
deskripsi: "Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024",
|
||||
link: "/darmasaba/penghargaan/juara-2-lomba-video-pendek-potensi-dan-peluang-investasi-di-desa-kabupaten-badung-2024"
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
images: "/api/img/penghargaan-3.png",
|
||||
juara: "Juara 2",
|
||||
deskripsi: "Duta Invenstasi Kabupaten Badung 2024",
|
||||
link: "/darmasaba/penghargaan/juara-2-duta-invenstasi-kabupaten-badung-2024"
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
images: "/api/img/penghargaan-1.png",
|
||||
juara: "Juara Favorit",
|
||||
deskripsi: "Lomba Video Pendek Potensi dan Peluang Investasi di Desa Kabupaten Badung 2024",
|
||||
link: "/darmasaba/penghargaan/juara-favorit-lomba-video-pendek-potensi-dan-peluang-investasi-di-desa-kabupaten-badung-2024"
|
||||
}
|
||||
]
|
||||
export default function Page() {
|
||||
return (
|
||||
<Stack pos={"relative"} bg={colors.grey[1]} py={"xl"} gap={22}>
|
||||
<Box px={{ base: "md", md: 100 }}>
|
||||
<BackButton />
|
||||
<BackButton />
|
||||
</Box>
|
||||
<Container w={{ base: "100%", md: "50%" }}>
|
||||
<Stack align="center" gap={0}>
|
||||
@@ -82,12 +40,27 @@ function Slider() {
|
||||
const theme = useMantineTheme();
|
||||
const mobile = useMediaQuery(`(max-width: ${theme.breakpoints.sm})`);
|
||||
const autoplay = useRef(Autoplay({ delay: 2000 }));
|
||||
const state = useProxy(penghargaanState);
|
||||
const roter = useTransitionRouter()
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
await state.findMany.load();
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error);
|
||||
}
|
||||
}
|
||||
loadData();
|
||||
}, [])
|
||||
|
||||
const data = state.findMany.data || [];
|
||||
|
||||
const slides = data.map((item) => (
|
||||
|
||||
<CarouselSlide key={item.id}>
|
||||
<Paper h={"100%"} pos={"relative"} style={{
|
||||
backgroundImage: `url(${item.images}) `,
|
||||
backgroundImage: `url(${item.image?.link}) `,
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
@@ -104,11 +77,10 @@ function Slider() {
|
||||
/>
|
||||
<Stack justify="space-between" h={"100%"} gap={0} p={"lg"} pos={"relative"} >
|
||||
<Box p={"lg"}>
|
||||
<Text fz={"2.3rem"} fw={"bold"} ta={"center"} c={"white"}>{item.juara}</Text>
|
||||
<Text fz={"1.5rem"} ta={"center"} c={"white"}>{item.deskripsi}</Text>
|
||||
<Text fz={"1.5rem"} ta={"center"} c={"white"}>{item.name}</Text>
|
||||
</Box>
|
||||
<Group justify="center">
|
||||
<Button component={Link} href={item.link} px={46} radius={"100"} size="md" bg={colors["blue-button"]}>
|
||||
<Group justify="center" >
|
||||
<Button onClick={() => roter.push(`/darmasaba/penghargaan/${item.id}`)} px={46} radius={"100"} size="md" bg={colors["blue-button"]}>
|
||||
Detail
|
||||
</Button>
|
||||
</Group>
|
||||
@@ -125,7 +97,7 @@ function Slider() {
|
||||
plugins={[autoplay.current]}
|
||||
onMouseEnter={autoplay.current.stop}
|
||||
onMouseLeave={autoplay.current.reset}
|
||||
w={{base: 500, md: 800, lg: 900 , xl: width}}
|
||||
w={{ base: 500, md: 800, lg: 900, xl: width }}
|
||||
height={height}
|
||||
slideSize={{ base: "100%", sm: "50%", md: "33.333333%" }}
|
||||
slideGap={{ base: "xl", sm: "md" }}
|
||||
|
||||
@@ -1,10 +1,32 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
'use client';
|
||||
import penghargaanState from "@/app/admin/(dashboard)/_state/desa/penghargaan";
|
||||
import colors from "@/con/colors";
|
||||
import { Stack, Box, Container, Button, Text } from "@mantine/core";
|
||||
import { useTransitionRouter } from 'next-view-transitions'
|
||||
import { useEffect, useState } from "react";
|
||||
import { useProxy } from "valtio/utils";
|
||||
|
||||
function Penghargaan() {
|
||||
const router = useTransitionRouter()
|
||||
const state = useProxy(penghargaanState)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
await state.findMany.load()
|
||||
} catch (error) {
|
||||
console.error('Error loading data:', error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
loadData()
|
||||
}, [])
|
||||
|
||||
const data = state.findMany.data?.slice(0, 3)
|
||||
return (
|
||||
<Stack pos={"relative"} h={720}>
|
||||
<video
|
||||
@@ -44,17 +66,30 @@ function Penghargaan() {
|
||||
>
|
||||
Penghargaan
|
||||
</Text>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"1.4rem"} c={"white"}>
|
||||
Juara 2 Lomba Video Pendek
|
||||
{loading ? (
|
||||
<Text
|
||||
style={{
|
||||
textAlign: "center",
|
||||
}}
|
||||
fw={"bold"}
|
||||
fz={"2.4rem"}
|
||||
c={"white"}
|
||||
>
|
||||
Memuat Data...
|
||||
</Text>
|
||||
<Text fz={"1.4rem"} c={"white"}>
|
||||
Juara 2 Duta Investasi
|
||||
</Text>
|
||||
<Text fz={"1.2rem"} c={"white"}>
|
||||
Juara Favorit Lomba Video Pendek
|
||||
</Text>
|
||||
</Stack>
|
||||
) : (
|
||||
data?.map((v, k) => {
|
||||
return (
|
||||
<Box key={k}>
|
||||
<Stack align="center" gap={0}>
|
||||
<Text fz={"1.4rem"} c={"white"}>
|
||||
{v.name}
|
||||
</Text>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
})
|
||||
)}
|
||||
<Button color={colors["blue-button"]} onClick={() => router.push("/darmasaba/penghargaan")} variant="white" radius={100}>
|
||||
Selanjutnya
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user