merge: feat(beasiswa) dynamic stats penerima & dana tersalurkan + formatDana
This commit is contained in:
@@ -7,7 +7,12 @@ async function beasiswaConfigFindUnique() {
|
|||||||
orderBy: { createdAt: 'desc' },
|
orderBy: { createdAt: 'desc' },
|
||||||
});
|
});
|
||||||
|
|
||||||
return { success: true, data };
|
return {
|
||||||
|
success: true,
|
||||||
|
data: data
|
||||||
|
? { ...data, danaTersalurkan: data.danaTersalurkan.toString() }
|
||||||
|
: null,
|
||||||
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error di beasiswaConfigFindUnique:", e);
|
console.error("Error di beasiswaConfigFindUnique:", e);
|
||||||
return { success: false, message: "Gagal mengambil konfigurasi beasiswa" };
|
return { success: false, message: "Gagal mengambil konfigurasi beasiswa" };
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import beasiswaDesaState from '@/app/admin/(dashboard)/_state/pendidikan/beasiswa-desa';
|
import beasiswaDesaState from '@/app/admin/(dashboard)/_state/pendidikan/beasiswa-desa';
|
||||||
|
import ringkasanBeasiswaState from '@/app/admin/(dashboard)/_state/pendidikan/ringkasan-beasiswa';
|
||||||
import colors from '@/con/colors';
|
import colors from '@/con/colors';
|
||||||
import { Box, Button, Center, Divider, Group, Image, Modal, Pagination, Paper, Select, SimpleGrid, Skeleton, Stack, Stepper, Text, TextInput, Title } from '@mantine/core';
|
import { Box, Button, Center, Divider, Group, Image, Modal, Pagination, Paper, Select, SimpleGrid, Skeleton, Stack, Stepper, Text, TextInput, Title } from '@mantine/core';
|
||||||
import { useDisclosure, useShallowEffect } from '@mantine/hooks';
|
import { useDisclosure, useShallowEffect } from '@mantine/hooks';
|
||||||
@@ -9,15 +10,20 @@ import { useState } from 'react';
|
|||||||
import { useProxy } from 'valtio/utils';
|
import { useProxy } from 'valtio/utils';
|
||||||
import BackButton from '../../desa/layanan/_com/BackButto';
|
import BackButton from '../../desa/layanan/_com/BackButto';
|
||||||
|
|
||||||
const dataBeasiswa = [
|
function formatDana(value: string | number): string {
|
||||||
{ id: 1, nama: 'Penerima Beasiswa', jumlah: '250+', icon: IconUsers },
|
const num = typeof value === 'string' ? parseFloat(value.replace(/[^0-9.-]/g, '')) : value;
|
||||||
{ id: 2, nama: 'Peluang Kelulusan', jumlah: '90%', icon: IconSchool },
|
if (isNaN(num)) return String(value);
|
||||||
{ id: 3, nama: 'Dana Tersalurkan', jumlah: '1.5M', icon: IconCoin },
|
if (num >= 1_000_000_000_000) return `${(num / 1_000_000_000_000).toFixed(num % 1_000_000_000_000 === 0 ? 0 : 1)}T`;
|
||||||
];
|
if (num >= 1_000_000_000) return `${(num / 1_000_000_000).toFixed(num % 1_000_000_000 === 0 ? 0 : 1)}M`;
|
||||||
|
if (num >= 1_000_000) return `${(num / 1_000_000).toFixed(num % 1_000_000 === 0 ? 0 : 1)}Jt`;
|
||||||
|
if (num >= 1_000) return `${(num / 1_000).toFixed(num % 1_000 === 0 ? 0 : 1)}Rb`;
|
||||||
|
return String(num);
|
||||||
|
}
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
const beasiswaDesa = useProxy(beasiswaDesaState.beasiswaPendaftar)
|
const beasiswaDesa = useProxy(beasiswaDesaState.beasiswaPendaftar)
|
||||||
const ungggulanDesa = useProxy(beasiswaDesaState.keunggulanProgram)
|
const ungggulanDesa = useProxy(beasiswaDesaState.keunggulanProgram)
|
||||||
|
const statsBeasiswa = useProxy(ringkasanBeasiswaState.findStats)
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
const router = useTransitionRouter()
|
const router = useTransitionRouter()
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
@@ -61,6 +67,16 @@ function Page() {
|
|||||||
load(page, 3, "");
|
load(page, 3, "");
|
||||||
}, [page])
|
}, [page])
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
statsBeasiswa.load();
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const dataBeasiswa = [
|
||||||
|
{ id: 1, nama: 'Penerima Beasiswa', jumlah: statsBeasiswa.data?.jumlahPenerima?.toString() ?? '-', icon: IconUsers },
|
||||||
|
{ id: 2, nama: 'Peluang Kelulusan', jumlah: '90%', icon: IconSchool },
|
||||||
|
{ id: 3, nama: 'Dana Tersalurkan', jumlah: statsBeasiswa.data?.danaTersalurkan ? formatDana(statsBeasiswa.data.danaTersalurkan) : '-', icon: IconCoin },
|
||||||
|
];
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
await beasiswaDesa.create.create();
|
await beasiswaDesa.create.create();
|
||||||
resetForm();
|
resetForm();
|
||||||
|
|||||||
6
tasks-sample.csv
Normal file
6
tasks-sample.csv
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
"title","description","kind","priority","startsAt","dueAt","estimateHours","assigneeEmail","tagNames"
|
||||||
|
"[Beasiswa] Import ringkasanBeasiswaState ke halaman publik beasiswa-desa","Import ringkasanBeasiswaState dari src/app/admin/(dashboard)/_state/pendidikan/ringkasan-beasiswa.ts ke src/app/darmasaba/(pages)/pendidikan/beasiswa-desa/page.tsx untuk mengakses data stats beasiswa secara dinamis.","TASK","MEDIUM","","","0.5","nicoarya20@gmail.com",""
|
||||||
|
"[Beasiswa] Tambah useProxy + useShallowEffect fetch stats beasiswa","Tambah useProxy(ringkasanBeasiswaState.findStats) dan useShallowEffect untuk memanggil statsBeasiswa.load() saat komponen mount di halaman publik beasiswa-desa/page.tsx.","TASK","MEDIUM","","","0.5","nicoarya20@gmail.com",""
|
||||||
|
"[Beasiswa] Ubah dataBeasiswa dari static ke dynamic (penerima & dana tersalurkan)","Pindahkan dataBeasiswa dari static array di luar komponen menjadi computed array di dalam Page(). Field 'Penerima Beasiswa' diambil dari statsBeasiswa.data.jumlahPenerima dan 'Dana Tersalurkan' dari statsBeasiswa.data.danaTersalurkan. Fallback '-' bila data belum tersedia.","TASK","MEDIUM","","","0.5","nicoarya20@gmail.com",""
|
||||||
|
"[Beasiswa] Buat fungsi formatDana untuk konversi angka ke format pendek Indonesia","Buat helper function formatDana(value: string | number) di halaman beasiswa-desa/page.tsx. Konversi: >= 1T → XT, >= 1M (miliar) → XM, >= 1Jt → XJt, >= 1Rb → XRb. Desimal 1 angka hanya muncul jika ada sisa (misal 1.5Jt), bilangan bulat tanpa desimal (misal 2Jt).","TASK","MEDIUM","","","0.5","nicoarya20@gmail.com",""
|
||||||
|
"[Beasiswa] Terapkan formatDana ke field Dana Tersalurkan di dataBeasiswa","Terapkan formatDana(statsBeasiswa.data.danaTersalurkan) pada entry Dana Tersalurkan di array dataBeasiswa agar nilai dari API otomatis diformat ke representasi singkat (Rb/Jt/M/T).","TASK","MEDIUM","","","0.5","nicoarya20@gmail.com",""
|
||||||
|
Reference in New Issue
Block a user