]> git.localhorst.tv Git - alttp.git/blob - resources/js/hooks/tracker.js
compact keysanity tracker
[alttp.git] / resources / js / hooks / tracker.js
1 import PropTypes from 'prop-types';
2 import React from 'react';
3
4 import {
5         CONFIG,
6         DUNGEONS,
7         applyLogic,
8         configureDungeons,
9         makeEmptyState,
10         mergeStates,
11 } from '../helpers/tracker';
12
13 const context = React.createContext({});
14
15 export const useTracker = () => React.useContext(context);
16
17 export const TrackerProvider = ({ children }) => {
18         const [config, setConfig] = React.useState(CONFIG);
19         const [state, setState] = React.useState(makeEmptyState());
20         const [autoState, setAutoState] = React.useState(makeEmptyState());
21         const [manualState, setManualState] = React.useState(makeEmptyState());
22         const [dungeons, setDungeons] = React.useState(DUNGEONS);
23         const [logic, setLogic] = React.useState({});
24         const [pins, setPins] = React.useState([]);
25
26         const saveConfig = React.useCallback((values) => {
27                 setConfig(s => {
28                         const newConfig = { ...s, ...values };
29                         localStorage.setItem('tracker.config', JSON.stringify(newConfig));
30                         return newConfig;
31                 });
32         }, []);
33
34         const addPin = React.useCallback((pin) => {
35                 setPins(ps => {
36                         const id = ps.length ? ps[ps.length - 1].id + 1 : 1;
37                         return [...ps, { ...pin, id }];
38                 });
39         }, []);
40
41         const removePin = React.useCallback((pin) => {
42                 setPins(ps => ps.filter(p => p.id !== pin.id));
43         }, []);
44
45         React.useEffect(() => {
46                 const savedConfig = localStorage.getItem('tracker.config');
47                 if (savedConfig) {
48                         setConfig(c => ({ ...c, ...JSON.parse(savedConfig) }));
49                 }
50         }, []);
51
52         React.useEffect(() => {
53                 const newDungeons = configureDungeons(config);
54                 setDungeons(newDungeons);
55         }, [config]);
56
57         React.useEffect(() => {
58                 setState(mergeStates(autoState, manualState));
59         }, [autoState, manualState]);
60
61         React.useEffect(() => {
62                 setLogic(applyLogic(config, dungeons, state));
63         }, [config, dungeons, state]);
64
65         const value = React.useMemo(() => {
66                 return {
67                         addPin,
68                         config,
69                         dungeons,
70                         logic,
71                         pins,
72                         removePin,
73                         saveConfig,
74                         setAutoState,
75                         setManualState,
76                         state,
77                 };
78         }, [config, dungeons, logic, pins, state]);
79
80         return <context.Provider value={value}>
81                 {children}
82         </context.Provider>;
83 };
84
85 TrackerProvider.propTypes = {
86         children: PropTypes.node,
87 };