DEV Community

buildr
buildr

Posted on

React TypeScript: Delete with Confirmation Modal and RTK Query

import { useState } from "react";
import { toast } from "react-toastify";
import { useNavigate } from "react-router-dom";
import {
  useGetAllAgencyQuery,
  useDeleteAgencyMutation,
} from "../services/agencyApi";

const AgencyTable = () => {
  const navigate = useNavigate();

  // Agency selected for deletion
  const [selectedAgencyId, setSelectedAgencyId] =
    useState<number | null>(null);

  // Get all agencies
  const {
    data: agencyData = [],
    isLoading: isAgencyLoading,
    isError: isAgencyError,
  } = useGetAllAgencyQuery();

  // Delete agency mutation
  const [deleteAgency, { isLoading: isDeleting }] =
    useDeleteAgencyMutation();

  // Delete button click
  const handleDeleteClick = (agencyId: number) => {
    setSelectedAgencyId(agencyId);
  };

  // Cancel delete
  const handleCancelDelete = () => {
    setSelectedAgencyId(null);
  };

  // Confirm delete
  const handleConfirmDelete = async () => {
    if (selectedAgencyId === null) return;

    try {
      const result = await deleteAgency({
        agencyId: selectedAgencyId,
      }).unwrap();

      toast.success(result.response);

      setSelectedAgencyId(null);
    } catch (error) {
      console.error("Delete agency error:", error);

      toast.error("Failed to delete agency");
    }
  };

  // Add Property
  const handleAddProperty = (agencyId: number) => {
    navigate(`/admin/properties/add/${agencyId}`);
  };

  // Loading state
  if (isAgencyLoading) {
    return <div>Loading agencies...</div>;
  }

  // Error state
  if (isAgencyError) {
    return <div>Failed to load agencies.</div>;
  }

  return (
    <>
      <div className="overflow-x-auto">
        <table className="w-full border-collapse">
          <thead>
            <tr>
              <th>ID</th>
              <th>Agency Name</th>
              <th>Agency Type</th>
              <th>Website</th>
              <th>Action</th>
            </tr>
          </thead>

          <tbody>
            {agencyData.length > 0 ? (
              agencyData.map((agency) => (
                <tr key={agency.id}>
                  <td>{agency.id}</td>

                  <td>{agency.agencyName}</td>

                  <td>{agency.agencyType}</td>

                  <td>{agency.website || "-"}</td>

                  <td>
                    <div className="flex gap-2">
                      {/* Add Property */}
                      <button
                        type="button"
                        onClick={() =>
                          handleAddProperty(agency.id)
                        }
                        className="rounded bg-blue-600 px-4 py-2 text-white"
                      >
                        Add Property
                      </button>

                      {/* Delete */}
                      <button
                        type="button"
                        onClick={() =>
                          handleDeleteClick(agency.id)
                        }
                        className="rounded bg-red-600 px-4 py-2 text-white"
                      >
                        Delete
                      </button>
                    </div>
                  </td>
                </tr>
              ))
            ) : (
              <tr>
                <td colSpan={5}>
                  No agencies found.
                </td>
              </tr>
            )}
          </tbody>
        </table>
      </div>

      {/* Delete Confirmation Modal */}
      {selectedAgencyId !== null && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
          <div className="w-[400px] rounded-lg bg-white p-6 shadow-lg">
            <h2 className="text-xl font-semibold">
              Delete Agency
            </h2>

            <p className="mt-3 text-gray-600">
              Are you sure you want to delete this agency?
            </p>

            <div className="mt-6 flex justify-end gap-3">
              {/* Cancel */}
              <button
                type="button"
                onClick={handleCancelDelete}
                disabled={isDeleting}
                className="rounded border px-4 py-2"
              >
                Cancel
              </button>

              {/* Confirm */}
              <button
                type="button"
                onClick={handleConfirmDelete}
                disabled={isDeleting}
                className="rounded bg-red-600 px-4 py-2 text-white"
              >
                {isDeleting ? "Deleting..." : "Confirm"}
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
};

export default AgencyTable;
Enter fullscreen mode Exit fullscreen mode

Add Property navigation

const handleAddProperty = (agencyId: number) => {
  navigate(`/admin/properties/add/${agencyId}`);
};
Enter fullscreen mode Exit fullscreen mode

For example, agency ID 5 par click karne par:

/admin/properties/add/5
Enter fullscreen mode Exit fullscreen mode

route open hoga.

Aapka AddProperty component separate file mein rahega aur useParams() se agencyId receive karega.

Top comments (0)