Context: interactive comment section CRUD app
When deleting a comment, the user clicks a Delete button which opens a modal to ask them to confirm the deletion. That part (the modal opening/closing and deleting the comment) works fine.
What I want to add is an alert/flash notification once the user has confirmed the deletion and the comment is removed. I was able to implement this when updating the comment, but when using the exact same method for deleting, the alert is not rendering for some reason.
I have a feeling this has something to do with the fact that this component uses a modal but I can't figure out what is blocking exactly.
What I've tried:
DeleteConfirmationModal
(as opposed to passing it down from a parent component){alert.show && <Alert {...alert} showAlert={showAlert} />}
inside the Modal
or inside the article
aside
elementHere below is my code. I would be grateful if someone could help me fixing this.
const UserActionButtons = ({ comment, isEditing, isMobile, isReply, isCurrentUser, onDelete, editComment, handleClickReply}: UserActionButtonsProps) => {
const [isDeleteModalOpen, setDeleteModalOpen] = useState<boolean>(false)
const handleOpenConfirmationModal = (): void => {
setDeleteModalOpen(true)
}
const handleCloseConfirmationModal = (): void => {
setDeleteModalOpen(false)
}
return (
<>
{isCurrentUser ?
(<div className={`${isEditing && isMobile ? 'hidden' : 'cta-button'}`}>
<div className='flex items-center fill-primary-red-soft hover:fill-primary-red-pale text-primary-red-soft hover:text-primary-red-pale '>
<DeleteIcon />
<p className="font-medium mr-4"
onClick={() => handleOpenConfirmationModal()}
> Delete</p>
</div>
<DeleteConfirmationModal
isOpen={isDeleteModalOpen}
onDelete={onDelete}
onCancel={handleCloseConfirmationModal}
comment={comment}
isReply={isReply}
/>
<div className='flex items-center cta-button-blue'>
<EditIcon />
<p className="font-medium"
onClick={editComment}
> Edit</p>
</div>
</div>
) : !isEditing &&
(<div className='cta-button cta-button-blue'>
<ReplyIcon />
<p className="font-medium"
onClick={handleClickReply}
> Reply</p>
</div>)}
</>
)
}
const DeleteConfirmationModal = ({
isOpen,
comment,
isReply,
onCancel,
onDelete
}: DeleteConfirmationModalProps) => {
const { id } = comment
const [alert, setAlert] = useState<AlertInterface>({ show: false, type: '', text: '' })
const showAlert = (show = false, type = '', text = ''): void => {
setAlert({ show, type, text })
}
const deleteComment = (id: number, deletedComment?: MessageMeta): void => {
onDelete(id, deletedComment)
showAlert(true, 'success', 'Comment deleted!')
// console.log(alert.show)
}
useEffect(() => {
console.log(alert)
}, [alert])
return (
<>
{alert.show && <Alert {...alert} showAlert={showAlert} />}
<Modal isOpen={isOpen}>
<article className='flex flex-col gap-y-4'>
<h4 className='font-medium text-xl text-neutral-blue-dark'>Delete comment</h4>
<p className='text-neutral-blue-grayish'>Are you sure you want to delete this comment? This will remove the comment and can't be undone.</p>
<div className='flex gap-x-2 justify-between'>
<button className='bg-neutral-blue-grayish text-white font-medium px-4 sm:px-8 py-3 uppercase rounded-lg border-none w-6/12'
onClick={onCancel}>No, cancel</button>
<button className='bg-primary-red-soft text-white font-medium px-4 sm:px-8 py-3 uppercase rounded-lg border-none w-6/12'
onClick={() => deleteComment(id, isReply ? comment : undefined)}
>Yes, delete</button>
</div>
</article>
</Modal >
</>
)
}
const Alert = ({
type,
text,
showAlert
}: AlertProps) => {
console.log('alert renders')
useEffect(() => {
const timeout = setTimeout(() => {
showAlert()
}, 3000)
return () => clearTimeout(timeout)
}, [])
return (
<aside className={`${type === 'success' ? 'bg-primary-green-success' : 'bg-primary-red-soft'} text-white fixed bottom-5 right-5 p-4 z-50`}>{text}</aside>
)
}
const Modal = ({
isOpen,
children
}: ModalProps) => {
const [isModalOpen, setModalOpen] = useState(isOpen)
const modalRef = useRef<HTMLDialogElement | null>(null)
useEffect(() => {
setModalOpen(isOpen)
}, [isOpen])
useEffect(() => {
const modalElement = modalRef.current
if (modalElement) {
if (isModalOpen) {
modalElement.showModal()
} else {
modalElement.close()
}
}
}, [isModalOpen])
return (
<dialog ref={modalRef}
className={'p-4 sm:p-6 rounded-lg min-w-20 max-w-xs sm:max-w-sm cursor-default'}>
{children}
</dialog>
)
}
I actually found the solution which is not in the code I shared above
Basically because I'm recursively rendering the comments, I also needed to pass the showAlert
prop to the Comment component itself
I also lifted the state up to the highest parent
{comment.replies?.length !== 0 ? (
<div className='flex w-full'>
<div className='w-0.5 bg-neutral-gray-light md:ml-12'></div>
<div className='pl-6 md:pl-12 max-w-full flex-grow'>
{comment.replies?.map((reply) =>
(<Comment
key={reply.id}
comment={reply}
currentUser={currentUser}
commentList={commentList}
onReply={onReply}
onEdit={onEdit}
onDelete={onDelete}
onScoreChange={onScoreChange}
showAlert={showAlert}
/>))}
</div>
</div>) : null}