Skip to content
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

Add support for rewinding the chart's prediction while viewing current data #129

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
aee92cf
start Dropdown
SHewitt95 May 26, 2020
f5c5ff1
add useChartReducer
SHewitt95 May 26, 2020
05e5bee
start StatefulChart
SHewitt95 May 26, 2020
e855885
reduce the reducer
SHewitt95 May 26, 2020
7b6f442
move StatefulChart into Chart
SHewitt95 May 26, 2020
2e3fb77
swap filters based on if rewind is enabled
SHewitt95 May 26, 2020
6782f18
more work on Dropdown
SHewitt95 May 26, 2020
8273aae
use dispatch, useWeekDays, built-out Dropdown
SHewitt95 May 26, 2020
305a37b
build out useChartReducer
SHewitt95 May 26, 2020
eacad84
remove StatefulChart
SHewitt95 May 26, 2020
ecf14d3
delete console.log
SHewitt95 May 26, 2020
b91526c
remove last remnants of StatefulChart, adjust Dropdown values
SHewitt95 May 26, 2020
f33f3a8
remove loose state
SHewitt95 May 26, 2020
5cba001
add prop-types to dropdown
SHewitt95 May 26, 2020
bd3626d
clean up useChartReducer
SHewitt95 May 26, 2020
6c15b63
move Dropdown, add Box styling
SHewitt95 May 26, 2020
2d434b8
add FormControl, styles
SHewitt95 May 26, 2020
3fec315
move logic to hook
SHewitt95 May 26, 2020
d24e479
rename to useTimeTravel
SHewitt95 May 26, 2020
66d6f7d
destructure state
SHewitt95 May 26, 2020
6d679cc
add TimeTravelDropdown
SHewitt95 May 27, 2020
180aaf0
only show days with values
SHewitt95 May 27, 2020
be5df67
change name in hook
SHewitt95 May 27, 2020
3e2d385
spread initialState
SHewitt95 May 27, 2020
c7d89ea
resetTimeTravel
SHewitt95 May 27, 2020
d658ff1
change wording
SHewitt95 May 27, 2020
df91105
add translations
SHewitt95 May 27, 2020
ed71b1a
fix uncontrolled component error
SHewitt95 May 27, 2020
12fdd82
add comment
SHewitt95 May 27, 2020
764573c
return state
SHewitt95 May 27, 2020
5555b6a
whoops, return initialState
SHewitt95 May 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions src/components/Dropdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import React from "react";
import {
Select,
MenuItem,
InputLabel,
FormControl,
FormHelperText,
makeStyles,
} from "@material-ui/core";
import {
string,
arrayOf,
shape,
number,
func,
bool,
oneOfType,
} from "prop-types";
import { useTranslation } from "react-i18next";
import { useWeekDays } from "../utils/";

const useDropdownStyles = makeStyles({
formControl: {
width: "100%",
maxWidth: "575px",
},
});

const Dropdown = ({
menuItems,
onChange,
label,
labelId,
selectId,
helperText,
disabled,
value,
}) => (
<FormControl className={useDropdownStyles().formControl} disabled={disabled}>
<InputLabel id={labelId}>{label}</InputLabel>
<Select value={value} labelId={labelId} id={selectId} onChange={onChange}>
<MenuItem value="">
<em>Clear Selection</em>
</MenuItem>
{menuItems.map((item) => {
if (!item) return null;
return (
<MenuItem value={item.value} key={item.value}>
{item.text}
</MenuItem>
);
})}
</Select>
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
);

Dropdown.propTypes = {
menuItems: arrayOf(
shape({
text: string,
value: number,
})
).isRequired,
onChange: func,
label: string,
labelId: string,
selectId: string,
helperText: string,
disabled: bool,
value: oneOfType([number, string]),
};

Dropdown.defaults = {
onChange: () => {},
label: "",
labelId: "",
selectId: "",
helperText: "",
disabled: false,
value: "",
};

