浏览代码

Path Alias, Theme fix

master
Lazar Kostic 2 年前
父节点
当前提交
8f2cfc3204

+ 15
- 13
.eslintrc 查看文件

@@ -1,14 +1,13 @@
{
"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": {
"react/jsx-filename-extension": "off",
"react/jsx-props-no-spreading": "off",
@@ -21,8 +20,11 @@
"no-use-before-define": "off",
"no-template-curly-in-string": "off",
"react-hooks/exhaustive-deps": "warn",
"prettier/prettier": ["error", {
"endOfLine":"auto"
}]
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
]
}
}

+ 20
- 19
.eslintrc.json 查看文件

@@ -1,22 +1,23 @@
{
"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 查看文件

@@ -0,0 +1,6 @@
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}

+ 4
- 4
src/components/InputFields/BaseInputField.js 查看文件

@@ -2,10 +2,10 @@ import React, { useEffect, useState, useRef } from 'react';
import PropTypes from 'prop-types';
import { ErrorMessage } from 'formik';
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 = ({
type,

+ 2
- 2
src/components/InputFields/Checkbox.js 查看文件

@@ -1,7 +1,7 @@
import React from 'react';
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 }) => (
<label htmlFor={name} className={`c-checkbox ${className || ''}`}>

+ 12
- 12
src/components/InputFields/CurrencyField.js 查看文件

@@ -1,15 +1,15 @@
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 {
PLUS_SYMBOL,
MINUS_SYMBOL,
NUMPAD_MINUS_SYMBOL,
NUMPAD_PLUS_SYMBOL,
K_KEYCODE,
} from '../../constants/keyCodeConstants';
} from "constants/keyCodeConstants";

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

