Skip to content

Commit

Permalink
feat: Add an Operator Selector to data-research page (#444)
Browse files Browse the repository at this point in the history
Co-authored-by: yadenmezi <[email protected]>
  • Loading branch information
yardenmezi and yadenmezi authored Jan 31, 2024
1 parent 1758bf5 commit ee2cc1b
Show file tree
Hide file tree
Showing 8 changed files with 1,694 additions and 3,762 deletions.
4 changes: 4 additions & 0 deletions src/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@
"order_by_severity": "by severity",
"choose_dates": "Dates",
"single_line_map_title": "Locations of selected lines",
"operatorSelectorOptions":
{
"all": "all"
},
"reportBug": {
"description": "This form is designed so that we can receive feedback and improve the application. Please be aware that the submitted information will be available to the public.",
"error": "An error occurred while sending the report. Please try again later.",
Expand Down
5 changes: 4 additions & 1 deletion src/locale/he.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@
"donations": "שרתים עולים כסף - עזרו לנו להמשיך לתחזק ולפתח את הפרויקט!"
}
},

"operatorSelectorOptions":
{
"all": "הכל"
},
"dashboard_page_graph_title_hour": "אחוזי יציאה מסך הנסיעות לפי שעה",
"dashboard_page_graph_title_day": "אחוזי יציאה מסך הנסיעות לפי יום",
"group_by_day_tooltip_content": "קיבוץ לפי יום",
Expand Down
13 changes: 10 additions & 3 deletions src/model/operator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@ export type Operator = {
id: string
}

