Jum'at, 30 May 2025 :

Yang Sudah Di Kerjakan
* Tampilan UI Admin di menu inovasi
* API Create, edit dan delete potensi
* Tampilan UI Landing Page sudah sesuai di mobile

Yang Lagi Dikerjakan:
* Progress Tampilan UI Admin Di Menu lingkungan
* Progress API Create, edit dan delete potensi

Yang Akan Dikerjakan:
* API Create, edit dan delete pengumuman
* Tampilan UI Admin Di Menu Pendidikan
This commit is contained in:
2025-05-30 21:13:55 +08:00
parent 77f99a7c8f
commit 8f2b9665a9
12 changed files with 110 additions and 136 deletions

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
"use client"; "use client";
import { import {
@@ -15,19 +14,19 @@ import {
Title, Title,
} from "@mantine/core"; } from "@mantine/core";
import { IconArrowBack, IconImageInPicture } from "@tabler/icons-react"; import { IconArrowBack, IconImageInPicture } from "@tabler/icons-react";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { useProxy } from "valtio/utils";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import { useProxy } from "valtio/utils";
import EditEditor from "@/app/admin/(dashboard)/_com/editEditor";
import colors from "@/con/colors";
import ApiFetch from "@/lib/api-fetch"; import ApiFetch from "@/lib/api-fetch";
import { FileInput } from "@mantine/core"; import { FileInput } from "@mantine/core";
import stateDashboardBerita from "../../../../_state/desa/berita";
import { Prisma } from "@prisma/client";
import { useShallowEffect } from "@mantine/hooks"; import { useShallowEffect } from "@mantine/hooks";
import { BeritaEditor } from "../../_com/BeritaEditor"; import { Prisma } from "@prisma/client";
import colors from "@/con/colors"; import stateDashboardBerita from "../../../../_state/desa/berita";
function EditBerita() { function EditBerita() {
const beritaState = useProxy(stateDashboardBerita); const beritaState = useProxy(stateDashboardBerita);
@@ -36,8 +35,6 @@ function EditBerita() {
const [previewImage, setPreviewImage] = useState<string | null>(null); const [previewImage, setPreviewImage] = useState<string | null>(null);
const [file, setFile] = useState<File | null>(null); const [file, setFile] = useState<File | null>(null);
const [editorInstance, setEditorInstance] = useState<any>(null);
const [isEditorReady, setIsEditorReady] = useState(false);
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
judul: beritaState.berita.edit.form.judul || '', judul: beritaState.berita.edit.form.judul || '',
deskripsi: beritaState.berita.edit.form.deskripsi || '', deskripsi: beritaState.berita.edit.form.deskripsi || '',
@@ -76,28 +73,7 @@ function EditBerita() {
loadBerita(); loadBerita();
}, [params?.id]); // ✅ hapus beritaState dari dependency }, [params?.id]); // ✅ hapus beritaState dari dependency
// Handle editor ready
const handleEditorReady = (editor: any) => {
setEditorInstance(editor);
setIsEditorReady(true);
// Set initial content if exists
if (formData.content) {
editor.commands.setContent(formData.content);
}
};
const handleSubmit = async () => { const handleSubmit = async () => {
if (!isEditorReady || !editorInstance) {
return toast.error("Editor belum siap");
}
const htmlContent = editorInstance.getHTML();
if (!htmlContent || htmlContent === "<p></p>") {
return toast.warn("Konten tidak boleh kosong");
}
try { try {
// Update global state with form data // Update global state with form data
@@ -105,7 +81,7 @@ function EditBerita() {
...beritaState.berita.edit.form, ...beritaState.berita.edit.form,
judul: formData.judul, judul: formData.judul,
deskripsi: formData.deskripsi, deskripsi: formData.deskripsi,
content: htmlContent, content: formData.content,
kategoriBeritaId: formData.kategoriBeritaId || '', kategoriBeritaId: formData.kategoriBeritaId || '',
imageId: formData.imageId // Keep existing imageId if not changed imageId: formData.imageId // Keep existing imageId if not changed
}; };
@@ -189,14 +165,12 @@ function EditBerita() {
<Box> <Box>
<Text fz={"sm"} fw={"bold"}>Konten</Text> <Text fz={"sm"} fw={"bold"}>Konten</Text>
<BeritaEditor <EditEditor
initialContent={formData.content} value={formData.content}
onEditorReady={handleEditorReady} onChange={(htmlContent) => {
showSubmit={false} setFormData((prev) => ({ ...prev, content: htmlContent }));
onUpdate={(content) => { beritaState.berita.edit.form.content = htmlContent;
setFormData((prev) => ({ ...prev, content })); }}
beritaState.berita.edit.form.content = content;
}}
/> />
</Box> </Box>

View File

@@ -8,8 +8,8 @@ import { useParams, useRouter } from 'next/navigation';
import { useState } from 'react'; import { useState } from 'react';
import colors from '@/con/colors'; import colors from '@/con/colors';
import { ModalKonfirmasiHapus } from '../../../../_com/modalKonfirmasiHapus'; import { ModalKonfirmasiHapus } from '../../../_com/modalKonfirmasiHapus';
import stateDashboardBerita from '../../../../_state/desa/berita'; import stateDashboardBerita from '../../../_state/desa/berita';
function DetailBerita() { function DetailBerita() {
const beritaState = useProxy(stateDashboardBerita) const beritaState = useProxy(stateDashboardBerita)
@@ -45,52 +45,64 @@ function DetailBerita() {
return ( return (
<Box> <Box>
<Box mb={10}> <Box mb={10}>
<Button variant="subtle" onClick={() => router.back()}> <Button variant="subtle" onClick={() => router.back()}>
<IconArrowBack color={colors['blue-button']} size={25} /> <IconArrowBack color={colors['blue-button']} size={25} />
</Button> </Button>
</Box> </Box>
<Paper bg={colors['white-1']} w={{ base: "100%", md: "100%", lg: "50%" }} p={'md'}> <Paper bg={colors['white-1']} w={{ base: "100%", md: "100%", lg: "50%" }} p={'md'}>
<Stack> <Stack>
<Text fz={"xl"} fw={"bold"}>Detail Berita</Text> <Text fz={"xl"} fw={"bold"}>Detail Berita</Text>
{beritaState.berita.findUnique.data ? ( {beritaState.berita.findUnique.data ? (
<Paper key={beritaState.berita.findUnique.data.id} bg={colors['BG-trans']} p={'md'}> <Paper key={beritaState.berita.findUnique.data.id} bg={colors['BG-trans']} p={'md'}>
<Stack gap={"xs"}>
<Box> <Box>
<Text fw={"bold"} fz={"lg"}>Kategori</Text> <Text fw={"bold"} fz={"lg"}>Kategori</Text>
<Text fz={"lg"}>{beritaState.berita.findUnique.data?.kategoriBerita?.name}</Text> <Text fz={"lg"}>{beritaState.berita.findUnique.data?.kategoriBerita?.name}</Text>
</Box>
<Box>
<Text fw={"bold"} fz={"lg"}>Judul</Text> <Text fw={"bold"} fz={"lg"}>Judul</Text>
<Text fz={"lg"}>{beritaState.berita.findUnique.data?.judul}</Text> <Text fz={"lg"}>{beritaState.berita.findUnique.data?.judul}</Text>
</Box>
<Box>
<Text fw={"bold"} fz={"lg"}>Deskripsi</Text> <Text fw={"bold"} fz={"lg"}>Deskripsi</Text>
<Text fz={"lg"} >{beritaState.berita.findUnique.data?.deskripsi}</Text> <Text fz={"lg"} >{beritaState.berita.findUnique.data?.deskripsi}</Text>
</Box>
<Box>
<Text fw={"bold"} fz={"lg"}>Gambar</Text> <Text fw={"bold"} fz={"lg"}>Gambar</Text>
<Image w={{ base: 150, md: 150, lg: 150 }} src={beritaState.berita.findUnique.data?.image?.link} alt="gambar" /> <Image w={{ base: 150, md: 150, lg: 150 }} src={beritaState.berita.findUnique.data?.image?.link} alt="gambar" />
<Flex gap={"xs"} mt={10}>
<Button
onClick={() => {
if (beritaState.berita.findUnique.data) {
setSelectedId(beritaState.berita.findUnique.data.id);
setModalHapus(true);
}
}}
disabled={beritaState.berita.delete.loading || !beritaState.berita.findUnique.data}
color={"red"}
>
<IconX size={20} />
</Button>
<Button
onClick={() => {
if (beritaState.berita.findUnique.data) {
router.push(`/admin/desa/berita/edit/${beritaState.berita.findUnique.data.id}`);
}
}}
disabled={!beritaState.berita.findUnique.data}
color={"green"}
>
<IconEdit size={20} />
</Button>
</Flex>
</Box> </Box>
</Paper> <Box>
) : null} <Text fw={"bold"} fz={"lg"}>Konten</Text>
<Text fz={"lg"} dangerouslySetInnerHTML={{ __html: beritaState.berita.findUnique.data?.content }} />
</Box>
<Flex gap={"xs"} mt={10}>
<Button
onClick={() => {
if (beritaState.berita.findUnique.data) {
setSelectedId(beritaState.berita.findUnique.data.id);
setModalHapus(true);
}
}}
disabled={beritaState.berita.delete.loading || !beritaState.berita.findUnique.data}
color={"red"}
>
<IconX size={20} />
</Button>
<Button
onClick={() => {
if (beritaState.berita.findUnique.data) {
router.push(`/admin/desa/berita/${beritaState.berita.findUnique.data.id}/edit`);
}
}}
disabled={!beritaState.berita.findUnique.data}
color={"green"}
>
<IconEdit size={20} />
</Button>
</Flex>
</Stack>
</Paper>
) : null}
</Stack> </Stack>
</Paper> </Paper>

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
'use client' 'use client'
import colors from '@/con/colors'; import colors from '@/con/colors';
import ApiFetch from '@/lib/api-fetch'; import ApiFetch from '@/lib/api-fetch';
@@ -10,14 +9,13 @@ import { useRouter } from 'next/navigation';
import { useState } from 'react'; import { useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { useProxy } from 'valtio/utils'; import { useProxy } from 'valtio/utils';
import CreateEditor from '../../../_com/createEditor';
import stateDashboardBerita from '../../../_state/desa/berita'; import stateDashboardBerita from '../../../_state/desa/berita';
import { BeritaEditor } from '../_com/BeritaEditor';
export default function CreateBerita() { export default function CreateBerita() {
const beritaState = useProxy(stateDashboardBerita); const beritaState = useProxy(stateDashboardBerita);
const [previewImage, setPreviewImage] = useState<string | null>(null); const [previewImage, setPreviewImage] = useState<string | null>(null);
const [file, setFile] = useState<File | null>(null); const [file, setFile] = useState<File | null>(null);
const [editorInstance, setEditorInstance] = useState<any>(null);
const router = useRouter() const router = useRouter()
const resetForm = () => { const resetForm = () => {
@@ -33,21 +31,12 @@ export default function CreateBerita() {
// Reset state lokal // Reset state lokal
setPreviewImage(null); setPreviewImage(null);
setFile(null); setFile(null);
if (editorInstance) {
editorInstance.commands.setContent(""); // Kosongkan editor
}
}; };
const handleSubmit = async () => { const handleSubmit = async () => {
if (!file) { if (!file) {
return toast.warn("Pilih file gambar terlebih dahulu"); return toast.warn("Pilih file gambar terlebih dahulu");
} }
if (!editorInstance) return toast.error("Editor belum siap");
const htmlContent = editorInstance.getHTML();
if (!htmlContent || htmlContent === "<p></p>") return toast.warn("Konten tidak boleh kosong");
beritaState.berita.create.form.content = htmlContent;
// Upload gambar dulu // Upload gambar dulu
const res = await ApiFetch.api.fileStorage.create.post({ const res = await ApiFetch.api.fileStorage.create.post({
@@ -124,9 +113,11 @@ export default function CreateBerita() {
)} )}
<Box> <Box>
<Text fz={"sm"} fw={"bold"}>Konten</Text> <Text fz={"sm"} fw={"bold"}>Konten</Text>
<BeritaEditor <CreateEditor
showSubmit={false} value={beritaState.berita.create.form.content}
onEditorReady={(ed) => setEditorInstance(ed)} onChange={(htmlContent) => {
beritaState.berita.create.form.content = htmlContent;
}}
/> />
</Box> </Box>
<Button bg={colors['blue-button']} onClick={handleSubmit}>Simpan Berita</Button> <Button bg={colors['blue-button']} onClick={handleSubmit}>Simpan Berita</Button>

View File

@@ -163,7 +163,7 @@ function BeritaList() {
<Image w={100} src={item.image?.link} alt="gambar" /> <Image w={100} src={item.image?.link} alt="gambar" />
</TableTd> </TableTd>
<TableTd> <TableTd>
<Button bg={"green"} onClick={() => router.push(`/admin/desa/berita/detail/${item.id}`)}> <Button bg={"green"} onClick={() => router.push(`/admin/desa/berita/${item.id}`)}>
<IconDeviceImacCog size={25} /> <IconDeviceImacCog size={25} />
</Button> </Button>
</TableTd> </TableTd>

View File

@@ -13,9 +13,6 @@ type FormCreate = Prisma.BeritaGetPayload<{
}>; }>;
async function beritaCreate(context: Context) { async function beritaCreate(context: Context) {
const body = context.body as FormCreate; const body = context.body as FormCreate;
console.log(body)
// console.log(body)
await prisma.berita.create({ await prisma.berita.create({
data: { data: {

View File

@@ -40,26 +40,20 @@ export default async function handler(
} }
// Ensure we're returning a proper Response object // Ensure we're returning a proper Response object
return new Response(JSON.stringify({ return Response.json({
success: true, success: true,
message: "Success fetch berita by ID", message: "Success fetch berita by ID",
data, data,
}), { }, {
status: 200, status: 200,
headers: {
'Content-Type': 'application/json',
},
}); });
} catch (e) { } catch (e) {
console.error("Find by ID error:", e); console.error("Find by ID error:", e);
return new Response(JSON.stringify({ return Response.json({
success: false, success: false,
message: "Gagal mengambil berita: " + (e instanceof Error ? e.message : 'Unknown error'), message: "Gagal mengambil berita: " + (e instanceof Error ? e.message : 'Unknown error'),
}), { }, {
status: 500, status: 500,
headers: {
'Content-Type': 'application/json',
},
}); });
} }
} }

View File

@@ -85,7 +85,7 @@ async function beritaUpdate(context: Context) {
{ status: 200, headers: { 'Content-Type': 'application/json' } } { status: 200, headers: { 'Content-Type': 'application/json' } }
); );
} catch (error) { } catch (error) {
console.error("Error updating berita:", error); console.error("Error updating berita:", error);
return new Response( return new Response(
JSON.stringify({ JSON.stringify({
success: false, success: false,

View File

@@ -10,7 +10,7 @@ function Footer() {
return ( return (
<> <>
<Stack bg={colors["blue-button"]}> <Stack bg={colors["blue-button"]}>
<Box w={mobile ? "100%" : "100%"} p={"xl"} h={{ base: 1850, md: 1100 }} > <Box w={mobile ? "100%" : "100%"} p={"xl"} h={{ base: 2500, md: 1100 }} >
<Center> <Center>
<Paper w={"100%"}> <Paper w={"100%"}>
<Box component="footer" py="xl"> <Box component="footer" py="xl">

View File

@@ -44,9 +44,9 @@ function DesaAntiKorupsi() {
<Stack gap={"0"} bg={colors.Bg} p={"sm"} h={mobile ? 2000 : 1150}> <Stack gap={"0"} bg={colors.Bg} p={"sm"} h={mobile ? 2000 : 1150}>
<Container w={{ base: "100%", md: "80%" }} p={"xl"} > <Container w={{ base: "100%", md: "80%" }} p={"xl"} >
<Center> <Center>
<Text fz={"3.4rem"}>Desa Anti Korupsi</Text> <Text fz={{base: "2.4rem", md: "3.4rem"}}>Desa Anti Korupsi</Text>
</Center> </Center>
<Text ta={"center"} fz={"1.4rem"}>Desa antikorupsi mendorong pemerintahan jujur dan transparan. Keuangan desa dikelola terbuka dengan melibatkan warga mengawasi anggaran, sehingga digunakan tepat sasaran sesuai kebutuhan.</Text> <Text ta={"center"} fz={{base: "1.2rem", md: "1.4rem"}}>Desa antikorupsi mendorong pemerintahan jujur dan transparan. Keuangan desa dikelola terbuka dengan melibatkan warga mengawasi anggaran, sehingga digunakan tepat sasaran sesuai kebutuhan.</Text>
<Center py={20}> <Center py={20}>
<Button radius={"lg"} fz={"h4"} bg={colors["blue-button"]} component={Link} href={"/darmasaba/desaantikorupsi"}>Selengkapnya</Button> <Button radius={"lg"} fz={"h4"} bg={colors["blue-button"]} component={Link} href={"/darmasaba/desaantikorupsi"}>Selengkapnya</Button>
</Center> </Center>
@@ -65,13 +65,13 @@ function DesaAntiKorupsi() {
<Paper p={"lg"} > <Paper p={"lg"} >
<Flex gap={"lg"} justify={"center"} align={"center"}> <Flex gap={"lg"} justify={"center"} align={"center"}>
<Box > <Box >
<Text fz={"lg"} ta={"center"} c={colors["blue-button"]}>{v.judul}</Text> <Text fz={{base: "1.2rem", md: "lg"}} ta={"center"} c={colors["blue-button"]}>{v.judul}</Text>
<Flex justify={"center"} align={"center"}> <Flex justify={"center"} align={"center"}>
<Box> <Box>
{v.icon} {v.icon}
</Box> </Box>
<Box px={20}> <Box px={20}>
<Text fz={"sm"} ta={"justify"}>{v.deskripsi}</Text> <Text fz={"sm"} ta={{base: "left", md: "justify"}}>{v.deskripsi}</Text>
</Box> </Box>
</Flex> </Flex>
</Box> </Box>

View File

@@ -1,7 +1,8 @@
"use client"; "use client";
import { Stack, Container, Center, Text, Paper, Flex, Box, SimpleGrid } from "@mantine/core";
import { BarChart, PieChart } from '@mantine/charts';
import colors from "@/con/colors"; import colors from "@/con/colors";
import { BarChart, PieChart } from '@mantine/charts';
import { Box, Center, Container, Flex, Paper, SimpleGrid, Stack, Text } from "@mantine/core";
import { useMediaQuery } from "@mantine/hooks";
const dataBarChart = [ const dataBarChart = [
{ {
@@ -71,13 +72,14 @@ const dataPieChart3 = [
] ]
function Kepuasan() { function Kepuasan() {
const isMobile = useMediaQuery('(max-width: 768px)');
return ( return (
<Stack p={"sm"}> <Stack p={"sm"}>
<Container w={{ base: "100%", md: "80%" }} p={"xl"}> <Container w={{ base: "100%", md: "80%" }} p={"xl"}>
<Center> <Center>
<Text fz={"3.4rem"}>Indeks Kepuasan Masyarakat</Text> <Text ta={"center"} fz={{base: "2.4rem", md: "3.4rem"}}>Indeks Kepuasan Masyarakat</Text>
</Center> </Center>
<Text fz={"1.4rem"} ta={"center"}>Ukur kebahagiaan warga, tingkatkan layanan desa! Dengan partisipasi aktif masyarakat, kami berkomitmen untuk terus memperbaiki layanan agar lebih transparan, efektif, dan sesuai dengan kebutuhan warga. Kepuasan Anda adalah prioritas utama kami dalam membangun desa yang lebih baik!</Text> <Text fz={{base: "1.2rem", md: "1.4rem"}} ta={"center"}>Ukur kebahagiaan warga, tingkatkan layanan desa! Dengan partisipasi aktif masyarakat, kami berkomitmen untuk terus memperbaiki layanan agar lebih transparan, efektif, dan sesuai dengan kebutuhan warga. Kepuasan Anda adalah prioritas utama kami dalam membangun desa yang lebih baik!</Text>
</Container> </Container>
<Box px={"xl"}> <Box px={"xl"}>
<Paper p={"lg"} bg={colors.Bg}> <Paper p={"lg"} bg={colors.Bg}>
@@ -118,7 +120,7 @@ function Kepuasan() {
<Text fw={"bold"}>Jenis Kelamin</Text> <Text fw={"bold"}>Jenis Kelamin</Text>
<Box py={"xl"}> <Box py={"xl"}>
<PieChart <PieChart
size={250} size={isMobile ? 100 : 220}
withLabelsLine withLabelsLine
labelsPosition="outside" labelsPosition="outside"
labelsType="percent" labelsType="percent"
@@ -135,7 +137,7 @@ function Kepuasan() {
<Text fw={"bold"}>Pilihan</Text> <Text fw={"bold"}>Pilihan</Text>
<Box py={"xl"}> <Box py={"xl"}>
<PieChart <PieChart
size={250} size={isMobile ? 100 : 220}
withLabelsLine withLabelsLine
labelsPosition="outside" labelsPosition="outside"
labelsType="percent" labelsType="percent"
@@ -152,7 +154,7 @@ function Kepuasan() {
<Text fw={"bold"}>Umur</Text> <Text fw={"bold"}>Umur</Text>
<Box py={"xl"}> <Box py={"xl"}>
<PieChart <PieChart
size={250} size={isMobile ? 100 : 220}
withLabelsLine withLabelsLine
labelsPosition="outside" labelsPosition="outside"
labelsType="percent" labelsType="percent"

View File

@@ -5,9 +5,9 @@ import {
Card, Card,
Flex, Flex,
Grid, Grid,
GridCol,
Image, Image,
Paper, Paper,
SimpleGrid,
Stack, Stack,
Text Text
} from "@mantine/core"; } from "@mantine/core";
@@ -58,10 +58,9 @@ function LandingPage() {
<Grid <Grid
> >
<Grid.Col span={{ <Grid.Col span={{
base: 2, base: 3,
sm: 3, lg: 2,
md: 3, md: 3,
xl: 2
}}> }}>
<Box <Box
pos={"relative"} pos={"relative"}
@@ -88,10 +87,9 @@ function LandingPage() {
</Grid.Col> </Grid.Col>
<Grid.Col span={{ <Grid.Col span={{
base: 2, base: 6,
sm: 3, lg: 2,
md: 3, md: 3,
xl: 2
}}> }}>
<Box <Box
pos={"relative"} pos={"relative"}
@@ -118,10 +116,9 @@ function LandingPage() {
</Box> </Box>
</Grid.Col> </Grid.Col>
<Grid.Col span={{ <Grid.Col span={{
base: 8, base: 12,
sm: 12, lg: 8,
md: 12, md: 12,
xl: 8
}}> }}>
<Paper <Paper
pos={"relative"} pos={"relative"}
@@ -130,15 +127,14 @@ function LandingPage() {
w={{ base: "100%", sm: "auto", md: "auto" }} w={{ base: "100%", sm: "auto", md: "auto" }}
flex={{ base: "1", sm: "1", md: "1" }} flex={{ base: "1", sm: "1", md: "1" }}
> >
<SimpleGrid <Grid
cols={{
base: 2,
sm: 1,
md: 2,
}}
spacing={{ base: "xs", md: "md" }}
> >
<Box> <GridCol span={{
base: 12,
lg: 6,
md: 6,
}}>
<Box>
<Text c={colors["white-1"]} fz={"sm"}> <Text c={colors["white-1"]} fz={"sm"}>
Jadwal Kerja Jadwal Kerja
</Text> </Text>
@@ -168,7 +164,14 @@ function LandingPage() {
</Flex> </Flex>
</Paper> </Paper>
</Box> </Box>
<Box> </GridCol>
<GridCol span={{
base: 12,
lg: 6,
md: 6,
}}>
<Box>
<Text c={colors["white-1"]} fz={"sm"}> <Text c={colors["white-1"]} fz={"sm"}>
Rabu, 10 Maret 2025 Rabu, 10 Maret 2025
</Text> </Text>
@@ -187,7 +190,8 @@ function LandingPage() {
</Box> </Box>
</Paper> </Paper>
</Box> </Box>
</SimpleGrid> </GridCol>
</Grid>
</Paper> </Paper>
</Grid.Col> </Grid.Col>

View File

@@ -51,7 +51,7 @@ function Penghargaan() {
<Text fz={"1.4rem"} c={"white"}> <Text fz={"1.4rem"} c={"white"}>
Juara 2 Duta Investasi Juara 2 Duta Investasi
</Text> </Text>
<Text fz={"1.4rem"} c={"white"}> <Text fz={"1.2rem"} c={"white"}>
Juara Favorit Lomba Video Pendek Juara Favorit Lomba Video Pendek
</Text> </Text>
</Stack> </Stack>