From 663573ec00a8bfd20fd08065979031f19a77bb77 Mon Sep 17 00:00:00 2001 From: MaikNeubert Date: Sun, 18 Feb 2024 11:27:47 +0100 Subject: [PATCH 01/10] Components -> components --- .../statviz/{Components => components}/ErrorCard.tsx | 0 .../statviz/{Components => components}/NoDataCard.tsx | 0 .../statviz/{Components => components}/VisHeader.tsx | 0 .../custom-graphs/BarChartCenterAxis.tsx | 0 .../filter/BoxesOrItemsSelect.tsx | 0 .../filter/GenderProductFilter.tsx | 0 .../{Components => components}/filter/MultiSelectFilter.tsx | 0 .../{Components => components}/filter/TimeRangeSelect.tsx | 0 .../{Components => components}/filter/ValueFilter.tsx | 0 .../statviz/{Components => components}/nivo/BarChart.tsx | 0 .../statviz/{Components => components}/nivo/PieChart.tsx | 0 .../statviz/{Components => components}/nivo/SankeyChart.tsx | 0 .../statviz/{Components => components}/nivo/Sunburst.tsx | 0 .../visualizations/createdBoxes/CreatedBoxes.tsx | 0 .../visualizations/createdBoxes/CreatedBoxesCharts.tsx | 0 .../createdBoxes/CreatedBoxesDataContainer.tsx | 0 .../createdBoxes/CreatedBoxesFilterContainer.tsx | 0 .../visualizations/createdBoxes/TopCreatedProducts.tsx | 0 .../visualizations/demographic/DemographicCharts.tsx | 0 .../visualizations/demographic/DemographicDataWrapper.tsx | 0 .../visualizations/demographic/DemographicFilterWrapper.tsx | 0 .../visualizations/demographic/DemographicPyramid.tsx | 2 +- .../visualizations/movedBoxes/BoxFlowSankey.tsx | 0 .../visualizations/movedBoxes/MovedBoxes.test.tsx | 0 .../visualizations/movedBoxes/MovedBoxesCharts.tsx | 0 .../visualizations/movedBoxes/MovedBoxesDataContainer.tsx | 0 .../visualizations/movedBoxes/MovedBoxesFilterContainer.tsx | 0 .../visualizations/stock/StockCharts.tsx | 0 .../visualizations/stock/StockDataContainer.tsx | 0 .../visualizations/stock/StockDataFilter.tsx | 0 .../visualizations/stock/StockOverviewPie.tsx | 0 .../visualizations/stock/StockSunburst.tsx | 0 shared-components/statviz/dashboard/Dashboard.tsx | 6 +++--- shared-components/statviz/dashboard/Demographics.tsx | 2 +- shared-components/statviz/dashboard/ItemsAndBoxes.tsx | 2 +- shared-components/statviz/dashboard/MovedBoxes.tsx | 2 +- shared-components/statviz/dashboard/StockOverview.tsx | 2 +- shared-components/statviz/hooks/useMultiSelectFilter.ts | 2 +- shared-components/statviz/hooks/useValueFilter.ts | 2 +- 39 files changed, 10 insertions(+), 10 deletions(-) rename shared-components/statviz/{Components => components}/ErrorCard.tsx (100%) rename shared-components/statviz/{Components => components}/NoDataCard.tsx (100%) rename shared-components/statviz/{Components => components}/VisHeader.tsx (100%) rename shared-components/statviz/{Components => components}/custom-graphs/BarChartCenterAxis.tsx (100%) rename shared-components/statviz/{Components => components}/filter/BoxesOrItemsSelect.tsx (100%) rename shared-components/statviz/{Components => components}/filter/GenderProductFilter.tsx (100%) rename shared-components/statviz/{Components => components}/filter/MultiSelectFilter.tsx (100%) rename shared-components/statviz/{Components => components}/filter/TimeRangeSelect.tsx (100%) rename shared-components/statviz/{Components => components}/filter/ValueFilter.tsx (100%) rename shared-components/statviz/{Components => components}/nivo/BarChart.tsx (100%) rename shared-components/statviz/{Components => components}/nivo/PieChart.tsx (100%) rename shared-components/statviz/{Components => components}/nivo/SankeyChart.tsx (100%) rename shared-components/statviz/{Components => components}/nivo/Sunburst.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/createdBoxes/CreatedBoxes.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/createdBoxes/CreatedBoxesCharts.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/createdBoxes/TopCreatedProducts.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/demographic/DemographicCharts.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/demographic/DemographicDataWrapper.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/demographic/DemographicFilterWrapper.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/demographic/DemographicPyramid.tsx (98%) rename shared-components/statviz/{Components => components}/visualizations/movedBoxes/BoxFlowSankey.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/movedBoxes/MovedBoxes.test.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/movedBoxes/MovedBoxesCharts.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/movedBoxes/MovedBoxesDataContainer.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/stock/StockCharts.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/stock/StockDataContainer.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/stock/StockDataFilter.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/stock/StockOverviewPie.tsx (100%) rename shared-components/statviz/{Components => components}/visualizations/stock/StockSunburst.tsx (100%) diff --git a/shared-components/statviz/Components/ErrorCard.tsx b/shared-components/statviz/components/ErrorCard.tsx similarity index 100% rename from shared-components/statviz/Components/ErrorCard.tsx rename to shared-components/statviz/components/ErrorCard.tsx diff --git a/shared-components/statviz/Components/NoDataCard.tsx b/shared-components/statviz/components/NoDataCard.tsx similarity index 100% rename from shared-components/statviz/Components/NoDataCard.tsx rename to shared-components/statviz/components/NoDataCard.tsx diff --git a/shared-components/statviz/Components/VisHeader.tsx b/shared-components/statviz/components/VisHeader.tsx similarity index 100% rename from shared-components/statviz/Components/VisHeader.tsx rename to shared-components/statviz/components/VisHeader.tsx diff --git a/shared-components/statviz/Components/custom-graphs/BarChartCenterAxis.tsx b/shared-components/statviz/components/custom-graphs/BarChartCenterAxis.tsx similarity index 100% rename from shared-components/statviz/Components/custom-graphs/BarChartCenterAxis.tsx rename to shared-components/statviz/components/custom-graphs/BarChartCenterAxis.tsx diff --git a/shared-components/statviz/Components/filter/BoxesOrItemsSelect.tsx b/shared-components/statviz/components/filter/BoxesOrItemsSelect.tsx similarity index 100% rename from shared-components/statviz/Components/filter/BoxesOrItemsSelect.tsx rename to shared-components/statviz/components/filter/BoxesOrItemsSelect.tsx diff --git a/shared-components/statviz/Components/filter/GenderProductFilter.tsx b/shared-components/statviz/components/filter/GenderProductFilter.tsx similarity index 100% rename from shared-components/statviz/Components/filter/GenderProductFilter.tsx rename to shared-components/statviz/components/filter/GenderProductFilter.tsx diff --git a/shared-components/statviz/Components/filter/MultiSelectFilter.tsx b/shared-components/statviz/components/filter/MultiSelectFilter.tsx similarity index 100% rename from shared-components/statviz/Components/filter/MultiSelectFilter.tsx rename to shared-components/statviz/components/filter/MultiSelectFilter.tsx diff --git a/shared-components/statviz/Components/filter/TimeRangeSelect.tsx b/shared-components/statviz/components/filter/TimeRangeSelect.tsx similarity index 100% rename from shared-components/statviz/Components/filter/TimeRangeSelect.tsx rename to shared-components/statviz/components/filter/TimeRangeSelect.tsx diff --git a/shared-components/statviz/Components/filter/ValueFilter.tsx b/shared-components/statviz/components/filter/ValueFilter.tsx similarity index 100% rename from shared-components/statviz/Components/filter/ValueFilter.tsx rename to shared-components/statviz/components/filter/ValueFilter.tsx diff --git a/shared-components/statviz/Components/nivo/BarChart.tsx b/shared-components/statviz/components/nivo/BarChart.tsx similarity index 100% rename from shared-components/statviz/Components/nivo/BarChart.tsx rename to shared-components/statviz/components/nivo/BarChart.tsx diff --git a/shared-components/statviz/Components/nivo/PieChart.tsx b/shared-components/statviz/components/nivo/PieChart.tsx similarity index 100% rename from shared-components/statviz/Components/nivo/PieChart.tsx rename to shared-components/statviz/components/nivo/PieChart.tsx diff --git a/shared-components/statviz/Components/nivo/SankeyChart.tsx b/shared-components/statviz/components/nivo/SankeyChart.tsx similarity index 100% rename from shared-components/statviz/Components/nivo/SankeyChart.tsx rename to shared-components/statviz/components/nivo/SankeyChart.tsx diff --git a/shared-components/statviz/Components/nivo/Sunburst.tsx b/shared-components/statviz/components/nivo/Sunburst.tsx similarity index 100% rename from shared-components/statviz/Components/nivo/Sunburst.tsx rename to shared-components/statviz/components/nivo/Sunburst.tsx diff --git a/shared-components/statviz/Components/visualizations/createdBoxes/CreatedBoxes.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxes.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/createdBoxes/CreatedBoxes.tsx rename to shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxes.tsx diff --git a/shared-components/statviz/Components/visualizations/createdBoxes/CreatedBoxesCharts.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesCharts.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/createdBoxes/CreatedBoxesCharts.tsx rename to shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesCharts.tsx diff --git a/shared-components/statviz/Components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx rename to shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx diff --git a/shared-components/statviz/Components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx rename to shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx diff --git a/shared-components/statviz/Components/visualizations/createdBoxes/TopCreatedProducts.tsx b/shared-components/statviz/components/visualizations/createdBoxes/TopCreatedProducts.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/createdBoxes/TopCreatedProducts.tsx rename to shared-components/statviz/components/visualizations/createdBoxes/TopCreatedProducts.tsx diff --git a/shared-components/statviz/Components/visualizations/demographic/DemographicCharts.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicCharts.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/demographic/DemographicCharts.tsx rename to shared-components/statviz/components/visualizations/demographic/DemographicCharts.tsx diff --git a/shared-components/statviz/Components/visualizations/demographic/DemographicDataWrapper.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicDataWrapper.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/demographic/DemographicDataWrapper.tsx rename to shared-components/statviz/components/visualizations/demographic/DemographicDataWrapper.tsx diff --git a/shared-components/statviz/Components/visualizations/demographic/DemographicFilterWrapper.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicFilterWrapper.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/demographic/DemographicFilterWrapper.tsx rename to shared-components/statviz/components/visualizations/demographic/DemographicFilterWrapper.tsx diff --git a/shared-components/statviz/Components/visualizations/demographic/DemographicPyramid.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicPyramid.tsx similarity index 98% rename from shared-components/statviz/Components/visualizations/demographic/DemographicPyramid.tsx rename to shared-components/statviz/components/visualizations/demographic/DemographicPyramid.tsx index ab04dcfe6..5e00938ba 100644 --- a/shared-components/statviz/Components/visualizations/demographic/DemographicPyramid.tsx +++ b/shared-components/statviz/components/visualizations/demographic/DemographicPyramid.tsx @@ -2,7 +2,7 @@ import { Card, CardBody, CardHeader, Heading } from "@chakra-ui/react"; import { range } from "lodash"; import { ApolloError } from "@apollo/client"; import { filter, sum, summarize, tidy, groupBy, map } from "@tidyjs/tidy"; -import BarChartCenterAxis from "../../Custom-graphs/BarChartCenterAxis"; +import BarChartCenterAxis from "../../custom-graphs/BarChartCenterAxis"; import { HumanGender } from "../../../../types/generated/graphql"; import VisHeader from "../../VisHeader"; import useDemographics from "../../../hooks/useDemographics"; diff --git a/shared-components/statviz/Components/visualizations/movedBoxes/BoxFlowSankey.tsx b/shared-components/statviz/components/visualizations/movedBoxes/BoxFlowSankey.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/movedBoxes/BoxFlowSankey.tsx rename to shared-components/statviz/components/visualizations/movedBoxes/BoxFlowSankey.tsx diff --git a/shared-components/statviz/Components/visualizations/movedBoxes/MovedBoxes.test.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxes.test.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/movedBoxes/MovedBoxes.test.tsx rename to shared-components/statviz/components/visualizations/movedBoxes/MovedBoxes.test.tsx diff --git a/shared-components/statviz/Components/visualizations/movedBoxes/MovedBoxesCharts.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesCharts.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/movedBoxes/MovedBoxesCharts.tsx rename to shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesCharts.tsx diff --git a/shared-components/statviz/Components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx rename to shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx diff --git a/shared-components/statviz/Components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx rename to shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx diff --git a/shared-components/statviz/Components/visualizations/stock/StockCharts.tsx b/shared-components/statviz/components/visualizations/stock/StockCharts.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/stock/StockCharts.tsx rename to shared-components/statviz/components/visualizations/stock/StockCharts.tsx diff --git a/shared-components/statviz/Components/visualizations/stock/StockDataContainer.tsx b/shared-components/statviz/components/visualizations/stock/StockDataContainer.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/stock/StockDataContainer.tsx rename to shared-components/statviz/components/visualizations/stock/StockDataContainer.tsx diff --git a/shared-components/statviz/Components/visualizations/stock/StockDataFilter.tsx b/shared-components/statviz/components/visualizations/stock/StockDataFilter.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/stock/StockDataFilter.tsx rename to shared-components/statviz/components/visualizations/stock/StockDataFilter.tsx diff --git a/shared-components/statviz/Components/visualizations/stock/StockOverviewPie.tsx b/shared-components/statviz/components/visualizations/stock/StockOverviewPie.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/stock/StockOverviewPie.tsx rename to shared-components/statviz/components/visualizations/stock/StockOverviewPie.tsx diff --git a/shared-components/statviz/Components/visualizations/stock/StockSunburst.tsx b/shared-components/statviz/components/visualizations/stock/StockSunburst.tsx similarity index 100% rename from shared-components/statviz/Components/visualizations/stock/StockSunburst.tsx rename to shared-components/statviz/components/visualizations/stock/StockSunburst.tsx diff --git a/shared-components/statviz/dashboard/Dashboard.tsx b/shared-components/statviz/dashboard/Dashboard.tsx index c5e892040..6075292cd 100644 --- a/shared-components/statviz/dashboard/Dashboard.tsx +++ b/shared-components/statviz/dashboard/Dashboard.tsx @@ -1,11 +1,11 @@ import { Accordion, Center, Heading, Wrap, WrapItem } from "@chakra-ui/react"; -import TimeRangeSelect from "../Components/filter/TimeRangeSelect"; +import TimeRangeSelect from "../components/filter/TimeRangeSelect"; import Demographics from "./Demographics"; import MovedBoxes from "./MovedBoxes"; import ItemsAndBoxes from "./ItemsAndBoxes"; import StockOverview from "./StockOverview"; -import BoxesOrItemsSelect from "../Components/filter/BoxesOrItemsSelect"; -import GenderProductFilter from "../Components/filter/GenderProductFilter"; +import BoxesOrItemsSelect from "../components/filter/BoxesOrItemsSelect"; +import GenderProductFilter from "../components/filter/GenderProductFilter"; export default function Dashboard() { return ( diff --git a/shared-components/statviz/dashboard/Demographics.tsx b/shared-components/statviz/dashboard/Demographics.tsx index d3f4e0201..7838932f5 100644 --- a/shared-components/statviz/dashboard/Demographics.tsx +++ b/shared-components/statviz/dashboard/Demographics.tsx @@ -8,7 +8,7 @@ import { WrapItem, Box, } from "@chakra-ui/react"; -import DemographicChart from "../Components/visualizations/demographic/DemographicPyramid"; +import DemographicChart from "../components/visualizations/demographic/DemographicPyramid"; export default function Demographics() { return ( diff --git a/shared-components/statviz/dashboard/ItemsAndBoxes.tsx b/shared-components/statviz/dashboard/ItemsAndBoxes.tsx index 2bdc52a28..efe35b67f 100644 --- a/shared-components/statviz/dashboard/ItemsAndBoxes.tsx +++ b/shared-components/statviz/dashboard/ItemsAndBoxes.tsx @@ -6,7 +6,7 @@ import { AccordionIcon, AccordionPanel, } from "@chakra-ui/react"; -import CreatedBoxesDataContainer from "../Components/visualizations/createdBoxes/CreatedBoxesDataContainer"; +import CreatedBoxesDataContainer from "../components/visualizations/createdBoxes/CreatedBoxesDataContainer"; export type BoxesOrItemsCount = "boxesCount" | "itemsCount"; diff --git a/shared-components/statviz/dashboard/MovedBoxes.tsx b/shared-components/statviz/dashboard/MovedBoxes.tsx index acdf3fe18..3fadbbdc1 100644 --- a/shared-components/statviz/dashboard/MovedBoxes.tsx +++ b/shared-components/statviz/dashboard/MovedBoxes.tsx @@ -6,7 +6,7 @@ import { AccordionPanel, Box, } from "@chakra-ui/react"; -import MovedBoxesDataContainer from "../Components/visualizations/movedBoxes/MovedBoxesDataContainer"; +import MovedBoxesDataContainer from "../components/visualizations/movedBoxes/MovedBoxesDataContainer"; export default function MovedBoxes() { return ( diff --git a/shared-components/statviz/dashboard/StockOverview.tsx b/shared-components/statviz/dashboard/StockOverview.tsx index cb024bd72..fcb21ebf6 100644 --- a/shared-components/statviz/dashboard/StockOverview.tsx +++ b/shared-components/statviz/dashboard/StockOverview.tsx @@ -6,7 +6,7 @@ import { AccordionPanel, Box, } from "@chakra-ui/react"; -import StockDataContainer from "../Components/visualizations/stock/StockDataContainer"; +import StockDataContainer from "../components/visualizations/stock/StockDataContainer"; export default function StockOverview() { return ( diff --git a/shared-components/statviz/hooks/useMultiSelectFilter.ts b/shared-components/statviz/hooks/useMultiSelectFilter.ts index 8379f81b9..d71b1d445 100644 --- a/shared-components/statviz/hooks/useMultiSelectFilter.ts +++ b/shared-components/statviz/hooks/useMultiSelectFilter.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; import { useSearchParams } from "react-router-dom"; -import { IFilterValue } from "../Components/filter/ValueFilter"; +import { IFilterValue } from "../components/filter/ValueFilter"; export const urlFilterValuesEncode = (array: (IFilterValue & T)[]): string => array.map((e) => encodeURIComponent(e.urlId)).join(","); diff --git a/shared-components/statviz/hooks/useValueFilter.ts b/shared-components/statviz/hooks/useValueFilter.ts index 3338d9c29..5e9a41a22 100644 --- a/shared-components/statviz/hooks/useValueFilter.ts +++ b/shared-components/statviz/hooks/useValueFilter.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; import { useSearchParams } from "react-router-dom"; -import { IFilterValue } from "../Components/filter/ValueFilter"; +import { IFilterValue } from "../components/filter/ValueFilter"; export default function useValueFilter( values: (IFilterValue & T)[], From 1fd707863d2b04dfdf00b7b2e3b2cf5827dc9e4c Mon Sep 17 00:00:00 2001 From: MaikNeubert Date: Sun, 18 Feb 2024 21:07:51 +0100 Subject: [PATCH 02/10] implement tag filter in statviz (or comparison) --- .../statviz/components/filter/TagFilter.tsx | 44 +++++++++++++++++++ .../CreatedBoxesDataContainer.tsx | 6 +++ .../CreatedBoxesFilterContainer.tsx | 23 ++++++++-- .../statviz/dashboard/Dashboard.tsx | 6 +++ shared-components/types/generated/gql.ts | 4 +- shared-components/types/generated/graphql.ts | 4 +- 6 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 shared-components/statviz/components/filter/TagFilter.tsx diff --git a/shared-components/statviz/components/filter/TagFilter.tsx b/shared-components/statviz/components/filter/TagFilter.tsx new file mode 100644 index 000000000..349305979 --- /dev/null +++ b/shared-components/statviz/components/filter/TagFilter.tsx @@ -0,0 +1,44 @@ +import { makeVar, useReactiveVar } from "@apollo/client"; +import { Box } from "@chakra-ui/react"; +import MultiSelectFilter from "./MultiSelectFilter"; +import { IFilterValue } from "./ValueFilter"; +import { TagDimensionInfo } from "../../../types/generated/graphql"; +import useMultiSelectFilter from "../../hooks/useMultiSelectFilter"; + +interface ITagFilterValue extends IFilterValue { + color: string; + id: number; +} + +export const tagFilterId = "tags"; + +export const tagFilter = makeVar([]); + +export const tagToFilterValue = (tag: TagDimensionInfo): ITagFilterValue => ({ + value: tag.id!.toString(), + label: tag.name!, + color: tag.color!, + id: tag.id!, + urlId: tag.id!.toString(), +}); + +export default function TagFilter() { + const tagFilterOptions = useReactiveVar(tagFilter); + const { onFilterChange, filterValue } = useMultiSelectFilter( + tagFilterOptions, + tagFilterId, + ); + + return ( + + + + ); +} diff --git a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx index e1abea398..8d4c74996 100644 --- a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx +++ b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx @@ -13,6 +13,7 @@ const CREATED_BOXES_QUERY = gql(` productId categoryId createdOn + tagIds gender itemsCount } @@ -26,6 +27,11 @@ const CREATED_BOXES_QUERY = gql(` id name } + tag { + id + name + color + } } } } diff --git a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx index 804cf48cf..2ce818f43 100644 --- a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx +++ b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx @@ -20,6 +20,7 @@ import { products, } from "../../filter/GenderProductFilter"; import useMultiSelectFilter from "../../../hooks/useMultiSelectFilter"; +import { tagFilter, tagFilterId, tagToFilterValue } from "../../filter/TagFilter"; interface ICreatedBoxesFilterContainerProps { createdBoxes: CreatedBoxesData; @@ -35,15 +36,18 @@ export default function CreatedBoxesFilterContainer({ defaultBoxesOrItems, boxesOrItemsUrlId, ); - const productFilterValues = useReactiveVar(products); + const productFilterOptions = useReactiveVar(products); const { filterValue: filterProductGenders } = useMultiSelectFilter(genders, genderFilterId); const { filterValue: filterProducts } = useMultiSelectFilter( - productFilterValues, + productFilterOptions, productFilterId, ); - // use products from the createdBoxes query to feed the global products filter + const tagFilterOptions = useReactiveVar(tagFilter); + const { filterValue: filteredTags } = useMultiSelectFilter(tagFilterOptions, tagFilterId); + + // use products from the createdBoxes query to feed the global products and tags filter // and filter the product filter by filtered product genders useEffect(() => { const p = createdBoxes.dimensions!.product!.map((e) => productToFilterValue(e!)); @@ -57,6 +61,10 @@ export default function CreatedBoxesFilterContainer({ } else { products(p); } + + const tags = createdBoxes.dimensions!.tag!.map((e) => tagToFilterValue(e!)); + tagFilter(tags); + // we only need to update products if the product gender selection is updated // including filterProducts would cause unnecessary rerenders // eslint-disable-next-line react-hooks/exhaustive-deps @@ -93,13 +101,20 @@ export default function CreatedBoxesFilterContainer({ ), ); } + if (filteredTags.length > 0) { + filters.push( + filter((fact: CreatedBoxesResult) => + filteredTags.some((fT) => fact.tagIds!.includes(fT.id)), + ), + ); + } if (filters.length > 0) { // @ts-expect-error return tidy(createdBoxesFacts, ...filters); } return createdBoxesFacts; - }, [createdBoxesFacts, filterProductGenders, filterProducts]); + }, [createdBoxesFacts, filterProductGenders, filterProducts, filteredTags]); const filteredCreatedBoxesCube = { facts: filteredFacts, diff --git a/shared-components/statviz/dashboard/Dashboard.tsx b/shared-components/statviz/dashboard/Dashboard.tsx index 6075292cd..f85d1ea1c 100644 --- a/shared-components/statviz/dashboard/Dashboard.tsx +++ b/shared-components/statviz/dashboard/Dashboard.tsx @@ -6,6 +6,7 @@ import ItemsAndBoxes from "./ItemsAndBoxes"; import StockOverview from "./StockOverview"; import BoxesOrItemsSelect from "../components/filter/BoxesOrItemsSelect"; import GenderProductFilter from "../components/filter/GenderProductFilter"; +import TagFilter from "../components/filter/TagFilter"; export default function Dashboard() { return ( @@ -35,6 +36,11 @@ export default function Dashboard() { + +
+ +
+
diff --git a/shared-components/types/generated/gql.ts b/shared-components/types/generated/gql.ts index 222d06c39..b444c0d10 100644 --- a/shared-components/types/generated/gql.ts +++ b/shared-components/types/generated/gql.ts @@ -13,7 +13,7 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - "\n query createdBoxes($baseId: Int!) {\n createdBoxes(baseId: $baseId) {\n facts {\n boxesCount\n productId\n categoryId\n createdOn\n gender\n itemsCount\n }\n dimensions {\n product {\n id\n name\n gender\n }\n category {\n id\n name\n }\n }\n }\n }\n": types.CreatedBoxesDocument, + "\n query createdBoxes($baseId: Int!) {\n createdBoxes(baseId: $baseId) {\n facts {\n boxesCount\n productId\n categoryId\n createdOn\n tagIds\n gender\n itemsCount\n }\n dimensions {\n product {\n id\n name\n gender\n }\n category {\n id\n name\n }\n tag {\n id\n name\n color\n }\n }\n }\n }\n": types.CreatedBoxesDocument, "\n query movedBoxes($baseId: Int!) {\n movedBoxes(baseId: $baseId) {\n facts {\n movedOn\n targetId\n categoryId\n boxesCount\n itemsCount\n gender\n productName\n }\n dimensions {\n category {\n id\n name\n }\n target {\n id\n name\n type\n }\n }\n }\n }\n": types.MovedBoxesDocument, "\n query stockOverview($baseId: Int!) {\n stockOverview(baseId: $baseId) {\n facts {\n productName\n categoryId\n gender\n boxesCount\n itemsCount\n sizeId\n tagIds\n boxState\n locationId\n }\n dimensions {\n category {\n id\n name\n }\n size {\n id\n name\n }\n tag {\n id\n name\n }\n location {\n id\n name\n }\n }\n }\n }\n": types.StockOverviewDocument, "\n query BeneficiaryDemographics($baseId: Int!) {\n beneficiaryDemographics(baseId: $baseId) {\n facts {\n count\n createdOn\n age\n gender\n }\n dimensions {\n tag {\n name\n id\n }\n }\n }\n }\n": types.BeneficiaryDemographicsDocument, @@ -36,7 +36,7 @@ export function gql(source: string): unknown; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "\n query createdBoxes($baseId: Int!) {\n createdBoxes(baseId: $baseId) {\n facts {\n boxesCount\n productId\n categoryId\n createdOn\n gender\n itemsCount\n }\n dimensions {\n product {\n id\n name\n gender\n }\n category {\n id\n name\n }\n }\n }\n }\n"): (typeof documents)["\n query createdBoxes($baseId: Int!) {\n createdBoxes(baseId: $baseId) {\n facts {\n boxesCount\n productId\n categoryId\n createdOn\n gender\n itemsCount\n }\n dimensions {\n product {\n id\n name\n gender\n }\n category {\n id\n name\n }\n }\n }\n }\n"]; +export function gql(source: "\n query createdBoxes($baseId: Int!) {\n createdBoxes(baseId: $baseId) {\n facts {\n boxesCount\n productId\n categoryId\n createdOn\n tagIds\n gender\n itemsCount\n }\n dimensions {\n product {\n id\n name\n gender\n }\n category {\n id\n name\n }\n tag {\n id\n name\n color\n }\n }\n }\n }\n"): (typeof documents)["\n query createdBoxes($baseId: Int!) {\n createdBoxes(baseId: $baseId) {\n facts {\n boxesCount\n productId\n categoryId\n createdOn\n tagIds\n gender\n itemsCount\n }\n dimensions {\n product {\n id\n name\n gender\n }\n category {\n id\n name\n }\n tag {\n id\n name\n color\n }\n }\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/shared-components/types/generated/graphql.ts b/shared-components/types/generated/graphql.ts index fd386a3eb..94deb96fd 100644 --- a/shared-components/types/generated/graphql.ts +++ b/shared-components/types/generated/graphql.ts @@ -362,7 +362,7 @@ export type CreatedBoxesQueryVariables = Exact<{ }>; -export type CreatedBoxesQuery = { __typename?: 'Query', createdBoxes?: { __typename?: 'CreatedBoxesData', facts?: Array<{ __typename?: 'CreatedBoxesResult', boxesCount?: number | null, productId?: number | null, categoryId?: number | null, createdOn?: any | null, gender?: ProductGender | null, itemsCount?: number | null } | null> | null, dimensions?: { __typename?: 'CreatedBoxDataDimensions', product?: Array<{ __typename?: 'ProductDimensionInfo', id?: number | null, name?: string | null, gender?: ProductGender | null } | null> | null, category?: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null } | null> | null } | null } | null }; +export type CreatedBoxesQuery = { __typename?: 'Query', createdBoxes?: { __typename?: 'CreatedBoxesData', facts?: Array<{ __typename?: 'CreatedBoxesResult', boxesCount?: number | null, productId?: number | null, categoryId?: number | null, createdOn?: any | null, tagIds?: Array | null, gender?: ProductGender | null, itemsCount?: number | null } | null> | null, dimensions?: { __typename?: 'CreatedBoxDataDimensions', product?: Array<{ __typename?: 'ProductDimensionInfo', id?: number | null, name?: string | null, gender?: ProductGender | null } | null> | null, category?: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null } | null> | null, tag?: Array<{ __typename?: 'TagDimensionInfo', id?: number | null, name?: string | null, color?: string | null } | null> | null } | null } | null }; export type MovedBoxesQueryVariables = Exact<{ baseId: Scalars['Int']['input']; @@ -386,7 +386,7 @@ export type BeneficiaryDemographicsQueryVariables = Exact<{ export type BeneficiaryDemographicsQuery = { __typename?: 'Query', beneficiaryDemographics?: { __typename?: 'BeneficiaryDemographicsData', facts?: Array<{ __typename?: 'BeneficiaryDemographicsResult', count?: number | null, createdOn?: any | null, age?: number | null, gender?: HumanGender | null } | null> | null, dimensions?: { __typename?: 'BeneficiaryDemographicsDimensions', tag?: Array<{ __typename?: 'TagDimensionInfo', name?: string | null, id?: number | null } | null> | null } | null } | null }; -export const CreatedBoxesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"createdBoxes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdBoxes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"boxesCount"}},{"kind":"Field","name":{"kind":"Name","value":"productId"}},{"kind":"Field","name":{"kind":"Name","value":"categoryId"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"itemsCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"product"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}}]}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const CreatedBoxesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"createdBoxes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdBoxes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"boxesCount"}},{"kind":"Field","name":{"kind":"Name","value":"productId"}},{"kind":"Field","name":{"kind":"Name","value":"categoryId"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"tagIds"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"itemsCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"product"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}}]}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const MovedBoxesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"movedBoxes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"movedBoxes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"movedOn"}},{"kind":"Field","name":{"kind":"Name","value":"targetId"}},{"kind":"Field","name":{"kind":"Name","value":"categoryId"}},{"kind":"Field","name":{"kind":"Name","value":"boxesCount"}},{"kind":"Field","name":{"kind":"Name","value":"itemsCount"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"productName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const StockOverviewDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"stockOverview"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stockOverview"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"categoryId"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"boxesCount"}},{"kind":"Field","name":{"kind":"Name","value":"itemsCount"}},{"kind":"Field","name":{"kind":"Name","value":"sizeId"}},{"kind":"Field","name":{"kind":"Name","value":"tagIds"}},{"kind":"Field","name":{"kind":"Name","value":"boxState"}},{"kind":"Field","name":{"kind":"Name","value":"locationId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"size"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"location"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const BeneficiaryDemographicsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"BeneficiaryDemographics"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"beneficiaryDemographics"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]}}]} as unknown as DocumentNode; From fb3c069086d0668954b819283ce72c72f6f88bd2 Mon Sep 17 00:00:00 2001 From: MaikNeubert Date: Sun, 18 Feb 2024 21:09:01 +0100 Subject: [PATCH 03/10] modify cache for TagDimensionInfo --- front/src/queries/cache.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/front/src/queries/cache.ts b/front/src/queries/cache.ts index f22df81ec..0dfce52ea 100644 --- a/front/src/queries/cache.ts +++ b/front/src/queries/cache.ts @@ -17,6 +17,9 @@ export const cache = new InMemoryCache({ // DimensionInfos must be normalized by id and name keyFields: ["id", "name"], }, + TagDimensionInfo: { + keyFields: ["id", "name"], + }, }, }); From 7a0bed47e83dd24aa2b9163397acaa7a31746a69 Mon Sep 17 00:00:00 2001 From: MaikNeubert Date: Sat, 24 Feb 2024 11:34:07 +0100 Subject: [PATCH 04/10] tag filtering --- .../statviz/components/NoDataCard.tsx | 15 +++- .../components/filter/GenderProductFilter.tsx | 8 +- .../statviz/components/filter/TagFilter.tsx | 6 +- .../CreatedBoxesFilterContainer.tsx | 12 ++- .../demographic/DemographicCharts.tsx | 10 +++ .../demographic/DemographicDataContainer.tsx | 53 ++++++++++++ .../DemographicFilterContainer.tsx | 81 +++++++++++++++++++ .../demographic/DemographicFilterWrapper.tsx | 0 .../demographic/DemographicPyramid.tsx | 58 ++++++------- .../movedBoxes/MovedBoxesDataContainer.tsx | 3 +- .../movedBoxes/MovedBoxesFilterContainer.tsx | 10 ++- .../stock/StockDataContainer.tsx | 5 +- .../visualizations/stock/StockDataFilter.tsx | 33 +++++++- .../statviz/dashboard/Demographics.tsx | 4 +- .../statviz/hooks/useDemographics.ts | 55 ------------- .../statviz/queries/fragments.ts | 17 ++++ .../filter.tsx} | 0 shared-components/types/generated/gql.ts | 22 +++-- shared-components/types/generated/graphql.ts | 26 +++--- 19 files changed, 291 insertions(+), 127 deletions(-) create mode 100644 shared-components/statviz/components/visualizations/demographic/DemographicDataContainer.tsx create mode 100644 shared-components/statviz/components/visualizations/demographic/DemographicFilterContainer.tsx delete mode 100644 shared-components/statviz/components/visualizations/demographic/DemographicFilterWrapper.tsx delete mode 100644 shared-components/statviz/hooks/useDemographics.ts create mode 100644 shared-components/statviz/queries/fragments.ts rename shared-components/statviz/{components/visualizations/demographic/DemographicDataWrapper.tsx => state/filter.tsx} (100%) diff --git a/shared-components/statviz/components/NoDataCard.tsx b/shared-components/statviz/components/NoDataCard.tsx index 555ec0f66..a8fc7910b 100644 --- a/shared-components/statviz/components/NoDataCard.tsx +++ b/shared-components/statviz/components/NoDataCard.tsx @@ -1,12 +1,21 @@ import { Card, CardHeader, Heading } from "@chakra-ui/react"; -export default function NoDataCard(props: { header: string }) { +interface INoDataCardProps { + header: string; + message?: string; +} + +export default function NoDataCard({ header, message }: INoDataCardProps) { return ( - {props.header} + {header} - No data for the selected time range or selected filters + {message} ); } + +NoDataCard.defaultProps = { + message: "No data for the selected time range or selected filters", +}; diff --git a/shared-components/statviz/components/filter/GenderProductFilter.tsx b/shared-components/statviz/components/filter/GenderProductFilter.tsx index 5e1dcd787..a0c201dca 100644 --- a/shared-components/statviz/components/filter/GenderProductFilter.tsx +++ b/shared-components/statviz/components/filter/GenderProductFilter.tsx @@ -92,9 +92,9 @@ export default function GenderProductFilter() { @@ -102,9 +102,9 @@ export default function GenderProductFilter() { diff --git a/shared-components/statviz/components/filter/TagFilter.tsx b/shared-components/statviz/components/filter/TagFilter.tsx index 349305979..ff1422033 100644 --- a/shared-components/statviz/components/filter/TagFilter.tsx +++ b/shared-components/statviz/components/filter/TagFilter.tsx @@ -1,5 +1,5 @@ -import { makeVar, useReactiveVar } from "@apollo/client"; import { Box } from "@chakra-ui/react"; +import { makeVar, useReactiveVar } from "@apollo/client"; import MultiSelectFilter from "./MultiSelectFilter"; import { IFilterValue } from "./ValueFilter"; import { TagDimensionInfo } from "../../../types/generated/graphql"; @@ -34,9 +34,9 @@ export default function TagFilter() { diff --git a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx index 2ce818f43..368e5a366 100644 --- a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx +++ b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo } from "react"; -import { TidyFn, filter, tidy } from "@tidyjs/tidy"; +import { TidyFn, distinct, filter, tidy } from "@tidyjs/tidy"; import { useReactiveVar } from "@apollo/client"; import { CreatedBoxesData, CreatedBoxesResult } from "../../../../types/generated/graphql"; import CreatedBoxesCharts from "./CreatedBoxesCharts"; @@ -47,7 +47,8 @@ export default function CreatedBoxesFilterContainer({ const tagFilterOptions = useReactiveVar(tagFilter); const { filterValue: filteredTags } = useMultiSelectFilter(tagFilterOptions, tagFilterId); - // use products from the createdBoxes query to feed the global products and tags filter + // use products from the createdBoxes query to feed the global products and Tags for Boxes filter + // Beneficiary and All Tags are merged inside the DemographicFilterContainer // and filter the product filter by filtered product genders useEffect(() => { const p = createdBoxes.dimensions!.product!.map((e) => productToFilterValue(e!)); @@ -62,9 +63,12 @@ export default function CreatedBoxesFilterContainer({ products(p); } - const tags = createdBoxes.dimensions!.tag!.map((e) => tagToFilterValue(e!)); - tagFilter(tags); + const boxTags = createdBoxes.dimensions!.tag!.map((e) => tagToFilterValue(e!)); + if (boxTags.length > 0) { + const distinctTagFilterValues = tidy([...tagFilterOptions, ...boxTags], distinct(["id"])); + tagFilter(distinctTagFilterValues); + } // we only need to update products if the product gender selection is updated // including filterProducts would cause unnecessary rerenders // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/shared-components/statviz/components/visualizations/demographic/DemographicCharts.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicCharts.tsx index e69de29bb..550a61c0b 100644 --- a/shared-components/statviz/components/visualizations/demographic/DemographicCharts.tsx +++ b/shared-components/statviz/components/visualizations/demographic/DemographicCharts.tsx @@ -0,0 +1,10 @@ +import { BeneficiaryDemographicsData } from "../../../../types/generated/graphql"; +import DemographicPyramid from "./DemographicPyramid"; + +interface IDemographicChartProps { + demographics: BeneficiaryDemographicsData; +} + +export default function DemographicCharts({ demographics }: IDemographicChartProps) { + return ; +} diff --git a/shared-components/statviz/components/visualizations/demographic/DemographicDataContainer.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicDataContainer.tsx new file mode 100644 index 000000000..666e108c6 --- /dev/null +++ b/shared-components/statviz/components/visualizations/demographic/DemographicDataContainer.tsx @@ -0,0 +1,53 @@ +import { gql, useQuery } from "@apollo/client"; +import { Spinner } from "@chakra-ui/react"; +import { useParams } from "react-router-dom"; +import DemographicFilterContainer from "./DemographicFilterContainer"; +import ErrorCard, { predefinedErrors } from "../../ErrorCard"; +import NoDataCard from "../../NoDataCard"; + +const DEMOGRAPHIC_QUERY = gql(` + query BeneficiaryDemographics($baseId: Int!) { + beneficiaryDemographics(baseId: $baseId) { + facts { + count + createdOn + age + gender + tagIds + } + dimensions { + tag { + id + name + color + } + } + } + } +`); + +export default function DemographicDataContainer() { + const { baseId } = useParams(); + const { data, loading, error } = useQuery(DEMOGRAPHIC_QUERY, { + variables: { baseId: parseInt(baseId!, 10) }, + }); + + if (error) { + return ; + } + if (loading) { + return ; + } + if (data === undefined) { + return ; + } + if (data.beneficiaryDemographics.facts.length === 0) { + return ( + + ); + } + return ; +} diff --git a/shared-components/statviz/components/visualizations/demographic/DemographicFilterContainer.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicFilterContainer.tsx new file mode 100644 index 000000000..1fe2e16c0 --- /dev/null +++ b/shared-components/statviz/components/visualizations/demographic/DemographicFilterContainer.tsx @@ -0,0 +1,81 @@ +import { useReactiveVar } from "@apollo/client"; +import { useEffect, useMemo } from "react"; +import { TidyFn, distinct, filter, tidy } from "@tidyjs/tidy"; +import { + BeneficiaryDemographicsData, + BeneficiaryDemographicsResult, +} from "../../../../types/generated/graphql"; +import DemographicCharts from "./DemographicCharts"; +import { tagFilter, tagFilterId, tagToFilterValue } from "../../filter/TagFilter"; +import useMultiSelectFilter from "../../../hooks/useMultiSelectFilter"; +import useTimerange from "../../../hooks/useTimerange"; +import { filterListByInterval } from "../../../../utils/helpers"; + +interface IDemographicFilterContainerProps { + demographics: BeneficiaryDemographicsData; +} + +export default function DemographicFilterContainer({ + demographics, +}: IDemographicFilterContainerProps) { + const { interval } = useTimerange(); + + const tagFilterOptions = useReactiveVar(tagFilter); + const { filterValue: filteredTags } = useMultiSelectFilter(tagFilterOptions, tagFilterId); + + // merge Beneficiary tags to Box and All tags + useEffect(() => { + const beneficiaryTagFilterValues = demographics.dimensions!.tag!.map((e) => + tagToFilterValue(e!), + ); + + if (beneficiaryTagFilterValues.length > 0) { + const distinctTagFilterValues = tidy( + [...tagFilterOptions, ...beneficiaryTagFilterValues], + distinct(["id"]), + ); + + tagFilter(distinctTagFilterValues); + } + // including tagFilterOptions in the dependencies can lead to infinite update loops + // between CreatedBoxes updating the TagFilter and DemographicFilter updating the TagFilter + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [demographics.dimensions]); + + const demographicFacts = useMemo(() => { + try { + return filterListByInterval( + (demographics.facts as BeneficiaryDemographicsResult[]) ?? [], + "createdOn", + interval, + ) as BeneficiaryDemographicsResult[]; + } catch (error) { + // TODO useError + } + return []; + }, [demographics.facts, interval]); + + const filteredFacts = useMemo(() => { + const filters: TidyFn[] = []; + if (filteredTags.length > 0) { + filters.push( + filter((fact: BeneficiaryDemographicsResult) => + filteredTags.some((fT) => fact.tagIds!.includes(fT.id)), + ), + ); + } + + if (filters.length > 0) { + // @ts-expect-error + return tidy(demographicFacts, ...filters); + } + return demographicFacts; + }, [demographicFacts, filteredTags]); + + const demographicCube = { + ...demographics, + facts: filteredFacts, + }; + + return ; +} diff --git a/shared-components/statviz/components/visualizations/demographic/DemographicFilterWrapper.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicFilterWrapper.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/shared-components/statviz/components/visualizations/demographic/DemographicPyramid.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicPyramid.tsx index 5e00938ba..b9602b896 100644 --- a/shared-components/statviz/components/visualizations/demographic/DemographicPyramid.tsx +++ b/shared-components/statviz/components/visualizations/demographic/DemographicPyramid.tsx @@ -1,12 +1,16 @@ -import { Card, CardBody, CardHeader, Heading } from "@chakra-ui/react"; +import { Card, CardBody } from "@chakra-ui/react"; import { range } from "lodash"; -import { ApolloError } from "@apollo/client"; import { filter, sum, summarize, tidy, groupBy, map } from "@tidyjs/tidy"; +import { useMemo } from "react"; import BarChartCenterAxis from "../../custom-graphs/BarChartCenterAxis"; -import { HumanGender } from "../../../../types/generated/graphql"; +import { + BeneficiaryDemographicsData, + BeneficiaryDemographicsResult, + HumanGender, +} from "../../../../types/generated/graphql"; import VisHeader from "../../VisHeader"; -import useDemographics from "../../../hooks/useDemographics"; import getOnExport from "../../../utils/chartExport"; +import NoDataCard from "../../NoDataCard"; export interface IDemographicFact { createdOn: Date; @@ -28,6 +32,7 @@ export interface IDemographicCube { } interface IDemographicChartProps { + demographics: BeneficiaryDemographicsData; width: number; height: number; } @@ -35,42 +40,23 @@ interface IDemographicChartProps { const visId = "demographic-pyramid"; const heading = "Demographic"; -export default function DemographicChart({ width, height }: IDemographicChartProps) { - const { demographics, error, loading } = useDemographics(); +export default function DemographicPyramid({ + demographics, + width, + height, +}: IDemographicChartProps) { const onExport = getOnExport(BarChartCenterAxis); - if (error instanceof ApolloError) { - return

{error.message}

; - } - if (loading || typeof demographics === "undefined") { - return

loading...

; - } - if (demographics.length === 0) { - return ( - - - {heading} - - -

- No demographic data available for your base. Either you are a sending base which is not - registering people or the birth date is not registered. -

-
-
- ); - } - const prepareFacts = () => { const dataXr = tidy( - demographics, + demographics.facts as BeneficiaryDemographicsResult[], filter((value) => value.gender === HumanGender.Male), groupBy("age", [summarize({ count: sum("count") })]), map((value) => ({ x: value.count, y: value.age ?? 0 })), ); const dataXl = tidy( - demographics, + demographics.facts as BeneficiaryDemographicsResult[], filter((value) => value.gender === HumanGender.Female), groupBy("age", [summarize({ count: sum("count") })]), map((value) => ({ x: value.count, y: value.age ?? 0 })), @@ -79,12 +65,16 @@ export default function DemographicChart({ width, height }: IDemographicChartPro return [dataXr, dataXl]; }; - const [dataXr, dataXl] = prepareFacts(); + const [dataXr, dataXl] = useMemo(prepareFacts, [demographics.facts]); + + if (dataXr.length === 0 && dataXl.length === 0) { + return ; + } const maxAge: number = - demographics.reduce((acc: number, current) => { - if (!current.age) return acc; - if (current.age > acc) return current.age; + demographics.facts!.reduce((acc: number, current: BeneficiaryDemographicsResult) => { + if (!current!.age) return acc; + if (current!.age > acc) return current!.age; return acc; }, 0) ?? 100; diff --git a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx index 6172c0e8a..d2d3b0bea 100644 --- a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx +++ b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx @@ -17,6 +17,7 @@ export const MOVED_BOXES_QUERY = gql(` itemsCount gender productName + tagIds } dimensions { category { @@ -35,7 +36,7 @@ export const MOVED_BOXES_QUERY = gql(` // The data wrapper collects data and passes it to the filter-wrapper // which applys filters to the data -// the filter wrapper passes it to the Chart which maps the datacube to a VisX or nivo Chart +// the filter wrapper passes it to the Chart which maps the Datacube to a VisX or Nivo Chart export default function MovedBoxesDataContainer() { const { baseId } = useParams(); const { data, loading, error } = useQuery<{ movedBoxes: MovedBoxesData }, QueryMovedBoxesArgs>( diff --git a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx index 967f27906..ac545635b 100644 --- a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx +++ b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx @@ -18,6 +18,7 @@ import { productFilterId, products, } from "../../filter/GenderProductFilter"; +import { tagFilter, tagFilterId } from "../../filter/TagFilter"; export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxesData }) { const { interval } = useTimerange(); @@ -29,6 +30,7 @@ export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxe ); const productsFilterValues = useReactiveVar(products); + const tagFilterValues = useReactiveVar(tagFilter); const { filterValue: productsFilter } = useMultiSelectFilter( productsFilterValues, @@ -36,6 +38,7 @@ export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxe ); const { filterValue: genderFilter } = useMultiSelectFilter(genders, genderFilterId); + const { filterValue: filteredTags } = useMultiSelectFilter(tagFilterValues, tagFilterId); const movedBoxesFacts = useMemo(() => { try { @@ -70,13 +73,18 @@ export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxe ), ); } + if (filteredTags.length > 0) { + filters.push( + filter((fact: MovedBoxesResult) => filteredTags.some((fT) => fact.tagIds!.includes(fT.id))), + ); + } if (filters.length > 0) { // @ts-expect-error return tidy(movedBoxesFacts, ...filters); } return movedBoxesFacts; - }, [genderFilter, movedBoxesFacts, productsFilter]); + }, [filteredTags, genderFilter, movedBoxesFacts, productsFilter]); const filteredMovedBoxesCube = { facts: filteredFacts as MovedBoxesResult[], diff --git a/shared-components/statviz/components/visualizations/stock/StockDataContainer.tsx b/shared-components/statviz/components/visualizations/stock/StockDataContainer.tsx index 4344be1d9..02aeb9542 100644 --- a/shared-components/statviz/components/visualizations/stock/StockDataContainer.tsx +++ b/shared-components/statviz/components/visualizations/stock/StockDataContainer.tsx @@ -1,9 +1,9 @@ import { useQuery } from "@apollo/client"; import { Box, Spinner } from "@chakra-ui/react"; import { useParams } from "react-router-dom"; -import { gql } from "../../../../types/generated/gql"; import StockDataFilter from "./StockDataFilter"; import ErrorCard, { predefinedErrors } from "../../ErrorCard"; +import { gql } from "../../../../types/generated"; const STOCK_QUERY = gql(` query stockOverview($baseId: Int!) { @@ -29,8 +29,7 @@ const STOCK_QUERY = gql(` name } tag { - id - name + ...TagFragment } location { id diff --git a/shared-components/statviz/components/visualizations/stock/StockDataFilter.tsx b/shared-components/statviz/components/visualizations/stock/StockDataFilter.tsx index ea001d39c..d6a733d13 100644 --- a/shared-components/statviz/components/visualizations/stock/StockDataFilter.tsx +++ b/shared-components/statviz/components/visualizations/stock/StockDataFilter.tsx @@ -1,4 +1,7 @@ -import { StockOverviewData } from "../../../../types/generated/graphql"; +import { useReactiveVar } from "@apollo/client"; +import { useMemo } from "react"; +import { TidyFn, filter, tidy } from "@tidyjs/tidy"; +import { StockOverviewData, StockOverviewResult } from "../../../../types/generated/graphql"; import StockCharts from "./StockCharts"; import { boxesOrItemsFilterValues, @@ -6,6 +9,8 @@ import { defaultBoxesOrItems, } from "../../filter/BoxesOrItemsSelect"; import useValueFilter from "../../../hooks/useValueFilter"; +import useMultiSelectFilter from "../../../hooks/useMultiSelectFilter"; +import { tagFilter, tagFilterId } from "../../filter/TagFilter"; interface IStockDataFilterProps { stockOverview: StockOverviewData; @@ -14,11 +19,35 @@ interface IStockDataFilterProps { export default function StockDataFilter({ stockOverview }: IStockDataFilterProps) { // currently not affected by the selected timerange + const tagFilerValues = useReactiveVar(tagFilter); + const { filterValue } = useValueFilter( boxesOrItemsFilterValues, defaultBoxesOrItems, boxesOrItemsUrlId, ); - return ; + const { filterValue: filteredTags } = useMultiSelectFilter(tagFilerValues, tagFilterId); + + const filteredStockOverview = useMemo(() => { + const filters: TidyFn[] = []; + if (filteredTags.length > 0) { + filters.push( + filter((fact: StockOverviewResult) => + filteredTags.some((fT) => fact.tagIds!.includes(fT.id)), + ), + ); + } + + if (filter.length > 0) { + return { + ...stockOverview, + // @ts-expect-error ts(2556) + facts: tidy(stockOverview.facts, ...filters), + } as StockOverviewData; + } + return stockOverview; + }, [filteredTags, stockOverview]); + + return ; } diff --git a/shared-components/statviz/dashboard/Demographics.tsx b/shared-components/statviz/dashboard/Demographics.tsx index 7838932f5..ff0cdafd3 100644 --- a/shared-components/statviz/dashboard/Demographics.tsx +++ b/shared-components/statviz/dashboard/Demographics.tsx @@ -8,7 +8,7 @@ import { WrapItem, Box, } from "@chakra-ui/react"; -import DemographicChart from "../components/visualizations/demographic/DemographicPyramid"; +import DemographicDataContainer from "../components/visualizations/demographic/DemographicDataContainer"; export default function Demographics() { return ( @@ -22,7 +22,7 @@ export default function Demographics() { - + diff --git a/shared-components/statviz/hooks/useDemographics.ts b/shared-components/statviz/hooks/useDemographics.ts deleted file mode 100644 index c60bcbd0f..000000000 --- a/shared-components/statviz/hooks/useDemographics.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { useQuery } from "@apollo/client"; -import { useParams } from "react-router-dom"; -import { useMemo } from "react"; -import { gql } from "../../types/generated/gql"; -import { BeneficiaryDemographicsResult } from "../../types/generated/graphql"; -import useTimerange from "./useTimerange"; -import { filterListByInterval } from "../../utils/helpers"; - -const DEMOGRAPHIC_QUERY = gql(` - query BeneficiaryDemographics($baseId: Int!) { - beneficiaryDemographics(baseId: $baseId) { - facts { - count - createdOn - age - gender - } - dimensions { - tag { - name - id - } - } - } - } -`); - -export default function useDemographics() { - const { baseId } = useParams(); - const { data, loading, error } = useQuery(DEMOGRAPHIC_QUERY, { - variables: { baseId: parseInt(baseId!, 10) }, - }); - - const { timerange, interval } = useTimerange(); - - return { - demographics: useMemo(() => { - if (!data) return []; - - const demographicFacts = data.beneficiaryDemographics - ?.facts as BeneficiaryDemographicsResult[]; - - try { - return filterListByInterval(demographicFacts, "createdOn", interval); - } catch (intervalFilterError) { - // TODO show toast with error message? - } - return []; - }, [data, interval]), - data, - loading, - error, - timerange, - }; -} diff --git a/shared-components/statviz/queries/fragments.ts b/shared-components/statviz/queries/fragments.ts new file mode 100644 index 000000000..1833f737a --- /dev/null +++ b/shared-components/statviz/queries/fragments.ts @@ -0,0 +1,17 @@ +import { gql } from "../../types/generated"; + +export const TAG_FRAGMENT = gql(` + fragment TagFragment on TagDimensionInfo { + id + name + color + } +`); + +export const PRODUCT_FRAGMENT = gql(` + fragment ProductFragment on ProductDimensionInfo { + id + name + gender + } +`); diff --git a/shared-components/statviz/components/visualizations/demographic/DemographicDataWrapper.tsx b/shared-components/statviz/state/filter.tsx similarity index 100% rename from shared-components/statviz/components/visualizations/demographic/DemographicDataWrapper.tsx rename to shared-components/statviz/state/filter.tsx diff --git a/shared-components/types/generated/gql.ts b/shared-components/types/generated/gql.ts index b444c0d10..cb64d9942 100644 --- a/shared-components/types/generated/gql.ts +++ b/shared-components/types/generated/gql.ts @@ -14,9 +14,11 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ */ const documents = { "\n query createdBoxes($baseId: Int!) {\n createdBoxes(baseId: $baseId) {\n facts {\n boxesCount\n productId\n categoryId\n createdOn\n tagIds\n gender\n itemsCount\n }\n dimensions {\n product {\n id\n name\n gender\n }\n category {\n id\n name\n }\n tag {\n id\n name\n color\n }\n }\n }\n }\n": types.CreatedBoxesDocument, - "\n query movedBoxes($baseId: Int!) {\n movedBoxes(baseId: $baseId) {\n facts {\n movedOn\n targetId\n categoryId\n boxesCount\n itemsCount\n gender\n productName\n }\n dimensions {\n category {\n id\n name\n }\n target {\n id\n name\n type\n }\n }\n }\n }\n": types.MovedBoxesDocument, - "\n query stockOverview($baseId: Int!) {\n stockOverview(baseId: $baseId) {\n facts {\n productName\n categoryId\n gender\n boxesCount\n itemsCount\n sizeId\n tagIds\n boxState\n locationId\n }\n dimensions {\n category {\n id\n name\n }\n size {\n id\n name\n }\n tag {\n id\n name\n }\n location {\n id\n name\n }\n }\n }\n }\n": types.StockOverviewDocument, - "\n query BeneficiaryDemographics($baseId: Int!) {\n beneficiaryDemographics(baseId: $baseId) {\n facts {\n count\n createdOn\n age\n gender\n }\n dimensions {\n tag {\n name\n id\n }\n }\n }\n }\n": types.BeneficiaryDemographicsDocument, + "\n query BeneficiaryDemographics($baseId: Int!) {\n beneficiaryDemographics(baseId: $baseId) {\n facts {\n count\n createdOn\n age\n gender\n tagIds\n }\n }\n }\n": types.BeneficiaryDemographicsDocument, + "\n query movedBoxes($baseId: Int!) {\n movedBoxes(baseId: $baseId) {\n facts {\n movedOn\n targetId\n categoryId\n boxesCount\n itemsCount\n gender\n productName\n tagIds\n }\n dimensions {\n category {\n id\n name\n }\n target {\n id\n name\n type\n }\n }\n }\n }\n": types.MovedBoxesDocument, + "\n query stockOverview($baseId: Int!) {\n stockOverview(baseId: $baseId) {\n facts {\n productName\n categoryId\n gender\n boxesCount\n itemsCount\n sizeId\n tagIds\n boxState\n locationId\n }\n dimensions {\n category {\n id\n name\n }\n size {\n id\n name\n }\n tag {\n ...TagFragment\n }\n location {\n id\n name\n }\n }\n }\n }\n": types.StockOverviewDocument, + "\n fragment TagFragment on TagDimensionInfo {\n id\n name\n color\n }\n": types.TagFragmentFragmentDoc, + "\n fragment ProductFragment on ProductDimensionInfo {\n id\n name\n gender\n }\n": types.ProductFragmentFragmentDoc, }; /** @@ -40,15 +42,23 @@ export function gql(source: "\n query createdBoxes($baseId: Int!) {\n create /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "\n query movedBoxes($baseId: Int!) {\n movedBoxes(baseId: $baseId) {\n facts {\n movedOn\n targetId\n categoryId\n boxesCount\n itemsCount\n gender\n productName\n }\n dimensions {\n category {\n id\n name\n }\n target {\n id\n name\n type\n }\n }\n }\n }\n"): (typeof documents)["\n query movedBoxes($baseId: Int!) {\n movedBoxes(baseId: $baseId) {\n facts {\n movedOn\n targetId\n categoryId\n boxesCount\n itemsCount\n gender\n productName\n }\n dimensions {\n category {\n id\n name\n }\n target {\n id\n name\n type\n }\n }\n }\n }\n"]; +export function gql(source: "\n query BeneficiaryDemographics($baseId: Int!) {\n beneficiaryDemographics(baseId: $baseId) {\n facts {\n count\n createdOn\n age\n gender\n tagIds\n }\n }\n }\n"): (typeof documents)["\n query BeneficiaryDemographics($baseId: Int!) {\n beneficiaryDemographics(baseId: $baseId) {\n facts {\n count\n createdOn\n age\n gender\n tagIds\n }\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "\n query stockOverview($baseId: Int!) {\n stockOverview(baseId: $baseId) {\n facts {\n productName\n categoryId\n gender\n boxesCount\n itemsCount\n sizeId\n tagIds\n boxState\n locationId\n }\n dimensions {\n category {\n id\n name\n }\n size {\n id\n name\n }\n tag {\n id\n name\n }\n location {\n id\n name\n }\n }\n }\n }\n"): (typeof documents)["\n query stockOverview($baseId: Int!) {\n stockOverview(baseId: $baseId) {\n facts {\n productName\n categoryId\n gender\n boxesCount\n itemsCount\n sizeId\n tagIds\n boxState\n locationId\n }\n dimensions {\n category {\n id\n name\n }\n size {\n id\n name\n }\n tag {\n id\n name\n }\n location {\n id\n name\n }\n }\n }\n }\n"]; +export function gql(source: "\n query movedBoxes($baseId: Int!) {\n movedBoxes(baseId: $baseId) {\n facts {\n movedOn\n targetId\n categoryId\n boxesCount\n itemsCount\n gender\n productName\n tagIds\n }\n dimensions {\n category {\n id\n name\n }\n target {\n id\n name\n type\n }\n }\n }\n }\n"): (typeof documents)["\n query movedBoxes($baseId: Int!) {\n movedBoxes(baseId: $baseId) {\n facts {\n movedOn\n targetId\n categoryId\n boxesCount\n itemsCount\n gender\n productName\n tagIds\n }\n dimensions {\n category {\n id\n name\n }\n target {\n id\n name\n type\n }\n }\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "\n query BeneficiaryDemographics($baseId: Int!) {\n beneficiaryDemographics(baseId: $baseId) {\n facts {\n count\n createdOn\n age\n gender\n }\n dimensions {\n tag {\n name\n id\n }\n }\n }\n }\n"): (typeof documents)["\n query BeneficiaryDemographics($baseId: Int!) {\n beneficiaryDemographics(baseId: $baseId) {\n facts {\n count\n createdOn\n age\n gender\n }\n dimensions {\n tag {\n name\n id\n }\n }\n }\n }\n"]; +export function gql(source: "\n query stockOverview($baseId: Int!) {\n stockOverview(baseId: $baseId) {\n facts {\n productName\n categoryId\n gender\n boxesCount\n itemsCount\n sizeId\n tagIds\n boxState\n locationId\n }\n dimensions {\n category {\n id\n name\n }\n size {\n id\n name\n }\n tag {\n ...TagFragment\n }\n location {\n id\n name\n }\n }\n }\n }\n"): (typeof documents)["\n query stockOverview($baseId: Int!) {\n stockOverview(baseId: $baseId) {\n facts {\n productName\n categoryId\n gender\n boxesCount\n itemsCount\n sizeId\n tagIds\n boxState\n locationId\n }\n dimensions {\n category {\n id\n name\n }\n size {\n id\n name\n }\n tag {\n ...TagFragment\n }\n location {\n id\n name\n }\n }\n }\n }\n"]; +/** + * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function gql(source: "\n fragment TagFragment on TagDimensionInfo {\n id\n name\n color\n }\n"): (typeof documents)["\n fragment TagFragment on TagDimensionInfo {\n id\n name\n color\n }\n"]; +/** + * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function gql(source: "\n fragment ProductFragment on ProductDimensionInfo {\n id\n name\n gender\n }\n"): (typeof documents)["\n fragment ProductFragment on ProductDimensionInfo {\n id\n name\n gender\n }\n"]; export function gql(source: string) { return (documents as any)[source] ?? {}; diff --git a/shared-components/types/generated/graphql.ts b/shared-components/types/generated/graphql.ts index 94deb96fd..044484fa2 100644 --- a/shared-components/types/generated/graphql.ts +++ b/shared-components/types/generated/graphql.ts @@ -364,29 +364,37 @@ export type CreatedBoxesQueryVariables = Exact<{ export type CreatedBoxesQuery = { __typename?: 'Query', createdBoxes?: { __typename?: 'CreatedBoxesData', facts?: Array<{ __typename?: 'CreatedBoxesResult', boxesCount?: number | null, productId?: number | null, categoryId?: number | null, createdOn?: any | null, tagIds?: Array | null, gender?: ProductGender | null, itemsCount?: number | null } | null> | null, dimensions?: { __typename?: 'CreatedBoxDataDimensions', product?: Array<{ __typename?: 'ProductDimensionInfo', id?: number | null, name?: string | null, gender?: ProductGender | null } | null> | null, category?: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null } | null> | null, tag?: Array<{ __typename?: 'TagDimensionInfo', id?: number | null, name?: string | null, color?: string | null } | null> | null } | null } | null }; -export type MovedBoxesQueryVariables = Exact<{ +export type BeneficiaryDemographicsQueryVariables = Exact<{ baseId: Scalars['Int']['input']; }>; -export type MovedBoxesQuery = { __typename?: 'Query', movedBoxes?: { __typename?: 'MovedBoxesData', facts?: Array<{ __typename?: 'MovedBoxesResult', movedOn: any, targetId: string, categoryId: number, boxesCount: number, itemsCount: number, gender: ProductGender, productName: string } | null> | null, dimensions?: { __typename?: 'MovedBoxDataDimensions', category?: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null } | null> | null, target?: Array<{ __typename?: 'TargetDimensionInfo', id?: string | null, name?: string | null, type?: TargetType | null } | null> | null } | null } | null }; +export type BeneficiaryDemographicsQuery = { __typename?: 'Query', beneficiaryDemographics?: { __typename?: 'BeneficiaryDemographicsData', facts?: Array<{ __typename?: 'BeneficiaryDemographicsResult', count?: number | null, createdOn?: any | null, age?: number | null, gender?: HumanGender | null, tagIds?: Array | null } | null> | null } | null }; -export type StockOverviewQueryVariables = Exact<{ +export type MovedBoxesQueryVariables = Exact<{ baseId: Scalars['Int']['input']; }>; -export type StockOverviewQuery = { __typename?: 'Query', stockOverview?: { __typename?: 'StockOverviewData', facts: Array<{ __typename?: 'StockOverviewResult', productName: string, categoryId: number, gender: ProductGender, boxesCount: number, itemsCount: number, sizeId: number, tagIds?: Array | null, boxState: BoxState, locationId: number }>, dimensions: { __typename?: 'StockOverviewDataDimensions', category: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null }>, size: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null }>, tag: Array<{ __typename?: 'TagDimensionInfo', id?: number | null, name?: string | null }>, location: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null }> } } | null }; +export type MovedBoxesQuery = { __typename?: 'Query', movedBoxes?: { __typename?: 'MovedBoxesData', facts?: Array<{ __typename?: 'MovedBoxesResult', movedOn: any, targetId: string, categoryId: number, boxesCount: number, itemsCount: number, gender: ProductGender, productName: string, tagIds?: Array | null } | null> | null, dimensions?: { __typename?: 'MovedBoxDataDimensions', category?: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null } | null> | null, target?: Array<{ __typename?: 'TargetDimensionInfo', id?: string | null, name?: string | null, type?: TargetType | null } | null> | null } | null } | null }; -export type BeneficiaryDemographicsQueryVariables = Exact<{ +export type StockOverviewQueryVariables = Exact<{ baseId: Scalars['Int']['input']; }>; -export type BeneficiaryDemographicsQuery = { __typename?: 'Query', beneficiaryDemographics?: { __typename?: 'BeneficiaryDemographicsData', facts?: Array<{ __typename?: 'BeneficiaryDemographicsResult', count?: number | null, createdOn?: any | null, age?: number | null, gender?: HumanGender | null } | null> | null, dimensions?: { __typename?: 'BeneficiaryDemographicsDimensions', tag?: Array<{ __typename?: 'TagDimensionInfo', name?: string | null, id?: number | null } | null> | null } | null } | null }; +export type StockOverviewQuery = { __typename?: 'Query', stockOverview?: { __typename?: 'StockOverviewData', facts: Array<{ __typename?: 'StockOverviewResult', productName: string, categoryId: number, gender: ProductGender, boxesCount: number, itemsCount: number, sizeId: number, tagIds?: Array | null, boxState: BoxState, locationId: number }>, dimensions: { __typename?: 'StockOverviewDataDimensions', category: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null }>, size: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null }>, tag: Array<( + { __typename?: 'TagDimensionInfo' } + & { ' $fragmentRefs'?: { 'TagFragmentFragment': TagFragmentFragment } } + )>, location: Array<{ __typename?: 'DimensionInfo', id?: number | null, name?: string | null }> } } | null }; + +export type TagFragmentFragment = { __typename?: 'TagDimensionInfo', id?: number | null, name?: string | null, color?: string | null } & { ' $fragmentName'?: 'TagFragmentFragment' }; +export type ProductFragmentFragment = { __typename?: 'ProductDimensionInfo', id?: number | null, name?: string | null, gender?: ProductGender | null } & { ' $fragmentName'?: 'ProductFragmentFragment' }; +export const TagFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagDimensionInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]} as unknown as DocumentNode; +export const ProductFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProductFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProductDimensionInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}}]}}]} as unknown as DocumentNode; export const CreatedBoxesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"createdBoxes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdBoxes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"boxesCount"}},{"kind":"Field","name":{"kind":"Name","value":"productId"}},{"kind":"Field","name":{"kind":"Name","value":"categoryId"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"tagIds"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"itemsCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"product"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}}]}},{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}}]}}]}}]} as unknown as DocumentNode; -export const MovedBoxesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"movedBoxes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"movedBoxes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"movedOn"}},{"kind":"Field","name":{"kind":"Name","value":"targetId"}},{"kind":"Field","name":{"kind":"Name","value":"categoryId"}},{"kind":"Field","name":{"kind":"Name","value":"boxesCount"}},{"kind":"Field","name":{"kind":"Name","value":"itemsCount"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"productName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]}}]}}]}}]} as unknown as DocumentNode; -export const StockOverviewDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"stockOverview"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stockOverview"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"categoryId"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"boxesCount"}},{"kind":"Field","name":{"kind":"Name","value":"itemsCount"}},{"kind":"Field","name":{"kind":"Name","value":"sizeId"}},{"kind":"Field","name":{"kind":"Name","value":"tagIds"}},{"kind":"Field","name":{"kind":"Name","value":"boxState"}},{"kind":"Field","name":{"kind":"Name","value":"locationId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"size"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"location"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]} as unknown as DocumentNode; -export const BeneficiaryDemographicsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"BeneficiaryDemographics"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"beneficiaryDemographics"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const BeneficiaryDemographicsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"BeneficiaryDemographics"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"beneficiaryDemographics"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"count"}},{"kind":"Field","name":{"kind":"Name","value":"createdOn"}},{"kind":"Field","name":{"kind":"Name","value":"age"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"tagIds"}}]}}]}}]}}]} as unknown as DocumentNode; +export const MovedBoxesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"movedBoxes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"movedBoxes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"movedOn"}},{"kind":"Field","name":{"kind":"Name","value":"targetId"}},{"kind":"Field","name":{"kind":"Name","value":"categoryId"}},{"kind":"Field","name":{"kind":"Name","value":"boxesCount"}},{"kind":"Field","name":{"kind":"Name","value":"itemsCount"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"tagIds"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"target"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const StockOverviewDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"stockOverview"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stockOverview"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"baseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"baseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"facts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"categoryId"}},{"kind":"Field","name":{"kind":"Name","value":"gender"}},{"kind":"Field","name":{"kind":"Name","value":"boxesCount"}},{"kind":"Field","name":{"kind":"Name","value":"itemsCount"}},{"kind":"Field","name":{"kind":"Name","value":"sizeId"}},{"kind":"Field","name":{"kind":"Name","value":"tagIds"}},{"kind":"Field","name":{"kind":"Name","value":"boxState"}},{"kind":"Field","name":{"kind":"Name","value":"locationId"}}]}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"category"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"size"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tag"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TagFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"location"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TagFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TagDimensionInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]} as unknown as DocumentNode; From 8f9b4945adb755ed6653c2261f33a6331257b641 Mon Sep 17 00:00:00 2001 From: MaikNeubert Date: Sat, 24 Feb 2024 11:41:00 +0100 Subject: [PATCH 05/10] statviz reverse created boxes grouping --- .../filter/CreatedBoxesGrouping.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/shared-components/statviz/components/filter/CreatedBoxesGrouping.tsx b/shared-components/statviz/components/filter/CreatedBoxesGrouping.tsx index 4515b957d..8fd252f8e 100644 --- a/shared-components/statviz/components/filter/CreatedBoxesGrouping.tsx +++ b/shared-components/statviz/components/filter/CreatedBoxesGrouping.tsx @@ -9,14 +9,9 @@ export interface ICreatedBoxesTimeGroupOption { export const createdBoxesGroupingOptions: (IFilterValue & ICreatedBoxesTimeGroupOption)[] = [ { - value: "day", - urlId: "d", - label: "day", - }, - { - value: "week", - urlId: "w", - label: "week", + value: "year", + urlId: "y", + label: "year", }, { value: "month", @@ -24,9 +19,14 @@ export const createdBoxesGroupingOptions: (IFilterValue & ICreatedBoxesTimeGroup label: "month", }, { - value: "year", - urlId: "y", - label: "year", + value: "week", + urlId: "w", + label: "week", + }, + { + value: "day", + urlId: "d", + label: "day", }, ]; From 54640c51d4b055f5e3e124d5b2e444153aae4c83 Mon Sep 17 00:00:00 2001 From: MaikNeubert Date: Sat, 24 Feb 2024 12:01:32 +0100 Subject: [PATCH 06/10] move global filter state from components to state/filter.tsx --- .../components/filter/GenderProductFilter.tsx | 17 +++------ .../filter/ShipmentsLocationFilter.tsx | 36 +++++++++++++++++++ .../statviz/components/filter/TagFilter.tsx | 17 +++------ .../CreatedBoxesFilterContainer.tsx | 20 +++++------ .../DemographicFilterContainer.tsx | 11 +++--- .../movedBoxes/MovedBoxesFilterContainer.tsx | 14 +++----- .../visualizations/stock/StockDataFilter.tsx | 5 +-- shared-components/statviz/state/filter.tsx | 21 +++++++++++ 8 files changed, 91 insertions(+), 50 deletions(-) create mode 100644 shared-components/statviz/components/filter/ShipmentsLocationFilter.tsx diff --git a/shared-components/statviz/components/filter/GenderProductFilter.tsx b/shared-components/statviz/components/filter/GenderProductFilter.tsx index a0c201dca..678244be9 100644 --- a/shared-components/statviz/components/filter/GenderProductFilter.tsx +++ b/shared-components/statviz/components/filter/GenderProductFilter.tsx @@ -1,15 +1,10 @@ -import { makeVar, useReactiveVar } from "@apollo/client"; +import { useReactiveVar } from "@apollo/client"; import { Wrap, WrapItem } from "@chakra-ui/react"; import MultiSelectFilter from "./MultiSelectFilter"; import { IFilterValue } from "./ValueFilter"; import { ProductDimensionInfo, ProductGender } from "../../../types/generated/graphql"; import useMultiSelectFilter from "../../hooks/useMultiSelectFilter"; - -interface IProductFilterValue extends IFilterValue { - id: number; - name: string; - gender: ProductGender; -} +import { IProductFilterValue, productFilterValuesVar } from "../../state/filter"; export const genders: IFilterValue[] = [ { @@ -67,8 +62,6 @@ export const genders: IFilterValue[] = [ export const genderFilterId = "gf"; export const productFilterId = "pf"; -export const products = makeVar([]); - export const productToFilterValue = (product: ProductDimensionInfo): IProductFilterValue => ({ id: product.id!, value: product.id!.toString(), @@ -79,9 +72,9 @@ export const productToFilterValue = (product: ProductDimensionInfo): IProductFil }); export default function GenderProductFilter() { - const productFilterOptions = useReactiveVar(products); + const productFilterValues = useReactiveVar(productFilterValuesVar); const { onFilterChange: onProductFilterChange, filterValue: productFilterValue } = - useMultiSelectFilter(productFilterOptions, productFilterId); + useMultiSelectFilter(productFilterValues, productFilterId); const { onFilterChange: onGenderFilterChange, filterValue: genderFilterValue } = useMultiSelectFilter(genders, genderFilterId); @@ -105,7 +98,7 @@ export default function GenderProductFilter() { placeholder="products" filterId={productFilterId} fieldLabel="products" - values={productFilterOptions} + values={productFilterValues} /> diff --git a/shared-components/statviz/components/filter/ShipmentsLocationFilter.tsx b/shared-components/statviz/components/filter/ShipmentsLocationFilter.tsx new file mode 100644 index 000000000..b34a8251a --- /dev/null +++ b/shared-components/statviz/components/filter/ShipmentsLocationFilter.tsx @@ -0,0 +1,36 @@ +import { Box } from "@chakra-ui/react"; +import { useReactiveVar } from "@apollo/client"; +import MultiSelectFilter from "./MultiSelectFilter"; +import { DimensionInfo } from "../../../types/generated/graphql"; +import useMultiSelectFilter from "../../hooks/useMultiSelectFilter"; +import { ILocationFilterValue, locationFilterValuesVar } from "../../state/filter"; + +export const locationFilterId = "location"; + +export const locationToFilterValue = (tag: DimensionInfo): ILocationFilterValue => ({ + value: tag.id!.toString(), + label: tag.name!, + id: tag.id!, + urlId: tag.id!.toString(), +}); + +export default function ShipmentsLocationFilter() { + const locationFilterValues = useReactiveVar(locationFilterValuesVar); + const { onFilterChange, filterValue } = useMultiSelectFilter( + locationFilterValues, + locationFilterId, + ); + + return ( + + + + ); +} diff --git a/shared-components/statviz/components/filter/TagFilter.tsx b/shared-components/statviz/components/filter/TagFilter.tsx index ff1422033..447d66dd7 100644 --- a/shared-components/statviz/components/filter/TagFilter.tsx +++ b/shared-components/statviz/components/filter/TagFilter.tsx @@ -1,19 +1,12 @@ import { Box } from "@chakra-ui/react"; -import { makeVar, useReactiveVar } from "@apollo/client"; +import { useReactiveVar } from "@apollo/client"; import MultiSelectFilter from "./MultiSelectFilter"; -import { IFilterValue } from "./ValueFilter"; import { TagDimensionInfo } from "../../../types/generated/graphql"; import useMultiSelectFilter from "../../hooks/useMultiSelectFilter"; - -interface ITagFilterValue extends IFilterValue { - color: string; - id: number; -} +import { ITagFilterValue, tagFilterValuesVar } from "../../state/filter"; export const tagFilterId = "tags"; -export const tagFilter = makeVar([]); - export const tagToFilterValue = (tag: TagDimensionInfo): ITagFilterValue => ({ value: tag.id!.toString(), label: tag.name!, @@ -23,9 +16,9 @@ export const tagToFilterValue = (tag: TagDimensionInfo): ITagFilterValue => ({ }); export default function TagFilter() { - const tagFilterOptions = useReactiveVar(tagFilter); + const tagFilterValues = useReactiveVar(tagFilterValuesVar); const { onFilterChange, filterValue } = useMultiSelectFilter( - tagFilterOptions, + tagFilterValues, tagFilterId, ); @@ -37,7 +30,7 @@ export default function TagFilter() { placeholder="tags" filterId={tagFilterId} fieldLabel="tags" - values={tagFilterOptions} + values={tagFilterValues} /> ); diff --git a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx index 368e5a366..527752290 100644 --- a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx +++ b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesFilterContainer.tsx @@ -17,10 +17,10 @@ import { genders, productFilterId, productToFilterValue, - products, } from "../../filter/GenderProductFilter"; import useMultiSelectFilter from "../../../hooks/useMultiSelectFilter"; -import { tagFilter, tagFilterId, tagToFilterValue } from "../../filter/TagFilter"; +import { tagFilterId, tagToFilterValue } from "../../filter/TagFilter"; +import { productFilterValuesVar, tagFilterValuesVar } from "../../../state/filter"; interface ICreatedBoxesFilterContainerProps { createdBoxes: CreatedBoxesData; @@ -36,16 +36,16 @@ export default function CreatedBoxesFilterContainer({ defaultBoxesOrItems, boxesOrItemsUrlId, ); - const productFilterOptions = useReactiveVar(products); + const productFilterValues = useReactiveVar(productFilterValuesVar); const { filterValue: filterProductGenders } = useMultiSelectFilter(genders, genderFilterId); const { filterValue: filterProducts } = useMultiSelectFilter( - productFilterOptions, + productFilterValues, productFilterId, ); - const tagFilterOptions = useReactiveVar(tagFilter); - const { filterValue: filteredTags } = useMultiSelectFilter(tagFilterOptions, tagFilterId); + const tagFilterValues = useReactiveVar(tagFilterValuesVar); + const { filterValue: filteredTags } = useMultiSelectFilter(tagFilterValues, tagFilterId); // use products from the createdBoxes query to feed the global products and Tags for Boxes filter // Beneficiary and All Tags are merged inside the DemographicFilterContainer @@ -53,21 +53,21 @@ export default function CreatedBoxesFilterContainer({ useEffect(() => { const p = createdBoxes.dimensions!.product!.map((e) => productToFilterValue(e!)); if (filterProductGenders.length > 0) { - products([ + productFilterValuesVar([ ...filterProducts, ...p.filter( (product) => filterProductGenders.findIndex((fPG) => fPG.value === product.gender) !== -1, ), ]); } else { - products(p); + productFilterValuesVar(p); } const boxTags = createdBoxes.dimensions!.tag!.map((e) => tagToFilterValue(e!)); if (boxTags.length > 0) { - const distinctTagFilterValues = tidy([...tagFilterOptions, ...boxTags], distinct(["id"])); + const distinctTagFilterValues = tidy([...tagFilterValues, ...boxTags], distinct(["id"])); - tagFilter(distinctTagFilterValues); + tagFilterValuesVar(distinctTagFilterValues); } // we only need to update products if the product gender selection is updated // including filterProducts would cause unnecessary rerenders diff --git a/shared-components/statviz/components/visualizations/demographic/DemographicFilterContainer.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicFilterContainer.tsx index 1fe2e16c0..d694af25c 100644 --- a/shared-components/statviz/components/visualizations/demographic/DemographicFilterContainer.tsx +++ b/shared-components/statviz/components/visualizations/demographic/DemographicFilterContainer.tsx @@ -6,10 +6,11 @@ import { BeneficiaryDemographicsResult, } from "../../../../types/generated/graphql"; import DemographicCharts from "./DemographicCharts"; -import { tagFilter, tagFilterId, tagToFilterValue } from "../../filter/TagFilter"; +import { tagFilterId, tagToFilterValue } from "../../filter/TagFilter"; import useMultiSelectFilter from "../../../hooks/useMultiSelectFilter"; import useTimerange from "../../../hooks/useTimerange"; import { filterListByInterval } from "../../../../utils/helpers"; +import { tagFilterValuesVar } from "../../../state/filter"; interface IDemographicFilterContainerProps { demographics: BeneficiaryDemographicsData; @@ -20,8 +21,8 @@ export default function DemographicFilterContainer({ }: IDemographicFilterContainerProps) { const { interval } = useTimerange(); - const tagFilterOptions = useReactiveVar(tagFilter); - const { filterValue: filteredTags } = useMultiSelectFilter(tagFilterOptions, tagFilterId); + const tagFilterValues = useReactiveVar(tagFilterValuesVar); + const { filterValue: filteredTags } = useMultiSelectFilter(tagFilterValues, tagFilterId); // merge Beneficiary tags to Box and All tags useEffect(() => { @@ -31,11 +32,11 @@ export default function DemographicFilterContainer({ if (beneficiaryTagFilterValues.length > 0) { const distinctTagFilterValues = tidy( - [...tagFilterOptions, ...beneficiaryTagFilterValues], + [...tagFilterValues, ...beneficiaryTagFilterValues], distinct(["id"]), ); - tagFilter(distinctTagFilterValues); + tagFilterValuesVar(distinctTagFilterValues); } // including tagFilterOptions in the dependencies can lead to infinite update loops // between CreatedBoxes updating the TagFilter and DemographicFilter updating the TagFilter diff --git a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx index ac545635b..ac6062126 100644 --- a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx +++ b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx @@ -12,13 +12,9 @@ import { defaultBoxesOrItems, } from "../../filter/BoxesOrItemsSelect"; import useMultiSelectFilter from "../../../hooks/useMultiSelectFilter"; -import { - genderFilterId, - genders, - productFilterId, - products, -} from "../../filter/GenderProductFilter"; -import { tagFilter, tagFilterId } from "../../filter/TagFilter"; +import { genderFilterId, genders, productFilterId } from "../../filter/GenderProductFilter"; +import { tagFilterId } from "../../filter/TagFilter"; +import { productFilterValuesVar, tagFilterValuesVar } from "../../../state/filter"; export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxesData }) { const { interval } = useTimerange(); @@ -29,8 +25,8 @@ export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxe boxesOrItemsUrlId, ); - const productsFilterValues = useReactiveVar(products); - const tagFilterValues = useReactiveVar(tagFilter); + const productsFilterValues = useReactiveVar(productFilterValuesVar); + const tagFilterValues = useReactiveVar(tagFilterValuesVar); const { filterValue: productsFilter } = useMultiSelectFilter( productsFilterValues, diff --git a/shared-components/statviz/components/visualizations/stock/StockDataFilter.tsx b/shared-components/statviz/components/visualizations/stock/StockDataFilter.tsx index d6a733d13..6329c8978 100644 --- a/shared-components/statviz/components/visualizations/stock/StockDataFilter.tsx +++ b/shared-components/statviz/components/visualizations/stock/StockDataFilter.tsx @@ -10,7 +10,8 @@ import { } from "../../filter/BoxesOrItemsSelect"; import useValueFilter from "../../../hooks/useValueFilter"; import useMultiSelectFilter from "../../../hooks/useMultiSelectFilter"; -import { tagFilter, tagFilterId } from "../../filter/TagFilter"; +import { tagFilterId } from "../../filter/TagFilter"; +import { tagFilterValuesVar } from "../../../state/filter"; interface IStockDataFilterProps { stockOverview: StockOverviewData; @@ -19,7 +20,7 @@ interface IStockDataFilterProps { export default function StockDataFilter({ stockOverview }: IStockDataFilterProps) { // currently not affected by the selected timerange - const tagFilerValues = useReactiveVar(tagFilter); + const tagFilerValues = useReactiveVar(tagFilterValuesVar); const { filterValue } = useValueFilter( boxesOrItemsFilterValues, diff --git a/shared-components/statviz/state/filter.tsx b/shared-components/statviz/state/filter.tsx index e69de29bb..22cb4137b 100644 --- a/shared-components/statviz/state/filter.tsx +++ b/shared-components/statviz/state/filter.tsx @@ -0,0 +1,21 @@ +import { makeVar } from "@apollo/client"; +import { ProductGender } from "../../types/generated/graphql"; +import { IFilterValue } from "../components/filter/ValueFilter"; + +export interface IProductFilterValue extends IFilterValue { + id: number; + name: string; + gender: ProductGender; +} +export const productFilterValuesVar = makeVar([]); + +export interface ITagFilterValue extends IFilterValue { + color: string; + id: number; +} +export const tagFilterValuesVar = makeVar([]); + +export interface ILocationFilterValue extends IFilterValue { + id: number; +} +export const locationFilterValuesVar = makeVar([]); From 2d71b9f8bac46b65159b1b20ccd80f017417e7da Mon Sep 17 00:00:00 2001 From: MaikNeubert Date: Tue, 27 Feb 2024 15:20:32 +0100 Subject: [PATCH 07/10] shipment negativ flow --- .../components/filter/LocationFilter.tsx | 32 +++++++++++ .../filter/ShipmentsLocationFilter.tsx | 36 ------------ .../statviz/components/nivo/SankeyChart.tsx | 11 ++-- .../movedBoxes/BoxFlowSankey.tsx | 55 +++++++++++++++++-- .../movedBoxes/MovedBoxesFilterContainer.tsx | 41 +++++++++++--- shared-components/statviz/state/filter.tsx | 9 +-- .../statviz/utils/chartExport.tsx | 4 +- 7 files changed, 130 insertions(+), 58 deletions(-) create mode 100644 shared-components/statviz/components/filter/LocationFilter.tsx delete mode 100644 shared-components/statviz/components/filter/ShipmentsLocationFilter.tsx diff --git a/shared-components/statviz/components/filter/LocationFilter.tsx b/shared-components/statviz/components/filter/LocationFilter.tsx new file mode 100644 index 000000000..575fd5ec9 --- /dev/null +++ b/shared-components/statviz/components/filter/LocationFilter.tsx @@ -0,0 +1,32 @@ +import { useReactiveVar } from "@apollo/client"; +import useMultiSelectFilter from "../../hooks/useMultiSelectFilter"; +import { ITargetFilterValue, targetFilterValuesVar } from "../../state/filter"; +import MultiSelectFilter from "./MultiSelectFilter"; +import { TargetDimensionInfo } from "../../../types/generated/graphql"; + +export const targetFilterId = "loc"; + +export const targetToFilterValue = (target: TargetDimensionInfo): ITargetFilterValue => ({ + id: target.id!, + value: target.name!, + label: target.name!, + urlId: target.id!, + type: target.type!, +}); + +export default function Targetfilter() { + const targetFilterValues = useReactiveVar(targetFilterValuesVar); + + const { onFilterChange, filterValue } = useMultiSelectFilter(targetFilterValues, targetFilterId); + + return ( + + ); +} diff --git a/shared-components/statviz/components/filter/ShipmentsLocationFilter.tsx b/shared-components/statviz/components/filter/ShipmentsLocationFilter.tsx deleted file mode 100644 index b34a8251a..000000000 --- a/shared-components/statviz/components/filter/ShipmentsLocationFilter.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Box } from "@chakra-ui/react"; -import { useReactiveVar } from "@apollo/client"; -import MultiSelectFilter from "./MultiSelectFilter"; -import { DimensionInfo } from "../../../types/generated/graphql"; -import useMultiSelectFilter from "../../hooks/useMultiSelectFilter"; -import { ILocationFilterValue, locationFilterValuesVar } from "../../state/filter"; - -export const locationFilterId = "location"; - -export const locationToFilterValue = (tag: DimensionInfo): ILocationFilterValue => ({ - value: tag.id!.toString(), - label: tag.name!, - id: tag.id!, - urlId: tag.id!.toString(), -}); - -export default function ShipmentsLocationFilter() { - const locationFilterValues = useReactiveVar(locationFilterValuesVar); - const { onFilterChange, filterValue } = useMultiSelectFilter( - locationFilterValues, - locationFilterId, - ); - - return ( - - - - ); -} diff --git a/shared-components/statviz/components/nivo/SankeyChart.tsx b/shared-components/statviz/components/nivo/SankeyChart.tsx index a79316f96..66c063994 100644 --- a/shared-components/statviz/components/nivo/SankeyChart.tsx +++ b/shared-components/statviz/components/nivo/SankeyChart.tsx @@ -15,7 +15,7 @@ export interface ISankeyNode { } export interface ISankeyData { - nodes: { id: string; name: string }[]; + nodes: { id: string; name: string; nodeColor?: string }[]; links: ISankeyLink[]; } @@ -84,21 +84,20 @@ export default function SankeyChart(chart: ISankeyChart) { layers.push(() => {chart.timestamp}); } + const colors = chart.data.nodes.map((e) => e.nodeColor ?? "green"); + return (
item.count > 0), + map((item) => { + if (item.count < 0) { + return { + ...item, + count: Math.abs(item.count), + isNegative: true, + }; + } + return { + ...item, + isNegative: false, + }; + }), innerJoin(data.dimensions?.target as TargetDimensionInfo[], { by: { id: "targetId" }, }), @@ -50,6 +67,16 @@ export default function BoxFlowSankey({ width, height, data, boxesOrItems }: IBo const movedBoxesByTargetType = tidy( movedBoxes, groupBy("type", [summarize({ count: sum("count") })]), + map((movedBox) => { + if (movedBox.count < 0) { + return { + ...movedBox, + count: Math.abs(movedBox.count), + isNegative: true, + }; + } + return { ...movedBox, isNegative: false }; + }), ); const links = [ @@ -60,6 +87,7 @@ export default function BoxFlowSankey({ width, height, data, boxesOrItems }: IBo source: outgoingNode.id, target: selfReportedNode.id, value: target.count, + isNegative: target.isNegative, }; } if (target.type === "Shipment") { @@ -67,6 +95,7 @@ export default function BoxFlowSankey({ width, height, data, boxesOrItems }: IBo source: outgoingNode.id, target: shipmentNode.id, value: target.count, + isNegative: target.isNegative, }; } return undefined; @@ -78,6 +107,7 @@ export default function BoxFlowSankey({ width, height, data, boxesOrItems }: IBo source: selfReportedNode.id, target: movedBox.targetId, value: movedBox.count, + isNegative: movedBox.isNegative, }; } if (movedBox.type === "Shipment") { @@ -85,20 +115,26 @@ export default function BoxFlowSankey({ width, height, data, boxesOrItems }: IBo source: shipmentNode.id, target: movedBox.targetId, value: movedBox.count, + isNegative: movedBox.isNegative, }; } return { source: outgoingNode.id, target: movedBox.targetId, value: movedBox.count, + isNegative: movedBox.isNegative, }; }), ]; + const nodes = [ outgoingNode, ...movedBoxes.map((movedBox) => ({ id: movedBox.targetId, - name: movedBox.name, + name: movedBox.isNegative ? `${movedBox.name} removed` : movedBox.name, + nodeColor: movedBox.isNegative + ? "red" + : sample(["#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22"]), })), ]; @@ -138,7 +174,18 @@ export default function BoxFlowSankey({ width, height, data, boxesOrItems }: IBo visId="bf" /> + + + + + + + + + + Negative Box Flow + ); diff --git a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx index ac6062126..268b61f25 100644 --- a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx +++ b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesFilterContainer.tsx @@ -1,4 +1,4 @@ -import { useMemo } from "react"; +import { useEffect, useMemo } from "react"; import { useReactiveVar } from "@apollo/client"; import { TidyFn, filter, tidy } from "@tidyjs/tidy"; import useTimerange from "../../../hooks/useTimerange"; @@ -14,9 +14,18 @@ import { import useMultiSelectFilter from "../../../hooks/useMultiSelectFilter"; import { genderFilterId, genders, productFilterId } from "../../filter/GenderProductFilter"; import { tagFilterId } from "../../filter/TagFilter"; -import { productFilterValuesVar, tagFilterValuesVar } from "../../../state/filter"; +import { + targetFilterValuesVar, + productFilterValuesVar, + tagFilterValuesVar, +} from "../../../state/filter"; +import { targetFilterId, targetToFilterValue } from "../../filter/LocationFilter"; + +interface IMovedBoxesFilterContainerProps { + movedBoxes: MovedBoxesData; +} -export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxesData }) { +export default function MovedBoxesFilterContainer({ movedBoxes }: IMovedBoxesFilterContainerProps) { const { interval } = useTimerange(); const { filterValue } = useValueFilter( @@ -27,6 +36,7 @@ export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxe const productsFilterValues = useReactiveVar(productFilterValuesVar); const tagFilterValues = useReactiveVar(tagFilterValuesVar); + const targetFilterValues = useReactiveVar(targetFilterValuesVar); const { filterValue: productsFilter } = useMultiSelectFilter( productsFilterValues, @@ -35,11 +45,18 @@ export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxe const { filterValue: genderFilter } = useMultiSelectFilter(genders, genderFilterId); const { filterValue: filteredTags } = useMultiSelectFilter(tagFilterValues, tagFilterId); + const { filterValue: excludedTargets } = useMultiSelectFilter(targetFilterValues, targetFilterId); + + // fill target filter with data + useEffect(() => { + const targets = movedBoxes.dimensions!.target!.map((t) => targetToFilterValue(t!)); + targetFilterValuesVar(targets); + }, [movedBoxes.dimensions]); const movedBoxesFacts = useMemo(() => { try { return filterListByInterval( - props.movedBoxes.facts as MovedBoxesResult[], + movedBoxes.facts as MovedBoxesResult[], "movedOn", interval, ) as MovedBoxesResult[]; @@ -47,7 +64,7 @@ export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxe // TODO show toast with error message? } return []; - }, [interval, props.movedBoxes.facts]); + }, [interval, movedBoxes.facts]); const filteredFacts = useMemo(() => { const filters: TidyFn[] = []; @@ -69,6 +86,16 @@ export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxe ), ); } + if (excludedTargets.length > 0) { + filters.push( + filter( + (fact: MovedBoxesResult) => + excludedTargets.find((filteredTarget) => filteredTarget.id! === fact.targetId!) === + undefined, + ), + ); + } + if (filteredTags.length > 0) { filters.push( filter((fact: MovedBoxesResult) => filteredTags.some((fT) => fact.tagIds!.includes(fT.id))), @@ -80,11 +107,11 @@ export default function MovedBoxesFilterContainer(props: { movedBoxes: MovedBoxe return tidy(movedBoxesFacts, ...filters); } return movedBoxesFacts; - }, [filteredTags, genderFilter, movedBoxesFacts, productsFilter]); + }, [excludedTargets, filteredTags, genderFilter, movedBoxesFacts, productsFilter]); const filteredMovedBoxesCube = { facts: filteredFacts as MovedBoxesResult[], - dimensions: props.movedBoxes.dimensions, + dimensions: movedBoxes.dimensions, }; return ; } diff --git a/shared-components/statviz/state/filter.tsx b/shared-components/statviz/state/filter.tsx index 22cb4137b..685b5c0f3 100644 --- a/shared-components/statviz/state/filter.tsx +++ b/shared-components/statviz/state/filter.tsx @@ -1,5 +1,5 @@ import { makeVar } from "@apollo/client"; -import { ProductGender } from "../../types/generated/graphql"; +import { ProductGender, TargetType } from "../../types/generated/graphql"; import { IFilterValue } from "../components/filter/ValueFilter"; export interface IProductFilterValue extends IFilterValue { @@ -15,7 +15,8 @@ export interface ITagFilterValue extends IFilterValue { } export const tagFilterValuesVar = makeVar([]); -export interface ILocationFilterValue extends IFilterValue { - id: number; +export interface ITargetFilterValue extends IFilterValue { + id: string; + type: TargetType; } -export const locationFilterValuesVar = makeVar([]); +export const targetFilterValuesVar = makeVar([]); diff --git a/shared-components/statviz/utils/chartExport.tsx b/shared-components/statviz/utils/chartExport.tsx index 9ca747cc6..64346da45 100644 --- a/shared-components/statviz/utils/chartExport.tsx +++ b/shared-components/statviz/utils/chartExport.tsx @@ -71,7 +71,9 @@ const exportChartWithSettings = ( } }; - setTimeout(exportImage, 1); + // increase to 250ms to see if it fixes download issues in safari. + // a better solution must be researched + setTimeout(exportImage, 250); }; const root = createRoot(exportContainer); From 7fef4e5e2580f66f0a828aaae2ebe991f2946221 Mon Sep 17 00:00:00 2001 From: MaikNeubert Date: Sun, 10 Mar 2024 21:13:49 +0100 Subject: [PATCH 08/10] moved boxes basic tests --- .../movedBoxes/MovedBoxes.test.tsx | 105 ++++-- .../movedBoxes/MovedBoxesDataContainer.tsx | 3 +- .../statviz/hooks/useMultiSelectFilter.ts | 2 +- shared-components/statviz/testData.tsx | 333 ++++++++++++++++++ shared-components/tests/setupTests.ts | 16 + shared-components/vitest.config.ts | 18 + 6 files changed, 448 insertions(+), 29 deletions(-) create mode 100644 shared-components/statviz/testData.tsx diff --git a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxes.test.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxes.test.tsx index 352a151dd..a5cb338ff 100644 --- a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxes.test.tsx +++ b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxes.test.tsx @@ -1,38 +1,91 @@ -import { it, expect } from "vitest"; +import { it, expect, vi, describe } from "vitest"; import { GraphQLError } from "graphql"; +import { MockedResponse } from "@apollo/client/testing"; import MovedBoxesDataContainer, { MOVED_BOXES_QUERY } from "./MovedBoxesDataContainer"; -import { render, screen } from "../../../../tests/testUtils"; - -const mockFailedMovedBoxesQuery = ({ baseId = "1", networkError = false }) => ({ - request: { - query: MOVED_BOXES_QUERY, - variables: { baseId }, - }, - result: networkError - ? undefined - : { - data: null, - errors: [new GraphQLError("Error!")], +import { render, screen, waitFor } from "../../../../tests/testUtils"; +import { movedBoxesResultMockData } from "../../../testData"; + +const mockResponsiveSankey = vi.fn(); + +describe("Moved Boxes Visualizations", () => { + const mockMovedBoxesQuery = ({ + baseId = 1, + networkError = false, + graphqlError = false, + delay = 0, + mockData = {}, + }): MockedResponse => { + const getResult = () => { + if (networkError) return undefined; + if (graphqlError) + return { + data: null, + errors: [new GraphQLError("Error!")], + }; + return { + data: mockData, + errors: undefined, + }; + }; + + return { + request: { + query: MOVED_BOXES_QUERY, + variables: { baseId }, }, - error: networkError ? new Error() : undefined, -}); + result: getResult(), + error: networkError ? new Error() : undefined, + delay, + }; + }; + + vi.mock("@nivo/sankey", () => ({ + ResponsiveSankey: (props) => { + mockResponsiveSankey(props); + + return
ResponsiveSankey
; + }, + })); + + it("x.x.x.x - user scans wants to see movedBoxes viz, but a network error is returned", async () => { + render(, { + routePath: "/bases/:baseId/", + initialUrl: "/bases/1/", + mocks: [mockMovedBoxesQuery({ networkError: true })], + }); -const movedBoxesDataTests = [ - { - name: "x.x.x.x - user scans wants to see movedBoxes viz, but a network error is returned", - mocks: [mockFailedMovedBoxesQuery({ networkError: true })], - alert: /An unexpected error happened/i, - }, -]; + expect(await screen.findByText(/An unexpected error happened/i)).toBeInTheDocument(); + }); -movedBoxesDataTests.forEach(({ name, mocks, alert }) => { - it(name, async () => { + it("x.x.x.x - user waits for data and sees the loading spinner", async () => { render(, { routePath: "/bases/:baseId/", initialUrl: "/bases/1/", - mocks, + mocks: [mockMovedBoxesQuery({ delay: 250 })], + }); + + expect(await screen.findByText(/loading.../i)).toBeInTheDocument(); + }); + + it("x.x.x.x - user selects a timerange where no data is present and sees the No data view", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz?stg=cn&boi=bc&cbg=m&to=2024-02-17&from=2023-11-17", + mocks: [mockMovedBoxesQuery({ mockData: movedBoxesResultMockData })], + }); + + expect( + await screen.findByText(/No data for the selected time range or selected filters/i), + ).toBeInTheDocument(); + }); + + it("x.x.x.x - user sees movedBoxes viz", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz?stg=cn&boi=bc&cbg=m&to=2023-09-02&from=2023-01-30", + mocks: [mockMovedBoxesQuery({ mockData: movedBoxesResultMockData })], }); - expect(await screen.findByText(alert)).toBeInTheDocument(); + await waitFor(() => expect(mockResponsiveSankey).toHaveBeenCalled()); }); }); diff --git a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx index d2d3b0bea..927202f13 100644 --- a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx +++ b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxesDataContainer.tsx @@ -35,7 +35,7 @@ export const MOVED_BOXES_QUERY = gql(` `); // The data wrapper collects data and passes it to the filter-wrapper -// which applys filters to the data +// which applies filters to the data // the filter wrapper passes it to the Chart which maps the Datacube to a VisX or Nivo Chart export default function MovedBoxesDataContainer() { const { baseId } = useParams(); @@ -45,7 +45,6 @@ export default function MovedBoxesDataContainer() { variables: { baseId: parseInt(baseId!, 10) }, }, ); - if (error) { return An unexpected error happened {error.message}; } diff --git a/shared-components/statviz/hooks/useMultiSelectFilter.ts b/shared-components/statviz/hooks/useMultiSelectFilter.ts index d71b1d445..d6093ea6f 100644 --- a/shared-components/statviz/hooks/useMultiSelectFilter.ts +++ b/shared-components/statviz/hooks/useMultiSelectFilter.ts @@ -28,8 +28,8 @@ export default function useMultiSelectFilter( } if (param === "") { searchParams.delete(filterId); + setSearchParams(searchParams); } - setSearchParams(searchParams); }, [searchParams, filterId, values, defaultFilterValues, setSearchParams]); const onFilterChange = (event) => { diff --git a/shared-components/statviz/testData.tsx b/shared-components/statviz/testData.tsx new file mode 100644 index 000000000..d9900b26a --- /dev/null +++ b/shared-components/statviz/testData.tsx @@ -0,0 +1,333 @@ +const movedBoxesFacts = [ + { + __typename: "MovedBoxesResult", + movedOn: "2023-04-02", + targetId: "Gelöschte Boxen", + categoryId: 3, + boxesCount: 1, + itemsCount: 78, + gender: "Women", + productName: "longsleeves", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-04-02", + targetId: "Gelöschte Boxen", + categoryId: 5, + boxesCount: 1, + itemsCount: 15, + gender: "Women", + productName: "summer shoes", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-06-05", + targetId: "Packstation", + categoryId: 5, + boxesCount: -1, + itemsCount: -10, + gender: "UnisexAdult", + productName: "rubber boots", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 3, + boxesCount: 1, + itemsCount: 15, + gender: "Women", + productName: "summer jackets", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 3, + boxesCount: 2, + itemsCount: 34, + gender: "Women", + productName: "summer jackets", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 3, + boxesCount: 1, + itemsCount: 80, + gender: "Women", + productName: "t-shirts", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 3, + boxesCount: 1, + itemsCount: 57, + gender: "Women", + productName: "t-shirts", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 3, + boxesCount: 3, + itemsCount: 221, + gender: "Women", + productName: "t-shirts", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 3, + boxesCount: 1, + itemsCount: 11, + gender: "Women", + productName: "winter jackets", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 5, + boxesCount: 2, + itemsCount: 19, + gender: "UnisexAdult", + productName: "rubber boots", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 5, + boxesCount: 2, + itemsCount: 35, + gender: "UnisexKid", + productName: "rubber boots", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 5, + boxesCount: 1, + itemsCount: 26, + gender: "Women", + productName: "summer shoes", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 5, + boxesCount: 1, + itemsCount: 25, + gender: "Women", + productName: "summer shoes", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 5, + boxesCount: 6, + itemsCount: 129, + gender: "UnisexKid", + productName: "summer shoes", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 5, + boxesCount: 1, + itemsCount: 29, + gender: "UnisexBaby", + productName: "summer shoes", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 9, + boxesCount: 1, + itemsCount: 17, + gender: "none", + productName: "bed sheets", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 12, + boxesCount: 2, + itemsCount: 89, + gender: "Women", + productName: "gloves", + tagIds: [], + }, + { + __typename: "MovedBoxesResult", + movedOn: "2023-07-02", + targetId: "Shipment1Calai", + categoryId: 12, + boxesCount: 1, + itemsCount: 59, + gender: "UnisexKid", + productName: "summer hats", + tagIds: [], + }, +]; + +const categories = [ + { + __typename: "DimensionInfo", + id: 1, + name: "Underwear / Nightwear", + }, + { + __typename: "DimensionInfo", + id: 2, + name: "Bottoms", + }, + { + __typename: "DimensionInfo", + id: 3, + name: "Tops", + }, + { + __typename: "DimensionInfo", + id: 4, + name: "Accessories", + }, + { + __typename: "DimensionInfo", + id: 5, + name: "Jackets / Outerwear", + }, + { + __typename: "DimensionInfo", + id: 7, + name: "Skirts / Dresses", + }, + { + __typename: "DimensionInfo", + id: 8, + name: "Baby", + }, + { + __typename: "DimensionInfo", + id: 9, + name: "Other", + }, + { + __typename: "DimensionInfo", + id: 10, + name: "Hygiene", + }, + { + __typename: "DimensionInfo", + id: 11, + name: "Food & Kitchen", + }, + { + __typename: "DimensionInfo", + id: 12, + name: "Clothing", + }, + { + __typename: "DimensionInfo", + id: 13, + name: "Equipment", + }, + { + __typename: "DimensionInfo", + id: 14, + name: "Toys & Games", + }, + { + __typename: "DimensionInfo", + id: 15, + name: "Medication", + }, + { + __typename: "DimensionInfo", + id: 18, + name: "Books & Stationery", + }, + { + __typename: "DimensionInfo", + id: 19, + name: "Water", + }, + { + __typename: "DimensionInfo", + id: 20, + name: "Shelter", + }, +]; + +const targets = [ + { + __typename: "TargetDimensionInfo", + id: "Shipment1Calai", + name: "Shipment1Calai", + type: "OutgoingLocation", + }, + { + __typename: "TargetDimensionInfo", + id: "V93 LR", + name: "V93 LR", + type: "OutgoingLocation", + }, + { + __typename: "TargetDimensionInfo", + id: "Gelöschte Boxen", + name: "Gelöschte Boxen", + type: "OutgoingLocation", + }, + { + __typename: "TargetDimensionInfo", + id: "Lost", + name: "Lost", + type: "BoxState", + }, + { + __typename: "TargetDimensionInfo", + id: "Scrap", + name: "Scrap", + type: "BoxState", + }, +]; + +export const movedBoxesResultMockData = { + movedBoxes: { + __typename: "MovedBoxesData", + facts: movedBoxesFacts, + dimensions: { + __typename: "MovedBoxDataDimensions", + target: targets, + category: categories, + }, + }, +}; diff --git a/shared-components/tests/setupTests.ts b/shared-components/tests/setupTests.ts index 1dd407a63..ca1482f46 100644 --- a/shared-components/tests/setupTests.ts +++ b/shared-components/tests/setupTests.ts @@ -3,3 +3,19 @@ // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import "@testing-library/jest-dom"; +import { vi } from "vitest"; + +Object.defineProperty(window, "matchMedia", { + // workaround for window.matchMedia not found used by chakraUI, see https://github.com/vitest-dev/vitest/issues/821 for more information + writable: true, + value: vi.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // deprecated + removeListener: vi.fn(), // deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), +}); diff --git a/shared-components/vitest.config.ts b/shared-components/vitest.config.ts index e6899d19d..55450bb38 100644 --- a/shared-components/vitest.config.ts +++ b/shared-components/vitest.config.ts @@ -9,5 +9,23 @@ export default defineProject({ outputFile: { junit: "./coverage/junit.xml", }, + alias: [ + // Workaround for issue in d3 https://github.com/plouc/nivo/issues/2310 + { find: "@nivo/annotations", replacement: "@nivo/annotations/dist/nivo-annotations.es.js" }, + { find: "@nivo/arcs", replacement: "@nivo/arcs/dist/nivo-arcs.es.js" }, + { find: "@nivo/axes", replacement: "@nivo/axes/dist/nivo-axes.es.js" }, + { find: "@nivo/bar", replacement: "@nivo/bar/dist/nivo-bar.es.js" }, + { find: "@nivo/colors", replacement: "@nivo/colors/dist/nivo-colors.es.js" }, + { find: "@nivo/core", replacement: "@nivo/core/dist/nivo-core.es.js" }, + { find: "@nivo/legends", replacement: "@nivo/legends/dist/nivo-legends.es.js" }, + { find: "@nivo/line", replacement: "@nivo/line/dist/nivo-line.es.js" }, + { find: "@nivo/pie", replacement: "@nivo/pie/dist/nivo-pie.es.js" }, + { find: "@nivo/recompose", replacement: "@nivo/recompose/dist/nivo-recompose.es.js" }, + { find: "@nivo/scales", replacement: "@nivo/scales/dist/nivo-scales.es.js" }, + { find: "@nivo/scatterplot", replacement: "@nivo/scatterplot/dist/nivo-scatterplot.es.js" }, + { find: "@nivo/tooltip", replacement: "@nivo/tooltip/dist/nivo-tooltip.es.js" }, + { find: "@nivo/voronoi", replacement: "@nivo/voronoi/dist/nivo-voronoi.es.js" }, + { find: "@nivo/sankey", replacement: "@nivo/sankey/dist/nivo-sankey.es.js" }, + ], }, }); From 84ffd83a0dbb02f1627c70c51d2eadf54082aaf1 Mon Sep 17 00:00:00 2001 From: MaikNeubert Date: Mon, 11 Mar 2024 01:02:34 +0100 Subject: [PATCH 09/10] add basic tests for visualizations (no data, network error, loading) --- .../createdBoxes/CreatedBoxes.test.tsx | 90 ++++++++ .../CreatedBoxesDataContainer.tsx | 2 +- .../demographic/Demographic.test.tsx | 57 +++++ .../demographic/DemographicDataContainer.tsx | 2 +- .../movedBoxes/MovedBoxes.test.tsx | 14 +- .../visualizations/stock/Stock.test.tsx | 57 +++++ .../stock/StockDataContainer.tsx | 4 +- .../statviz/mocks/beneficiaryDemographics.ts | 0 .../statviz/mocks/categoryDim.ts | 87 +++++++ .../statviz/mocks/createdBoxes.ts | 139 ++++++++++++ .../statviz/mocks/locationDim.ts | 17 ++ .../{testData.tsx => mocks/movedBoxes.ts} | 130 +---------- shared-components/statviz/mocks/productDim.ts | 9 + shared-components/statviz/mocks/sizeDim.ts | 212 ++++++++++++++++++ .../statviz/mocks/stockOverview.ts | 88 ++++++++ shared-components/statviz/mocks/tagDim.ts | 32 +++ shared-components/statviz/mocks/targetDim.ts | 32 +++ 17 files changed, 837 insertions(+), 135 deletions(-) create mode 100644 shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxes.test.tsx create mode 100644 shared-components/statviz/components/visualizations/demographic/Demographic.test.tsx create mode 100644 shared-components/statviz/components/visualizations/stock/Stock.test.tsx create mode 100644 shared-components/statviz/mocks/beneficiaryDemographics.ts create mode 100644 shared-components/statviz/mocks/categoryDim.ts create mode 100644 shared-components/statviz/mocks/createdBoxes.ts create mode 100644 shared-components/statviz/mocks/locationDim.ts rename shared-components/statviz/{testData.tsx => mocks/movedBoxes.ts} (68%) create mode 100644 shared-components/statviz/mocks/productDim.ts create mode 100644 shared-components/statviz/mocks/sizeDim.ts create mode 100644 shared-components/statviz/mocks/stockOverview.ts create mode 100644 shared-components/statviz/mocks/tagDim.ts create mode 100644 shared-components/statviz/mocks/targetDim.ts diff --git a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxes.test.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxes.test.tsx new file mode 100644 index 000000000..a3f0f1da2 --- /dev/null +++ b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxes.test.tsx @@ -0,0 +1,90 @@ +import { MockedResponse } from "@apollo/client/testing"; +import { GraphQLError } from "graphql"; +import { it, expect, describe } from "vitest"; +import CreatedBoxesDataContainer, { CREATED_BOXES_QUERY } from "./CreatedBoxesDataContainer"; +import { render, screen } from "../../../../tests/testUtils"; +import createdBoxes from "../../../mocks/createdBoxes"; + +describe("Created Boxes Visualizations", () => { + const mockCreatedBoxesQuery = ({ + baseId = 1, + networkError = false, + graphqlError = false, + delay = 0, + mockData = {}, + }): MockedResponse => { + const getResult = () => { + if (networkError) return undefined; + if (graphqlError) + return { + data: null, + errors: [new GraphQLError("Error!")], + }; + return { + data: mockData, + errors: undefined, + }; + }; + return { + request: { + query: CREATED_BOXES_QUERY, + variables: { baseId }, + }, + result: getResult(), + error: networkError ? new Error() : undefined, + delay, + }; + }; + + it("x.x.x.x - user wants to see createdBoxes viz, but a network error is returned", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz", + mocks: [mockCreatedBoxesQuery({ networkError: true })], + }); + + expect(await screen.findByText(/An unexpected error happened/i)).toBeInTheDocument(); + }); + + it("x.x.x.x - user waits for data and sees the loading spinner", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz", + mocks: [mockCreatedBoxesQuery({ delay: 250 })], + }); + + expect(await screen.findByText(/loading.../i)).toBeInTheDocument(); + }); + + it("x.x.x.x - user sees createdBoxes viz", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz", + mocks: [mockCreatedBoxesQuery({ mockData: createdBoxes })], + }); + + // expect(await screen.findByText(/loading.../i)).toBeInTheDocument(); + }); + + it("x.x.x.x - user calls page with some filters", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz", + mocks: [mockCreatedBoxesQuery({ mockData: createdBoxes })], + }); + + // expect(await screen.findByText(/loading.../i)).toBeInTheDocument(); + }); + + it("x.x.x.x - user selects timerange without data", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz?stg=cn&boi=bc&cbg=m&to=2021-09-02&from=2022-01-30", + mocks: [mockCreatedBoxesQuery({ mockData: createdBoxes })], + }); + + // expect( + // await screen.findByText(/No data for the selected time range or selected filters/i), + // ).toBeInTheDocument(); + }); +}); diff --git a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx index 8d4c74996..c325fe508 100644 --- a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx +++ b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxesDataContainer.tsx @@ -5,7 +5,7 @@ import ErrorCard, { predefinedErrors } from "../../ErrorCard"; import CreatedBoxesFilterContainer from "./CreatedBoxesFilterContainer"; import { gql } from "../../../../types/generated"; -const CREATED_BOXES_QUERY = gql(` +export const CREATED_BOXES_QUERY = gql(` query createdBoxes($baseId: Int!) { createdBoxes(baseId: $baseId) { facts { diff --git a/shared-components/statviz/components/visualizations/demographic/Demographic.test.tsx b/shared-components/statviz/components/visualizations/demographic/Demographic.test.tsx new file mode 100644 index 000000000..83a7b86cd --- /dev/null +++ b/shared-components/statviz/components/visualizations/demographic/Demographic.test.tsx @@ -0,0 +1,57 @@ +import { MockedResponse } from "@apollo/client/testing"; +import { GraphQLError } from "graphql"; +import { it, expect, describe } from "vitest"; +import { render, screen } from "../../../../tests/testUtils"; +import DemographicDataContainer, { DEMOGRAPHIC_QUERY } from "./DemographicDataContainer"; + +describe("Demographic Visualizations", () => { + const mockDemographicsQuery = ({ + baseId = 1, + networkError = false, + graphqlError = false, + delay = 0, + mockData = {}, + }): MockedResponse => { + const getResult = () => { + if (networkError) return undefined; + if (graphqlError) + return { + data: null, + errors: [new GraphQLError("Error!")], + }; + return { + data: mockData, + errors: undefined, + }; + }; + return { + request: { + query: DEMOGRAPHIC_QUERY, + variables: { baseId }, + }, + result: getResult(), + error: networkError ? new Error() : undefined, + delay, + }; + }; + + it("x.x.x.x - user wants to see createdBoxes viz, but a network error is returned", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz", + mocks: [mockDemographicsQuery({ networkError: true })], + }); + + expect(await screen.findByText(/An unexpected error happened/i)).toBeInTheDocument(); + }); + + it("x.x.x.x - user waits for data and sees the loading spinner", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz", + mocks: [mockDemographicsQuery({ delay: 250 })], + }); + + expect(await screen.findByText(/loading.../i)).toBeInTheDocument(); + }); +}); diff --git a/shared-components/statviz/components/visualizations/demographic/DemographicDataContainer.tsx b/shared-components/statviz/components/visualizations/demographic/DemographicDataContainer.tsx index 666e108c6..b1039b97d 100644 --- a/shared-components/statviz/components/visualizations/demographic/DemographicDataContainer.tsx +++ b/shared-components/statviz/components/visualizations/demographic/DemographicDataContainer.tsx @@ -5,7 +5,7 @@ import DemographicFilterContainer from "./DemographicFilterContainer"; import ErrorCard, { predefinedErrors } from "../../ErrorCard"; import NoDataCard from "../../NoDataCard"; -const DEMOGRAPHIC_QUERY = gql(` +export const DEMOGRAPHIC_QUERY = gql(` query BeneficiaryDemographics($baseId: Int!) { beneficiaryDemographics(baseId: $baseId) { facts { diff --git a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxes.test.tsx b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxes.test.tsx index a5cb338ff..6dca43345 100644 --- a/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxes.test.tsx +++ b/shared-components/statviz/components/visualizations/movedBoxes/MovedBoxes.test.tsx @@ -3,7 +3,7 @@ import { GraphQLError } from "graphql"; import { MockedResponse } from "@apollo/client/testing"; import MovedBoxesDataContainer, { MOVED_BOXES_QUERY } from "./MovedBoxesDataContainer"; import { render, screen, waitFor } from "../../../../tests/testUtils"; -import { movedBoxesResultMockData } from "../../../testData"; +import movedBoxes from "../../../mocks/movedBoxes"; const mockResponsiveSankey = vi.fn(); @@ -49,8 +49,8 @@ describe("Moved Boxes Visualizations", () => { it("x.x.x.x - user scans wants to see movedBoxes viz, but a network error is returned", async () => { render(, { - routePath: "/bases/:baseId/", - initialUrl: "/bases/1/", + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz", mocks: [mockMovedBoxesQuery({ networkError: true })], }); @@ -59,8 +59,8 @@ describe("Moved Boxes Visualizations", () => { it("x.x.x.x - user waits for data and sees the loading spinner", async () => { render(, { - routePath: "/bases/:baseId/", - initialUrl: "/bases/1/", + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz", mocks: [mockMovedBoxesQuery({ delay: 250 })], }); @@ -71,7 +71,7 @@ describe("Moved Boxes Visualizations", () => { render(, { routePath: "/bases/:baseId/statviz", initialUrl: "/bases/1/statviz?stg=cn&boi=bc&cbg=m&to=2024-02-17&from=2023-11-17", - mocks: [mockMovedBoxesQuery({ mockData: movedBoxesResultMockData })], + mocks: [mockMovedBoxesQuery({ mockData: movedBoxes })], }); expect( @@ -83,7 +83,7 @@ describe("Moved Boxes Visualizations", () => { render(, { routePath: "/bases/:baseId/statviz", initialUrl: "/bases/1/statviz?stg=cn&boi=bc&cbg=m&to=2023-09-02&from=2023-01-30", - mocks: [mockMovedBoxesQuery({ mockData: movedBoxesResultMockData })], + mocks: [mockMovedBoxesQuery({ mockData: movedBoxes })], }); await waitFor(() => expect(mockResponsiveSankey).toHaveBeenCalled()); diff --git a/shared-components/statviz/components/visualizations/stock/Stock.test.tsx b/shared-components/statviz/components/visualizations/stock/Stock.test.tsx new file mode 100644 index 000000000..eae0835d8 --- /dev/null +++ b/shared-components/statviz/components/visualizations/stock/Stock.test.tsx @@ -0,0 +1,57 @@ +import { MockedResponse } from "@apollo/client/testing"; +import { GraphQLError } from "graphql"; +import { it, expect, describe } from "vitest"; +import { render, screen } from "../../../../tests/testUtils"; +import { STOCK_QUERY, StockDataContainer } from "./StockDataContainer"; + +describe("Stock Overview Visualizations", () => { + const mockStockQuery = ({ + baseId = 1, + networkError = false, + graphqlError = false, + delay = 0, + mockData = {}, + }): MockedResponse => { + const getResult = () => { + if (networkError) return undefined; + if (graphqlError) + return { + data: null, + errors: [new GraphQLError("Error!")], + }; + return { + data: mockData, + errors: undefined, + }; + }; + return { + request: { + query: STOCK_QUERY, + variables: { baseId }, + }, + result: getResult(), + error: networkError ? new Error() : undefined, + delay, + }; + }; + + it("x.x.x.x - user wants to see the stock visualizations viz, but a network error is returned", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz", + mocks: [mockStockQuery({ networkError: true })], + }); + + expect(await screen.findByText(/An unexpected error happened/i)).toBeInTheDocument(); + }); + + it("x.x.x.x - user wants to see the stock visualizations viz and waits for data", async () => { + render(, { + routePath: "/bases/:baseId/statviz", + initialUrl: "/bases/1/statviz", + mocks: [mockStockQuery({ delay: 250 })], + }); + + expect(await screen.findByText(/loading.../i)).toBeInTheDocument(); + }); +}); diff --git a/shared-components/statviz/components/visualizations/stock/StockDataContainer.tsx b/shared-components/statviz/components/visualizations/stock/StockDataContainer.tsx index 02aeb9542..65f7bf788 100644 --- a/shared-components/statviz/components/visualizations/stock/StockDataContainer.tsx +++ b/shared-components/statviz/components/visualizations/stock/StockDataContainer.tsx @@ -5,7 +5,7 @@ import StockDataFilter from "./StockDataFilter"; import ErrorCard, { predefinedErrors } from "../../ErrorCard"; import { gql } from "../../../../types/generated"; -const STOCK_QUERY = gql(` +export const STOCK_QUERY = gql(` query stockOverview($baseId: Int!) { stockOverview(baseId: $baseId) { facts { @@ -40,7 +40,7 @@ const STOCK_QUERY = gql(` } `); -export default function StockDataContainer() { +export function StockDataContainer() { const { baseId } = useParams(); const { data, loading, error } = useQuery(STOCK_QUERY, { variables: { baseId: parseInt(baseId!, 10) }, diff --git a/shared-components/statviz/mocks/beneficiaryDemographics.ts b/shared-components/statviz/mocks/beneficiaryDemographics.ts new file mode 100644 index 000000000..e69de29bb diff --git a/shared-components/statviz/mocks/categoryDim.ts b/shared-components/statviz/mocks/categoryDim.ts new file mode 100644 index 000000000..eb86dbd11 --- /dev/null +++ b/shared-components/statviz/mocks/categoryDim.ts @@ -0,0 +1,87 @@ +export default [ + { + __typename: "DimensionInfo", + id: 1, + name: "Underwear / Nightwear", + }, + { + __typename: "DimensionInfo", + id: 2, + name: "Bottoms", + }, + { + __typename: "DimensionInfo", + id: 3, + name: "Tops", + }, + { + __typename: "DimensionInfo", + id: 4, + name: "Accessories", + }, + { + __typename: "DimensionInfo", + id: 5, + name: "Jackets / Outerwear", + }, + { + __typename: "DimensionInfo", + id: 7, + name: "Skirts / Dresses", + }, + { + __typename: "DimensionInfo", + id: 8, + name: "Baby", + }, + { + __typename: "DimensionInfo", + id: 9, + name: "Other", + }, + { + __typename: "DimensionInfo", + id: 10, + name: "Hygiene", + }, + { + __typename: "DimensionInfo", + id: 11, + name: "Food & Kitchen", + }, + { + __typename: "DimensionInfo", + id: 12, + name: "Clothing", + }, + { + __typename: "DimensionInfo", + id: 13, + name: "Equipment", + }, + { + __typename: "DimensionInfo", + id: 14, + name: "Toys & Games", + }, + { + __typename: "DimensionInfo", + id: 15, + name: "Medication", + }, + { + __typename: "DimensionInfo", + id: 18, + name: "Books & Stationery", + }, + { + __typename: "DimensionInfo", + id: 19, + name: "Water", + }, + { + __typename: "DimensionInfo", + id: 20, + name: "Shelter", + }, +]; diff --git a/shared-components/statviz/mocks/createdBoxes.ts b/shared-components/statviz/mocks/createdBoxes.ts new file mode 100644 index 000000000..974737803 --- /dev/null +++ b/shared-components/statviz/mocks/createdBoxes.ts @@ -0,0 +1,139 @@ +import categoryDim from "./categoryDim"; +import productDim from "./productDim"; +import tagDim from "./tagDim"; + +const facts = [ + { + __typename: "CreatedBoxesResult", + boxesCount: 5, + productId: 1772, + categoryId: 3, + createdOn: "2019-11-12T00:00:00", + tagIds: [], + gender: "Women", + itemsCount: 142, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 14, + productId: 1772, + categoryId: 3, + createdOn: "2020-01-07T00:00:00", + tagIds: [791, 882], + gender: "Women", + itemsCount: 374, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 4, + productId: 1772, + categoryId: 3, + createdOn: "2020-01-08T00:00:00", + tagIds: [791, 884], + gender: "Women", + itemsCount: 81, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 2, + productId: 1772, + categoryId: 3, + createdOn: "2020-01-12T00:00:00", + tagIds: [], + gender: "Women", + itemsCount: 38, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 2, + productId: 1772, + categoryId: 3, + createdOn: "2020-01-21T00:00:00", + tagIds: [], + gender: "Women", + itemsCount: 44, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 5, + productId: 1772, + categoryId: 3, + createdOn: "2020-03-08T00:00:00", + tagIds: [787, 879], + gender: "Women", + itemsCount: 143, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 53, + productId: 1772, + categoryId: 3, + createdOn: "2020-04-18T00:00:00", + tagIds: [], + gender: "Women", + itemsCount: 1262, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 1, + productId: 1772, + categoryId: 3, + createdOn: "2020-05-17T00:00:00", + tagIds: [], + gender: "Women", + itemsCount: 23, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 1, + productId: 1772, + categoryId: 3, + createdOn: "2020-06-07T00:00:00", + tagIds: [], + gender: "Women", + itemsCount: 23, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 3, + productId: 1772, + categoryId: 3, + createdOn: "2020-06-28T00:00:00", + tagIds: [], + gender: "Women", + itemsCount: 59, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 1, + productId: 1772, + categoryId: 3, + createdOn: "2020-07-05T00:00:00", + tagIds: [], + gender: "Women", + itemsCount: 20, + }, + { + __typename: "CreatedBoxesResult", + boxesCount: 2, + productId: 1772, + categoryId: 3, + createdOn: "2020-07-12T00:00:00", + tagIds: [], + gender: "Women", + itemsCount: 42, + }, +]; + +export default { + createdBoxes: { + __typename: "CreatedBoxesData", + facts, + dimensions: { + __typename: "CreatedBoxDataDimensions", + product: productDim, + category: categoryDim, + tag: tagDim, + }, + }, +}; diff --git a/shared-components/statviz/mocks/locationDim.ts b/shared-components/statviz/mocks/locationDim.ts new file mode 100644 index 000000000..3d05fe8e9 --- /dev/null +++ b/shared-components/statviz/mocks/locationDim.ts @@ -0,0 +1,17 @@ +export default [ + { + __typename: "DimensionInfo", + id: 12, + name: "Stockroom", + }, + { + __typename: "DimensionInfo", + id: 42, + name: "Shipment01Loc", + }, + { + __typename: "DimensionInfo", + id: 125, + name: "Shop", + }, +]; diff --git a/shared-components/statviz/testData.tsx b/shared-components/statviz/mocks/movedBoxes.ts similarity index 68% rename from shared-components/statviz/testData.tsx rename to shared-components/statviz/mocks/movedBoxes.ts index d9900b26a..efc68df19 100644 --- a/shared-components/statviz/testData.tsx +++ b/shared-components/statviz/mocks/movedBoxes.ts @@ -1,3 +1,6 @@ +import categoryDim from "./categoryDim"; +import targetDim from "./targetDim"; + const movedBoxesFacts = [ { __typename: "MovedBoxesResult", @@ -199,135 +202,14 @@ const movedBoxesFacts = [ }, ]; -const categories = [ - { - __typename: "DimensionInfo", - id: 1, - name: "Underwear / Nightwear", - }, - { - __typename: "DimensionInfo", - id: 2, - name: "Bottoms", - }, - { - __typename: "DimensionInfo", - id: 3, - name: "Tops", - }, - { - __typename: "DimensionInfo", - id: 4, - name: "Accessories", - }, - { - __typename: "DimensionInfo", - id: 5, - name: "Jackets / Outerwear", - }, - { - __typename: "DimensionInfo", - id: 7, - name: "Skirts / Dresses", - }, - { - __typename: "DimensionInfo", - id: 8, - name: "Baby", - }, - { - __typename: "DimensionInfo", - id: 9, - name: "Other", - }, - { - __typename: "DimensionInfo", - id: 10, - name: "Hygiene", - }, - { - __typename: "DimensionInfo", - id: 11, - name: "Food & Kitchen", - }, - { - __typename: "DimensionInfo", - id: 12, - name: "Clothing", - }, - { - __typename: "DimensionInfo", - id: 13, - name: "Equipment", - }, - { - __typename: "DimensionInfo", - id: 14, - name: "Toys & Games", - }, - { - __typename: "DimensionInfo", - id: 15, - name: "Medication", - }, - { - __typename: "DimensionInfo", - id: 18, - name: "Books & Stationery", - }, - { - __typename: "DimensionInfo", - id: 19, - name: "Water", - }, - { - __typename: "DimensionInfo", - id: 20, - name: "Shelter", - }, -]; - -const targets = [ - { - __typename: "TargetDimensionInfo", - id: "Shipment1Calai", - name: "Shipment1Calai", - type: "OutgoingLocation", - }, - { - __typename: "TargetDimensionInfo", - id: "V93 LR", - name: "V93 LR", - type: "OutgoingLocation", - }, - { - __typename: "TargetDimensionInfo", - id: "Gelöschte Boxen", - name: "Gelöschte Boxen", - type: "OutgoingLocation", - }, - { - __typename: "TargetDimensionInfo", - id: "Lost", - name: "Lost", - type: "BoxState", - }, - { - __typename: "TargetDimensionInfo", - id: "Scrap", - name: "Scrap", - type: "BoxState", - }, -]; - -export const movedBoxesResultMockData = { +export default { movedBoxes: { __typename: "MovedBoxesData", facts: movedBoxesFacts, dimensions: { __typename: "MovedBoxDataDimensions", - target: targets, - category: categories, + target: targetDim, + category: categoryDim, }, }, }; diff --git a/shared-components/statviz/mocks/productDim.ts b/shared-components/statviz/mocks/productDim.ts new file mode 100644 index 000000000..02f943616 --- /dev/null +++ b/shared-components/statviz/mocks/productDim.ts @@ -0,0 +1,9 @@ +export default [ + { __typename: "ProductDimensionInfo", id: 1, name: "Unicorns", gender: "Mixed" }, + { __typename: "ProductDimensionInfo", id: 2, name: "Jumper", gender: "Men" }, + { __typename: "ProductDimensionInfo", id: 5, name: "Jumper", gender: "Women" }, + { __typename: "ProductDimensionInfo", id: 12421, name: "Jumper", gender: "Girl" }, + { __typename: "ProductDimensionInfo", id: 5232, name: "Trouser", gender: "Men" }, + { __typename: "ProductDimensionInfo", id: 23, name: 'Tro!^%$"user', gender: "Mixed" }, + { __typename: "ProductDimensionInfo", id: 451, name: "Trouser", gender: "Women" }, +]; diff --git a/shared-components/statviz/mocks/sizeDim.ts b/shared-components/statviz/mocks/sizeDim.ts new file mode 100644 index 000000000..d0e73a8bd --- /dev/null +++ b/shared-components/statviz/mocks/sizeDim.ts @@ -0,0 +1,212 @@ +export default [ + { + __typename: "DimensionInfo", + id: 1, + name: "S", + }, + { + __typename: "DimensionInfo", + id: 2, + name: "M", + }, + { + __typename: "DimensionInfo", + id: 3, + name: "L", + }, + { + __typename: "DimensionInfo", + id: 4, + name: "XL", + }, + { + __typename: "DimensionInfo", + id: 5, + name: "XS", + }, + { + __typename: "DimensionInfo", + id: 28, + name: "34", + }, + { + __typename: "DimensionInfo", + id: 30, + name: "36", + }, + { + __typename: "DimensionInfo", + id: 31, + name: "37", + }, + { + __typename: "DimensionInfo", + id: 32, + name: "38", + }, + { + __typename: "DimensionInfo", + id: 33, + name: "39", + }, + { + __typename: "DimensionInfo", + id: 34, + name: "40", + }, + { + __typename: "DimensionInfo", + id: 35, + name: "41", + }, + { + __typename: "DimensionInfo", + id: 36, + name: "42 and bigger", + }, + { + __typename: "DimensionInfo", + id: 52, + name: "Mixed", + }, + { + __typename: "DimensionInfo", + id: 53, + name: "S", + }, + { + __typename: "DimensionInfo", + id: 55, + name: "L", + }, + { + __typename: "DimensionInfo", + id: 56, + name: "38 and smaller", + }, + { + __typename: "DimensionInfo", + id: 57, + name: "39", + }, + { + __typename: "DimensionInfo", + id: 58, + name: "40", + }, + { + __typename: "DimensionInfo", + id: 59, + name: "41", + }, + { + __typename: "DimensionInfo", + id: 60, + name: "42", + }, + { + __typename: "DimensionInfo", + id: 61, + name: "43", + }, + { + __typename: "DimensionInfo", + id: 62, + name: "44", + }, + { + __typename: "DimensionInfo", + id: 63, + name: "45", + }, + { + __typename: "DimensionInfo", + id: 64, + name: "46 and bigger", + }, + { + __typename: "DimensionInfo", + id: 68, + name: "One size", + }, + { + __typename: "DimensionInfo", + id: 71, + name: "Mixed", + }, + { + __typename: "DimensionInfo", + id: 104, + name: "Pack of 5-20", + }, + { + __typename: "DimensionInfo", + id: 109, + name: "Size 1 (3-6 kg)", + }, + { + __typename: "DimensionInfo", + id: 110, + name: "Size 2 (5-8 kg)", + }, + { + __typename: "DimensionInfo", + id: 111, + name: "Size 3 (7-13 kg)", + }, + { + __typename: "DimensionInfo", + id: 112, + name: "Size 4 (9-17 kg)", + }, + { + __typename: "DimensionInfo", + id: 113, + name: "Size 5 (>12 kg)", + }, + { + __typename: "DimensionInfo", + id: 114, + name: "Size 6 (>16 kg)", + }, + { + __typename: "DimensionInfo", + id: 115, + name: "Kids (>19 kg)", + }, + { + __typename: "DimensionInfo", + id: 116, + name: "2-5 years", + }, + { + __typename: "DimensionInfo", + id: 117, + name: "6-10 years", + }, + { + __typename: "DimensionInfo", + id: 118, + name: "11-15 years", + }, + { + __typename: "DimensionInfo", + id: 126, + name: "Singlepack", + }, + { + __typename: "DimensionInfo", + id: 127, + name: "Multipack", + }, + { + __typename: "DimensionInfo", + id: 138, + name: "0-6 months", + }, + { + __typename: "DimensionInfo", + id: 139, + name: "7-24 months", + }, +]; diff --git a/shared-components/statviz/mocks/stockOverview.ts b/shared-components/statviz/mocks/stockOverview.ts new file mode 100644 index 000000000..ba82ff542 --- /dev/null +++ b/shared-components/statviz/mocks/stockOverview.ts @@ -0,0 +1,88 @@ +import categoryDim from "./categoryDim"; +import sizeDim from "./sizeDim"; + +const facts = [ + { + __typename: "StockOverviewResult", + productName: "Jumper", + categoryId: 3, + gender: "Men", + boxesCount: 1, + itemsCount: 47, + sizeId: 1, + tagIds: [1], + boxState: "InStock", + locationId: 12, + }, + { + __typename: "StockOverviewResult", + productName: "Jumper", + categoryId: 3, + gender: "Women", + boxesCount: 1, + itemsCount: 47, + sizeId: 2, + tagIds: [1, 2], + boxState: "InStock", + locationId: 12, + }, + { + __typename: "StockOverviewResult", + productName: "Jumper", + categoryId: 3, + gender: "Girl", + boxesCount: 1, + itemsCount: 47, + sizeId: 1, + tagIds: [4], + boxState: "InStock", + locationId: 125, + }, + { + __typename: "StockOverviewResult", + productName: "Trouser", + categoryId: 3, + gender: "Men", + boxesCount: 1, + itemsCount: 47, + sizeId: 1, + tagIds: [4], + boxState: "InStock", + locationId: 12, + }, + { + __typename: "StockOverviewResult", + productName: 'Tro!^%$"user', + categoryId: 3, + gender: "Mixed", + boxesCount: 1, + itemsCount: 47, + sizeId: 1, + tagIds: [], + boxState: "InStock", + locationId: 125, + }, + { + __typename: "StockOverviewResult", + productName: "Trouser", + categoryId: 3, + gender: "Men", + boxesCount: 1, + itemsCount: 47, + sizeId: 3, + tagIds: [], + boxState: "InStock", + locationId: 12, + }, +]; + +export default { + stockOverview: { + __typename: "StockOverviewData", + facts, + dimensions: { + category: categoryDim, + size: sizeDim, + }, + }, +}; diff --git a/shared-components/statviz/mocks/tagDim.ts b/shared-components/statviz/mocks/tagDim.ts new file mode 100644 index 000000000..1fcf88731 --- /dev/null +++ b/shared-components/statviz/mocks/tagDim.ts @@ -0,0 +1,32 @@ +export default [ + { + __typename: "TagDimensionInfo", + id: 1, + name: "Test-Tag", + color: "#f8aa9e", + }, + { + __typename: "TagDimensionInfo", + id: 2, + name: "Palette1", + color: "#f8aa9e", + }, + { + __typename: "TagDimensionInfo", + id: 3, + name: "Palette2", + color: "#d89016", + }, + { + __typename: "TagDimensionInfo", + id: 4, + name: "Tag01", + color: "#315c88", + }, + { + __typename: "TagDimensionInfo", + id: 5, + name: "Tag02", + color: "#315c88", + }, +]; diff --git a/shared-components/statviz/mocks/targetDim.ts b/shared-components/statviz/mocks/targetDim.ts new file mode 100644 index 000000000..b81aafa96 --- /dev/null +++ b/shared-components/statviz/mocks/targetDim.ts @@ -0,0 +1,32 @@ +export default [ + { + __typename: "TargetDimensionInfo", + id: "Shipment1Calai", + name: "Shipment1Calai", + type: "OutgoingLocation", + }, + { + __typename: "TargetDimensionInfo", + id: "V93 LR", + name: "V93 LR", + type: "OutgoingLocation", + }, + { + __typename: "TargetDimensionInfo", + id: "Gelöschte Boxen", + name: "Gelöschte Boxen", + type: "OutgoingLocation", + }, + { + __typename: "TargetDimensionInfo", + id: "Lost", + name: "Lost", + type: "BoxState", + }, + { + __typename: "TargetDimensionInfo", + id: "Scrap", + name: "Scrap", + type: "BoxState", + }, +]; From f27cf90eadcce24a5c60222a3ffe6f2544aa28cf Mon Sep 17 00:00:00 2001 From: MaikNeubert Date: Mon, 11 Mar 2024 01:16:26 +0100 Subject: [PATCH 10/10] wip tests --- .../createdBoxes/CreatedBoxes.test.tsx | 20 ++++++++++++++----- .../statviz/mocks/createdBoxes.ts | 20 +++++++++---------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxes.test.tsx b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxes.test.tsx index a3f0f1da2..bbb90c35d 100644 --- a/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxes.test.tsx +++ b/shared-components/statviz/components/visualizations/createdBoxes/CreatedBoxes.test.tsx @@ -1,10 +1,12 @@ import { MockedResponse } from "@apollo/client/testing"; import { GraphQLError } from "graphql"; -import { it, expect, describe } from "vitest"; +import { it, vi, expect, describe } from "vitest"; import CreatedBoxesDataContainer, { CREATED_BOXES_QUERY } from "./CreatedBoxesDataContainer"; -import { render, screen } from "../../../../tests/testUtils"; +import { render, screen, waitFor } from "../../../../tests/testUtils"; import createdBoxes from "../../../mocks/createdBoxes"; +const mockCreatedBoxesBarChart = vi.fn(); + describe("Created Boxes Visualizations", () => { const mockCreatedBoxesQuery = ({ baseId = 1, @@ -36,6 +38,14 @@ describe("Created Boxes Visualizations", () => { }; }; + vi.mock("@nivo/bar", () => ({ + ResponsiveSankey: (props) => { + mockCreatedBoxesBarChart(props); + + return
BarChart
; + }, + })); + it("x.x.x.x - user wants to see createdBoxes viz, but a network error is returned", async () => { render(, { routePath: "/bases/:baseId/statviz", @@ -58,18 +68,18 @@ describe("Created Boxes Visualizations", () => { it("x.x.x.x - user sees createdBoxes viz", async () => { render(, { - routePath: "/bases/:baseId/statviz", + routePath: "/bases/:baseId/statviz?stg=cn&boi=bc&cbg=m&to=2023-09-02&from=2023-01-30", initialUrl: "/bases/1/statviz", mocks: [mockCreatedBoxesQuery({ mockData: createdBoxes })], }); - // expect(await screen.findByText(/loading.../i)).toBeInTheDocument(); + await waitFor(() => expect(mockCreatedBoxesBarChart).toHaveBeenCalled()); }); it("x.x.x.x - user calls page with some filters", async () => { render(, { routePath: "/bases/:baseId/statviz", - initialUrl: "/bases/1/statviz", + initialUrl: "/bases/1/statviz?stg=cn&boi=bc&cbg=m&to=2023-09-02&from=2023-01-30", mocks: [mockCreatedBoxesQuery({ mockData: createdBoxes })], }); diff --git a/shared-components/statviz/mocks/createdBoxes.ts b/shared-components/statviz/mocks/createdBoxes.ts index 974737803..214f4e126 100644 --- a/shared-components/statviz/mocks/createdBoxes.ts +++ b/shared-components/statviz/mocks/createdBoxes.ts @@ -28,7 +28,7 @@ const facts = [ boxesCount: 4, productId: 1772, categoryId: 3, - createdOn: "2020-01-08T00:00:00", + createdOn: "202-01-08T00:00:00", tagIds: [791, 884], gender: "Women", itemsCount: 81, @@ -38,7 +38,7 @@ const facts = [ boxesCount: 2, productId: 1772, categoryId: 3, - createdOn: "2020-01-12T00:00:00", + createdOn: "202-01-12T00:00:00", tagIds: [], gender: "Women", itemsCount: 38, @@ -48,7 +48,7 @@ const facts = [ boxesCount: 2, productId: 1772, categoryId: 3, - createdOn: "2020-01-21T00:00:00", + createdOn: "202-01-21T00:00:00", tagIds: [], gender: "Women", itemsCount: 44, @@ -58,7 +58,7 @@ const facts = [ boxesCount: 5, productId: 1772, categoryId: 3, - createdOn: "2020-03-08T00:00:00", + createdOn: "202-03-08T00:00:00", tagIds: [787, 879], gender: "Women", itemsCount: 143, @@ -68,7 +68,7 @@ const facts = [ boxesCount: 53, productId: 1772, categoryId: 3, - createdOn: "2020-04-18T00:00:00", + createdOn: "2023-04-18T00:00:00", tagIds: [], gender: "Women", itemsCount: 1262, @@ -78,7 +78,7 @@ const facts = [ boxesCount: 1, productId: 1772, categoryId: 3, - createdOn: "2020-05-17T00:00:00", + createdOn: "2023-05-17T00:00:00", tagIds: [], gender: "Women", itemsCount: 23, @@ -88,7 +88,7 @@ const facts = [ boxesCount: 1, productId: 1772, categoryId: 3, - createdOn: "2020-06-07T00:00:00", + createdOn: "2023-06-07T00:00:00", tagIds: [], gender: "Women", itemsCount: 23, @@ -98,7 +98,7 @@ const facts = [ boxesCount: 3, productId: 1772, categoryId: 3, - createdOn: "2020-06-28T00:00:00", + createdOn: "2023-06-28T00:00:00", tagIds: [], gender: "Women", itemsCount: 59, @@ -108,7 +108,7 @@ const facts = [ boxesCount: 1, productId: 1772, categoryId: 3, - createdOn: "2020-07-05T00:00:00", + createdOn: "2023-07-05T00:00:00", tagIds: [], gender: "Women", itemsCount: 20, @@ -118,7 +118,7 @@ const facts = [ boxesCount: 2, productId: 1772, categoryId: 3, - createdOn: "2020-07-12T00:00:00", + createdOn: "2023-07-12T00:00:00", tagIds: [], gender: "Women", itemsCount: 42,