Lazar Kostic 2 лет назад
Родитель
Сommit
8f2cfc3204

+ 15
- 13
.eslintrc Просмотреть файл

{ {
"extends": [
"react-app",
"airbnb",
"prettier"
],
"plugins": [
"react",
"react-hooks",
"security"
],
"extends": ["react-app", "airbnb", "prettier"],
"settings": {
"import/resolver": {
"node": {
"paths": ["src"]
}
}
},
"plugins": ["react", "react-hooks", "security"],
"rules": { "rules": {
"react/jsx-filename-extension": "off", "react/jsx-filename-extension": "off",
"react/jsx-props-no-spreading": "off", "react/jsx-props-no-spreading": "off",
"no-use-before-define": "off", "no-use-before-define": "off",
"no-template-curly-in-string": "off", "no-template-curly-in-string": "off",
"react-hooks/exhaustive-deps": "warn", "react-hooks/exhaustive-deps": "warn",
"prettier/prettier": ["error", {
"endOfLine":"auto"
}]
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
]
} }
} }

+ 20
- 19
.eslintrc.json Просмотреть файл

{ {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"env": {
"browser": true,
"es2021": true
},
"extends": ["eslint:recommended", "plugin:react/recommended"],
"settings": {
"import/resolver": {
"node": {
"paths": ["src"]
}
} }
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["react"],
"rules": {}
} }

+ 6
- 0
jsconfig.json Просмотреть файл

{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}

+ 4
- 4
src/components/InputFields/BaseInputField.js Просмотреть файл

import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { ErrorMessage } from 'formik'; import { ErrorMessage } from 'formik';
import IconButton from '../IconButton/IconButton'; import IconButton from '../IconButton/IconButton';
import { ReactComponent as Search } from '../../assets/images/svg/search.svg';
import { ReactComponent as EyeOn } from '../../assets/images/svg/eye-on.svg';
import { ReactComponent as EyeOff } from '../../assets/images/svg/eye-off.svg';
import { ReactComponent as CapsLock } from '../../assets/images/svg/caps-lock.svg';
import { ReactComponent as Search } from 'assets/images/svg/search.svg';
import { ReactComponent as EyeOn } from 'assets/images/svg/eye-on.svg';
import { ReactComponent as EyeOff } from 'assets/images/svg/eye-off.svg';
import { ReactComponent as CapsLock } from 'assets/images/svg/caps-lock.svg';


