1 import axios from 'axios';
2 import PropTypes from 'prop-types';
3 import React, { useEffect, useState } from 'react';
4 import { Helmet } from 'react-helmet';
5 import { withTranslation } from 'react-i18next';
6 import { useParams } from 'react-router-dom';
7 import toastr from 'toastr';
9 import CanonicalLinks from '../components/common/CanonicalLinks';
10 import ErrorBoundary from '../components/common/ErrorBoundary';
11 import ErrorMessage from '../components/common/ErrorMessage';
12 import Loading from '../components/common/Loading';
13 import NotFound from '../pages/NotFound';
14 import Detail from '../components/techniques/Detail';
15 import Dialog from '../components/techniques/Dialog';
18 } from '../helpers/permissions';
19 import { getLanguages, getMatchedLocale, getTranslation } from '../helpers/Technique';
20 import { useUser } from '../hooks/user';
21 import i18n from '../i18n';
23 const Technique = ({ basepath, type }) => {
24 const params = useParams();
25 const { name } = params;
26 const { user } = useUser();
28 const [error, setError] = useState(null);
29 const [loading, setLoading] = useState(true);
30 const [technique, setTechnique] = useState(null);
32 const [editContent, setEditContent] = useState(null);
33 const [showContentDialog, setShowContentDialog] = useState(false);
35 const actions = React.useMemo(() => ({
36 editContent: mayEditContent(user) ? content => {
37 setEditContent(content);
38 setShowContentDialog(true);
42 const saveContent = React.useCallback(async values => {
44 const response = await axios.put(`/api/content/${values.id}`, {
45 parent_id: technique.id,
48 toastr.success(i18n.t('content.saveSuccess'));
49 setTechnique(response.data);
50 setShowContentDialog(false);
52 toastr.error(i18n.t('content.saveError'));
54 }, [technique && technique.id]);
57 const ctrl = new AbortController();
60 .get(`/api/pages/${type}/${name}`, { signal: ctrl.signal })
64 setTechnique(response.data);
81 return <ErrorMessage error={error} />;
88 return <ErrorBoundary>
90 <title>{getTranslation(technique, 'title', i18n.language)}</title>
91 <meta name="description" content={getTranslation(technique, 'short', i18n.language)} />
93 {technique.image ? <Helmet>
94 <meta property="og:image" content={technique.image} />
95 <meta property="twitter:image" content={technique.image} />
97 {!technique.image && technique.gif ? <Helmet>
98 <meta property="og:image" content={technique.gif} />
99 <meta property="twitter:image" content={technique.gif} />
102 base={`/${basepath}/${technique.name}`}
103 lang={getMatchedLocale(technique, i18n.language)}
104 langs={getLanguages(technique)}
106 <Detail actions={actions} technique={technique} />
108 content={editContent}
109 language={i18n.language}
110 onHide={() => { setShowContentDialog(false); }}
111 onSubmit={saveContent}
112 show={showContentDialog}
117 Technique.propTypes = {
118 basepath: PropTypes.string,
119 type: PropTypes.string,
122 export default withTranslation()(Technique);