I want to click anywhere on the box to navigate me to the post detail page except the buttons. It's buttons should it's own job

76 Views Asked by At
import {
  Box,
  Flex,
  Text,
  Input,
  Image,
  useColorModeValue,
  useClipboard,
  Divider,
  IconButton,
  HStack,
  Menu,
  MenuButton,
  MenuList,
  Portal,
  MenuItem,
  useToast,
  useOutsideClick,
  useDisclosure,
} from "@chakra-ui/react";
import {
  BsThreeDots,
  BsDot,
  BsBookmark,
  BsFlag,
  BsCheckCircle,
} from "react-icons/bs";
import { BsHeart } from "react-icons/bs";
import { AiFillHeart, AiFillMessage } from "react-icons/ai";
import { FaShareSquare } from "react-icons/fa";
import parse from "html-react-parser";
import copyLink from "@/images/copy-link.svg";
import { axiosInstance } from "@/axiosConfig";
import { COLORS } from "../../constants/COLORS";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { useDispatch, useSelector } from "react-redux";
import { Link, useNavigate } from "react-router-dom";
import { addNotice, deleteMyPostSlice } from "../../redux/slices/userSlice";
import { FiEdit } from "react-icons/fi";
import { HiOutlineTrash } from "react-icons/hi";
import {
  addComment,
  deletePost,
  publishPost,
  unPublishPost,
} from "../../redux/asyncActions/postAction";
import CustomImage from "../small/CustomImage";
import {
  deletePostSlice,
  removeBookmarkSlice,
} from "../../redux/slices/postSlice";
import {
  EmailShareButton,
  FacebookShareButton,
  TwitterShareButton,
  LinkedinShareButton,
  FacebookIcon,
  TwitterIcon,
  LinkedinIcon,
  EmailIcon,
} from "react-share";
import AddPicker from "../small/AddPicker";
import PostTag from "./PostTag";
import LikedPeople from "../small/LikedPeopleModal";
import { useRef } from "react";
import ReportModal from "../common/ReportModal";

dayjs.extend(relativeTime);
var domain = window.location.host;

