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 tracking multiple sets of turnip prices #125

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 16 additions & 27 deletions src/containers/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,19 @@ import React from "react";
import { CssBaseline, ThemeProvider, Container, Box } from "@material-ui/core";
import { ThemeProvider as StyledComponentsThemeProvider } from "styled-components";
import {
useFilters,
useTitle,
useTabs,
theme,
useShare,
useCalculation,
} from "../utils";
import { Title, Filter, Footer } from "../containers";
import { ShareDialog, Chart, Table } from "../components";
import { Title, Footer, IslandTabs, Calculator } from "../containers";

const App = () => {
useTitle();
const { inputFilters, filters, saveFilters } = useFilters();
const {
onCloseShareModal,
showShareDialog,
openShareDialog,
shareFilters,
} = useShare(filters);
const {tabs, addTab, deleteTab, value, handleTabChange} = useTabs();

const result = useCalculation({ filters });
const panelMarkup = tabs.map((tab, index) => (
<Calculator filterKey={tab.key} key={tab.key} value={value} index={index} />
));

return (
<ThemeProvider theme={theme}>
Expand All @@ -30,21 +23,17 @@ const App = () => {
<Container maxWidth="md">
<Title />
<Box mx={[-1.5, 0]}>
<Filter
filters={inputFilters}
onChange={saveFilters}
openShareDialog={openShareDialog}
/>
<Chart {...result} />
<Table {...result} />
<Footer />
</Box>
<IslandTabs
tabs={tabs}
value={value}
onAdd={addTab}
onDelete={deleteTab}
onChange={handleTabChange}
/>
{panelMarkup}
<Footer />
</Box>
</Container>
<ShareDialog
open={showShareDialog}
filters={shareFilters}
onClose={onCloseShareModal}
/>
</StyledComponentsThemeProvider>
</ThemeProvider>
);
Expand Down
41 changes: 41 additions & 0 deletions src/containers/Calculator.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from "react";
import PropTypes from "prop-types";
import { useFilters, useShare, useCalculation } from "../utils";
import { Filter, TabPanel } from "../containers";
import { ShareDialog, Chart, Table } from "../components";

const Calculator = ({ value, index, filterKey }) => {
const { inputFilters, filters, saveFilters } = useFilters(filterKey);
const {
onCloseShareModal,
showShareDialog,
openShareDialog,
shareFilters,
} = useShare(filters);
const result = useCalculation({ filters });

return (
<TabPanel value={value} index={index}>
<Filter
filters={inputFilters}
onChange={saveFilters}
openShareDialog={openShareDialog}
/>
<Chart {...result} />
<Table {...result} />
<ShareDialog
open={showShareDialog}
filters={shareFilters}
onClose={onCloseShareModal}
/>
</TabPanel>
);
};

Calculator.propTypes = {
value: PropTypes.number.isRequired,
index: PropTypes.number.isRequired,
filterKey: PropTypes.string.isRequired,
};

export default Calculator;
87 changes: 87 additions & 0 deletions src/containers/IslandTabs.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { makeStyles } from "@material-ui/styles";
import { Tab, Tabs } from "@material-ui/core";
import { Add, Close } from "@material-ui/icons";

const useTabsStyles = makeStyles(({ spacing }) => ({
root: {
marginLeft: spacing(2),
},
indicator: {
backgroundColor: "#18A558",
},
}));

const useTabStyles = makeStyles(({ breakpoints, spacing }) => ({
root: {
textTransform: "initial",
padding: spacing(-1, 2),
[breakpoints.up("md")]: {
minWidth: 120,
},
"&:hover": {
backgroundColor: "rgba(13, 152, 186, 0.1)",
"& .MuiTab-label": {
color: "#18A558",
},
},
"&$selected": {
"& *": {
color: "#18A558",
},
},
},
selected: {},
textColorInherit: {
opacity: 1,
},
wrapper: {
flexDirection: "row-reverse",
letterSpacing: 0.5,
'& svg, .material-icons': {
marginLeft: 12,
marginTop: 7,
},
},
}));

const IslandTabs = ({ tabs, onAdd, onDelete, onChange, value }) => {
const { t } = useTranslation()
const tabClasses = useTabStyles();
const tabsClasses = useTabsStyles();

return (
<Tabs variant="scrollable" scrollButtons="auto" value={value} onChange={onChange} classes={tabsClasses}>
{tabs.map((tab, index) => (
<Tab
key={tab.key}
label={`${t("Island")} ${tab.id + 1}`}
disableRipple
icon={value === index && <Close id={tab.id} onClick={onDelete} fontSize="small" />}
classes={{
...tabClasses,
wrapper: `${tabClasses.wrapper} MuiTab-label`,
}}
/>
))}
<Tab label={t("Add Island")} classes={tabClasses} icon={<Add onClick={onAdd} />} />
</Tabs>
);
};

IslandTabs.propTypes = {
tabs: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
key: PropTypes.string.isRequired,
}),
),
value: PropTypes.number.isRequired,
onChange: PropTypes.func.isRequired,
onAdd: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired,
};

