diff --git a/features/issues/components/filters/filters.styled.ts b/features/issues/components/filters/filters.styled.ts index 7d9c604..55190dd 100644 --- a/features/issues/components/filters/filters.styled.ts +++ b/features/issues/components/filters/filters.styled.ts @@ -1,5 +1,6 @@ import styled from "styled-components"; import { breakpoint } from "@styles/theme"; +import { Select as UnstyledSelect, Input as UnstyledInput } from "@features/ui"; export const Container = styled.div` display: flex; @@ -12,7 +13,20 @@ export const Container = styled.div` flex-direction: row; justify-content: flex-end; order: initial; - gap: 3rem; flex-wrap: wrap; } `; + +export const Select = styled(UnstyledSelect)` + width: 100%; + @media (min-width: ${breakpoint("desktop")}) { + width: 10rem; + } +`; + +export const Input = styled(UnstyledInput)` + width: 100%; + @media (min-width: ${breakpoint("desktop")}) { + width: 17.5rem; + } +`; diff --git a/features/issues/components/filters/filters.tsx b/features/issues/components/filters/filters.tsx index 5b92d0d..9155675 100644 --- a/features/issues/components/filters/filters.tsx +++ b/features/issues/components/filters/filters.tsx @@ -1,45 +1,37 @@ -import React, { - useState, - useEffect, - useCallback, - useRef, - useContext, -} from "react"; -import { useRouter } from "next/router"; -import { useWindowSize } from "react-use"; -import { Select, Option, Input, NavigationContext } from "@features/ui"; +import React, { useState } from "react"; +import { useDebouncedCallback } from "use-debounce"; +import { capitalize } from "lodash"; +import { Option } from "@features/ui"; +import { IssueFilters, IssueLevel, IssueStatus } from "@api/issues.types"; import { useFilters } from "../../hooks/use-filters"; -import { IssueLevel, IssueStatus } from "@api/issues.types"; -import { useProjects } from "@features/projects"; import * as S from "./filters.styled"; +function getStatusDefaultValue(filters: IssueFilters) { + if (!filters.status) { + return "Status"; + } + if (filters.status === IssueStatus.open) { + return "Unresolved"; + } + return "Resolved"; +} + +function getLevelDefaultValue(filters: IssueFilters) { + if (!filters.level) { + return "Level"; + } + return capitalize(filters.level); +} + export function Filters() { const { handleFilters, filters } = useFilters(); - const { data: projects } = useProjects(); - const router = useRouter(); - const routerQueryProjectName = - (router.query.projectName as string)?.toLowerCase() || undefined; - const [inputValue, setInputValue] = useState(""); - const projectNames = projects?.map((project) => project.name.toLowerCase()); - const isFirst = useRef(true); - const { width } = useWindowSize(); - const isMobileScreen = width <= 1023; - const { isMobileMenuOpen } = useContext(NavigationContext); - const handleChange = (input: string) => { - setInputValue(input); - if (inputValue?.length < 2) { - handleProjectName(undefined); - return; - } - - const name = projectNames?.find((name) => - name?.toLowerCase().includes(inputValue.toLowerCase()) - ); + const debouncedHandleFilters = useDebouncedCallback(handleFilters, 300); + const [inputValue, setInputValue] = useState(filters.project || ""); - if (name) { - handleProjectName(name); - } + const handleChange = (project: string) => { + setInputValue(project); + debouncedHandleFilters({ project: project.toLowerCase() }); }; const handleLevel = (level?: string) => { @@ -59,51 +51,11 @@ export function Filters() { handleFilters({ status: status as IssueStatus }); }; - const handleProjectName = useCallback( - (projectName?: string) => - handleFilters({ project: projectName?.toLowerCase() }), - [handleFilters] - ); - - useEffect(() => { - const newObj: { [key: string]: string } = { - ...filters, - }; - - Object.keys(newObj).forEach((key) => { - if (newObj[key] === undefined) { - delete newObj[key]; - } - }); - - const url = { - pathname: router.pathname, - query: { - page: router.query.page || 1, - ...newObj, - }, - }; - - if (routerQueryProjectName && isFirst) { - handleProjectName(routerQueryProjectName); - setInputValue(routerQueryProjectName || ""); - isFirst.current = false; - } - - router.push(url, undefined, { shallow: false }); - }, [filters.level, filters.status, filters.project, router.query.page]); - return ( - + - + - ); diff --git a/features/issues/context/filters-context.tsx b/features/issues/context/filters-context.tsx deleted file mode 100644 index a7472ee..0000000 --- a/features/issues/context/filters-context.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React, { - useState, - useMemo, - useCallback, - createContext, - ReactNode, -} from "react"; -import { IssueFilters } from "@api/issues.types"; - -export const FiltersContext = createContext<{ - filters: IssueFilters; - handleFilters: (filter: IssueFilters) => unknown; -}>({ - filters: { status: undefined, level: undefined, project: undefined }, - // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function - handleFilters: (_filter: IssueFilters) => {}, -}); - -type FiltersProviderProps = { - children: ReactNode | ReactNode[]; -}; - -export function FiltersProvider({ children }: FiltersProviderProps) { - const [filters, setFilters] = useState({ - status: undefined, - level: undefined, - project: undefined, - }); - - const handleFilters = useCallback( - (filter: any) => - setFilters((prevFilters) => ({ ...prevFilters, ...filter })), - [] - ); - - const memoizedValue = useMemo( - () => ({ filters, handleFilters }), - [filters, handleFilters] - ); - - return ( - - {children} - - ); -} diff --git a/features/issues/context/index.ts b/features/issues/context/index.ts deleted file mode 100644 index cfeccc8..0000000 --- a/features/issues/context/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./filters-context"; diff --git a/features/issues/hooks/use-filters.ts b/features/issues/hooks/use-filters.ts index 8ebce02..2256aca 100644 --- a/features/issues/hooks/use-filters.ts +++ b/features/issues/hooks/use-filters.ts @@ -1,4 +1,19 @@ -import { useContext } from "react"; -import { FiltersContext } from "../context/filters-context"; +import { useRouter } from "next/router"; +import { IssueFilters } from "@api/issues.types"; -export const useFilters = () => useContext(FiltersContext); +export const useFilters = () => { + const router = useRouter(); + + const filters = { + status: router.query.status, + level: router.query.level, + project: router.query.project, + } as IssueFilters; + + const handleFilters = (newFilters: IssueFilters) => { + const query = { ...router.query, ...newFilters }; + router.push({ query }); + }; + + return { filters, handleFilters }; +}; diff --git a/features/issues/index.ts b/features/issues/index.ts index 4818906..8e6318f 100644 --- a/features/issues/index.ts +++ b/features/issues/index.ts @@ -1,3 +1,2 @@ export * from "./api"; export * from "./components/issue-list"; -export * from "./context"; diff --git a/features/ui/input/input.styled.ts b/features/ui/input/input.styled.ts index c5ce947..a410060 100644 --- a/features/ui/input/input.styled.ts +++ b/features/ui/input/input.styled.ts @@ -17,6 +17,7 @@ export const InputContainer = styled.input<{ border-radius: 7px; width: calc(${space(20)} * 4 - ${space(6)}); padding: ${space(2, 3)}; + box-sizing: border-box; letter-spacing: 0.05rem; color: ${color("gray", 900)}; ${textFont("md", "regular")}; diff --git a/features/ui/page-container/page-container.tsx b/features/ui/page-container/page-container.tsx index d5e132d..4f97f80 100644 --- a/features/ui/page-container/page-container.tsx +++ b/features/ui/page-container/page-container.tsx @@ -3,7 +3,6 @@ import Head from "next/head"; import styled from "styled-components"; import { SidebarNavigation } from "../sidebar-navigation"; import { color, displayFont, textFont, space, breakpoint } from "@styles/theme"; -import { FiltersProvider } from "@features/issues"; type PageContainerProps = { children: React.ReactNode; @@ -58,23 +57,21 @@ export function PageContainer({ children, title, info }: PageContainerProps) { // "Warning: A title element received an array with more than 1 element as children." const documentTitle = `ProLog - ${title}`; return ( - - - - {documentTitle} - - - + + + {documentTitle} + + + - -
- - {title} - {info} - {children} - -
-
-
+ +
+ + {title} + {info} + {children} + +
+ ); } diff --git a/features/ui/sidebar-navigation/sidebar-navigation.tsx b/features/ui/sidebar-navigation/sidebar-navigation.tsx index 54c3047..5569c4b 100644 --- a/features/ui/sidebar-navigation/sidebar-navigation.tsx +++ b/features/ui/sidebar-navigation/sidebar-navigation.tsx @@ -49,6 +49,7 @@ const Container = styled.div<{ isCollapsed: boolean }>` const FixedContainer = styled.div` ${containerStyles} position: fixed; + z-index: 1; `; const Header = styled.header` diff --git a/package-lock.json b/package-lock.json index 5cbf726..04f398a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,8 @@ "react-dom": "^18.2.0", "react-use": "^17.4.0", "styled-components": "^5.3.6", - "styled-normalize": "^8.0.7" + "styled-normalize": "^8.0.7", + "use-debounce": "^9.0.2" }, "devDependencies": { "@babel/core": "^7.17.5", @@ -30809,6 +30810,17 @@ "node": ">=0.10.0" } }, + "node_modules/use-debounce": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-9.0.2.tgz", + "integrity": "sha512-QLyB0sxt9F5AisGDrUybCRJSLE60bTQR0yXc+IebNGUu1GCXwii1zsZl82mPGdWqDVQy7+1FKMLHQUixxf5Nbw==", + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", @@ -55544,6 +55556,12 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "use-debounce": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-9.0.2.tgz", + "integrity": "sha512-QLyB0sxt9F5AisGDrUybCRJSLE60bTQR0yXc+IebNGUu1GCXwii1zsZl82mPGdWqDVQy7+1FKMLHQUixxf5Nbw==", + "requires": {} + }, "use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", diff --git a/package.json b/package.json index 1fd4b26..0aae8a2 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "react-dom": "^18.2.0", "react-use": "^17.4.0", "styled-components": "^5.3.6", - "styled-normalize": "^8.0.7" + "styled-normalize": "^8.0.7", + "use-debounce": "^9.0.2" }, "devDependencies": { "@babel/core": "^7.17.5", diff --git a/pages/dashboard/issues.tsx b/pages/dashboard/issues.tsx index 933f1cd..73a91ce 100644 --- a/pages/dashboard/issues.tsx +++ b/pages/dashboard/issues.tsx @@ -1,18 +1,15 @@ import { PageContainer } from "@features/ui"; import { IssueList } from "@features/issues"; -import { FiltersProvider } from "@features/issues"; import type { NextPage } from "next"; const IssuesPage: NextPage = () => { return ( - - - - - + + + ); };