const NewsFeedPost = ({ data }) => {
  const [liked, setLiked] = useState(data?.has_liked);
  const [hasFav, setHasFav] = useState(data?.has_favorited);
  const [likedCount, setLikedCount] = useState(data?.likers_count);
  const [commentInput, setCommentInput] = useState("");

  const { isOpen, onOpen, onClose } = useDisclosure();

  const userId = useSelector((state) => state.userReducer?.userInfo?.id);
  const { hasCopied, onCopy } = useClipboard(
    `${domain}/post-detail/${data?.id}`
  );
  const toast = useToast();

  const bg = useColorModeValue("white", COLORS.darkGray);

  const borderColor = useColorModeValue(
    COLORS.lightGrayBorder,
    COLORS.darkGrayBorder
  );
  const navigate = useNavigate();

  const ref = useRef();
  const [isModalOpen, setIsModalOpen] = useState(false);

  useOutsideClick({
    ref: ref,
    handler: () => setIsModalOpen(false),
  });

  const dispatch = useDispatch();
  const likeThisPost = async (post_id) => {
    try {
      const r = await axiosInstance.post(`post/like/${post_id}`);
      setLikedCount(r.data.likers_count);
      setLiked((prev) => !prev);
    } catch (err) {}
  };
  const bookmarkThisPost = async (post_id) => {
    try {
      const r = await axiosInstance.post(`post/favorite/${post_id}`);
      setHasFav(r.data.favorited);
      if (r.data.favorited) {
        dispatch(addNotice("This post has been bookmarked"));
      } else {
        dispatch(addNotice("Bookmark has been removed"));
      }
      dispatch(removeBookmarkSlice(post_id));
    } catch (err) {}
  };

  const deleteThisPost = (id) => {
    dispatch(deletePost(id));
    dispatch(deleteMyPostSlice(id));
  };

  const addMyComment = (e, id) => {
    e.preventDefault();
    let data = {
      post_id: id,
      content: commentInput,
    };
    dispatch(addComment(data));
    navigate(`/post-detail/${id}`, { replace: true });
  };

  const unPublishPosts = (id) => {
    dispatch(unPublishPost(id));
    dispatch(deletePostSlice(id));
  };

  const publishPosts = (id) => {
    dispatch(publishPost(id));
    dispatch(deleteMyPostSlice(id));
  };

  return (
    <Box
      bg={bg}
      mt="1.5rem"
      p="1.5rem"
      pt="0.8rem"
      borderWidth={1}
      borderColor={borderColor}
      style={{ borderRadius: "10px" }}
      onClick={() => navigate(`/post-detail/${data?.id}`)}
    >
      <Flex mb="1.5rem" align="center" direction="row" justify="space-between">
        <Link to={`/post-detail/${data?.id}`}>
          <Text fontWeight="400">{data?.title}</Text>
        </Link>

        <Menu>
          <MenuButton>
            <BsThreeDots />
          </MenuButton>
          <Portal>
            <MenuList w="100px" p="3" bg={bg}>
              {data?.user.id === userId ? (
                <Flex direction={"column"} ml="1rem">
                  <Link to={`/post-edit/${data?.id}`}>
                    <Flex className="menuitems">
                      <FiEdit />
                      <Text ml="4" fontSize="0.8rem">
                        Edit
                      </Text>
                    </Flex>
                  </Link>

                  <Flex
                    className="menuitems"
                    onClick={() => deleteThisPost(data?.id)}
                  >
                    <HiOutlineTrash />
                    <Text ml="4" fontSize="0.8rem">
                      Delete
                    </Text>
                  </Flex>
                  {!data.is_published ? (
                    <Flex
                      className="menuitems"
                      onClick={() => publishPosts(data?.id)}
                    >
                      <BsCheckCircle />
                      <Text ml="4" fontSize="0.8rem">
                        Publish
                      </Text>
                    </Flex>
                  ) : (
                    <Flex
                      className="menuitems"
                      onClick={() => unPublishPosts(data?.id)}
                    >
                      <FiEdit />
                      <Text ml="4" fontSize="0.8rem">
                        Unpublish
                      </Text>
                    </Flex>
                  )}
                  <Flex
                    className="menuitems"
                    onClick={() => bookmarkThisPost(data?.id)}
                  >
                    <BsBookmark color={hasFav ? "lightgreen" : ""} />
                    <Text ml="4" fontSize="0.8rem">
                      {hasFav ? "Remove Bookmark" : "Bookmark"}
                    </Text>
                  </Flex>
                </Flex>
              ) : (
                <Flex direction={"column"} ml="1rem">
                  <Flex
                    className="menuitems"
                    onClick={() => bookmarkThisPost(data?.id)}
                  >
                    <BsBookmark color={hasFav ? "lightgreen" : ""} />
                    <Text ml="4" fontSize="0.8rem">
                      {hasFav ? "Remove Bookmark" : " Bookmark"}
                    </Text>
                  </Flex>
                  <Flex className="menuitems" onClick={onOpen}>
                    <BsFlag />
                    <Text ml="4" fontSize="0.8rem">
                      Report
                    </Text>
                    <ReportModal
                      modalIsOpen={isOpen}
                      closeModal={onClose}
                      type="post"
                      id={data?.id}
                    />
                  </Flex>
                </Flex>
              )}
            </MenuList>
          </Portal>
        </Menu>
      </Flex>
      <Flex direction="row" align="center" justify="space-between">
        <Box>
          <Flex direction="row" align="center">
            <Link to={`/user-profile/${data?.user?.id}`}>
              <CustomImage
                size="50px"
                char={data.user?.firstname.charAt(0)}
                imageUrl={data?.user?.photo}
                alt={`${data.user?.firstname}'s Avatar`}
                role={data?.user?.role}
              />
            </Link>
            <Flex ml="1rem" direction="column">
              <Link to={`/user-profile/${data?.user?.id}`}>
                <Text
                  fontSize={["12px", "13px", "13px", "13px"]}
                  mb="2px"
                  fontWeight="500"
                >
                  {data?.user?.firstname} {data?.user?.lastname}
                </Text>
              </Link>
              <Flex direction="row" align="center">
                <Text
                  style={{ color: "#ABAAAF" }}
                  fontSize={["9px", "9px", "9px", "12px"]}
                >
                  {dayjs(data.created_at).fromNow()}
                </Text>
                <BsDot
                  color="#ABAAAF"
                  fontSize={"20px"}
                  //  fontSize={["14px","14px","15px","24px"]}
                  ml="4px"
                />
                <Flex fontSize="10px" ml="4px">
                  in{" "}
                  <Text
                    ml="1"
                    cursor="pointer"
                    color="#FF8053"
                    onClick={() =>
                      navigate(`/?category_id=${data?.category?.id}`)
                    }
                  >
                    {data?.category?.name}
                  </Text>
                </Flex>
              </Flex>
            </Flex>
          </Flex>
        </Box>
        {data.tags && <PostTag tags={data?.tags} />}
      </Flex>
      <Box className="parseContent" mt="1.5rem" fontSize="12px">
        <Link to={`/post-detail/${data?.id}`}>{parse(data.content_html)}</Link>
      </Box>
      <Divider mt="1rem" mb="0.5rem" />
      <Flex
        direction="row"
        justify={{ base: "start", sm: "space-between" }}
        mt="1rem"
        align="center"
      >
        <Box w={{ base: "50%", sm: "50%", md: "70%", lg: "70%" }}>
          <Box pos="relative">
            <form
              onSubmit={(e) => addMyComment(e, data?.id)}
              style={{ position: "relative" }}
            >
              <Input
                value={commentInput}
                onChange={(e) => setCommentInput(e.target.value)}
                fontSize={["9px", "10px", "12px", "12px"]}
                placeholder="Add Response..."
                // zIndex={0}
              />
              <AddPicker setInput={setCommentInput} />
            </form>
          </Box>
        </Box>
        <Box width={{ base: "45%", sm: "45%", lg: "40%" }} pl="1.5rem">
          <Flex direction="row" justify="space-around" position="relative">
            <Flex direction="row" align="center">
              <IconButton
                onClick={() => likeThisPost(data.id)}
                _hover={{ background: "transparent" }}
                _active={{ background: "transparent" }}
                _focus={{ boxShadow: "none" }}
                bg="transparent"
                color="#C5D0E6"
                children={
                  liked ? (
                    <AiFillHeart fontSize={"1.7rem"} color={COLORS.hasLiked} />
                  ) : (
                    <BsHeart fontSize={"1.4rem"} />
                  )
                }
              />
              <Text
                color="#ABAAAF"
                fontSize="14px"
                onClick={() => setIsModalOpen(true)}
                cursor="pointer"
              >
                {likedCount}
              </Text>
              {isModalOpen && (
                <Box ref={ref}>
                  <LikedPeople />
                </Box>
              )}
            </Flex>
            <Link to={`/post-detail/${data?.id}`}>
              <DataIconCount icon="AiFillMessage" count={data.comments_count} />
            </Link>
            <Menu>
              <MenuButton
                bg="transparent"
                color="#C5D0E6"
                _hover={{ background: "transparent", color: "#7B6CB4" }}
                _active={{ background: "transparent" }}
                _focus={{ boxShadow: "none" }}
                className="newsfeed-iconbtn"
                as={IconButton}
                aria-label="Options"
                icon={<FaShareSquare fontSize={"1.5rem"} />}
              />
              <MenuList bg={bg}>
                <MenuItem fontSize="12px">
                  <HStack align="center" gap="4px">
                    <FacebookShareButton
                      url={`${domain}/post-detail/${data?.id}`}
                    >
                      <Flex>
                        <FacebookIcon size={22} />
                        <Text ml="3">Facebook</Text>{" "}
                      </Flex>
                    </FacebookShareButton>
                  </HStack>
                </MenuItem>
                <MenuItem fontSize="12px">
                  <TwitterShareButton url={`${domain}/post-detail/${data?.id}`}>
                    <Flex>
                      <TwitterIcon size={22} />
                      <Text ml="3">Twitter</Text>{" "}
                    </Flex>
                  </TwitterShareButton>
                </MenuItem>
                <MenuItem fontSize="12px">
                  <LinkedinShareButton
                    url={`${domain}/post-detail/${data?.id}`}
                  >
                    <Flex>
                      <LinkedinIcon size={22} />
                      <Text ml="3">LinkedIn</Text>{" "}
                    </Flex>
                  </LinkedinShareButton>
                </MenuItem>
                <MenuItem fontSize="12px">
                  <EmailShareButton url={`${domain}/post-detail/${data?.id}`}>
                    <Flex>
                      <EmailIcon size={22} />
                      <Text ml="3">Mail</Text>
                    </Flex>
                  </EmailShareButton>
                </MenuItem>
                <MenuItem fontSize="12px">
                  <HStack
                    onClick={() => {
                      onCopy();
                      toast({
                        description: "Copied Post Link",
                        status: "success",
                        position: "top-right",
                      });
                    }}
                    align="center"
                    gap="4px"
                  >
                    <Image src={copyLink} />
                    <Text>Copy Link</Text>
                  </HStack>
                </MenuItem>
              </MenuList>
            </Menu>
          </Flex>
        </Box>
      </Flex>
    </Box>
  );
};

I enter image description here

I have a post where there are lots of button. Each button has it's own task. Whenever I click on any white space or anywhere except this buttons, I should get navigated to post details page. So I have assigned navigate function on the onclick of the parent container that is "Box". The issue is that since all children are wrapped in box so clicking on those buttons also navigate . I want to navigate only on white spaces. I wrote a clumsy way of using e.stopPropagation() so buttons click prevent navigate() but still few buttons are navigating. Is there any way of navigating only when anywhere except buttons?

1

There are 1 best solutions below

0
Nice Books On

In the click event listener, check if the event current target is not a button.

if(!evt.currentTarget.matches('button'))