Skip to content

System Dialog


tsx
import { type ReactNode } from 'react';
import { create } from 'zustand';

export type confirmContetnt = {
  acceptLabel?: string;
  header: ReactNode | string;
  message: ReactNode | string;
  rejectivInvisible?: boolean;
};
export type AppStoreType = {
  actions: {
    confirm: (
      data: confirmContetnt & { onAccept?: () => void; onCancel?: () => void },
    ) => Promise<void>;

    toast: (data: ToastMessage | ToastMessage[]) => void;
  };

  confirm: (
    data: confirmContetnt & { onAccept?: () => void; onCancel?: () => void },
  ) => Promise<void>;

  toast: ToastMessage | ToastMessage[] | null;
};
export const useAppStore = create<AppStoreType>((set) => ({
  actions: {
    async confirm(data) {
      set({ confirm: data });
    },

    async toast(data) {
      set({ toast: data });
    },
  },
  // state
  confirm: null,
  toast: null,
}));

export const { confirm, toast } = useAppStore.getState().actions;
"
confirm component "import { ConfirmDialog } from "primereact/confirmdialog";

import { confirmContetnt } from "@/stores/useAppStore";
import { classNames } from "primereact/utils";
import { t } from "@lingui/macro";

type confirmFun = (confrimed: boolean) => void;
type stateContent = confirmContetnt & { visible: boolean };
type confirmRef = {
  show: (content: confirmContetnt) => Promise<boolean>;
};
export const Confirm = forwardRef<confirmRef>((_, ref) => {
  const [
    { acceptLabel, header, message, rejectivInvisible, visible },
    setContent,
  ] = useState<stateContent>({
    acceptLabel: undefined,
    header: "",
    message: "",
    rejectivInvisible: undefined,
    visible: false,
  });
  const [confirmHandler, setConfirmHandler] = useState<confirmFun | null>(null);
  useImperativeHandle(ref, () => ({
    show: ({
      header: headerContet,
      message: massgeContent,
      ...others
    }: confirmContetnt): Promise<boolean> => {
      setContent({
        acceptLabel: others?.acceptLabel,
        header: headerContet,
        massage: massgeContent,
        rejectivInvisible: others?.rejectivInvisible,
        visible: true,
      });
      return new Promise<boolean>((resolve) => {
        const handle = (confirmed: boolean) => {
          setContent((content) => ({ ...content, visible: false }));
          resolve(confirmed);
        };

        setConfirmHandler(() => handle);
      });
    },
  }));
  const handleConfirm = (confirmed: boolean) => {
    if (confirmHandler) {
      confirmHandler(confirmed);
      setConfirmHandler(null);
    }
  };

  return (
    <ConfirmDialog
      accept={() => handleConfirm(true)}
      acceptLabel={acceptLabel || t`Yes`}
      header={header}
      pt={{
        rejectButton: {
          root: {
            className:
              "w-full px-4 py-2 mt-3 text-zinc-700 shadow-none border-zinc-700 text-base font-medium text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm",
          },
        },
        acceptButton: {
          root: {
            className:
              "px-4 py-2 text-base font-medium focus:shadow-none focus:outline-none   text-white bg-zinc-700 border border-transparent rounded-md  shadow-sm hover:bg-zinc-800    sm:ml-3 sm:w-auto sm:text-sm",
          },
        },
      }}
      message={message}
      onHide={() => setContent((content) => ({ ...content, visible: false }))}
      reject={() => handleConfirm(false)}
      rejectClassName={classNames({
        invisible: rejectivInvisible,
      })}
      rejectLabel={t`No`}
      visible={visible}
    />
  );
});
"
the root file "
import { NavBar } from './components/NavBar';
import { Notifications } from './components/Notifications';
import { User } from './components/User';
import ChangeLanguage from '@/components/changeLanguage';
import { type confirmContetnt, useAppStore } from '@/stores/useAppStore';
import { Toast } from 'primereact/toast';

type confirmRef = {
  show: (content: confirmContetnt) => Promise<boolean>;
};

export function Component() {
  const { confirm, toast } = useAppStore();

  const confirmRef = useRef<confirmRef>(null);
  const toastRef = useRef<Toast>(null);

  useEffect(() => {
    (async () => {
      if (confirm) {
        const result = await confirmRef?.current?.show({
          header: confirm?.header,
          message: confirm?.message,
        });
        if (result && confirm.onAccept) confirm.onAccept();
        else if (result && confirm.onCancel) confirm.onCancel();
        useAppStore.setState({ confirm: null });
      }
    })();
  }, [confirm]);

  useEffect(() => {
    if (toast) toastRef?.current?.show(toast);

    useAppStore.setState({ toast: null });
  }, [toast]);
  return (
    <>
      <div className="grid grid-cols-[0.1fr_auto] max-w-full">
        <NavBar />
        <div>
          <div className="flex justify-end items-center gap-2 bg-slate-200 p-4">
            <div className="flex items-center gap-2 lg:gap-5 ">
              <User />
              <Notifications />
              <ChangeLanguage />
            </div>
          </div>
          <Outlet />
        </div>
      </div>
      <Toast ref={toastRef} />
      <Confirm ref={confirmRef} />
    </>
  );
}