From 244b2225b22a36b1e91f568294609c3803fd0164 Mon Sep 17 00:00:00 2001 From: NoamGaash Date: Sat, 16 Dec 2023 12:51:49 +0200 Subject: [PATCH] feat: create research route (#307) --- README.md | 2 + src/layout/index.tsx | 7 +- src/pages/DataResearch/DataResearch.scss | 3 + src/pages/DataResearch/DataResearch.tsx | 229 +++++++++++++++++++++++ src/routes/index.tsx | 7 +- src/shared/Widget.tsx | 2 +- 6 files changed, 246 insertions(+), 4 deletions(-) create mode 100644 src/pages/DataResearch/DataResearch.scss create mode 100644 src/pages/DataResearch/DataResearch.tsx diff --git a/README.md b/README.md index 6c7cf39e..21e77725 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ We've hidden a couple of fun surprises in our web app, just for you. Discovering Watch the magic unfold as you type "storybook" on your keyboard. You might just stumble upon our Storybook, a treasure trove of UI components showcasing the beauty and functionality of our app. - **Type "english":** Feel like switching up the language? Type "english" and see the language toggle in action. Our app is multilingual, and you can experience it by triggering this secret command. + - **Type "geek":** + To get some experimental charts with some additional data and aggregation ## deployments diff --git a/src/layout/index.tsx b/src/layout/index.tsx index 9ce78566..81336db7 100644 --- a/src/layout/index.tsx +++ b/src/layout/index.tsx @@ -3,7 +3,7 @@ import MainHeader from './header/Header' import SideBar from './sidebar/SideBar' import styled from 'styled-components' import LayoutContext from './LayoutContext' -import { Outlet } from 'react-router-dom' +import { Link, Outlet } from 'react-router-dom' import { Suspense } from 'react' import Preloader from 'src/shared/Preloader' import { EasterEgg } from 'src/pages/EasterEgg/EasterEgg' @@ -39,6 +39,11 @@ export function MainLayout() { + + + + + diff --git a/src/pages/DataResearch/DataResearch.scss b/src/pages/DataResearch/DataResearch.scss new file mode 100644 index 00000000..5e970cb4 --- /dev/null +++ b/src/pages/DataResearch/DataResearch.scss @@ -0,0 +1,3 @@ +.recharts-tooltip-wrapper { + z-index: 1; +} diff --git a/src/pages/DataResearch/DataResearch.tsx b/src/pages/DataResearch/DataResearch.tsx new file mode 100644 index 00000000..5e545b37 --- /dev/null +++ b/src/pages/DataResearch/DataResearch.tsx @@ -0,0 +1,229 @@ +import React, { useMemo } from 'react' +import { useGroupBy } from 'src/api/groupByService' +import Widget from 'src/shared/Widget' +import { useDate } from '../components/DateTimePicker' +import moment from 'moment' +import { Grid } from '@mui/material' +import { DateSelector } from '../components/DateSelector' +import { useTranslation } from 'react-i18next' +import { Skeleton } from 'antd' +import { + Area, + Tooltip, + AreaChart, + CartesianGrid, + ResponsiveContainer, + XAxis, + YAxis, +} from 'recharts' +import { PageContainer } from '../components/PageContainer' +import { getColorName } from '../dashboard/AllLineschart/OperatorHbarChart/OperatorHbarChart' + +import './DataResearch.scss' + +const now = moment() +const unique: (value: string, index: number, self: string[]) => boolean = (value, index, self) => + self.indexOf(value) === index + +export const DataResearch = () => { + return ( + + +

מחקרים

+

אם יש לכם רעיון מעניין למה קורים פה דברים, דברו איתנו בסלאק!

+
+ +
+ ) +} + +function StackedResearchSection() { + const [startDate, setStartDate] = useDate(now.clone().subtract(7, 'days')) + const [endDate, setEndDate] = useDate(now.clone().subtract(1, 'day')) + const [groupByHour, setGroupByHour] = React.useState(false) + const [graphData, loadingGraph] = useGroupBy({ + dateTo: endDate, + dateFrom: startDate, + groupBy: groupByHour ? 'operator_ref,gtfs_route_hour' : 'operator_ref,gtfs_route_date', + }) + + return ( + +

בעיות etl/gps/משהו גלובאלי אחר

+ + + + +
+ ) +} + +function StackedResearchInputs({ + startDate, + setStartDate, + endDate, + setEndDate, + groupByHour, + setGroupByHour, +}: { + startDate: moment.Moment + setStartDate: (date: moment.Moment) => void + endDate: moment.Moment + setEndDate: (date: moment.Moment) => void + groupByHour: boolean + setGroupByHour: (value: boolean) => void +}) { + const { t } = useTranslation() + return ( + <> + + + setStartDate(data)} + customLabel={t('start')} + /> + + + setEndDate(data)} + customLabel={t('end')} + /> + + + + + ) +} + +const StackedResearchChart = ({ + graphData, + isLoading, + title, + description, + field = 'total_actual_rides', +}: { + graphData: { + gtfs_route_date: string + gtfs_route_hour: string + operator_ref?: { + agency_name?: string + } + total_actual_rides: number + total_planned_rides: number + }[] + isLoading?: boolean + title?: string + description?: string + field?: 'total_actual_rides' | 'total_planned_rides' | 'total_missed_rides' +}) => { + const data = useMemo( + () => + graphData + .reduce((acc, curr) => { + const val = + field === 'total_missed_rides' + ? curr.total_planned_rides - curr.total_actual_rides + : curr[field] + const date = curr.gtfs_route_date ?? curr.gtfs_route_hour + const entry = acc.find((item) => item.date === date) + if (entry) { + if (val) entry[curr.operator_ref?.agency_name || 'Unknown'] = val + } else { + const newEntry = { + date: date, + [curr.operator_ref?.agency_name || 'Unknown']: val, + } + acc.push(newEntry) + } + return acc + }, [] as Record[]) + .sort((a, b) => { + if (a.date > b.date) return 1 + if (a.date < b.date) return -1 + return 0 + }), + [graphData], + ) + + const operators = graphData + .map((operator) => operator.operator_ref?.agency_name || 'Unknown') + .filter(unique) + + return ( + <> + {title &&

{title}

} + {description && ( +

+ מה רואים בגרף? +
+ {description} +

+ )} + {isLoading ? ( + + ) : ( + + + + + + {operators.map((operator) => ( + + ))} + + + + )} + + ) +} diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 792724b9..4f1c8ca9 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -9,6 +9,9 @@ const SingleLineMapPage = lazy(() => import('../pages/singleLineMap')) const About = lazy(() => import('../pages/about')) const Profile = lazy(() => import('../pages/Profile')) const BugReportForm = lazy(() => import('../pages/BugReportForm ')) +const DataResearch = lazy(() => + import('../pages/DataResearch/DataResearch').then((m) => ({ default: m.DataResearch })), +) import { RadarChartOutlined, @@ -104,8 +107,8 @@ const getRoutesList = () => { return gtfs_route }} /> - , - } key="back" />, + } /> + } key="back" /> // ) diff --git a/src/shared/Widget.tsx b/src/shared/Widget.tsx index 5ce1393c..e319c227 100644 --- a/src/shared/Widget.tsx +++ b/src/shared/Widget.tsx @@ -1,5 +1,5 @@ const Widget = (props: { children: React.ReactNode }) => { - return
{props.children}
+ return
{props.children}
} export default Widget