add components for modal
This commit is contained in:
@@ -0,0 +1,62 @@
|
|||||||
|
import { type FC, Fragment, type ReactNode, useEffect } from 'react'
|
||||||
|
import { createPortal } from 'react-dom'
|
||||||
|
import HeaderModal from './HeaderModal'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
open: boolean,
|
||||||
|
close: () => void,
|
||||||
|
children: ReactNode,
|
||||||
|
isHeader?: boolean,
|
||||||
|
title_header?: string,
|
||||||
|
width?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const DefaulModal: FC<Props> = (props: Props) => {
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.open) {
|
||||||
|
document.body.style.overflow = 'hidden'
|
||||||
|
} else {
|
||||||
|
document.body.style.overflow = 'auto'
|
||||||
|
}
|
||||||
|
}, [props.open])
|
||||||
|
|
||||||
|
|
||||||
|
const modalContent = props.open ? (
|
||||||
|
<Fragment>
|
||||||
|
<div
|
||||||
|
onClick={props.close}
|
||||||
|
className='fixed size-full top-0 bottom-0 right-0 left-0 bg-black/40 inset-0 z-9998'
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{ maxWidth: props.width }}
|
||||||
|
className='xl:justify-center xl:items-center items-end flex overflow-x-hidden overflow-y-auto fixed inset-0 z-9999 h-auto top-0 bottom-0 m-auto outline-none focus:outline-none xl:max-w-xl mx-auto pointer-events-none'
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className='relative xl:h-full h-[80%] bottom-0 left-0 flex xl:items-center sm:h-auto w-full xl:my-6 xl:p-2 pointer-events-auto'
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<div className='border-0 h-auto p-5 lg:min-w-full overflow-y-auto rounded-3xl rounded-b-none xl:rounded-b-3xl relative flex flex-col w-full bg-white outline-none focus:outline-none shadow-2xl'>
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
props.isHeader && props.title_header &&
|
||||||
|
<div className='pb-3 border-b border-border'>
|
||||||
|
<div className='h-[5px] w-[200px] mx-auto bg-[#D1D3D7] rounded-full mb-4 xl:hidden'></div>
|
||||||
|
<HeaderModal close={props.close} label={props.title_header} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
{props.children}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
) : null
|
||||||
|
|
||||||
|
return createPortal(modalContent, document.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DefaulModal
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { CloseCircle } from 'iconsax-react'
|
||||||
|
import { type FC } from 'react'
|
||||||
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
label: string,
|
||||||
|
close: () => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
const HeaderModal: FC<Props> = (props: Props) => {
|
||||||
|
return (
|
||||||
|
<div className='flex justify-between items-center'>
|
||||||
|
<div className='text-sm'>{props.label}</div>
|
||||||
|
<div className='size-7 rounded-full bg-white bg-opacity-35 flex justify-center items-center'>
|
||||||
|
<CloseCircle
|
||||||
|
size={16}
|
||||||
|
color='black'
|
||||||
|
onClick={props.close}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HeaderModal
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import { type FC, useState } from 'react'
|
||||||
|
import DefaulModal from './DefaulModal'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Button from './Button'
|
||||||
|
import Textarea from './Textarea'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isloading?: boolean,
|
||||||
|
close: () => void,
|
||||||
|
isOpen: boolean,
|
||||||
|
onConfrim: (text?: string) => void,
|
||||||
|
label?: string,
|
||||||
|
isHasDescription?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const ModalConfrim: FC<Props> = (props: Props) => {
|
||||||
|
|
||||||
|
const { t } = useTranslation('global')
|
||||||
|
const [description, setDescription] = useState<string>('')
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaulModal
|
||||||
|
open={props.isOpen}
|
||||||
|
close={props.close}
|
||||||
|
title_header={t('confrim.subject')}
|
||||||
|
isHeader
|
||||||
|
>
|
||||||
|
<div className='mt-6'>
|
||||||
|
<div className='text-sm text-center'>
|
||||||
|
{
|
||||||
|
props.label ?
|
||||||
|
props.label
|
||||||
|
:
|
||||||
|
t('confrim.content')
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
props.isHasDescription &&
|
||||||
|
<div className='mt-4'>
|
||||||
|
<Textarea
|
||||||
|
placeholder={t('description')}
|
||||||
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
|
value={description}
|
||||||
|
className='bg-transparent border border-gray-500 rounded-xl w-[300px] p-2'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='flex gap-4 justify-center mt-10'>
|
||||||
|
<Button
|
||||||
|
onClick={() => props.onConfrim(props.isHasDescription ? description : undefined)}
|
||||||
|
disabled={props.isloading}
|
||||||
|
>
|
||||||
|
بله
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className='bg-transparent text-black border border-primary'
|
||||||
|
onClick={props.close}
|
||||||
|
>
|
||||||
|
لغو
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaulModal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModalConfrim
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { type FC, type InputHTMLAttributes } from 'react'
|
||||||
|
import Error from './Error'
|
||||||
|
import { clx } from '../helpers/utils'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
label?: string,
|
||||||
|
error_text?: string
|
||||||
|
} & InputHTMLAttributes<HTMLTextAreaElement>
|
||||||
|
|
||||||
|
const Textarea: FC<Props> = (props: Props) => {
|
||||||
|
return (
|
||||||
|
<div className='w-full relative'>
|
||||||
|
{
|
||||||
|
props.label &&
|
||||||
|
<div className='text-sm' >
|
||||||
|
{props.label}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
{...props}
|
||||||
|
className={clx(
|
||||||
|
'border border-border leading-7 w-full rounded-xl px-4 py-3 min-h-[100px] mt-1 text-xs',
|
||||||
|
props.className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
|
||||||
|
</textarea>
|
||||||
|
|
||||||
|
{
|
||||||
|
props.error_text &&
|
||||||
|
<Error errorText={props.error_text} />
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Textarea
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Trash } from 'iconsax-react'
|
||||||
|
import { type FC, useState } from 'react'
|
||||||
|
import ModalConfrim from './ModalConfrim'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onDelete: () => void,
|
||||||
|
isloading?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const TrashWithConfrim: FC<Props> = ({ onDelete, isloading = false }) => {
|
||||||
|
const [isConfirm, setIsConfirm] = useState(false)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Trash
|
||||||
|
onClick={() => setIsConfirm(true)}
|
||||||
|
className='size-5'
|
||||||
|
color='#888'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ModalConfrim
|
||||||
|
isOpen={isConfirm}
|
||||||
|
close={() => setIsConfirm(false)}
|
||||||
|
onConfrim={() => onDelete()}
|
||||||
|
isloading={isloading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TrashWithConfrim
|
||||||
Reference in New Issue
Block a user