]> git.localhorst.tv Git - alttp.git/blob - resources/js/components/pages/Techniques.js
more alternate/canonical links
[alttp.git] / resources / js / components / pages / Techniques.js
1 import axios from 'axios';
2 import PropTypes from 'prop-types';
3 import React from 'react';
4 import { Helmet } from 'react-helmet';
5 import { withTranslation } from 'react-i18next';
6
7 import NotFound from './NotFound';
8 import CanonicalLinks from '../common/CanonicalLinks';
9 import ErrorBoundary from '../common/ErrorBoundary';
10 import ErrorMessage from '../common/ErrorMessage';
11 import Loading from '../common/Loading';
12 import Overview from '../techniques/Overview';
13 import { compareTranslation } from '../../helpers/Technique';
14 import i18n from '../../i18n';
15
16 const Techniques = ({ namespace, type }) => {
17         const [error, setError] = React.useState(null);
18         const [filter, setFilter] = React.useState({});
19         const [loading, setLoading] = React.useState(true);
20         const [techniques, setTechniques] = React.useState([]);
21
22         React.useEffect(() => {
23                 const savedFilter = localStorage.getItem(`content.filter.${type}`);
24                 if (savedFilter) {
25                         setFilter(JSON.parse(savedFilter));
26                 } else {
27                         setFilter(filter => filter ? {} : filter);
28                 }
29         }, [type]);
30
31         const updateFilter = React.useCallback(newFilter => {
32                 localStorage.setItem(`content.filter.${type}`, JSON.stringify(newFilter));
33                 setFilter(newFilter);
34         }, [type]);
35
36         React.useEffect(() => {
37                 const ctrl = new AbortController();
38                 if (!techniques.length) {
39                         setLoading(true);
40                 }
41                 axios
42                         .get(`/api/content`, {
43                                 params: {
44                                         type,
45                                         ...filter,
46                                 },
47                                 signal: ctrl.signal
48                         })
49                         .then(response => {
50                                 setError(null);
51                                 setLoading(false);
52                                 setTechniques(response.data.sort(compareTranslation('title', i18n.language)));
53                         })
54                         .catch(error => {
55                                 if (!axios.isCancel(error)) {
56                                         setError(error);
57                                         setLoading(false);
58                                         setTechniques([]);
59                                 }
60                         });
61                 return () => {
62                         ctrl.abort();
63                 };
64         }, [filter, namespace, type]);
65
66         React.useEffect(() => {
67                 setTechniques(t => [...t].sort(compareTranslation('title', i18n.language)));
68         }, [namespace, i18n.language]);
69
70         if (loading) {
71                 return <Loading />;
72         }
73
74         if (error) {
75                 return <ErrorMessage error={error} />;
76         }
77
78         if (!techniques || !techniques.length) {
79                 return <NotFound />;
80         }
81
82         return <ErrorBoundary>
83                 <Helmet>
84                         <title>{i18n.t(`${namespace}.heading`)}</title>
85                         <meta name="description" content={i18n.t(`${namespace}.description`)} />
86                 </Helmet>
87                 <CanonicalLinks base="/tech" />
88                 <Overview
89                         filter={filter}
90                         namespace={namespace}
91                         setFilter={updateFilter}
92                         techniques={techniques}
93                         type={type}
94                 />
95         </ErrorBoundary>;
96 };
97
98 Techniques.propTypes = {
99         namespace: PropTypes.string,
100         type: PropTypes.string,
101 };
102
103 export default withTranslation()(Techniques);