-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: create research route #307
Changes from 7 commits
c7e42b5
29911dd
ec97477
7a09664
d4b1b19
4b0c1df
595acf8
b7554fd
611447e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
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' | ||
|
||
const now = moment() | ||
const unique: (value: string, index: number, self: string[]) => boolean = (value, index, self) => | ||
self.indexOf(value) === index | ||
|
||
export const DataResearch = () => { | ||
return ( | ||
<PageContainer> | ||
<Widget> | ||
<h1>מחקרים</h1> | ||
<p>אם יש לכם רעיון מעניין למה קורים פה דברים, דברו איתנו בסלאק!</p> | ||
</Widget> | ||
<StackedResearchSection /> | ||
</PageContainer> | ||
) | ||
} | ||
|
||
function StackedResearchSection() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should move it above the DataResearch component There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As I wrote in different comment you don't have to |
||
const [startDate, setStartDate] = useDate(now.clone().subtract(7, 'days')) | ||
const [endDate, setEndDate] = useDate(now.clone().subtract(1, 'day')) | ||
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> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also here and in some more places in this file , pls use useTranslation |
||
<StackedResearchInputs | ||
startDate={startDate} | ||
setStartDate={setStartDate} | ||
endDate={endDate} | ||
setEndDate={setEndDate} | ||
groupByHour={groupByHour} | ||
setGroupByHour={setGroupByHour} | ||
/> | ||
<StackedResearchChart | ||
graphData={graphData} | ||
isLoading={loadingGraph} | ||
field="total_actual_rides" | ||
title="מספר נסיעות בפועל" | ||
description="כמה נסיעות נרשמו כהתבצעו בכל יום/שעה בטווח הזמן שבחרתם. (נסיעות = siri rides)" | ||
/> | ||
<StackedResearchChart | ||
graphData={graphData} | ||
isLoading={loadingGraph} | ||
field="total_planned_rides" | ||
title="מספר נסיעות מתוכננות" | ||
description="כמה נסיעות היו אמורות להיות בכל יום/שעה בטווח הזמן שבחרתם. (נסיעות = נסיעות מתוכננות בgtfs)" | ||
/> | ||
<StackedResearchChart | ||
graphData={graphData} | ||
isLoading={loadingGraph} | ||
field="total_missed_rides" | ||
title="מספר נסיעות שלא התבצעו" | ||
description="כמה נסיעות היו אמורות להיות בכל יום/שעה בטווח הזמן שבחרתם אבל לא התבצעו. (הפרש בין שני הגרפים הקודמים)" | ||
/> | ||
</Widget> | ||
) | ||
} | ||
|
||
function StackedResearchInputs({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should move it above the StackedResearchSection component There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, you don't have to, but when I read the file from above to down you use functions and then declare them. However, you use the component in different file so it is not give an errors, up to you. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Usually, I prefer putting helper function and small utilities at the bottom, so when you read it you'll see the important things first. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok 👍 |
||
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 ( | ||
<> | ||
<Grid container> | ||
<Grid xs={6} item> | ||
<DateSelector | ||
time={startDate} | ||
onChange={(data) => setStartDate(data)} | ||
customLabel={t('start')} | ||
/> | ||
</Grid> | ||
<Grid xs={6} item> | ||
<DateSelector | ||
time={endDate} | ||
onChange={(data) => setEndDate(data)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: It is better not to allow to choose an end date earlier than the start date There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you're right, but since it's an internal endpoint, it's less important here. |
||
customLabel={t('end')} | ||
/> | ||
</Grid> | ||
</Grid> | ||
<label> | ||
<input | ||
type="checkbox" | ||
checked={groupByHour} | ||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setGroupByHour(e.target.checked)} | ||
/> | ||
{t('group_by_hour_tooltip_content')} | ||
</label> | ||
</> | ||
) | ||
} | ||
|
||
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<string, string | number>[]) | ||
.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 && <h2>{title}</h2>} | ||
{description && ( | ||
<p> | ||
<strong>מה רואים בגרף?</strong> | ||
<br /> | ||
{description} | ||
</p> | ||
)} | ||
{isLoading ? ( | ||
<Skeleton active /> | ||
) : ( | ||
<ResponsiveContainer width="100%" height="100%" minHeight="500px"> | ||
<AreaChart | ||
width={500} | ||
height={400} | ||
data={data} | ||
margin={{ | ||
top: 10, | ||
right: 30, | ||
left: 0, | ||
bottom: 0, | ||
}}> | ||
<CartesianGrid strokeDasharray="3 3" /> | ||
<XAxis dataKey="date" /> | ||
<YAxis /> | ||
{operators.map((operator) => ( | ||
<Area | ||
type="monotone" | ||
dataKey={operator} | ||
key={operator} | ||
stackId="1" | ||
stroke={getColorName(operator)} | ||
fill={getColorName(operator)} | ||
/> | ||
))} | ||
<Tooltip /> | ||
</AreaChart> | ||
</ResponsiveContainer> | ||
)} | ||
</> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
const Widget = (props: { children: React.ReactNode }) => { | ||
return <div className="widget">{props.children}</div> | ||
return <section className="widget">{props.children}</section> | ||
} | ||
|
||
export default Widget |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use here useTranslation and not Hebrew
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's a temporary internal thing, I don't think it should ever be translated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I understand