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

Commit

Permalink
Display temp & RH in graph for each station (#127)
Browse files Browse the repository at this point in the history
* Normalize actuals & model data and modify their display
* Integrate storybook into the project
* Display all forecast weather values in the graph
* Rename to "model" and "readings"
* Turn fire weather page related components to pure components
  • Loading branch information
Kyubinhan authored May 28, 2020
1 parent e0a4dbf commit 8dc6165
Show file tree
Hide file tree
Showing 34 changed files with 16,000 additions and 11,962 deletions.
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 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",
"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({
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

0 comments on commit 8dc6165

Please sign in to comment.