export const getRelevantOperators = async () => {
export const getRelevantOperators = async (onlyRelevantOperators: boolean) => {
const agencyList = await getAgencyList()
if (!onlyRelevantOperators) {
const allOperators = agencyList.map((agency) => ({
name: agency.agency_name,
id: agency.operator_ref.toString(),
}))
return allOperators
}
const relevant = [
'אגד',
'אגד תעבורה',
Expand All @@ -17,12 +25,11 @@ export const getRelevantOperators = async () => {
'קווים',
'תנופה',
]
const agencyList = await getAgencyList()
const agencyMap = new Map()
// convert to Map
agencyList.forEach((obj) => {
agencyMap.set(obj.agency_name, obj)
})

const res = relevant.reduce((acc: Operator[], name: string): Operator[] => {
return agencyMap.has(name)
? [...acc, { name, id: agencyMap.get(name)?.operator_ref.toString() }]
Expand Down
28 changes: 22 additions & 6 deletions src/pages/DataResearch/DataResearch.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo } from 'react'
import React, { useMemo, useState } from 'react'
import { useGroupBy } from 'src/api/groupByService'
import Widget from 'src/shared/Widget'
import { useDate } from '../components/DateTimePicker'
Expand All @@ -18,8 +18,8 @@ import {
} from 'recharts'
import { PageContainer } from '../components/PageContainer'
import { getColorName } from '../dashboard/AllLineschart/OperatorHbarChart/OperatorHbarChart'

import './DataResearch.scss'
import OperatorSelector, { FilterOperatorOptions } from '../components/OperatorSelector'

const now = moment()
const unique: (value: string, index: number, self: string[]) => boolean = (value, index, self) =>
Expand All @@ -40,13 +40,14 @@ export const DataResearch = () => {
function StackedResearchSection() {
const [startDate, setStartDate] = useDate(now.clone().subtract(7, 'days'))
const [endDate, setEndDate] = useDate(now.clone().subtract(1, 'day'))
const [operatorId, setOperatorId] = useState('')
const [groupByHour, setGroupByHour] = React.useState<boolean>(false)
const [graphData, loadingGraph] = useGroupBy({
dateTo: endDate,
dateFrom: startDate,
groupBy: groupByHour ? 'operator_ref,gtfs_route_hour' : 'operator_ref,gtfs_route_date',
})

return (
<Widget>
<h1>בעיות etl/gps/משהו גלובאלי אחר</h1>
Expand All @@ -57,27 +58,32 @@ function StackedResearchSection() {
setEndDate={setEndDate}
groupByHour={groupByHour}
setGroupByHour={setGroupByHour}
operatorId={operatorId}
setOperatorId={setOperatorId}
/>
<StackedResearchChart
graphData={graphData}
isLoading={loadingGraph}
field="total_actual_rides"
title="מספר נסיעות בפועל"
description="כמה נסיעות נרשמו כהתבצעו בכל יום/שעה בטווח הזמן שבחרתם. (נסיעות = siri rides)"
agencyId={operatorId}
/>
<StackedResearchChart
graphData={graphData}
isLoading={loadingGraph}
field="total_planned_rides"
title="מספר נסיעות מתוכננות"
description="כמה נסיעות היו אמורות להיות בכל יום/שעה בטווח הזמן שבחרתם. (נסיעות = נסיעות מתוכננות בgtfs)"
agencyId={operatorId}
/>
<StackedResearchChart
graphData={graphData}
isLoading={loadingGraph}
field="total_missed_rides"
title="מספר נסיעות שלא התבצעו"
description="כמה נסיעות היו אמורות להיות בכל יום/שעה בטווח הזמן שבחרתם אבל לא התבצעו. (הפרש בין שני הגרפים הקודמים)"
agencyId={operatorId}
/>
</Widget>
)
Expand All @@ -90,13 +96,17 @@ function StackedResearchInputs({
setEndDate,
groupByHour,
setGroupByHour,
operatorId,
setOperatorId,
}: {
startDate: moment.Moment
setStartDate: (date: moment.Moment) => void
endDate: moment.Moment
setEndDate: (date: moment.Moment) => void
groupByHour: boolean
setGroupByHour: (value: boolean) => void
operatorId: string
setOperatorId: (value: string) => void
}) {
const { t } = useTranslation()
return (
Expand All @@ -116,6 +126,7 @@ function StackedResearchInputs({
customLabel={t('end')}
/>
</Grid>
<OperatorSelector operatorId={operatorId} setOperatorId={setOperatorId} filter={FilterOperatorOptions.ALL}/>
</Grid>
<label>
<input
Expand All @@ -135,11 +146,13 @@ const StackedResearchChart = ({
title,
description,
field = 'total_actual_rides',
agencyId = '',
}: {
graphData: {
gtfs_route_date: string
gtfs_route_hour: string
operator_ref?: {
agency_id?: string
agency_name?: string
}
total_actual_rides: number
Expand All @@ -149,10 +162,13 @@ const StackedResearchChart = ({
title?: string
description?: string
field?: 'total_actual_rides' | 'total_planned_rides' | 'total_missed_rides'
agencyId?: string
}) => {
const filteredGraphData =
agencyId == '' ? graphData : graphData.filter((dataRecord) => dataRecord.operator_ref?.agency_id === agencyId)
const data = useMemo(
() =>
graphData
filteredGraphData
.reduce((acc, curr) => {
const val =
field === 'total_missed_rides'
Expand All @@ -176,10 +192,10 @@ const StackedResearchChart = ({
if (a.date < b.date) return -1
return 0
}),
[graphData],
[filteredGraphData],
)

const operators = graphData
const operators = filteredGraphData
.map((operator) => operator.operator_ref?.agency_name || 'Unknown')
.filter(unique)

Expand Down
34 changes: 34 additions & 0 deletions src/pages/components/OperatorSelector.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { Meta, StoryObj } from '@storybook/react';
import '../../shared/shared.css';
import OperatorSelector, { FilterOperatorOptions } from './OperatorSelector';
import { useState } from 'react';

const OperatorSelectorStory = () => {
const [operatorId, setOperatorId] = useState<string>();

return (
<div>
<h1>בחירת המפעילים הגדולים</h1>
<OperatorSelector operatorId={operatorId} setOperatorId={setOperatorId} filter={FilterOperatorOptions.MAJOR}></OperatorSelector>
<h1>בחירת כל המפעילים</h1>
<OperatorSelector operatorId={operatorId} setOperatorId={setOperatorId} filter={FilterOperatorOptions.ALL}></OperatorSelector>
<h1>בחירת המפעילים הרלוונטיים</h1>
<OperatorSelector operatorId={operatorId} setOperatorId={() => ""} filter={FilterOperatorOptions.RELEVANT}></OperatorSelector>
</div>
);
};

const meta: Meta = {
title: 'Components/OperatorSelector',
component: OperatorSelectorStory,
};

export default meta;

type Story = StoryObj<typeof meta>;

const defaultArgs = {};

export const Default: Story = {
args: defaultArgs,
};
32 changes: 22 additions & 10 deletions src/pages/components/OperatorSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,41 @@ import { useTranslation } from 'react-i18next'
import { Operator, getRelevantOperators } from 'src/model/operator'
import { Autocomplete, TextField } from '@mui/material'

export enum FilterOperatorOptions {
ALL,
RELEVANT,
MAJOR,
}

type OperatorSelectorProps = {
operatorId?: string
setOperatorId: (operatorId: string) => void
onlyMajorOperators?: boolean
filter?: FilterOperatorOptions
}

const OperatorSelector = ({
operatorId,
setOperatorId,
onlyMajorOperators = false,
filter = FilterOperatorOptions.RELEVANT,
}: OperatorSelectorProps) => {
const { t } = useTranslation()
const [operators, setOperators] = useState<Operator[]>([])
useEffect(() => {
const majorOperatorsIds = ['3', '5', '15', '18', '25', '34']
getRelevantOperators().then((resultObj) =>
setOperators(
onlyMajorOperators
? resultObj.filter((item) => majorOperatorsIds.includes(item.id))
: resultObj,
),
)
}, [onlyMajorOperators])
getRelevantOperators(filter != FilterOperatorOptions.ALL)
.then((list) =>
filter === FilterOperatorOptions.ALL
? [...list, { id: '', name: t('operatorSelectorOptions.all') }]
: list,
)
.then((resultObj) =>
setOperators(
filter == FilterOperatorOptions.MAJOR && resultObj
? resultObj.filter((item) => majorOperatorsIds.includes(item.id))
: resultObj,
),
)
}, [filter == FilterOperatorOptions.MAJOR])

const valueFinned = operators.find((operator) => operator.id === operatorId)
const value = valueFinned ? valueFinned : null
Expand Down
5 changes: 2 additions & 3 deletions src/pages/dashboard/DashboardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Alert, Typography } from 'antd'
import Grid from '@mui/material/Unstable_Grid2' // Grid version 2

// Components
import OperatorSelector from 'src/pages/components/OperatorSelector'
import OperatorSelector, { FilterOperatorOptions } from 'src/pages/components/OperatorSelector'
import DayTimeChart from './ArrivalByTimeChart/DayTimeChart'
import AllLinesChart from './AllLineschart/AllLinesChart'
import WorstLinesChart from './WorstLinesChart/WorstLinesChart'
Expand Down Expand Up @@ -65,15 +65,14 @@ const DashboardPage = () => {
<OperatorSelector
operatorId={operatorId}
setOperatorId={setOperatorId}
onlyMajorOperators
filter={FilterOperatorOptions.MAJOR}
/>
</Grid>
</Grid>
<Grid container spacing={2} alignItems="flex-start">
<Grid xs={12} lg={6} className="widget">
<AllLinesChart startDate={startDate} endDate={endDate} />
</Grid>

<Grid xs={12} lg={6} className="widget">
<WorstLinesChart startDate={startDate} endDate={endDate} operatorId={operatorId} />
</Grid>
Expand Down
Loading

0 comments on commit ee2cc1b

Please sign in to comment.