if (meta.error && meta.touched) {
style += ` c-currency-field--error`;
@@ -60,11 +60,11 @@ const CurrencyField = ({

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

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

return (
@@ -79,7 +79,7 @@ const CurrencyField = ({
{...props}
prefix={prefixSymbol()}
onValueChange={(value) => {
onChange(value ? Number(value) : '');
onChange(value ? Number(value) : "");
}}
onKeyDown={(event) => onKeydownHandler(event)}
ref={inputField}
@@ -91,7 +91,7 @@ const CurrencyField = ({
{...props}
prefix={prefixSymbol()}
onValueChange={(value) => {
onChange(value ? Number(value) : '');
onChange(value ? Number(value) : "");
}}
onKeyDown={(event) => onKeydownHandler(event)}
ref={inputField}

+ 1
- 1
src/components/InputFields/NumberField.js 查看文件

@@ -12,7 +12,7 @@ import {
NUMPAD_PLUS_SYMBOL,
DOWN_ARROW_KEYCODE,
UP_ARROW_KEYCODE,
} from '../../constants/keyCodeConstants';
} from 'constants/keyCodeConstants';

const NumberField = ({
field,

+ 2
- 2
src/components/InputFields/Radio.js 查看文件

@@ -1,7 +1,7 @@
import React from 'react';
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 = ({
className,

+ 3
- 4
src/components/InputFields/Search.js 查看文件

@@ -1,12 +1,11 @@
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 = ({
field,
form,
label,
placeholder,
disabled,
className,

+ 1
- 1
src/components/InputFields/SelectField.js 查看文件

@@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import Select, { components, createFilter } from 'react-select';
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 = ({
label,

+ 1
- 1
src/components/InputFields/TextField.js 查看文件

@@ -7,7 +7,7 @@ import {
TAB_KEYCODE,
RIGHT_ARROW_KEYCODE,
LEFT_ARROW_KEYCODE,
} from '../../constants/keyCodeConstants';
} from 'constants/keyCodeConstants';

const TextField = ({
field,

+ 164
- 165
src/components/MUI/Examples/PagingSortingFilteringExample.js 查看文件

@@ -1,183 +1,182 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState } from "react";
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 { useDispatch, useSelector, batch } from 'react-redux';
import useDebounce from '../../../hooks/useDebounceHook';
import { useDispatch, useSelector, batch } from "react-redux";
import useDebounce from "hooks/useDebounceHook";
import {
itemsSelector,
pageSelector,
itemsPerPageSelector,
countSelector,
sortSelector,
} from '../../../store/selectors/randomDataSelectors';
itemsSelector,
pageSelector,
itemsPerPageSelector,
countSelector,
sortSelector,
} from "store/selectors/randomDataSelectors";
import {
loadData,
updatePage,
updateItemsPerPage,
updateFilter,
updateSort,
} from '../../../store/actions/randomData/randomDataActions';
loadData,
updatePage,
updateItemsPerPage,
updateFilter,
updateSort,
} from "store/actions/randomData/randomDataActions";

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;

+ 145
- 145
src/components/MUI/Examples/PagingSortingFilteringExampleServerSide.js 查看文件

@@ -1,159 +1,159 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState } from "react";
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 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 [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;

+ 2
- 2
src/components/MUI/NavbarComponent.js 查看文件

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

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

+ 5
- 6
src/components/Router/PrivateRoute.js 查看文件

@@ -1,9 +1,8 @@
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 dispatch = useDispatch();

+ 1
- 1
src/context/ColorModeContext.js 查看文件

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

export const ColorModeContext = createContext();


+ 2
- 2
src/context/RandomDataContext.js 查看文件

@@ -1,7 +1,7 @@
import React, { createContext, useContext, useState } from 'react';
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) =>
getRequest('/items', {

+ 2
- 2
src/hooks/useToggleColorMode.js 查看文件

@@ -3,8 +3,8 @@ import { createTheme } from "@mui/material/styles";
import {
authScopeSetHelper,
authScopeStringGetHelper,
} from "../util/helpers/authScopeHelpers";
import selectedTheme from "../themes";
} from "util/helpers/authScopeHelpers";
import selectedTheme from "themes";

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

+ 13
- 11
src/index.js 查看文件

@@ -1,24 +1,26 @@
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(
<HelmetProvider>
<React.StrictMode>
<Provider store={store}>
<ColorModeProvider>
<App />
<CssBaseline />
<App />
</ColorModeProvider>
</Provider>
</React.StrictMode>
</HelmetProvider>,
document.getElementById('root'),
document.getElementById("root")
);

+ 5
- 5
src/pages/AuthCallback/AuthCallback.js 查看文件

@@ -1,13 +1,13 @@
import React, { useEffect } from "react";
import { useLocation } from "react-router-dom";
import { HOME_PAGE } from "../../constants/pages";
import { HOME_PAGE } from "constants/pages";
import PropTypes from "prop-types";
import { useParams } from "react-router-dom";
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 }) {
const dispatch = useDispatch();

+ 2
- 2
src/pages/ErrorPages/NotFoundPage.js 查看文件

@@ -1,7 +1,7 @@
import React from 'react';
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 { t } = useTranslation();

+ 5
- 5
src/pages/ForgotPasswordPage/ForgotPasswordPage.js 查看文件

@@ -3,12 +3,12 @@ import { Formik, Form, Field } from 'formik';
import { useTranslation } from 'react-i18next';
import * as Yup from 'yup';
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({
email: Yup.string().required(

+ 79
- 79
src/pages/ForgotPasswordPage/ForgotPasswordPageMUI.js 查看文件

@@ -1,88 +1,88 @@
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 {
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 { 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;

+ 7
- 7
src/pages/HomePage/HomePageMUI.js 查看文件

@@ -1,12 +1,12 @@
import React from "react";
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 getPosts = async () => {

+ 45
- 58
src/pages/LoginPage/LoginPage.js 查看文件

@@ -1,32 +1,25 @@
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({
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 }) => {
@@ -46,43 +39,39 @@ const LoginPage = ({ history }) => {
// }, [history, tokens]);

const isLoading = useSelector(
selectIsLoadingByActionType(LOGIN_USER_LOADING),
selectIsLoadingByActionType(LOGIN_USER_LOADING)
);
const handleApiResponseSuccess =()=>{
const handleApiResponseSuccess = () => {
history.push({
pathname: HOME_PAGE,
state: {
from: history.location.pathname,
},
});
}
};
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 (
<Auth>
<AuthCard
title="Log In"
isLoading={isLoading}
>
<AuthCard title="Log In" isLoading={isLoading}>
<div className="c-login c-login--user">
<div className="c-login__form">
<Formik
initialValues={{
username: '',
password: '',
username: "",
password: "",
}}
onSubmit={handleSubmit}
validationSchema={LoginValidationSchema}
@@ -92,7 +81,7 @@ const LoginPage = ({ history }) => {
{({ values }) => (
<Form>
<Field
label={t('common.labelUsername')}
label={t("common.labelUsername")}
value={values.username.value}
component={TextField}
name="username"
@@ -100,15 +89,13 @@ const LoginPage = ({ history }) => {
<Field
label={
<div className="c-login--password__label">
{t('common.labelPassword')}
{t("common.labelPassword")}
</div>
}
link={
<NavLink
to={FORGOT_PASSWORD_PAGE}
>
{t('login.forgotYourPassword')}
</NavLink>
<NavLink to={FORGOT_PASSWORD_PAGE}>
{t("login.forgotYourPassword")}
</NavLink>
}
name="password"
component={PasswordField}
@@ -121,15 +108,15 @@ const LoginPage = ({ history }) => {
variant="primary"
type="submit"
>
{t('common.continue')}
{t("common.continue")}
</Button>
</Form>
)}
</Formik>
</div>
</div>
</AuthCard>
</Auth>
</AuthCard>
</Auth>
);
};


+ 12
- 11
src/pages/LoginPage/LoginPageMUI.js 查看文件

@@ -5,12 +5,13 @@ import { useFormik } from "formik";
import { useDispatch, useSelector } from "react-redux";
import { NavLink } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { clearLoginErrors, fetchUser } from "store/actions/login/loginActions";
import { selectLoginError } from "store/selectors/loginSelectors";
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 {
Box,
Button,
@@ -23,12 +24,12 @@ import {
Typography,
} from "@mui/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";

const LoginPage = ({ history }) => {

+ 10
- 15
src/pages/RegisterPage/RegisterPageMUI.js 查看文件

@@ -8,13 +8,9 @@ import { useTranslation } from "react-i18next";
import {
clearRegisterErrors,
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 {
Box,
Button,
@@ -27,15 +23,14 @@ import {
Typography,
} from "@mui/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 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 dispatch = useDispatch();

+ 3
- 2
src/store/saga/loginSaga.js 查看文件

@@ -23,7 +23,6 @@ import {
REFRESH_TOKEN_CONST,
} from "../../constants/localStorage";
import {
authScopeClearHelper,
authScopeStringGetHelper,
authScopeRemoveHelper,
authScopeSetHelper,
@@ -83,7 +82,9 @@ function* logoutUser() {
} catch (error) {
console.log(error); // eslint-disable-line
} finally {
yield call(authScopeClearHelper);
// yield call(authScopeClearHelper);
yield call(authScopeRemoveHelper, JWT_TOKEN);
yield call(authScopeRemoveHelper, JWT_REFRESH_TOKEN);
yield call(removeHeaderToken);
yield put(resetLoginState());
yield call(history.replace, LOGIN_PAGE);

+ 1
- 1
src/util/helpers/authScopeHelpers.js 查看文件

@@ -1,4 +1,4 @@
import { SESSION_STORAGE_SCOPE } from '../../constants/sessionStorage';
import { SESSION_STORAGE_SCOPE } from 'constants/sessionStorage';

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

+ 11145
- 11564
yarn.lock
文件差异内容过多而无法显示
查看文件


正在加载...
取消
保存