From a23e9ab03706a09485bbf6d5fb948c443c0321be Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Mon, 25 Mar 2024 19:39:51 +0100 Subject: [PATCH] Filter and sort dropdowns fixes --- .../src/components/atoms/ClickOutside.tsx | 30 ---------------- .../frontend/src/components/atoms/index.ts | 1 - .../components/molecules/DataActionsBar.tsx | 34 +++++++++---------- .../molecules/GovernanceActionsFilters.tsx | 18 ++++++---- .../molecules/GovernanceActionsSorting.tsx | 17 ++++++---- .../components/molecules/OrderActionsChip.tsx | 5 +++ govtool/frontend/src/hooks/index.ts | 5 +-- .../frontend/src/hooks/useOutsideClick.tsx | 25 ++++++++++++++ 8 files changed, 72 insertions(+), 63 deletions(-) delete mode 100644 govtool/frontend/src/components/atoms/ClickOutside.tsx create mode 100644 govtool/frontend/src/hooks/useOutsideClick.tsx diff --git a/govtool/frontend/src/components/atoms/ClickOutside.tsx b/govtool/frontend/src/components/atoms/ClickOutside.tsx deleted file mode 100644 index 86266bf2a..000000000 --- a/govtool/frontend/src/components/atoms/ClickOutside.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React, { useRef, useEffect, RefObject } from "react"; - -const useOutsideClick = (ref: RefObject, onClick: () => void) => { - useEffect(() => { - document.addEventListener("mousedown", (e) => { - if (ref.current && !ref.current.contains(e.target as Node)) { - onClick(); - } - }); - - return () => { - document.removeEventListener("mousedown", (e) => { - if (ref.current && !ref.current.contains(e.target as Node)) { - onClick(); - } - }); - }; - }, [ref]); -}; - -interface Props { - children: React.ReactElement; - onClick: () => void; -} - -export const ClickOutside = ({ children, onClick }: Props) => { - const wrapperRef = useRef(null); - useOutsideClick(wrapperRef, onClick); - return
{children}
; -}; diff --git a/govtool/frontend/src/components/atoms/index.ts b/govtool/frontend/src/components/atoms/index.ts index 6fa848bac..186752f80 100644 --- a/govtool/frontend/src/components/atoms/index.ts +++ b/govtool/frontend/src/components/atoms/index.ts @@ -2,7 +2,6 @@ export * from "./ActionRadio"; export * from "./Background"; export * from "./Button"; export * from "./Checkbox"; -export * from "./ClickOutside"; export * from "./CopyButton"; export * from "./DrawerLink"; export * from "./ExternalModalButton"; diff --git a/govtool/frontend/src/components/molecules/DataActionsBar.tsx b/govtool/frontend/src/components/molecules/DataActionsBar.tsx index 297d58bab..08e27a1db 100644 --- a/govtool/frontend/src/components/molecules/DataActionsBar.tsx +++ b/govtool/frontend/src/components/molecules/DataActionsBar.tsx @@ -4,7 +4,6 @@ import Search from "@mui/icons-material/Search"; import { GovernanceActionsFilters, GovernanceActionsSorting } from "@molecules"; import { OrderActionsChip } from "./OrderActionsChip"; -import { ClickOutside } from "../atoms"; import { theme } from "@/theme"; type DataActionsBarProps = { @@ -86,24 +85,23 @@ export const DataActionsBar: FC = ({ ...props }) => { setSortOpen={setSortOpen} sortingActive={sortingActive} sortOpen={sortOpen} - /> + > + {filtersOpen && ( + + )} + {sortOpen && ( + + )} + - {filtersOpen && ( - - - - )} - {sortOpen && ( - - - - )} ); }; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionsFilters.tsx b/govtool/frontend/src/components/molecules/GovernanceActionsFilters.tsx index 89542217d..29bf5cc99 100644 --- a/govtool/frontend/src/components/molecules/GovernanceActionsFilters.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceActionsFilters.tsx @@ -1,4 +1,4 @@ -import { Dispatch, SetStateAction, useCallback } from "react"; +import { Dispatch, SetStateAction, useCallback, useRef } from "react"; import { Box, Checkbox, @@ -8,16 +8,18 @@ import { } from "@mui/material"; import { GOVERNANCE_ACTIONS_FILTERS } from "@consts"; -import { useScreenDimension, useTranslation } from "@hooks"; +import { useOnClickOutside, useScreenDimension, useTranslation } from "@hooks"; interface Props { chosenFilters: string[]; setChosenFilters: Dispatch>; + closeFilters: () => void; } export const GovernanceActionsFilters = ({ chosenFilters, setChosenFilters, + closeFilters, }: Props) => { const handleFilterChange = useCallback( (e: React.ChangeEvent) => { @@ -36,7 +38,10 @@ export const GovernanceActionsFilters = ({ ); const { t } = useTranslation(); - const { isMobile } = useScreenDimension(); + const { isMobile, screenWidth } = useScreenDimension(); + + const wrapperRef = useRef(null); + useOnClickOutside(wrapperRef, closeFilters); return ( >; + closeSorts: () => void; } export const GovernanceActionsSorting = ({ chosenSorting, setChosenSorting, + closeSorts, }: Props) => { const { t } = useTranslation(); - const { isMobile } = useScreenDimension(); + + const wrapperRef = useRef(null); + useOnClickOutside(wrapperRef, closeSorts); return ( diff --git a/govtool/frontend/src/components/molecules/OrderActionsChip.tsx b/govtool/frontend/src/components/molecules/OrderActionsChip.tsx index 037a68cd4..006133653 100644 --- a/govtool/frontend/src/components/molecules/OrderActionsChip.tsx +++ b/govtool/frontend/src/components/molecules/OrderActionsChip.tsx @@ -13,6 +13,7 @@ type Props = { sortOpen: boolean; setSortOpen: Dispatch>; sortingActive: boolean; + children?: React.ReactNode; isFiltering?: boolean; }; @@ -32,6 +33,7 @@ export const OrderActionsChip = (props: Props) => { setSortOpen, sortingActive, isFiltering = true, + children, } = props; return ( @@ -41,6 +43,8 @@ export const OrderActionsChip = (props: Props) => { alignItems="center" ml="8px" gap={isMobile ? "8px" : "24px"} + position="relative" + sx={{ alignSelf: "end" }} > {isFiltering && ( { )} + {children} ); }; diff --git a/govtool/frontend/src/hooks/index.ts b/govtool/frontend/src/hooks/index.ts index 84e427cfa..126c2d0c9 100644 --- a/govtool/frontend/src/hooks/index.ts +++ b/govtool/frontend/src/hooks/index.ts @@ -1,8 +1,9 @@ export { useTranslation } from "react-i18next"; +export * from "./useFetchNextPageDetector"; +export * from "./useOutsideClick"; +export * from "./useSaveScrollPosition"; export * from "./useScreenDimension"; export * from "./useSlider"; -export * from "./useSaveScrollPosition"; -export * from "./useFetchNextPageDetector"; export * from "./useWalletConnectionListener"; export * from "./forms"; diff --git a/govtool/frontend/src/hooks/useOutsideClick.tsx b/govtool/frontend/src/hooks/useOutsideClick.tsx new file mode 100644 index 000000000..cc91719c3 --- /dev/null +++ b/govtool/frontend/src/hooks/useOutsideClick.tsx @@ -0,0 +1,25 @@ +import { MutableRefObject, useEffect } from "react"; + +export function useOnClickOutside( + ref: MutableRefObject, + handler: (event: MouseEvent | TouchEvent) => void, +) { + useEffect(() => { + const listener = (event: MouseEvent | TouchEvent) => { + const target = event.target as Node; + + if (!ref.current || ref.current.contains(target)) { + return; + } + handler(event); + }; + + document.addEventListener("mousedown", listener as EventListener); + document.addEventListener("touchstart", listener as EventListener); + + return () => { + document.removeEventListener("mousedown", listener as EventListener); + document.removeEventListener("touchstart", listener as EventListener); + }; + }, [ref, handler]); +}