From 8ad828b63b86d602a8d4fcf018479fccdc6a840b Mon Sep 17 00:00:00 2001 From: karolina-siemieniuk-morawska Date: Tue, 21 Nov 2023 15:16:45 +0100 Subject: [PATCH] year facet added --- ui/.eslintrc.json | 15 +- ui/package.json | 2 + ui/src/components/search/CheckboxFacet.tsx | 3 +- ui/src/components/search/YearFacet.tsx | 160 +++++++++++++++------ ui/src/pages/search.tsx | 7 +- ui/src/styles/globals.css | 48 ++++++- ui/src/theme/themeConfig.ts | 10 +- ui/src/types.ts | 11 +- ui/yarn.lock | 10 ++ 9 files changed, 211 insertions(+), 55 deletions(-) diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index 47c83df14..c0299d8ad 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -1,6 +1,17 @@ { - "extends": ["next/babel","next/core-web-vitals"], + "root": true, + "extends": ["next/core-web-vitals"], + "overrides": [ + { + "files": ["*.js"], + "parser": "espree", + "parserOptions": { + "ecmaVersion": 2020 + } + } + ], "rules": { - "react/display-name": "off" + "react/display-name": "off", + "react-hooks/exhaustive-deps": "off" } } diff --git a/ui/package.json b/ui/package.json index d50c448d1..e3f018725 100644 --- a/ui/package.json +++ b/ui/package.json @@ -11,6 +11,7 @@ "dependencies": { "@ant-design/cssinjs": "^1.17.2", "antd": "^5.10.1", + "lodash.isequal": "^4.5.0", "moment": "^2.29.4", "next": "13.5.5", "nextjs-progressbar": "^0.0.16", @@ -20,6 +21,7 @@ "react-vis": "^1.12.1" }, "devDependencies": { + "@types/lodash": "^4.14.201", "@types/node": "^20", "@types/react-html-parser": "^2.0.4", "autoprefixer": "^10", diff --git a/ui/src/components/search/CheckboxFacet.tsx b/ui/src/components/search/CheckboxFacet.tsx index b7ddf30f7..d2b8cc82f 100644 --- a/ui/src/components/search/CheckboxFacet.tsx +++ b/ui/src/components/search/CheckboxFacet.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import { Card } from "antd"; + import { getSearchUrl } from "@/utils/utils"; import { Country, Journal, Params } from "@/types"; @@ -28,7 +29,7 @@ const CheckboxFacet: React.FC = ({ }, []); useEffect(() => { - router.push(getSearchUrl({ ...params, [type]: filters })); + router.push(getSearchUrl({ ...params, page: 1, [type]: filters })); }, [filters]); const shortJournalName = (value: string) => { diff --git a/ui/src/components/search/YearFacet.tsx b/ui/src/components/search/YearFacet.tsx index bbcbb3229..c019562e2 100644 --- a/ui/src/components/search/YearFacet.tsx +++ b/ui/src/components/search/YearFacet.tsx @@ -1,77 +1,143 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { FlexibleWidthXYPlot, VerticalBarSeries, Hint } from "react-vis"; -import { Card, Slider } from "antd"; -import { PublicationYear } from "@/types"; +import 'react-vis/dist/style.css'; +import { Button, Card, Slider } from "antd"; +import { SliderMarks } from "antd/es/slider"; +import { useRouter } from "next/navigation"; +import * as isEqual from "lodash.isequal"; + +import { getSearchUrl } from "@/utils/utils"; +import { PublicationYear, YearFacetData, Params } from "@/types"; interface YearFacetProps { data: PublicationYear[]; + params: Params; } -const initialData = [ - { x: 2017, y: 8 }, - { x: 2018, y: 5 }, - { x: 2019, y: 4 }, - { x: 2020, y: 9 }, - { x: 2021, y: 1 }, - { x: 2022, y: 7 }, - { x: 2023, y: 6 }, - { x: 2024, y: 3 }, - { x: 2025, y: 2 }, - { x: 2026, y: 1 }, -]; - -const data = [ - { x: 2020, y: 9 }, - { x: 2021, y: 1 }, - { x: 2022, y: 7 }, - { x: 2023, y: 6 }, -]; - -const YearFacet: React.FC = ({ data }) => { +const YearFacet: React.FC = ({ data, params }) => { const [hoveredBar, setHoveredBar] = useState(null); - const [initialData, setInitialData] = useState(data); - const [sliderEndpoints, setSliderEndpoints] = useState([2017, 2026]); + const [filters, setFilters] = useState([]); + const [initialData, setInitialData] = useState([]); + const [initialEndpoints, setInitialEndpoints] = useState([]); + const [sliderEndpoints, setSliderEndpoints] = useState([]); + const [marks, setMarks] = useState(undefined); + const [reset, setReset] = useState(false); + const router = useRouter(); + + useEffect(() => { + const initialData = mapInitialDataToYears(data); + setFilters(initialData); + setInitialData(initialData); + setSliderEndpoints(getSliderEndpoints(initialData)); + setInitialEndpoints(getSliderEndpoints(initialData)); + setMarks(getMarks(initialData)); + }, []); + + useEffect(() => { + router.push( + getSearchUrl({ + ...params, + page: 1, + publication_year__range: sliderEndpoints.join("__"), + }) + ); + }, [filters]); - const onBarClick = (value: number) => { - const endpoints = [value, value]; - onSliderChange(endpoints); + const mapInitialDataToYears = ( + initial: PublicationYear[] + ): YearFacetData[] => { + return initial?.map((item) => ({ + x: new Date(item?.key)?.getFullYear(), + y: item?.doc_count, + })); }; - const onSliderChange = (range: any) => { - setSliderEndpoints(range); - setInitialData(range); + + const getSliderEndpoints = (initial: YearFacetData[]): number[] => { + if (initial.length === 1) return [initial[0]?.x]; + return [initial[0]?.x, initial[initial.length - 1]?.x]; + }; + + const getMarks = (initial: YearFacetData[]): SliderMarks => { + if (initial.length === 1) { + return { + [initial[0]?.x]: [initial[0]?.x], + }; + } + return { + [initial[0]?.x]: [initial[0]?.x], + [initial[initial.length - 1]?.x]: [initial[initial.length - 1]?.x], + }; + }; + + const updateStateAndMarks = (newFilters: YearFacetData[]) => { + setFilters(newFilters); + setSliderEndpoints(getSliderEndpoints(newFilters)); + setMarks(getMarks(newFilters)); + }; + + const onBarClick = (value: YearFacetData) => { + updateStateAndMarks([value]); + }; + + const onSliderChange = (data: number[]) => { + const firstIndex = initialData.findIndex( + (item: YearFacetData) => item.x === data[0] + ); + const lastIndex = initialData.findIndex( + (item: YearFacetData) => item.x === data[data.length - 1] + ); + const range = initialData.slice(firstIndex, lastIndex + 1); + + updateStateAndMarks(range); + }; + + const onBarMouseHover = (bar: YearFacetData) => { + setHoveredBar({ [bar.x]: bar.y }); }; - const onBarMouseHover = (bar: any) => setHoveredBar({ [bar.x]: bar.y }); const onBarMouseOut = () => setHoveredBar(null); + const resetFilters = () => { + setReset(!reset); + updateStateAndMarks(initialData); + }; + return ( -
- +
+ {!isEqual(initialData, filters) && ( +
+ +
+ )} + - {hoveredBar && ( - - )} + {hoveredBar && }
); diff --git a/ui/src/pages/search.tsx b/ui/src/pages/search.tsx index 2a0161cd9..0826bad38 100644 --- a/ui/src/pages/search.tsx +++ b/ui/src/pages/search.tsx @@ -28,7 +28,12 @@ const SearchPage: React.FC = ({
{results && results.length > 0 && ( <> - {/* */} +