2024-06-07 20:17:03 +03:00
|
|
|
'use client';
|
|
|
|
|
|
|
|
import clsx from 'clsx';
|
|
|
|
|
2025-02-26 00:16:22 +03:00
|
|
|
import { type HelpTopic } from '@/features/help';
|
|
|
|
import { BadgeHelp } from '@/features/help/components';
|
2025-02-12 21:36:03 +03:00
|
|
|
|
2025-02-19 23:29:45 +03:00
|
|
|
import { useEscapeKey } from '@/hooks/useEscapeKey';
|
2025-01-16 16:31:03 +03:00
|
|
|
import { useDialogsStore } from '@/stores/dialogs';
|
2025-02-11 20:56:11 +03:00
|
|
|
import { prepareTooltip } from '@/utils/utils';
|
2024-06-07 20:17:03 +03:00
|
|
|
|
2025-02-07 10:53:49 +03:00
|
|
|
import { Button, MiniButton, SubmitButton } from '../Control';
|
2025-02-10 01:32:16 +03:00
|
|
|
import { IconClose } from '../Icons';
|
2025-02-20 20:22:05 +03:00
|
|
|
import { type Styling } from '../props';
|
2025-02-12 21:36:03 +03:00
|
|
|
|
2025-02-06 20:27:56 +03:00
|
|
|
import { ModalBackdrop } from './ModalBackdrop';
|
2024-06-07 20:17:03 +03:00
|
|
|
|
2025-02-20 20:22:05 +03:00
|
|
|
export interface ModalProps extends Styling {
|
2024-11-21 15:09:31 +03:00
|
|
|
/** Title of the modal window. */
|
2024-06-07 20:17:03 +03:00
|
|
|
header?: string;
|
2024-11-21 15:09:31 +03:00
|
|
|
|
2025-02-06 20:27:56 +03:00
|
|
|
/** Indicates that the modal window should be scrollable. */
|
|
|
|
overflowVisible?: boolean;
|
|
|
|
|
|
|
|
/** Help topic to be displayed in the modal window. */
|
|
|
|
helpTopic?: HelpTopic;
|
|
|
|
|
|
|
|
/** Callback to determine if help should be displayed. */
|
|
|
|
hideHelpWhen?: () => boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface ModalFormProps extends ModalProps {
|
2024-11-21 15:09:31 +03:00
|
|
|
/** Text of the submit button. */
|
2024-06-07 20:17:03 +03:00
|
|
|
submitText?: string;
|
2024-11-21 15:09:31 +03:00
|
|
|
|
|
|
|
/** Tooltip for the submit button when the form is invalid. */
|
2024-06-07 20:17:03 +03:00
|
|
|
submitInvalidTooltip?: string;
|
|
|
|
|
2024-11-21 15:09:31 +03:00
|
|
|
/** Indicates that submit button is enabled. */
|
2024-06-07 20:17:03 +03:00
|
|
|
canSubmit?: boolean;
|
2024-11-21 15:09:31 +03:00
|
|
|
|
|
|
|
/** Callback to be called before submit. */
|
2024-08-30 20:18:04 +03:00
|
|
|
beforeSubmit?: () => boolean;
|
2024-11-21 15:09:31 +03:00
|
|
|
|
|
|
|
/** Callback to be called after submit. */
|
2025-02-15 16:42:33 +03:00
|
|
|
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
|
2025-02-15 15:33:37 +03:00
|
|
|
|
|
|
|
/** Callback to be called when modal is canceled. */
|
|
|
|
onCancel?: () => void;
|
2024-06-07 20:17:03 +03:00
|
|
|
}
|
|
|
|
|
2024-11-21 15:09:31 +03:00
|
|
|
/**
|
2025-02-06 20:27:56 +03:00
|
|
|
* Displays a customizable modal window with submit form.
|
2024-11-21 15:09:31 +03:00
|
|
|
*/
|
2025-02-06 20:27:56 +03:00
|
|
|
export function ModalForm({
|
2024-10-29 12:05:23 +03:00
|
|
|
children,
|
|
|
|
|
2025-02-06 20:27:56 +03:00
|
|
|
className,
|
2024-06-07 20:17:03 +03:00
|
|
|
header,
|
2024-10-29 12:05:23 +03:00
|
|
|
overflowVisible,
|
|
|
|
|
2025-02-10 14:10:51 +03:00
|
|
|
canSubmit = true,
|
2025-02-06 20:27:56 +03:00
|
|
|
submitText = 'Продолжить',
|
|
|
|
submitInvalidTooltip,
|
2024-08-30 20:18:04 +03:00
|
|
|
beforeSubmit,
|
2024-06-07 20:17:03 +03:00
|
|
|
onSubmit,
|
2025-02-15 15:33:37 +03:00
|
|
|
onCancel,
|
2024-10-29 12:05:23 +03:00
|
|
|
|
|
|
|
helpTopic,
|
|
|
|
hideHelpWhen,
|
2024-06-07 20:17:03 +03:00
|
|
|
...restProps
|
2025-02-06 20:27:56 +03:00
|
|
|
}: React.PropsWithChildren<ModalFormProps>) {
|
2025-01-16 16:31:03 +03:00
|
|
|
const hideDialog = useDialogsStore(state => state.hideDialog);
|
2025-02-15 15:33:37 +03:00
|
|
|
|
|
|
|
function handleCancel() {
|
|
|
|
onCancel?.();
|
|
|
|
hideDialog();
|
|
|
|
}
|
|
|
|
useEscapeKey(handleCancel);
|
2024-06-07 20:17:03 +03:00
|
|
|
|
2025-02-06 20:27:56 +03:00
|
|
|
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
2024-08-30 20:18:04 +03:00
|
|
|
if (beforeSubmit && !beforeSubmit()) {
|
|
|
|
return;
|
|
|
|
}
|
2025-02-15 16:42:33 +03:00
|
|
|
onSubmit(event);
|
|
|
|
hideDialog();
|
2025-02-06 20:27:56 +03:00
|
|
|
}
|
2024-06-07 20:17:03 +03:00
|
|
|
|
|
|
|
return (
|
2025-03-07 16:21:18 +03:00
|
|
|
<div className='fixed top-0 left-0 w-full h-full z-modal isolate cursor-default'>
|
2025-02-15 15:33:37 +03:00
|
|
|
<ModalBackdrop onHide={handleCancel} />
|
2025-02-06 20:27:56 +03:00
|
|
|
<form
|
2024-06-07 20:17:03 +03:00
|
|
|
className={clsx(
|
2024-12-12 13:17:24 +03:00
|
|
|
'cc-animate-modal',
|
2025-03-07 16:21:18 +03:00
|
|
|
'absolute bottom-1/2 left-1/2 -translate-x-1/2 translate-y-1/2',
|
2024-12-17 10:52:36 +03:00
|
|
|
'border rounded-xl bg-prim-100'
|
2024-06-07 20:17:03 +03:00
|
|
|
)}
|
2025-02-06 20:27:56 +03:00
|
|
|
onSubmit={handleSubmit}
|
2024-06-07 20:17:03 +03:00
|
|
|
>
|
2024-10-29 12:05:23 +03:00
|
|
|
{helpTopic && !hideHelpWhen?.() ? (
|
2025-03-07 22:04:56 +03:00
|
|
|
<BadgeHelp
|
|
|
|
topic={helpTopic} //
|
|
|
|
className='float-left mt-2 ml-2'
|
|
|
|
padding='p-0'
|
|
|
|
contentClass='sm:max-w-[40rem]'
|
|
|
|
/>
|
2024-10-29 12:05:23 +03:00
|
|
|
) : null}
|
2024-06-07 20:17:03 +03:00
|
|
|
|
2025-03-07 16:21:18 +03:00
|
|
|
<MiniButton
|
|
|
|
noPadding
|
|
|
|
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
|
|
|
|
icon={<IconClose size='1.25rem' />}
|
|
|
|
className='float-right mt-2 mr-2'
|
|
|
|
onClick={handleCancel}
|
|
|
|
/>
|
2024-12-18 21:26:44 +03:00
|
|
|
|
2024-06-07 20:17:03 +03:00
|
|
|
{header ? <h1 className='px-12 py-2 select-none'>{header}</h1> : null}
|
|
|
|
|
|
|
|
<div
|
2024-09-06 13:49:36 +03:00
|
|
|
className={clsx(
|
2025-03-04 12:23:23 +03:00
|
|
|
'@container/modal',
|
|
|
|
'max-h-[calc(100svh-8rem)] max-w-[100svw] xs:max-w-[calc(100svw-2rem)]',
|
|
|
|
'overscroll-contain outline-hidden',
|
2024-09-06 13:49:36 +03:00
|
|
|
{
|
|
|
|
'overflow-auto': !overflowVisible,
|
|
|
|
'overflow-visible': overflowVisible
|
|
|
|
},
|
|
|
|
className
|
|
|
|
)}
|
2024-12-12 13:17:24 +03:00
|
|
|
{...restProps}
|
2024-06-07 20:17:03 +03:00
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</div>
|
|
|
|
|
2025-03-07 16:21:18 +03:00
|
|
|
<div className='z-pop my-2 flex gap-12 justify-center text-sm'>
|
2025-02-06 20:27:56 +03:00
|
|
|
<SubmitButton
|
|
|
|
autoFocus
|
|
|
|
text={submitText}
|
|
|
|
title={!canSubmit ? submitInvalidTooltip : ''}
|
|
|
|
className='min-w-[7rem]'
|
|
|
|
disabled={!canSubmit}
|
|
|
|
/>
|
2025-02-15 15:33:37 +03:00
|
|
|
<Button text='Отмена' className='min-w-[7rem]' onClick={handleCancel} />
|
2024-06-07 20:17:03 +03:00
|
|
|
</div>
|
2025-02-06 20:27:56 +03:00
|
|
|
</form>
|
2024-06-07 20:17:03 +03:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|