feat(form): add loading state and replace custom switch component

This commit introduces a loading state for form submissions and replaces the custom switch component with a third-party library for improved user experience and maintainability.

- Adds `react-switch` as a dependency to replace the custom-built switch component, providing a more robust and feature-rich solution.
- Implements a loading indicator on form submission buttons and in the confirmation modal by utilizing the `useIsMutating` hook from TanStack Query. This provides clear visual feedback to the user during asynchronous operations.
- Creates a reusable `FormFooter` component to encapsulate the submit and cancel buttons, centralizing the form submission logic and loading state.
- Refactors the company create/edit forms to use the new `FormFooter` and `react-switch` components.
- Moves the `BreadcrumbItem` type to a shared types file for better code organization.
This commit is contained in:
AmirReza Jamali
2025-09-20 16:13:04 +03:30
parent 2c43e945c2
commit e6493f5d83
27 changed files with 782 additions and 84 deletions
+11 -4
View File
@@ -1,4 +1,5 @@
"use client";
import { useIsMutating } from "@tanstack/react-query";
import React, { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { z } from "zod";
@@ -23,6 +24,7 @@ export type ConfirmationModalProps = z.infer<
>;
const ConfirmationModal: React.FC<ConfirmationModalProps> = (props) => {
const isMutating = useIsMutating();
const validatedProps = ConfirmationModalPropsSchema.parse(props);
const {
isOpen,
@@ -107,7 +109,7 @@ const ConfirmationModal: React.FC<ConfirmationModalProps> = (props) => {
<div
className={`relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full ${currentSize} dark:bg-dark-2`}
>
<div className="bg-white px-4 pb-4 pt-5 sm:p-6 sm:pb-4 dark:bg-dark-2">
<div className="bg-white px-4 pb-4 pt-5 dark:bg-dark-2 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div
className={`mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full ${currentVariant.iconBg} sm:mx-0 sm:h-10 sm:w-10`}
@@ -131,17 +133,22 @@ const ConfirmationModal: React.FC<ConfirmationModalProps> = (props) => {
</div>
</div>
<div className="bg-gray px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6 dark:bg-dark-2 dark:border-t dark:border-stroke-dark">
<div className="bg-gray px-4 py-3 dark:border-t dark:border-stroke-dark dark:bg-dark-2 sm:flex sm:flex-row-reverse sm:px-6">
<button
type="button"
className={`inline-flex w-full justify-center rounded-md px-3 py-2 text-sm font-semibold text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 sm:ml-3 sm:w-auto ${currentVariant.confirmBtn} dark:ring-offset-dark-2`}
disabled={isMutating > 0}
onClick={onConfirm}
>
{confirmText}
{isMutating ? (
<div className="h-5 w-5 animate-spin rounded-full border-b-2 border-gray-1"></div>
) : (
confirmText
)}
</button>
<button
type="button"
className="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-dark shadow-sm ring-1 ring-inset ring-stroke hover:bg-gray focus:outline-none focus:ring-2 focus:ring-dark-5 focus:ring-offset-2 sm:mt-0 sm:w-auto dark:bg-dark-3 dark:text-white dark:ring-stroke-dark dark:hover:bg-dark-4 dark:focus:ring-offset-dark-2"
className="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-dark shadow-sm ring-1 ring-inset ring-stroke hover:bg-gray focus:outline-none focus:ring-2 focus:ring-dark-5 focus:ring-offset-2 dark:bg-dark-3 dark:text-white dark:ring-stroke-dark dark:hover:bg-dark-4 dark:focus:ring-offset-dark-2 sm:mt-0 sm:w-auto"
onClick={onCancel}
>
{cancelText}