react-admin-base-bootstrap 0.5.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/Components/BootstrapDataTable.d.ts +0 -1
- package/lib/esm/Components/BootstrapDataTable.js +5 -5
- package/lib/esm/Components/BootstrapPagination.d.ts +0 -1
- package/lib/esm/Components/BootstrapPagination.js +4 -4
- package/lib/esm/Components/CRUD.js +23 -7
- package/lib/esm/Components/CheckBox.d.ts +0 -1
- package/lib/esm/Components/EntityEditor.js +1 -1
- package/lib/esm/Components/ExcelExportButton.d.ts +0 -1
- package/lib/esm/Components/ExternalLoginButton.d.ts +0 -1
- package/lib/esm/Components/ImagePicker.d.ts +0 -1
- package/lib/esm/Components/LanguageProvider.d.ts +0 -1
- package/lib/esm/Components/LoadingButton.d.ts +0 -1
- package/lib/esm/Components/MenuState.js +17 -9
- package/lib/esm/Components/ThemeProvider.d.ts +0 -1
- package/lib/esm/Components/Validator.d.ts +0 -1
- package/package.json +12 -15
- package/src/Components/BootstrapDataTable.tsx +4 -5
- package/src/Components/BootstrapPagination.tsx +4 -4
- package/src/Components/CRUD.tsx +13 -7
- package/src/Components/EntityEditor.tsx +2 -1
- package/src/Components/MenuState.tsx +21 -9
- package/tsconfig.json +2 -1
|
@@ -114,10 +114,10 @@ export default function BootstrapTable({ url, bordered, noStrip, defaultParams,
|
|
|
114
114
|
React.createElement(CardHeader, null,
|
|
115
115
|
React.createElement(Row, null,
|
|
116
116
|
add && React.createElement(Col, { xs: "12", md: "2" },
|
|
117
|
-
React.createElement(Link, { to: add, className: "btn btn-primary font-xl
|
|
117
|
+
React.createElement(Link, { to: add, className: "btn btn-primary font-xl d-block" },
|
|
118
118
|
React.createElement("i", { className: "fa fa-plus" }))),
|
|
119
119
|
React.createElement(Col, { md: "2" },
|
|
120
|
-
React.createElement(Input, { type: "select",
|
|
120
|
+
React.createElement(Input, { type: "select", value: itemPerPage.toString(), onChange: a => setItemPerPage(+a.currentTarget.value) },
|
|
121
121
|
React.createElement("option", { value: "1" }, "1"),
|
|
122
122
|
React.createElement("option", { value: "20" }, "20"),
|
|
123
123
|
React.createElement("option", { value: "50" }, "50"),
|
|
@@ -127,10 +127,10 @@ export default function BootstrapTable({ url, bordered, noStrip, defaultParams,
|
|
|
127
127
|
React.createElement("option", { value: "-1" }, intl.formatMessage({ id: "ALL" })))),
|
|
128
128
|
children[2],
|
|
129
129
|
React.createElement(Col, { md: "3", className: "ms-auto" },
|
|
130
|
-
React.createElement(Input, { placeholder: intl.formatMessage({ id: "SEARCH" }), type: "text", value: params.query || '',
|
|
130
|
+
React.createElement(Input, { placeholder: intl.formatMessage({ id: "SEARCH" }), type: "text", value: params.query || '', onChange: e => setParams(Object.assign(Object.assign({}, params), { query: e.currentTarget.value })) })))),
|
|
131
131
|
data === null ? React.createElement(Alert, { className: "text-center mb-0 mx-3 ", color: "warning" },
|
|
132
|
-
React.createElement("i", { className: "fas fa-spinner fa-
|
|
133
|
-
React.createElement("i", { className: "far fa-times-circle
|
|
132
|
+
React.createElement("i", { className: "fas fa-spinner fa-spin" })) : !data.length ? React.createElement(Alert, { className: "text-center mx-3", color: "danger" },
|
|
133
|
+
React.createElement("i", { className: "far fa-times-circle" }),
|
|
134
134
|
" ",
|
|
135
135
|
React.createElement(FormattedMessage, { id: "NO_DATA_IS_AVAILABLE" })) : React.createElement(Table, { hover: true, bordered: bordered, striped: !noStrip, responsive: true, size: "md", className: "mb-0 dataTable" },
|
|
136
136
|
children[0],
|
|
@@ -6,8 +6,8 @@ export default function BootstrapPagination({ className, currentPage, pageCount,
|
|
|
6
6
|
return null;
|
|
7
7
|
return React.createElement(Pagination, { listClassName: "mb-0", className: className },
|
|
8
8
|
React.createElement(PaginatorCore, { activePage: currentPage, pageCount: pageCount, showPages: 15, prevPage: index => React.createElement(PaginationItem, { onClick: () => onPageChange(index) },
|
|
9
|
-
React.createElement(PaginationLink, { previous: true, tag: "button" }, "\u00AB")), page: index => React.createElement(PaginationItem, { key: index, active: currentPage === index },
|
|
10
|
-
React.createElement(PaginationLink, { tag: "button", onClick: () => onPageChange(index) }, index)), nextPage: index => React.createElement(PaginationItem, { onClick: () => onPageChange(index) },
|
|
11
|
-
React.createElement(PaginationLink, { next: true, tag: "button" }, "\u00BB")), dots: index => React.createElement(PaginationItem, { onClick: () => onPageChange(index), active: currentPage === index },
|
|
12
|
-
React.createElement(PaginationLink, { tag: "button" }, index)) }));
|
|
9
|
+
React.createElement(PaginationLink, { previous: true, tag: "button", type: "button" }, "\u00AB")), page: index => React.createElement(PaginationItem, { key: index, active: currentPage === index },
|
|
10
|
+
React.createElement(PaginationLink, { tag: "button", type: "button", onClick: () => onPageChange(index) }, index)), nextPage: index => React.createElement(PaginationItem, { onClick: () => onPageChange(index) },
|
|
11
|
+
React.createElement(PaginationLink, { next: true, tag: "button", type: "button" }, "\u00BB")), dots: index => React.createElement(PaginationItem, { onClick: () => onPageChange(index), active: currentPage === index },
|
|
12
|
+
React.createElement(PaginationLink, { tag: "button", type: "button" }, index)) }));
|
|
13
13
|
}
|
|
@@ -7,10 +7,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
11
|
+
var t = {};
|
|
12
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
13
|
+
t[p] = s[p];
|
|
14
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
15
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
16
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
17
|
+
t[p[i]] = s[p[i]];
|
|
18
|
+
}
|
|
19
|
+
return t;
|
|
20
|
+
};
|
|
10
21
|
import React, { useCallback, useContext, useRef, useState } from 'react';
|
|
11
22
|
import { ValidatorProvider } from "react-admin-base";
|
|
12
23
|
import { FormattedMessage } from 'react-intl';
|
|
13
|
-
import {
|
|
24
|
+
import { Navigate, Routes, useParams, Route } from 'react-router-dom';
|
|
14
25
|
import { Alert, Button, Col, Form, Modal, ModalFooter, ModalHeader, Row } from "reactstrap";
|
|
15
26
|
import LoadingButton from '../Components/LoadingButton';
|
|
16
27
|
import BootstrapDataTable, { Actions } from './BootstrapDataTable';
|
|
@@ -47,7 +58,7 @@ export function ModalEntityEditor({ entity, title, size, url, onReload, disabled
|
|
|
47
58
|
});
|
|
48
59
|
}, [save, saved, error, onReload, url]);
|
|
49
60
|
return React.createElement(React.Fragment, null,
|
|
50
|
-
(saved || !open) && url && React.createElement(
|
|
61
|
+
(saved || !open) && url && React.createElement(Navigate, { to: url, replace: true }),
|
|
51
62
|
React.createElement(Modal, { isOpen: true, size: size, toggle: () => url ? setOpen(false) : onReload(null), fade: false },
|
|
52
63
|
title && React.createElement(ModalHeader, { toggle: () => url ? setOpen(false) : onReload(null) },
|
|
53
64
|
React.createElement("b", null, title)),
|
|
@@ -73,9 +84,14 @@ export function CRUDActions({ id, edit, del, children }) {
|
|
|
73
84
|
const url = useContext(UrlContext);
|
|
74
85
|
return React.createElement(Actions, { edit: edit && (url + "/" + id + "/edit"), del: del }, children);
|
|
75
86
|
}
|
|
87
|
+
function ComponentWrapper(_a) {
|
|
88
|
+
var { Component } = _a, props = __rest(_a, ["Component"]);
|
|
89
|
+
const { id } = useParams();
|
|
90
|
+
return React.createElement(Component, Object.assign({}, props, { id: id }));
|
|
91
|
+
}
|
|
76
92
|
export default function CRUD(props) {
|
|
77
93
|
const ref = useRef(null);
|
|
78
|
-
const {
|
|
94
|
+
const { url, apiUrl, Component, defaultParams, noAdd } = props;
|
|
79
95
|
var reload = useCallback(function () {
|
|
80
96
|
return __awaiter(this, void 0, void 0, function* () {
|
|
81
97
|
if (ref.current) {
|
|
@@ -84,8 +100,8 @@ export default function CRUD(props) {
|
|
|
84
100
|
});
|
|
85
101
|
}, [ref]);
|
|
86
102
|
return React.createElement(UrlContext.Provider, { value: url },
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
React.createElement(BootstrapDataTable, Object.assign({ innerRef: ref, add: !noAdd &&
|
|
103
|
+
React.createElement(Routes, null,
|
|
104
|
+
!noAdd && React.createElement(Route, { path: "create", element: React.createElement(ComponentWrapper, Object.assign({ Component: Component, url: url, onReload: reload }, (defaultParams || {}))) }),
|
|
105
|
+
React.createElement(Route, { path: ":id/edit", element: React.createElement(ComponentWrapper, Object.assign({ Component: Component, url: url, onReload: reload }, (defaultParams || {}))) })),
|
|
106
|
+
React.createElement(BootstrapDataTable, Object.assign({ innerRef: ref, add: !noAdd && "create" }, props, { url: apiUrl || url })));
|
|
91
107
|
}
|
|
@@ -14,7 +14,7 @@ import { Alert, Form } from 'reactstrap';
|
|
|
14
14
|
import LoadingButton from "../Components/LoadingButton";
|
|
15
15
|
import { ValidationErrors } from './Validator';
|
|
16
16
|
export default function EntityEditor({ entity, disabled, children, onSave, saveButtonClassName, saveButtonText }) {
|
|
17
|
-
const [
|
|
17
|
+
const [data, _2, save, loading] = entity;
|
|
18
18
|
const [saved, setSaved] = useState(false);
|
|
19
19
|
const [error, setError] = useState(false);
|
|
20
20
|
const onSubmit = useCallback(function (e) {
|
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
import { useEffect, useReducer } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useReducer, useRef } from 'react';
|
|
2
2
|
import { useMediaQuery } from 'react-responsive';
|
|
3
|
-
import {
|
|
3
|
+
import { useLocation } from "react-router-dom";
|
|
4
4
|
export function useIsMobile() {
|
|
5
5
|
return useMediaQuery({ query: '(max-width: 992px)' });
|
|
6
6
|
}
|
|
7
|
+
const useOnLocationChange = (handleLocationChange) => {
|
|
8
|
+
const location = useLocation();
|
|
9
|
+
const locationRef = useRef("");
|
|
10
|
+
useEffect(function () {
|
|
11
|
+
if (locationRef.current != location.pathname) {
|
|
12
|
+
handleLocationChange(location);
|
|
13
|
+
locationRef.current = location.pathname;
|
|
14
|
+
}
|
|
15
|
+
}, [location.pathname, locationRef, handleLocationChange]);
|
|
16
|
+
};
|
|
7
17
|
export function useMenuState() {
|
|
8
18
|
const isMobile = useIsMobile();
|
|
9
19
|
const state = useReducer(a => !a, !isMobile);
|
|
10
20
|
const [isOpen, toggleOpen] = state;
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return history.listen(function () {
|
|
15
|
-
toggleOpen();
|
|
16
|
-
});
|
|
21
|
+
const locationChangeCallback = useCallback(function () {
|
|
22
|
+
if (isMobile && !isOpen) {
|
|
23
|
+
toggleOpen();
|
|
17
24
|
}
|
|
18
|
-
}, [isMobile, isOpen
|
|
25
|
+
}, [isMobile, isOpen]);
|
|
26
|
+
useOnLocationChange(locationChangeCallback);
|
|
19
27
|
return state;
|
|
20
28
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-admin-base-bootstrap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
@@ -25,32 +25,29 @@
|
|
|
25
25
|
"delay": "100"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"react": "^
|
|
29
|
-
"react-dom": "^17.0.2",
|
|
28
|
+
"react": "^18.0.0",
|
|
30
29
|
"react-intl": "^5.21.0",
|
|
31
|
-
"react-router-dom": "^
|
|
30
|
+
"react-router-dom": "^6.3.0"
|
|
32
31
|
},
|
|
33
32
|
"dependencies": {
|
|
34
|
-
"@emotion/react": "^11.
|
|
35
|
-
"@fortawesome/fontawesome-free": "^
|
|
33
|
+
"@emotion/react": "^11.8.2",
|
|
34
|
+
"@fortawesome/fontawesome-free": "^6.1.1",
|
|
36
35
|
"bootstrap": "^5.1.3",
|
|
37
36
|
"file-dialog": "^0.0.8",
|
|
38
37
|
"modal-cropper": "^1.2.3",
|
|
39
38
|
"nprogress": "^0.2.0",
|
|
40
39
|
"prettysize": "^2.0.0",
|
|
41
|
-
"react-admin-base": "^0.
|
|
40
|
+
"react-admin-base": "^0.7.0",
|
|
42
41
|
"react-responsive": "^8.2.0",
|
|
43
|
-
"react-select": "^5.2.
|
|
44
|
-
"reactstrap": "^9.0.
|
|
42
|
+
"react-select": "^5.2.2",
|
|
43
|
+
"reactstrap": "^9.0.1",
|
|
45
44
|
"rewire": "^6.0.0",
|
|
46
|
-
"sweetalert2": "^11.
|
|
45
|
+
"sweetalert2": "^11.4.8"
|
|
47
46
|
},
|
|
48
47
|
"devDependencies": {
|
|
49
|
-
"@types/react": "^17.0.34",
|
|
50
|
-
"@types/react-router-dom": "^5.3.2",
|
|
51
48
|
"cross-env": "^7.0.3",
|
|
52
|
-
"nodemon": "^2.0.
|
|
53
|
-
"react-intl": "^5.
|
|
54
|
-
"typescript": "^4.
|
|
49
|
+
"nodemon": "^2.0.15",
|
|
50
|
+
"react-intl": "^5.24.8",
|
|
51
|
+
"typescript": "^4.6.3"
|
|
55
52
|
}
|
|
56
53
|
}
|
|
@@ -114,9 +114,9 @@ export default function BootstrapTable({url, bordered, noStrip, defaultParams, a
|
|
|
114
114
|
<DataContextProvider value={fetchData}>
|
|
115
115
|
<CardHeader>
|
|
116
116
|
<Row>
|
|
117
|
-
{add && <Col xs="12" md="2"><Link to={add} className="btn btn-primary font-xl
|
|
117
|
+
{add && <Col xs="12" md="2"><Link to={add} className="btn btn-primary font-xl d-block"><i className="fa fa-plus"/></Link></Col>}
|
|
118
118
|
<Col md="2">
|
|
119
|
-
<Input type="select"
|
|
119
|
+
<Input type="select" value={itemPerPage.toString()} onChange={a => setItemPerPage(+a.currentTarget.value)}>
|
|
120
120
|
<option value="1">1</option>
|
|
121
121
|
<option value="20">20</option>
|
|
122
122
|
<option value="50">50</option>
|
|
@@ -131,14 +131,13 @@ export default function BootstrapTable({url, bordered, noStrip, defaultParams, a
|
|
|
131
131
|
<Input
|
|
132
132
|
placeholder={intl.formatMessage({id: "SEARCH"})} type="text"
|
|
133
133
|
value={params.query || ''}
|
|
134
|
-
bsSize="lg"
|
|
135
134
|
onChange={e => setParams({...params, query: e.currentTarget.value})}
|
|
136
135
|
/>
|
|
137
136
|
</Col>
|
|
138
137
|
</Row>
|
|
139
138
|
</CardHeader>
|
|
140
|
-
{data === null ? <Alert className="text-center mb-0 mx-3 " color="warning"><i className="fas fa-spinner fa-
|
|
141
|
-
<i className="far fa-times-circle
|
|
139
|
+
{data === null ? <Alert className="text-center mb-0 mx-3 " color="warning"><i className="fas fa-spinner fa-spin"></i></Alert> : !data.length ? <Alert className="text-center mx-3" color="danger">
|
|
140
|
+
<i className="far fa-times-circle"></i> <FormattedMessage id="NO_DATA_IS_AVAILABLE"/>
|
|
142
141
|
</Alert> : <Table hover bordered={bordered} striped={!noStrip} responsive size="md" className="mb-0 dataTable">
|
|
143
142
|
{children[0]}
|
|
144
143
|
<tbody>
|
|
@@ -19,17 +19,17 @@ export default function BootstrapPagination({ className, currentPage, pageCount,
|
|
|
19
19
|
activePage={currentPage}
|
|
20
20
|
pageCount={pageCount}
|
|
21
21
|
showPages={15}
|
|
22
|
-
prevPage={index => <PaginationItem onClick={() => onPageChange(index)}><PaginationLink previous tag="button">«</PaginationLink></PaginationItem>}
|
|
22
|
+
prevPage={index => <PaginationItem onClick={() => onPageChange(index)}><PaginationLink previous tag="button" type="button">«</PaginationLink></PaginationItem>}
|
|
23
23
|
|
|
24
24
|
page={index => <PaginationItem key={index} active={currentPage === index}>
|
|
25
|
-
<PaginationLink tag="button" onClick={() => onPageChange(index)}>{index}</PaginationLink>
|
|
25
|
+
<PaginationLink tag="button" type="button" onClick={() => onPageChange(index)}>{index}</PaginationLink>
|
|
26
26
|
</PaginationItem>}
|
|
27
27
|
|
|
28
28
|
nextPage={index => <PaginationItem
|
|
29
|
-
onClick={() => onPageChange(index)}><PaginationLink next tag="button">»</PaginationLink></PaginationItem>}
|
|
29
|
+
onClick={() => onPageChange(index)}><PaginationLink next tag="button" type="button">»</PaginationLink></PaginationItem>}
|
|
30
30
|
|
|
31
31
|
dots={index => <PaginationItem
|
|
32
|
-
onClick={() => onPageChange(index)} active={currentPage === index}><PaginationLink tag="button">{index}</PaginationLink></PaginationItem>}
|
|
32
|
+
onClick={() => onPageChange(index)} active={currentPage === index}><PaginationLink tag="button" type="button">{index}</PaginationLink></PaginationItem>}
|
|
33
33
|
/>
|
|
34
34
|
</Pagination>;
|
|
35
35
|
}
|
package/src/Components/CRUD.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useContext, useRef, useState } from 'react';
|
|
2
2
|
import { ValidatorProvider } from "react-admin-base";
|
|
3
3
|
import { FormattedMessage } from 'react-intl';
|
|
4
|
-
import {
|
|
4
|
+
import { Navigate, Routes, useParams, Route } from 'react-router-dom';
|
|
5
5
|
import { Alert, Button, Col, Form, Modal, ModalFooter, ModalHeader, Row } from "reactstrap";
|
|
6
6
|
import LoadingButton from '../Components/LoadingButton';
|
|
7
7
|
import BootstrapDataTable, { Actions } from './BootstrapDataTable';
|
|
@@ -56,7 +56,7 @@ export function ModalEntityEditor({ entity, title, size, url, onReload, disabled
|
|
|
56
56
|
}, [save, saved, error, onReload, url]);
|
|
57
57
|
|
|
58
58
|
return <>
|
|
59
|
-
{ (saved || !open) && url && <
|
|
59
|
+
{ (saved || !open) && url && <Navigate to={url} replace />}
|
|
60
60
|
<Modal isOpen size={size} toggle={() => url ? setOpen(false) : onReload(null)} fade={false}>
|
|
61
61
|
{ title && <ModalHeader toggle={() => url ? setOpen(false) : onReload(null)}>
|
|
62
62
|
<b>{ title }</b>
|
|
@@ -104,9 +104,14 @@ export function CRUDActions({ id, edit, del, children }: CrudActionProps) {
|
|
|
104
104
|
</Actions>;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
function ComponentWrapper({ Component, ...props }) {
|
|
108
|
+
const { id } = useParams();
|
|
109
|
+
return <Component {...props} id={id} />;
|
|
110
|
+
}
|
|
111
|
+
|
|
107
112
|
export default function CRUD(props) {
|
|
108
113
|
const ref = useRef(null as any);
|
|
109
|
-
const {
|
|
114
|
+
const { url, apiUrl, Component, defaultParams, noAdd } = props;
|
|
110
115
|
|
|
111
116
|
var reload = useCallback(async function() {
|
|
112
117
|
if (ref.current) {
|
|
@@ -115,9 +120,10 @@ export default function CRUD(props) {
|
|
|
115
120
|
}, [ref]);
|
|
116
121
|
|
|
117
122
|
return <UrlContext.Provider value={url}>
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
<Routes>
|
|
124
|
+
{ !noAdd && <Route path="create" element={<ComponentWrapper Component={Component} url={url} onReload={reload} {...(defaultParams || {})} />} /> }
|
|
125
|
+
<Route path=":id/edit" element={<ComponentWrapper Component={Component} url={url} onReload={reload} {...(defaultParams || {})} />} />
|
|
126
|
+
</Routes>
|
|
127
|
+
<BootstrapDataTable innerRef={ref} add={!noAdd && "create"} {...props} url={apiUrl || url} />
|
|
122
128
|
</UrlContext.Provider>;
|
|
123
129
|
}
|
|
@@ -4,6 +4,7 @@ import { FormattedMessage } from "react-intl";
|
|
|
4
4
|
import { Alert, Form } from 'reactstrap';
|
|
5
5
|
import LoadingButton from "../Components/LoadingButton";
|
|
6
6
|
import { ValidationErrors } from './Validator';
|
|
7
|
+
import { Navigate } from 'react-router-dom';
|
|
7
8
|
|
|
8
9
|
type EntityEditorParams = {
|
|
9
10
|
entity: any;
|
|
@@ -15,7 +16,7 @@ type EntityEditorParams = {
|
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
export default function EntityEditor({ entity, disabled, children, onSave, saveButtonClassName, saveButtonText }: EntityEditorParams) {
|
|
18
|
-
const [
|
|
19
|
+
const [ data, _2, save, loading ] = entity;
|
|
19
20
|
|
|
20
21
|
const [ saved, setSaved ] = useState(false);
|
|
21
22
|
const [ error, setError ] = useState<any>(false);
|
|
@@ -1,25 +1,37 @@
|
|
|
1
|
-
import { useEffect, useReducer } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useReducer, useRef } from 'react';
|
|
2
2
|
import { useMediaQuery } from 'react-responsive';
|
|
3
|
-
import {
|
|
3
|
+
import { useLocation } from "react-router-dom";
|
|
4
4
|
|
|
5
5
|
export function useIsMobile() {
|
|
6
6
|
return useMediaQuery({ query: '(max-width: 992px)' });
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
const useOnLocationChange = (handleLocationChange: any) => {
|
|
10
|
+
const location = useLocation();
|
|
11
|
+
|
|
12
|
+
const locationRef = useRef("");
|
|
13
|
+
|
|
14
|
+
useEffect(function() {
|
|
15
|
+
if (locationRef.current != location.pathname) {
|
|
16
|
+
handleLocationChange(location);
|
|
17
|
+
locationRef.current = location.pathname;
|
|
18
|
+
}
|
|
19
|
+
}, [location.pathname, locationRef, handleLocationChange]);
|
|
20
|
+
};
|
|
21
|
+
|
|
9
22
|
export function useMenuState() {
|
|
10
23
|
const isMobile = useIsMobile();
|
|
11
24
|
|
|
12
25
|
const state = useReducer(a => !a, !isMobile);
|
|
13
26
|
const [ isOpen, toggleOpen ] = state;
|
|
14
27
|
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return history.listen(function() {
|
|
19
|
-
toggleOpen();
|
|
20
|
-
});
|
|
28
|
+
const locationChangeCallback = useCallback(function() {
|
|
29
|
+
if (isMobile && !isOpen) {
|
|
30
|
+
toggleOpen();
|
|
21
31
|
}
|
|
22
|
-
}, [isMobile, isOpen
|
|
32
|
+
}, [ isMobile, isOpen ]);
|
|
23
33
|
|
|
34
|
+
useOnLocationChange(locationChangeCallback);
|
|
35
|
+
|
|
24
36
|
return state;
|
|
25
37
|
}
|