]> git.localhorst.tv Git - alttp.git/blobdiff - resources/js/pages/Techniques.js
improved directory structure
[alttp.git] / resources / js / pages / Techniques.js
diff --git a/resources/js/pages/Techniques.js b/resources/js/pages/Techniques.js
new file mode 100644 (file)
index 0000000..0c5d5b0
--- /dev/null
@@ -0,0 +1,100 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Helmet } from 'react-helmet';
+import { withTranslation } from 'react-i18next';
+
+import NotFound from './NotFound';
+import CanonicalLinks from '../components/common/CanonicalLinks';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import ErrorMessage from '../components/common/ErrorMessage';
+import Loading from '../components/common/Loading';
+import Overview from '../components/techniques/Overview';
+import { compareTranslation } from '../helpers/Technique';
+import i18n from '../i18n';
+
+const Techniques = ({ namespace, type }) => {
+       const [error, setError] = React.useState(null);
+       const [filter, setFilter] = React.useState({});
+       const [loading, setLoading] = React.useState(true);
+       const [techniques, setTechniques] = React.useState([]);
+
+       React.useEffect(() => {
+               const savedFilter = localStorage.getItem(`content.filter.${type}`);
+               if (savedFilter) {
+                       setFilter(JSON.parse(savedFilter));
+               } else {
+                       setFilter(filter => filter ? {} : filter);
+               }
+       }, [type]);
+
+       const updateFilter = React.useCallback(newFilter => {
+               localStorage.setItem(`content.filter.${type}`, JSON.stringify(newFilter));
+               setFilter(newFilter);
+       }, [type]);
+
+       React.useEffect(() => {
+               const ctrl = new AbortController();
+               if (!techniques.length) {
+                       setLoading(true);
+               }
+               axios
+                       .get(`/api/pages/${type}`, {
+                               params: filter,
+                               signal: ctrl.signal
+                       })
+                       .then(response => {
+                               setError(null);
+                               setLoading(false);
+                               setTechniques(response.data.sort(compareTranslation('title', i18n.language)));
+                       })
+                       .catch(error => {
+                               if (!axios.isCancel(error)) {
+                                       setError(error);
+                                       setLoading(false);
+                                       setTechniques([]);
+                               }
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [filter, namespace, type]);
+
+       React.useEffect(() => {
+               setTechniques(t => [...t].sort(compareTranslation('title', i18n.language)));
+       }, [namespace, i18n.language]);
+
+       if (loading) {
+               return <Loading />;
+       }
+
+       if (error) {
+               return <ErrorMessage error={error} />;
+       }
+
+       if (!techniques || !techniques.length) {
+               return <NotFound />;
+       }
+
+       return <ErrorBoundary>
+               <Helmet>
+                       <title>{i18n.t(`${namespace}.heading`)}</title>
+                       <meta name="description" content={i18n.t(`${namespace}.description`)} />
+               </Helmet>
+               <CanonicalLinks base="/tech" />
+               <Overview
+                       filter={filter}
+                       namespace={namespace}
+                       setFilter={updateFilter}
+                       techniques={techniques}
+                       type={type}
+               />
+       </ErrorBoundary>;
+};
+
+Techniques.propTypes = {
+       namespace: PropTypes.string,
+       type: PropTypes.string,
+};
+
+export default withTranslation()(Techniques);