diff --git a/frontend/src/components/ConfirmationModal.tsx b/frontend/src/components/ConfirmationModal.tsx new file mode 100644 index 0000000..2f249f3 --- /dev/null +++ b/frontend/src/components/ConfirmationModal.tsx @@ -0,0 +1,48 @@ +import { Dialog, DialogPanel, DialogTitle } from "@headlessui/react"; +import StatsStyling from "../styles/stats_styling"; + +type Props = { + open: boolean; + title: string; + message: string; + confirmLabel?: string; + cancelLabel?: string; + loading?: boolean; + onConfirm: () => void; + onCancel: () => void; +}; + +const styles = StatsStyling; + +export default function ConfirmationModal({ + open, + title, + message, + confirmLabel = "Confirm", + cancelLabel = "Cancel", + loading = false, + onConfirm, + onCancel, +}: Props) { + return ( + +
+ +
+ + {title} +

{message}

+ +
+ + +
+
+
+
+ ); +} diff --git a/frontend/src/pages/DatasetEdit.tsx b/frontend/src/pages/DatasetEdit.tsx index 1f21ce1..fb92603 100644 --- a/frontend/src/pages/DatasetEdit.tsx +++ b/frontend/src/pages/DatasetEdit.tsx @@ -2,6 +2,7 @@ import StatsStyling from "../styles/stats_styling"; import { useNavigate, useParams } from "react-router-dom"; import { useEffect, useMemo, useState, type FormEvent } from "react"; import axios from "axios"; +import ConfirmationModal from "../components/ConfirmationModal"; const API_BASE_URL = import.meta.env.VITE_BACKEND_URL; const styles = StatsStyling; @@ -19,16 +20,11 @@ const DatasetEditPage = () => { const [statusMessage, setStatusMessage] = useState(""); const [loading, setLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); + const [isDeleting, setIsDeleting] = useState(false); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [hasError, setHasError] = useState(false); const [datasetName, setDatasetName] = useState(""); - - const token = localStorage.getItem("access_token"); - if (!token) { - setHasError(true); - setStatusMessage("You must be signed in to save changes."); - } - useEffect(() => { if (!Number.isInteger(parsedDatasetId) || parsedDatasetId <= 0) { setHasError(true); @@ -108,21 +104,37 @@ const DatasetEditPage = () => { }; const deleteDataset = async () => { - try{ + const deleteToken = localStorage.getItem("access_token"); + if (!deleteToken) { + setHasError(true); + setStatusMessage("You must be signed in to delete datasets."); + setIsDeleteModalOpen(false); + return; + } + + try { + setIsDeleting(true); + setHasError(false); + setStatusMessage(""); + await axios.delete( `${API_BASE_URL}/dataset/${parsedDatasetId}`, - { headers: { Authorization: `Bearer ${token}` } } + { headers: { Authorization: `Bearer ${deleteToken}` } } ); + + setIsDeleteModalOpen(false); navigate("/datasets", { replace: true }); } catch (error: unknown) { setHasError(true); if (axios.isAxiosError(error)) { - setStatusMessage(String(error.response?.data?.error || error.message || "Save failed.")); + setStatusMessage(String(error.response?.data?.error || error.message || "Delete failed.")); } else { - setStatusMessage("Save failed due to an unexpected error."); + setStatusMessage("Delete failed due to an unexpected error."); } + } finally { + setIsDeleting(false); } - } + }; return (
@@ -159,8 +171,8 @@ const DatasetEditPage = () => { @@ -169,14 +181,14 @@ const DatasetEditPage = () => { type="button" style={styles.buttonSecondary} onClick={() => navigate("/datasets")} - disabled={isSaving} + disabled={isSaving || isDeleting} > Cancel @@ -186,6 +198,17 @@ const DatasetEditPage = () => { : statusMessage}
+ + setIsDeleteModalOpen(false)} + onConfirm={deleteDataset} + /> );