Fix UI Admin Menu Landing Page & PPID

This commit is contained in:
2025-09-01 16:14:28 +08:00
parent 22ec8d942d
commit 7ae83788b4
74 changed files with 4312 additions and 2798 deletions

View File

@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
'use client'
import colors from '@/con/colors';
import { Alert, Box, Button, Center, Group, Image, Paper, Stack, Text, TextInput, Title } from '@mantine/core';
import { Alert, Box, Button, Center, Group, Image, Paper, Stack, Text, TextInput, Title, Tooltip } from '@mantine/core';
import { useEffect, useState } from 'react';
import { useProxy } from 'valtio/utils';
import stateProfilePPID from '../../../_state/ppid/profile_ppid/profile_PPID';
@@ -146,129 +146,139 @@ function EditProfilePPID() {
}
return (
<Box>
<Stack gap="xs">
<Box>
<Button variant="subtle" onClick={handleBack}>
<IconArrowBack color={colors['blue-button']} size={20} />
</Button>
</Box>
<Box p="md">
<Stack gap="md">
<Group mb="md">
<Tooltip label="Kembali ke halaman sebelumnya" withArrow>
<Button variant="subtle" onClick={handleBack} p="xs" radius="md">
<IconArrowBack color={colors['blue-button']} size={24} />
</Button>
</Tooltip>
<Title order={4} ml="sm" c="dark">
Edit Profil PPID
</Title>
</Group>
<Box>
<Paper w={{ base: "100%", md: "50%" }} bg={colors['white-1']} p="md" radius={10}>
<Stack gap="xs">
<Title order={3}>Edit Profile PPID</Title>
<Paper
w={{ base: "100%", md: "50%" }}
bg={colors['white-1']}
p="md"
radius="md"
shadow="sm"
style={{ border: '1px solid #e0e0e0' }}
>
<Stack gap="md">
<Title order={3} c={colors['blue-button']}>Edit Profile PPID</Title>
{/* Nama Field */}
<TextInput
label={<Text fw="bold">Nama Perbekel</Text>}
placeholder="Masukkan nama perbekel"
value={allState.editForm.form.name}
onChange={(e) => handleFieldChange('name', e.currentTarget.value)}
error={!allState.editForm.form.name && "Nama wajib diisi"}
/>
{/* Nama Field */}
<TextInput
label={<Text fw="bold">Nama Perbekel</Text>}
placeholder="Masukkan nama perbekel"
value={allState.editForm.form.name}
onChange={(e) => handleFieldChange('name', e.currentTarget.value)}
error={!allState.editForm.form.name && "Nama wajib diisi"}
/>
{/* File Upload */}
{/* File Upload */}
<Box>
<Text fz={"md"} fw={"bold"}>Gambar</Text>
<Box>
<Text fz={"md"} fw={"bold"}>Gambar</Text>
<Box>
<Dropzone
onDrop={(files) => {
const selectedFile = files[0]; // Ambil file pertama
if (selectedFile) {
setFile(selectedFile);
setPreviewImage(URL.createObjectURL(selectedFile)); // Buat preview
}
}}
onReject={() => toast.error('File tidak valid.')}
maxSize={5 * 1024 ** 2} // Maks 5MB
accept={{ 'image/*': [] }}
>
<Group justify="center" gap="xl" mih={220} style={{ pointerEvents: 'none' }}>
<Dropzone.Accept>
<IconUpload size={52} color="var(--mantine-color-blue-6)" stroke={1.5} />
</Dropzone.Accept>
<Dropzone.Reject>
<IconX size={52} color="var(--mantine-color-red-6)" stroke={1.5} />
</Dropzone.Reject>
<Dropzone.Idle>
<IconPhoto size={52} color="var(--mantine-color-dimmed)" stroke={1.5} />
</Dropzone.Idle>
<Dropzone
onDrop={(files) => {
const selectedFile = files[0]; // Ambil file pertama
if (selectedFile) {
setFile(selectedFile);
setPreviewImage(URL.createObjectURL(selectedFile)); // Buat preview
}
}}
onReject={() => toast.error('File tidak valid.')}
maxSize={5 * 1024 ** 2} // Maks 5MB
accept={{ 'image/*': [] }}
>
<Group justify="center" gap="xl" mih={220} style={{ pointerEvents: 'none' }}>
<Dropzone.Accept>
<IconUpload size={52} color="var(--mantine-color-blue-6)" stroke={1.5} />
</Dropzone.Accept>
<Dropzone.Reject>
<IconX size={52} color="var(--mantine-color-red-6)" stroke={1.5} />
</Dropzone.Reject>
<Dropzone.Idle>
<IconPhoto size={52} color="var(--mantine-color-dimmed)" stroke={1.5} />
</Dropzone.Idle>
<div>
<Text size="xl" inline>
Drag gambar ke sini atau klik untuk pilih file
</Text>
<Text size="sm" c="dimmed" inline mt={7}>
Maksimal 5MB dan harus format gambar
</Text>
</div>
</Group>
</Dropzone>
<div>
<Text size="xl" inline>
Tarik gambar ke sini atau klik untuk memilih file
</Text>
<Text size="sm" c="dimmed" inline mt={7}>
Maksimal 5MB dan harus format gambar
</Text>
</div>
</Group>
</Dropzone>
{/* Tampilkan preview kalau ada */}
{previewImage && (
<Box mt="sm">
<Image
src={previewImage}
alt="Preview"
style={{
maxWidth: '100%',
maxHeight: '200px',
objectFit: 'contain',
borderRadius: '8px',
border: '1px solid #ddd',
}}
/>
</Box>
)}
{/* Tampilkan preview kalau ada */}
{previewImage && (
<Box mt="sm">
<Image
src={previewImage}
alt="Preview"
style={{
maxWidth: '100%',
maxHeight: '200px',
objectFit: 'contain',
borderRadius: '8px',
border: '1px solid #ddd',
}}
/>
</Box>
)}
</Box>
</Box>
</Box>
{/* Rich Components */}
<Biodata
value={allState.editForm.form.biodata}
onChange={(val) => handleFieldChange('biodata', val)}
/>
{/* Rich Components */}
<Biodata
value={allState.editForm.form.biodata}
onChange={(val) => handleFieldChange('biodata', val)}
/>
<RiwayatKarir
value={allState.editForm.form.riwayat}
onChange={(val) => handleFieldChange('riwayat', val)}
/>
<RiwayatKarir
value={allState.editForm.form.riwayat}
onChange={(val) => handleFieldChange('riwayat', val)}
/>
<PengalamanOrganisasi
value={allState.editForm.form.pengalaman}
onChange={(val) => handleFieldChange('pengalaman', val)}
/>
<PengalamanOrganisasi
value={allState.editForm.form.pengalaman}
onChange={(val) => handleFieldChange('pengalaman', val)}
/>
<ProgramKerjaUnggulan
value={allState.editForm.form.unggulan}
onChange={(val) => handleFieldChange('unggulan', val)}
/>
<ProgramKerjaUnggulan
value={allState.editForm.form.unggulan}
onChange={(val) => handleFieldChange('unggulan', val)}
/>
{/* Submit Button */}
<Group>
<Button
bg={colors['blue-button']}
onClick={handleSubmit}
loading={isSubmitting || allState.editForm.loading}
disabled={!allState.editForm.form.name}
>
{isSubmitting ? 'Menyimpan...' : 'Simpan Perubahan'}
</Button>
{/* Submit Button */}
<Group>
<Button
bg={colors['blue-button']}
onClick={handleSubmit}
loading={isSubmitting || allState.editForm.loading}
disabled={!allState.editForm.form.name}
>
{isSubmitting ? 'Menyimpan...' : 'Simpan Perubahan'}
</Button>
<Button
variant="outline"
onClick={handleBack}
disabled={isSubmitting || allState.editForm.loading}
>
Batal
</Button>
</Group>
</Stack>
</Paper>
</Box>
<Button
variant="outline"
onClick={handleBack}
disabled={isSubmitting || allState.editForm.loading}
>
Batal
</Button>
</Group>
</Stack>
</Paper>
</Stack>
</Box>
);

