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} />
</>
);
}