export default IslandTabs;
24 changes: 24 additions & 0 deletions src/containers/TabPanel.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";
import PropTypes from "prop-types";

// Manual implementation of https://material-ui.com/api/tab-panel/
// TabPanel not yet available in @material-ui/core
const TabPanel = ({ value, index, children }) => {
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
>
{value === index && children}
</div>
);
};

TabPanel.propTypes = {
value: PropTypes.number.isRequired,
index: PropTypes.number.isRequired,
children: PropTypes.node,
};

export default TabPanel;
3 changes: 3 additions & 0 deletions src/containers/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export { default as App } from "./App";
export { default as IslandTabs } from "./IslandTabs";
export { default as TabPanel } from "./TabPanel";
export { default as Calculator } from "./Calculator";
export { default as Filter } from "./Filter";
export { default as Footer } from "./Footer";
export { default as Localizer } from "./Localizer";
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",
"Add Island": "Add Island",
"Island": "Island"
}
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 useTabs } from "./useTabs";
4 changes: 2 additions & 2 deletions src/utils/useFilters.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useEffect, useMemo } from "react";
import { useLocalStorage } from "react-use";

const useFilters = () => {
const [filters, saveFilters] = useLocalStorage("filters", []);
const useFilters = (key) => {
const [filters, saveFilters] = useLocalStorage(key, []);

// Array of strings
const inputFilters = useMemo(
Expand Down
79 changes: 79 additions & 0 deletions src/utils/useTabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { useState, useEffect, useCallback } from "react";
import { useLocalStorage } from "react-use";

const DEFAULT_TAB_LIST = [
{
id: 0,
key: "filters-0",
},
];

const useTabs = () => {
const [value, setValue] = useState(0);
const [tabs, saveTabs] = useLocalStorage("tablist", DEFAULT_TAB_LIST);

useEffect(() => {
if (!Array.isArray(tabs)) {
saveTabs(DEFAULT_TAB_LIST);
}
}, [tabs, saveTabs]);

const addTab = useCallback(() => {
let id = 0
for (id = 0; id < tabs.length; id++) {
if (tabs[id].id !== id) {
break;
}
}
setValue(id);
saveTabs([...tabs.slice(0, id), {
id,
key: `filters-${id}`,
}, ...tabs.slice(id)]);
}, [tabs, saveTabs]);

const deleteTab = useCallback((event) => {
// Prevent MaterialUI from switching tabs
event.stopPropagation();

// Prevent deleting the last tab
if (tabs.length === 1) {
return;
}

let deletedTabIndex = 0;
const tabId = parseInt(event.target.id, 10);

const tabList = tabs.filter((tab, index) => {
if (tab.id === tabId) {
deletedTabIndex = index;
localStorage.removeItem(tab.key);
}
return tab.id !== tabId;
});

if (deletedTabIndex !== 0) {
setValue(deletedTabIndex - 1)
}

saveTabs(tabList);
}, [tabs, saveTabs]);

const handleTabChange = useCallback((_event, newValue) => {
if (newValue === tabs.length) {
addTab();
} else {
setValue(newValue);
}
}, [tabs, addTab]);

return {
value,
tabs,
addTab,
deleteTab,
handleTabChange,
};
};

export default useTabs;