Merge pull request 'fix/admin/menu-desa/berita' (#69) from fix/admin/menu-desa/berita into staggingweb

Reviewed-on: #69
This commit is contained in:
2026-02-25 16:27:35 +08:00
254 changed files with 8153 additions and 685 deletions

View File

@@ -1,7 +1,11 @@
'use client';
import React from 'react';
import { Grid, GridCol, Paper, TextInput, Title } from '@mantine/core';
import { Grid, GridCol, Paper, TextInput } from '@mantine/core';
import { IconSearch } from '@tabler/icons-react';
import colors from '@/con/colors';
import { useDarkMode } from '@/state/darkModeStore';
import { themeTokens } from '@/utils/themeTokens';
import { UnifiedTitle } from '@/components/admin/UnifiedTypography';
type HeaderSearchProps = {
title: string;
@@ -18,13 +22,16 @@ const HeaderSearch = ({
value,
onChange,
}: HeaderSearchProps) => {
const { isDark } = useDarkMode();
const tokens = themeTokens(isDark);
return (
<Grid mb={10}>
<GridCol span={{ base: 12, md: 9 }}>
<Title order={3}>{title}</Title>
<UnifiedTitle order={3}>{title}</UnifiedTitle>
</GridCol>
<GridCol span={{ base: 12, md: 3 }}>
<Paper radius="lg" bg={colors['white-1']}>
<Paper radius="lg" bg={tokens.colors.bg.surface}>
<TextInput
radius="lg"
placeholder={placeholder}
@@ -32,6 +39,16 @@ const HeaderSearch = ({
w="100%"
value={value}
onChange={onChange}
style={{
input: {
backgroundColor: tokens.colors.bg.surface,
color: tokens.colors.text.primary,
borderColor: tokens.colors.border.default,
'::placeholder': {
color: tokens.colors.text.muted,
},
},
}}
/>
</Paper>
</GridCol>

View File

@@ -1,12 +1,16 @@
'use client'
import colors from '@/con/colors';
import { Grid, GridCol, Button, Text } from '@mantine/core';
import { Grid, GridCol, Button } from '@mantine/core';
import { IconCircleDashedPlus } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import React from 'react';
import { useDarkMode } from '@/state/darkModeStore';
import { themeTokens } from '@/utils/themeTokens';
import { UnifiedText } from '@/components/admin/UnifiedTypography';
const JudulList = ({ title = "", href = "#" }) => {
const { isDark } = useDarkMode();
const tokens = themeTokens(isDark);
const router = useRouter();
const handleNavigate = () => {
@@ -16,10 +20,18 @@ const JudulList = ({ title = "", href = "#" }) => {
return (
<Grid align="center" mb={10}>
<GridCol span={{ base: 12, md: 11 }}>
<Text fz={"xl"} fw={"bold"}>{title}</Text>
<UnifiedText size="body" weight="bold" color="primary">{title}</UnifiedText>
</GridCol>
<GridCol span={{ base: 12, md: 1 }} ta="right">
<Button onClick={handleNavigate} bg={colors['blue-button']}>
<Button
onClick={handleNavigate}
bg={tokens.colors.primary}
style={{
background: `linear-gradient(135deg, ${tokens.colors.primary}, ${isDark ? '#60A5FA' : '#4facfe'})`,
color: tokens.colors.text.inverse,
boxShadow: isDark ? 'none' : `0 4px 15px rgba(79, 172, 254, 0.4)`,
}}
>
<IconCircleDashedPlus size={25} />
</Button>
</GridCol>

View File

@@ -1,9 +1,11 @@
'use client'
import colors from '@/con/colors';
import { Grid, GridCol, Button, Text, Paper, TextInput } from '@mantine/core';
import { Grid, GridCol, Button, Paper, TextInput } from '@mantine/core';
import { IconCircleDashedPlus, IconSearch } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import React from 'react';
import { useDarkMode } from '@/state/darkModeStore';
import { themeTokens } from '@/utils/themeTokens';
import { UnifiedText } from '@/components/admin/UnifiedTypography';
type JudulListTabProps = {
title: string;
@@ -14,17 +16,16 @@ type JudulListTabProps = {
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
}
const JudulListTab = ({
title = "",
href = "#",
placeholder = "pencarian",
searchIcon = <IconSearch size={20} />,
value,
onChange
onChange
}: JudulListTabProps) => {
const { isDark } = useDarkMode();
const tokens = themeTokens(isDark);
const router = useRouter();
const handleNavigate = () => {
@@ -34,10 +35,17 @@ const JudulListTab = ({
return (
<Grid mb={10}>
<GridCol span={{ base: 12, md: 8 }}>
<Text fz={{ base: "md", md: "xl" }} fw={"bold"}>{title}</Text>
<UnifiedText
size="body"
weight="bold"
color="primary"
style={{ fontSize: 'clamp(1rem, 2vw, 1.25rem)' }}
>
{title}
</UnifiedText>
</GridCol>
<GridCol span={{ base: 9, md: 3 }} ta="right">
<Paper radius={"lg"} bg={colors['white-1']}>
<Paper radius={"lg"} bg={tokens.colors.bg.surface}>
<TextInput
radius="lg"
placeholder={placeholder}
@@ -45,11 +53,29 @@ const JudulListTab = ({
w="100%"
value={value}
onChange={onChange}
style={{
input: {
backgroundColor: tokens.colors.bg.surface,
color: tokens.colors.text.primary,
borderColor: tokens.colors.border.default,
'::placeholder': {
color: tokens.colors.text.muted,
},
},
}}
/>
</Paper>
</GridCol>
<GridCol span={{ base: 3, md: 1 }} ta="right">
<Button onClick={handleNavigate} bg={colors['blue-button']}>
<Button
onClick={handleNavigate}
bg={tokens.colors.primary}
style={{
background: `linear-gradient(135deg, ${tokens.colors.primary}, ${isDark ? '#60A5FA' : '#4facfe'})`,
color: tokens.colors.text.inverse,
boxShadow: isDark ? 'none' : `0 4px 15px rgba(79, 172, 254, 0.4)`,
}}
>
<IconCircleDashedPlus size={25} />
</Button>
</GridCol>

View File

@@ -38,11 +38,9 @@ function normalizeItem(item: Partial<z.infer<typeof ApbdesItemSchema>>): z.infer
const anggaran = item.anggaran ?? 0;
const realisasi = item.realisasi ?? 0;
// ✅ Formula yang benar
const selisih = anggaran - realisasi; // positif = sisa anggaran, negatif = over budget
const selisih = realisasi - anggaran; // positif = sisa anggaran, negatif = over budget
const persentase = anggaran > 0 ? (realisasi / anggaran) * 100 : 0; // persentase realisasi terhadap anggaran
return {

View File

@@ -55,10 +55,15 @@ const programInovasi = proxy({
programInovasi.findMany.load();
return toast.success("Sukses menambahkan");
}
console.log(res);
if (process.env.NODE_ENV === 'development') {
console.log(res);
}
return toast.error("failed create");
} catch (error) {
console.log((error as Error).message);
if (process.env.NODE_ENV === 'development') {
console.error("Create error:", error);
}
toast.error("Gagal menambahkan data");
} finally {
programInovasi.create.loading = false;
}
@@ -91,13 +96,17 @@ const programInovasi = proxy({
programInovasi.findMany.total = res.data.total || 0;
programInovasi.findMany.totalPages = res.data.totalPages || 1;
} else {
console.error("Failed to load pegawai:", res.data?.message);
if (process.env.NODE_ENV === 'development') {
console.error("Failed to load pegawai:", res.data?.message);
}
programInovasi.findMany.data = [];
programInovasi.findMany.total = 0;
programInovasi.findMany.totalPages = 1;
}
} catch (error) {
console.error("Error loading pegawai:", error);
if (process.env.NODE_ENV === 'development') {
console.error("Error loading pegawai:", error);
}
programInovasi.findMany.data = [];
programInovasi.findMany.total = 0;
programInovasi.findMany.totalPages = 1;
@@ -112,19 +121,25 @@ const programInovasi = proxy({
image: true;
};
}> | null,
loading: false,
async load(id: string) {
try {
const res = await fetch(`/api/landingpage/programinovasi/${id}`);
if (res.ok) {
const data = await res.json();
programInovasi.findUnique.data = data.data ?? null;
programInovasi.findUnique.loading = true;
const res = await (ApiFetch.api.landingpage.programinovasi as any)[id].get();
if (res.data?.success) {
programInovasi.findUnique.data = res.data.data ?? null;
return res.data.data;
} else {
console.error("Failed to fetch program inovasi:", res.statusText);
toast.error(res.data?.message || "Gagal memuat data program inovasi");
programInovasi.findUnique.data = null;
return null;
}
} catch (error) {
console.error("Error fetching program inovasi:", error);
programInovasi.findUnique.data = null;
return null;
} finally {
programInovasi.findUnique.loading = false;
}
},
},
@@ -135,27 +150,18 @@ const programInovasi = proxy({
try {
programInovasi.delete.loading = true;
const res = await (ApiFetch.api.landingpage.programinovasi as any)["del"][id].delete();
const response = await fetch(
`/api/landingpage/programinovasi/del/${id}`,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
}
);
const result = await response.json();
if (response.ok && result?.success) {
toast.success(result.message || "Program inovasi berhasil dihapus");
await programInovasi.findMany.load(); // refresh list
if (res.data?.success) {
toast.success(res.data.message || "Program inovasi berhasil dihapus");
await programInovasi.findMany.load();
} else {
toast.error(result?.message || "Gagal menghapus program inovasi");
toast.error(res.data?.message || "Gagal menghapus program inovasi");
}
} catch (error) {
console.error("Gagal delete:", error);
if (process.env.NODE_ENV === 'development') {
console.error("Gagal delete:", error);
}
toast.error("Terjadi kesalahan saat menghapus program inovasi");
} finally {
programInovasi.delete.loading = false;
@@ -174,20 +180,11 @@ const programInovasi = proxy({
}
try {
const response = await fetch(`/api/landingpage/programinovasi/${id}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
programInovasi.update.loading = true;
const res = await (ApiFetch.api.landingpage.programinovasi as any)[id].get();
const result = await response.json();
if (result?.success) {
const data = result.data;
if (res.data?.success) {
const data = res.data.data;
this.id = data.id;
this.form = {
name: data.name,
@@ -197,13 +194,15 @@ const programInovasi = proxy({
};
return data;
} else {
throw new Error(
result?.message || "Gagal mengambil data program inovasi"
);
toast.error(res.data?.message || "Gagal mengambil data program inovasi");
return null;
}
} catch (error) {
console.error((error as Error).message);
if (process.env.NODE_ENV === 'development') {
console.error("Error loading program inovasi:", error);
}
toast.error("Terjadi kesalahan saat mengambil data program inovasi");
return null;
} finally {
programInovasi.update.loading = false;
}
@@ -221,41 +220,25 @@ const programInovasi = proxy({
try {
programInovasi.update.loading = true;
const res = await (ApiFetch.api.landingpage.programinovasi as any)[this.id].put({
name: this.form.name,
description: this.form.description,
imageId: this.form.imageId,
link: this.form.link,
});
const response = await fetch(
`/api/landingpage/programinovasi/${this.id}`,
{
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: this.form.name,
description: this.form.description,
imageId: this.form.imageId,
link: this.form.link,
}),
}
);
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(
errorData.message || `HTTP error! status: ${response.status}`
);
}
const result = await response.json();
if (result.success) {
if (res.data?.success) {
toast.success("Berhasil update program inovasi");
await programInovasi.findMany.load(); // refresh list
await programInovasi.findMany.load();
return true;
} else {
throw new Error(result.message || "Gagal update program inovasi");
toast.error(res.data?.message || "Gagal update program inovasi");
return false;
}
} catch (error) {
console.error("Error updating program inovasi:", error);
if (process.env.NODE_ENV === 'development') {
console.error("Error updating program inovasi:", error);
}
toast.error(
error instanceof Error
? error.message
@@ -443,7 +426,7 @@ const pejabatDesa = proxy({
const templateMediaSosial = z.object({
name: z.string().min(3, "Nama minimal 3 karakter"),
imageId: z.string().nullable().optional(),
iconUrl: z.string().min(3, "Icon URL minimal 3 karakter"),
iconUrl: z.string().optional(), // ✅ Optional - tidak selalu required
icon: z.string().nullable().optional(),
});
@@ -484,10 +467,15 @@ const mediaSosial = proxy({
mediaSosial.findMany.load();
return toast.success("Sukses menambahkan");
}
console.log(res);
if (process.env.NODE_ENV === 'development') {
console.log(res);
}
return toast.error("failed create");
} catch (error) {
console.log((error as Error).message);
if (process.env.NODE_ENV === 'development') {
console.log((error as Error).message);
}
toast.error("Gagal menambahkan data");
} finally {
mediaSosial.create.loading = false;
}
@@ -518,13 +506,17 @@ const mediaSosial = proxy({
mediaSosial.findMany.total = res.data.total || 0;
mediaSosial.findMany.totalPages = res.data.totalPages || 1;
} else {
console.error("Failed to load media sosial:", res.data?.message);
if (process.env.NODE_ENV === 'development') {
console.error("Failed to load media sosial:", res.data?.message);
}
mediaSosial.findMany.data = [];
mediaSosial.findMany.total = 0;
mediaSosial.findMany.totalPages = 1;
}
} catch (error) {
console.error("Error loading media sosial:", error);
if (process.env.NODE_ENV === 'development') {
console.error("Error loading media sosial:", error);
}
mediaSosial.findMany.data = [];
mediaSosial.findMany.total = 0;
mediaSosial.findMany.totalPages = 1;
@@ -539,25 +531,32 @@ const mediaSosial = proxy({
image: true;
};
}> | null,
loading: false,
async load(id: string) {
if (!id) {
toast.warn("ID tidak valid");
return null;
}
mediaSosial.update.loading = true;
mediaSosial.findUnique.loading = true;
try {
const res = await fetch(`/api/landingpage/mediasosial/${id}`);
if (res.ok) {
const data = await res.json();
mediaSosial.findUnique.data = data.data ?? null;
const res = await (ApiFetch.api.landingpage.mediasosial as any)[id].get();
if (res.data?.success) {
mediaSosial.findUnique.data = res.data.data ?? null;
return res.data.data;
} else {
console.error("Failed to fetch media sosial:", res.statusText);
toast.error(res.data?.message || "Gagal memuat data media sosial");
mediaSosial.findUnique.data = null;
return null;
}
} catch (error) {
console.error("Error fetching media sosial:", error);
if (process.env.NODE_ENV === 'development') {
console.error("Error fetching media sosial:", error);
}
mediaSosial.findUnique.data = null;
return null;
} finally {
mediaSosial.findUnique.loading = false;
}
},
},
@@ -568,24 +567,18 @@ const mediaSosial = proxy({
try {
mediaSosial.delete.loading = true;
const res = await (ApiFetch.api.landingpage.mediasosial as any)["del"][id].delete();
const response = await fetch(`/api/landingpage/mediasosial/del/${id}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
});
const result = await response.json();
if (response.ok && result?.success) {
toast.success(result.message || "Media Sosial berhasil dihapus");
await mediaSosial.findMany.load(); // refresh list
if (res.data?.success) {
toast.success(res.data.message || "Media Sosial berhasil dihapus");
await mediaSosial.findMany.load();
} else {
toast.error(result?.message || "Gagal menghapus media sosial");
toast.error(res.data?.message || "Gagal menghapus media sosial");
}
} catch (error) {
console.error("Gagal delete:", error);
if (process.env.NODE_ENV === 'development') {
console.error("Gagal delete:", error);
}
toast.error("Terjadi kesalahan saat menghapus media sosial");
} finally {
mediaSosial.delete.loading = false;
@@ -603,43 +596,32 @@ const mediaSosial = proxy({
return null;
}
mediaSosial.update.loading = true; // ✅ Tambahkan ini di awal
mediaSosial.update.loading = true;
try {
const response = await fetch(`/api/landingpage/mediasosial/${id}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const res = await (ApiFetch.api.landingpage.mediasosial as any)[id].get();
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
if (result?.success) {
const data = result.data;
if (res.data?.success) {
const data = res.data.data;
this.id = data.id;
this.form = {
name: data.name || "",
imageId: data.imageId || null,
iconUrl: data.iconUrl || "",
icon: data.icon || null,
};
return data;
} else {
throw new Error(
result?.message || "Gagal mengambil data media sosial"
);
toast.error(res.data?.message || "Gagal mengambil data media sosial");
return null;
}
} catch (error) {
console.error((error as Error).message);
if (process.env.NODE_ENV === 'development') {
console.error("Error loading media sosial:", error);
}
toast.error("Terjadi kesalahan saat mengambil data media sosial");
return null;
} finally {
mediaSosial.update.loading = false; // ✅ Supaya berhenti loading walau error
mediaSosial.update.loading = false;
}
},
@@ -655,41 +637,25 @@ const mediaSosial = proxy({
try {
mediaSosial.update.loading = true;
const res = await (ApiFetch.api.landingpage.mediasosial as any)[this.id].put({
name: this.form.name,
imageId: this.form.imageId,
iconUrl: this.form.iconUrl,
icon: this.form.icon,
});
const response = await fetch(
`/api/landingpage/mediasosial/${this.id}`,
{
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: this.form.name,
imageId: this.form.imageId,
iconUrl: this.form.iconUrl,
icon: this.form.icon,
}),
}
);
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(
errorData.message || `HTTP error! status: ${response.status}`
);
}
const result = await response.json();
if (result.success) {
if (res.data?.success) {
toast.success("Berhasil update media sosial");
await mediaSosial.findMany.load(); // refresh list
await mediaSosial.findMany.load();
return true;
} else {
throw new Error(result.message || "Gagal update media sosial");
toast.error(res.data?.message || "Gagal update media sosial");
return false;
}
} catch (error) {
console.error("Error updating media sosial:", error);
if (process.env.NODE_ENV === 'development') {
console.error("Error updating media sosial:", error);
}
toast.error(
error instanceof Error
? error.message

View File

@@ -33,6 +33,13 @@ function EditKategoriBerita() {
name: '',
});
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== ''
);
};
useEffect(() => {
const loadKategori = async () => {
const id = params?.id as string;
@@ -72,6 +79,11 @@ function EditKategoriBerita() {
};
const handleSubmit = async () => {
if (!formData.name?.trim()) {
toast.error('Nama kategori berita wajib diisi');
return;
}
try {
setIsSubmitting(true);
// update global state hanya saat submit
@@ -143,8 +155,11 @@ function EditKategoriBerita() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -22,6 +22,13 @@ function CreateKategoriBerita() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
createState.create.form.name?.trim() !== ''
);
};
const resetForm = () => {
createState.create.form = {
name: '',
@@ -29,6 +36,11 @@ function CreateKategoriBerita() {
};
const handleSubmit = async () => {
if (!createState.create.form.name?.trim()) {
toast.error('Nama kategori berita wajib diisi');
return;
}
setIsSubmitting(true);
try {
await createState.create.create();
@@ -93,8 +105,11 @@ function CreateKategoriBerita() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -160,7 +160,7 @@ function ListKategoriBerita({ search }: { search: string }) {
))
) : (
<TableTr>
<TableTd colSpan={4}>
<TableTd colSpan={3}> {/* ✅ Match column count (3 columns) */}
<Center py={24}>
<Text c="dimmed" fz="sm" lh={1.4}>
Tidak ada data kategori berita yang cocok

View File

@@ -48,6 +48,24 @@ function EditBerita() {
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.judul?.trim() !== '' &&
formData.kategoriBeritaId !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
(file !== null || originalData.imageId !== '') && // Either a new file is selected or an existing image exists
!isHtmlEmpty(formData.content)
);
};
const [originalData, setOriginalData] = useState({
judul: "",
deskripsi: "",
@@ -103,6 +121,31 @@ function EditBerita() {
};
const handleSubmit = async () => {
if (!formData.judul?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (!formData.kategoriBeritaId) {
toast.error('Kategori wajib dipilih');
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error('Deskripsi singkat wajib diisi');
return;
}
if (!file && !originalData.imageId) {
toast.error('Gambar wajib dipilih');
return;
}
if (isHtmlEmpty(formData.content)) {
toast.error('Konten wajib diisi');
return;
}
try {
setIsSubmitting(true);
// Update global state hanya sekali di sini
@@ -326,8 +369,11 @@ function EditBerita() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -32,6 +32,24 @@ export default function CreateBerita() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
beritaState.berita.create.form.judul?.trim() !== '' &&
beritaState.berita.create.form.kategoriBeritaId !== '' &&
!isHtmlEmpty(beritaState.berita.create.form.deskripsi) &&
file !== null &&
!isHtmlEmpty(beritaState.berita.create.form.content)
);
};
useShallowEffect(() => {
beritaState.kategoriBerita.findMany.load();
}, []);
@@ -49,6 +67,31 @@ export default function CreateBerita() {
};
const handleSubmit = async () => {
if (!beritaState.berita.create.form.judul?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (!beritaState.berita.create.form.kategoriBeritaId) {
toast.error('Kategori wajib dipilih');
return;
}
if (isHtmlEmpty(beritaState.berita.create.form.deskripsi)) {
toast.error('Deskripsi singkat wajib diisi');
return;
}
if (!file) {
toast.error('Gambar wajib dipilih');
return;
}
if (isHtmlEmpty(beritaState.berita.create.form.content)) {
toast.error('Konten wajib diisi');
return;
}
try {
setIsSubmitting(true);
if (!file) {
@@ -250,8 +293,11 @@ export default function CreateBerita() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -187,7 +187,7 @@ function ListBerita({ search }: { search: string }) {
<Pagination
value={page}
onChange={(newPage) => {
load(newPage, 10);
load(newPage, 10, debouncedSearch); // ✅ Include search parameter
window.scrollTo({ top: 0, behavior: 'smooth' });
}}
total={totalPages}

View File

@@ -45,6 +45,22 @@ function EditFoto() {
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
(file !== null || originalData.imagesId !== '') // Either a new file is selected or an existing image exists
);
};
const [originalData, setOriginalData] = useState({
name: "",
deskripsi: "",
@@ -94,6 +110,21 @@ function EditFoto() {
};
const handleSubmit = async () => {
if (!formData.name?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error('Deskripsi wajib diisi');
return;
}
if (!file && !originalData.imagesId) {
toast.error('Gambar wajib dipilih');
return;
}
try {
setIsSubmitting(true);
// Update global state hanya sekali di sini
@@ -285,8 +316,11 @@ function EditFoto() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -30,6 +30,22 @@ function CreateFoto() {
const [previewImage, setPreviewImage] = useState<string | null>(null);
const [file, setFile] = useState<File | null>(null);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
FotoState.create.form.name?.trim() !== '' &&
!isHtmlEmpty(FotoState.create.form.deskripsi) &&
file !== null
);
};
const resetForm = () => {
FotoState.create.form = {
name: '',
@@ -41,6 +57,21 @@ function CreateFoto() {
};
const handleSubmit = async () => {
if (!FotoState.create.form.name?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (isHtmlEmpty(FotoState.create.form.deskripsi)) {
toast.error('Deskripsi wajib diisi');
return;
}
if (!file) {
toast.error('Gambar wajib dipilih');
return;
}
try {
setIsSubmitting(true);
if (!file) {
@@ -210,8 +241,11 @@ function CreateFoto() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -28,6 +28,24 @@ function EditVideo() {
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
const embedLink = convertYoutubeUrlToEmbed(formData.linkVideo);
return (
formData.name?.trim() !== '' &&
formData.linkVideo?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
embedLink !== null // Make sure the embed link is valid
);
};
const [originalData, setOriginalData] = useState({
name: "",
deskripsi: "",
@@ -86,6 +104,21 @@ function EditVideo() {
};
const handleSubmit = async () => {
if (!formData.name?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (!formData.linkVideo?.trim()) {
toast.error('Link YouTube wajib diisi');
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error('Deskripsi wajib diisi');
return;
}
try {
setIsSubmitting(true);
const converted = convertYoutubeUrlToEmbed(formData.linkVideo);
@@ -218,8 +251,11 @@ function EditVideo() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -28,6 +28,23 @@ function CreateVideo() {
const embedLink = convertYoutubeUrlToEmbed(link);
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
videoState.create.form.name?.trim() !== '' &&
link.trim() !== '' &&
!isHtmlEmpty(videoState.create.form.deskripsi) &&
embedLink !== null // Make sure the embed link is valid
);
};
const resetForm = () => {
videoState.create.form = {
name: '',
@@ -38,6 +55,26 @@ function CreateVideo() {
};
const handleSubmit = async () => {
if (!videoState.create.form.name?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (!link.trim()) {
toast.error('Link YouTube wajib diisi');
return;
}
if (isHtmlEmpty(videoState.create.form.deskripsi)) {
toast.error('Deskripsi wajib diisi');
return;
}
if (!embedLink) {
toast.error('Link YouTube tidak valid. Pastikan formatnya benar.');
return;
}
try {
setIsSubmitting(true);
if (!embedLink) {
@@ -168,8 +205,11 @@ function CreateVideo() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -35,6 +35,21 @@ function EditPelayananPendudukNonPermanent() {
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi)
);
};
const [originalData, setOriginalData] = useState({
name: '',
deskripsi: '',
@@ -86,6 +101,16 @@ function EditPelayananPendudukNonPermanent() {
};
const handleSubmit = async () => {
if (!formData.name?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error('Deskripsi wajib diisi');
return;
}
try {
setIsSubmitting(true);
if (!statePendudukNonPermanent.findById.data) return;
@@ -173,8 +198,11 @@ function EditPelayananPendudukNonPermanent() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -36,6 +36,22 @@ function EditPelayananPerizinanBerusaha() {
});
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi)
);
};
const [originalData, setOriginalData] = useState({
id: '',
name: '',
@@ -102,6 +118,21 @@ function EditPelayananPerizinanBerusaha() {
};
const handleSubmit = async () => {
if (!formData.name?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error('Deskripsi wajib diisi');
return;
}
if (!formData.link?.trim()) {
toast.error('Link wajib diisi');
return;
}
try {
setIsSubmitting(true);
await state.update.update(formData);
@@ -192,8 +223,11 @@ function EditPelayananPerizinanBerusaha() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -149,6 +149,22 @@ function EditSuratKeterangan() {
const [previewImage2, setPreviewImage2] = useState<string | null>(null);
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
(previewImage !== null || originalData.imageId !== '') // Either a new file is selected or an existing image exists
);
};
// 🧭 Load Initial Data
useEffect(() => {
const loadSurat = async () => {
@@ -209,6 +225,21 @@ function EditSuratKeterangan() {
// 💾 Submit Handler
const handleSubmit = useCallback(async () => {
if (!formData.name?.trim()) {
toast.error('Nama surat keterangan wajib diisi');
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error('Konten wajib diisi');
return;
}
if (!previewImage && !originalData.imageId) {
toast.error('Gambar konten pelayanan wajib dipilih');
return;
}
try {
setIsSubmitting(true);
@@ -251,7 +282,7 @@ function EditSuratKeterangan() {
} finally {
setIsSubmitting(false);
}
}, [formData, file, file2, router]);
}, [formData, file, file2, router, previewImage, originalData.imageId]);
// 📝 Form Field Handlers
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -324,10 +355,10 @@ function EditSuratKeterangan() {
{/* Action Buttons */}
<Group justify="right">
<Button
variant="outline"
color="gray"
radius="md"
<Button
variant="outline"
color="gray"
radius="md"
onClick={handleResetForm}
disabled={isSubmitting}
>
@@ -336,9 +367,11 @@ function EditSuratKeterangan() {
<Button
onClick={handleSubmit}
radius="md"
disabled={isSubmitting}
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79,172,254,0.4)',
}}

View File

@@ -31,6 +31,22 @@ function CreateSuratKeterangan() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
stateSurat.create.form.name?.trim() !== '' &&
!isHtmlEmpty(stateSurat.create.form.deskripsi) &&
previewImage !== null
);
};
const resetForm = () => {
stateSurat.create.form = {
name: '',
@@ -43,8 +59,19 @@ function CreateSuratKeterangan() {
};
const handleSubmit = async () => {
if (!stateSurat.create.form.name?.trim()) {
toast.error('Nama surat keterangan wajib diisi');
return;
}
if (isHtmlEmpty(stateSurat.create.form.deskripsi)) {
toast.error('Konten wajib diisi');
return;
}
if (!previewImage) {
return toast.warn('Pilih file gambar utama terlebih dahulu');
toast.error('Gambar konten pelayanan wajib dipilih');
return;
}
try {
@@ -284,8 +311,11 @@ function CreateSuratKeterangan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -24,6 +24,15 @@ function EditPelayananTelunjukSakti() {
const params = useParams();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.deskripsi?.trim() !== '' &&
formData.link?.trim() !== ''
);
};
const [formData, setFormData] = useState({
name: '',
deskripsi: '',
@@ -84,6 +93,21 @@ function EditPelayananTelunjukSakti() {
// Submit: update global state hanya saat simpan
const handleSubmit = async () => {
if (!formData.name?.trim()) {
toast.error('Nama pelayanan wajib diisi');
return;
}
if (!formData.deskripsi?.trim()) {
toast.error('Judul link wajib diisi');
return;
}
if (!formData.link?.trim()) {
toast.error('Link wajib diisi');
return;
}
try {
setIsSubmitting(true);
stateTelunjukDesa.edit.form = {
@@ -165,8 +189,11 @@ function EditPelayananTelunjukSakti() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -23,6 +23,15 @@ function CreatePelayananTelunjukDesa() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
stateTelunjukDesa.create.form.name?.trim() !== '' &&
stateTelunjukDesa.create.form.deskripsi?.trim() !== '' &&
stateTelunjukDesa.create.form.link?.trim() !== ''
);
};
const resetForm = () => {
stateTelunjukDesa.create.form = {
name: '',
@@ -32,6 +41,21 @@ function CreatePelayananTelunjukDesa() {
};
const handleSubmit = async () => {
if (!stateTelunjukDesa.create.form.name?.trim()) {
toast.error('Nama pelayanan wajib diisi');
return;
}
if (!stateTelunjukDesa.create.form.deskripsi?.trim()) {
toast.error('Judul link wajib diisi');
return;
}
if (!stateTelunjukDesa.create.form.link?.trim()) {
toast.error('Link wajib diisi');
return;
}
try {
setIsSubmitting(true);
await stateTelunjukDesa.create.create();
@@ -118,8 +142,11 @@ function CreatePelayananTelunjukDesa() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -33,6 +33,23 @@ function EditPenghargaan() {
const [file, setFile] = useState<File | null>(null);
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.juara?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
(file !== null || originalData.imageId !== '') // Either a new file is selected or an existing image exists
);
};
const [originalData, setOriginalData] = useState({
name: "",
juara: "",
@@ -100,6 +117,26 @@ function EditPenghargaan() {
// Submit
const handleSubmit = async () => {
if (!formData.name?.trim()) {
toast.error('Nama penghargaan wajib diisi');
return;
}
if (!formData.juara?.trim()) {
toast.error('Juara wajib diisi');
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error('Deskripsi wajib diisi');
return;
}
if (!file && !originalData.imageId) {
toast.error('Gambar wajib dipilih');
return;
}
try {
setIsSubmitting(true);
// Sync ke global state saat submit
@@ -281,8 +318,11 @@ function EditPenghargaan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -30,6 +30,23 @@ function CreatePenghargaan() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
statePenghargaan.create.form.name?.trim() !== '' &&
statePenghargaan.create.form.juara?.trim() !== '' &&
!isHtmlEmpty(statePenghargaan.create.form.deskripsi) &&
file !== null
);
};
const resetForm = () => {
statePenghargaan.create.form = {
name: '',
@@ -42,6 +59,26 @@ function CreatePenghargaan() {
};
const handleSubmit = async () => {
if (!statePenghargaan.create.form.name?.trim()) {
toast.error('Nama penghargaan wajib diisi');
return;
}
if (!statePenghargaan.create.form.juara?.trim()) {
toast.error('Juara wajib diisi');
return;
}
if (isHtmlEmpty(statePenghargaan.create.form.deskripsi)) {
toast.error('Deskripsi wajib diisi');
return;
}
if (!file) {
toast.error('Gambar wajib dipilih');
return;
}
try {
setIsSubmitting(true);
if (!file) {
@@ -201,8 +238,11 @@ function CreatePenghargaan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -27,6 +27,13 @@ function EditKategoriPengumuman() {
const [formData, setFormData] = useState({ name: '' });
const [originalData, setOriginalData] = useState({ name: '' });
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== ''
);
};
// Load data awal sekali aja
useEffect(() => {
const loadKategori = async () => {
@@ -56,6 +63,11 @@ function EditKategoriPengumuman() {
};
const handleSubmit = async () => {
if (!formData.name?.trim()) {
toast.error('Nama kategori pengumuman wajib diisi');
return;
}
try {
setIsSubmitting(true);
// Update global state hanya di sini
@@ -134,8 +146,11 @@ function EditKategoriPengumuman() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -22,6 +22,13 @@ function CreateKategoriPengumuman() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
createState.create.form.name?.trim() !== ''
);
};
const resetForm = () => {
createState.create.form = {
name: '',
@@ -29,6 +36,11 @@ function CreateKategoriPengumuman() {
};
const handleSubmit = async () => {
if (!createState.create.form.name?.trim()) {
toast.error('Nama kategori pengumuman wajib diisi');
return;
}
try {
await createState.create.create();
resetForm();
@@ -92,8 +104,11 @@ function CreateKategoriPengumuman() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -36,6 +36,23 @@ function EditPengumuman() {
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.judul?.trim() !== '' &&
formData.deskripsi?.trim() !== '' &&
formData.categoryPengumumanId !== '' &&
!isHtmlEmpty(formData.content)
);
};
const [originalData, setOriginalData] = useState({
judul: "",
deskripsi: "",
@@ -81,6 +98,26 @@ function EditPengumuman() {
};
const handleSubmit = async () => {
if (!formData.judul?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (!formData.deskripsi?.trim()) {
toast.error('Deskripsi singkat wajib diisi');
return;
}
if (!formData.categoryPengumumanId) {
toast.error('Kategori wajib dipilih');
return;
}
if (isHtmlEmpty(formData.content)) {
toast.error('Konten lengkap wajib diisi');
return;
}
try {
setIsSubmitting(true);
// update global state hanya sekali pas submit
@@ -197,8 +234,11 @@ function EditPengumuman() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -27,11 +27,48 @@ function CreatePengumuman() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
pengumumanState.pengumuman.create.form.judul?.trim() !== '' &&
pengumumanState.pengumuman.create.form.categoryPengumumanId !== '' &&
pengumumanState.pengumuman.create.form.deskripsi?.trim() !== '' &&
!isHtmlEmpty(pengumumanState.pengumuman.create.form.content)
);
};
useShallowEffect(() => {
pengumumanState.category.findMany.load();
}, []);
const handleSubmit = async () => {
if (!pengumumanState.pengumuman.create.form.judul?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (!pengumumanState.pengumuman.create.form.categoryPengumumanId) {
toast.error('Kategori wajib dipilih');
return;
}
if (!pengumumanState.pengumuman.create.form.deskripsi?.trim()) {
toast.error('Deskripsi singkat wajib diisi');
return;
}
if (isHtmlEmpty(pengumumanState.pengumuman.create.form.content)) {
toast.error('Konten lengkap wajib diisi');
return;
}
try {
setIsSubmitting(true);
await pengumumanState.pengumuman.create.create();
@@ -150,8 +187,11 @@ function CreatePengumuman() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -33,6 +33,13 @@ function EditKategoriPotensi() {
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
formData.nama?.trim() !== ''
);
};
// Load data dari backend -> isi ke formData lokal
useEffect(() => {
const loadKategori = async () => {
@@ -73,6 +80,11 @@ function EditKategoriPotensi() {
};
const handleSubmit = async () => {
if (!formData.nama?.trim()) {
toast.error('Nama kategori potensi wajib diisi');
return;
}
try {
setIsSubmitting(true);
// Update global state hanya pas submit
@@ -141,8 +153,11 @@ function EditKategoriPotensi() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -21,6 +21,13 @@ function CreateKategoriPotensi() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
createState.create.form.nama?.trim() !== ''
);
};
const resetForm = () => {
createState.create.form = {
nama: '',
@@ -28,6 +35,11 @@ function CreateKategoriPotensi() {
};
const handleSubmit = async () => {
if (!createState.create.form.nama?.trim()) {
alert('Nama kategori potensi wajib diisi');
return;
}
try {
setIsSubmitting(true);
await createState.create.create();
@@ -91,8 +103,11 @@ function CreateKategoriPotensi() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -42,6 +42,24 @@ function EditPotensi() {
});
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
formData.kategoriId !== '' &&
(file !== null || originalData.imageId !== '') && // Either a new file is selected or an existing image exists
!isHtmlEmpty(formData.content)
);
};
const [originalData, setOriginalData] = useState({
name: "",
deskripsi: "",
@@ -109,6 +127,31 @@ function EditPotensi() {
const handleSubmit = async () => {
if (!formData.name?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error('Deskripsi singkat wajib diisi');
return;
}
if (!formData.kategoriId) {
toast.error('Kategori wajib dipilih');
return;
}
if (!file && !originalData.imageId) {
toast.error('Gambar wajib dipilih');
return;
}
if (isHtmlEmpty(formData.content)) {
toast.error('Konten lengkap wajib diisi');
return;
}
try {
setIsSubmitting(true);
let imageId = formData.imageId;
@@ -341,8 +384,11 @@ function EditPotensi() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -8,6 +8,7 @@ import { IconArrowBack, IconEdit, IconTrash } from '@tabler/icons-react';
import { useParams, useRouter } from 'next/navigation';
import { useState } from 'react';
import { useProxy } from 'valtio/utils';
import DOMPurify from 'dompurify';
export default function DetailPotensi() {
const router = useRouter();
@@ -77,7 +78,17 @@ export default function DetailPotensi() {
<Box>
<Text fz="lg" fw="bold">Deskripsi</Text>
<Text fz="md" c="dimmed" style={{ wordBreak: "break-word", whiteSpace: "normal" }} dangerouslySetInnerHTML={{ __html: data.deskripsi || '-' }}></Text>
<Text
fz="md"
c="dimmed"
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(data.deskripsi || '-', {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'ul', 'ol', 'li'],
ALLOWED_ATTR: []
})
}}
></Text>
</Box>
<Box>
@@ -102,7 +113,12 @@ export default function DetailPotensi() {
<Text
fz="md"
c="dimmed"
dangerouslySetInnerHTML={{ __html: data.content || '-' }}
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(data.content || '-', {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'ul', 'ol', 'li'],
ALLOWED_ATTR: []
})
}}
style={{ wordBreak: "break-word", whiteSpace: "normal" }}
/>
</Box>

View File

@@ -32,11 +32,54 @@ function CreatePotensi() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
potensiState.create.form.name?.trim() !== '' &&
!isHtmlEmpty(potensiState.create.form.deskripsi) &&
potensiState.create.form.kategoriId !== '' &&
file !== null &&
!isHtmlEmpty(potensiState.create.form.content)
);
};
useEffect(() => {
potensiDesaState.kategoriPotensi.findMany.load();
}, []);
const handleSubmit = async () => {
if (!potensiState.create.form.name?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (isHtmlEmpty(potensiState.create.form.deskripsi)) {
toast.error('Deskripsi singkat wajib diisi');
return;
}
if (!potensiState.create.form.kategoriId) {
toast.error('Kategori wajib dipilih');
return;
}
if (!file) {
toast.error('Gambar wajib dipilih');
return;
}
if (isHtmlEmpty(potensiState.create.form.content)) {
toast.error('Konten lengkap wajib diisi');
return;
}
try {
setIsSubmitting(true);
if (!file) return toast.warn('Pilih file gambar terlebih dahulu');
@@ -266,8 +309,11 @@ function CreatePotensi() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -27,6 +27,7 @@ import { useProxy } from 'valtio/utils';
import HeaderSearch from '../../../_com/header';
import potensiDesaState from '../../../_state/desa/potensi';
import { useDebouncedValue } from '@mantine/hooks';
import DOMPurify from 'dompurify';
function Potensi() {
const [search, setSearch] = useState("");
@@ -137,7 +138,12 @@ function ListPotensi({ search }: { search: string }) {
fz="sm"
lh={1.5}
lineClamp={2}
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(item.deskripsi, {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'ul', 'ol', 'li'],
ALLOWED_ATTR: []
})
}}
style={{ wordBreak: 'break-word' }}
/>
</TableTd>
@@ -199,7 +205,12 @@ function ListPotensi({ search }: { search: string }) {
<Text
fz="sm"
lh={1.5}
dangerouslySetInnerHTML={{ __html: item.deskripsi }}
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(item.deskripsi, {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'u', 'ul', 'ol', 'li'],
ALLOWED_ATTR: []
})
}}
style={{ wordBreak: 'break-word' }}
/>
</Box>

View File

@@ -83,6 +83,21 @@ function Page() {
};
}, [params?.id, router]);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.judul?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi)
);
};
// 🔁 Reset form
const handleResetForm = () => {
setFormData(originalData);
@@ -95,6 +110,11 @@ function Page() {
toast.error('Judul wajib diisi');
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error('Deskripsi wajib diisi');
return;
}
setIsSubmitting(true);
try {
@@ -224,14 +244,16 @@ function Page() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}
loading={isSubmitting}
>
Simpan
{isSubmitting ? <Loader size="sm" color="white" /> : 'Simpan'}
</Button>
</Group>
</Stack>

View File

@@ -34,6 +34,21 @@ function Page() {
images: [] as Array<{ label: string; imageId: string }>
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.judul?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi)
);
};
// Load data
useEffect(() => {
const loadData = async () => {
@@ -122,6 +137,12 @@ function Page() {
toast.error("Judul wajib diisi");
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error("Deskripsi wajib diisi");
return;
}
try {
setIsSubmitting(true);
const uploadedImages = [];
@@ -315,8 +336,11 @@ function Page() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -99,6 +99,21 @@ function Page() {
toast.info('Form dikembalikan ke data awal');
};
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.judul?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi)
);
};
// 💾 Submit Handler
const handleSubmit = async () => {
// Validation
@@ -106,6 +121,11 @@ function Page() {
toast.error('Judul wajib diisi');
return;
}
if (isHtmlEmpty(formData.deskripsi)) {
toast.error('Deskripsi wajib diisi');
return;
}
setIsSubmitting(true);
@@ -260,8 +280,11 @@ function Page() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -81,6 +81,21 @@ function Page() {
};
}, [params?.id, router]);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
!isHtmlEmpty(formData.visi) &&
!isHtmlEmpty(formData.misi)
);
};
// 🔄 Reset Form
const handleResetForm = () => {
setFormData(originalData);
@@ -89,11 +104,16 @@ function Page() {
// 💾 Submit
const handleSubmit = async () => {
if (!formData.visi.trim()) {
if (isHtmlEmpty(formData.visi)) {
toast.error('Visi wajib diisi');
return;
}
if (isHtmlEmpty(formData.misi)) {
toast.error('Misi wajib diisi');
return;
}
setIsSubmitting(true);
try {
const originalState = stateProfileDesa.visiMisiDesa;
@@ -227,14 +247,16 @@ function Page() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}
loading={isSubmitting}
>
Simpan
{isSubmitting ? <Loader size="sm" color="white" /> : 'Simpan'}
</Button>
</Group>
</Stack>

View File

@@ -95,7 +95,7 @@ function Page() {
fz={{ base: 'md', md: 'lg' }}
lh={{ base: 1.4, md: 1.4 }}
>
I.B. Surya Prabhawa Manuaba, S.H., M.H.
{perbekel.nama || "I.B. Surya Prabhawa Manuaba, S.H., M.H."}
</Text>
</Paper>
</Stack>

View File

@@ -51,6 +51,17 @@ function EditAPBDesa() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [isLoading, setIsLoading] = useState(true);
// Check if form is valid
const isFormValid = () => {
return (
formData.tahun?.trim() !== '' &&
Number(formData.tahun) > 0 &&
formData.pendapatanIds.length > 0 &&
formData.belanjaIds.length > 0 &&
formData.pembiayaanIds.length > 0
);
};
// ==================== LOAD DATA ====================
useEffect(() => {
const loadAPBdesa = async () => {
@@ -213,8 +224,11 @@ function EditAPBDesa() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -27,6 +27,17 @@ function CreateAPBDesa() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
apbDesaState.create.form.tahun !== null &&
apbDesaState.create.form.tahun > 0 &&
apbDesaState.create.form.pendapatanIds.length > 0 &&
apbDesaState.create.form.belanjaIds.length > 0 &&
apbDesaState.create.form.pembiayaanIds.length > 0
);
};
const resetForm = () => {
apbDesaState.create.form = {
tahun: 0,
@@ -121,8 +132,11 @@ function CreateAPBDesa() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -35,6 +35,15 @@ function EditBelanja() {
value: '',
});
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.value !== '' &&
Number(formData.value) > 0
);
};
// format angka ke rupiah
const formatRupiah = (value: number | string) => {
const number =
@@ -172,8 +181,11 @@ function EditBelanja() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -24,6 +24,15 @@ function CreateBelanja() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
belanjaState.create.form.name?.trim() !== '' &&
belanjaState.create.form.value !== null &&
belanjaState.create.form.value > 0
);
};
const formatRupiah = (value: number | string) => {
const number =
typeof value === 'number' ? value : Number(value.replace(/\D/g, ''));
@@ -126,8 +135,11 @@ function CreateBelanja() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -34,6 +34,15 @@ function EditPembiayaan() {
value: '',
});
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.value !== '' &&
Number(formData.value) > 0
);
};
const formatRupiah = (value: number | string) => {
const number =
typeof value === 'number'
@@ -169,8 +178,11 @@ function EditPembiayaan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -23,6 +23,15 @@ function CreatePembiayaan() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
pembiayaanState.create.form.name?.trim() !== '' &&
pembiayaanState.create.form.value !== null &&
pembiayaanState.create.form.value > 0
);
};
const formatRupiah = (value: number | string) => {
const number =
typeof value === 'number' ? value : Number(value.replace(/\D/g, ''));
@@ -127,8 +136,11 @@ function CreatePembiayaan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -34,6 +34,15 @@ function EditPendapatan() {
value: '',
});
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.value !== '' &&
Number(formData.value) > 0
);
};
// helper format
const formatRupiah = (value: number | string) => {
const number = typeof value === 'number'
@@ -176,8 +185,11 @@ function EditPendapatan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -22,6 +22,15 @@ function CreatePendapatan() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
pendapatanState.create.form.name?.trim() !== '' &&
pendapatanState.create.form.value !== null &&
pendapatanState.create.form.value > 0
);
};
const formatRupiah = (value: number | string) => {
const number = typeof value === 'number' ? value : Number(value.replace(/\D/g, ''));
return new Intl.NumberFormat('id-ID', {
@@ -122,8 +131,11 @@ function CreatePendapatan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -56,6 +56,14 @@ export default function EditPegawaiBumDes() {
const [previewImage, setPreviewImage] = useState<string | null>(null);
const [file, setFile] = useState<File | null>(null);
// Check if form is valid
const isFormValid = () => {
return (
formData.namaLengkap?.trim() !== '' &&
formData.posisiId?.trim() !== ''
);
};
// Format date for <input type="date">
const formatDateForInput = (dateString: string) => {
if (!dateString) return '';
@@ -325,8 +333,11 @@ export default function EditPegawaiBumDes() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -23,6 +23,15 @@ function CreatePegawaiBumDes() {
const [file, setFile] = useState<File | null>(null);
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
stateOrganisasi.create.form.namaLengkap?.trim() !== '' &&
stateOrganisasi.create.form.posisiId?.trim() !== '' &&
file !== null
);
};
const resetForm = () => {
stateOrganisasi.create.form = {
namaLengkap: "",
@@ -284,8 +293,11 @@ function CreatePegawaiBumDes() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -31,6 +31,23 @@ function EditPosisiOrganisasiBumDes() {
hierarki: 0,
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.nama?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
formData.hierarki !== null &&
formData.hierarki >= 0
);
};
// Fungsi generik untuk update formData
const handleChange = (field: keyof typeof formData, value: any) => {
setFormData(prev => ({ ...prev, [field]: value }));
@@ -173,8 +190,11 @@ function EditPosisiOrganisasiBumDes() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -15,6 +15,23 @@ function CreatePosisiOrganisasiBumDes() {
const stateOrganisasi = useProxy(stateStrukturBumDes.posisiOrganisasi);
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
stateOrganisasi.create.form.nama?.trim() !== '' &&
!isHtmlEmpty(stateOrganisasi.create.form.deskripsi) &&
stateOrganisasi.create.form.hierarki !== null &&
stateOrganisasi.create.form.hierarki >= 0
);
};
useEffect(() => {
stateOrganisasi.findMany.load();
}, []);
@@ -115,8 +132,11 @@ function CreatePosisiOrganisasiBumDes() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -41,6 +41,17 @@ export default function EditDemografiPekerjaan() {
perempuan: 0,
});
// Check if form is valid
const isFormValid = () => {
return (
formData.pekerjaan?.trim() !== '' &&
formData.lakiLaki !== null &&
formData.lakiLaki >= 0 &&
formData.perempuan !== null &&
formData.perempuan >= 0
);
};
// ✅ Load data hanya sekali di awal (tidak reset form)
useEffect(() => {
if (!id) return;
@@ -186,8 +197,11 @@ export default function EditDemografiPekerjaan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -26,6 +26,17 @@ function CreateDemografiPekerjaan() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
stateDemografi.create.form.pekerjaan?.trim() !== '' &&
stateDemografi.create.form.lakiLaki !== null &&
stateDemografi.create.form.lakiLaki >= 0 &&
stateDemografi.create.form.perempuan !== null &&
stateDemografi.create.form.perempuan >= 0
);
};
const resetForm = () => {
stateDemografi.create.form = {
pekerjaan: '',
@@ -128,8 +139,11 @@ function CreateDemografiPekerjaan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -37,6 +37,16 @@ function EditJumlahPendudukMiskin() {
totalPoorPopulation: 0,
});
// Check if form is valid
const isFormValid = () => {
return (
formData.year !== null &&
formData.year > 0 &&
formData.totalPoorPopulation !== null &&
formData.totalPoorPopulation >= 0
);
};
// 🔹 Load data awal dari backend
useEffect(() => {
if (!id) return;
@@ -160,8 +170,11 @@ function EditJumlahPendudukMiskin() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -16,6 +16,16 @@ export default function CreateJumlahPendudukMiskin() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
stateJPM.create.form.year !== null &&
stateJPM.create.form.year > 0 &&
stateJPM.create.form.totalPoorPopulation !== null &&
stateJPM.create.form.totalPoorPopulation >= 0
);
};
const resetForm = () => {
stateJPM.create.form = {
year: new Date().getFullYear(),
@@ -105,8 +115,11 @@ export default function CreateJumlahPendudukMiskin() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -33,6 +33,17 @@ function EditGrafikBerdasarkanPendidikan() {
S1: '',
});
// Check if form is valid
const isFormValid = () => {
return (
formData.SD?.trim() !== '' &&
formData.SMP?.trim() !== '' &&
formData.SMA?.trim() !== '' &&
formData.D3?.trim() !== '' &&
formData.S1?.trim() !== ''
);
};
useEffect(() => {
if (id) {
stategrafik.findUnique.load(id).then(() => {
@@ -174,8 +185,11 @@ function EditGrafikBerdasarkanPendidikan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -16,6 +16,17 @@ function CreateGrafikBerdasarkanPendidikan() {
const [donutData, setDonutData] = useState<any[]>([]);
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
stategrafik.create.form.SD?.trim() !== '' &&
stategrafik.create.form.SMP?.trim() !== '' &&
stategrafik.create.form.SMA?.trim() !== '' &&
stategrafik.create.form.D3?.trim() !== '' &&
stategrafik.create.form.S1?.trim() !== ''
);
};
const resetForm = () => {
stategrafik.create.form = {
...stategrafik.create.form,
@@ -127,8 +138,11 @@ function CreateGrafikBerdasarkanPendidikan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -43,6 +43,16 @@ function EditGrafikBerdasarkanUsiaKerjaYangMenganggur() {
usia46_keatas: '',
});
// Check if form is valid
const isFormValid = () => {
return (
formData.usia18_25?.trim() !== '' &&
formData.usia26_35?.trim() !== '' &&
formData.usia36_45?.trim() !== '' &&
formData.usia46_keatas?.trim() !== ''
);
};
// load data dari global state -> masukin ke local state
useEffect(() => {
if (id) {
@@ -179,8 +189,11 @@ function EditGrafikBerdasarkanUsiaKerjaYangMenganggur() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -17,6 +17,16 @@ function CreateGrafikBerdasarkanUsiaKerjaYangMenganggur() {
const [donutData, setDonutData] = useState<any[]>([]);
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
stategrafik.create.form.usia18_25?.trim() !== '' &&
stategrafik.create.form.usia26_35?.trim() !== '' &&
stategrafik.create.form.usia36_45?.trim() !== '' &&
stategrafik.create.form.usia46_keatas?.trim() !== ''
);
};
const resetForm = () => {
stategrafik.create.form = {
...stategrafik.create.form,
@@ -120,8 +130,11 @@ function CreateGrafikBerdasarkanUsiaKerjaYangMenganggur() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -53,6 +53,19 @@ function EditDetailDataPengangguran() {
percentageChange: 0,
});
// Check if form is valid
const isFormValid = () => {
return (
formData.month?.trim() !== '' &&
formData.year !== null &&
formData.year > 0 &&
formData.educatedUnemployment !== null &&
formData.educatedUnemployment >= 0 &&
formData.uneducatedUnemployment !== null &&
formData.uneducatedUnemployment >= 0
);
};
// --- hitung total + persentase perubahan
const calculateTotalAndChange = useCallback(
async (data: typeof formData) => {
@@ -255,8 +268,11 @@ function EditDetailDataPengangguran() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -27,6 +27,19 @@ function CreateJumlahPengangguran() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
stateDetail.create.form.month?.trim() !== '' &&
stateDetail.create.form.year !== null &&
stateDetail.create.form.year > 0 &&
stateDetail.create.form.educatedUnemployment !== null &&
stateDetail.create.form.educatedUnemployment >= 0 &&
stateDetail.create.form.uneducatedUnemployment !== null &&
stateDetail.create.form.uneducatedUnemployment >= 0
);
};
const monthOptions = [
'Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun',
'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'
@@ -204,8 +217,11 @@ function CreateJumlahPengangguran() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -48,6 +48,27 @@ function EditLowonganKerja() {
notelp: '',
})
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.posisi?.trim() !== '' &&
formData.namaPerusahaan?.trim() !== '' &&
formData.notelp?.trim() !== '' &&
formData.lokasi?.trim() !== '' &&
formData.tipePekerjaan?.trim() !== '' &&
formData.gaji?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
!isHtmlEmpty(formData.kualifikasi)
);
};
// load data sekali aja ketika mount / id berubah
useEffect(() => {
const loadLowongan = async () => {
@@ -229,8 +250,11 @@ function EditLowonganKerja() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -24,6 +24,27 @@ function CreateLowonganKerja() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
lowonganState.create.form.posisi?.trim() !== '' &&
lowonganState.create.form.namaPerusahaan?.trim() !== '' &&
lowonganState.create.form.notelp?.trim() !== '' &&
lowonganState.create.form.lokasi?.trim() !== '' &&
lowonganState.create.form.tipePekerjaan?.trim() !== '' &&
lowonganState.create.form.gaji?.trim() !== '' &&
!isHtmlEmpty(lowonganState.create.form.deskripsi) &&
!isHtmlEmpty(lowonganState.create.form.kualifikasi)
);
};
const resetForm = () => {
lowonganState.create.form = {
posisi: '',
@@ -175,8 +196,11 @@ function CreateLowonganKerja() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -28,6 +28,11 @@ function EditKategoriProduk() {
const [formData, setFormData] = useState({ nama: '' });
const [originalData, setOriginalData] = useState({ nama: '' });
// Check if form is valid
const isFormValid = () => {
return formData.nama?.trim() !== '';
};
useEffect(() => {
const loadKategoriProduk = async () => {
if (!id) return;
@@ -146,8 +151,11 @@ function EditKategoriProduk() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -23,6 +23,11 @@ function CreateKategoriProduk() {
const statePasar = useProxy(pasarDesaState.kategoriProduk);
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return statePasar.create.form.nama?.trim() !== '';
};
useEffect(() => {
statePasar.findMany.load();
}, []);
@@ -101,8 +106,11 @@ function CreateKategoriProduk() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -68,6 +68,23 @@ function EditPasarDesa() {
deskripsi: ''
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.nama?.trim() !== '' &&
formData.harga !== null &&
formData.harga > 0 &&
!isHtmlEmpty(formData.deskripsi)
);
};
// load data awal
useEffect(() => {
pasarState.kategoriProduk.findManyAll.load();
@@ -352,8 +369,11 @@ function EditPasarDesa() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -32,6 +32,24 @@ export default function CreatePasarDesa() {
const [file, setFile] = useState<File | null>(null);
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
statePasar.pasarDesa.create.form.nama?.trim() !== '' &&
statePasar.pasarDesa.create.form.harga !== null &&
statePasar.pasarDesa.create.form.harga > 0 &&
!isHtmlEmpty(statePasar.pasarDesa.create.form.deskripsi) &&
file !== null
);
};
useEffect(() => {
statePasar.kategoriProduk.findManyAll.load();
}, []);
@@ -265,8 +283,11 @@ export default function CreatePasarDesa() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -53,6 +53,24 @@ function EditProgramKemiskinan() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [originalData, setOriginalData] = useState<FormData>(initialForm);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.nama?.trim() !== '' &&
formData.icon?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
formData.statistik.jumlah?.trim() !== '' &&
formData.statistik.tahun?.trim() !== ''
);
};
// Load data 1x dari global state → isi local state
useEffect(() => {
if (!id) return;
@@ -235,8 +253,11 @@ function EditProgramKemiskinan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -29,6 +29,25 @@ function CreateProgramKemiskinan() {
const [lineChart, setLineChart] = useState<any[]>([]);
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
programState.create.form.nama?.trim() !== '' &&
programState.create.form.icon?.trim() !== '' &&
!isHtmlEmpty(programState.create.form.deskripsi) &&
programState.create.form.statistik.jumlah?.trim() !== '' &&
programState.create.form.statistik.tahun?.trim() !== ''
);
};
const resetForm = () => {
programState.create.form = {
nama: '',
@@ -172,8 +191,11 @@ function CreateProgramKemiskinan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -41,6 +41,23 @@ function EditSektorUnggulanDesa() {
value: 0,
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
!isHtmlEmpty(formData.description) &&
formData.value !== null &&
formData.value >= 0
);
};
// Load data saat komponen mount
useEffect(() => {
if (id) {
@@ -168,8 +185,11 @@ function EditSektorUnggulanDesa() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -27,6 +27,23 @@ function CreateSektorUnggulanDesa() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
stateGrafik.create.form.name?.trim() !== '' &&
!isHtmlEmpty(stateGrafik.create.form.description) &&
stateGrafik.create.form.value !== null &&
stateGrafik.create.form.value >= 0
);
};
const resetForm = () => {
stateGrafik.create.form = {
name: '',
@@ -132,8 +149,11 @@ function CreateSektorUnggulanDesa() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -44,6 +44,21 @@ function EditDigitalSmartVillage() {
imageUrl: '',
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi)
);
};
useEffect(() => {
const loadData = async () => {
const id = params?.id as string;
@@ -248,8 +263,11 @@ function EditDigitalSmartVillage() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -30,6 +30,22 @@ export default function CreateDesaDigital() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
stateDesaDigital.create.form.name?.trim() !== '' &&
!isHtmlEmpty(stateDesaDigital.create.form.deskripsi) &&
file !== null
);
};
const resetForm = () => {
stateDesaDigital.create.form = {
name: '',
@@ -227,8 +243,11 @@ export default function CreateDesaDigital() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -44,6 +44,21 @@ function EditInfoTeknologiTepatGuna() {
imageUrl: '',
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi)
);
};
// Load data pertama kali
useEffect(() => {
const id = params?.id as string;
@@ -260,8 +275,11 @@ function EditInfoTeknologiTepatGuna() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -30,6 +30,22 @@ function CreateInfoTeknologiTepatGuna() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
stateInfoTekno.create.form.name?.trim() !== '' &&
!isHtmlEmpty(stateInfoTekno.create.form.deskripsi) &&
file !== null
);
};
const resetForm = () => {
stateInfoTekno.create.form = {
name: '',
@@ -202,8 +218,11 @@ function CreateInfoTeknologiTepatGuna() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -44,6 +44,23 @@ function EditKolaborasiInovasi() {
kolaborator: "",
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.slug?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
formData.kolaborator?.trim() !== ''
);
};
// Load data awal dari server
useEffect(() => {
const loadKolaborasi = async () => {
@@ -199,8 +216,11 @@ function EditKolaborasiInovasi() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -16,6 +16,22 @@ function CreateProgramKreatifDesa() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
stateCreate.create.form.name?.trim() !== '' &&
stateCreate.create.form.slug?.trim() !== '' &&
!isHtmlEmpty(stateCreate.create.form.deskripsi)
);
};
const resetForm = () => {
stateCreate.create.form = {
name: "",
@@ -135,8 +151,11 @@ function CreateProgramKreatifDesa() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -51,6 +51,11 @@ function EditMitraKolaborasi() {
imageUrl: '',
});
// Check if form is valid
const isFormValid = () => {
return formData.name?.trim() !== '';
};
// Load data ke state lokal sekali saja
useEffect(() => {
const loadData = async () => {
@@ -263,8 +268,11 @@ function EditMitraKolaborasi() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -29,6 +29,14 @@ function CreateMitraKolaborasi() {
const [file, setFile] = useState<File | null>(null);
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
state.create.form.name?.trim() !== '' &&
file !== null
);
};
const resetForm = () => {
state.create.form = {
name: '',
@@ -181,8 +189,11 @@ function CreateMitraKolaborasi() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -51,6 +51,23 @@ function EditProgramKreatifDesa() {
const [isDataChanged, setIsDataChanged] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.slug?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi) &&
formData.icon?.trim() !== ''
);
};
// Load data hanya sekali berdasarkan params.id
useEffect(() => {
const loadProgramKreatif = async () => {
@@ -236,8 +253,11 @@ function EditProgramKreatifDesa() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -25,6 +25,23 @@ function CreateProgramKreatifDesa() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
stateCreate.create.form.name?.trim() !== '' &&
stateCreate.create.form.icon?.trim() !== '' &&
stateCreate.create.form.slug?.trim() !== '' &&
!isHtmlEmpty(stateCreate.create.form.deskripsi)
);
};
const resetForm = () => {
stateCreate.create.form = {
name: "",
@@ -127,8 +144,11 @@ function CreateProgramKreatifDesa() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -53,6 +53,21 @@ function EditKeamananLingkungan() {
imageUrl: "",
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi)
);
};
// Load data sekali pas mount
useEffect(() => {
const loadData = async () => {
@@ -294,8 +309,11 @@ function EditKeamananLingkungan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -35,6 +35,22 @@ function CreateKeamananLingkungan() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false)
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
keamananState.create.form.name?.trim() !== '' &&
!isHtmlEmpty(keamananState.create.form.deskripsi) &&
file !== null
);
};
const resetForm = () => {
keamananState.create.form = {
name: '',
@@ -237,8 +253,11 @@ function CreateKeamananLingkungan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -39,6 +39,15 @@ function EditKontakItem() {
icon: '',
});
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.nomorTelepon?.trim() !== '' &&
formData.icon?.trim() !== ''
);
};
// Load data sekali dari global state
useEffect(() => {
const loadKontakDarurat = async () => {
@@ -170,8 +179,11 @@ function EditKontakItem() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -23,6 +23,16 @@ function CreateKontakItem() {
const kontakState = useProxy(kontakDarurat.kontakDaruratItem);
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
kontakState.create.form.nama?.trim() !== '' &&
kontakState.create.form.nomorTelepon?.trim() !== '' &&
kontakState.create.form.icon?.trim() !== ''
);
};
const resetForm = () => {
kontakState.create.form = {
nama: '',
@@ -115,8 +125,11 @@ function CreateKontakItem() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -46,6 +46,14 @@ export default function EditKontakDaruratKeamanan() {
kategoriId: [],
});
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.kategoriId.length > 0
);
};
// 🔁 Load data saat ID berubah
useEffect(() => {
const loadInitialData = async () => {
@@ -213,8 +221,11 @@ export default function EditKontakDaruratKeamanan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -26,6 +26,14 @@ function CreateKontakDaruratKeamanan() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
kontakState.create.form.nama?.trim() !== '' &&
kontakState.create.form.icon?.trim() !== ''
);
};
useShallowEffect(() => {
kontakDarurat.kontakDaruratItem.findMany.load();
}, []);
@@ -127,8 +135,11 @@ function CreateKontakDaruratKeamanan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -55,6 +55,25 @@ function EditLaporanPublik() {
kronologi: '',
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.judul?.trim() !== '' &&
formData.lokasi?.trim() !== '' &&
formData.tanggalWaktu?.trim() !== '' &&
formData.status?.trim() !== '' &&
!isHtmlEmpty(formData.kronologi) &&
!isHtmlEmpty(formData.penanganan)
);
};
useEffect(() => {
const loadLaporanPublik = async () => {
const id = params?.id as string;
@@ -223,8 +242,11 @@ function EditLaporanPublik() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -26,6 +26,16 @@ function CreateLaporanPublik() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
stateLaporan.create.form.judul?.trim() !== '' &&
stateLaporan.create.form.lokasi?.trim() !== '' &&
stateLaporan.create.form.tanggalWaktu?.trim() !== '' &&
stateLaporan.create.form.kronologi?.trim() !== ''
);
};
const resetForm = () => {
stateLaporan.create.form = {
judul: '',
@@ -123,8 +133,11 @@ function CreateLaporanPublik() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -41,6 +41,23 @@ function EditPencegahanKriminalitas() {
linkVideo: '',
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.judul?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsiSingkat) &&
!isHtmlEmpty(formData.deskripsi) &&
convertYoutubeUrlToEmbed(formData.linkVideo) !== ''
);
};
// load data hanya sekali pas id berubah
useEffect(() => {
const loadKriminalitas = async () => {
@@ -220,8 +237,11 @@ function EditPencegahanKriminalitas() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -28,6 +28,23 @@ function CreatePencegahanKriminalitas() {
const embedLink = convertYoutubeUrlToEmbed(link);
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
kriminalitasState.create.form.judul?.trim() !== '' &&
!isHtmlEmpty(kriminalitasState.create.form.deskripsiSingkat) &&
!isHtmlEmpty(kriminalitasState.create.form.deskripsi) &&
embedLink !== ''
);
};
const resetForm = () => {
kriminalitasState.create.form = {
judul: "",
@@ -165,8 +182,11 @@ function CreatePencegahanKriminalitas() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -67,6 +67,17 @@ function EditPolsekTerdekat() {
layananPolsekId: []
});
// Check if form is valid
const isFormValid = () => {
return (
formData.nama?.trim() !== '' &&
formData.jarakKeDesa?.trim() !== '' &&
formData.alamat?.trim() !== '' &&
formData.nomorTelepon?.trim() !== '' &&
formData.layananPolsekId.length > 0
);
};
useEffect(() => {
statePolsekTerdekat.layananPolsek.findManyAll.load();
}, []);
@@ -261,8 +272,11 @@ function EditPolsekTerdekat() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -24,6 +24,17 @@ function CreatePolsekTerdekat() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
polsekState.create.form.nama?.trim() !== '' &&
polsekState.create.form.jarakKeDesa?.trim() !== '' &&
polsekState.create.form.alamat?.trim() !== '' &&
polsekState.create.form.nomorTelepon?.trim() !== '' &&
polsekState.create.form.layananPolsekId.length > 0
);
};
useEffect(() => {
statePolsekTerdekat.layananPolsek.findManyAll.load();
}, []);
@@ -219,8 +230,11 @@ function CreatePolsekTerdekat() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -33,6 +33,11 @@ function EditLayananPolsek() {
nama: '',
});
// Check if form is valid
const isFormValid = () => {
return formData.nama?.trim() !== '';
};
useEffect(() => {
const loadLayananPolsek = async () => {
const id = params?.id as string;
@@ -143,8 +148,11 @@ function EditLayananPolsek() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -22,6 +22,11 @@ function CreateLayananPolsek() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return createState.create.form.nama?.trim() !== '';
};
const resetForm = () => {
createState.create.form = {
nama: '',
@@ -93,8 +98,11 @@ function CreateLayananPolsek() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -52,6 +52,21 @@ function EditTipsKeamanan() {
imageUrl: "",
});
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.judul?.trim() !== '' &&
!isHtmlEmpty(formData.deskripsi)
);
};
// Load data saat pertama kali
useEffect(() => {
const loadData = async () => {
@@ -295,8 +310,11 @@ function EditTipsKeamanan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -30,6 +30,22 @@ function CreateKeamananLingkungan() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
stateKeamanan.create.form.judul?.trim() !== '' &&
!isHtmlEmpty(stateKeamanan.create.form.deskripsi) &&
file !== null
);
};
const resetForm = () => {
stateKeamanan.create.form = {
judul: '',
@@ -199,8 +215,11 @@ function CreateKeamananLingkungan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -30,6 +30,33 @@ function CreateArtikelKesehatan() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
stateArtikelKesehatan.create.form.title?.trim() !== '' &&
stateArtikelKesehatan.create.form.content?.trim() !== '' &&
!isHtmlEmpty(stateArtikelKesehatan.create.form.introduction.content) &&
stateArtikelKesehatan.create.form.symptom.title?.trim() !== '' &&
!isHtmlEmpty(stateArtikelKesehatan.create.form.symptom.content) &&
stateArtikelKesehatan.create.form.prevention.title?.trim() !== '' &&
!isHtmlEmpty(stateArtikelKesehatan.create.form.prevention.content) &&
stateArtikelKesehatan.create.form.firstAid.title?.trim() !== '' &&
!isHtmlEmpty(stateArtikelKesehatan.create.form.firstAid.content) &&
stateArtikelKesehatan.create.form.mythVsFact.title?.trim() !== '' &&
!isHtmlEmpty(stateArtikelKesehatan.create.form.mythVsFact.mitos) &&
!isHtmlEmpty(stateArtikelKesehatan.create.form.mythVsFact.fakta) &&
!isHtmlEmpty(stateArtikelKesehatan.create.form.doctorSign.content) &&
file !== null
);
};
const resetForm = () => {
stateArtikelKesehatan.create.form = {
title: '',
@@ -65,10 +92,79 @@ function CreateArtikelKesehatan() {
const handleSubmit = async (e?: React.FormEvent) => {
e?.preventDefault();
if (!stateArtikelKesehatan.create.form.title?.trim()) {
toast.error('Judul wajib diisi');
return;
}
if (!stateArtikelKesehatan.create.form.content?.trim()) {
toast.error('Deskripsi wajib diisi');
return;
}
if (isHtmlEmpty(stateArtikelKesehatan.create.form.introduction.content)) {
toast.error('Pendahuluan wajib diisi');
return;
}
if (!stateArtikelKesehatan.create.form.symptom.title?.trim()) {
toast.error('Judul gejala wajib diisi');
return;
}
if (isHtmlEmpty(stateArtikelKesehatan.create.form.symptom.content)) {
toast.error('Deskripsi gejala wajib diisi');
return;
}
if (!stateArtikelKesehatan.create.form.prevention.title?.trim()) {
toast.error('Judul pencegahan wajib diisi');
return;
}
if (isHtmlEmpty(stateArtikelKesehatan.create.form.prevention.content)) {
toast.error('Deskripsi pencegahan wajib diisi');
return;
}
if (!stateArtikelKesehatan.create.form.firstAid.title?.trim()) {
toast.error('Judul pertolongan pertama wajib diisi');
return;
}
if (isHtmlEmpty(stateArtikelKesehatan.create.form.firstAid.content)) {
toast.error('Deskripsi pertolongan pertama wajib diisi');
return;
}
if (!stateArtikelKesehatan.create.form.mythVsFact.title?.trim()) {
toast.error('Judul mitos vs fakta wajib diisi');
return;
}
if (isHtmlEmpty(stateArtikelKesehatan.create.form.mythVsFact.mitos)) {
toast.error('Deskripsi mitos wajib diisi');
return;
}
if (isHtmlEmpty(stateArtikelKesehatan.create.form.mythVsFact.fakta)) {
toast.error('Deskripsi fakta wajib diisi');
return;
}
if (isHtmlEmpty(stateArtikelKesehatan.create.form.doctorSign.content)) {
toast.error('Deskripsi kapan harus ke dokter wajib diisi');
return;
}
if (!file) {
toast.error('Gambar wajib dipilih');
return;
}
try {
if (!file) {
return toast.warn('Silakan pilih file gambar terlebih dahulu');
}
setIsSubmitting(true);
const res = await ApiFetch.api.fileStorage.create.post({
file,
@@ -344,8 +440,11 @@ function CreateArtikelKesehatan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -45,6 +45,28 @@ function EditFasilitasKesehatan() {
const params = useParams<{ id: string }>();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.informasiUmum.fasilitas?.trim() !== '' &&
formData.informasiUmum.alamat?.trim() !== '' &&
formData.informasiUmum.jamOperasional?.trim() !== '' &&
!isHtmlEmpty(formData.layananUnggulan.content) &&
formData.dokterdanTenagaMedis.length > 0 &&
!isHtmlEmpty(formData.fasilitasPendukung.content) &&
!isHtmlEmpty(formData.prosedurPendaftaran.content) &&
formData.tarifDanLayanan.length > 0
);
};
const [formData, setFormData] = useState<EditFasilitasKesehatanForm>({
name: '',
informasiUmum: { fasilitas: '', alamat: '', jamOperasional: '' },
@@ -111,6 +133,52 @@ function EditFasilitasKesehatan() {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!formData.name?.trim()) {
toast.error('Nama fasilitas kesehatan wajib diisi');
return;
}
if (!formData.informasiUmum.fasilitas?.trim()) {
toast.error('Fasilitas wajib diisi');
return;
}
if (!formData.informasiUmum.alamat?.trim()) {
toast.error('Alamat wajib diisi');
return;
}
if (!formData.informasiUmum.jamOperasional?.trim()) {
toast.error('Jam operasional wajib diisi');
return;
}
if (isHtmlEmpty(formData.layananUnggulan.content)) {
toast.error('Layanan unggulan wajib diisi');
return;
}
if (formData.dokterdanTenagaMedis.length === 0) {
toast.error('Dokter dan tenaga medis wajib dipilih');
return;
}
if (isHtmlEmpty(formData.fasilitasPendukung.content)) {
toast.error('Fasilitas pendukung wajib diisi');
return;
}
if (formData.tarifDanLayanan.length === 0) {
toast.error('Tarif dan layanan wajib dipilih');
return;
}
if (isHtmlEmpty(formData.prosedurPendaftaran.content)) {
toast.error('Prosedur pendaftaran wajib diisi');
return;
}
try {
setIsSubmitting(true);
@@ -264,8 +332,11 @@ function EditFasilitasKesehatan() {
<Button
type="submit"
radius="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -26,6 +26,28 @@ function CreateFasilitasKesehatan() {
const router = useRouter();
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if HTML content is empty
const isHtmlEmpty = (html: string) => {
// Remove all HTML tags and check if there's any text content
const textContent = html.replace(/<[^>]*>/g, '').trim();
return textContent === '';
};
// Check if form is valid
const isFormValid = () => {
return (
stateFasilitasKesehatan.create.form.name?.trim() !== '' &&
stateFasilitasKesehatan.create.form.informasiUmum.fasilitas?.trim() !== '' &&
stateFasilitasKesehatan.create.form.informasiUmum.alamat?.trim() !== '' &&
stateFasilitasKesehatan.create.form.informasiUmum.jamOperasional?.trim() !== '' &&
!isHtmlEmpty(stateFasilitasKesehatan.create.form.layananUnggulan.content) &&
stateFasilitasKesehatan.create.form.dokterdanTenagaMedis.length > 0 &&
!isHtmlEmpty(stateFasilitasKesehatan.create.form.fasilitasPendukung.content) &&
stateFasilitasKesehatan.create.form.tarifDanLayanan.length > 0 &&
!isHtmlEmpty(stateFasilitasKesehatan.create.form.prosedurPendaftaran.content)
);
};
const resetForm = () => {
stateFasilitasKesehatan.create.form = {
name: '',
@@ -50,6 +72,52 @@ function CreateFasilitasKesehatan() {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!stateFasilitasKesehatan.create.form.name?.trim()) {
toast.error('Nama fasilitas kesehatan wajib diisi');
return;
}
if (!stateFasilitasKesehatan.create.form.informasiUmum.fasilitas?.trim()) {
toast.error('Fasilitas wajib diisi');
return;
}
if (!stateFasilitasKesehatan.create.form.informasiUmum.alamat?.trim()) {
toast.error('Alamat wajib diisi');
return;
}
if (!stateFasilitasKesehatan.create.form.informasiUmum.jamOperasional?.trim()) {
toast.error('Jam operasional wajib diisi');
return;
}
if (isHtmlEmpty(stateFasilitasKesehatan.create.form.layananUnggulan.content)) {
toast.error('Layanan unggulan wajib diisi');
return;
}
if (stateFasilitasKesehatan.create.form.dokterdanTenagaMedis.length === 0) {
toast.error('Dokter dan tenaga medis wajib dipilih');
return;
}
if (isHtmlEmpty(stateFasilitasKesehatan.create.form.fasilitasPendukung.content)) {
toast.error('Fasilitas pendukung wajib diisi');
return;
}
if (stateFasilitasKesehatan.create.form.tarifDanLayanan.length === 0) {
toast.error('Layanan wajib dipilih');
return;
}
if (isHtmlEmpty(stateFasilitasKesehatan.create.form.prosedurPendaftaran.content)) {
toast.error('Prosedur pendaftaran wajib diisi');
return;
}
try {
setIsSubmitting(true);
await stateFasilitasKesehatan.create.submit();
@@ -214,8 +282,11 @@ function CreateFasilitasKesehatan() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

View File

@@ -29,6 +29,20 @@ function EditDokterTenagaMedis() {
const params = useParams();
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.specialist?.trim() !== '' &&
formData.jadwal?.trim() !== '' &&
formData.jadwalLibur?.trim() !== '' &&
formData.jamBukaOperasional !== '' &&
formData.jamTutupOperasional !== '' &&
formData.jamBukaLibur !== '' &&
formData.jamTutupLibur !== ''
);
};
const [formData, setFormData] = useState({
name: '',
specialist: '',
@@ -108,6 +122,46 @@ function EditDokterTenagaMedis() {
// Submit
const handleSubmit = async () => {
if (!formData.name?.trim()) {
toast.error('Nama dokter wajib diisi');
return;
}
if (!formData.specialist?.trim()) {
toast.error('Specialist wajib diisi');
return;
}
if (!formData.jadwal?.trim()) {
toast.error('Jadwal wajib diisi');
return;
}
if (!formData.jadwalLibur?.trim()) {
toast.error('Jadwal libur wajib diisi');
return;
}
if (!formData.jamBukaOperasional) {
toast.error('Jam buka operasional wajib diisi');
return;
}
if (!formData.jamTutupOperasional) {
toast.error('Jam tutup operasional wajib diisi');
return;
}
if (!formData.jamBukaLibur) {
toast.error('Jam buka hari libur wajib diisi');
return;
}
if (!formData.jamTutupLibur) {
toast.error('Jam tutup hari libur wajib diisi');
return;
}
try {
setIsSubmitting(true);
state.update.form = { ...state.update.form, ...formData };
@@ -223,8 +277,11 @@ function EditDokterTenagaMedis() {
onClick={handleSubmit}
radius="md"
size="md"
disabled={!isFormValid() || isSubmitting}
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || isSubmitting
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
color: '#fff',
boxShadow: '0 4px 15px rgba(79, 172, 254, 0.4)',
}}

Some files were not shown because too many files have changed in this diff Show More