|
| 1 | +import React, { |
| 2 | + useState, |
| 3 | + useEffect, |
| 4 | + useCallback, |
| 5 | + useRef, |
| 6 | + useContext, |
| 7 | +} from "react"; |
| 8 | +import { useRouter } from "next/router"; |
| 9 | +import { useWindowSize } from "react-use"; |
| 10 | +import { Select, Option, Input, NavigationContext } from "@features/ui"; |
| 11 | +import { useFilters } from "../../hooks/use-filters"; |
| 12 | +import { IssueLevel, IssueStatus } from "@api/issues.types"; |
| 13 | +import { useProjects } from "@features/projects"; |
| 14 | +import * as S from "./filters.styled"; |
| 15 | + |
| 16 | +export function Filters() { |
| 17 | + const { handleFilters, filters } = useFilters(); |
| 18 | + const { data: projects } = useProjects(); |
| 19 | + const router = useRouter(); |
| 20 | + const routerQueryProjectName = |
| 21 | + (router.query.projectName as string)?.toLowerCase() || undefined; |
| 22 | + const [inputValue, setInputValue] = useState<string>(""); |
| 23 | + const projectNames = projects?.map((project) => project.name.toLowerCase()); |
| 24 | + const isFirst = useRef(true); |
| 25 | + const { width } = useWindowSize(); |
| 26 | + const isMobileScreen = width <= 1023; |
| 27 | + const { isMobileMenuOpen } = useContext(NavigationContext); |
| 28 | + const handleChange = (input: string) => { |
| 29 | + setInputValue(input); |
| 30 | + |
| 31 | + if (inputValue?.length < 2) { |
| 32 | + handleProjectName(undefined); |
| 33 | + return; |
| 34 | + } |
| 35 | + |
| 36 | + const name = projectNames?.find((name) => |
| 37 | + name?.toLowerCase().includes(inputValue.toLowerCase()) |
| 38 | + ); |
| 39 | + |
| 40 | + if (name) { |
| 41 | + handleProjectName(name); |
| 42 | + } |
| 43 | + }; |
| 44 | + |
| 45 | + const handleLevel = (level?: string) => { |
| 46 | + if (level) { |
| 47 | + level = level.toLowerCase(); |
| 48 | + } |
| 49 | + handleFilters({ level: level as IssueLevel }); |
| 50 | + }; |
| 51 | + |
| 52 | + const handleStatus = (status?: string) => { |
| 53 | + if (status === "Unresolved") { |
| 54 | + status = "open"; |
| 55 | + } |
| 56 | + if (status) { |
| 57 | + status = status.toLowerCase(); |
| 58 | + } |
| 59 | + handleFilters({ status: status as IssueStatus }); |
| 60 | + }; |
| 61 | + |
| 62 | + const handleProjectName = useCallback( |
| 63 | + (projectName?: string) => |
| 64 | + handleFilters({ project: projectName?.toLowerCase() }), |
| 65 | + [handleFilters] |
| 66 | + ); |
| 67 | + |
| 68 | + useEffect(() => { |
| 69 | + const newObj: { [key: string]: string } = { |
| 70 | + ...filters, |
| 71 | + }; |
| 72 | + |
| 73 | + Object.keys(newObj).forEach((key) => { |
| 74 | + if (newObj[key] === undefined) { |
| 75 | + delete newObj[key]; |
| 76 | + } |
| 77 | + }); |
| 78 | + |
| 79 | + const url = { |
| 80 | + pathname: router.pathname, |
| 81 | + query: { |
| 82 | + page: router.query.page || 1, |
| 83 | + ...newObj, |
| 84 | + }, |
| 85 | + }; |
| 86 | + |
| 87 | + if (routerQueryProjectName && isFirst) { |
| 88 | + handleProjectName(routerQueryProjectName); |
| 89 | + setInputValue(routerQueryProjectName || ""); |
| 90 | + isFirst.current = false; |
| 91 | + } |
| 92 | + |
| 93 | + router.push(url, undefined, { shallow: false }); |
| 94 | + }, [filters.level, filters.status, filters.project, router.query.page]); |
| 95 | + |
| 96 | + return ( |
| 97 | + <S.Container> |
| 98 | + <Select |
| 99 | + placeholder="Status" |
| 100 | + defaultValue="Status" |
| 101 | + width={isMobileScreen ? "97%" : "8rem"} |
| 102 | + data-cy="filter-by-status" |
| 103 | + style={{ |
| 104 | + ...(isMobileMenuOpen && { |
| 105 | + opacity: 0, |
| 106 | + }), |
| 107 | + }} |
| 108 | + > |
| 109 | + <Option value={undefined} handleCallback={handleStatus}> |
| 110 | + --None-- |
| 111 | + </Option> |
| 112 | + <Option value="Unresolved" handleCallback={handleStatus}> |
| 113 | + Unresolved |
| 114 | + </Option> |
| 115 | + <Option value="Resolved" handleCallback={handleStatus}> |
| 116 | + Resolved |
| 117 | + </Option> |
| 118 | + </Select> |
| 119 | + |
| 120 | + <Select |
| 121 | + placeholder="Level" |
| 122 | + defaultValue="Level" |
| 123 | + width={isMobileScreen ? "97%" : "8rem"} |
| 124 | + data-cy="filter-by-level" |
| 125 | + style={{ |
| 126 | + ...(isMobileMenuOpen && { |
| 127 | + opacity: 0, |
| 128 | + }), |
| 129 | + }} |
| 130 | + > |
| 131 | + <Option value={undefined} handleCallback={handleLevel}> |
| 132 | + --None-- |
| 133 | + </Option> |
| 134 | + <Option value="Error" handleCallback={handleLevel}> |
| 135 | + Error |
| 136 | + </Option> |
| 137 | + <Option value="Warning" handleCallback={handleLevel}> |
| 138 | + Warning |
| 139 | + </Option> |
| 140 | + <Option value="Info" handleCallback={handleLevel}> |
| 141 | + Info |
| 142 | + </Option> |
| 143 | + </Select> |
| 144 | + |
| 145 | + <Input |
| 146 | + handleChange={handleChange} |
| 147 | + value={inputValue} |
| 148 | + label="project name" |
| 149 | + placeholder="Project Name" |
| 150 | + iconSrc="/icons/search-icon.svg" |
| 151 | + data-cy="filter-by-project" |
| 152 | + style={{ |
| 153 | + ...(isMobileScreen && { width: "94%", marginRight: "3rem" }), |
| 154 | + ...(isMobileMenuOpen && { |
| 155 | + opacity: 0, |
| 156 | + }), |
| 157 | + }} |
| 158 | + /> |
| 159 | + </S.Container> |
| 160 | + ); |
| 161 | +} |
0 commit comments