feat: implement form validation for empty fields across multiple admin pages

- Added validation to disable submit buttons when required fields are empty
- Implemented consistent validation patterns across various admin pages
- Applied validation to create and edit forms for berita, gallery, layanan, penghargaan, pengumuman, potensi, profil-desa, and ppid sections
- Used helper functions to check for empty HTML content in editor fields
- Ensured submit buttons are disabled until all required fields are filled

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-02-14 14:17:17 +08:00
parent b35874b120
commit 9678e6979b
41 changed files with 1131 additions and 83 deletions

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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -28,6 +28,15 @@ function EditDaftarInformasiPublik() {
tanggal: '',
});
// Check if form is valid
const isFormValid = () => {
return (
formData.jenisInformasi?.trim() !== '' &&
formData.deskripsi?.trim() !== '' &&
formData.tanggal?.trim() !== ''
);
};
const formatDateForInput = (dateString: string) => {
if (!dateString) return '';
const date = new Date(dateString);
@@ -128,10 +137,13 @@ function EditDaftarInformasiPublik() {
<Group justify="right" mt="md">
<Button
onClick={handleSubmit}
disabled={!isFormValid()}
radius="md"
size="md"
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid()
? `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

@@ -11,6 +11,15 @@ export default function CreateDaftarInformasi() {
const daftarInformasi = useProxy(daftarInformasiPublik);
const router = useRouter();
// Check if form is valid
const isFormValid = () => {
return (
daftarInformasi.create.form.jenisInformasi?.trim() !== '' &&
daftarInformasi.create.form.deskripsi?.trim() !== '' &&
daftarInformasi.create.form.tanggal?.trim() !== ''
);
};
const resetForm = () => {
daftarInformasi.create.form = {
jenisInformasi: "",
@@ -106,10 +115,13 @@ export default function CreateDaftarInformasi() {
<Button
onClick={handleSubmit}
loading={daftarInformasi.create.loading}
disabled={!isFormValid() || daftarInformasi.create.loading}
radius="md"
size="md"
style={{
background: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
background: !isFormValid() || daftarInformasi.create.loading
? `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,21 @@ function EditDasarHukum() {
content: '',
});
// Helper function to check if rich text content is empty
const isRichTextEmpty = (content: string) => {
// Remove HTML tags and check if the resulting text is empty
const plainText = content.replace(/<[^>]*>/g, '').trim();
return plainText === '' || content.trim() === '<p></p>' || content.trim() === '<p><br></p>';
};
// Check if form is valid
const isFormValid = () => {
return (
!isRichTextEmpty(formData.judul) &&
!isRichTextEmpty(formData.content)
);
};
// Load data awal sekali
useShallowEffect(() => {
if (!dasarHukumState.findById.data) {
@@ -137,8 +152,11 @@ function EditDasarHukum() {
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

@@ -57,6 +57,17 @@ function EditResponden() {
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
formData.name?.trim() !== '' &&
formData.tanggal?.trim() !== '' &&
formData.jenisKelaminId?.trim() !== '' &&
formData.ratingId?.trim() !== '' &&
formData.kelompokUmurId?.trim() !== ''
);
};
// 🔹 Load data pilihan select
const loadSelectOptions = useCallback(() => {
indeksKepuasanState.jenisKelaminResponden.findMany.load();
@@ -231,8 +242,11 @@ function EditResponden() {
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 RespondenCreate() {
const [donutData, setDonutData] = useState<any[]>([]);
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
stategrafikBerdasarkanResponden.create.form.name?.trim() !== '' &&
stategrafikBerdasarkanResponden.create.form.tanggal?.trim() !== '' &&
stategrafikBerdasarkanResponden.create.form.jenisKelaminId?.trim() !== '' &&
stategrafikBerdasarkanResponden.create.form.ratingId?.trim() !== '' &&
stategrafikBerdasarkanResponden.create.form.kelompokUmurId?.trim() !== ''
);
};
const resetForm = () => {
stategrafikBerdasarkanResponden.create.form = {
...stategrafikBerdasarkanResponden.create.form,
@@ -151,8 +162,11 @@ function RespondenCreate() {
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,12 @@ export default function EditPegawaiPPID() {
const [previewImage, setPreviewImage] = useState<string | null>(null);
const [file, setFile] = useState<File | null>(null);
// Helper function to validate email format
const isValidEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
// Format date for <input type="date">
const formatDateForInput = (dateString: string) => {
if (!dateString) return '';
@@ -63,6 +69,20 @@ export default function EditPegawaiPPID() {
return date.toISOString().split('T')[0];
};
// Check if form is valid
const isFormValid = () => {
return (
formData.namaLengkap?.trim() !== '' &&
formData.gelarAkademik?.trim() !== '' &&
formData.posisiId !== '' &&
formData.tanggalMasuk !== '' &&
formData.email !== '' &&
isValidEmail(formData.email) &&
formData.telepon !== '' &&
formData.alamat !== ''
);
};
useEffect(() => {
const loadPegawai = async () => {
try {
@@ -347,8 +367,11 @@ export default function EditPegawaiPPID() {
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 CreatePegawaiPPID() {
resetForm();
}, []);
// Helper function to validate email format
const isValidEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
// Check if form is valid
const isFormValid = () => {
return (
stateOrganisasi.create.form.namaLengkap?.trim() !== '' &&
stateOrganisasi.create.form.gelarAkademik?.trim() !== '' &&
stateOrganisasi.create.form.posisiId !== '' &&
stateOrganisasi.create.form.tanggalMasuk !== '' &&
stateOrganisasi.create.form.email !== '' &&
isValidEmail(stateOrganisasi.create.form.email) &&
stateOrganisasi.create.form.telepon !== '' &&
stateOrganisasi.create.form.alamat !== '' &&
file !== null
);
};
const resetForm = () => {
stateOrganisasi.create.form = {
namaLengkap: "",
@@ -78,7 +99,7 @@ function CreatePegawaiPPID() {
};
return (
<Box px={{ base: 0, md: 'lg' }} py="xs">
<Box px={{ base: 0, md: 'lg' }} py="xs">
<Group mb="md">
<Button variant="subtle" onClick={() => router.back()} p="xs" radius="md">
<IconArrowBack color={colors['blue-button']} size={24} />
@@ -99,15 +120,16 @@ function CreatePegawaiPPID() {
<Stack gap="md">
<Box>
<TextInput
required
label="Nama Lengkap"
placeholder="Masukkan nama lengkap"
value={stateOrganisasi.create.form.namaLengkap}
onChange={(e) => (stateOrganisasi.create.form.namaLengkap = e.currentTarget.value)}
required
/>
</Box>
<Box>
<TextInput
required
label="Gelar Akademik"
placeholder="Contoh: S.Kom"
value={stateOrganisasi.create.form.gelarAkademik}
@@ -191,6 +213,7 @@ function CreatePegawaiPPID() {
</Box>
<Box>
<TextInput
required
label="Tanggal Masuk"
type="date"
placeholder="Contoh: 2022-01-01"
@@ -201,6 +224,7 @@ function CreatePegawaiPPID() {
<Box>
<TextInput
required
label="Email"
type="email"
placeholder="Contoh: email@example.com"
@@ -211,6 +235,7 @@ function CreatePegawaiPPID() {
<Box>
<TextInput
required
type='number'
label="Nomor Telepon"
placeholder="Contoh: 08123456789"
@@ -221,6 +246,7 @@ function CreatePegawaiPPID() {
<Box>
<TextInput
required
label="Alamat"
placeholder="Contoh: Jl. Contoh No. 1"
value={stateOrganisasi.create.form.alamat}
@@ -229,35 +255,8 @@ function CreatePegawaiPPID() {
</Box>
<Box>
<Text fw="bold" fz="sm" mb={6}>
Posisi
</Text>
<Select
label="Kategori"
placeholder="Pilih kategori"
data={stateStrukturPPID.posisiOrganisasi.findManyAll.data?.map((item) => ({
label: item.nama,
value: item.id,
})) || []}
value={stateOrganisasi.create.form.posisiId || null}
onChange={(val: string | null) => {
if (val) {
const selected = stateStrukturPPID.posisiOrganisasi.findManyAll.data?.find(
(item) => item.id === val
);
if (selected) {
stateOrganisasi.create.form.posisiId = selected.id;
}
} else {
stateOrganisasi.create.form.posisiId = '';
}
}}
searchable
clearable
nothingFoundMessage="Tidak ditemukan"
required
/>
{/* <Select
label="Posisi"
placeholder="Pilih posisi"
data={stateStrukturPPID.posisiOrganisasi.findManyAll.data?.map(p => ({
value: p.id,
@@ -269,10 +268,10 @@ function CreatePegawaiPPID() {
}}
searchable
clearable
/> */}
required
/>
</Box>
{/* ======= Tombol Aksi ======= */}
<Group justify="right">
{/* Tombol Batal */}
@@ -291,8 +290,11 @@ function CreatePegawaiPPID() {
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,15 @@ function EditPosisiOrganisasiPPID() {
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
formData.nama?.trim() !== '' &&
formData.hierarki?.toString().trim() !== '' &&
formData.deskripsi?.trim() !== ''
);
};
const [originalData, setOriginalData] = useState({
nama: "",
deskripsi: "",
@@ -174,8 +183,11 @@ function EditPosisiOrganisasiPPID() {
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,15 @@ function CreatePosisiOrganisasiPPID() {
const stateOrganisasi = useProxy(stateStrukturPPID.posisiOrganisasi);
const [isSubmitting, setIsSubmitting] = useState(false);
// Check if form is valid
const isFormValid = () => {
return (
stateOrganisasi.create.form.nama?.trim() !== '' &&
stateOrganisasi.create.form.hierarki?.toString().trim() !== '' &&
stateOrganisasi.create.form.deskripsi?.trim() !== ''
);
};
useEffect(() => {
stateOrganisasi.findMany.load();
}, []);
@@ -115,8 +124,11 @@ function CreatePosisiOrganisasiPPID() {
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

@@ -20,6 +20,21 @@ function VisiMisiPPIDEdit() {
const [originalData, setOriginalData] = useState({ visi: '', misi: '' });
const [isSubmitting, setIsSubmitting] = useState(false);
// Helper function to check if rich text content is empty
const isRichTextEmpty = (content: string) => {
// Remove HTML tags and check if the resulting text is empty
const plainText = content.replace(/<[^>]*>/g, '').trim();
return plainText === '' || content.trim() === '<p></p>' || content.trim() === '<p><br></p>';
};
// Check if form is valid
const isFormValid = () => {
return (
!isRichTextEmpty(formData.visi) &&
!isRichTextEmpty(formData.misi)
);
};
// Initialize global data ke state lokal saat pertama load
useShallowEffect(() => {
if (!visiMisi.findById.data) {
@@ -116,8 +131,11 @@ function VisiMisiPPIDEdit() {
onClick={submit}
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,17 @@ function Kepuasan() {
indeksKepuasanState.kelompokUmurResponden.findMany.load();
}, []);
// Check if form is valid
const isFormValid = () => {
return (
state.create.form.name?.trim() !== '' &&
state.create.form.tanggal?.trim() !== '' &&
state.create.form.jenisKelaminId?.trim() !== '' &&
state.create.form.ratingId?.trim() !== '' &&
state.create.form.kelompokUmurId?.trim() !== ''
);
};
const handleSubmit = async () => {
try {
const id = await state.create.create();
@@ -442,7 +453,17 @@ function Kepuasan() {
disabled={indeksKepuasanState.kelompokUmurResponden.findMany.loading}
labelProps={{ style: { fontSize: '0.95rem', lineHeight: '1.4' } } as any}
/>
<Button mt={10} bg={colors['blue-button']} onClick={handleSubmit}>
<Button
mt={10}
bg={colors['blue-button']}
onClick={handleSubmit}
disabled={!isFormValid()}
style={{
background: !isFormValid()
? `linear-gradient(135deg, #cccccc, #eeeeee)`
: `linear-gradient(135deg, ${colors['blue-button']}, #4facfe)`,
}}
>
Submit
</Button>
</Stack>

View File

@@ -54,6 +54,28 @@ function Page() {
const permohonanInformasiPublikState = useProxy(statePermohonanInformasi);
const router = useRouter();
// Helper function to validate email format
const isValidEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
// Check if form is valid
const isFormValid = () => {
const form = permohonanInformasiPublikState.statepermohonanInformasiPublik.create.form;
return (
form.name?.trim() !== '' &&
form.nik?.trim() !== '' &&
form.notelp?.trim() !== '' &&
form.alamat?.trim() !== '' &&
form.email?.trim() !== '' &&
isValidEmail(form.email) &&
form.jenisInformasiDimintaId &&
form.caraMemperolehInformasiId &&
form.caraMemperolehSalinanInformasiId
);
};
const submitForms = async () => {
const { create } = permohonanInformasiPublikState.statepermohonanInformasiPublik;
const hasil = await create.create();
@@ -266,6 +288,7 @@ function Page() {
bg={colors['blue-button']}
leftSection={<IconSend2 size={20} color={colors['white-1']} />}
onClick={submitForms}
disabled={!isFormValid()}
>
Kirim Permohonan
</Button>

View File

@@ -56,6 +56,24 @@ function Page() {
const stateKeberatan = useProxy(permohonanKeberatanInformasi);
const router = useRouter();
// Helper function to validate email format
const isValidEmail = (email: string) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
// Check if form is valid
const isFormValid = () => {
const form = stateKeberatan.create.form;
return (
form.name?.trim() !== '' &&
form.email?.trim() !== '' &&
isValidEmail(form.email) &&
form.notelp?.trim() !== '' &&
form.alasan?.trim() !== ''
);
};
const submit = async () => {
const hasil = await stateKeberatan.create.create();
if (hasil) router.push('/darmasaba/permohonan/berhasil');
@@ -232,6 +250,7 @@ function Page() {
radius="md"
fw={600}
bg={colors['blue-button']}
disabled={!isFormValid()}
>
Kirim Permohonan
</Button>