import { motion } from 'framer-motion'; import { useCallback, useRef, useState } from 'react'; import copyToClipboard from 'copy-to-clipboard'; import PropTypes from 'prop-types'; import { channel as $channelContent } from '../../../content'; import { channelAPI } from '../../../api'; import { clsm } from '../../../utils'; import { createAnimationProps } from '../../../helpers/animationPropsHelper'; import { Link as LinkIcon, Menu as MenuIcon, PersonAdd as PersonAddIcon, PersonOff as PersonOffIcon } from '../../../assets/icons'; import { useChannel } from '../../../contexts/Channel'; import { useModal } from '../../../contexts/Modal'; import { useNotif } from '../../../contexts/Notification'; import { useResponsiveDevice } from '../../../contexts/ResponsiveDevice'; import { useUser } from '../../../contexts/User'; import Button from '../../../components/Button'; import Spinner from '../../../components/Spinner'; import useClickAway from '../../../hooks/useClickAway'; const $content = $channelContent.profileViewMenu; const $modalContent = $channelContent.chat.modal; const BUTTON_TEXT_CLASSES = ['text-black', 'dark:text-white']; const IconClasses = clsm([ 'dark:fill-white', 'fill-white-player', 'h-6', 'w-6' ]); const ProfileViewMenu = ({ channelUsername }) => { const menuRef = useRef(); const toggleBtnRef = useRef(); const moderateUserButton = useRef(); const { userData, isSessionValid } = useUser(); const { notifySuccess, notifyError } = useNotif(); const { openModal } = useModal(); const { isMobileView } = useResponsiveDevice(); const { channelData: { isChannelBanned, channelArn } = {}, refreshChannelData } = useChannel(); const [isMenuOpen, setIsMenuOpen] = useState(false); const [isModerationActionLoading, setIsModerationActionLoading] = useState(false); const isOwnChannel = channelUsername === userData?.username; const toggleMenu = useCallback((value) => { setIsMenuOpen((prev) => (value !== undefined ? value : !prev)); }, []); useClickAway([toggleBtnRef, menuRef], () => toggleMenu(false), isMenuOpen); const moderationHandler = () => { toggleMenu(false); let confirmText, modalMessage, successMessage, errorMessage; if (isChannelBanned) { confirmText = $modalContent.unban_user_modal.confirm_unban_user; modalMessage = `${$modalContent.unban_user_modal.unban_user_message} ${channelUsername}?`; successMessage = $channelContent.notifications.success.user_unbanned; errorMessage = $channelContent.notifications.error.unban_user; } else { confirmText = $modalContent.ban_user_modal.confirm_ban_user; modalMessage = `${$modalContent.ban_user_modal.ban_user_message} ${channelUsername}?`; successMessage = $channelContent.notifications.success.user_banned; errorMessage = $channelContent.notifications.error.ban_user; } const onConfirm = () => { (async function () { setIsModerationActionLoading(true); const handler = isChannelBanned ? channelAPI.unbanUser : channelAPI.banUser; const { result, error } = await handler(channelArn); if (result) { await refreshChannelData(); notifySuccess(successMessage); } if (error) notifyError(errorMessage); setIsModerationActionLoading(false); })(); }; openModal({ content: { confirmText, isDestructive: true, message: modalMessage }, onConfirm, onCancel: () => toggleMenu(true), lastFocusedElement: moderateUserButton }); }; const copyChannelLinkHandler = () => { copyToClipboard(window.location.href); notifySuccess($content.notifications.success.channel_link_copied); toggleMenu(false); }; return ( <> {isModerationActionLoading ? ( <Spinner className="m-2.5" variant="light" /> ) : ( <Button className={clsm(['h-11', 'w-11'])} onClick={() => toggleMenu()} ref={toggleBtnRef} variant="icon" isDisabled={isModerationActionLoading} > <MenuIcon className={IconClasses} /> </Button> )} <motion.div ref={menuRef} {...createAnimationProps({ animations: ['fadeIn-full', 'scale'], options: { isVisible: isMenuOpen }, customVariants: { visible: { x: isMobileView ? '-50%' : 0, display: 'flex' }, hidden: { x: isMobileView ? '-50%' : 0, transitionEnd: { display: 'none' } } } })} className={clsm([ 'bg-lightMode-gray-light', 'dark:bg-darkMode-gray', 'absolute', 'flex-col', 'gap-4', 'mt-2', 'origin-top-left', 'p-4', 'rounded-3xl', 'w-[223px]', isMobileView && ['left-1/2', 'origin-top'] ])} > {!isOwnChannel && isSessionValid && ( <Button variant="tertiaryText" onClick={moderationHandler} ref={moderateUserButton} className={clsm(BUTTON_TEXT_CLASSES)} > {isChannelBanned ? ( <PersonAddIcon className={IconClasses} /> ) : ( <PersonOffIcon className={IconClasses} /> )} <p>{isChannelBanned ? $content.unban_user : $content.ban_user}</p> </Button> )} <Button variant="tertiaryText" onClick={copyChannelLinkHandler} className={clsm(BUTTON_TEXT_CLASSES)} > <LinkIcon className={IconClasses} /> <p>{$content.copy_channel_link}</p> </Button> </motion.div> </> ); }; ProfileViewMenu.propTypes = { channelUsername: PropTypes.string.isRequired }; export default ProfileViewMenu;