From 22d826ba6cc396549a673bafa2df36070d6605cb Mon Sep 17 00:00:00 2001 From: Billy Marcello <145271272+BeLieM@users.noreply.github.com> Date: Sat, 13 Dec 2025 16:27:06 +0700 Subject: [PATCH] add edit faq, edit feedback and edit lowongan --- src/App.tsx | 6 + src/Pages/EditFAQ.tsx | 151 ++++++++++++++++ src/Pages/EditFeedback.tsx | 258 +++++++++++++++++++++++++++ src/Pages/EditLowongan.tsx | 356 +++++++++++++++++++++++++++++++++++++ src/Pages/ListFeedback.tsx | 2 +- src/Pages/ListLowongan.tsx | 28 +++ 6 files changed, 800 insertions(+), 1 deletion(-) create mode 100644 src/Pages/EditFAQ.tsx create mode 100644 src/Pages/EditFeedback.tsx create mode 100644 src/Pages/EditLowongan.tsx diff --git a/src/App.tsx b/src/App.tsx index 1e5ef39..c552720 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -25,6 +25,9 @@ import AddFeedback from "./Pages/AddFeedback"; import ListFaq from "./Pages/ListFaq"; import AddFaq from "./Pages/AddFAQ"; import Dashboard from "./Pages/Dashboard"; +import EditFaq from "./Pages/EditFAQ"; +import EditFeedback from "./Pages/EditFeedback"; +import EditLowongan from "./Pages/EditLowongan"; function App() { return ( @@ -61,6 +64,9 @@ function App() { } /> } /> } /> + }> + }> + }> diff --git a/src/Pages/EditFAQ.tsx b/src/Pages/EditFAQ.tsx new file mode 100644 index 0000000..36bd921 --- /dev/null +++ b/src/Pages/EditFAQ.tsx @@ -0,0 +1,151 @@ +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import SidebarAdmin from "../Layout/SidebarAdmin"; +import NavbarAdmin from "../Layout/NavbarAdmin"; +import "froala-editor/js/plugins.pkgd.min.js"; +import "froala-editor/css/froala_editor.pkgd.min.css"; +import "froala-editor/css/froala_style.min.css"; +import FroalaEditor from "react-froala-wysiwyg"; +import axios from "axios"; + +const EditFaq = () => { + const { id } = useParams<{ id: string }>(); + const [questions, setQuestions] = useState(""); + const [answers, setAnswers] = useState("

"); + const [loading, setLoading] = useState(false); + const [mounted, setMounted] = useState(false); + const [prefilled, setPrefilled] = useState(false); + + const navigate = useNavigate(); + + const token = document.cookie + .split("; ") + .find((row) => row.startsWith("token=")) + ?.split("=")[1]; + + useEffect(() => { + setMounted(true); + }, []); + + useEffect(() => { + const fetchFaqDetail = async () => { + if (!id) return; + + setLoading(true); + setPrefilled(false); + + try { + const res = await axios.get( + `${import.meta.env.VITE_API_BASE_URL}/faq-api/get/${id}`, + { headers: token ? { Authorization: `Bearer ${token}` } : undefined } + ); + + if (res.data?.status) { + const data = res.data.data; + setQuestions(data?.pertanyaan ?? ""); + setAnswers(data?.jawaban ?? "

"); + setPrefilled(true); + } else { + alert(res.data?.message || "Gagal mengambil detail FAQ."); + navigate("/faq-list"); + } + } catch (e: any) { + console.error(e); + alert(e?.response?.data?.message || "Gagal mengambil detail FAQ."); + navigate("/faq-list"); + } finally { + setLoading(false); + } + }; + + fetchFaqDetail(); + }, [id]); + + const handleSubmit = async () => { + if (!token) return alert("Token tidak ditemukan."); + if (!id) return alert("ID FAQ tidak ditemukan."); + if (!questions || !answers) return alert("Semua field wajib diisi."); + + try { + const res = await axios.patch( + `${import.meta.env.VITE_API_BASE_URL}/faq-api/update/${id}`, + { pertanyaan: questions, jawaban: answers }, + { headers: { Authorization: `Bearer ${token}` } } + ); + + if (res.data?.status) { + alert("Faq berhasil diperbarui!"); + navigate("/faq-list"); + } else { + alert(res.data?.message || "Gagal memperbarui faq."); + } + } catch (e: any) { + console.error(e); + alert( + e?.response?.data?.message || "Terjadi kesalahan saat memperbarui faq." + ); + } + }; + + return ( +
+ +
+ +
+
+

+ Edit Frequently Asked Questions +

+ +
+ +
+
+ + setQuestions(e.target.value)} + placeholder="Tulis pertanyaan kamu..." + /> +
+ +
+ + + {/* Render Froala hanya setelah mount + data terisi */} + {mounted && prefilled ? ( + setAnswers(model ?? "

")} + config={{ + placeholderText: "Tulis jawaban kamu...", + charCounterCount: true, + toolbarSticky: true, + heightMin: 200, + }} + /> + ) : ( +
+ {loading ? "Memuat editor..." : "Menyiapkan editor..."} +
+ )} +
+
+
+
+
+ ); +}; + +export default EditFaq; diff --git a/src/Pages/EditFeedback.tsx b/src/Pages/EditFeedback.tsx new file mode 100644 index 0000000..6f086e2 --- /dev/null +++ b/src/Pages/EditFeedback.tsx @@ -0,0 +1,258 @@ +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import SidebarAdmin from "../Layout/SidebarAdmin"; +import NavbarAdmin from "../Layout/NavbarAdmin"; +import "froala-editor/js/plugins.pkgd.min.js"; +import "froala-editor/css/froala_editor.pkgd.min.css"; +import "froala-editor/css/froala_style.min.css"; +import FroalaEditor from "react-froala-wysiwyg"; +import axios from "axios"; + +type FeedbackDetailResponse = { + status: boolean; + data?: { + id?: string | number; + nama?: string; + universitas?: string; + posisi?: string; + batch?: string | number; + tahun?: string | number; + pesan?: string; + image_path?: string; // opsional kalau BE ngasih path gambar lama + }; + message?: string; +}; + +const EditFeedback = () => { + const { id } = useParams(); // /feedback-edit/:id (contoh) + const [posisi, setPosisi] = useState(""); + const [universitas, setUniversitas] = useState(""); + const [nama, setNama] = useState(""); + const [image, setImage] = useState(null); + const [batch, setBatch] = useState(""); + const [feedback, setFeedbacks] = useState(""); + const [year, setYear] = useState(""); + const navigate = useNavigate(); + + const [existingImagePath, setExistingImagePath] = useState(""); + + useEffect(() => { + const token = document.cookie + .split("; ") + .find((row) => row.startsWith("token=")) + ?.split("=")[1]; + + if (!token) { + alert("Token tidak ditemukan."); + return; + } + + if (!id) { + alert("ID feedback tidak ditemukan."); + navigate("/feedback-list"); + return; + } + + const fetchDetail = async () => { + try { + const response = await axios.get( + `${import.meta.env.VITE_API_BASE_URL}/feedback-api/get/${id}`, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + + if (response.data.status && response.data.data) { + const d = response.data.data; + + setNama(d.nama ?? ""); + setUniversitas(d.universitas ?? ""); + setPosisi(d.posisi ?? ""); + setBatch(d.batch !== undefined ? String(d.batch) : ""); + setYear(d.tahun !== undefined ? String(d.tahun) : ""); + setFeedbacks(d.pesan ?? ""); + setExistingImagePath(d.image_path ?? ""); + } else { + alert(response.data.message || "Gagal mengambil detail feedback."); + navigate("/feedback-list"); + } + } catch (error: any) { + console.error("Error fetching feedback detail:", error); + alert("Terjadi kesalahan saat mengambil detail feedback."); + navigate("/feedback-list"); + } + }; + + fetchDetail(); + }, [id, navigate]); + + const handleSubmit = async () => { + const token = document.cookie + .split("; ") + .find((row) => row.startsWith("token=")) + ?.split("=")[1]; + + if (!token) { + alert("Token tidak ditemukan."); + return; + } + + if (!id) { + alert("ID feedback tidak ditemukan."); + return; + } + + if (!nama || !universitas || !posisi || !batch || !year || !feedback) { + alert("Semua field wajib diisi."); + return; + } + + try { + const formData = new FormData(); + formData.append("nama", nama); + formData.append("universitas", universitas); + formData.append("posisi", posisi); + formData.append("batch", batch); + formData.append("tahun", year); + formData.append("pesan", feedback); + + if (image) formData.append("image", image); + + if (!image && existingImagePath) { + formData.append("existing_image_path", existingImagePath); + } + + const response = await axios.patch( + `${import.meta.env.VITE_API_BASE_URL}/feedback-api/update/${id}`, + formData, + { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "multipart/form-data", + }, + } + ); + + if (response.data.status) { + alert("Feedback berhasil diupdate!"); + navigate("/feedback-list"); + } else { + alert(response.data.message || "Gagal mengupdate feedback."); + } + } catch (error: any) { + console.error("Error updating feedback:", error); + alert("Terjadi kesalahan saat mengupdate feedback."); + } + }; + + return ( +
+ +
+ +
+
+

Edit Feedback

+ +
+ +
+
+
+ + setNama(e.target.value)} + placeholder="John Doe" + /> +
+ +
+ + setUniversitas(e.target.value)} + placeholder="Telkom University Bandung" + /> +
+ +
+ + setPosisi(e.target.value)} + placeholder="UI/UX Designer" + /> +
+ +
+ + setBatch(e.target.value)} + placeholder="5" + /> +
+ +
+ + setYear(e.target.value)} + placeholder="2025" + /> +
+ +
+ + + setImage(e.target.files ? e.target.files[0] : null) + } + className="border border-gray-300 rounded-lg p-3" + /> +
+
+ + {/* Isi Konten */} +
+ + setFeedbacks(model)} + config={{ + placeholderText: "Tulis feedback kamu...", + charCounterCount: true, + toolbarSticky: true, + heightMin: 200, + }} + /> +
+
+
+
+
+ ); +}; + +export default EditFeedback; diff --git a/src/Pages/EditLowongan.tsx b/src/Pages/EditLowongan.tsx new file mode 100644 index 0000000..68ea6fd --- /dev/null +++ b/src/Pages/EditLowongan.tsx @@ -0,0 +1,356 @@ +import { useEffect, useState } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import SidebarAdmin from "../Layout/SidebarAdmin"; +import NavbarAdmin from "../Layout/NavbarAdmin"; +import "froala-editor/js/plugins.pkgd.min.js"; +import "froala-editor/css/froala_editor.pkgd.min.css"; +import "froala-editor/css/froala_style.min.css"; +import FroalaEditor from "react-froala-wysiwyg"; +import axios from "axios"; + +type LowonganDetail = { + id: number; + posisi: string; + kelompok_peminatan: string; + lokasi: string; + paid: "paid" | "unpaid" | string; + durasi_awal: string; + durasi_akhir: string; + jobdesk: string; + image?: string; +}; + +const EditLowongan = () => { + const { id } = useParams(); + const navigate = useNavigate(); + + const [posisi, setPosisi] = useState(""); + const [kelompok, setKelompok] = useState(""); + const [kelompokOptions, setKelompokOptions] = useState([]); + const [lokasi, setLokasi] = useState(""); + const [paid, setPaid] = useState("paid"); + const [durasiAwal, setDurasiAwal] = useState(""); + const [durasiAkhir, setDurasiAkhir] = useState(""); + const [jobdesk, setJobdesk] = useState(""); + const [image, setImage] = useState(null); + + const [isCustomKelompok, setIsCustomKelompok] = useState(false); + const [customKelompok, setCustomKelompok] = useState(""); + + const [isLoading, setIsLoading] = useState(true); + + const [froalaReady, setFroalaReady] = useState(false); + + const token = document.cookie + .split("; ") + .find((row) => row.startsWith("token=")) + ?.split("=")[1]; + + useEffect(() => { + axios + .get( + `${ + import.meta.env.VITE_API_BASE_URL + }/lowongan-magang-api/get/kelompok-all` + ) + .then((res) => { + const data = res.data.data || []; + setKelompokOptions(data); + }) + .catch((err) => { + console.error("Gagal memuat kelompok peminatan:", err); + setKelompokOptions([]); + }); + }, []); + + useEffect(() => { + const fetchDetail = async () => { + if (!id) { + alert("ID lowongan tidak ditemukan."); + navigate("/lowongan-list"); + return; + } + + if (!token) { + alert("Token tidak ditemukan."); + navigate("/humic-20242025-2"); + return; + } + + try { + setIsLoading(true); + setFroalaReady(false); + + const res = await axios.get( + `${import.meta.env.VITE_API_BASE_URL}/lowongan-magang-api/get/id/${id}`, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + + const data: LowonganDetail = res.data.data; + + setPosisi(data.posisi ?? ""); + setLokasi(data.lokasi ?? ""); + setPaid((data.paid ?? "paid") as string); + setDurasiAwal((data.durasi_awal ?? "").slice(0, 10)); + setDurasiAkhir((data.durasi_akhir ?? "").slice(0, 10)); + setJobdesk(String(data.jobdesk ?? "")); + + const kp = data.kelompok_peminatan ?? ""; + setKelompok(kp); + setCustomKelompok(kp); + } catch (err) { + console.error("Gagal memuat detail lowongan:", err); + alert("Gagal memuat detail lowongan."); + navigate("/lowongan-list"); + } finally { + setIsLoading(false); + } + }; + + fetchDetail(); + }, [id]); + + useEffect(() => { + if (!isLoading) { + const t = setTimeout(() => setFroalaReady(true), 0); + return () => clearTimeout(t); + } + }, [isLoading]); + + useEffect(() => { + if (!kelompok) return; + + if (kelompokOptions.length === 0) { + setIsCustomKelompok(true); + setCustomKelompok(kelompok); + return; + } + + const exists = kelompokOptions.includes(kelompok); + if (exists) { + setIsCustomKelompok(false); + setCustomKelompok(""); + } else { + setIsCustomKelompok(true); + setCustomKelompok(kelompok); + } + }, [kelompokOptions, kelompok]); + + const handleSubmit = async () => { + if (!id) { + alert("ID lowongan tidak ditemukan."); + return; + } + + if (!token) { + alert("Token tidak ditemukan."); + return; + } + + const finalKelompok = + isCustomKelompok || kelompokOptions.length === 0 + ? customKelompok + : kelompok; + + if (!finalKelompok.trim()) { + alert("Kategori internship wajib diisi."); + return; + } + + const formData = new FormData(); + formData.append("posisi", posisi); + formData.append("kelompok_peminatan", finalKelompok); + formData.append("lokasi", lokasi); + formData.append("jobdesk", jobdesk); + formData.append("durasi_awal", durasiAwal); + formData.append("durasi_akhir", durasiAkhir); + formData.append("paid", paid); + + if (image) formData.append("image", image); + + try { + await axios.patch( + `${import.meta.env.VITE_API_BASE_URL}/lowongan-magang-api/update/${id}`, + formData, + { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "multipart/form-data", + }, + } + ); + + alert("Lowongan berhasil diperbarui!"); + navigate("/lowongan-list"); + } catch (error) { + console.error("Error updating internship:", error); + alert("Gagal memperbarui lowongan."); + } + }; + + return ( +
+ +
+ +
+
+

Edit Lowongan

+ +
+ +
+ {/* Internship Fields Only */} +
+
+ + + {kelompokOptions.length > 0 && ( + + )} + + {(isCustomKelompok || kelompokOptions.length === 0) && ( + setCustomKelompok(e.target.value)} + /> + )} +
+ +
+ + +
+ +
+ + setLokasi(e.target.value)} + placeholder="Onsite,Jakarta" + /> +
+ +
+ + setPosisi(e.target.value)} + placeholder="UI/UX Designer" + /> +
+ +
+ + setDurasiAwal(e.target.value)} + /> +
+ +
+ + setDurasiAkhir(e.target.value)} + /> +
+ +
+ + + setImage(e.target.files ? e.target.files[0] : null) + } + className="border border-gray-300 rounded-lg p-3" + /> +
+
+ + {/* Isi Konten */} +
+ + + {froalaReady ? ( + setJobdesk(model || "")} + config={{ + placeholderText: "Tulis deskripsi lowongan...", + charCounterCount: true, + toolbarSticky: true, + heightMin: 200, + }} + /> + ) : ( +
+ )} +
+ +
+
+
+ ); +}; + +export default EditLowongan; diff --git a/src/Pages/ListFeedback.tsx b/src/Pages/ListFeedback.tsx index 137d742..2051dce 100644 --- a/src/Pages/ListFeedback.tsx +++ b/src/Pages/ListFeedback.tsx @@ -144,7 +144,7 @@ const ListFeedback = () => { + {/* Tombol Edit */} + + {/* Tombol Hapus */}