Skip to content
This repository has been archived by the owner on Dec 9, 2020. It is now read-only.

Display temp & RH in graph for each station #127

Merged
merged 13 commits into from
May 28, 2020
Merged
2 changes: 2 additions & 0 deletions .storybook/addons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import '@storybook/addon-actions/register'
import '@storybook/addon-knobs/register'
12 changes: 12 additions & 0 deletions .storybook/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { configure, addDecorator } from '@storybook/react'
import { ThemeDecorator } from './decorators/ThemeDecorator'

const req = require.context('../src', true, /\.stories\.tsx$/)

function loadStories() {
req.keys().forEach(req)
}

addDecorator(ThemeDecorator)

configure(loadStories, module)
8 changes: 8 additions & 0 deletions .storybook/decorators/ThemeDecorator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react'
import { ThemeProvider } from '@material-ui/core/styles'

import { theme } from '../../src/app/theme'

export const ThemeDecorator = storyFn => (
<ThemeProvider theme={theme}>{storyFn()}</ThemeProvider>
)
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ WORKDIR /app
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./

## Install only the packages defined in the package-lock.json (faster than the normal npm install)
RUN npm set progress=false && npm ci --production
# Install all the dependencies to run the application in development mode
RUN npm set progress=false && npm ci --no-cache
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we rather want?

Suggested change
RUN npm set progress=false && npm ci --no-cache
RUN npm set progress=false && npm ci --no-cache --production


# Copy the contents of the project to the image
COPY . .
Expand Down
26,010 changes: 14,556 additions & 11,454 deletions package-lock.json

Large diffs are not rendered by default.

21 changes: 14 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,35 @@
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.43",
"@reduxjs/toolkit": "^1.2.5",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.4.0",
"@testing-library/user-event": "^7.2.1",
"@types/node": "^12.12.26",
"@types/react": "^16.9.19",
"@types/react-dom": "^16.9.5",
"@types/react-redux": "^7.1.7",
"@types/react-router-dom": "^5.1.3",
"@types/webpack-env": "^1.15.1",
"@types/recharts": "^1.8.10",
"axios": "^0.19.2",
"clsx": "^1.1.0",
"moment": "^2.26.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-redux": "^7.2.0",
"react-router-dom": "^5.1.2",
"react-scripts": "3.4.0",
"react-scripts": "3.4.1",
"recharts": "^1.8.5",
"typescript": "^3.7.5"
},
"scripts": {
"start": "react-scripts start",
"start": "CI=true react-scripts start",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the CI=true do?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly sure what it does but it fixes the issue where it fails to start in the docker container.
facebook/create-react-app#8688 (comment)

"build": "react-scripts build",
"test": "DEBUG_PRINT_LIMIT=5000 react-scripts test",
"test:ci": "CI=true npm test",
"eject": "react-scripts eject",
"lint": "eslint './src/**/*.{ts,tsx}'",
"lint:fix": "eslint --fix './src/**/*.{ts,tsx}'",
"format": "prettier --write \"**/*.+(js|jsx|json|yml|yaml|css|md)\""
"format": "prettier --write \"**/*.+(js|jsx|json|yml|yaml|css|md)\"",
"storybook": "start-storybook -p 9009 -s public",
"build-storybook": "build-storybook -s public"
},
"browserslist": {
"production": [
Expand All @@ -59,6 +60,12 @@
]
},
"devDependencies": {
"@storybook/addon-actions": "^5.3.19",
"@storybook/addon-knobs": "^5.3.19",
"@storybook/react": "^5.3.19",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.4.0",
"@testing-library/user-event": "^7.2.1",
"@types/jest": "^24.9.1",
"@typescript-eslint/eslint-plugin": "^2.19.0",
"@typescript-eslint/parser": "^2.19.0",
Expand All @@ -74,4 +81,4 @@
"pre-push": ".githooks/pre-push & npm run lint & npm run test:ci"
}
}
}
}
14 changes: 7 additions & 7 deletions src/api/forecastAPI.ts → src/api/modelAPI.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'api/axios'
import { Station } from 'api/stationAPI'

