Home.tsx 6.21 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import React, { ChangeEvent, useContext, useEffect, useState } from 'react'
import { useHistory } from 'react-router-dom'
import DatePicker from 'react-datepicker'
import { PageMarginLeftRight } from '../../style/PageMarginLeftRight'
import styled, { ThemeContext } from 'styled-components'
import { distance } from '../../style/sizes'
import { Bar, BarChart, CartesianGrid, Label, Legend, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'
import { chartColors } from '../../style/chartColors'
import 'react-datepicker/dist/react-datepicker.css'
import Input from '../../components/input/Input'
import { InputWithLabel } from '../../components/inputWithLabel/InputWithLabel'
import { ChartInfoBox } from '../../components/chartInfoBox/ChartInfoBox'
import Button from '../../components/button/Button'
import Select from 'components/select/Select'
import { ClipLoader } from 'react-spinners'
import logo from './../../pictures/SantanderCyclesLogo.png';

interface IBikeTripDurationCount {
    classLabel: string,
    count: number
}

/**
 * Landing page of our dashboard.
 * Contains non-map visualizations.
 * Also contains link to access bike sharing map of London.
 */
export const Home = () => {
    const history = useHistory()

    const [startTimeStamp, setStartTimestamp] = useState(Date.UTC(2015, 0, 4, 0, 5))
    const [endTimeStamp, setEndTimeStamp] = useState(Date.UTC(2015, 0, 19, 0, 10))
    const [classSize, setClassSize] = useState(300)

    const [tripDurationData, setTripDurationData] = useState<IBikeTripDurationCount[] | undefined>(undefined)

    const [loadingState, setLoadingState] = useState(false)

    // fetch data from our server once at beginning, later only on button click
    useEffect(() => {fetchData()}, [])

    const fetchData = async () => {
        setLoadingState(true)
        const response = await fetch(`http://localhost:8081/api/bike-trip-durations?classSize=${classSize}&from=${startTimeStamp / 1000}&to=${endTimeStamp / 1000}`)
        const jsonResponse = await response.json()
        setTripDurationData(jsonResponse.bikeTripDurationCounts)
        setLoadingState(false)
    }

    return (
        <PageMarginLeftRight>
            <StyledTopRow>
            <div><Button onClick={() => history.push('/map')}>To map</Button></div>
            <img src={logo} alt='Logo' height='75' />
            </StyledTopRow>
            <StyledRow>
            <h2>Bike-sharing in London</h2>
            </StyledRow>
            <StyledRow>
                <div>
                <ChartInfoBox bold={true} description={'This bar chart shows the count of trips with similar durations within the selected timerange. The bars represent the number of trips.'}>
                    <StyledRow>
                        <InputWithLabel label={'Class Size'}> 
                            <Select defaultValue='300' onChange={(event: ChangeEvent<HTMLSelectElement>) => setClassSize(Number(event.target.value))}>
                                <option value='60'>1 minute</option>
                                <option value='300'>5 minutes</option>
                                <option value='600'>10 minutes</option>
                                <option value='1200'>20 minutes</option>
                                <option value='1800'>30 minutes</option>
                            </Select>
                        </InputWithLabel>
                    </StyledRow>
                    <StyledRow>
                        <InputWithLabel label={'From'}>
                            <DatePicker
                                selected={new Date(startTimeStamp)}
                                onChange={(date: Date) => setStartTimestamp(date.getTime())}
                                dateFormat='yyyy/MM/dd, HH:mm'
                                showTimeSelect
                                timeFormat='HH:mm'
                                timeIntervals={5}
                                customInput={<Input />}
                            />
                        </InputWithLabel>
                        <InputWithLabel label={'To'}>
                            <DatePicker
                                selected={new Date(endTimeStamp)}
                                onChange={(date: Date) => setEndTimeStamp(date.getTime())}
                                dateFormat='yyyy/MM/dd, HH:mm'
                                showTimeSelect
                                timeFormat='HH:mm'
                                timeIntervals={5}
                                customInput={<Input />}
                            />
                        </InputWithLabel>
                    </StyledRow>
                    <StyledRow>
                        <Button onClick={fetchData}>Apply Options</Button>&nbsp;&nbsp;&nbsp;{loadingState && <ClipLoader color={'white'} loading={loadingState}/>}
                    </StyledRow>
                </ChartInfoBox>
                </div>
                <ResponsiveContainer width='100%' height={600}>
                    <BarChart
                        data={tripDurationData}
                        margin={{top: 5, right: 0, left: 30, bottom: 50,}}
                        barCategoryGap={15}
                    >
                        <CartesianGrid strokeDasharray='3 3'/>
                        <XAxis dataKey='classLabel' angle={45} textAnchor='start' height={50}>
                            <Label value='duration of trip in minutes' offset={10} position='bottom' style={{fill: 'rgba(255, 255, 255, 1)'}} />
                        </XAxis>
                        <YAxis allowDecimals={false} />
                        <Tooltip contentStyle={{ backgroundColor: useContext(ThemeContext).colors.backgroundPrimary }}/>
                        <Legend layout='vertical' verticalAlign='top' align='center'/>
                        <Bar dataKey='count' fill={chartColors.cyan['50']} legendType='rect' name='count of trips' />
                    </BarChart>
                </ResponsiveContainer>
            </StyledRow>

        </PageMarginLeftRight>
    )
}

const StyledRow = styled.div`
    padding: ${distance.large};
    display: flex;
    flex-direction: row;
`
const StyledTopRow = styled.div`
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    padding: ${distance.large};
`