export const TimeTravelDropdown = ({ filters, dispatch }) => {
const [value, setValue] = React.useState("");
const { weekDaysCombined } = useWeekDays();
const { t } = useTranslation();

return (
<Dropdown
value={value}
label={t("Rewind to a day and time")}
labelId="rewind-label"
selectId="rewind-select"
helperText={t(
"Use this dropdown to see how the chart evolved as you filled out the prices above."
)}
menuItems={weekDaysCombined.map((weekday, idx) => {
const indexInFilters = idx + 1;

if (!filters[indexInFilters]) {
// Ignore values left blank by the user
return null;
}

return {
text: weekday,
value: indexInFilters,
};
})}
onChange={(e) => {
const { value } = e.target;
setValue(value);
dispatch({
payload: {
rewindEnabled: typeof value === "number",
indexInHistory: value,
filters,
},
});
}}
/>
);
};

export default Dropdown;
1 change: 1 addition & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { Button, ClearButton, useButtonStyles } from "./Button";
export { default as Chart } from "./Chart";
export { Dialog, ClearDataDialog, ShareDialog } from "./Dialog";
export { default as Table } from "./Table";
export { default as Dropdown, TimeTravelDropdown } from "./Dropdown";
21 changes: 11 additions & 10 deletions src/containers/App.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import React from "react";
import { CssBaseline, ThemeProvider, Container, Box } from "@material-ui/core";
import { ThemeProvider as StyledComponentsThemeProvider } from "styled-components";
import {
useFilters,
useTitle,
theme,
useShare,
useCalculation,
} from "../utils";
import { useFilters, useTitle, theme, useShare, useTimeTravel } from "../utils";
import { Title, Filter, Footer } from "../containers";
import { ShareDialog, Chart, Table } from "../components";
import { ShareDialog, Table, TimeTravelDropdown, Chart } from "../components";

const App = () => {
useTitle();
Expand All @@ -21,7 +15,11 @@ const App = () => {
shareFilters,
} = useShare(filters);

const result = useCalculation({ filters });
const [dispatch, result] = useTimeTravel(filters);
const resetTimeTravel = (array) => {
saveFilters(array);
dispatch({ payload: { rewindEnabled: false } });
};

return (
<ThemeProvider theme={theme}>
Expand All @@ -32,9 +30,12 @@ const App = () => {
<Box mx={[-1.5, 0]}>
<Filter
filters={inputFilters}
onChange={saveFilters}
onChange={resetTimeTravel}
openShareDialog={openShareDialog}
/>
<Box p={[0.5, 1, 2]} mt={2}>
<TimeTravelDropdown filters={filters} dispatch={dispatch} />
</Box>
<Chart {...result} />
<Table {...result} />
<Footer />
Expand Down
4 changes: 3 additions & 1 deletion src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@
"Chance": "Chance",
"Pattern": "Pattern",
"patternNames": "Fluctuating_High Spike_Decreasing_Small Spike",
"All Patterns": "All Patterns"
"All Patterns": "All Patterns",
"Rewind to a day and time": "Rewind to a day and time",
"Use this dropdown to see how the chart evolved as you filled out the prices above.": "Use this dropdown to see how the chart evolved as you filled out the prices above."
}
1 change: 1 addition & 0 deletions src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { default as useShare } from "./useShare";
export { default as useTitle } from "./useTitle";
export { default as useWeekDays } from "./useWeekDays";
export { default as useCalculation } from "./useCalculation";
export { default as useTimeTravel } from "./useTimeTravel";
49 changes: 49 additions & 0 deletions src/utils/useTimeTravel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useReducer } from "react";
import { useCalculation } from "./index";

const initialState = {
rewindEnabled: false,
rewindFilters: [],
};

const reducer = (state = initialState, action) => {
const { rewindEnabled, filters, indexInHistory } = action.payload;
if (rewindEnabled) {
return {
...state,
rewindEnabled,
rewindFilters: filters.map((filter, idx) => {
if (idx > indexInHistory) {
// Ignore values beyond the selected point in history
return null;
}
return filter;
}),
};
}

return initialState;
};

const useTimeTravel = (filters) => {
const [{ rewindEnabled, rewindFilters }, dispatch] = useReducer(
reducer,
initialState
);

// Get prediction/minMax values based on rewindFilters
// if rewindEnabled is true
const calcInput = rewindEnabled ? rewindFilters : filters;
const result = useCalculation({ filters: calcInput });

if (rewindEnabled) {
// Draw "Daily Price" based on the user's actual input.
// This allows the user to see their actual turnip prices graphed
// compared to past projections as they evolved.
result.filters = filters;
}

return [dispatch, result];
};

export default useTimeTravel;