View File

@@ -1,6 +1,6 @@
'use client'
import colors from '@/con/colors';
import { Box, Button, Center, Divider, Grid, GridCol, Image, Paper, Skeleton, Stack, Text, Title } from '@mantine/core';
import { Box, Button, Center, Divider, Grid, GridCol, Image, Paper, Skeleton, Stack, Text, Title, Tooltip } from '@mantine/core';
import { useShallowEffect } from '@mantine/hooks';
import { IconEdit } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
@@ -16,9 +16,11 @@ function Page() {
}, [])
if (!allList.profile.data) {
return <Stack>
<Skeleton radius={10} h={800} />
</Stack>
return (
<Stack align="center" justify="center" py="xl">
<Skeleton radius="md" height={800} />
</Stack>
);
}
const dataArray = Array.isArray(allList.profile.data)
@@ -26,89 +28,96 @@ function Page() {
: [allList.profile.data];
return (
<Paper bg={colors['white-1']} p={'md'}>
<Stack gap={"xs"}>
<Grid>
<Paper bg={colors['white-1']} p="lg" radius="md" shadow="sm">
<Stack gap="md">
<Grid align="center">
<GridCol span={{ base: 12, md: 11 }}>
<Title order={3}>Preview Profile PPID</Title>
<Title order={3} c={colors['blue-button']}>Preview Profil PPID</Title>
</GridCol>
<GridCol span={{ base: 12, md: 1 }}>
<Button bg={colors['blue-button']} onClick={() => router.push(`/admin/ppid/profile-ppid/${allList.profile.data?.id}`)}>
<IconEdit size={16} />
</Button>
<Tooltip label="Edit Profil PPID" withArrow>
<Button
c="green"
variant="light"
leftSection={<IconEdit size={18} stroke={2} />}
radius="md"
onClick={() => router.push(`/admin/ppid/profile-ppid/${allList.profile.data?.id}`)}
>
Edit
</Button>
</Tooltip>
</GridCol>
</Grid>
{dataArray.map((item) => (
<Box key={item.id} >
<Paper p={"xl"} bg={colors['BG-trans']}>
<Box px={{ base: "md", md: 100 }}>
<Grid>
<GridCol span={{ base: 12, md: 12 }}>
<Center>
<Image src={"/darmasaba-icon.png"} w={{ base: 100, md: 150 }} alt='' />
</Center>
</GridCol>
<GridCol span={{ base: 12, md: 12 }}>
<Text ta={"center"} fz={{ base: "1.2rem", md: "1.8rem" }} fw={'bold'}>PROFIL PIMPINAN BADAN PUBLIK DESA DARMASABA </Text>
</GridCol>
</Grid>
</Box>
<Divider my={"md"} color={colors['blue-button']} />
{/* biodata perbekel */}
<Box px={{ base: 0, md: 50 }} pb={30}>
<Box pb={20} px={{ base: 0, md: 50 }}>
<Paper bg={colors['BG-trans']} w={{ base: "100%", md: "100%" }}>
<Stack gap={0}>
<Center>
<Image
pt={{ base: 0, md: 90 }}
src={item.image?.link || "/perbekel.png"}
w={{ base: 250, md: 350 }}
alt='Foto Profil PPID'
onError={(e) => {
e.currentTarget.src = "/perbekel.png";
}}
/>
</Center>
<Paper
bg={colors['blue-button']}
py={20}
className="glass3"
px={{ base: 10, md: 10 }}
>
<Text ta={"center"} c={colors['white-1']} fw={"bolder"} fz={{ base: "1.2rem", md: "1.6rem" }}>
{item.name}
</Text>
</Paper>
</Stack>
<Paper key={item.id} p="xl" bg={'white'} withBorder radius="md" shadow="xs">
<Box px={{ base: "sm", md: 100 }}>
<Grid>
<GridCol span={12}>
<Center>
<Image src="/darmasaba-icon.png" w={{ base: 100, md: 150 }} alt="Logo Desa" />
</Center>
</GridCol>
<GridCol span={12}>
<Text ta="center" fz={{ base: "1.2rem", md: "1.8rem" }} fw="bold" c={colors['blue-button']}>
PROFIL PIMPINAN BADAN PUBLIK DESA DARMASABA
</Text>
</GridCol>
</Grid>
</Box>
<Divider my="md" color={colors['blue-button']} />
<Box px={{ base: 0, md: 50 }} pb="xl">
<Paper bg={colors['BG-trans']} radius="md" shadow="xs" p="lg">
<Stack gap={0}>
<Center>
<Image
pt={{ base: 0, md: 60 }}
src={item.image?.link || "/perbekel.png"}
w={{ base: 250, md: 350 }}
alt="Foto Profil PPID"
radius="md"
onError={(e) => { e.currentTarget.src = "/perbekel.png"; }}
/>
</Center>
<Paper
bg={colors['blue-button']}
py="md"
px="sm"
radius="md"
className="glass3"
style={{ mt: -30, boxShadow: '0 4px 20px rgba(0,0,0,0.15)' }}
>
<Text ta="center" c={colors['white-1']} fw="bolder" fz={{ base: "1.2rem", md: "1.6rem" }}>
{item.name}
</Text>
</Paper>
</Box>
<Box pt={10}>
<Box>
<Text fz={{ base: "1.125rem", md: "1.6rem" }} fw={'bold'}>Biodata</Text>
<Text fz={{ base: "1rem", md: "1.5rem" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: item.biodata }} />
</Box>
<Box>
<Text fz={{ base: "1.125rem", md: "1.6rem" }} fw={'bold'}>Riwayat Karir</Text>
<Text fz={{ base: "1rem", md: "1.5rem" }} dangerouslySetInnerHTML={{ __html: item.riwayat }} />
</Box>
</Box>
<Box pb={30}>
<Text fz={{ base: "1.125rem", md: "1.6rem" }} fw={'bold'}>Pengalaman Organisasi</Text>
<Box px={20}>
<Text fz={{ base: "1rem", md: "1.5rem" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: item.pengalaman }} />
</Box>
</Box>
<Box pb={20}>
<Text fz={{ base: "1.125rem", md: "1.6rem" }} fw={'bold'}>Program Kerja Unggulan</Text>
<Box px={20}>
<Text fz={{ base: "1rem", md: "1.5rem" }} ta={"justify"} dangerouslySetInnerHTML={{ __html: item.unggulan }} />
</Box>
</Stack>
</Paper>
<Box mt="lg">
<Text fz={{ base: "1.125rem", md: "1.5rem" }} fw="bold" mb={4}>Biodata</Text>
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" c={colors['blue-button']} dangerouslySetInnerHTML={{ __html: item.biodata }} />
</Box>
<Box mt="xl">
<Text fz={{ base: "1.125rem", md: "1.5rem" }} fw="bold" mb={4}>Riwayat Karir</Text>
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" c={colors['blue-button']} dangerouslySetInnerHTML={{ __html: item.riwayat }} />
</Box>
<Box mt="xl">
<Text fz={{ base: "1.125rem", md: "1.5rem" }} fw="bold" mb={4}>Pengalaman Organisasi</Text>
<Box px={20}>
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" c={colors['blue-button']} dangerouslySetInnerHTML={{ __html: item.pengalaman }} />
</Box>
</Box>
</Paper>
</Box>
<Box mt="xl" mb="lg">
<Text fz={{ base: "1.125rem", md: "1.5rem" }} fw="bold" mb={4}>Program Kerja Unggulan</Text>
<Box px={20}>
<Text fz={{ base: "1rem", md: "1.4rem" }} ta="justify" c={colors['blue-button']} dangerouslySetInnerHTML={{ __html: item.unggulan }} />
</Box>
</Box>
</Box>
</Paper>
))}
</Stack>
</Paper>