const BaseInputField = ({ const BaseInputField = ({
type, type,

+ 2
- 2
src/components/InputFields/Checkbox.js Просмотреть файл

import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { ReactComponent as Checked } from '../../assets/images/svg/checked.svg';
import { ReactComponent as Unchecked } from '../../assets/images/svg/unchecked.svg';
import { ReactComponent as Checked } from 'assets/images/svg/checked.svg';
import { ReactComponent as Unchecked } from 'assets/images/svg/unchecked.svg';


const Checkbox = ({ className, children, name, onChange, checked, field }) => ( const Checkbox = ({ className, children, name, onChange, checked, field }) => (
<label htmlFor={name} className={`c-checkbox ${className || ''}`}> <label htmlFor={name} className={`c-checkbox ${className || ''}`}>

+ 12
- 12
src/components/InputFields/CurrencyField.js Просмотреть файл

import React, { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { ErrorMessage, useField } from 'formik';
import CurrencyInput from 'react-currency-input-field';
import { formatMoneyNumeral } from '../../util/helpers/numeralHelpers';
import React, { useEffect, useRef } from "react";
import PropTypes from "prop-types";
import { ErrorMessage, useField } from "formik";
import CurrencyInput from "react-currency-input-field";
import { formatMoneyNumeral } from "util/helpers/numeralHelpers";
import { import {
PLUS_SYMBOL, PLUS_SYMBOL,
MINUS_SYMBOL, MINUS_SYMBOL,
NUMPAD_MINUS_SYMBOL, NUMPAD_MINUS_SYMBOL,
NUMPAD_PLUS_SYMBOL, NUMPAD_PLUS_SYMBOL,
K_KEYCODE, K_KEYCODE,
} from '../../constants/keyCodeConstants';
} from "constants/keyCodeConstants";


const CurrencyField = ({ const CurrencyField = ({
autoFocus, autoFocus,
const [field, meta] = useField(props); const [field, meta] = useField(props);
const inputField = useRef(null); const inputField = useRef(null);
function styles() { function styles() {
let style = 'c-currency-field';
let style = "c-currency-field";


if (meta.error && meta.touched) { if (meta.error && meta.touched) {
style += ` c-currency-field--error`; style += ` c-currency-field--error`;


const prefix = formatMoneyNumeral(0); const prefix = formatMoneyNumeral(0);
const prefixSymbol = () => { const prefixSymbol = () => {
if (prefix.includes('CAD')) {
return 'CAD ';
if (prefix.includes("CAD")) {
return "CAD ";
} }


return '$';
return "$";
}; };


return ( return (
{...props} {...props}
prefix={prefixSymbol()} prefix={prefixSymbol()}
onValueChange={(value) => { onValueChange={(value) => {
onChange(value ? Number(value) : '');
onChange(value ? Number(value) : "");
}} }}
onKeyDown={(event) => onKeydownHandler(event)} onKeyDown={(event) => onKeydownHandler(event)}
ref={inputField} ref={inputField}
{...props} {...props}
prefix={prefixSymbol()} prefix={prefixSymbol()}
onValueChange={(value) => { onValueChange={(value) => {
onChange(value ? Number(value) : '');
onChange(value ? Number(value) : "");
}} }}
onKeyDown={(event) => onKeydownHandler(event)} onKeyDown={(event) => onKeydownHandler(event)}
ref={inputField} ref={inputField}

+ 1
- 1
src/components/InputFields/NumberField.js Просмотреть файл

NUMPAD_PLUS_SYMBOL, NUMPAD_PLUS_SYMBOL,
DOWN_ARROW_KEYCODE, DOWN_ARROW_KEYCODE,
UP_ARROW_KEYCODE, UP_ARROW_KEYCODE,
} from '../../constants/keyCodeConstants';
} from 'constants/keyCodeConstants';


const NumberField = ({ const NumberField = ({
field, field,

+ 2
- 2
src/components/InputFields/Radio.js Просмотреть файл

import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { ReactComponent as RadioOn } from '../../assets/images/svg/radio-on.svg';
import { ReactComponent as RadioOff } from '../../assets/images/svg/radio-off.svg';
import { ReactComponent as RadioOn } from 'assets/images/svg/radio-on.svg';
import { ReactComponent as RadioOff } from 'assets/images/svg/radio-off.svg';


const Checkbox = ({ const Checkbox = ({
className, className,

+ 3
- 4
src/components/InputFields/Search.js Просмотреть файл

import React from 'react';
import PropTypes from 'prop-types';
import React from "react";
import PropTypes from "prop-types";


import BaseInputField from './BaseInputField';
import BaseInputField from "./BaseInputField";


const Search = ({ const Search = ({
field, field,
form, form,
label,
placeholder, placeholder,
disabled, disabled,
className, className,

+ 1
- 1
src/components/InputFields/SelectField.js Просмотреть файл

import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Select, { components, createFilter } from 'react-select'; import Select, { components, createFilter } from 'react-select';
import { ErrorMessage, useField } from 'formik'; import { ErrorMessage, useField } from 'formik';
import { ReactComponent as FilledChevronDown } from '../../assets/images/svg/filled-chevron-down.svg';
import { ReactComponent as FilledChevronDown } from 'assets/images/svg/filled-chevron-down.svg';


const SelectField = ({ const SelectField = ({
label, label,

+ 1
- 1
src/components/InputFields/TextField.js Просмотреть файл

TAB_KEYCODE, TAB_KEYCODE,
RIGHT_ARROW_KEYCODE, RIGHT_ARROW_KEYCODE,
LEFT_ARROW_KEYCODE, LEFT_ARROW_KEYCODE,
} from '../../constants/keyCodeConstants';
} from 'constants/keyCodeConstants';


const TextField = ({ const TextField = ({
field, field,

+ 164
- 165
src/components/MUI/Examples/PagingSortingFilteringExample.js Просмотреть файл

import React, { useEffect, useState } from 'react';
import React, { useEffect, useState } from "react";
import { import {
Paper,
Box,
Grid,
Typography,
Divider,
TablePagination,
TextField,
FormControl,
InputLabel,
Select,
MenuItem,
} from '@mui/material';
Paper,
Box,
Grid,
Typography,
Divider,
TablePagination,
TextField,
FormControl,
InputLabel,
Select,
MenuItem,
} from "@mui/material";
// import { useTranslation } from 'react-i18next'; // import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector, batch } from 'react-redux';
import useDebounce from '../../../hooks/useDebounceHook';
import { useDispatch, useSelector, batch } from "react-redux";
import useDebounce from "hooks/useDebounceHook";
import { import {
itemsSelector,
pageSelector,
itemsPerPageSelector,
countSelector,
sortSelector,
} from '../../../store/selectors/randomDataSelectors';
itemsSelector,
pageSelector,
itemsPerPageSelector,
countSelector,
sortSelector,
} from "store/selectors/randomDataSelectors";
import { import {
loadData,
updatePage,
updateItemsPerPage,
updateFilter,
updateSort,
} from '../../../store/actions/randomData/randomDataActions';
loadData,
updatePage,
updateItemsPerPage,
updateFilter,
updateSort,
} from "store/actions/randomData/randomDataActions";


const PagingSortingFilteringExample = () => { const PagingSortingFilteringExample = () => {
const [filterText, setFilterText] = useState('');
const [filterText, setFilterText] = useState("");


const dispatch = useDispatch();
// const { t } = useTranslation();
const items = useSelector(itemsSelector);
const currentPage = useSelector(pageSelector);
const itemsPerPage = useSelector(itemsPerPageSelector);
const totalCount = useSelector(countSelector);
const sort = useSelector(sortSelector) || 'name-asc';
const dispatch = useDispatch();
// const { t } = useTranslation();
const items = useSelector(itemsSelector);
const currentPage = useSelector(pageSelector);
const itemsPerPage = useSelector(itemsPerPageSelector);
const totalCount = useSelector(countSelector);
const sort = useSelector(sortSelector) || "name-asc";


// Use debounce to prevent too many rerenders
const debouncedFilterText = useDebounce(filterText, 500);
// Use debounce to prevent too many rerenders
const debouncedFilterText = useDebounce(filterText, 500);


useEffect(() => {
dispatch(loadData(30));
dispatch(updateSort(sort));
}, []);
useEffect(() => {
dispatch(loadData(30));
dispatch(updateSort(sort));
}, []);


useEffect(() => {
batch(() => {
dispatch(updateFilter(filterText));
currentPage > 0 && dispatch(updatePage(0));
});
}, [debouncedFilterText]);
useEffect(() => {
batch(() => {
dispatch(updateFilter(filterText));
currentPage > 0 && dispatch(updatePage(0));
});
}, [debouncedFilterText]);


const handleFilterTextChange = (event) => {
const filterText = event.target.value;
setFilterText(filterText);
};
const handleFilterTextChange = (event) => {
const filterText = event.target.value;
setFilterText(filterText);
};


const handleSortChange = (event) => {
const sort = event.target.value;
dispatch(updateSort(sort));
};
const handleSortChange = (event) => {
const sort = event.target.value;
dispatch(updateSort(sort));
};


const handlePageChange = (event, newPage) => {
dispatch(updatePage(newPage));
};
const handlePageChange = (event, newPage) => {
dispatch(updatePage(newPage));
};


const handleItemsPerPageChange = (event) => {
const itemsPerPage = parseInt(event.target.value);
batch(() => {
dispatch(updateItemsPerPage(itemsPerPage));
dispatch(updatePage(0));
});
};
const handleItemsPerPageChange = (event) => {
const itemsPerPage = parseInt(event.target.value);
batch(() => {
dispatch(updateItemsPerPage(itemsPerPage));
dispatch(updatePage(0));
});
};



return (
<Paper
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'start',
py: 2,
minHeight: 500,
}}
elevation={5}
>
<Typography sx={{ my: 4 }} variant="h4" gutterBottom align="center">
Pagination, Filtering and Sorting Example Client Side
</Typography>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
flexWrap: 'wrap',
mx: 2,
}}
>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
width: '100%',
}}
>
{/* TODO Separate into SelectComponent */}
<FormControl sx={{ flexGrow: 1 }}>
<InputLabel id="sort-label">Sort</InputLabel>
<Select
label="Sort"
labelId="sort-label"
id="sort-select-helper"
value={sort}
onChange={handleSortChange}
>
<MenuItem value="name-asc">Name - A-Z</MenuItem>
<MenuItem value="name-desc">Name - Z-A</MenuItem>
<MenuItem value="price-asc">Price - Lowest to Highest</MenuItem>
<MenuItem value="price-desc">Price - Highest to Lowest</MenuItem>
</Select>
</FormControl>
<TextField
sx={{ flexGrow: 1 }}
variant="outlined"
label="Filter"
placeholder="Filter"
value={filterText}
onChange={handleFilterTextChange}
/>
</Box>
</Box>
<Grid container>
{items &&
items.length > 0 &&
items
.slice(
currentPage * itemsPerPage,
currentPage * itemsPerPage + itemsPerPage
)
.map((product, index) => (
// ! DON'T USE index for key, this is for example only
<Grid item sx={{ p: 2 }} xs={12} sm={6} md={4} lg={3} key={index}>
{/* TODO separate into component */}
<Paper sx={{ p: 3, height: '100%' }} elevation={3}>
<Typography sx={{ fontWeight: 600 }}>Name: </Typography>
<Typography display="inline"> {product.name}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Designer: </Typography>
<Typography display="inline"> {product.designer}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Type: </Typography>
<Typography display="inline"> {product.type}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Price: </Typography>
<Typography display="inline"> ${product.price}</Typography>
</Paper>
</Grid>
))}
</Grid>
<Box sx={{ width: '100%' }}>
<TablePagination
component="div"
count={totalCount}
page={currentPage}
onPageChange={handlePageChange}
rowsPerPage={itemsPerPage}
onRowsPerPageChange={handleItemsPerPageChange}
rowsPerPageOptions={[12, 24, 48, 96]}
labelRowsPerPage="Items per page"
showFirstButton
showLastButton
/>
</Box>
</Paper>
);
return (
<Paper
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "start",
py: 2,
minHeight: 500,
}}
elevation={5}
>
<Typography sx={{ my: 4 }} variant="h4" gutterBottom align="center">
Pagination, Filtering and Sorting Example Client Side
</Typography>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
flexWrap: "wrap",
mx: 2,
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
width: "100%",
}}
>
{/* TODO Separate into SelectComponent */}
<FormControl sx={{ flexGrow: 1 }}>
<InputLabel id="sort-label">Sort</InputLabel>
<Select
label="Sort"
labelId="sort-label"
id="sort-select-helper"
value={sort}
onChange={handleSortChange}
>
<MenuItem value="name-asc">Name - A-Z</MenuItem>
<MenuItem value="name-desc">Name - Z-A</MenuItem>
<MenuItem value="price-asc">Price - Lowest to Highest</MenuItem>
<MenuItem value="price-desc">Price - Highest to Lowest</MenuItem>
</Select>
</FormControl>
<TextField
sx={{ flexGrow: 1 }}
variant="outlined"
label="Filter"
placeholder="Filter"
value={filterText}
onChange={handleFilterTextChange}
/>
</Box>
</Box>
<Grid container>
{items &&
items.length > 0 &&
items
.slice(
currentPage * itemsPerPage,
currentPage * itemsPerPage + itemsPerPage
)
.map((product, index) => (
// ! DON'T USE index for key, this is for example only
<Grid item sx={{ p: 2 }} xs={12} sm={6} md={4} lg={3} key={index}>
{/* TODO separate into component */}
<Paper sx={{ p: 3, height: "100%" }} elevation={3}>
<Typography sx={{ fontWeight: 600 }}>Name: </Typography>
<Typography display="inline"> {product.name}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Designer: </Typography>
<Typography display="inline"> {product.designer}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Type: </Typography>
<Typography display="inline"> {product.type}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Price: </Typography>
<Typography display="inline"> ${product.price}</Typography>
</Paper>
</Grid>
))}
</Grid>
<Box sx={{ width: "100%" }}>
<TablePagination
component="div"
count={totalCount}
page={currentPage}
onPageChange={handlePageChange}
rowsPerPage={itemsPerPage}
onRowsPerPageChange={handleItemsPerPageChange}
rowsPerPageOptions={[12, 24, 48, 96]}
labelRowsPerPage="Items per page"
showFirstButton
showLastButton
/>
</Box>
</Paper>
);
}; };


export default PagingSortingFilteringExample; export default PagingSortingFilteringExample;

+ 145
- 145
src/components/MUI/Examples/PagingSortingFilteringExampleServerSide.js Просмотреть файл

import React, { useEffect, useState } from 'react';
import React, { useEffect, useState } from "react";
import { import {
Paper,
Box,
Grid,
Typography,
Divider,
TablePagination,
TextField,
FormControl,
InputLabel,
Select,
MenuItem,
} from '@mui/material';
Paper,
Box,
Grid,
Typography,
Divider,
TablePagination,
TextField,
FormControl,
InputLabel,
Select,
MenuItem,
} from "@mui/material";
// import { useTranslation } from 'react-i18next'; // import { useTranslation } from 'react-i18next';
import Backdrop from '../BackdropComponent';
import useDebounce from '../../../hooks/useDebounceHook';
import { useRandomData } from '../../../context/RandomDataContext';
import Backdrop from "../BackdropComponent";
import useDebounce from "hooks/useDebounceHook";
import { useRandomData } from "context/RandomDataContext";


const PagingSortingFilteringExampleServerSide = () => { const PagingSortingFilteringExampleServerSide = () => {
const [filterText, setFilterText] = useState('');
const { state, data } = useRandomData();
const { items, loading, totalCount, currentPage, itemsPerPage, sort } = data;
const { setPage, setItemsPerPage, setSort, setFilter } = state;
// const { t } = useTranslation();
const [filterText, setFilterText] = useState("");
const { state, data } = useRandomData();
const { items, loading, totalCount, currentPage, itemsPerPage, sort } = data;
const { setPage, setItemsPerPage, setSort, setFilter } = state;
// const { t } = useTranslation();


// Use debounce to prevent too many rerenders
const debouncedFilterText = useDebounce(filterText, 500);
// Use debounce to prevent too many rerenders
const debouncedFilterText = useDebounce(filterText, 500);


useEffect(() => {
setFilter(filterText);
}, [debouncedFilterText]);
useEffect(() => {
setFilter(filterText);
}, [debouncedFilterText]);


const handleFilterTextChange = (event) => {
const filterText = event.target.value;
setFilterText(filterText);
};
const handleFilterTextChange = (event) => {
const filterText = event.target.value;
setFilterText(filterText);
};


const handleSortChange = (event) => {
const sort = event.target.value;
setSort(sort);
};
const handleSortChange = (event) => {
const sort = event.target.value;
setSort(sort);
};


const handlePageChange = (event, newPage) => {
setPage(newPage);
};
const handlePageChange = (event, newPage) => {
setPage(newPage);
};


const handleItemsPerPageChange = (event) => {
const itemsPerPage = parseInt(event.target.value);
setItemsPerPage(itemsPerPage);
setPage(0);
};
const handleItemsPerPageChange = (event) => {
const itemsPerPage = parseInt(event.target.value);
setItemsPerPage(itemsPerPage);
setPage(0);
};


return (
<Paper
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'start',
py: 2,
minHeight: 500,
position: 'relative',
}}
elevation={5}
>
{loading && <Backdrop isLoading position="absolute" />}
<Typography sx={{ my: 4 }} variant="h4" gutterBottom align="center">
Pagination, Filtering and Sorting Example Server Side
</Typography>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
flexWrap: 'wrap',
mx: 2,
}}
>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
width: '100%',
}}
>
<FormControl sx={{ flexGrow: 1 }}>
<InputLabel id="sort-label">Sort</InputLabel>
<Select
label="Sort"
labelId="sort-label"
id="sort-select-helper"
value={sort || ''}
onChange={handleSortChange}
>
<MenuItem value="">None</MenuItem>
<MenuItem value="name-asc">Name - A-Z</MenuItem>
<MenuItem value="name-desc">Name - Z-A</MenuItem>
<MenuItem value="price-asc">Price - Lowest to Highest</MenuItem>
<MenuItem value="price-desc">Price - Highest to Lowest</MenuItem>
</Select>
</FormControl>
<TextField
sx={{ flexGrow: 1 }}
variant="outlined"
label="Filter"
placeholder="Filter"
value={filterText}
onChange={handleFilterTextChange}
/>
</Box>
<Grid container sx={{ position: 'relative' }}>
{items &&
items.length > 0 &&
items.map((item) => (
<Grid
item
sx={{ p: 2 }}
xs={12}
sm={6}
md={4}
lg={3}
key={item.id}
>
{/* TODO separate into component */}
<Paper sx={{ p: 3, height: '100%' }} elevation={3}>
<Typography sx={{ fontWeight: 600 }}>Name: </Typography>
<Typography display="inline"> {item.name}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Company: </Typography>
<Typography display="inline"> {item.company}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Color: </Typography>
<Typography display="inline"> {item.color}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Price: </Typography>
<Typography display="inline"> {item.price}</Typography>
</Paper>
</Grid>
))}
</Grid>
<Box sx={{ width: '100%' }}>
<TablePagination
component="div"
count={totalCount}
page={currentPage}
onPageChange={handlePageChange}
rowsPerPage={itemsPerPage}
onRowsPerPageChange={handleItemsPerPageChange}
rowsPerPageOptions={[12, 24, 48, 96]}
labelRowsPerPage="Items per page"
showFirstButton
showLastButton
/>
</Box>
</Box>
</Paper>
);
return (
<Paper
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "start",
py: 2,
minHeight: 500,
position: "relative",
}}
elevation={5}
>
{loading && <Backdrop isLoading position="absolute" />}
<Typography sx={{ my: 4 }} variant="h4" gutterBottom align="center">
Pagination, Filtering and Sorting Example Server Side
</Typography>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
flexWrap: "wrap",
mx: 2,
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
width: "100%",
}}
>
<FormControl sx={{ flexGrow: 1 }}>
<InputLabel id="sort-label">Sort</InputLabel>
<Select
label="Sort"
labelId="sort-label"
id="sort-select-helper"
value={sort || ""}
onChange={handleSortChange}
>
<MenuItem value="">None</MenuItem>
<MenuItem value="name-asc">Name - A-Z</MenuItem>
<MenuItem value="name-desc">Name - Z-A</MenuItem>
<MenuItem value="price-asc">Price - Lowest to Highest</MenuItem>
<MenuItem value="price-desc">Price - Highest to Lowest</MenuItem>
</Select>
</FormControl>
<TextField
sx={{ flexGrow: 1 }}
variant="outlined"
label="Filter"
placeholder="Filter"
value={filterText}
onChange={handleFilterTextChange}
/>
</Box>
<Grid container sx={{ position: "relative" }}>
{items &&
items.length > 0 &&
items.map((item) => (
<Grid
item
sx={{ p: 2 }}
xs={12}
sm={6}
md={4}
lg={3}
key={item.id}
>
{/* TODO separate into component */}
<Paper sx={{ p: 3, height: "100%" }} elevation={3}>
<Typography sx={{ fontWeight: 600 }}>Name: </Typography>
<Typography display="inline"> {item.name}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Company: </Typography>
<Typography display="inline"> {item.company}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Color: </Typography>
<Typography display="inline"> {item.color}</Typography>
<Divider />
<Typography sx={{ fontWeight: 600 }}>Price: </Typography>
<Typography display="inline"> {item.price}</Typography>
</Paper>
</Grid>
))}
</Grid>
<Box sx={{ width: "100%" }}>
<TablePagination
component="div"
count={totalCount}
page={currentPage}
onPageChange={handlePageChange}
rowsPerPage={itemsPerPage}
onRowsPerPageChange={handleItemsPerPageChange}
rowsPerPageOptions={[12, 24, 48, 96]}
labelRowsPerPage="Items per page"
showFirstButton
showLastButton
/>
</Box>
</Box>
</Paper>
);
}; };


export default PagingSortingFilteringExampleServerSide; export default PagingSortingFilteringExampleServerSide;

+ 2
- 2
src/components/MUI/NavbarComponent.js Просмотреть файл

import Brightness7Icon from "@mui/icons-material/Brightness7"; import Brightness7Icon from "@mui/icons-material/Brightness7";
import MenuList from "./MenuListComponent"; import MenuList from "./MenuListComponent";
import Drawer from "./DrawerComponent"; import Drawer from "./DrawerComponent";
import { ColorModeContext } from "../../context/ColorModeContext";
import { ColorModeContext } from "context/ColorModeContext";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { logoutUser } from "../../store/actions/login/loginActions";
import { logoutUser } from "store/actions/login/loginActions";


const NavbarComponent = () => { const NavbarComponent = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();

+ 5
- 6
src/components/Router/PrivateRoute.js Просмотреть файл

import React, { useEffect } from 'react';
import { Redirect, Route } from 'react-router';
import { useDispatch } from 'react-redux';
import { authenticateUser } from '../../store/actions/login/loginActions';
// import { selectIsUserAuthenticated } from '../../store/selectors/userSelectors';
import { LOGIN_PAGE } from '../../constants/pages';
import React, { useEffect } from "react";
import { Redirect, Route } from "react-router";
import { useDispatch } from "react-redux";
import { authenticateUser } from "store/actions/login/loginActions";
import { LOGIN_PAGE } from "constants/pages";


const PrivateRoute = ({ ...props }) => { const PrivateRoute = ({ ...props }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();

+ 1
- 1
src/context/ColorModeContext.js Просмотреть файл

import React, { createContext } from 'react'; import React, { createContext } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { ThemeProvider } from '@mui/material/styles'; import { ThemeProvider } from '@mui/material/styles';
import useToggleColorMode from '../hooks/useToggleColorMode';
import useToggleColorMode from 'hooks/useToggleColorMode';


export const ColorModeContext = createContext(); export const ColorModeContext = createContext();



+ 2
- 2
src/context/RandomDataContext.js Просмотреть файл

import React, { createContext, useContext, useState } from 'react'; import React, { createContext, useContext, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import usePagingHook from '../hooks/usePagingHook';
import { getRequest } from '../request/jsonServerRequest';
import usePagingHook from 'hooks/usePagingHook';
import { getRequest } from 'request/jsonServerRequest';


const apiCall = (page, itemsPerPage, sort, sortDirection, filter) => const apiCall = (page, itemsPerPage, sort, sortDirection, filter) =>
getRequest('/items', { getRequest('/items', {

+ 2
- 2
src/hooks/useToggleColorMode.js Просмотреть файл

import { import {
authScopeSetHelper, authScopeSetHelper,
authScopeStringGetHelper, authScopeStringGetHelper,
} from "../util/helpers/authScopeHelpers";
import selectedTheme from "../themes";
} from "util/helpers/authScopeHelpers";
import selectedTheme from "themes";


const useToggleColorMode = () => { const useToggleColorMode = () => {
const currentColorMode = authScopeStringGetHelper("colorMode") || "light"; const currentColorMode = authScopeStringGetHelper("colorMode") || "light";

+ 13
- 11
src/index.js Просмотреть файл

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { HelmetProvider } from 'react-helmet-async';
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { HelmetProvider } from "react-helmet-async";


import './main.scss';
import App from './App';
import store from './store';
import "./main.scss";
import App from "./App";
import store from "./store";


import './i18n';
import ColorModeProvider from './context/ColorModeContext';
import "./i18n";
import ColorModeProvider from "./context/ColorModeContext";
import { CssBaseline } from "@mui/material";


ReactDOM.render( ReactDOM.render(
<HelmetProvider> <HelmetProvider>
<React.StrictMode> <React.StrictMode>
<Provider store={store}> <Provider store={store}>
<ColorModeProvider> <ColorModeProvider>
<App />
<CssBaseline />
<App />
</ColorModeProvider> </ColorModeProvider>
</Provider> </Provider>
</React.StrictMode> </React.StrictMode>
</HelmetProvider>, </HelmetProvider>,
document.getElementById('root'),
document.getElementById("root")
); );

+ 5
- 5
src/pages/AuthCallback/AuthCallback.js Просмотреть файл

import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { HOME_PAGE } from "../../constants/pages";
import { HOME_PAGE } from "constants/pages";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { fetchAuthProvider } from "../../store/actions/authProvider/authProviderActions";
import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
import { AUTH_PROVIDER_SCOPE } from "../../store/actions/authProvider/authProviderActionConstants";
import Backdrop from '../../components/MUI/BackdropComponent';
import { fetchAuthProvider } from "store/actions/authProvider/authProviderActions";
import { selectIsLoadingByActionType } from "store/selectors/loadingSelectors";
import { AUTH_PROVIDER_SCOPE } from "store/actions/authProvider/authProviderActionConstants";
import Backdrop from 'components/MUI/BackdropComponent';


function AuthCallback({ history }) { function AuthCallback({ history }) {
const dispatch = useDispatch(); const dispatch = useDispatch();

+ 2
- 2
src/pages/ErrorPages/NotFoundPage.js Просмотреть файл

import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Button from '../../components/Button/Button';
import Section from '../../components/Section/Section';
import Button from 'components/Button/Button';
import Section from 'components/Section/Section';


const NotFoundPage = () => { const NotFoundPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();

+ 5
- 5
src/pages/ForgotPasswordPage/ForgotPasswordPage.js Просмотреть файл

import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import * as Yup from 'yup'; import * as Yup from 'yup';
import i18next from 'i18next'; import i18next from 'i18next';
import Auth from '../../components/Auth/Auth';
import AuthCard from '../../components/AuthCards/AuthCard';
import TextField from '../../components/InputFields/TextField';
import Button from '../../components/Button/Button';
import Auth from 'components/Auth/Auth';
import AuthCard from 'components/AuthCards/AuthCard';
import TextField from 'components/InputFields/TextField';
import Button from 'components/Button/Button';


import Section from '../../components/Section/Section';
import Section from 'components/Section/Section';


const forgotPasswordValidationSchema = Yup.object().shape({ const forgotPasswordValidationSchema = Yup.object().shape({
email: Yup.string().required( email: Yup.string().required(

+ 79
- 79
src/pages/ForgotPasswordPage/ForgotPasswordPageMUI.js Просмотреть файл

import React from 'react';
import { useFormik } from 'formik';
import { useTranslation } from 'react-i18next';
import React from "react";
import { useFormik } from "formik";
import { useTranslation } from "react-i18next";
import { import {
Box,
Container,
Typography,
Button,
TextField,
Link,
Grid,
} from '@mui/material';
import Backdrop from '../../components/MUI/BackdropComponent';
import { LOGIN_PAGE } from '../../constants/pages';
import { NavLink } from 'react-router-dom';
import forgotPasswordValidation from '../../validations/forgotPasswordValidation';
import forgotPasswordInitialValues from '../../initialValues/forgotPasswordInitialValues';
Box,
Container,
Typography,
Button,
TextField,
Link,
Grid,
} from "@mui/material";
import Backdrop from "components/MUI/BackdropComponent";
import { LOGIN_PAGE } from "constants/pages";
import { NavLink } from "react-router-dom";
import forgotPasswordValidation from "validations/forgotPasswordValidation";
import forgotPasswordInitialValues from "initialValues/forgotPasswordInitialValues";


const ForgotPasswordPage = () => { const ForgotPasswordPage = () => {
const { t } = useTranslation();
const { t } = useTranslation();


const handleSubmit = (values) => {
console.log('Values', values);
};
const handleSubmit = (values) => {
console.log("Values", values);
};


const formik = useFormik({
initialValues: forgotPasswordInitialValues,
validationSchema: forgotPasswordValidation,
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});
const formik = useFormik({
initialValues: forgotPasswordInitialValues,
validationSchema: forgotPasswordValidation,
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});


return (
<Container component="main" maxWidth="md">
<Box
sx={{
marginTop: 32,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Typography component="h1" variant="h5">
{t('forgotPassword.title')}
</Typography>
<Box
component="form"
onSubmit={formik.handleSubmit}
sx={{ position: 'relative', mt: 1, p: 1 }}
>
<Backdrop position="absolute" isLoading={false} />
<TextField
name="email"
label={t('login.forgotPasswordEmail')}
margin="normal"
value={formik.values.email}
onChange={formik.handleChange}
error={formik.touched.email && Boolean(formik.errors.email)}
helperText={formik.touched.email && formik.errors.email}
autoFocus
fullWidth
/>
<Button
type="submit"
variant="contained"
sx={{ mt: 3, mb: 2 }}
fullWidth
>
{t('forgotPassword.label')}
</Button>
<Grid container justifyContent="center">
<Link
to={LOGIN_PAGE}
component={NavLink}
variant="body2"
underline="hover"
>
{t('common.back')}
</Link>
</Grid>
</Box>
</Box>
</Container>
);
return (
<Container component="main" maxWidth="md">
<Box
sx={{
marginTop: 32,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Typography component="h1" variant="h5">
{t("forgotPassword.title")}
</Typography>
<Box
component="form"
onSubmit={formik.handleSubmit}
sx={{ position: "relative", mt: 1, p: 1 }}
>
<Backdrop position="absolute" isLoading={false} />
<TextField
name="email"
label={t("login.forgotPasswordEmail")}
margin="normal"
value={formik.values.email}
onChange={formik.handleChange}
error={formik.touched.email && Boolean(formik.errors.email)}
helperText={formik.touched.email && formik.errors.email}
autoFocus
fullWidth
/>
<Button
type="submit"
variant="contained"
sx={{ mt: 3, mb: 2 }}
fullWidth
>
{t("forgotPassword.label")}
</Button>
<Grid container justifyContent="center">
<Link
to={LOGIN_PAGE}
component={NavLink}
variant="body2"
underline="hover"
>
{t("common.back")}
</Link>
</Grid>
</Box>
</Box>
</Container>
);
}; };


export default ForgotPasswordPage; export default ForgotPasswordPage;

+ 7
- 7
src/pages/HomePage/HomePageMUI.js Просмотреть файл

import React from "react"; import React from "react";
import { Box, Button, Grid } from "@mui/material"; import { Box, Button, Grid } from "@mui/material";
import Navbar from "../../components/MUI/NavbarComponent";
import Modals from "../../components/MUI/Examples/ModalsExample";
import DataGrid from "../../components/MUI/Examples/DataGridExample";
import PagingSortingFiltering from "../../components/MUI/Examples/PagingSortingFilteringExample";
import PagingSortingFilteringServerSide from "../../components/MUI/Examples/PagingSortingFilteringExampleServerSide";
import RandomDataProvider from "../../context/RandomDataContext";
import { getRequest } from "../../request";
import Navbar from "components/MUI/NavbarComponent";
import Modals from "components/MUI/Examples/ModalsExample";
import DataGrid from "components/MUI/Examples/DataGridExample";
import PagingSortingFiltering from "components/MUI/Examples/PagingSortingFilteringExample";
import PagingSortingFilteringServerSide from "components/MUI/Examples/PagingSortingFilteringExampleServerSide";
import RandomDataProvider from "context/RandomDataContext";
import { getRequest } from "request";


const HomePage = () => { const HomePage = () => {
const getPosts = async () => { const getPosts = async () => {

+ 45
- 58
src/pages/LoginPage/LoginPage.js Просмотреть файл

import React from 'react';
import PropTypes from 'prop-types';
import { Field, Form, Formik } from 'formik';
import { useDispatch, useSelector } from 'react-redux';
import { NavLink } from 'react-router-dom';
import * as Yup from 'yup';
import { useTranslation } from 'react-i18next';
import i18next from 'i18next';
import PasswordField from '../../components/InputFields/PasswordField';
import Button from '../../components/Button/Button';
import TextField from '../../components/InputFields/TextField';
import Auth from '../../components/Auth/Auth';
import AuthCard from '../../components/AuthCards/AuthCard';
import {
clearLoginErrors,
fetchUser,
} from '../../store/actions/login/loginActions';
import {
selectLoginError,
} from '../../store/selectors/loginSelectors';
import {
FORGOT_PASSWORD_PAGE, HOME_PAGE,
} from '../../constants/pages';
import { selectIsLoadingByActionType } from '../../store/selectors/loadingSelectors';
import { LOGIN_USER_LOADING } from '../../store/actions/login/loginActionConstants';
import React from "react";
import PropTypes from "prop-types";
import { Field, Form, Formik } from "formik";
import { useDispatch, useSelector } from "react-redux";
import { NavLink } from "react-router-dom";
import * as Yup from "yup";
import { useTranslation } from "react-i18next";
import i18next from "i18next";
import PasswordField from "components/InputFields/PasswordField";
import Button from "components/Button/Button";
import TextField from "components/InputFields/TextField";
import Auth from "components/Auth/Auth";
import AuthCard from "components/AuthCards/AuthCard";
import { clearLoginErrors, fetchUser } from "store/actions/login/loginActions";
import { selectLoginError } from "store/selectors/loginSelectors";
import { FORGOT_PASSWORD_PAGE, HOME_PAGE } from "constants/pages";
import { selectIsLoadingByActionType } from "store/selectors/loadingSelectors";
import { LOGIN_USER_LOADING } from "store/actions/login/loginActionConstants";


const LoginValidationSchema = Yup.object().shape({ const LoginValidationSchema = Yup.object().shape({
username: Yup.string().required(i18next.t('login.usernameRequired')),
password: Yup.string().required(i18next.t('login.passwordRequired')),
username: Yup.string().required(i18next.t("login.usernameRequired")),
password: Yup.string().required(i18next.t("login.passwordRequired")),
}); });


const LoginPage = ({ history }) => { const LoginPage = ({ history }) => {
// }, [history, tokens]); // }, [history, tokens]);


const isLoading = useSelector( const isLoading = useSelector(
selectIsLoadingByActionType(LOGIN_USER_LOADING),
selectIsLoadingByActionType(LOGIN_USER_LOADING)
); );
const handleApiResponseSuccess =()=>{
const handleApiResponseSuccess = () => {
history.push({ history.push({
pathname: HOME_PAGE, pathname: HOME_PAGE,
state: { state: {
from: history.location.pathname, from: history.location.pathname,
}, },
}); });
}
};
const handleSubmit = (values) => { const handleSubmit = (values) => {
// destructure value as username.
const { username: Username } = values;
const { password: Password } = values;
dispatch(clearLoginErrors());
dispatch(
fetchUser({
Username,
Password,
handleApiResponseSuccess
},
),
);
// destructure value as username.
const { username: Username } = values;
const { password: Password } = values;
dispatch(clearLoginErrors());
dispatch(
fetchUser({
Username,
Password,
handleApiResponseSuccess,
})
);
}; };


return ( return (
<Auth> <Auth>
<AuthCard
title="Log In"
isLoading={isLoading}
>
<AuthCard title="Log In" isLoading={isLoading}>
<div className="c-login c-login--user"> <div className="c-login c-login--user">
<div className="c-login__form"> <div className="c-login__form">
<Formik <Formik
initialValues={{ initialValues={{
username: '',
password: '',
username: "",
password: "",
}} }}
onSubmit={handleSubmit} onSubmit={handleSubmit}
validationSchema={LoginValidationSchema} validationSchema={LoginValidationSchema}
{({ values }) => ( {({ values }) => (
<Form> <Form>
<Field <Field
label={t('common.labelUsername')}
label={t("common.labelUsername")}
value={values.username.value} value={values.username.value}
component={TextField} component={TextField}
name="username" name="username"
<Field <Field
label={ label={
<div className="c-login--password__label"> <div className="c-login--password__label">
{t('common.labelPassword')}
{t("common.labelPassword")}
</div> </div>
} }
link={ link={
<NavLink
to={FORGOT_PASSWORD_PAGE}
>
{t('login.forgotYourPassword')}
</NavLink>
<NavLink to={FORGOT_PASSWORD_PAGE}>
{t("login.forgotYourPassword")}
</NavLink>
} }
name="password" name="password"
component={PasswordField} component={PasswordField}
variant="primary" variant="primary"
type="submit" type="submit"
> >
{t('common.continue')}
{t("common.continue")}
</Button> </Button>
</Form> </Form>
)} )}
</Formik> </Formik>
</div> </div>
</div> </div>
</AuthCard>
</Auth>
</AuthCard>
</Auth>
); );
}; };



+ 12
- 11
src/pages/LoginPage/LoginPageMUI.js Просмотреть файл

import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { clearLoginErrors, fetchUser } from "store/actions/login/loginActions";
import { selectLoginError } from "store/selectors/loginSelectors";
import { import {
clearLoginErrors,
fetchUser,
} from "../../store/actions/login/loginActions";
import { selectLoginError } from "../../store/selectors/loginSelectors";
import { FORGOT_PASSWORD_PAGE, HOME_PAGE, REGISTER_PAGE } from "../../constants/pages";
FORGOT_PASSWORD_PAGE,
HOME_PAGE,
REGISTER_PAGE,
} from "constants/pages";
import { import {
Box, Box,
Button, Button,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import { Visibility, VisibilityOff } from "@mui/icons-material"; import { Visibility, VisibilityOff } from "@mui/icons-material";
import Backdrop from "../../components/MUI/BackdropComponent";
import ErrorMessage from "../../components/MUI/ErrorMessageComponent";
import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
import { LOGIN_USER_SCOPE } from "../../store/actions/login/loginActionConstants";
import loginValidation from "../../validations/loginValidation";
import loginInitialValues from "../../initialValues/loginInitialValues";
import Backdrop from "components/MUI/BackdropComponent";
import ErrorMessage from "components/MUI/ErrorMessageComponent";
import { selectIsLoadingByActionType } from "store/selectors/loadingSelectors";
import { LOGIN_USER_SCOPE } from "store/actions/login/loginActionConstants";
import loginValidation from "validations/loginValidation";
import loginInitialValues from "initialValues/loginInitialValues";
import GoogleIcon from "@mui/icons-material/Google"; import GoogleIcon from "@mui/icons-material/Google";


const LoginPage = ({ history }) => { const LoginPage = ({ history }) => {

+ 10
- 15
src/pages/RegisterPage/RegisterPageMUI.js Просмотреть файл

import { import {
clearRegisterErrors, clearRegisterErrors,
registerUser, registerUser,
} from "../../store/actions/register/registerActions";
import { selectRegisterError } from "../../store/selectors/registerSelectors";
import {
FORGOT_PASSWORD_PAGE,
HOME_PAGE,
LOGIN_PAGE,
} from "../../constants/pages";
} from "store/actions/register/registerActions";
import { selectRegisterError } from "store/selectors/registerSelectors";
import { FORGOT_PASSWORD_PAGE, LOGIN_PAGE } from "constants/pages";
import { import {
Box, Box,
Button, Button,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import { Visibility, VisibilityOff } from "@mui/icons-material"; import { Visibility, VisibilityOff } from "@mui/icons-material";
import Backdrop from "../../components/MUI/BackdropComponent";
import ErrorMessage from "../../components/MUI/ErrorMessageComponent";
import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
import { LOGIN_USER_SCOPE } from "../../store/actions/login/loginActionConstants";
import Backdrop from "components/MUI/BackdropComponent";
import ErrorMessage from "components/MUI/ErrorMessageComponent";
import { selectIsLoadingByActionType } from "store/selectors/loadingSelectors";
import GoogleIcon from "@mui/icons-material/Google"; import GoogleIcon from "@mui/icons-material/Google";
import registerInitialValues from "../../initialValues/registerInitialValues";
import registerValidation from "../../validations/registerValidation";
import { REGISTER_USER_SCOPE } from "../../store/actions/register/registerActionConstants";
import { makeToastMessage } from "../../util/helpers/toastMessage";
import registerInitialValues from "initialValues/registerInitialValues";
import registerValidation from "validations/registerValidation";
import { REGISTER_USER_SCOPE } from "store/actions/register/registerActionConstants";
import { makeToastMessage } from "util/helpers/toastMessage";


const RegisterPage = ({ history }) => { const RegisterPage = ({ history }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();

+ 3
- 2
src/store/saga/loginSaga.js Просмотреть файл

REFRESH_TOKEN_CONST, REFRESH_TOKEN_CONST,
} from "../../constants/localStorage"; } from "../../constants/localStorage";
import { import {
authScopeClearHelper,
authScopeStringGetHelper, authScopeStringGetHelper,
authScopeRemoveHelper, authScopeRemoveHelper,
authScopeSetHelper, authScopeSetHelper,
} catch (error) { } catch (error) {
console.log(error); // eslint-disable-line console.log(error); // eslint-disable-line
} finally { } finally {
yield call(authScopeClearHelper);
// yield call(authScopeClearHelper);
yield call(authScopeRemoveHelper, JWT_TOKEN);
yield call(authScopeRemoveHelper, JWT_REFRESH_TOKEN);
yield call(removeHeaderToken); yield call(removeHeaderToken);
yield put(resetLoginState()); yield put(resetLoginState());
yield call(history.replace, LOGIN_PAGE); yield call(history.replace, LOGIN_PAGE);

+ 1
- 1
src/util/helpers/authScopeHelpers.js Просмотреть файл

import { SESSION_STORAGE_SCOPE } from '../../constants/sessionStorage';
import { SESSION_STORAGE_SCOPE } from 'constants/sessionStorage';


export function authScopeGetHelper(key) { export function authScopeGetHelper(key) {
if (sessionStorage.getItem(SESSION_STORAGE_SCOPE)) { if (sessionStorage.getItem(SESSION_STORAGE_SCOPE)) {

+ 11145
- 11564
yarn.lock
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


Загрузка…
Отмена
Сохранить