interface WxValue {
export interface ModelValue {
datetime: string
temperature: number
relative_humidity: number
Expand All @@ -26,20 +26,20 @@ interface WxValue {
wind_direction_850m: number
}

export interface Forecast {
export interface Model {
station: Station
values: WxValue[]
values: ModelValue[]
}

export interface ForecastsResponse {
forecasts: Forecast[]
export interface ModelsResponse {
forecasts: Model[]
}

export async function getForecasts(stationCodes: number[]): Promise<Forecast[]> {
export async function getModels(stationCodes: number[]): Promise<Model[]> {
const url = '/forecasts/'

try {
const { data } = await axios.post<ForecastsResponse>(url, {
const { data } = await axios.post<ModelsResponse>(url, {
stations: stationCodes
})
return data.forecasts
Expand Down
14 changes: 7 additions & 7 deletions src/api/hourliesAPI.ts → src/api/readingAPI.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Station } from 'api/stationAPI'
import axios from 'api/axios'

interface HourlyReading {
export interface ReadingValue {
datetime: string
temperature: number
relative_humidity: number
Expand All @@ -14,20 +14,20 @@ interface HourlyReading {
fwi?: number
}

export interface HourlyReadings {
export interface Reading {
station: Station
values: HourlyReading[]
values: ReadingValue[]
}

export interface HourliesResponse {
hourlies: HourlyReadings[]
export interface ReadingsResponse {
hourlies: Reading[]
}

export async function getHourlies(stationCodes: number[]): Promise<HourlyReadings[]> {
export async function getReadings(stationCodes: number[]): Promise<Reading[]> {
const url = '/hourlies/'

try {
const { data } = await axios.post<HourliesResponse>(url, {
const { data } = await axios.post<ReadingsResponse>(url, {
stations: stationCodes
})
return data.hourlies
Expand Down
40 changes: 2 additions & 38 deletions src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,9 @@
import React from 'react'
import { CssBaseline } from '@material-ui/core'
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'
import { ThemeProvider } from '@material-ui/core/styles'

import { Routes } from 'app/Routes'

// Theme documentation: https://material-ui.com/customization/palette/
// Theme demo: https://material.io/resources/color/#!/?view.left=1&view.right=1&primary.color=003365&secondary.color=FBC02D
// Do not export this! theme can be accessed within makeStyles & withStyles. Use ErrorMessage.tsx as a reference
const theme = createMuiTheme({
palette: {
primary: {
light: '#3E5C93',
main: '#003365',
dark: '#000C3A'
},
secondary: {
light: '#FFF263',
main: '#FBC02D',
dark: '#C49000'
},
success: { main: '#44D77A' },
error: { main: '#FF3E34' },
warning: { main: '#FE7921' },
contrastThreshold: 3,
tonalOffset: 0.1
},
typography: {
button: {
textTransform: 'none'
}
},
breakpoints: {
values: {
xs: 0,
sm: 600,
md: 1080, // Default: 960
lg: 1280,
xl: 1920
}
}
})
import { theme } from 'app/theme'

const App = () => {
return (
Expand Down
4 changes: 2 additions & 2 deletions src/app/Routes.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'

import { DailyForecastsPage } from 'features/dailyForecasts/DailyForecastsPage'
import FireWeatherPage from 'features/fireWeather/pages/FireWeatherPage'
import { PercentileCalculatorPageWithDisclaimer } from 'features/percentileCalculator/pages/PercentileCalculatorPageWithDisclaimer'
import { HIDE_DISCLAIMER } from 'utils/constants'

Expand All @@ -20,7 +20,7 @@ export const Routes = () => {
</Route>

<Route path="/fire-weather/">
<DailyForecastsPage />
<FireWeatherPage />
</Route>

<Route>
Expand Down
12 changes: 6 additions & 6 deletions src/app/rootReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { combineReducers } from '@reduxjs/toolkit'
import stationsReducer from 'features/stations/slices/stationsSlice'
import percentilesReducer from 'features/percentileCalculator/slices/percentilesSlice'
import authReducer from 'features/auth/slices/authenticationSlice'
import forecastsReducer from 'features/dailyForecasts/slices/ForecastsSlice'
import hourliesReducer from 'features/hourlies/slices/HourliesSlice'
import modelsReducer from 'features/fireWeather/slices/modelsSlice'
import readingsReducer from 'features/fireWeather/slices/readingsSlice'

const rootReducer = combineReducers({
stations: stationsReducer,
percentiles: percentilesReducer,
authentication: authReducer,
forecasts: forecastsReducer,
hourlies: hourliesReducer
models: modelsReducer,
readings: readingsReducer
})

// Infer whatever gets returned from rootReducer and use it as the type of the root state
Expand All @@ -23,5 +23,5 @@ export const selectStations = (state: RootState) => state.stations
export const selectPercentiles = (state: RootState) => state.percentiles
export const selectAuthentication = (state: RootState) => state.authentication
export const selectToken = (state: RootState) => state.authentication.token
export const selectForecasts = (state: RootState) => state.forecasts
export const selectHourlies = (state: RootState) => state.hourlies
export const selectModels = (state: RootState) => state.models
export const selectReadings = (state: RootState) => state.readings
38 changes: 38 additions & 0 deletions src/app/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createMuiTheme } from '@material-ui/core/styles'

// Theme documentation: https://material-ui.com/customization/palette/
// Theme demo: https://material.io/resources/color/#!/?view.left=1&view.right=1&primary.color=003365&secondary.color=FBC02D
// Do not export this directly for styling! theme should be accessed within makeStyles & withStyles. Use ErrorMessage.tsx as a reference
export const theme = createMuiTheme({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says not to export?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I had to make it exportable so that I can use the same theme in Storybook .storybook/decorators/ThemeDecorator.tsx. I will change the wording to Do not export this directly for styling!

palette: {
primary: {
light: '#3E5C93',
main: '#003365',
dark: '#000C3A'
},
secondary: {
light: '#FFF263',
main: '#FBC02D',
dark: '#C49000'
},
success: { main: '#44D77A' },
error: { main: '#FF3E34' },
warning: { main: '#FE7921' },
contrastThreshold: 3,
tonalOffset: 0.1
},
typography: {
button: {
textTransform: 'none'
}
},
breakpoints: {
values: {
xs: 0,
sm: 600,
md: 1080, // Default: 960
lg: 1280,
xl: 1920
}
}
})
36 changes: 36 additions & 0 deletions src/components/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import { withKnobs, select } from '@storybook/addon-knobs'

import { Button } from 'components'

storiesOf('Button', module)
.addDecorator(withKnobs)
.add('collections', () => {
const style = { margin: 10 }
const color = select(
'color',
{ Primary: 'primary', Secondary: 'secondary', Default: 'default' },
'primary'
)

return (
<>
<Button
color={color}
variant="contained"
style={style}
onClick={action('clicked')}
>
Button
</Button>
<Button color={color} variant="contained" style={style} loading>
Button
</Button>
<Button color={color} variant="contained" style={style} disabled>
Button
</Button>
</>
)
})
6 changes: 3 additions & 3 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ const useStyles = makeStyles(theme => ({
}
}))

export const Button = ({ loading, ...buttonProps }: Props) => {
export const Button = ({ loading, className, disabled, ...buttonProps }: Props) => {
const classes = useStyles()
const buttonClassName = clsx(classes.root, buttonProps.className)
const buttonClassName = clsx(classes.root, className)

return (
<B className={buttonClassName} {...buttonProps}>
<B {...buttonProps} className={buttonClassName} disabled={disabled || loading}>
{buttonProps.children}
{loading && <CircularProgress size={24} className={classes.spinner} />}
</B>
Expand Down
6 changes: 3 additions & 3 deletions src/features/auth/slices/authenticationSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const initialState: State = {
error: null
}

const auth = createSlice({
const authSlice = createSlice({
name: 'authentication',
initialState,
reducers: {
Expand Down Expand Up @@ -62,9 +62,9 @@ export const {
authenticateFinished,
authenticateError,
refreshTokenFinished
} = auth.actions
} = authSlice.actions

export default auth.reducer
export default authSlice.reducer

export const authenticate = (): AppThunk => dispatch => {
dispatch(authenticateStart())
Expand Down
Loading