Update @material-ui to v4
This commit is contained in:
parent
d84ba84e91
commit
74d6794679
276 changed files with 13094 additions and 13943 deletions
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -20308,9 +20308,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.5.3",
|
"version": "3.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz",
|
||||||
"integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g=="
|
"integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ=="
|
||||||
},
|
},
|
||||||
"ua-parser-js": {
|
"ua-parser-js": {
|
||||||
"version": "0.7.20",
|
"version": "0.7.20",
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
"react-sortable-tree": "^2.6.2",
|
"react-sortable-tree": "^2.6.2",
|
||||||
"react-svg": "^2.2.11",
|
"react-svg": "^2.2.11",
|
||||||
"slugify": "^1.3.4",
|
"slugify": "^1.3.4",
|
||||||
"typescript": "^3.5.3",
|
"typescript": "^3.6.4",
|
||||||
"url-join": "^4.0.1",
|
"url-join": "^4.0.1",
|
||||||
"use-react-router": "^1.0.7"
|
"use-react-router": "^1.0.7"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AttributeBulkDeleteDialog';
|
export { default } from "./AttributeBulkDeleteDialog";
|
||||||
export * from './AttributeBulkDeleteDialog';
|
export * from "./AttributeBulkDeleteDialog";
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AttributeDeleteDialog';
|
export { default } from "./AttributeDeleteDialog";
|
||||||
export * from './AttributeDeleteDialog';
|
export * from "./AttributeDeleteDialog";
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AttributeDetails';
|
export { default } from "./AttributeDetails";
|
||||||
export * from './AttributeDetails';
|
export * from "./AttributeDetails";
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AttributeList';
|
export { default } from "./AttributeList";
|
||||||
export * from './AttributeList';
|
export * from "./AttributeList";
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AttributeListPage';
|
export { default } from "./AttributeListPage";
|
||||||
export * from './AttributeListPage';
|
export * from "./AttributeListPage";
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AttributePage';
|
export { default } from "./AttributePage";
|
||||||
export * from './AttributePage';
|
export * from "./AttributePage";
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AttributeProperties';
|
export { default } from "./AttributeProperties";
|
||||||
export * from './AttributeProperties';
|
export * from "./AttributeProperties";
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AttributeValueDeleteDialog';
|
export { default } from "./AttributeValueDeleteDialog";
|
||||||
export * from './AttributeValueDeleteDialog';
|
export * from "./AttributeValueDeleteDialog";
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AttributeValueEditDialog';
|
export { default } from "./AttributeValueEditDialog";
|
||||||
export * from './AttributeValueEditDialog';
|
export * from "./AttributeValueEditDialog";
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AttributeValues';
|
export { default } from "./AttributeValues";
|
||||||
export * from './AttributeValues';
|
export * from "./AttributeValues";
|
||||||
|
|
|
@ -12,12 +12,12 @@ import {
|
||||||
export const PRODUCT_FILTERS_KEY = "productFilters";
|
export const PRODUCT_FILTERS_KEY = "productFilters";
|
||||||
|
|
||||||
export function getFilterVariables(
|
export function getFilterVariables(
|
||||||
params: AttributeListUrlFilters
|
params: AttributeListUrlFilters
|
||||||
): AttributeFilterInput {
|
): AttributeFilterInput {
|
||||||
return {
|
return {
|
||||||
search: params.query
|
search: params.query
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
deleteFilterTab,
|
deleteFilterTab,
|
||||||
|
|
|
@ -1,21 +1,26 @@
|
||||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = createStyles({
|
const useStyles = makeStyles(
|
||||||
root: {
|
{
|
||||||
alignItems: "center",
|
root: {
|
||||||
display: "flex",
|
alignItems: "center",
|
||||||
height: "100vh",
|
display: "flex",
|
||||||
justifyContent: "center"
|
height: "100vh",
|
||||||
}
|
justifyContent: "center"
|
||||||
});
|
}
|
||||||
const LoginLoading = withStyles(styles, { name: "LoginLoading" })(
|
},
|
||||||
({ classes }: WithStyles<typeof styles>) => (
|
{ name: "LoginLoading" }
|
||||||
|
);
|
||||||
|
const LoginLoading: React.FC = props => {
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<CircularProgress size={128} />
|
<CircularProgress size={128} />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
LoginLoading.displayName = "LoginLoading";
|
LoginLoading.displayName = "LoginLoading";
|
||||||
export default LoginLoading;
|
export default LoginLoading;
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
@ -19,8 +14,8 @@ export interface FormData {
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
buttonContainer: {
|
buttonContainer: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "flex-end"
|
justifyContent: "flex-end"
|
||||||
|
@ -42,89 +37,86 @@ const styles = theme =>
|
||||||
marginBottom: theme.spacing(3),
|
marginBottom: theme.spacing(3),
|
||||||
padding: theme.spacing(1.5)
|
padding: theme.spacing(1.5)
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{ name: "LoginCard" }
|
||||||
|
);
|
||||||
|
|
||||||
export interface LoginCardProps extends WithStyles<typeof styles> {
|
export interface LoginCardProps {
|
||||||
error: boolean;
|
error: boolean;
|
||||||
disableLoginButton: boolean;
|
disableLoginButton: boolean;
|
||||||
onPasswordRecovery: () => void;
|
onPasswordRecovery: () => void;
|
||||||
onSubmit?(event: FormData);
|
onSubmit?(event: FormData);
|
||||||
}
|
}
|
||||||
|
|
||||||
const LoginCard = withStyles(styles, { name: "LoginCard" })(
|
const LoginCard: React.FC<LoginCardProps> = props => {
|
||||||
({
|
const { error, disableLoginButton, onPasswordRecovery, onSubmit } = props;
|
||||||
classes,
|
|
||||||
error,
|
|
||||||
disableLoginButton,
|
|
||||||
onPasswordRecovery,
|
|
||||||
onSubmit
|
|
||||||
}: LoginCardProps) => {
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
return (
|
const classes = useStyles(props);
|
||||||
<Form initial={{ email: "", password: "" }} onSubmit={onSubmit}>
|
const intl = useIntl();
|
||||||
{({ change: handleChange, data, submit: handleSubmit }) => (
|
|
||||||
<>
|
return (
|
||||||
{error && (
|
<Form initial={{ email: "", password: "" }} onSubmit={onSubmit}>
|
||||||
<div className={classes.panel}>
|
{({ change: handleChange, data, submit: handleSubmit }) => (
|
||||||
<Typography variant="caption">
|
<>
|
||||||
<FormattedMessage defaultMessage="Sorry, your username and/or password are incorrect. Please try again." />
|
{error && (
|
||||||
</Typography>
|
<div className={classes.panel}>
|
||||||
</div>
|
<Typography variant="caption">
|
||||||
)}
|
<FormattedMessage defaultMessage="Sorry, your username and/or password are incorrect. Please try again." />
|
||||||
<TextField
|
</Typography>
|
||||||
autoFocus
|
|
||||||
fullWidth
|
|
||||||
autoComplete="username"
|
|
||||||
label={intl.formatMessage(commonMessages.email)}
|
|
||||||
name="email"
|
|
||||||
onChange={handleChange}
|
|
||||||
value={data.email}
|
|
||||||
inputProps={{
|
|
||||||
"data-tc": "email"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormSpacer />
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
autoComplete="password"
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Password"
|
|
||||||
})}
|
|
||||||
name="password"
|
|
||||||
onChange={handleChange}
|
|
||||||
type="password"
|
|
||||||
value={data.password}
|
|
||||||
inputProps={{
|
|
||||||
"data-tc": "password"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormSpacer />
|
|
||||||
<div className={classes.buttonContainer}>
|
|
||||||
<Button
|
|
||||||
className={classes.loginButton}
|
|
||||||
color="primary"
|
|
||||||
disabled={disableLoginButton}
|
|
||||||
variant="contained"
|
|
||||||
onClick={handleSubmit}
|
|
||||||
type="submit"
|
|
||||||
data-tc="submit"
|
|
||||||
>
|
|
||||||
<FormattedMessage defaultMessage="Login" description="button" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
<FormSpacer />
|
)}
|
||||||
<Typography className={classes.link} onClick={onPasswordRecovery}>
|
<TextField
|
||||||
<FormattedMessage
|
autoFocus
|
||||||
defaultMessage="Reset your password"
|
fullWidth
|
||||||
description="button"
|
autoComplete="username"
|
||||||
/>
|
label={intl.formatMessage(commonMessages.email)}
|
||||||
</Typography>
|
name="email"
|
||||||
</>
|
onChange={handleChange}
|
||||||
)}
|
value={data.email}
|
||||||
</Form>
|
inputProps={{
|
||||||
);
|
"data-tc": "email"
|
||||||
}
|
}}
|
||||||
);
|
/>
|
||||||
|
<FormSpacer />
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
autoComplete="password"
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Password"
|
||||||
|
})}
|
||||||
|
name="password"
|
||||||
|
onChange={handleChange}
|
||||||
|
type="password"
|
||||||
|
value={data.password}
|
||||||
|
inputProps={{
|
||||||
|
"data-tc": "password"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormSpacer />
|
||||||
|
<div className={classes.buttonContainer}>
|
||||||
|
<Button
|
||||||
|
className={classes.loginButton}
|
||||||
|
color="primary"
|
||||||
|
disabled={disableLoginButton}
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
type="submit"
|
||||||
|
data-tc="submit"
|
||||||
|
>
|
||||||
|
<FormattedMessage defaultMessage="Login" description="button" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<FormSpacer />
|
||||||
|
<Typography className={classes.link} onClick={onPasswordRecovery}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Reset your password"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
};
|
||||||
LoginCard.displayName = "LoginCard";
|
LoginCard.displayName = "LoginCard";
|
||||||
export default LoginCard;
|
export default LoginCard;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { PermissionEnum } from '../types/globalTypes'
|
import { PermissionEnum } from "../types/globalTypes";
|
||||||
import { User } from "./types/User";
|
import { User } from "./types/User";
|
||||||
|
|
||||||
export const hasPermission = (permission: PermissionEnum, user: User) =>
|
export const hasPermission = (permission: PermissionEnum, user: User) =>
|
||||||
|
|
|
@ -4,19 +4,14 @@ import DialogActions from "@material-ui/core/DialogActions";
|
||||||
import DialogContent from "@material-ui/core/DialogContent";
|
import DialogContent from "@material-ui/core/DialogContent";
|
||||||
import DialogContentText from "@material-ui/core/DialogContentText";
|
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import { buttonMessages } from "@saleor/intl";
|
import { buttonMessages } from "@saleor/intl";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
deleteButton: {
|
deleteButton: {
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: theme.palette.error.main
|
backgroundColor: theme.palette.error.main
|
||||||
|
@ -24,49 +19,58 @@ const styles = theme =>
|
||||||
backgroundColor: theme.palette.error.main,
|
backgroundColor: theme.palette.error.main,
|
||||||
color: theme.palette.error.contrastText
|
color: theme.palette.error.contrastText
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{
|
||||||
|
name: "CategoryDeleteDialog"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export interface CategoryDeleteDialogProps extends WithStyles<typeof styles> {
|
export interface CategoryDeleteDialogProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
onClose();
|
onClose();
|
||||||
onConfirm();
|
onConfirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CategoryDeleteDialog = withStyles(styles, {
|
const CategoryDeleteDialog: React.FC<CategoryDeleteDialogProps> = props => {
|
||||||
name: "CategoryDeleteDialog"
|
const { name, open, onConfirm, onClose } = props;
|
||||||
})(({ classes, name, open, onConfirm, onClose }: CategoryDeleteDialogProps) => (
|
|
||||||
<Dialog onClose={onClose} open={open}>
|
const classes = useStyles(props);
|
||||||
<DialogTitle>
|
|
||||||
<FormattedMessage
|
return (
|
||||||
defaultMessage="Delete category"
|
<Dialog onClose={onClose} open={open}>
|
||||||
description="dialog title"
|
<DialogTitle>
|
||||||
/>
|
|
||||||
</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
<DialogContentText>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Are you sure you want to delete {categoryName}?"
|
defaultMessage="Delete category"
|
||||||
description="delete category"
|
description="dialog title"
|
||||||
values={{
|
|
||||||
categoryName: <strong>{name}</strong>
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</DialogContentText>
|
</DialogTitle>
|
||||||
</DialogContent>
|
<DialogContent>
|
||||||
<DialogActions>
|
<DialogContentText>
|
||||||
<Button onClick={onClose}>
|
<FormattedMessage
|
||||||
<FormattedMessage {...buttonMessages.back} />
|
defaultMessage="Are you sure you want to delete {categoryName}?"
|
||||||
</Button>
|
description="delete category"
|
||||||
<Button
|
values={{
|
||||||
className={classes.deleteButton}
|
categoryName: <strong>{name}</strong>
|
||||||
variant="contained"
|
}}
|
||||||
onClick={onConfirm}
|
/>
|
||||||
>
|
</DialogContentText>
|
||||||
<FormattedMessage {...buttonMessages.save} />
|
</DialogContent>
|
||||||
</Button>
|
<DialogActions>
|
||||||
</DialogActions>
|
<Button onClick={onClose}>
|
||||||
</Dialog>
|
<FormattedMessage {...buttonMessages.back} />
|
||||||
));
|
</Button>
|
||||||
|
<Button
|
||||||
|
className={classes.deleteButton}
|
||||||
|
variant="contained"
|
||||||
|
onClick={onConfirm}
|
||||||
|
>
|
||||||
|
<FormattedMessage {...buttonMessages.save} />
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
CategoryDeleteDialog.displayName = "CategoryDeleteDialog";
|
CategoryDeleteDialog.displayName = "CategoryDeleteDialog";
|
||||||
export default CategoryDeleteDialog;
|
export default CategoryDeleteDialog;
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@material-ui/core/Table";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
|
@ -20,8 +15,8 @@ import TablePagination from "@saleor/components/TablePagination";
|
||||||
import { maybe, renderCollection } from "@saleor/misc";
|
import { maybe, renderCollection } from "@saleor/misc";
|
||||||
import { ListActions, ListProps } from "@saleor/types";
|
import { ListActions, ListProps } from "@saleor/types";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
[theme.breakpoints.up("lg")]: {
|
[theme.breakpoints.up("lg")]: {
|
||||||
colName: {
|
colName: {
|
||||||
width: 840
|
width: 840
|
||||||
|
@ -45,7 +40,9 @@ const styles = theme =>
|
||||||
tableRow: {
|
tableRow: {
|
||||||
cursor: "pointer"
|
cursor: "pointer"
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{ name: "CategoryList" }
|
||||||
|
);
|
||||||
|
|
||||||
interface CategoryListProps extends ListProps, ListActions {
|
interface CategoryListProps extends ListProps, ListActions {
|
||||||
categories?: CategoryFragment[];
|
categories?: CategoryFragment[];
|
||||||
|
@ -55,10 +52,9 @@ interface CategoryListProps extends ListProps, ListActions {
|
||||||
|
|
||||||
const numberOfColumns = 4;
|
const numberOfColumns = 4;
|
||||||
|
|
||||||
const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
const CategoryList: React.FC<CategoryListProps> = props => {
|
||||||
({
|
const {
|
||||||
categories,
|
categories,
|
||||||
classes,
|
|
||||||
disabled,
|
disabled,
|
||||||
settings,
|
settings,
|
||||||
pageInfo,
|
pageInfo,
|
||||||
|
@ -72,7 +68,11 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
||||||
onPreviousPage,
|
onPreviousPage,
|
||||||
onUpdateListSettings,
|
onUpdateListSettings,
|
||||||
onRowClick
|
onRowClick
|
||||||
}: CategoryListProps & WithStyles<typeof styles>) => (
|
} = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead
|
<TableHead
|
||||||
colSpan={numberOfColumns}
|
colSpan={numberOfColumns}
|
||||||
|
@ -175,7 +175,8 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
|
|
||||||
CategoryList.displayName = "CategoryList";
|
CategoryList.displayName = "CategoryList";
|
||||||
export default CategoryList;
|
export default CategoryList;
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@material-ui/core/Table";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
|
@ -25,8 +20,8 @@ import { ListActions, ListProps } from "@saleor/types";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { CategoryDetails_category_products_edges_node } from "../../types/CategoryDetails";
|
import { CategoryDetails_category_products_edges_node } from "../../types/CategoryDetails";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
[theme.breakpoints.up("lg")]: {
|
[theme.breakpoints.up("lg")]: {
|
||||||
colName: {
|
colName: {
|
||||||
width: "auto"
|
width: "auto"
|
||||||
|
@ -69,20 +64,20 @@ const styles = theme =>
|
||||||
textRight: {
|
textRight: {
|
||||||
textAlign: "right"
|
textAlign: "right"
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{
|
||||||
|
name: "CategoryProductList"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
interface CategoryProductListProps
|
interface CategoryProductListProps extends ListProps, ListActions {
|
||||||
extends ListProps,
|
|
||||||
ListActions,
|
|
||||||
WithStyles<typeof styles> {
|
|
||||||
products: CategoryDetails_category_products_edges_node[];
|
products: CategoryDetails_category_products_edges_node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CategoryProductList = withStyles(styles, {
|
export const CategoryProductList: React.FC<
|
||||||
name: "CategoryProductList"
|
CategoryProductListProps
|
||||||
})(
|
> = props => {
|
||||||
({
|
const {
|
||||||
classes,
|
|
||||||
disabled,
|
disabled,
|
||||||
isChecked,
|
isChecked,
|
||||||
pageInfo,
|
pageInfo,
|
||||||
|
@ -94,150 +89,150 @@ export const CategoryProductList = withStyles(styles, {
|
||||||
onNextPage,
|
onNextPage,
|
||||||
onPreviousPage,
|
onPreviousPage,
|
||||||
onRowClick
|
onRowClick
|
||||||
}: CategoryProductListProps) => {
|
} = props;
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const numberOfColumns = 5;
|
const classes = useStyles(props);
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
const numberOfColumns = 5;
|
||||||
<div className={classes.tableContainer}>
|
|
||||||
<Table className={classes.table}>
|
|
||||||
<colgroup>
|
|
||||||
<col />
|
|
||||||
<col className={classes.colName} />
|
|
||||||
<col className={classes.colType} />
|
|
||||||
<col className={classes.colPublished} />
|
|
||||||
<col className={classes.colPrice} />
|
|
||||||
</colgroup>
|
|
||||||
<TableHead
|
|
||||||
colSpan={numberOfColumns}
|
|
||||||
selected={selected}
|
|
||||||
disabled={disabled}
|
|
||||||
items={products}
|
|
||||||
toggleAll={toggleAll}
|
|
||||||
toolbar={toolbar}
|
|
||||||
>
|
|
||||||
<TableCell className={classes.colName}>
|
|
||||||
<span className={classes.colNameHeader}>
|
|
||||||
<FormattedMessage defaultMessage="Name" description="product" />
|
|
||||||
</span>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colType}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Type"
|
|
||||||
description="product type"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colPublished}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Published"
|
|
||||||
description="product status"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colPrice}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Price"
|
|
||||||
description="product price"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
</TableHead>
|
|
||||||
<TableFooter>
|
|
||||||
<TableRow>
|
|
||||||
<TablePagination
|
|
||||||
colSpan={numberOfColumns}
|
|
||||||
hasNextPage={
|
|
||||||
pageInfo && !disabled ? pageInfo.hasNextPage : false
|
|
||||||
}
|
|
||||||
onNextPage={onNextPage}
|
|
||||||
hasPreviousPage={
|
|
||||||
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
|
||||||
}
|
|
||||||
onPreviousPage={onPreviousPage}
|
|
||||||
/>
|
|
||||||
</TableRow>
|
|
||||||
</TableFooter>
|
|
||||||
<TableBody>
|
|
||||||
{renderCollection(
|
|
||||||
products,
|
|
||||||
product => {
|
|
||||||
const isSelected = product ? isChecked(product.id) : false;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow
|
<div className={classes.tableContainer}>
|
||||||
selected={isSelected}
|
<Table className={classes.table}>
|
||||||
hover={!!product}
|
<colgroup>
|
||||||
key={product ? product.id : "skeleton"}
|
<col />
|
||||||
onClick={product && onRowClick(product.id)}
|
<col className={classes.colName} />
|
||||||
className={classes.link}
|
<col className={classes.colType} />
|
||||||
|
<col className={classes.colPublished} />
|
||||||
|
<col className={classes.colPrice} />
|
||||||
|
</colgroup>
|
||||||
|
<TableHead
|
||||||
|
colSpan={numberOfColumns}
|
||||||
|
selected={selected}
|
||||||
|
disabled={disabled}
|
||||||
|
items={products}
|
||||||
|
toggleAll={toggleAll}
|
||||||
|
toolbar={toolbar}
|
||||||
|
>
|
||||||
|
<TableCell className={classes.colName}>
|
||||||
|
<span className={classes.colNameHeader}>
|
||||||
|
<FormattedMessage defaultMessage="Name" description="product" />
|
||||||
|
</span>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colType}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Type"
|
||||||
|
description="product type"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colPublished}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Published"
|
||||||
|
description="product status"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colPrice}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Price"
|
||||||
|
description="product price"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
</TableHead>
|
||||||
|
<TableFooter>
|
||||||
|
<TableRow>
|
||||||
|
<TablePagination
|
||||||
|
colSpan={numberOfColumns}
|
||||||
|
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||||
|
onNextPage={onNextPage}
|
||||||
|
hasPreviousPage={
|
||||||
|
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
||||||
|
}
|
||||||
|
onPreviousPage={onPreviousPage}
|
||||||
|
/>
|
||||||
|
</TableRow>
|
||||||
|
</TableFooter>
|
||||||
|
<TableBody>
|
||||||
|
{renderCollection(
|
||||||
|
products,
|
||||||
|
product => {
|
||||||
|
const isSelected = product ? isChecked(product.id) : false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow
|
||||||
|
selected={isSelected}
|
||||||
|
hover={!!product}
|
||||||
|
key={product ? product.id : "skeleton"}
|
||||||
|
onClick={product && onRowClick(product.id)}
|
||||||
|
className={classes.link}
|
||||||
|
>
|
||||||
|
<TableCell padding="checkbox">
|
||||||
|
<Checkbox
|
||||||
|
checked={isSelected}
|
||||||
|
disabled={disabled}
|
||||||
|
disableClickPropagation
|
||||||
|
onChange={() => toggle(product.id)}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCellAvatar
|
||||||
|
className={classes.colName}
|
||||||
|
thumbnail={maybe(() => product.thumbnail.url)}
|
||||||
>
|
>
|
||||||
<TableCell padding="checkbox">
|
{product ? product.name : <Skeleton />}
|
||||||
<Checkbox
|
</TableCellAvatar>
|
||||||
checked={isSelected}
|
<TableCell className={classes.colType}>
|
||||||
disabled={disabled}
|
{product && product.productType ? (
|
||||||
disableClickPropagation
|
product.productType.name
|
||||||
onChange={() => toggle(product.id)}
|
) : (
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colPublished}>
|
||||||
|
{product &&
|
||||||
|
maybe(() => product.isAvailable !== undefined) ? (
|
||||||
|
<StatusLabel
|
||||||
|
label={
|
||||||
|
product.isAvailable
|
||||||
|
? intl.formatMessage({
|
||||||
|
defaultMessage: "Published",
|
||||||
|
description: "product",
|
||||||
|
id: "productStatusLabel"
|
||||||
|
})
|
||||||
|
: intl.formatMessage({
|
||||||
|
defaultMessage: "Not published",
|
||||||
|
description: "product"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
status={product.isAvailable ? "success" : "error"}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
) : (
|
||||||
<TableCellAvatar
|
<Skeleton />
|
||||||
className={classes.colName}
|
)}
|
||||||
thumbnail={maybe(() => product.thumbnail.url)}
|
</TableCell>
|
||||||
>
|
<TableCell className={classes.colPrice}>
|
||||||
{product ? product.name : <Skeleton />}
|
{maybe(() => product.basePrice) &&
|
||||||
</TableCellAvatar>
|
maybe(() => product.basePrice.amount) !== undefined &&
|
||||||
<TableCell className={classes.colType}>
|
maybe(() => product.basePrice.currency) !== undefined ? (
|
||||||
{product && product.productType ? (
|
<Money money={product.basePrice} />
|
||||||
product.productType.name
|
) : (
|
||||||
) : (
|
<Skeleton />
|
||||||
<Skeleton />
|
)}
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colPublished}>
|
|
||||||
{product &&
|
|
||||||
maybe(() => product.isAvailable !== undefined) ? (
|
|
||||||
<StatusLabel
|
|
||||||
label={
|
|
||||||
product.isAvailable
|
|
||||||
? intl.formatMessage({
|
|
||||||
defaultMessage: "Published",
|
|
||||||
description: "product",
|
|
||||||
id: "productStatusLabel"
|
|
||||||
})
|
|
||||||
: intl.formatMessage({
|
|
||||||
defaultMessage: "Not published",
|
|
||||||
description: "product"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
status={product.isAvailable ? "success" : "error"}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colPrice}>
|
|
||||||
{maybe(() => product.basePrice) &&
|
|
||||||
maybe(() => product.basePrice.amount) !== undefined &&
|
|
||||||
maybe(() => product.basePrice.currency) !== undefined ? (
|
|
||||||
<Money money={product.basePrice} />
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
() => (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell colSpan={numberOfColumns}>
|
|
||||||
<FormattedMessage defaultMessage="No products found" />
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)
|
);
|
||||||
)}
|
},
|
||||||
</TableBody>
|
() => (
|
||||||
</Table>
|
<TableRow>
|
||||||
</div>
|
<TableCell colSpan={numberOfColumns}>
|
||||||
);
|
<FormattedMessage defaultMessage="No products found" />
|
||||||
}
|
</TableCell>
|
||||||
);
|
</TableRow>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
CategoryProductList.displayName = "CategoryProductList";
|
CategoryProductList.displayName = "CategoryProductList";
|
||||||
export default CategoryProductList;
|
export default CategoryProductList;
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
@ -19,8 +14,8 @@ import Skeleton from "@saleor/components/Skeleton";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { CollectionDetails_collection_backgroundImage } from "../../types/CollectionDetails";
|
import { CollectionDetails_collection_backgroundImage } from "../../types/CollectionDetails";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
PhotosIcon: {
|
PhotosIcon: {
|
||||||
height: "64px",
|
height: "64px",
|
||||||
margin: "0 auto",
|
margin: "0 auto",
|
||||||
|
@ -50,7 +45,11 @@ const styles = theme =>
|
||||||
position: "relative",
|
position: "relative",
|
||||||
width: 148
|
width: 148
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{
|
||||||
|
name: "CollectionImage"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export interface CollectionImageProps {
|
export interface CollectionImageProps {
|
||||||
data: {
|
data: {
|
||||||
|
@ -62,83 +61,78 @@ export interface CollectionImageProps {
|
||||||
onImageUpload: (file: File) => void;
|
onImageUpload: (file: File) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CollectionImage = withStyles(styles)(
|
export const CollectionImage: React.FC<CollectionImageProps> = props => {
|
||||||
({
|
const { data, onImageUpload, image, onChange, onImageDelete } = props;
|
||||||
classes,
|
|
||||||
data,
|
|
||||||
onImageUpload,
|
|
||||||
image,
|
|
||||||
onChange,
|
|
||||||
onImageDelete
|
|
||||||
}: CollectionImageProps & WithStyles<typeof styles>) => {
|
|
||||||
const anchor = React.useRef<HTMLInputElement>();
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const handleImageUploadButtonClick = () => anchor.current.click();
|
const anchor = React.useRef<HTMLInputElement>();
|
||||||
|
const classes = useStyles(props);
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
const handleImageUploadButtonClick = () => anchor.current.click();
|
||||||
<Card>
|
|
||||||
<CardTitle
|
return (
|
||||||
title={intl.formatMessage({
|
<Card>
|
||||||
defaultMessage: "Background Image (optional)",
|
<CardTitle
|
||||||
description: "section header"
|
title={intl.formatMessage({
|
||||||
})}
|
defaultMessage: "Background Image (optional)",
|
||||||
toolbar={
|
description: "section header"
|
||||||
<>
|
})}
|
||||||
<Button
|
toolbar={
|
||||||
variant="text"
|
|
||||||
color="primary"
|
|
||||||
onClick={handleImageUploadButtonClick}
|
|
||||||
>
|
|
||||||
<FormattedMessage {...commonMessages.uploadImage} />
|
|
||||||
</Button>
|
|
||||||
<input
|
|
||||||
className={classes.fileField}
|
|
||||||
id="fileUpload"
|
|
||||||
onChange={event => onImageUpload(event.target.files[0])}
|
|
||||||
type="file"
|
|
||||||
ref={anchor}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{image === undefined ? (
|
|
||||||
<CardContent>
|
|
||||||
<div>
|
|
||||||
<div className={classes.imageContainer}>
|
|
||||||
<Skeleton />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
) : image === null ? (
|
|
||||||
<ImageUpload onImageUpload={onImageUpload} />
|
|
||||||
) : (
|
|
||||||
<CardContent>
|
|
||||||
<ImageTile image={image} onImageDelete={onImageDelete} />
|
|
||||||
</CardContent>
|
|
||||||
)}
|
|
||||||
{image && (
|
|
||||||
<>
|
<>
|
||||||
<Hr />
|
<Button
|
||||||
<CardContent>
|
variant="text"
|
||||||
<TextField
|
color="primary"
|
||||||
name="backgroundImageAlt"
|
onClick={handleImageUploadButtonClick}
|
||||||
label={intl.formatMessage(commonMessages.description)}
|
>
|
||||||
helperText={intl.formatMessage({
|
<FormattedMessage {...commonMessages.uploadImage} />
|
||||||
defaultMessage: "(Optional)",
|
</Button>
|
||||||
description: "field is optional"
|
<input
|
||||||
})}
|
className={classes.fileField}
|
||||||
value={data.backgroundImageAlt}
|
id="fileUpload"
|
||||||
onChange={onChange}
|
onChange={event => onImageUpload(event.target.files[0])}
|
||||||
fullWidth
|
type="file"
|
||||||
multiline
|
ref={anchor}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
|
||||||
</>
|
</>
|
||||||
)}
|
}
|
||||||
</Card>
|
/>
|
||||||
);
|
{image === undefined ? (
|
||||||
}
|
<CardContent>
|
||||||
);
|
<div>
|
||||||
|
<div className={classes.imageContainer}>
|
||||||
|
<Skeleton />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
) : image === null ? (
|
||||||
|
<ImageUpload onImageUpload={onImageUpload} />
|
||||||
|
) : (
|
||||||
|
<CardContent>
|
||||||
|
<ImageTile image={image} onImageDelete={onImageDelete} />
|
||||||
|
</CardContent>
|
||||||
|
)}
|
||||||
|
{image && (
|
||||||
|
<>
|
||||||
|
<Hr />
|
||||||
|
<CardContent>
|
||||||
|
<TextField
|
||||||
|
name="backgroundImageAlt"
|
||||||
|
label={intl.formatMessage(commonMessages.description)}
|
||||||
|
helperText={intl.formatMessage({
|
||||||
|
defaultMessage: "(Optional)",
|
||||||
|
description: "field is optional"
|
||||||
|
})}
|
||||||
|
value={data.backgroundImageAlt}
|
||||||
|
onChange={onChange}
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
/>
|
||||||
|
</CardContent>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
CollectionImage.displayName = "CollectionImage";
|
CollectionImage.displayName = "CollectionImage";
|
||||||
export default CollectionImage;
|
export default CollectionImage;
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@material-ui/core/Table";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
|
@ -21,8 +16,8 @@ import { maybe, renderCollection } from "@saleor/misc";
|
||||||
import { ListActions, ListProps } from "@saleor/types";
|
import { ListActions, ListProps } from "@saleor/types";
|
||||||
import { CollectionList_collections_edges_node } from "../../types/CollectionList";
|
import { CollectionList_collections_edges_node } from "../../types/CollectionList";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
[theme.breakpoints.up("lg")]: {
|
[theme.breakpoints.up("lg")]: {
|
||||||
colAvailability: {
|
colAvailability: {
|
||||||
width: 240
|
width: 240
|
||||||
|
@ -42,20 +37,18 @@ const styles = theme =>
|
||||||
tableRow: {
|
tableRow: {
|
||||||
cursor: "pointer" as "pointer"
|
cursor: "pointer" as "pointer"
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{ name: "CollectionList" }
|
||||||
|
);
|
||||||
|
|
||||||
interface CollectionListProps
|
interface CollectionListProps extends ListProps, ListActions {
|
||||||
extends ListProps,
|
|
||||||
ListActions,
|
|
||||||
WithStyles<typeof styles> {
|
|
||||||
collections: CollectionList_collections_edges_node[];
|
collections: CollectionList_collections_edges_node[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const numberOfColumns = 5;
|
const numberOfColumns = 5;
|
||||||
|
|
||||||
const CollectionList = withStyles(styles, { name: "CollectionList" })(
|
const CollectionList: React.FC<CollectionListProps> = props => {
|
||||||
({
|
const {
|
||||||
classes,
|
|
||||||
collections,
|
collections,
|
||||||
disabled,
|
disabled,
|
||||||
settings,
|
settings,
|
||||||
|
@ -69,122 +62,121 @@ const CollectionList = withStyles(styles, { name: "CollectionList" })(
|
||||||
toggle,
|
toggle,
|
||||||
toggleAll,
|
toggleAll,
|
||||||
toolbar
|
toolbar
|
||||||
}: CollectionListProps) => {
|
} = props;
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
return (
|
const classes = useStyles(props);
|
||||||
<Table>
|
const intl = useIntl();
|
||||||
<TableHead
|
|
||||||
colSpan={numberOfColumns}
|
return (
|
||||||
selected={selected}
|
<Table>
|
||||||
disabled={disabled}
|
<TableHead
|
||||||
items={collections}
|
colSpan={numberOfColumns}
|
||||||
toggleAll={toggleAll}
|
selected={selected}
|
||||||
toolbar={toolbar}
|
disabled={disabled}
|
||||||
>
|
items={collections}
|
||||||
<TableCell className={classes.colName}>
|
toggleAll={toggleAll}
|
||||||
<FormattedMessage defaultMessage="Category Name" />
|
toolbar={toolbar}
|
||||||
</TableCell>
|
>
|
||||||
<TableCell className={classes.colProducts}>
|
<TableCell className={classes.colName}>
|
||||||
<FormattedMessage defaultMessage="No. of Products" />
|
<FormattedMessage defaultMessage="Category Name" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={classes.colAvailability}>
|
<TableCell className={classes.colProducts}>
|
||||||
<FormattedMessage
|
<FormattedMessage defaultMessage="No. of Products" />
|
||||||
defaultMessage="Availability"
|
</TableCell>
|
||||||
description="collection availability"
|
<TableCell className={classes.colAvailability}>
|
||||||
/>
|
<FormattedMessage
|
||||||
</TableCell>
|
defaultMessage="Availability"
|
||||||
</TableHead>
|
description="collection availability"
|
||||||
<TableFooter>
|
/>
|
||||||
<TableRow>
|
</TableCell>
|
||||||
<TablePagination
|
</TableHead>
|
||||||
colSpan={numberOfColumns}
|
<TableFooter>
|
||||||
settings={settings}
|
<TableRow>
|
||||||
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
<TablePagination
|
||||||
onNextPage={onNextPage}
|
colSpan={numberOfColumns}
|
||||||
onUpdateListSettings={onUpdateListSettings}
|
settings={settings}
|
||||||
hasPreviousPage={
|
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||||
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
onNextPage={onNextPage}
|
||||||
}
|
onUpdateListSettings={onUpdateListSettings}
|
||||||
onPreviousPage={onPreviousPage}
|
hasPreviousPage={
|
||||||
/>
|
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
||||||
</TableRow>
|
}
|
||||||
</TableFooter>
|
onPreviousPage={onPreviousPage}
|
||||||
<TableBody>
|
/>
|
||||||
{renderCollection(
|
</TableRow>
|
||||||
collections,
|
</TableFooter>
|
||||||
collection => {
|
<TableBody>
|
||||||
const isSelected = collection ? isChecked(collection.id) : false;
|
{renderCollection(
|
||||||
return (
|
collections,
|
||||||
<TableRow
|
collection => {
|
||||||
className={classes.tableRow}
|
const isSelected = collection ? isChecked(collection.id) : false;
|
||||||
hover={!!collection}
|
return (
|
||||||
onClick={collection ? onRowClick(collection.id) : undefined}
|
<TableRow
|
||||||
key={collection ? collection.id : "skeleton"}
|
className={classes.tableRow}
|
||||||
selected={isSelected}
|
hover={!!collection}
|
||||||
data-tc="id"
|
onClick={collection ? onRowClick(collection.id) : undefined}
|
||||||
data-tc-id={maybe(() => collection.id)}
|
key={collection ? collection.id : "skeleton"}
|
||||||
|
selected={isSelected}
|
||||||
|
data-tc="id"
|
||||||
|
data-tc-id={maybe(() => collection.id)}
|
||||||
|
>
|
||||||
|
<TableCell padding="checkbox">
|
||||||
|
<Checkbox
|
||||||
|
checked={isSelected}
|
||||||
|
disabled={disabled}
|
||||||
|
disableClickPropagation
|
||||||
|
onChange={() => toggle(collection.id)}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colName} data-tc="name">
|
||||||
|
{maybe<React.ReactNode>(() => collection.name, <Skeleton />)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colProducts}>
|
||||||
|
{maybe<React.ReactNode>(
|
||||||
|
() => collection.products.totalCount,
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
className={classes.colAvailability}
|
||||||
|
data-tc="published"
|
||||||
|
data-tc-published={maybe(() => collection.isPublished)}
|
||||||
>
|
>
|
||||||
<TableCell padding="checkbox">
|
{maybe(
|
||||||
<Checkbox
|
() => (
|
||||||
checked={isSelected}
|
<StatusLabel
|
||||||
disabled={disabled}
|
status={collection.isPublished ? "success" : "error"}
|
||||||
disableClickPropagation
|
label={
|
||||||
onChange={() => toggle(collection.id)}
|
collection.isPublished
|
||||||
/>
|
? intl.formatMessage({
|
||||||
</TableCell>
|
defaultMessage: "Published",
|
||||||
<TableCell className={classes.colName} data-tc="name">
|
description: "collection is published"
|
||||||
{maybe<React.ReactNode>(
|
})
|
||||||
() => collection.name,
|
: intl.formatMessage({
|
||||||
<Skeleton />
|
defaultMessage: "Not published",
|
||||||
)}
|
description: "collection is not published"
|
||||||
</TableCell>
|
})
|
||||||
<TableCell className={classes.colProducts}>
|
}
|
||||||
{maybe<React.ReactNode>(
|
/>
|
||||||
() => collection.products.totalCount,
|
),
|
||||||
<Skeleton />
|
<Skeleton />
|
||||||
)}
|
)}
|
||||||
</TableCell>
|
|
||||||
<TableCell
|
|
||||||
className={classes.colAvailability}
|
|
||||||
data-tc="published"
|
|
||||||
data-tc-published={maybe(() => collection.isPublished)}
|
|
||||||
>
|
|
||||||
{maybe(
|
|
||||||
() => (
|
|
||||||
<StatusLabel
|
|
||||||
status={collection.isPublished ? "success" : "error"}
|
|
||||||
label={
|
|
||||||
collection.isPublished
|
|
||||||
? intl.formatMessage({
|
|
||||||
defaultMessage: "Published",
|
|
||||||
description: "collection is published"
|
|
||||||
})
|
|
||||||
: intl.formatMessage({
|
|
||||||
defaultMessage: "Not published",
|
|
||||||
description: "collection is not published"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
() => (
|
|
||||||
<TableRow>
|
|
||||||
<TableCell colSpan={numberOfColumns}>
|
|
||||||
<FormattedMessage defaultMessage="No collections found" />
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)
|
);
|
||||||
)}
|
},
|
||||||
</TableBody>
|
() => (
|
||||||
</Table>
|
<TableRow>
|
||||||
);
|
<TableCell colSpan={numberOfColumns}>
|
||||||
}
|
<FormattedMessage defaultMessage="No collections found" />
|
||||||
);
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
CollectionList.displayName = "CollectionList";
|
CollectionList.displayName = "CollectionList";
|
||||||
export default CollectionList;
|
export default CollectionList;
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
import Card from "@material-ui/core/Card";
|
import Card from "@material-ui/core/Card";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@material-ui/core/Table";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
|
@ -29,13 +24,13 @@ import { maybe, renderCollection } from "../../../misc";
|
||||||
import { ListActions, PageListProps } from "../../../types";
|
import { ListActions, PageListProps } from "../../../types";
|
||||||
import { CollectionDetails_collection } from "../../types/CollectionDetails";
|
import { CollectionDetails_collection } from "../../types/CollectionDetails";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
colActions: {
|
colActions: {
|
||||||
"&:last-child": {
|
"&:last-child": {
|
||||||
paddingRight: 0
|
paddingRight: 0
|
||||||
},
|
},
|
||||||
width: 76 + theme.spacing(0.5)
|
width: 76 + theme.spacing(0.5)
|
||||||
},
|
},
|
||||||
colName: {
|
colName: {
|
||||||
paddingLeft: 0,
|
paddingLeft: 0,
|
||||||
|
@ -56,21 +51,19 @@ const styles = theme =>
|
||||||
tableRow: {
|
tableRow: {
|
||||||
cursor: "pointer"
|
cursor: "pointer"
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{ name: "CollectionProducts" }
|
||||||
|
);
|
||||||
|
|
||||||
export interface CollectionProductsProps
|
export interface CollectionProductsProps extends PageListProps, ListActions {
|
||||||
extends PageListProps,
|
|
||||||
ListActions,
|
|
||||||
WithStyles<typeof styles> {
|
|
||||||
collection: CollectionDetails_collection;
|
collection: CollectionDetails_collection;
|
||||||
onProductUnassign: (id: string, event: React.MouseEvent<any>) => void;
|
onProductUnassign: (id: string, event: React.MouseEvent<any>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const numberOfColumns = 5;
|
const numberOfColumns = 5;
|
||||||
|
|
||||||
const CollectionProducts = withStyles(styles, { name: "CollectionProducts" })(
|
const CollectionProducts: React.FC<CollectionProductsProps> = props => {
|
||||||
({
|
const {
|
||||||
classes,
|
|
||||||
collection,
|
collection,
|
||||||
disabled,
|
disabled,
|
||||||
onAdd,
|
onAdd,
|
||||||
|
@ -84,165 +77,165 @@ const CollectionProducts = withStyles(styles, { name: "CollectionProducts" })(
|
||||||
toggle,
|
toggle,
|
||||||
toggleAll,
|
toggleAll,
|
||||||
toolbar
|
toolbar
|
||||||
}: CollectionProductsProps) => {
|
} = props;
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
return (
|
const classes = useStyles(props);
|
||||||
<Card>
|
const intl = useIntl();
|
||||||
<CardTitle
|
|
||||||
title={
|
|
||||||
!!collection ? (
|
|
||||||
intl.formatMessage(
|
|
||||||
{
|
|
||||||
defaultMessage: "Products in {name}",
|
|
||||||
description: "products in collection"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: maybe(() => collection.name, "...")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
toolbar={
|
|
||||||
<Button
|
|
||||||
disabled={disabled}
|
|
||||||
variant="text"
|
|
||||||
color="primary"
|
|
||||||
onClick={onAdd}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Assign product"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Table className={classes.table}>
|
|
||||||
<TableHead
|
|
||||||
colSpan={numberOfColumns}
|
|
||||||
selected={selected}
|
|
||||||
disabled={disabled}
|
|
||||||
items={maybe(() =>
|
|
||||||
collection.products.edges.map(edge => edge.node)
|
|
||||||
)}
|
|
||||||
toggleAll={toggleAll}
|
|
||||||
toolbar={toolbar}
|
|
||||||
>
|
|
||||||
<TableCell className={classes.colName}>
|
|
||||||
<span className={classes.colNameLabel}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Name"
|
|
||||||
description="product name"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colType}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Type"
|
|
||||||
description="product type"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colPublished}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Published"
|
|
||||||
description="product is published"
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colActions} />
|
|
||||||
</TableHead>
|
|
||||||
<TableFooter>
|
|
||||||
<TableRow>
|
|
||||||
<TablePagination
|
|
||||||
colSpan={numberOfColumns}
|
|
||||||
hasNextPage={maybe(() => pageInfo.hasNextPage)}
|
|
||||||
onNextPage={onNextPage}
|
|
||||||
hasPreviousPage={maybe(() => pageInfo.hasPreviousPage)}
|
|
||||||
onPreviousPage={onPreviousPage}
|
|
||||||
/>
|
|
||||||
</TableRow>
|
|
||||||
</TableFooter>
|
|
||||||
<TableBody>
|
|
||||||
{renderCollection(
|
|
||||||
maybe(() => collection.products.edges.map(edge => edge.node)),
|
|
||||||
product => {
|
|
||||||
const isSelected = product ? isChecked(product.id) : false;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow
|
<Card>
|
||||||
className={classes.tableRow}
|
<CardTitle
|
||||||
hover={!!product}
|
title={
|
||||||
onClick={!!product ? onRowClick(product.id) : undefined}
|
!!collection ? (
|
||||||
key={product ? product.id : "skeleton"}
|
intl.formatMessage(
|
||||||
selected={isSelected}
|
{
|
||||||
>
|
defaultMessage: "Products in {name}",
|
||||||
<TableCell padding="checkbox">
|
description: "products in collection"
|
||||||
<Checkbox
|
|
||||||
checked={isSelected}
|
|
||||||
disabled={disabled}
|
|
||||||
disableClickPropagation
|
|
||||||
onChange={() => toggle(product.id)}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCellAvatar
|
|
||||||
className={classes.colName}
|
|
||||||
thumbnail={maybe(() => product.thumbnail.url)}
|
|
||||||
>
|
|
||||||
{maybe<React.ReactNode>(() => product.name, <Skeleton />)}
|
|
||||||
</TableCellAvatar>
|
|
||||||
<TableCell className={classes.colType}>
|
|
||||||
{maybe<React.ReactNode>(
|
|
||||||
() => product.productType.name,
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colPublished}>
|
|
||||||
{maybe(
|
|
||||||
() => (
|
|
||||||
<StatusLabel
|
|
||||||
label={
|
|
||||||
product.isPublished
|
|
||||||
? intl.formatMessage({
|
|
||||||
defaultMessage: "Published",
|
|
||||||
description: "product is published"
|
|
||||||
})
|
|
||||||
: intl.formatMessage({
|
|
||||||
defaultMessage: "Not published",
|
|
||||||
description: "product is not published"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
status={product.isPublished ? "success" : "error"}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.colActions}>
|
|
||||||
<IconButton
|
|
||||||
disabled={!product}
|
|
||||||
onClick={event => onProductUnassign(product.id, event)}
|
|
||||||
>
|
|
||||||
<DeleteIcon color="primary" />
|
|
||||||
</IconButton>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
() => (
|
{
|
||||||
<TableRow>
|
name: maybe(() => collection.name, "...")
|
||||||
<TableCell />
|
}
|
||||||
<TableCell colSpan={numberOfColumns}>
|
)
|
||||||
<FormattedMessage defaultMessage="No products found" />
|
) : (
|
||||||
|
<Skeleton />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
toolbar={
|
||||||
|
<Button
|
||||||
|
disabled={disabled}
|
||||||
|
variant="text"
|
||||||
|
color="primary"
|
||||||
|
onClick={onAdd}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Assign product"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Table className={classes.table}>
|
||||||
|
<TableHead
|
||||||
|
colSpan={numberOfColumns}
|
||||||
|
selected={selected}
|
||||||
|
disabled={disabled}
|
||||||
|
items={maybe(() => collection.products.edges.map(edge => edge.node))}
|
||||||
|
toggleAll={toggleAll}
|
||||||
|
toolbar={toolbar}
|
||||||
|
>
|
||||||
|
<TableCell className={classes.colName}>
|
||||||
|
<span className={classes.colNameLabel}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Name"
|
||||||
|
description="product name"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colType}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Type"
|
||||||
|
description="product type"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colPublished}>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Published"
|
||||||
|
description="product is published"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colActions} />
|
||||||
|
</TableHead>
|
||||||
|
<TableFooter>
|
||||||
|
<TableRow>
|
||||||
|
<TablePagination
|
||||||
|
colSpan={numberOfColumns}
|
||||||
|
hasNextPage={maybe(() => pageInfo.hasNextPage)}
|
||||||
|
onNextPage={onNextPage}
|
||||||
|
hasPreviousPage={maybe(() => pageInfo.hasPreviousPage)}
|
||||||
|
onPreviousPage={onPreviousPage}
|
||||||
|
/>
|
||||||
|
</TableRow>
|
||||||
|
</TableFooter>
|
||||||
|
<TableBody>
|
||||||
|
{renderCollection(
|
||||||
|
maybe(() => collection.products.edges.map(edge => edge.node)),
|
||||||
|
product => {
|
||||||
|
const isSelected = product ? isChecked(product.id) : false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow
|
||||||
|
className={classes.tableRow}
|
||||||
|
hover={!!product}
|
||||||
|
onClick={!!product ? onRowClick(product.id) : undefined}
|
||||||
|
key={product ? product.id : "skeleton"}
|
||||||
|
selected={isSelected}
|
||||||
|
>
|
||||||
|
<TableCell padding="checkbox">
|
||||||
|
<Checkbox
|
||||||
|
checked={isSelected}
|
||||||
|
disabled={disabled}
|
||||||
|
disableClickPropagation
|
||||||
|
onChange={() => toggle(product.id)}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCellAvatar
|
||||||
|
className={classes.colName}
|
||||||
|
thumbnail={maybe(() => product.thumbnail.url)}
|
||||||
|
>
|
||||||
|
{maybe<React.ReactNode>(() => product.name, <Skeleton />)}
|
||||||
|
</TableCellAvatar>
|
||||||
|
<TableCell className={classes.colType}>
|
||||||
|
{maybe<React.ReactNode>(
|
||||||
|
() => product.productType.name,
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colPublished}>
|
||||||
|
{maybe(
|
||||||
|
() => (
|
||||||
|
<StatusLabel
|
||||||
|
label={
|
||||||
|
product.isPublished
|
||||||
|
? intl.formatMessage({
|
||||||
|
defaultMessage: "Published",
|
||||||
|
description: "product is published"
|
||||||
|
})
|
||||||
|
: intl.formatMessage({
|
||||||
|
defaultMessage: "Not published",
|
||||||
|
description: "product is not published"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
status={product.isPublished ? "success" : "error"}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
<Skeleton />
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.colActions}>
|
||||||
|
<IconButton
|
||||||
|
disabled={!product}
|
||||||
|
onClick={event => onProductUnassign(product.id, event)}
|
||||||
|
>
|
||||||
|
<DeleteIcon color="primary" />
|
||||||
|
</IconButton>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)
|
);
|
||||||
)}
|
},
|
||||||
</TableBody>
|
() => (
|
||||||
</Table>
|
<TableRow>
|
||||||
</Card>
|
<TableCell />
|
||||||
);
|
<TableCell colSpan={numberOfColumns}>
|
||||||
}
|
<FormattedMessage defaultMessage="No products found" />
|
||||||
);
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
CollectionProducts.displayName = "CollectionProducts";
|
CollectionProducts.displayName = "CollectionProducts";
|
||||||
export default CollectionProducts;
|
export default CollectionProducts;
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
import Card from "@material-ui/core/Card";
|
import Card from "@material-ui/core/Card";
|
||||||
import CardContent from "@material-ui/core/CardContent";
|
import CardContent from "@material-ui/core/CardContent";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
@ -15,21 +10,23 @@ import { ControlledCheckbox } from "@saleor/components/ControlledCheckbox";
|
||||||
import { ShopInfo_shop_permissions } from "@saleor/components/Shop/types/ShopInfo";
|
import { ShopInfo_shop_permissions } from "@saleor/components/Shop/types/ShopInfo";
|
||||||
import Skeleton from "@saleor/components/Skeleton";
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
checkboxContainer: {
|
checkboxContainer: {
|
||||||
marginTop: theme.spacing()
|
marginTop: theme.spacing()
|
||||||
},
|
},
|
||||||
hr: {
|
hr: {
|
||||||
backgroundColor: theme.overrides.MuiCard.root.borderColor,
|
backgroundColor: theme.palette.divider,
|
||||||
border: "none",
|
border: "none",
|
||||||
height: 1,
|
height: 1,
|
||||||
marginBottom: 0,
|
marginBottom: 0,
|
||||||
marginTop: 0
|
marginTop: 0
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{ name: "AccountPermissions" }
|
||||||
|
);
|
||||||
|
|
||||||
interface AccountPermissionsProps extends WithStyles<typeof styles> {
|
interface AccountPermissionsProps {
|
||||||
permissions: ShopInfo_shop_permissions[];
|
permissions: ShopInfo_shop_permissions[];
|
||||||
data: {
|
data: {
|
||||||
hasFullAccess: boolean;
|
hasFullAccess: boolean;
|
||||||
|
@ -39,89 +36,85 @@ interface AccountPermissionsProps extends WithStyles<typeof styles> {
|
||||||
onChange: (event: React.ChangeEvent<any>, cb?: () => void) => void;
|
onChange: (event: React.ChangeEvent<any>, cb?: () => void) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AccountPermissions = withStyles(styles, { name: "AccountPermissions" })(
|
const AccountPermissions: React.FC<AccountPermissionsProps> = props => {
|
||||||
({
|
const { data, disabled, permissions, onChange } = props;
|
||||||
classes,
|
|
||||||
data,
|
|
||||||
disabled,
|
|
||||||
permissions,
|
|
||||||
onChange
|
|
||||||
}: AccountPermissionsProps) => {
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const handleFullAccessChange = (event: React.ChangeEvent<any>) =>
|
const classes = useStyles(props);
|
||||||
onChange(event, () =>
|
const intl = useIntl();
|
||||||
onChange({
|
|
||||||
target: {
|
const handleFullAccessChange = (event: React.ChangeEvent<any>) =>
|
||||||
name: "permissions",
|
onChange(event, () =>
|
||||||
value: event.target.value ? permissions.map(perm => perm.code) : []
|
|
||||||
}
|
|
||||||
} as any)
|
|
||||||
);
|
|
||||||
const handlePermissionChange = (event: React.ChangeEvent<any>) => {
|
|
||||||
onChange({
|
onChange({
|
||||||
target: {
|
target: {
|
||||||
name: "permissions",
|
name: "permissions",
|
||||||
value: event.target.value
|
value: event.target.value ? permissions.map(perm => perm.code) : []
|
||||||
? data.permissions.concat([event.target.name])
|
|
||||||
: data.permissions.filter(perm => perm !== event.target.name)
|
|
||||||
}
|
}
|
||||||
} as any);
|
} as any)
|
||||||
};
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<CardTitle
|
|
||||||
title={intl.formatMessage({
|
|
||||||
defaultMessage: "Permissions",
|
|
||||||
description: "dialog header"
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<CardContent>
|
|
||||||
<Typography>
|
|
||||||
<FormattedMessage defaultMessage="Expand or restrict user's permissions to access certain part of saleor system." />
|
|
||||||
</Typography>
|
|
||||||
<div className={classes.checkboxContainer}>
|
|
||||||
<ControlledCheckbox
|
|
||||||
checked={data.hasFullAccess}
|
|
||||||
disabled={disabled}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "User has full access to the store",
|
|
||||||
description: "checkbox label"
|
|
||||||
})}
|
|
||||||
name="hasFullAccess"
|
|
||||||
onChange={handleFullAccessChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
{!data.hasFullAccess && (
|
|
||||||
<>
|
|
||||||
<hr className={classes.hr} />
|
|
||||||
<CardContent>
|
|
||||||
{permissions === undefined ? (
|
|
||||||
<Skeleton />
|
|
||||||
) : (
|
|
||||||
permissions.map(perm => (
|
|
||||||
<div key={perm.code}>
|
|
||||||
<ControlledCheckbox
|
|
||||||
checked={
|
|
||||||
data.permissions.filter(
|
|
||||||
userPerm => userPerm === perm.code
|
|
||||||
).length === 1
|
|
||||||
}
|
|
||||||
disabled={disabled}
|
|
||||||
label={perm.name.replace(/\./, "")}
|
|
||||||
name={perm.code}
|
|
||||||
onChange={handlePermissionChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
}
|
const handlePermissionChange = (event: React.ChangeEvent<any>) => {
|
||||||
);
|
onChange({
|
||||||
|
target: {
|
||||||
|
name: "permissions",
|
||||||
|
value: event.target.value
|
||||||
|
? data.permissions.concat([event.target.name])
|
||||||
|
: data.permissions.filter(perm => perm !== event.target.name)
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardTitle
|
||||||
|
title={intl.formatMessage({
|
||||||
|
defaultMessage: "Permissions",
|
||||||
|
description: "dialog header"
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<CardContent>
|
||||||
|
<Typography>
|
||||||
|
<FormattedMessage defaultMessage="Expand or restrict user's permissions to access certain part of saleor system." />
|
||||||
|
</Typography>
|
||||||
|
<div className={classes.checkboxContainer}>
|
||||||
|
<ControlledCheckbox
|
||||||
|
checked={data.hasFullAccess}
|
||||||
|
disabled={disabled}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "User has full access to the store",
|
||||||
|
description: "checkbox label"
|
||||||
|
})}
|
||||||
|
name="hasFullAccess"
|
||||||
|
onChange={handleFullAccessChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
{!data.hasFullAccess && (
|
||||||
|
<>
|
||||||
|
<hr className={classes.hr} />
|
||||||
|
<CardContent>
|
||||||
|
{permissions === undefined ? (
|
||||||
|
<Skeleton />
|
||||||
|
) : (
|
||||||
|
permissions.map(perm => (
|
||||||
|
<div key={perm.code}>
|
||||||
|
<ControlledCheckbox
|
||||||
|
checked={
|
||||||
|
data.permissions.filter(
|
||||||
|
userPerm => userPerm === perm.code
|
||||||
|
).length === 1
|
||||||
|
}
|
||||||
|
disabled={disabled}
|
||||||
|
label={perm.name.replace(/\./, "")}
|
||||||
|
name={perm.code}
|
||||||
|
onChange={handlePermissionChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
AccountPermissions.displayName = "AccountPermissions";
|
AccountPermissions.displayName = "AccountPermissions";
|
||||||
export default AccountPermissions;
|
export default AccountPermissions;
|
||||||
|
|
|
@ -3,12 +3,7 @@ import Dialog from "@material-ui/core/Dialog";
|
||||||
import DialogActions from "@material-ui/core/DialogActions";
|
import DialogActions from "@material-ui/core/DialogActions";
|
||||||
import DialogContent from "@material-ui/core/DialogContent";
|
import DialogContent from "@material-ui/core/DialogContent";
|
||||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
@ -18,8 +13,8 @@ import ConfirmButton, {
|
||||||
ConfirmButtonTransitionState
|
ConfirmButtonTransitionState
|
||||||
} from "../ConfirmButton/ConfirmButton";
|
} from "../ConfirmButton/ConfirmButton";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
deleteButton: {
|
deleteButton: {
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: theme.palette.error.main
|
backgroundColor: theme.palette.error.main
|
||||||
|
@ -27,9 +22,11 @@ const styles = theme =>
|
||||||
backgroundColor: theme.palette.error.main,
|
backgroundColor: theme.palette.error.main,
|
||||||
color: theme.palette.error.contrastText
|
color: theme.palette.error.contrastText
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{ name: "ActionDialog" }
|
||||||
|
);
|
||||||
|
|
||||||
interface ActionDialogProps extends WithStyles<typeof styles> {
|
interface ActionDialogProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
confirmButtonLabel?: string;
|
confirmButtonLabel?: string;
|
||||||
confirmButtonState: ConfirmButtonTransitionState;
|
confirmButtonState: ConfirmButtonTransitionState;
|
||||||
|
@ -40,10 +37,9 @@ interface ActionDialogProps extends WithStyles<typeof styles> {
|
||||||
onConfirm();
|
onConfirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ActionDialog = withStyles(styles, { name: "ActionDialog" })(
|
const ActionDialog: React.FC<ActionDialogProps> = props => {
|
||||||
({
|
const {
|
||||||
children,
|
children,
|
||||||
classes,
|
|
||||||
confirmButtonLabel,
|
confirmButtonLabel,
|
||||||
confirmButtonState,
|
confirmButtonState,
|
||||||
open,
|
open,
|
||||||
|
@ -51,35 +47,37 @@ const ActionDialog = withStyles(styles, { name: "ActionDialog" })(
|
||||||
variant,
|
variant,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
onClose
|
onClose
|
||||||
}: ActionDialogProps) => {
|
} = props;
|
||||||
const intl = useIntl();
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog onClose={onClose} open={open}>
|
||||||
|
<DialogTitle>{title}</DialogTitle>
|
||||||
|
<DialogContent>{children}</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onClose}>
|
||||||
|
<FormattedMessage {...buttonMessages.back} />
|
||||||
|
</Button>
|
||||||
|
<ConfirmButton
|
||||||
|
transitionState={confirmButtonState}
|
||||||
|
color="primary"
|
||||||
|
variant="contained"
|
||||||
|
onClick={onConfirm}
|
||||||
|
className={classNames({
|
||||||
|
[classes.deleteButton]: variant === "delete"
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{confirmButtonLabel ||
|
||||||
|
(variant === "delete"
|
||||||
|
? intl.formatMessage(buttonMessages.delete)
|
||||||
|
: intl.formatMessage(buttonMessages.confirm))}
|
||||||
|
</ConfirmButton>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog onClose={onClose} open={open}>
|
|
||||||
<DialogTitle>{title}</DialogTitle>
|
|
||||||
<DialogContent>{children}</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={onClose}>
|
|
||||||
<FormattedMessage {...buttonMessages.back} />
|
|
||||||
</Button>
|
|
||||||
<ConfirmButton
|
|
||||||
transitionState={confirmButtonState}
|
|
||||||
color="primary"
|
|
||||||
variant="contained"
|
|
||||||
onClick={onConfirm}
|
|
||||||
className={classNames({
|
|
||||||
[classes.deleteButton]: variant === "delete"
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{confirmButtonLabel ||
|
|
||||||
(variant === "delete"
|
|
||||||
? intl.formatMessage(buttonMessages.delete)
|
|
||||||
: intl.formatMessage(buttonMessages.confirm))}
|
|
||||||
</ConfirmButton>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
ActionDialog.displayName = "ActionDialog";
|
ActionDialog.displayName = "ActionDialog";
|
||||||
export default ActionDialog;
|
export default ActionDialog;
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
@ -16,16 +11,15 @@ import SingleAutocompleteSelectField, {
|
||||||
SingleAutocompleteChoiceType
|
SingleAutocompleteChoiceType
|
||||||
} from "../SingleAutocompleteSelectField";
|
} from "../SingleAutocompleteSelectField";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
root: {
|
||||||
root: {
|
display: "grid",
|
||||||
display: "grid",
|
gridColumnGap: theme.spacing(2),
|
||||||
gridColumnGap: theme.spacing(2),
|
gridTemplateColumns: "1fr 1fr"
|
||||||
gridTemplateColumns: "1fr 1fr"
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface AddressEditProps extends WithStyles<typeof styles> {
|
interface AddressEditProps {
|
||||||
countries: SingleAutocompleteChoiceType[];
|
countries: SingleAutocompleteChoiceType[];
|
||||||
countryDisplayValue: string;
|
countryDisplayValue: string;
|
||||||
data: AddressTypeInput;
|
data: AddressTypeInput;
|
||||||
|
@ -35,9 +29,8 @@ interface AddressEditProps extends WithStyles<typeof styles> {
|
||||||
onCountryChange(event: React.ChangeEvent<any>);
|
onCountryChange(event: React.ChangeEvent<any>);
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddressEdit = withStyles(styles, { name: "AddressEdit" })(
|
const AddressEdit: React.FC<AddressEditProps> = props => {
|
||||||
({
|
const {
|
||||||
classes,
|
|
||||||
countries,
|
countries,
|
||||||
countryDisplayValue,
|
countryDisplayValue,
|
||||||
data,
|
data,
|
||||||
|
@ -45,164 +38,165 @@ const AddressEdit = withStyles(styles, { name: "AddressEdit" })(
|
||||||
errors,
|
errors,
|
||||||
onChange,
|
onChange,
|
||||||
onCountryChange
|
onCountryChange
|
||||||
}: AddressEditProps) => {
|
} = props;
|
||||||
const intl = useIntl();
|
const classes = useStyles(props);
|
||||||
|
|
||||||
return (
|
const intl = useIntl();
|
||||||
<>
|
|
||||||
<div className={classes.root}>
|
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
error={!!errors.firstName}
|
|
||||||
helperText={errors.firstName}
|
|
||||||
label={intl.formatMessage(commonMessages.firstName)}
|
|
||||||
name="firstName"
|
|
||||||
onChange={onChange}
|
|
||||||
value={data.firstName}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
error={!!errors.lastName}
|
|
||||||
helperText={errors.lastName}
|
|
||||||
label={intl.formatMessage(commonMessages.lastName)}
|
|
||||||
name="lastName"
|
|
||||||
onChange={onChange}
|
|
||||||
value={data.lastName}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<FormSpacer />
|
|
||||||
<div className={classes.root}>
|
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
error={!!errors.companyName}
|
|
||||||
helperText={errors.companyName}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Company"
|
|
||||||
})}
|
|
||||||
name="companyName"
|
|
||||||
onChange={onChange}
|
|
||||||
value={data.companyName}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
error={!!errors.phone}
|
|
||||||
fullWidth
|
|
||||||
helperText={errors.phone}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Phone"
|
|
||||||
})}
|
|
||||||
name="phone"
|
|
||||||
value={data.phone}
|
|
||||||
onChange={onChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<FormSpacer />
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
error={!!errors.streetAddress1}
|
|
||||||
helperText={errors.streetAddress1}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Address line 1"
|
|
||||||
})}
|
|
||||||
name="streetAddress1"
|
|
||||||
onChange={onChange}
|
|
||||||
value={data.streetAddress1}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<FormSpacer />
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
error={!!errors.streetAddress2}
|
|
||||||
helperText={errors.streetAddress2}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Address line 2"
|
|
||||||
})}
|
|
||||||
name="streetAddress2"
|
|
||||||
onChange={onChange}
|
|
||||||
value={data.streetAddress2}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
<FormSpacer />
|
|
||||||
<div className={classes.root}>
|
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
error={!!errors.city}
|
|
||||||
helperText={errors.city}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "City"
|
|
||||||
})}
|
|
||||||
name="city"
|
|
||||||
onChange={onChange}
|
|
||||||
value={data.city}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
error={!!errors.postalCode}
|
|
||||||
helperText={errors.postalCode}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "ZIP / Postal code"
|
|
||||||
})}
|
|
||||||
name="postalCode"
|
|
||||||
onChange={onChange}
|
|
||||||
value={data.postalCode}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<FormSpacer />
|
return (
|
||||||
<div className={classes.root}>
|
<>
|
||||||
<div>
|
<div className={classes.root}>
|
||||||
<SingleAutocompleteSelectField
|
<div>
|
||||||
disabled={disabled}
|
<TextField
|
||||||
displayValue={countryDisplayValue}
|
disabled={disabled}
|
||||||
error={!!errors.country}
|
error={!!errors.firstName}
|
||||||
helperText={errors.country}
|
helperText={errors.firstName}
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage(commonMessages.firstName)}
|
||||||
defaultMessage: "Country"
|
name="firstName"
|
||||||
})}
|
onChange={onChange}
|
||||||
name="country"
|
value={data.firstName}
|
||||||
onChange={onCountryChange}
|
fullWidth
|
||||||
value={data.country}
|
/>
|
||||||
choices={countries}
|
|
||||||
InputProps={{
|
|
||||||
autoComplete: "off"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
disabled={disabled}
|
|
||||||
error={!!errors.countryArea}
|
|
||||||
helperText={errors.countryArea}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Country area"
|
|
||||||
})}
|
|
||||||
name="countryArea"
|
|
||||||
onChange={onChange}
|
|
||||||
value={data.countryArea}
|
|
||||||
fullWidth
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
<div>
|
||||||
);
|
<TextField
|
||||||
}
|
disabled={disabled}
|
||||||
);
|
error={!!errors.lastName}
|
||||||
|
helperText={errors.lastName}
|
||||||
|
label={intl.formatMessage(commonMessages.lastName)}
|
||||||
|
name="lastName"
|
||||||
|
onChange={onChange}
|
||||||
|
value={data.lastName}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<FormSpacer />
|
||||||
|
<div className={classes.root}>
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
disabled={disabled}
|
||||||
|
error={!!errors.companyName}
|
||||||
|
helperText={errors.companyName}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Company"
|
||||||
|
})}
|
||||||
|
name="companyName"
|
||||||
|
onChange={onChange}
|
||||||
|
value={data.companyName}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
disabled={disabled}
|
||||||
|
error={!!errors.phone}
|
||||||
|
fullWidth
|
||||||
|
helperText={errors.phone}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Phone"
|
||||||
|
})}
|
||||||
|
name="phone"
|
||||||
|
value={data.phone}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<FormSpacer />
|
||||||
|
<TextField
|
||||||
|
disabled={disabled}
|
||||||
|
error={!!errors.streetAddress1}
|
||||||
|
helperText={errors.streetAddress1}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Address line 1"
|
||||||
|
})}
|
||||||
|
name="streetAddress1"
|
||||||
|
onChange={onChange}
|
||||||
|
value={data.streetAddress1}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<FormSpacer />
|
||||||
|
<TextField
|
||||||
|
disabled={disabled}
|
||||||
|
error={!!errors.streetAddress2}
|
||||||
|
helperText={errors.streetAddress2}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Address line 2"
|
||||||
|
})}
|
||||||
|
name="streetAddress2"
|
||||||
|
onChange={onChange}
|
||||||
|
value={data.streetAddress2}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<FormSpacer />
|
||||||
|
<div className={classes.root}>
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
disabled={disabled}
|
||||||
|
error={!!errors.city}
|
||||||
|
helperText={errors.city}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "City"
|
||||||
|
})}
|
||||||
|
name="city"
|
||||||
|
onChange={onChange}
|
||||||
|
value={data.city}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
disabled={disabled}
|
||||||
|
error={!!errors.postalCode}
|
||||||
|
helperText={errors.postalCode}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "ZIP / Postal code"
|
||||||
|
})}
|
||||||
|
name="postalCode"
|
||||||
|
onChange={onChange}
|
||||||
|
value={data.postalCode}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormSpacer />
|
||||||
|
<div className={classes.root}>
|
||||||
|
<div>
|
||||||
|
<SingleAutocompleteSelectField
|
||||||
|
disabled={disabled}
|
||||||
|
displayValue={countryDisplayValue}
|
||||||
|
error={!!errors.country}
|
||||||
|
helperText={errors.country}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Country"
|
||||||
|
})}
|
||||||
|
name="country"
|
||||||
|
onChange={onCountryChange}
|
||||||
|
value={data.country}
|
||||||
|
choices={countries}
|
||||||
|
InputProps={{
|
||||||
|
autoComplete: "off"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
disabled={disabled}
|
||||||
|
error={!!errors.countryArea}
|
||||||
|
helperText={errors.countryArea}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Country area"
|
||||||
|
})}
|
||||||
|
name="countryArea"
|
||||||
|
onChange={onChange}
|
||||||
|
value={data.countryArea}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
AddressEdit.displayName = "AddressEdit";
|
AddressEdit.displayName = "AddressEdit";
|
||||||
export default AddressEdit;
|
export default AddressEdit;
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import Portal from "@material-ui/core/Portal";
|
import Portal from "@material-ui/core/Portal";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import ArrowBackIcon from "@material-ui/icons/ArrowBack";
|
import ArrowBackIcon from "@material-ui/icons/ArrowBack";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
@ -16,45 +11,44 @@ export interface AppHeaderProps {
|
||||||
onBack();
|
onBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
backArrow: {
|
||||||
backArrow: {
|
fontSize: 30
|
||||||
fontSize: 30
|
},
|
||||||
|
menuButton: {
|
||||||
|
flex: "0 0 auto",
|
||||||
|
marginLeft: -theme.spacing(2),
|
||||||
|
marginRight: theme.spacing(),
|
||||||
|
marginTop: -theme.spacing(2)
|
||||||
|
},
|
||||||
|
root: {
|
||||||
|
"&:hover": {
|
||||||
|
color: theme.typography.body1.color
|
||||||
},
|
},
|
||||||
menuButton: {
|
alignItems: "center",
|
||||||
flex: "0 0 auto",
|
color: theme.palette.grey[500],
|
||||||
marginLeft: -theme.spacing(2),
|
cursor: "pointer",
|
||||||
marginRight: theme.spacing(),
|
display: "flex",
|
||||||
marginTop: -theme.spacing(2)
|
marginTop: theme.spacing(0.5),
|
||||||
},
|
transition: theme.transitions.duration.standard + "ms"
|
||||||
root: {
|
},
|
||||||
"&:hover": {
|
skeleton: {
|
||||||
color: theme.typography.body1.color
|
marginBottom: theme.spacing(2),
|
||||||
},
|
width: "10rem"
|
||||||
alignItems: "center",
|
},
|
||||||
color: theme.palette.grey[500],
|
title: {
|
||||||
cursor: "pointer",
|
color: "inherit",
|
||||||
display: "flex",
|
flex: 1,
|
||||||
marginTop: theme.spacing(0.5),
|
marginLeft: theme.spacing(),
|
||||||
transition: theme.transitions.duration.standard + "ms"
|
textTransform: "uppercase"
|
||||||
},
|
}
|
||||||
skeleton: {
|
}));
|
||||||
marginBottom: theme.spacing(2),
|
const AppHeader: React.FC<AppHeaderProps> = props => {
|
||||||
width: "10rem"
|
const { children, onBack } = props;
|
||||||
},
|
|
||||||
title: {
|
const classes = useStyles(props);
|
||||||
color: "inherit",
|
|
||||||
flex: 1,
|
return (
|
||||||
marginLeft: theme.spacing(),
|
|
||||||
textTransform: "uppercase"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const AppHeader = withStyles(styles, { name: "AppHeader" })(
|
|
||||||
({
|
|
||||||
children,
|
|
||||||
classes,
|
|
||||||
onBack
|
|
||||||
}: AppHeaderProps & WithStyles<typeof styles>) => (
|
|
||||||
<AppHeaderContext.Consumer>
|
<AppHeaderContext.Consumer>
|
||||||
{anchor =>
|
{anchor =>
|
||||||
anchor ? (
|
anchor ? (
|
||||||
|
@ -71,7 +65,7 @@ const AppHeader = withStyles(styles, { name: "AppHeader" })(
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
</AppHeaderContext.Consumer>
|
</AppHeaderContext.Consumer>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
AppHeader.displayName = "AppHeader";
|
AppHeader.displayName = "AppHeader";
|
||||||
export default AppHeader;
|
export default AppHeader;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AppHeader';
|
export { default } from "./AppHeader";
|
||||||
export * from './AppHeader';
|
export * from "./AppHeader";
|
||||||
|
|
|
@ -8,7 +8,7 @@ import MenuItem from "@material-ui/core/MenuItem";
|
||||||
import Menu from "@material-ui/core/MenuList";
|
import Menu from "@material-ui/core/MenuList";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import Popper from "@material-ui/core/Popper";
|
import Popper from "@material-ui/core/Popper";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import SVG from "react-inlinesvg";
|
import SVG from "react-inlinesvg";
|
||||||
|
@ -36,8 +36,8 @@ import createMenuStructure from "./menuStructure";
|
||||||
import ResponsiveDrawer from "./ResponsiveDrawer";
|
import ResponsiveDrawer from "./ResponsiveDrawer";
|
||||||
import ThemeSwitch from "./ThemeSwitch";
|
import ThemeSwitch from "./ThemeSwitch";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
appAction: {
|
appAction: {
|
||||||
[theme.breakpoints.down("sm")]: {
|
[theme.breakpoints.down("sm")]: {
|
||||||
left: 0,
|
left: 0,
|
||||||
|
@ -263,249 +263,232 @@ const styles = theme =>
|
||||||
viewContainer: {
|
viewContainer: {
|
||||||
minHeight: `calc(100vh - ${theme.spacing(2) + appLoaderHeight + 70}px)`
|
minHeight: `calc(100vh - ${theme.spacing(2) + appLoaderHeight + 70}px)`
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{
|
||||||
|
name: "AppLayout"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
interface AppLayoutProps {
|
interface AppLayoutProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AppLayout = withStyles(styles, {
|
const AppLayout = withRouter<AppLayoutProps & RouteComponentProps<any>, any>(
|
||||||
name: "AppLayout"
|
({ children, location }: AppLayoutProps & RouteComponentProps<any>) => {
|
||||||
})(
|
const classes = useStyles({});
|
||||||
withRouter<AppLayoutProps & RouteComponentProps<any>, any>(
|
const { isDark, toggleTheme } = useTheme();
|
||||||
({
|
const [isMenuSmall, setMenuSmall] = useLocalStorage("isMenuSmall", false);
|
||||||
classes,
|
const [isDrawerOpened, setDrawerState] = React.useState(false);
|
||||||
children,
|
const [isMenuOpened, setMenuState] = React.useState(false);
|
||||||
location
|
const appActionAnchor = React.useRef<HTMLDivElement>();
|
||||||
}: AppLayoutProps &
|
const appHeaderAnchor = React.useRef<HTMLDivElement>();
|
||||||
WithStyles<typeof styles> &
|
const anchor = React.useRef<HTMLDivElement>();
|
||||||
RouteComponentProps<any>) => {
|
const { logout, user } = useUser();
|
||||||
const { isDark, toggleTheme } = useTheme();
|
const navigate = useNavigator();
|
||||||
const [isMenuSmall, setMenuSmall] = useLocalStorage("isMenuSmall", false);
|
const intl = useIntl();
|
||||||
const [isDrawerOpened, setDrawerState] = React.useState(false);
|
|
||||||
const [isMenuOpened, setMenuState] = React.useState(false);
|
|
||||||
const appActionAnchor = React.useRef<HTMLDivElement>();
|
|
||||||
const appHeaderAnchor = React.useRef<HTMLDivElement>();
|
|
||||||
const anchor = React.useRef<HTMLDivElement>();
|
|
||||||
const { logout, user } = useUser();
|
|
||||||
const navigate = useNavigator();
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const menuStructure = createMenuStructure(intl);
|
const menuStructure = createMenuStructure(intl);
|
||||||
const configurationMenu = createConfigurationMenu(intl);
|
const configurationMenu = createConfigurationMenu(intl);
|
||||||
const userPermissions = maybe(() => user.permissions, []);
|
const userPermissions = maybe(() => user.permissions, []);
|
||||||
|
|
||||||
const renderConfigure = configurationMenu.some(section =>
|
const renderConfigure = configurationMenu.some(section =>
|
||||||
section.menuItems.some(
|
section.menuItems.some(
|
||||||
menuItem =>
|
menuItem =>
|
||||||
!!userPermissions.find(
|
!!userPermissions.find(
|
||||||
userPermission => userPermission.code === menuItem.permission
|
userPermission => userPermission.code === menuItem.permission
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
setMenuState(false);
|
setMenuState(false);
|
||||||
logout();
|
logout();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleViewerProfile = () => {
|
const handleViewerProfile = () => {
|
||||||
setMenuState(false);
|
setMenuState(false);
|
||||||
navigate(staffMemberDetailsUrl(user.id));
|
navigate(staffMemberDetailsUrl(user.id));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMenuItemClick = (
|
const handleMenuItemClick = (url: string, event: React.MouseEvent<any>) => {
|
||||||
url: string,
|
event.stopPropagation();
|
||||||
event: React.MouseEvent<any>
|
event.preventDefault();
|
||||||
) => {
|
setDrawerState(false);
|
||||||
event.stopPropagation();
|
navigate(url);
|
||||||
event.preventDefault();
|
};
|
||||||
setDrawerState(false);
|
|
||||||
navigate(url);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleIsMenuSmall = () => {
|
const handleIsMenuSmall = () => {
|
||||||
setMenuSmall(!isMenuSmall);
|
setMenuSmall(!isMenuSmall);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppProgressProvider>
|
<AppProgressProvider>
|
||||||
{({ isProgress }) => (
|
{({ isProgress }) => (
|
||||||
<AppHeaderContext.Provider value={appHeaderAnchor}>
|
<AppHeaderContext.Provider value={appHeaderAnchor}>
|
||||||
<AppActionContext.Provider value={appActionAnchor}>
|
<AppActionContext.Provider value={appActionAnchor}>
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<div className={classes.sideBar}>
|
<div className={classes.sideBar}>
|
||||||
<ResponsiveDrawer
|
<ResponsiveDrawer
|
||||||
onClose={() => setDrawerState(false)}
|
onClose={() => setDrawerState(false)}
|
||||||
open={isDrawerOpened}
|
open={isDrawerOpened}
|
||||||
small={!isMenuSmall}
|
small={!isMenuSmall}
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={classNames(classes.logo, {
|
|
||||||
[classes.logoSmall]: isMenuSmall,
|
|
||||||
[classes.logoDark]: isDark
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<SVG
|
|
||||||
src={
|
|
||||||
isMenuSmall ? saleorDarkLogoSmall : saleorDarkLogo
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Hidden smDown>
|
|
||||||
<div
|
|
||||||
className={classNames(classes.isMenuSmall, {
|
|
||||||
[classes.isMenuSmallHide]: isMenuSmall,
|
|
||||||
[classes.isMenuSmallDark]: isDark
|
|
||||||
})}
|
|
||||||
onClick={handleIsMenuSmall}
|
|
||||||
>
|
|
||||||
<SVG src={menuArrowIcon} />
|
|
||||||
</div>
|
|
||||||
</Hidden>
|
|
||||||
<MenuList
|
|
||||||
className={
|
|
||||||
isMenuSmall ? classes.menuSmall : classes.menu
|
|
||||||
}
|
|
||||||
menuItems={menuStructure}
|
|
||||||
isMenuSmall={!isMenuSmall}
|
|
||||||
location={location.pathname}
|
|
||||||
user={user}
|
|
||||||
renderConfigure={renderConfigure}
|
|
||||||
onMenuItemClick={handleMenuItemClick}
|
|
||||||
/>
|
|
||||||
</ResponsiveDrawer>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={classNames(classes.content, {
|
|
||||||
[classes.contentToggle]: isMenuSmall
|
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
{isProgress ? (
|
<div
|
||||||
<LinearProgress
|
className={classNames(classes.logo, {
|
||||||
className={classes.appLoader}
|
[classes.logoSmall]: isMenuSmall,
|
||||||
color="primary"
|
[classes.logoDark]: isDark
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<SVG
|
||||||
|
src={isMenuSmall ? saleorDarkLogoSmall : saleorDarkLogo}
|
||||||
/>
|
/>
|
||||||
) : (
|
</div>
|
||||||
<div className={classes.appLoaderPlaceholder} />
|
<Hidden smDown>
|
||||||
)}
|
<div
|
||||||
<div className={classes.viewContainer}>
|
className={classNames(classes.isMenuSmall, {
|
||||||
<div>
|
[classes.isMenuSmallHide]: isMenuSmall,
|
||||||
<Container>
|
[classes.isMenuSmallDark]: isDark
|
||||||
<div className={classes.header}>
|
})}
|
||||||
|
onClick={handleIsMenuSmall}
|
||||||
|
>
|
||||||
|
<SVG src={menuArrowIcon} />
|
||||||
|
</div>
|
||||||
|
</Hidden>
|
||||||
|
<MenuList
|
||||||
|
className={isMenuSmall ? classes.menuSmall : classes.menu}
|
||||||
|
menuItems={menuStructure}
|
||||||
|
isMenuSmall={!isMenuSmall}
|
||||||
|
location={location.pathname}
|
||||||
|
user={user}
|
||||||
|
renderConfigure={renderConfigure}
|
||||||
|
onMenuItemClick={handleMenuItemClick}
|
||||||
|
/>
|
||||||
|
</ResponsiveDrawer>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames(classes.content, {
|
||||||
|
[classes.contentToggle]: isMenuSmall
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{isProgress ? (
|
||||||
|
<LinearProgress
|
||||||
|
className={classes.appLoader}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className={classes.appLoaderPlaceholder} />
|
||||||
|
)}
|
||||||
|
<div className={classes.viewContainer}>
|
||||||
|
<div>
|
||||||
|
<Container>
|
||||||
|
<div className={classes.header}>
|
||||||
|
<div
|
||||||
|
className={classNames(classes.menuIcon, {
|
||||||
|
[classes.menuIconOpen]: isDrawerOpened,
|
||||||
|
[classes.menuIconDark]: isDark
|
||||||
|
})}
|
||||||
|
onClick={() => setDrawerState(!isDrawerOpened)}
|
||||||
|
>
|
||||||
|
<span />
|
||||||
|
<span />
|
||||||
|
<span />
|
||||||
|
<span />
|
||||||
|
</div>
|
||||||
|
<div ref={appHeaderAnchor} />
|
||||||
|
<div className={classes.spacer} />
|
||||||
|
<div className={classes.userBar}>
|
||||||
|
<ThemeSwitch
|
||||||
|
className={classes.darkThemeSwitch}
|
||||||
|
checked={isDark}
|
||||||
|
onClick={toggleTheme}
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
className={classNames(classes.menuIcon, {
|
className={classes.userMenuContainer}
|
||||||
[classes.menuIconOpen]: isDrawerOpened,
|
ref={anchor}
|
||||||
[classes.menuIconDark]: isDark
|
|
||||||
})}
|
|
||||||
onClick={() => setDrawerState(!isDrawerOpened)}
|
|
||||||
>
|
>
|
||||||
<span />
|
<Chip
|
||||||
<span />
|
avatar={
|
||||||
<span />
|
user.avatar && (
|
||||||
<span />
|
<Avatar alt="user" src={user.avatar.url} />
|
||||||
</div>
|
)
|
||||||
<div ref={appHeaderAnchor} />
|
}
|
||||||
<div className={classes.spacer} />
|
className={classes.userChip}
|
||||||
<div className={classes.userBar}>
|
label={
|
||||||
<ThemeSwitch
|
<>
|
||||||
className={classes.darkThemeSwitch}
|
{user.email}
|
||||||
checked={isDark}
|
<ArrowDropdown
|
||||||
onClick={toggleTheme}
|
className={classNames(classes.arrow, {
|
||||||
|
[classes.rotate]: isMenuOpened
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
onClick={() => setMenuState(!isMenuOpened)}
|
||||||
/>
|
/>
|
||||||
<div
|
<Popper
|
||||||
className={classes.userMenuContainer}
|
className={classes.popover}
|
||||||
ref={anchor}
|
open={isMenuOpened}
|
||||||
|
anchorEl={anchor.current}
|
||||||
|
transition
|
||||||
|
disablePortal
|
||||||
|
placement="bottom-end"
|
||||||
>
|
>
|
||||||
<Chip
|
{({ TransitionProps, placement }) => (
|
||||||
avatar={
|
<Grow
|
||||||
user.avatar && (
|
{...TransitionProps}
|
||||||
<Avatar
|
style={{
|
||||||
alt="user"
|
transformOrigin:
|
||||||
src={user.avatar.url}
|
placement === "bottom"
|
||||||
/>
|
? "right top"
|
||||||
)
|
: "right bottom"
|
||||||
}
|
}}
|
||||||
className={classes.userChip}
|
>
|
||||||
label={
|
<Paper>
|
||||||
<>
|
<ClickAwayListener
|
||||||
{user.email}
|
onClickAway={() => setMenuState(false)}
|
||||||
<ArrowDropdown
|
mouseEvent="onClick"
|
||||||
className={classNames(classes.arrow, {
|
>
|
||||||
[classes.rotate]: isMenuOpened
|
<Menu>
|
||||||
})}
|
<MenuItem
|
||||||
/>
|
className={classes.userMenuItem}
|
||||||
</>
|
onClick={handleViewerProfile}
|
||||||
}
|
>
|
||||||
onClick={() => setMenuState(!isMenuOpened)}
|
<FormattedMessage
|
||||||
/>
|
defaultMessage="Account Settings"
|
||||||
<Popper
|
description="button"
|
||||||
className={classes.popover}
|
/>
|
||||||
open={isMenuOpened}
|
</MenuItem>
|
||||||
anchorEl={anchor.current}
|
<MenuItem
|
||||||
transition
|
className={classes.userMenuItem}
|
||||||
disablePortal
|
onClick={handleLogout}
|
||||||
placement="bottom-end"
|
>
|
||||||
>
|
<FormattedMessage
|
||||||
{({ TransitionProps, placement }) => (
|
defaultMessage="Log out"
|
||||||
<Grow
|
description="button"
|
||||||
{...TransitionProps}
|
/>
|
||||||
style={{
|
</MenuItem>
|
||||||
transformOrigin:
|
</Menu>
|
||||||
placement === "bottom"
|
</ClickAwayListener>
|
||||||
? "right top"
|
</Paper>
|
||||||
: "right bottom"
|
</Grow>
|
||||||
}}
|
)}
|
||||||
>
|
</Popper>
|
||||||
<Paper>
|
|
||||||
<ClickAwayListener
|
|
||||||
onClickAway={() =>
|
|
||||||
setMenuState(false)
|
|
||||||
}
|
|
||||||
mouseEvent="onClick"
|
|
||||||
>
|
|
||||||
<Menu>
|
|
||||||
<MenuItem
|
|
||||||
className={classes.userMenuItem}
|
|
||||||
onClick={handleViewerProfile}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Account Settings"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem
|
|
||||||
className={classes.userMenuItem}
|
|
||||||
onClick={handleLogout}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Log out"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</ClickAwayListener>
|
|
||||||
</Paper>
|
|
||||||
</Grow>
|
|
||||||
)}
|
|
||||||
</Popper>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</div>
|
||||||
</div>
|
</Container>
|
||||||
<main className={classes.view}>{children}</main>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.appAction} ref={appActionAnchor} />
|
<main className={classes.view}>{children}</main>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={classes.appAction} ref={appActionAnchor} />
|
||||||
</div>
|
</div>
|
||||||
</AppActionContext.Provider>
|
</div>
|
||||||
</AppHeaderContext.Provider>
|
</AppActionContext.Provider>
|
||||||
)}
|
</AppHeaderContext.Provider>
|
||||||
</AppProgressProvider>
|
)}
|
||||||
);
|
</AppProgressProvider>
|
||||||
}
|
);
|
||||||
)
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export default AppLayout;
|
export default AppLayout;
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
@ -24,92 +19,41 @@ import { orderDraftListUrl, orderListUrl } from "../../orders/urls";
|
||||||
import MenuNested from "./MenuNested";
|
import MenuNested from "./MenuNested";
|
||||||
import { IMenuItem } from "./menuStructure";
|
import { IMenuItem } from "./menuStructure";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
menuIcon: {
|
||||||
menuIcon: {
|
"& svg": {
|
||||||
"& svg": {
|
height: 32,
|
||||||
height: 32,
|
width: 32
|
||||||
width: 32
|
|
||||||
},
|
|
||||||
display: "inline-block",
|
|
||||||
position: "relative",
|
|
||||||
top: 8
|
|
||||||
},
|
},
|
||||||
menuIconDark: {
|
display: "inline-block",
|
||||||
"& path": {
|
position: "relative",
|
||||||
fill: theme.palette.common.white
|
top: 8
|
||||||
}
|
},
|
||||||
|
menuIconDark: {
|
||||||
|
"& path": {
|
||||||
|
fill: theme.palette.common.white
|
||||||
|
}
|
||||||
|
},
|
||||||
|
menuIconSmall: {
|
||||||
|
left: -5
|
||||||
|
},
|
||||||
|
menuIsActive: {
|
||||||
|
boxShadow: "0px 0px 12px 1px rgba(0,0,0,0.2)"
|
||||||
|
},
|
||||||
|
menuItemHover: {
|
||||||
|
"& p": {
|
||||||
|
fontSize: 14,
|
||||||
|
transition: "color 0.5s ease, opacity 0.3s ease-out"
|
||||||
},
|
},
|
||||||
menuIconSmall: {
|
"& path": {
|
||||||
left: -5
|
transition: "fill 0.5s ease"
|
||||||
},
|
},
|
||||||
menuIsActive: {
|
"&:hover": {
|
||||||
boxShadow: "0px 0px 12px 1px rgba(0,0,0,0.2)"
|
|
||||||
},
|
|
||||||
menuItemHover: {
|
|
||||||
"& p": {
|
"& p": {
|
||||||
fontSize: 14,
|
|
||||||
transition: "color 0.5s ease, opacity 0.3s ease-out"
|
|
||||||
},
|
|
||||||
"& path": {
|
|
||||||
transition: "fill 0.5s ease"
|
|
||||||
},
|
|
||||||
"&:hover": {
|
|
||||||
"& p": {
|
|
||||||
color: theme.palette.primary.main
|
|
||||||
},
|
|
||||||
"& path": {
|
|
||||||
fill: theme.palette.primary.main
|
|
||||||
},
|
|
||||||
"&:before": {
|
|
||||||
borderLeft: `solid 2px ${theme.palette.primary.main}`,
|
|
||||||
content: "''",
|
|
||||||
height: 33,
|
|
||||||
left: -20,
|
|
||||||
position: "absolute",
|
|
||||||
top: 8
|
|
||||||
},
|
|
||||||
color: theme.palette.primary.main
|
|
||||||
},
|
|
||||||
cursor: "pointer",
|
|
||||||
position: "relative"
|
|
||||||
},
|
|
||||||
menuList: {
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
height: "100%",
|
|
||||||
marginLeft: theme.spacing(4),
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
paddingBottom: theme.spacing(3)
|
|
||||||
},
|
|
||||||
menuListItem: {
|
|
||||||
alignItems: "center",
|
|
||||||
display: "block",
|
|
||||||
marginBottom: theme.spacing(5),
|
|
||||||
paddingLeft: 0,
|
|
||||||
textDecoration: "none",
|
|
||||||
transition: theme.transitions.duration.standard + "ms"
|
|
||||||
},
|
|
||||||
menuListItemActive: {
|
|
||||||
"& $menuListItemText": {
|
|
||||||
color: theme.palette.primary.main
|
color: theme.palette.primary.main
|
||||||
},
|
},
|
||||||
"& path": {
|
"& path": {
|
||||||
color: theme.palette.primary.main,
|
|
||||||
fill: theme.palette.primary.main
|
fill: theme.palette.primary.main
|
||||||
}
|
|
||||||
},
|
|
||||||
menuListItemOpen: {
|
|
||||||
"&:after": {
|
|
||||||
borderBottom: `10px solid transparent`,
|
|
||||||
borderLeft: `10px solid ${theme.palette.background.paper}`,
|
|
||||||
borderTop: `10px solid transparent`,
|
|
||||||
content: "''",
|
|
||||||
height: 0,
|
|
||||||
position: "absolute",
|
|
||||||
right: -35,
|
|
||||||
top: 15,
|
|
||||||
width: 0
|
|
||||||
},
|
},
|
||||||
"&:before": {
|
"&:before": {
|
||||||
borderLeft: `solid 2px ${theme.palette.primary.main}`,
|
borderLeft: `solid 2px ${theme.palette.primary.main}`,
|
||||||
|
@ -119,47 +63,97 @@ const styles = theme =>
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 8
|
top: 8
|
||||||
},
|
},
|
||||||
position: "relative"
|
color: theme.palette.primary.main
|
||||||
},
|
},
|
||||||
menuListItemText: {
|
cursor: "pointer",
|
||||||
"&:hover": {
|
position: "relative"
|
||||||
color: theme.palette.primary.main
|
},
|
||||||
},
|
menuList: {
|
||||||
bottom: 0,
|
display: "flex",
|
||||||
cursor: "pointer",
|
flexDirection: "column",
|
||||||
fontSize: "1rem",
|
height: "100%",
|
||||||
fontWeight: 500,
|
marginLeft: theme.spacing(4),
|
||||||
left: 30,
|
marginTop: theme.spacing(2),
|
||||||
opacity: 1,
|
paddingBottom: theme.spacing(3)
|
||||||
paddingLeft: 16,
|
},
|
||||||
position: "absolute",
|
menuListItem: {
|
||||||
textTransform: "uppercase",
|
alignItems: "center",
|
||||||
transition: "opacity 0.5s ease"
|
display: "block",
|
||||||
|
marginBottom: theme.spacing(5),
|
||||||
|
paddingLeft: 0,
|
||||||
|
textDecoration: "none",
|
||||||
|
transition: theme.transitions.duration.standard + "ms"
|
||||||
|
},
|
||||||
|
menuListItemActive: {
|
||||||
|
"& $menuListItemText": {
|
||||||
|
color: theme.palette.primary.main
|
||||||
},
|
},
|
||||||
menuListItemTextHide: {
|
"& path": {
|
||||||
bottom: 0,
|
color: theme.palette.primary.main,
|
||||||
left: 30,
|
fill: theme.palette.primary.main
|
||||||
opacity: 0,
|
|
||||||
position: "absolute"
|
|
||||||
},
|
|
||||||
subMenu: {
|
|
||||||
padding: "0 15px"
|
|
||||||
},
|
|
||||||
subMenuDrawer: {
|
|
||||||
background: "#000",
|
|
||||||
cursor: "pointer",
|
|
||||||
height: "100vh",
|
|
||||||
left: 0,
|
|
||||||
opacity: 0.2,
|
|
||||||
position: "absolute",
|
|
||||||
top: 0,
|
|
||||||
width: 0,
|
|
||||||
zIndex: -2
|
|
||||||
},
|
|
||||||
subMenuDrawerOpen: {
|
|
||||||
width: `100vw`
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
menuListItemOpen: {
|
||||||
|
"&:after": {
|
||||||
|
borderBottom: `10px solid transparent`,
|
||||||
|
borderLeft: `10px solid ${theme.palette.background.paper}`,
|
||||||
|
borderTop: `10px solid transparent`,
|
||||||
|
content: "''",
|
||||||
|
height: 0,
|
||||||
|
position: "absolute",
|
||||||
|
right: -35,
|
||||||
|
top: 15,
|
||||||
|
width: 0
|
||||||
|
},
|
||||||
|
"&:before": {
|
||||||
|
borderLeft: `solid 2px ${theme.palette.primary.main}`,
|
||||||
|
content: "''",
|
||||||
|
height: 33,
|
||||||
|
left: -20,
|
||||||
|
position: "absolute",
|
||||||
|
top: 8
|
||||||
|
},
|
||||||
|
position: "relative"
|
||||||
|
},
|
||||||
|
menuListItemText: {
|
||||||
|
"&:hover": {
|
||||||
|
color: theme.palette.primary.main
|
||||||
|
},
|
||||||
|
bottom: 0,
|
||||||
|
cursor: "pointer",
|
||||||
|
fontSize: "1rem",
|
||||||
|
fontWeight: 500,
|
||||||
|
left: 30,
|
||||||
|
opacity: 1,
|
||||||
|
paddingLeft: 16,
|
||||||
|
position: "absolute",
|
||||||
|
textTransform: "uppercase",
|
||||||
|
transition: "opacity 0.5s ease"
|
||||||
|
},
|
||||||
|
menuListItemTextHide: {
|
||||||
|
bottom: 0,
|
||||||
|
left: 30,
|
||||||
|
opacity: 0,
|
||||||
|
position: "absolute"
|
||||||
|
},
|
||||||
|
subMenu: {
|
||||||
|
padding: "0 15px"
|
||||||
|
},
|
||||||
|
subMenuDrawer: {
|
||||||
|
background: "#000",
|
||||||
|
cursor: "pointer",
|
||||||
|
height: "100vh",
|
||||||
|
left: 0,
|
||||||
|
opacity: 0.2,
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
width: 0,
|
||||||
|
zIndex: -2
|
||||||
|
},
|
||||||
|
subMenuDrawerOpen: {
|
||||||
|
width: `100vw`
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
interface MenuListProps {
|
interface MenuListProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
@ -176,9 +170,8 @@ export interface IActiveSubMenu {
|
||||||
label: string | null;
|
label: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuList = withStyles(styles, { name: "MenuList" })(
|
const MenuList: React.FC<MenuListProps> = props => {
|
||||||
({
|
const {
|
||||||
classes,
|
|
||||||
className,
|
className,
|
||||||
menuItems,
|
menuItems,
|
||||||
isMenuSmall,
|
isMenuSmall,
|
||||||
|
@ -186,134 +179,89 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
|
||||||
user,
|
user,
|
||||||
renderConfigure,
|
renderConfigure,
|
||||||
onMenuItemClick
|
onMenuItemClick
|
||||||
}: MenuListProps & WithStyles<typeof styles>) => {
|
} = props;
|
||||||
const { isDark } = useTheme();
|
|
||||||
const [activeSubMenu, setActiveSubMenu] = React.useState<IActiveSubMenu>({
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
const { isDark } = useTheme();
|
||||||
|
const [activeSubMenu, setActiveSubMenu] = React.useState<IActiveSubMenu>({
|
||||||
|
isActive: false,
|
||||||
|
label: null
|
||||||
|
});
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const configutationMenu = createConfigurationMenu(intl).map(menu => {
|
||||||
|
menu.menuItems.map(item =>
|
||||||
|
user.permissions.map(perm => perm.code).includes(item.permission)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSubMenu = itemLabel => {
|
||||||
|
setActiveSubMenu({
|
||||||
|
isActive:
|
||||||
|
itemLabel === activeSubMenu.label ? !activeSubMenu.isActive : true,
|
||||||
|
label: itemLabel
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeSubMenu = (menuItemUrl, event) => {
|
||||||
|
setActiveSubMenu({
|
||||||
isActive: false,
|
isActive: false,
|
||||||
label: null
|
label: null
|
||||||
});
|
});
|
||||||
const intl = useIntl();
|
if (menuItemUrl && event) {
|
||||||
|
onMenuItemClick(menuItemUrl, event);
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const configutationMenu = createConfigurationMenu(intl).map(menu => {
|
return (
|
||||||
menu.menuItems.map(item =>
|
<div
|
||||||
user.permissions.map(perm => perm.code).includes(item.permission)
|
className={classNames(className, {
|
||||||
);
|
[classes.menuIsActive]: activeSubMenu.isActive
|
||||||
});
|
})}
|
||||||
|
>
|
||||||
|
{/* FIXME: this .split("?")[0] looks gross */}
|
||||||
|
{menuItems.map(menuItem => {
|
||||||
|
const isActive = (menuItem: IMenuItem) =>
|
||||||
|
location.split("?")[0] === orderDraftListUrl().split("?")[0] &&
|
||||||
|
menuItem.url.split("?")[0] === orderListUrl().split("?")[0]
|
||||||
|
? false
|
||||||
|
: !!matchPath(location.split("?")[0], {
|
||||||
|
exact: menuItem.url.split("?")[0] === "/",
|
||||||
|
path: menuItem.url.split("?")[0]
|
||||||
|
});
|
||||||
|
|
||||||
const handleSubMenu = itemLabel => {
|
if (
|
||||||
setActiveSubMenu({
|
menuItem.permission &&
|
||||||
isActive:
|
!user.permissions.map(perm => perm.code).includes(menuItem.permission)
|
||||||
itemLabel === activeSubMenu.label ? !activeSubMenu.isActive : true,
|
) {
|
||||||
label: itemLabel
|
return null;
|
||||||
});
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const closeSubMenu = (menuItemUrl, event) => {
|
if (!menuItem.url) {
|
||||||
setActiveSubMenu({
|
const isAnyChildActive = menuItem.children.reduce(
|
||||||
isActive: false,
|
(acc, child) => acc || isActive(child),
|
||||||
label: null
|
false
|
||||||
});
|
);
|
||||||
if (menuItemUrl && event) {
|
|
||||||
onMenuItemClick(menuItemUrl, event);
|
|
||||||
event.stopPropagation();
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classNames(className, {
|
|
||||||
[classes.menuIsActive]: activeSubMenu.isActive
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{/* FIXME: this .split("?")[0] looks gross */}
|
|
||||||
{menuItems.map(menuItem => {
|
|
||||||
const isActive = (menuItem: IMenuItem) =>
|
|
||||||
location.split("?")[0] === orderDraftListUrl().split("?")[0] &&
|
|
||||||
menuItem.url.split("?")[0] === orderListUrl().split("?")[0]
|
|
||||||
? false
|
|
||||||
: !!matchPath(location.split("?")[0], {
|
|
||||||
exact: menuItem.url.split("?")[0] === "/",
|
|
||||||
path: menuItem.url.split("?")[0]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (
|
|
||||||
menuItem.permission &&
|
|
||||||
!user.permissions
|
|
||||||
.map(perm => perm.code)
|
|
||||||
.includes(menuItem.permission)
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!menuItem.url) {
|
|
||||||
const isAnyChildActive = menuItem.children.reduce(
|
|
||||||
(acc, child) => acc || isActive(child),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classNames(classes.menuListItem, {
|
|
||||||
[classes.menuListItemActive]: isAnyChildActive
|
|
||||||
})}
|
|
||||||
key={menuItem.label}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={classNames(classes.menuItemHover, {
|
|
||||||
[classes.menuListItemOpen]:
|
|
||||||
menuItem.ariaLabel === activeSubMenu.label &&
|
|
||||||
activeSubMenu.isActive
|
|
||||||
})}
|
|
||||||
data-tc={menuItem.label}
|
|
||||||
onClick={() => handleSubMenu(menuItem.ariaLabel)}
|
|
||||||
>
|
|
||||||
<SVG
|
|
||||||
className={classNames(classes.menuIcon, {
|
|
||||||
[classes.menuIconDark]: isDark,
|
|
||||||
[classes.menuIconSmall]: !isMenuSmall
|
|
||||||
})}
|
|
||||||
src={menuItem.icon}
|
|
||||||
/>
|
|
||||||
<Typography
|
|
||||||
aria-label={menuItem.ariaLabel}
|
|
||||||
className={classNames(classes.menuListItemText, {
|
|
||||||
[classes.menuListItemTextHide]: !isMenuSmall
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{menuItem.label}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
<MenuNested
|
|
||||||
activeItem={activeSubMenu}
|
|
||||||
closeSubMenu={setActiveSubMenu}
|
|
||||||
menuItem={menuItem}
|
|
||||||
onMenuItemClick={onMenuItemClick}
|
|
||||||
handleSubMenu={handleSubMenu}
|
|
||||||
title={menuItem.label}
|
|
||||||
icon={menuItem.icon}
|
|
||||||
ariaLabel={menuItem.ariaLabel}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
onClick={event => closeSubMenu(null, event)}
|
|
||||||
className={classNames(classes.subMenuDrawer, {
|
|
||||||
[classes.subMenuDrawerOpen]: activeSubMenu.isActive
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a
|
<div
|
||||||
className={classNames(classes.menuListItem, {
|
className={classNames(classes.menuListItem, {
|
||||||
[classes.menuListItemActive]: isActive(menuItem)
|
[classes.menuListItemActive]: isAnyChildActive
|
||||||
})}
|
})}
|
||||||
href={createHref(menuItem.url)}
|
|
||||||
onClick={event => closeSubMenu(menuItem.url, event)}
|
|
||||||
key={menuItem.label}
|
key={menuItem.label}
|
||||||
>
|
>
|
||||||
<div className={classes.menuItemHover}>
|
<div
|
||||||
|
className={classNames(classes.menuItemHover, {
|
||||||
|
[classes.menuListItemOpen]:
|
||||||
|
menuItem.ariaLabel === activeSubMenu.label &&
|
||||||
|
activeSubMenu.isActive
|
||||||
|
})}
|
||||||
|
data-tc={menuItem.label}
|
||||||
|
onClick={() => handleSubMenu(menuItem.ariaLabel)}
|
||||||
|
>
|
||||||
<SVG
|
<SVG
|
||||||
className={classNames(classes.menuIcon, {
|
className={classNames(classes.menuIcon, {
|
||||||
[classes.menuIconDark]: isDark,
|
[classes.menuIconDark]: isDark,
|
||||||
|
@ -330,14 +278,34 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
|
||||||
{menuItem.label}
|
{menuItem.label}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
<MenuNested
|
||||||
|
activeItem={activeSubMenu}
|
||||||
|
closeSubMenu={setActiveSubMenu}
|
||||||
|
menuItem={menuItem}
|
||||||
|
onMenuItemClick={onMenuItemClick}
|
||||||
|
handleSubMenu={handleSubMenu}
|
||||||
|
title={menuItem.label}
|
||||||
|
icon={menuItem.icon}
|
||||||
|
ariaLabel={menuItem.ariaLabel}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
onClick={event => closeSubMenu(null, event)}
|
||||||
|
className={classNames(classes.subMenuDrawer, {
|
||||||
|
[classes.subMenuDrawerOpen]: activeSubMenu.isActive
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
}
|
||||||
{renderConfigure && configutationMenu.length > 0 && (
|
|
||||||
|
return (
|
||||||
<a
|
<a
|
||||||
className={classes.menuListItem}
|
className={classNames(classes.menuListItem, {
|
||||||
href={createHref(configurationMenuUrl)}
|
[classes.menuListItemActive]: isActive(menuItem)
|
||||||
onClick={event => closeSubMenu(configurationMenuUrl, event)}
|
})}
|
||||||
|
href={createHref(menuItem.url)}
|
||||||
|
onClick={event => closeSubMenu(menuItem.url, event)}
|
||||||
|
key={menuItem.label}
|
||||||
>
|
>
|
||||||
<div className={classes.menuItemHover}>
|
<div className={classes.menuItemHover}>
|
||||||
<SVG
|
<SVG
|
||||||
|
@ -345,21 +313,48 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
|
||||||
[classes.menuIconDark]: isDark,
|
[classes.menuIconDark]: isDark,
|
||||||
[classes.menuIconSmall]: !isMenuSmall
|
[classes.menuIconSmall]: !isMenuSmall
|
||||||
})}
|
})}
|
||||||
src={configureIcon}
|
src={menuItem.icon}
|
||||||
/>
|
/>
|
||||||
<Typography
|
<Typography
|
||||||
aria-label="configuration"
|
aria-label={menuItem.ariaLabel}
|
||||||
className={classNames(classes.menuListItemText, {
|
className={classNames(classes.menuListItemText, {
|
||||||
[classes.menuListItemTextHide]: !isMenuSmall
|
[classes.menuListItemTextHide]: !isMenuSmall
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<FormattedMessage {...sectionNames.configuration} />
|
{menuItem.label}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
)}
|
);
|
||||||
</div>
|
})}
|
||||||
);
|
{renderConfigure && configutationMenu.length > 0 && (
|
||||||
}
|
<a
|
||||||
);
|
className={classes.menuListItem}
|
||||||
|
href={createHref(configurationMenuUrl)}
|
||||||
|
onClick={event => closeSubMenu(configurationMenuUrl, event)}
|
||||||
|
>
|
||||||
|
<div className={classes.menuItemHover}>
|
||||||
|
<SVG
|
||||||
|
className={classNames(classes.menuIcon, {
|
||||||
|
[classes.menuIconDark]: isDark,
|
||||||
|
[classes.menuIconSmall]: !isMenuSmall
|
||||||
|
})}
|
||||||
|
src={configureIcon}
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
aria-label="configuration"
|
||||||
|
className={classNames(classes.menuListItemText, {
|
||||||
|
[classes.menuListItemTextHide]: !isMenuSmall
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<FormattedMessage {...sectionNames.configuration} />
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuList.displayName = "MenuList";
|
||||||
export default MenuList;
|
export default MenuList;
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import Hidden from "@material-ui/core/Hidden";
|
import Hidden from "@material-ui/core/Hidden";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
@ -17,89 +12,88 @@ import { drawerWidthExpanded } from "./consts";
|
||||||
import { IActiveSubMenu } from "./MenuList";
|
import { IActiveSubMenu } from "./MenuList";
|
||||||
import { IMenuItem } from "./menuStructure";
|
import { IMenuItem } from "./menuStructure";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
menuListNested: {
|
||||||
menuListNested: {
|
background: theme.palette.background.paper,
|
||||||
background: theme.palette.background.paper,
|
height: "100vh",
|
||||||
height: "100vh",
|
position: "absolute",
|
||||||
position: "absolute",
|
right: 0,
|
||||||
right: 0,
|
top: 0,
|
||||||
top: 0,
|
transition: `right ${theme.transitions.duration.shorter}ms ease`,
|
||||||
transition: `right ${theme.transitions.duration.shorter}ms ease`,
|
width: 300,
|
||||||
width: 300,
|
zIndex: -1
|
||||||
zIndex: -1
|
},
|
||||||
|
menuListNestedClose: {
|
||||||
|
"& svg": {
|
||||||
|
fill: theme.palette.primary.main,
|
||||||
|
left: 7,
|
||||||
|
position: "relative",
|
||||||
|
top: -2
|
||||||
},
|
},
|
||||||
menuListNestedClose: {
|
border: `solid 1px #EAEAEA`,
|
||||||
"& svg": {
|
borderRadius: "100%",
|
||||||
fill: theme.palette.primary.main,
|
cursor: "pointer",
|
||||||
left: 7,
|
height: 32,
|
||||||
position: "relative",
|
position: "absolute",
|
||||||
top: -2
|
right: 32,
|
||||||
},
|
top: 35,
|
||||||
border: `solid 1px #EAEAEA`,
|
transform: "rotate(180deg)",
|
||||||
borderRadius: "100%",
|
width: 32
|
||||||
cursor: "pointer",
|
},
|
||||||
height: 32,
|
menuListNestedCloseDark: {
|
||||||
position: "absolute",
|
border: `solid 1px #252728`
|
||||||
right: 32,
|
},
|
||||||
top: 35,
|
menuListNestedHide: {
|
||||||
transform: "rotate(180deg)",
|
opacity: 0
|
||||||
width: 32
|
},
|
||||||
|
menuListNestedIcon: {
|
||||||
|
"& path": {
|
||||||
|
fill: "initial"
|
||||||
},
|
},
|
||||||
menuListNestedCloseDark: {
|
"& svg": { height: 32, position: "relative", top: 7, width: 32 }
|
||||||
border: `solid 1px #252728`
|
},
|
||||||
},
|
menuListNestedIconDark: {
|
||||||
menuListNestedHide: {
|
"& path": {
|
||||||
opacity: 0
|
fill: theme.palette.common.white
|
||||||
},
|
}
|
||||||
menuListNestedIcon: {
|
},
|
||||||
"& path": {
|
menuListNestedItem: {
|
||||||
fill: "initial"
|
"&:hover": {
|
||||||
},
|
"& p": {
|
||||||
"& svg": { height: 32, position: "relative", top: 7, width: 32 }
|
color: theme.palette.primary.main
|
||||||
},
|
|
||||||
menuListNestedIconDark: {
|
|
||||||
"& path": {
|
|
||||||
fill: theme.palette.common.white
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
menuListNestedItem: {
|
display: "block",
|
||||||
"&:hover": {
|
marginBottom: theme.spacing(2),
|
||||||
"& p": {
|
padding: "0px 30px",
|
||||||
color: theme.palette.primary.main
|
textDecoration: "none"
|
||||||
}
|
},
|
||||||
},
|
menuListNestedOpen: {
|
||||||
display: "block",
|
[theme.breakpoints.down("sm")]: {
|
||||||
marginBottom: theme.spacing(2),
|
right: 0,
|
||||||
padding: "0px 30px",
|
width: drawerWidthExpanded,
|
||||||
textDecoration: "none"
|
zIndex: 2
|
||||||
},
|
},
|
||||||
menuListNestedOpen: {
|
right: -300,
|
||||||
[theme.breakpoints.down("sm")]: {
|
zIndex: -1
|
||||||
right: 0,
|
},
|
||||||
width: drawerWidthExpanded,
|
subHeader: {
|
||||||
zIndex: 2
|
borderBottom: "solid 1px #EAEAEA",
|
||||||
},
|
margin: "30px",
|
||||||
right: -300,
|
marginBottom: 39,
|
||||||
zIndex: -1
|
paddingBottom: 22
|
||||||
|
},
|
||||||
|
subHeaderDark: {
|
||||||
|
borderBottom: "solid 1px #252728"
|
||||||
|
},
|
||||||
|
subHeaderTitle: {
|
||||||
|
[theme.breakpoints.up("md")]: {
|
||||||
|
paddingLeft: 0
|
||||||
},
|
},
|
||||||
subHeader: {
|
display: "inline",
|
||||||
borderBottom: "solid 1px #EAEAEA",
|
paddingLeft: 10
|
||||||
margin: "30px",
|
}
|
||||||
marginBottom: 39,
|
}));
|
||||||
paddingBottom: 22
|
|
||||||
},
|
|
||||||
subHeaderDark: {
|
|
||||||
borderBottom: "solid 1px #252728"
|
|
||||||
},
|
|
||||||
subHeaderTitle: {
|
|
||||||
[theme.breakpoints.up("md")]: {
|
|
||||||
paddingLeft: 0
|
|
||||||
},
|
|
||||||
display: "inline",
|
|
||||||
paddingLeft: 10
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export interface MenuNestedProps {
|
export interface MenuNestedProps {
|
||||||
activeItem: IActiveSubMenu;
|
activeItem: IActiveSubMenu;
|
||||||
|
@ -112,86 +106,85 @@ export interface MenuNestedProps {
|
||||||
onMenuItemClick: (url: string, event: React.MouseEvent<any>) => void;
|
onMenuItemClick: (url: string, event: React.MouseEvent<any>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MenuNested = withStyles(styles, { name: "MenuNested" })(
|
const MenuNested: React.FC<MenuNestedProps> = props => {
|
||||||
({
|
const {
|
||||||
activeItem,
|
activeItem,
|
||||||
ariaLabel,
|
ariaLabel,
|
||||||
classes,
|
|
||||||
closeSubMenu,
|
closeSubMenu,
|
||||||
icon,
|
icon,
|
||||||
menuItem,
|
menuItem,
|
||||||
onMenuItemClick,
|
onMenuItemClick,
|
||||||
title
|
title
|
||||||
}: MenuNestedProps & WithStyles<typeof styles>) => {
|
} = props;
|
||||||
const menuItems = menuItem.children;
|
const classes = useStyles(props);
|
||||||
const { isDark } = useTheme();
|
|
||||||
const closeMenu = (menuItemUrl, event) => {
|
const menuItems = menuItem.children;
|
||||||
onMenuItemClick(menuItemUrl, event);
|
const { isDark } = useTheme();
|
||||||
closeSubMenu({
|
const closeMenu = (menuItemUrl, event) => {
|
||||||
isActive: false,
|
onMenuItemClick(menuItemUrl, event);
|
||||||
label: null
|
closeSubMenu({
|
||||||
});
|
isActive: false,
|
||||||
event.stopPropagation();
|
label: null
|
||||||
event.preventDefault();
|
});
|
||||||
};
|
event.stopPropagation();
|
||||||
return (
|
event.preventDefault();
|
||||||
<>
|
};
|
||||||
<div
|
return (
|
||||||
className={classNames(classes.menuListNested, {
|
<>
|
||||||
[classes.menuListNestedOpen]:
|
<div
|
||||||
activeItem.label === ariaLabel && activeItem.isActive
|
className={classNames(classes.menuListNested, {
|
||||||
|
[classes.menuListNestedOpen]:
|
||||||
|
activeItem.label === ariaLabel && activeItem.isActive
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
className={classNames(classes.subHeader, {
|
||||||
|
[classes.subHeaderDark]: isDark
|
||||||
})}
|
})}
|
||||||
|
variant="h5"
|
||||||
>
|
>
|
||||||
<Typography
|
<Hidden mdUp>
|
||||||
className={classNames(classes.subHeader, {
|
<SVG
|
||||||
[classes.subHeaderDark]: isDark
|
className={classNames(classes.menuListNestedIcon, {
|
||||||
})}
|
[classes.menuListNestedIconDark]: isDark
|
||||||
variant="h5"
|
})}
|
||||||
|
src={icon}
|
||||||
|
/>
|
||||||
|
</Hidden>
|
||||||
|
<div className={classes.subHeaderTitle}>{title}</div>
|
||||||
|
<Hidden mdUp>
|
||||||
|
<div
|
||||||
|
className={classNames(classes.menuListNestedClose, {
|
||||||
|
[classes.menuListNestedCloseDark]: isDark
|
||||||
|
})}
|
||||||
|
data-tc={ariaLabel}
|
||||||
|
onClick={() =>
|
||||||
|
closeSubMenu({
|
||||||
|
isActive: false,
|
||||||
|
label: null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SVG src={menuArrowIcon} />
|
||||||
|
</div>
|
||||||
|
</Hidden>
|
||||||
|
</Typography>
|
||||||
|
{menuItems.map(item => (
|
||||||
|
<a
|
||||||
|
className={classNames(classes.menuListNestedItem)}
|
||||||
|
href={createHref(item.url)}
|
||||||
|
data-tc={ariaLabel}
|
||||||
|
onClick={event => closeMenu(item.url, event)}
|
||||||
|
key={item.label}
|
||||||
>
|
>
|
||||||
<Hidden mdUp>
|
<Typography aria-label={item.ariaLabel}>{item.label}</Typography>
|
||||||
<SVG
|
</a>
|
||||||
className={classNames(classes.menuListNestedIcon, {
|
))}
|
||||||
[classes.menuListNestedIconDark]: isDark
|
</div>
|
||||||
})}
|
</>
|
||||||
src={icon}
|
);
|
||||||
/>
|
};
|
||||||
</Hidden>
|
|
||||||
<div className={classes.subHeaderTitle}>{title}</div>
|
MenuNested.displayName = "MenuNested";
|
||||||
<Hidden mdUp>
|
|
||||||
<div
|
|
||||||
className={classNames(classes.menuListNestedClose, {
|
|
||||||
[classes.menuListNestedCloseDark]: isDark
|
|
||||||
})}
|
|
||||||
data-tc={ariaLabel}
|
|
||||||
onClick={() =>
|
|
||||||
closeSubMenu({
|
|
||||||
isActive: false,
|
|
||||||
label: null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<SVG src={menuArrowIcon} />
|
|
||||||
</div>
|
|
||||||
</Hidden>
|
|
||||||
</Typography>
|
|
||||||
{menuItems.map(item => {
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
className={classNames(classes.menuListNestedItem)}
|
|
||||||
href={createHref(item.url)}
|
|
||||||
data-tc={ariaLabel}
|
|
||||||
onClick={event => closeMenu(item.url, event)}
|
|
||||||
key={item.label}
|
|
||||||
>
|
|
||||||
<Typography aria-label={item.ariaLabel}>
|
|
||||||
{item.label}
|
|
||||||
</Typography>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
export default MenuNested;
|
export default MenuNested;
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
import Drawer from "@material-ui/core/Drawer";
|
import Drawer from "@material-ui/core/Drawer";
|
||||||
import Hidden from "@material-ui/core/Hidden";
|
import Hidden from "@material-ui/core/Hidden";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { drawerWidth, drawerWidthExpanded } from "./consts";
|
import { drawerWidth, drawerWidthExpanded } from "./consts";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
drawerDesktop: {
|
drawerDesktop: {
|
||||||
backgroundColor: theme.palette.background.paper,
|
backgroundColor: theme.palette.background.paper,
|
||||||
border: "none",
|
border: "none",
|
||||||
|
@ -29,17 +24,23 @@ const styles = theme =>
|
||||||
drawerMobile: {
|
drawerMobile: {
|
||||||
width: drawerWidthExpanded
|
width: drawerWidthExpanded
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{ name: "ResponsiveDrawer" }
|
||||||
|
);
|
||||||
|
|
||||||
interface ResponsiveDrawerProps extends WithStyles<typeof styles> {
|
interface ResponsiveDrawerProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
small: boolean;
|
small: boolean;
|
||||||
onClose?();
|
onClose?();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ResponsiveDrawer = withStyles(styles, { name: "ResponsiveDrawer" })(
|
const ResponsiveDrawer: React.FC<ResponsiveDrawerProps> = props => {
|
||||||
({ children, classes, onClose, open, small }: ResponsiveDrawerProps) => (
|
const { children, onClose, open, small } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<>
|
<>
|
||||||
<Hidden smDown>
|
<Hidden smDown>
|
||||||
<Drawer
|
<Drawer
|
||||||
|
@ -63,6 +64,6 @@ const ResponsiveDrawer = withStyles(styles, { name: "ResponsiveDrawer" })(
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</Hidden>
|
</Hidden>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
export default ResponsiveDrawer;
|
export default ResponsiveDrawer;
|
||||||
|
|
|
@ -1,43 +1,52 @@
|
||||||
import { Theme, withStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Switch, { SwitchProps } from "@material-ui/core/Switch";
|
import Switch, { SwitchProps } from "@material-ui/core/Switch";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import MoonIcon from "../../icons/Moon";
|
import MoonIcon from "../../icons/Moon";
|
||||||
import SunIcon from "../../icons/Sun";
|
import SunIcon from "../../icons/Sun";
|
||||||
|
|
||||||
const switchStyles = theme => ({
|
const useStyles = makeStyles(
|
||||||
bar: {
|
theme => ({
|
||||||
"$colorPrimary$checked + &": {
|
bar: {
|
||||||
backgroundColor: theme.palette.background.paper
|
"$colorPrimary$checked + &": {
|
||||||
|
backgroundColor: theme.palette.background.paper
|
||||||
|
},
|
||||||
|
background: theme.palette.background.paper
|
||||||
},
|
},
|
||||||
background: theme.palette.background.paper
|
checked: {
|
||||||
},
|
"& svg": {
|
||||||
checked: {
|
background: theme.palette.primary.main,
|
||||||
"& svg": {
|
color: theme.palette.background.paper
|
||||||
background: theme.palette.primary.main,
|
}
|
||||||
color: theme.palette.background.paper
|
},
|
||||||
|
colorPrimary: {},
|
||||||
|
root: {
|
||||||
|
"& svg": {
|
||||||
|
background: theme.palette.primary.main,
|
||||||
|
borderRadius: "100%",
|
||||||
|
height: 20,
|
||||||
|
width: 20
|
||||||
|
},
|
||||||
|
width: 58
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
colorPrimary: {},
|
{
|
||||||
root: {
|
name: "ThemeSwitch"
|
||||||
"& svg": {
|
|
||||||
background: theme.palette.primary.main,
|
|
||||||
borderRadius: "100%",
|
|
||||||
height: 20,
|
|
||||||
width: 20
|
|
||||||
},
|
|
||||||
width: 58
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
const ThemeSwitch = withStyles(switchStyles, {
|
const ThemeSwitch: React.FC<SwitchProps> = props => {
|
||||||
name: "ThemeSwitch"
|
const classes = useStyles(props);
|
||||||
})((props: SwitchProps) => (
|
|
||||||
<Switch
|
return (
|
||||||
{...props}
|
<Switch
|
||||||
color="primary"
|
{...props}
|
||||||
icon={<SunIcon />}
|
classes={classes}
|
||||||
checkedIcon={<MoonIcon />}
|
color="primary"
|
||||||
/>
|
icon={<SunIcon />}
|
||||||
));
|
checkedIcon={<MoonIcon />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
ThemeSwitch.displayName = "ThemeSwitch";
|
ThemeSwitch.displayName = "ThemeSwitch";
|
||||||
export default ThemeSwitch;
|
export default ThemeSwitch;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AppLayout';
|
export { default } from "./AppLayout";
|
||||||
export * from './AppLayout';
|
export * from "./AppLayout";
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Dialog from "@material-ui/core/Dialog";
|
||||||
import DialogActions from "@material-ui/core/DialogActions";
|
import DialogActions from "@material-ui/core/DialogActions";
|
||||||
import DialogContent from "@material-ui/core/DialogContent";
|
import DialogContent from "@material-ui/core/DialogContent";
|
||||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@material-ui/core/Table";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
|
@ -27,7 +27,7 @@ export interface FormData {
|
||||||
query: string;
|
query: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = createStyles({
|
const useStyles = makeStyles({
|
||||||
avatar: {
|
avatar: {
|
||||||
"&:first-child": {
|
"&:first-child": {
|
||||||
paddingLeft: 0
|
paddingLeft: 0
|
||||||
|
@ -44,7 +44,7 @@ const styles = createStyles({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface AssignCategoriesDialogProps extends WithStyles<typeof styles> {
|
interface AssignCategoriesDialogProps {
|
||||||
categories: SearchCategories_search_edges_node[];
|
categories: SearchCategories_search_edges_node[];
|
||||||
confirmButtonState: ConfirmButtonTransitionState;
|
confirmButtonState: ConfirmButtonTransitionState;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -71,11 +71,8 @@ function handleCategoryAssign(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AssignCategoriesDialog = withStyles(styles, {
|
const AssignCategoriesDialog: React.FC<AssignCategoriesDialogProps> = props => {
|
||||||
name: "AssignCategoriesDialog"
|
const {
|
||||||
})(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
confirmButtonState,
|
confirmButtonState,
|
||||||
open,
|
open,
|
||||||
loading,
|
loading,
|
||||||
|
@ -83,102 +80,103 @@ const AssignCategoriesDialog = withStyles(styles, {
|
||||||
onClose,
|
onClose,
|
||||||
onFetch,
|
onFetch,
|
||||||
onSubmit
|
onSubmit
|
||||||
}: AssignCategoriesDialogProps) => {
|
} = props;
|
||||||
const intl = useIntl();
|
const classes = useStyles(props);
|
||||||
const [query, onQueryChange] = useSearchQuery(onFetch);
|
|
||||||
const [selectedCategories, setSelectedCategories] = React.useState<
|
|
||||||
SearchCategories_search_edges_node[]
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
const handleSubmit = () => onSubmit(selectedCategories);
|
const intl = useIntl();
|
||||||
|
const [query, onQueryChange] = useSearchQuery(onFetch);
|
||||||
|
const [selectedCategories, setSelectedCategories] = React.useState<
|
||||||
|
SearchCategories_search_edges_node[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
return (
|
const handleSubmit = () => onSubmit(selectedCategories);
|
||||||
<Dialog
|
|
||||||
open={open}
|
return (
|
||||||
onClose={onClose}
|
<Dialog
|
||||||
classes={{ paper: classes.overflow }}
|
open={open}
|
||||||
fullWidth
|
onClose={onClose}
|
||||||
maxWidth="sm"
|
classes={{ paper: classes.overflow }}
|
||||||
>
|
fullWidth
|
||||||
<DialogTitle>
|
maxWidth="sm"
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Assign Categories"
|
||||||
|
description="dialog header"
|
||||||
|
/>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent className={classes.overflow}>
|
||||||
|
<TextField
|
||||||
|
name="query"
|
||||||
|
value={query}
|
||||||
|
onChange={onQueryChange}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Categories"
|
||||||
|
})}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search by category name, etc..."
|
||||||
|
})}
|
||||||
|
fullWidth
|
||||||
|
InputProps={{
|
||||||
|
autoComplete: "off",
|
||||||
|
endAdornment: loading && <CircularProgress size={16} />
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormSpacer />
|
||||||
|
<Table>
|
||||||
|
<TableBody>
|
||||||
|
{categories &&
|
||||||
|
categories.map(category => {
|
||||||
|
const isSelected = !!selectedCategories.find(
|
||||||
|
selectedCategories => selectedCategories.id === category.id
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow key={category.id}>
|
||||||
|
<TableCell
|
||||||
|
padding="checkbox"
|
||||||
|
className={classes.checkboxCell}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={isSelected}
|
||||||
|
onChange={() =>
|
||||||
|
handleCategoryAssign(
|
||||||
|
category,
|
||||||
|
isSelected,
|
||||||
|
selectedCategories,
|
||||||
|
setSelectedCategories
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.wideCell}>
|
||||||
|
{category.name}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onClose}>
|
||||||
|
<FormattedMessage {...buttonMessages.back} />
|
||||||
|
</Button>
|
||||||
|
<ConfirmButton
|
||||||
|
transitionState={confirmButtonState}
|
||||||
|
color="primary"
|
||||||
|
variant="contained"
|
||||||
|
type="submit"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Assign Categories"
|
defaultMessage="Assign categories"
|
||||||
description="dialog header"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</DialogTitle>
|
</ConfirmButton>
|
||||||
<DialogContent className={classes.overflow}>
|
</DialogActions>
|
||||||
<TextField
|
</Dialog>
|
||||||
name="query"
|
);
|
||||||
value={query}
|
};
|
||||||
onChange={onQueryChange}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Search Categories"
|
|
||||||
})}
|
|
||||||
placeholder={intl.formatMessage({
|
|
||||||
defaultMessage: "Search by category name, etc..."
|
|
||||||
})}
|
|
||||||
fullWidth
|
|
||||||
InputProps={{
|
|
||||||
autoComplete: "off",
|
|
||||||
endAdornment: loading && <CircularProgress size={16} />
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormSpacer />
|
|
||||||
<Table>
|
|
||||||
<TableBody>
|
|
||||||
{categories &&
|
|
||||||
categories.map(category => {
|
|
||||||
const isSelected = !!selectedCategories.find(
|
|
||||||
selectedCategories => selectedCategories.id === category.id
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableRow key={category.id}>
|
|
||||||
<TableCell
|
|
||||||
padding="checkbox"
|
|
||||||
className={classes.checkboxCell}
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
checked={isSelected}
|
|
||||||
onChange={() =>
|
|
||||||
handleCategoryAssign(
|
|
||||||
category,
|
|
||||||
isSelected,
|
|
||||||
selectedCategories,
|
|
||||||
setSelectedCategories
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.wideCell}>
|
|
||||||
{category.name}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={onClose}>
|
|
||||||
<FormattedMessage {...buttonMessages.back} />
|
|
||||||
</Button>
|
|
||||||
<ConfirmButton
|
|
||||||
transitionState={confirmButtonState}
|
|
||||||
color="primary"
|
|
||||||
variant="contained"
|
|
||||||
type="submit"
|
|
||||||
onClick={handleSubmit}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Assign categories"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</ConfirmButton>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
AssignCategoriesDialog.displayName = "AssignCategoriesDialog";
|
AssignCategoriesDialog.displayName = "AssignCategoriesDialog";
|
||||||
export default AssignCategoriesDialog;
|
export default AssignCategoriesDialog;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Dialog from "@material-ui/core/Dialog";
|
||||||
import DialogActions from "@material-ui/core/DialogActions";
|
import DialogActions from "@material-ui/core/DialogActions";
|
||||||
import DialogContent from "@material-ui/core/DialogContent";
|
import DialogContent from "@material-ui/core/DialogContent";
|
||||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@material-ui/core/Table";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
|
@ -27,7 +27,7 @@ export interface FormData {
|
||||||
query: string;
|
query: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = createStyles({
|
const useStyles = makeStyles({
|
||||||
avatar: {
|
avatar: {
|
||||||
"&:first-child": {
|
"&:first-child": {
|
||||||
paddingLeft: 0
|
paddingLeft: 0
|
||||||
|
@ -44,7 +44,7 @@ const styles = createStyles({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface AssignCollectionDialogProps extends WithStyles<typeof styles> {
|
interface AssignCollectionDialogProps {
|
||||||
collections: SearchCollections_search_edges_node[];
|
collections: SearchCollections_search_edges_node[];
|
||||||
confirmButtonState: ConfirmButtonTransitionState;
|
confirmButtonState: ConfirmButtonTransitionState;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -71,11 +71,8 @@ function handleCollectionAssign(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AssignCollectionDialog = withStyles(styles, {
|
const AssignCollectionDialog: React.FC<AssignCollectionDialogProps> = props => {
|
||||||
name: "AssignCollectionDialog"
|
const {
|
||||||
})(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
confirmButtonState,
|
confirmButtonState,
|
||||||
open,
|
open,
|
||||||
loading,
|
loading,
|
||||||
|
@ -83,103 +80,103 @@ const AssignCollectionDialog = withStyles(styles, {
|
||||||
onClose,
|
onClose,
|
||||||
onFetch,
|
onFetch,
|
||||||
onSubmit
|
onSubmit
|
||||||
}: AssignCollectionDialogProps) => {
|
} = props;
|
||||||
const intl = useIntl();
|
const classes = useStyles(props);
|
||||||
const [query, onQueryChange] = useSearchQuery(onFetch);
|
|
||||||
const [selectedCollections, setSelectedCollections] = React.useState<
|
|
||||||
SearchCollections_search_edges_node[]
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
const handleSubmit = () => onSubmit(selectedCollections);
|
const intl = useIntl();
|
||||||
|
const [query, onQueryChange] = useSearchQuery(onFetch);
|
||||||
|
const [selectedCollections, setSelectedCollections] = React.useState<
|
||||||
|
SearchCollections_search_edges_node[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
return (
|
const handleSubmit = () => onSubmit(selectedCollections);
|
||||||
<Dialog
|
|
||||||
onClose={onClose}
|
return (
|
||||||
open={open}
|
<Dialog
|
||||||
classes={{ paper: classes.overflow }}
|
onClose={onClose}
|
||||||
fullWidth
|
open={open}
|
||||||
maxWidth="sm"
|
classes={{ paper: classes.overflow }}
|
||||||
>
|
fullWidth
|
||||||
<DialogTitle>
|
maxWidth="sm"
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Assign Collection"
|
||||||
|
description="dialog header"
|
||||||
|
/>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent className={classes.overflow}>
|
||||||
|
<TextField
|
||||||
|
name="query"
|
||||||
|
value={query}
|
||||||
|
onChange={onQueryChange}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Collection"
|
||||||
|
})}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search by collection name, etc..."
|
||||||
|
})}
|
||||||
|
fullWidth
|
||||||
|
InputProps={{
|
||||||
|
autoComplete: "off",
|
||||||
|
endAdornment: loading && <CircularProgress size={16} />
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormSpacer />
|
||||||
|
<Table>
|
||||||
|
<TableBody>
|
||||||
|
{collections &&
|
||||||
|
collections.map(collection => {
|
||||||
|
const isSelected = !!selectedCollections.find(
|
||||||
|
selectedCollection => selectedCollection.id === collection.id
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow key={collection.id}>
|
||||||
|
<TableCell
|
||||||
|
padding="checkbox"
|
||||||
|
className={classes.checkboxCell}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={isSelected}
|
||||||
|
onChange={() =>
|
||||||
|
handleCollectionAssign(
|
||||||
|
collection,
|
||||||
|
isSelected,
|
||||||
|
selectedCollections,
|
||||||
|
setSelectedCollections
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={classes.wideCell}>
|
||||||
|
{collection.name}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onClose}>
|
||||||
|
<FormattedMessage {...buttonMessages.back} />
|
||||||
|
</Button>
|
||||||
|
<ConfirmButton
|
||||||
|
transitionState={confirmButtonState}
|
||||||
|
color="primary"
|
||||||
|
variant="contained"
|
||||||
|
type="submit"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Assign Collection"
|
defaultMessage="Assign collections"
|
||||||
description="dialog header"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</DialogTitle>
|
</ConfirmButton>
|
||||||
<DialogContent className={classes.overflow}>
|
</DialogActions>
|
||||||
<TextField
|
</Dialog>
|
||||||
name="query"
|
);
|
||||||
value={query}
|
};
|
||||||
onChange={onQueryChange}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Search Collection"
|
|
||||||
})}
|
|
||||||
placeholder={intl.formatMessage({
|
|
||||||
defaultMessage: "Search by collection name, etc..."
|
|
||||||
})}
|
|
||||||
fullWidth
|
|
||||||
InputProps={{
|
|
||||||
autoComplete: "off",
|
|
||||||
endAdornment: loading && <CircularProgress size={16} />
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormSpacer />
|
|
||||||
<Table>
|
|
||||||
<TableBody>
|
|
||||||
{collections &&
|
|
||||||
collections.map(collection => {
|
|
||||||
const isSelected = !!selectedCollections.find(
|
|
||||||
selectedCollection =>
|
|
||||||
selectedCollection.id === collection.id
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableRow key={collection.id}>
|
|
||||||
<TableCell
|
|
||||||
padding="checkbox"
|
|
||||||
className={classes.checkboxCell}
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
checked={isSelected}
|
|
||||||
onChange={() =>
|
|
||||||
handleCollectionAssign(
|
|
||||||
collection,
|
|
||||||
isSelected,
|
|
||||||
selectedCollections,
|
|
||||||
setSelectedCollections
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className={classes.wideCell}>
|
|
||||||
{collection.name}
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={onClose}>
|
|
||||||
<FormattedMessage {...buttonMessages.back} />
|
|
||||||
</Button>
|
|
||||||
<ConfirmButton
|
|
||||||
transitionState={confirmButtonState}
|
|
||||||
color="primary"
|
|
||||||
variant="contained"
|
|
||||||
type="submit"
|
|
||||||
onClick={handleSubmit}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Assign collections"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</ConfirmButton>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
AssignCollectionDialog.displayName = "AssignCollectionDialog";
|
AssignCollectionDialog.displayName = "AssignCollectionDialog";
|
||||||
export default AssignCollectionDialog;
|
export default AssignCollectionDialog;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Dialog from "@material-ui/core/Dialog";
|
||||||
import DialogActions from "@material-ui/core/DialogActions";
|
import DialogActions from "@material-ui/core/DialogActions";
|
||||||
import DialogContent from "@material-ui/core/DialogContent";
|
import DialogContent from "@material-ui/core/DialogContent";
|
||||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@material-ui/core/Table";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
|
@ -29,7 +29,7 @@ export interface FormData {
|
||||||
query: string;
|
query: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = createStyles({
|
const useStyles = makeStyles({
|
||||||
avatar: {
|
avatar: {
|
||||||
"&:first-child": {
|
"&:first-child": {
|
||||||
paddingLeft: 0
|
paddingLeft: 0
|
||||||
|
@ -77,11 +77,8 @@ function handleProductAssign(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AssignProductDialog = withStyles(styles, {
|
const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
|
||||||
name: "AssignProductDialog"
|
const {
|
||||||
})(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
confirmButtonState,
|
confirmButtonState,
|
||||||
open,
|
open,
|
||||||
loading,
|
loading,
|
||||||
|
@ -89,109 +86,110 @@ const AssignProductDialog = withStyles(styles, {
|
||||||
onClose,
|
onClose,
|
||||||
onFetch,
|
onFetch,
|
||||||
onSubmit
|
onSubmit
|
||||||
}: AssignProductDialogProps & WithStyles<typeof styles>) => {
|
} = props;
|
||||||
const intl = useIntl();
|
const classes = useStyles(props);
|
||||||
const [query, onQueryChange] = useSearchQuery(onFetch);
|
|
||||||
const [selectedProducts, setSelectedProducts] = React.useState<
|
|
||||||
SearchProducts_search_edges_node[]
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
const handleSubmit = () => onSubmit(selectedProducts);
|
const intl = useIntl();
|
||||||
|
const [query, onQueryChange] = useSearchQuery(onFetch);
|
||||||
|
const [selectedProducts, setSelectedProducts] = React.useState<
|
||||||
|
SearchProducts_search_edges_node[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
return (
|
const handleSubmit = () => onSubmit(selectedProducts);
|
||||||
<Dialog
|
|
||||||
onClose={onClose}
|
|
||||||
open={open}
|
|
||||||
classes={{ paper: classes.overflow }}
|
|
||||||
fullWidth
|
|
||||||
maxWidth="sm"
|
|
||||||
>
|
|
||||||
<DialogTitle>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Assign Product"
|
|
||||||
description="dialog header"
|
|
||||||
/>
|
|
||||||
</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
<TextField
|
|
||||||
name="query"
|
|
||||||
value={query}
|
|
||||||
onChange={onQueryChange}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Search Products"
|
|
||||||
})}
|
|
||||||
placeholder={intl.formatMessage({
|
|
||||||
defaultMessage:
|
|
||||||
"Search by product name, attribute, product type etc..."
|
|
||||||
})}
|
|
||||||
fullWidth
|
|
||||||
InputProps={{
|
|
||||||
autoComplete: "off",
|
|
||||||
endAdornment: loading && <CircularProgress size={16} />
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormSpacer />
|
|
||||||
<div className={classes.scrollArea}>
|
|
||||||
<Table>
|
|
||||||
<TableBody>
|
|
||||||
{products &&
|
|
||||||
products.map(product => {
|
|
||||||
const isSelected = selectedProducts.some(
|
|
||||||
selectedProduct => selectedProduct.id === product.id
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow key={product.id}>
|
<Dialog
|
||||||
<TableCellAvatar
|
onClose={onClose}
|
||||||
className={classes.avatar}
|
open={open}
|
||||||
thumbnail={maybe(() => product.thumbnail.url)}
|
classes={{ paper: classes.overflow }}
|
||||||
|
fullWidth
|
||||||
|
maxWidth="sm"
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Assign Product"
|
||||||
|
description="dialog header"
|
||||||
|
/>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<TextField
|
||||||
|
name="query"
|
||||||
|
value={query}
|
||||||
|
onChange={onQueryChange}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Products"
|
||||||
|
})}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
defaultMessage:
|
||||||
|
"Search by product name, attribute, product type etc..."
|
||||||
|
})}
|
||||||
|
fullWidth
|
||||||
|
InputProps={{
|
||||||
|
autoComplete: "off",
|
||||||
|
endAdornment: loading && <CircularProgress size={16} />
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormSpacer />
|
||||||
|
<div className={classes.scrollArea}>
|
||||||
|
<Table>
|
||||||
|
<TableBody>
|
||||||
|
{products &&
|
||||||
|
products.map(product => {
|
||||||
|
const isSelected = selectedProducts.some(
|
||||||
|
selectedProduct => selectedProduct.id === product.id
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow key={product.id}>
|
||||||
|
<TableCellAvatar
|
||||||
|
className={classes.avatar}
|
||||||
|
thumbnail={maybe(() => product.thumbnail.url)}
|
||||||
|
/>
|
||||||
|
<TableCell className={classes.wideCell}>
|
||||||
|
{product.name}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
padding="checkbox"
|
||||||
|
className={classes.checkboxCell}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={isSelected}
|
||||||
|
onChange={() =>
|
||||||
|
handleProductAssign(
|
||||||
|
product,
|
||||||
|
isSelected,
|
||||||
|
selectedProducts,
|
||||||
|
setSelectedProducts
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<TableCell className={classes.wideCell}>
|
</TableCell>
|
||||||
{product.name}
|
</TableRow>
|
||||||
</TableCell>
|
);
|
||||||
<TableCell
|
})}
|
||||||
padding="checkbox"
|
</TableBody>
|
||||||
className={classes.checkboxCell}
|
</Table>
|
||||||
>
|
</div>
|
||||||
<Checkbox
|
</DialogContent>
|
||||||
checked={isSelected}
|
<DialogActions>
|
||||||
onChange={() =>
|
<Button onClick={onClose}>
|
||||||
handleProductAssign(
|
<FormattedMessage {...buttonMessages.back} />
|
||||||
product,
|
</Button>
|
||||||
isSelected,
|
<ConfirmButton
|
||||||
selectedProducts,
|
transitionState={confirmButtonState}
|
||||||
setSelectedProducts
|
color="primary"
|
||||||
)
|
variant="contained"
|
||||||
}
|
type="submit"
|
||||||
/>
|
onClick={handleSubmit}
|
||||||
</TableCell>
|
>
|
||||||
</TableRow>
|
<FormattedMessage
|
||||||
);
|
defaultMessage="Assign products"
|
||||||
})}
|
description="button"
|
||||||
</TableBody>
|
/>
|
||||||
</Table>
|
</ConfirmButton>
|
||||||
</div>
|
</DialogActions>
|
||||||
</DialogContent>
|
</Dialog>
|
||||||
<DialogActions>
|
);
|
||||||
<Button onClick={onClose}>
|
};
|
||||||
<FormattedMessage {...buttonMessages.back} />
|
|
||||||
</Button>
|
|
||||||
<ConfirmButton
|
|
||||||
transitionState={confirmButtonState}
|
|
||||||
color="primary"
|
|
||||||
variant="contained"
|
|
||||||
type="submit"
|
|
||||||
onClick={handleSubmit}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Assign products"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</ConfirmButton>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
AssignProductDialog.displayName = "AssignProductDialog";
|
AssignProductDialog.displayName = "AssignProductDialog";
|
||||||
export default AssignProductDialog;
|
export default AssignProductDialog;
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@material-ui/core/MenuItem";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import ArrowBack from "@material-ui/icons/ArrowBack";
|
import ArrowBack from "@material-ui/icons/ArrowBack";
|
||||||
import Downshift from "downshift";
|
import Downshift from "downshift";
|
||||||
|
@ -43,31 +38,27 @@ const DebounceAutocomplete: React.ComponentType<
|
||||||
DebounceProps<string>
|
DebounceProps<string>
|
||||||
> = Debounce;
|
> = Debounce;
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
container: {
|
||||||
container: {
|
flexGrow: 1,
|
||||||
flexGrow: 1,
|
position: "relative"
|
||||||
position: "relative"
|
},
|
||||||
},
|
menuBack: {
|
||||||
menuBack: {
|
marginLeft: -theme.spacing(0.5),
|
||||||
marginLeft: -theme.spacing(.5),
|
marginRight: theme.spacing(1)
|
||||||
marginRight: theme.spacing(1)
|
},
|
||||||
},
|
paper: {
|
||||||
paper: {
|
left: 0,
|
||||||
left: 0,
|
marginTop: theme.spacing(),
|
||||||
marginTop: theme.spacing(),
|
padding: theme.spacing(),
|
||||||
padding: theme.spacing(),
|
position: "absolute",
|
||||||
position: "absolute",
|
right: 0,
|
||||||
right: 0,
|
zIndex: 2
|
||||||
zIndex: 2
|
},
|
||||||
},
|
root: {}
|
||||||
root: {}
|
}));
|
||||||
});
|
const AutocompleteSelectMenu: React.FC<AutocompleteSelectMenuProps> = props => {
|
||||||
const AutocompleteSelectMenu = withStyles(styles, {
|
const {
|
||||||
name: "AutocompleteSelectMenu"
|
|
||||||
})(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
disabled,
|
disabled,
|
||||||
displayValue,
|
displayValue,
|
||||||
error,
|
error,
|
||||||
|
@ -79,117 +70,118 @@ const AutocompleteSelectMenu = withStyles(styles, {
|
||||||
placeholder,
|
placeholder,
|
||||||
onChange,
|
onChange,
|
||||||
onInputChange
|
onInputChange
|
||||||
}: AutocompleteSelectMenuProps & WithStyles<typeof styles>) => {
|
} = props;
|
||||||
const [inputValue, setInputValue] = React.useState(displayValue || "");
|
const classes = useStyles(props);
|
||||||
const [menuPath, setMenuPath] = React.useState<number[]>([]);
|
|
||||||
|
|
||||||
const handleChange = (value: string) =>
|
const [inputValue, setInputValue] = React.useState(displayValue || "");
|
||||||
onChange({
|
const [menuPath, setMenuPath] = React.useState<number[]>([]);
|
||||||
target: {
|
|
||||||
name,
|
|
||||||
value
|
|
||||||
}
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
// Validate if option values are duplicated
|
const handleChange = (value: string) =>
|
||||||
React.useEffect(() => {
|
onChange({
|
||||||
if (!validateMenuOptions(options)) {
|
target: {
|
||||||
throw validationError;
|
name,
|
||||||
|
value
|
||||||
}
|
}
|
||||||
}, []);
|
} as any);
|
||||||
|
|
||||||
// Navigate back to main menu after input field change
|
// Validate if option values are duplicated
|
||||||
React.useEffect(() => setMenuPath([]), [options]);
|
React.useEffect(() => {
|
||||||
|
if (!validateMenuOptions(options)) {
|
||||||
|
throw validationError;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Reset input value after displayValue change
|
// Navigate back to main menu after input field change
|
||||||
React.useEffect(() => setInputValue(displayValue), [displayValue]);
|
React.useEffect(() => setMenuPath([]), [options]);
|
||||||
|
|
||||||
return (
|
// Reset input value after displayValue change
|
||||||
<DebounceAutocomplete debounceFn={onInputChange}>
|
React.useEffect(() => setInputValue(displayValue), [displayValue]);
|
||||||
{debounceFn => (
|
|
||||||
<Downshift
|
return (
|
||||||
itemToString={item => (item ? item.label : "")}
|
<DebounceAutocomplete debounceFn={onInputChange}>
|
||||||
onSelect={handleChange}
|
{debounceFn => (
|
||||||
>
|
<Downshift
|
||||||
{({ getItemProps, isOpen, openMenu, closeMenu, selectItem }) => {
|
itemToString={item => (item ? item.label : "")}
|
||||||
return (
|
onSelect={handleChange}
|
||||||
<div className={classes.container}>
|
>
|
||||||
<TextField
|
{({ getItemProps, isOpen, openMenu, closeMenu, selectItem }) => {
|
||||||
InputProps={{
|
return (
|
||||||
endAdornment: loading && <CircularProgress size={16} />,
|
<div className={classes.container}>
|
||||||
id: undefined,
|
<TextField
|
||||||
onBlur: () => {
|
InputProps={{
|
||||||
closeMenu();
|
endAdornment: loading && <CircularProgress size={16} />,
|
||||||
setMenuPath([]);
|
id: undefined,
|
||||||
setInputValue(displayValue);
|
onBlur: () => {
|
||||||
},
|
closeMenu();
|
||||||
onChange: event => {
|
setMenuPath([]);
|
||||||
debounceFn(event.target.value);
|
setInputValue(displayValue);
|
||||||
setInputValue(event.target.value);
|
},
|
||||||
},
|
onChange: event => {
|
||||||
onFocus: () => openMenu(),
|
debounceFn(event.target.value);
|
||||||
placeholder
|
setInputValue(event.target.value);
|
||||||
}}
|
},
|
||||||
disabled={disabled}
|
onFocus: () => openMenu(),
|
||||||
error={error}
|
placeholder
|
||||||
helperText={helperText}
|
}}
|
||||||
label={label}
|
disabled={disabled}
|
||||||
fullWidth={true}
|
error={error}
|
||||||
value={inputValue}
|
helperText={helperText}
|
||||||
/>
|
label={label}
|
||||||
{isOpen && (
|
fullWidth={true}
|
||||||
<Paper className={classes.paper} square>
|
value={inputValue}
|
||||||
{options.length ? (
|
/>
|
||||||
<>
|
{isOpen && (
|
||||||
{menuPath.length > 0 && (
|
<Paper className={classes.paper} square>
|
||||||
<MenuItem
|
{options.length ? (
|
||||||
component="div"
|
<>
|
||||||
{...getItemProps({
|
{menuPath.length > 0 && (
|
||||||
item: null
|
<MenuItem
|
||||||
})}
|
component="div"
|
||||||
onClick={() =>
|
{...getItemProps({
|
||||||
setMenuPath(
|
item: null
|
||||||
menuPath.slice(0, menuPath.length - 2)
|
})}
|
||||||
)
|
onClick={() =>
|
||||||
}
|
setMenuPath(
|
||||||
>
|
menuPath.slice(0, menuPath.length - 2)
|
||||||
<ArrowBack className={classes.menuBack} />
|
)
|
||||||
<FormattedMessage {...buttonMessages.back} />
|
}
|
||||||
</MenuItem>
|
>
|
||||||
)}
|
<ArrowBack className={classes.menuBack} />
|
||||||
{(menuPath.length
|
<FormattedMessage {...buttonMessages.back} />
|
||||||
? getMenuItemByPath(options, menuPath).children
|
</MenuItem>
|
||||||
: options
|
)}
|
||||||
).map((suggestion, index) => (
|
{(menuPath.length
|
||||||
<MenuItem
|
? getMenuItemByPath(options, menuPath).children
|
||||||
key={suggestion.value}
|
: options
|
||||||
component="div"
|
).map((suggestion, index) => (
|
||||||
{...getItemProps({ item: suggestion })}
|
<MenuItem
|
||||||
onClick={() =>
|
key={suggestion.value}
|
||||||
suggestion.value
|
component="div"
|
||||||
? selectItem(suggestion.value)
|
{...getItemProps({ item: suggestion })}
|
||||||
: setMenuPath([...menuPath, index])
|
onClick={() =>
|
||||||
}
|
suggestion.value
|
||||||
>
|
? selectItem(suggestion.value)
|
||||||
{suggestion.label}
|
: setMenuPath([...menuPath, index])
|
||||||
</MenuItem>
|
}
|
||||||
))}
|
>
|
||||||
</>
|
{suggestion.label}
|
||||||
) : (
|
</MenuItem>
|
||||||
<MenuItem disabled component="div">
|
))}
|
||||||
<FormattedMessage defaultMessage="No results" />
|
</>
|
||||||
</MenuItem>
|
) : (
|
||||||
)}
|
<MenuItem disabled component="div">
|
||||||
</Paper>
|
<FormattedMessage defaultMessage="No results" />
|
||||||
)}
|
</MenuItem>
|
||||||
</div>
|
)}
|
||||||
);
|
</Paper>
|
||||||
}}
|
)}
|
||||||
</Downshift>
|
</div>
|
||||||
)}
|
);
|
||||||
</DebounceAutocomplete>
|
}}
|
||||||
);
|
</Downshift>
|
||||||
}
|
)}
|
||||||
);
|
</DebounceAutocomplete>
|
||||||
|
);
|
||||||
|
};
|
||||||
AutocompleteSelectMenu.displayName = "AutocompleteSelectMenu";
|
AutocompleteSelectMenu.displayName = "AutocompleteSelectMenu";
|
||||||
export default AutocompleteSelectMenu;
|
export default AutocompleteSelectMenu;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './AutocompleteSelectMenu';
|
export { default } from "./AutocompleteSelectMenu";
|
||||||
export * from './AutocompleteSelectMenu';
|
export * from "./AutocompleteSelectMenu";
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import Menu from "@material-ui/core/Menu";
|
import Menu from "@material-ui/core/Menu";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@material-ui/core/MenuItem";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import MoreVertIcon from "@material-ui/icons/MoreVert";
|
import MoreVertIcon from "@material-ui/icons/MoreVert";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
@ -23,80 +18,73 @@ export interface CardMenuProps {
|
||||||
menuItems: CardMenuItem[];
|
menuItems: CardMenuItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
iconButton: {
|
||||||
iconButton: {
|
background: theme.palette.background.paper,
|
||||||
background: theme.palette.background.paper,
|
borderRadius: "100%",
|
||||||
borderRadius: "100%",
|
height: 32,
|
||||||
height: 32,
|
padding: 0,
|
||||||
padding: 0,
|
width: 32
|
||||||
width: 32
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const CardMenu = withStyles(styles, {
|
|
||||||
name: "CardMenu"
|
|
||||||
})(
|
|
||||||
({
|
|
||||||
className,
|
|
||||||
classes,
|
|
||||||
disabled,
|
|
||||||
menuItems
|
|
||||||
}: CardMenuProps & WithStyles<typeof styles>) => {
|
|
||||||
const [anchorEl, setAnchor] = React.useState<HTMLElement | null>(null);
|
|
||||||
|
|
||||||
const handleClick = (event: React.MouseEvent<any>) => {
|
|
||||||
setAnchor(event.currentTarget);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
setAnchor(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMenuClick = (menuItemIndex: number) => {
|
|
||||||
menuItems[menuItemIndex].onSelect();
|
|
||||||
handleClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
const open = !!anchorEl;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={className}>
|
|
||||||
<IconButton
|
|
||||||
aria-label="More"
|
|
||||||
aria-owns={open ? "long-menu" : null}
|
|
||||||
aria-haspopup="true"
|
|
||||||
className={classes.iconButton}
|
|
||||||
color="primary"
|
|
||||||
disabled={disabled}
|
|
||||||
onClick={handleClick}
|
|
||||||
>
|
|
||||||
<MoreVertIcon />
|
|
||||||
</IconButton>
|
|
||||||
<Menu
|
|
||||||
id="long-menu"
|
|
||||||
anchorEl={anchorEl}
|
|
||||||
open={open}
|
|
||||||
onClose={handleClose}
|
|
||||||
PaperProps={{
|
|
||||||
style: {
|
|
||||||
maxHeight: ITEM_HEIGHT * 4.5
|
|
||||||
// width: 200
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{menuItems.map((menuItem, menuItemIndex) => (
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => handleMenuClick(menuItemIndex)}
|
|
||||||
key={menuItem.label}
|
|
||||||
>
|
|
||||||
{menuItem.label}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Menu>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
}));
|
||||||
|
|
||||||
|
const CardMenu: React.FC<CardMenuProps> = props => {
|
||||||
|
const { className, disabled, menuItems } = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
const [anchorEl, setAnchor] = React.useState<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
const handleClick = (event: React.MouseEvent<any>) => {
|
||||||
|
setAnchor(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchor(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuClick = (menuItemIndex: number) => {
|
||||||
|
menuItems[menuItemIndex].onSelect();
|
||||||
|
handleClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const open = !!anchorEl;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<IconButton
|
||||||
|
aria-label="More"
|
||||||
|
aria-owns={open ? "long-menu" : null}
|
||||||
|
aria-haspopup="true"
|
||||||
|
className={classes.iconButton}
|
||||||
|
color="primary"
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
<Menu
|
||||||
|
id="long-menu"
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
PaperProps={{
|
||||||
|
style: {
|
||||||
|
maxHeight: ITEM_HEIGHT * 4.5
|
||||||
|
// width: 200
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{menuItems.map((menuItem, menuItemIndex) => (
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => handleMenuClick(menuItemIndex)}
|
||||||
|
key={menuItem.label}
|
||||||
|
>
|
||||||
|
{menuItem.label}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
CardMenu.displayName = "CardMenu";
|
CardMenu.displayName = "CardMenu";
|
||||||
export default CardMenu;
|
export default CardMenu;
|
||||||
|
|
|
@ -1,29 +1,25 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
spacer: {
|
||||||
spacer: {
|
[theme.breakpoints.down("sm")]: {
|
||||||
[theme.breakpoints.down("sm")]: {
|
marginTop: theme.spacing(1)
|
||||||
marginTop: theme.spacing(1)
|
},
|
||||||
},
|
marginTop: theme.spacing(3)
|
||||||
marginTop: theme.spacing(3)
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface CardSpacerProps extends WithStyles<typeof styles> {
|
interface CardSpacerProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CardSpacer = withStyles(styles, { name: "CardSpacer" })(
|
export const CardSpacer: React.FC<CardSpacerProps> = props => {
|
||||||
({ classes, children }: CardSpacerProps) => (
|
const { children } = props;
|
||||||
<div className={classes.spacer}>{children}</div>
|
|
||||||
)
|
const classes = useStyles(props);
|
||||||
);
|
|
||||||
|
return <div className={classes.spacer}>{children}</div>;
|
||||||
|
};
|
||||||
CardSpacer.displayName = "CardSpacer";
|
CardSpacer.displayName = "CardSpacer";
|
||||||
export default CardSpacer;
|
export default CardSpacer;
|
||||||
|
|
|
@ -1,42 +1,36 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
children: theme.mixins.gutters({}),
|
||||||
children: theme.mixins.gutters({}),
|
constantHeight: {
|
||||||
constantHeight: {
|
height: 56
|
||||||
height: 56
|
},
|
||||||
},
|
hr: {
|
||||||
hr: {
|
border: "none",
|
||||||
border: "none",
|
borderTop: `1px solid ${theme.palette.divider}`,
|
||||||
borderTop: `1px solid ${theme.overrides.MuiCard.root.borderColor}`,
|
height: 0,
|
||||||
height: 0,
|
marginBottom: 0,
|
||||||
marginBottom: 0,
|
marginTop: 0,
|
||||||
marginTop: 0,
|
width: "100%"
|
||||||
width: "100%"
|
},
|
||||||
},
|
root: theme.mixins.gutters({
|
||||||
root: theme.mixins.gutters({
|
alignItems: "center",
|
||||||
alignItems: "center",
|
display: "flex",
|
||||||
display: "flex",
|
minHeight: 56
|
||||||
minHeight: 56
|
}),
|
||||||
}),
|
title: {
|
||||||
title: {
|
flex: 1,
|
||||||
flex: 1,
|
lineHeight: 1
|
||||||
lineHeight: 1
|
},
|
||||||
},
|
toolbar: {
|
||||||
toolbar: {
|
marginRight: -theme.spacing(1)
|
||||||
marginRight: -theme.spacing(1)
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface CardTitleProps extends WithStyles<typeof styles> {
|
interface CardTitleProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
height?: "default" | "const";
|
height?: "default" | "const";
|
||||||
|
@ -45,24 +39,27 @@ interface CardTitleProps extends WithStyles<typeof styles> {
|
||||||
onClick?: (event: React.MouseEvent<any>) => void;
|
onClick?: (event: React.MouseEvent<any>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CardTitle = withStyles(styles, { name: "CardTitle" })(
|
const CardTitle: React.FC<CardTitleProps> = props => {
|
||||||
({
|
const {
|
||||||
classes,
|
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
height,
|
height,
|
||||||
title,
|
title,
|
||||||
toolbar,
|
toolbar,
|
||||||
onClick,
|
onClick,
|
||||||
...props
|
...rest
|
||||||
}: CardTitleProps) => (
|
} = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={classNames(classes.root, {
|
className={classNames(classes.root, {
|
||||||
[className]: !!className,
|
[className]: !!className,
|
||||||
[classes.constantHeight]: height === "const"
|
[classes.constantHeight]: height === "const"
|
||||||
})}
|
})}
|
||||||
{...props}
|
{...rest}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
className={classes.title}
|
className={classes.title}
|
||||||
|
@ -77,7 +74,7 @@ const CardTitle = withStyles(styles, { name: "CardTitle" })(
|
||||||
<div className={classes.children}>{children}</div>
|
<div className={classes.children}>{children}</div>
|
||||||
<hr className={classes.hr} />
|
<hr className={classes.hr} />
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
CardTitle.displayName = "CardTitle";
|
CardTitle.displayName = "CardTitle";
|
||||||
export default CardTitle;
|
export default CardTitle;
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
import { Omit } from "@material-ui/core";
|
|
||||||
import ButtonBase from "@material-ui/core/ButtonBase";
|
import ButtonBase from "@material-ui/core/ButtonBase";
|
||||||
import { CheckboxProps as MuiCheckboxProps } from "@material-ui/core/Checkbox";
|
import { CheckboxProps as MuiCheckboxProps } from "@material-ui/core/Checkbox";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
@ -25,116 +19,116 @@ export type CheckboxProps = Omit<
|
||||||
onChange?: (event: React.ChangeEvent<any>) => void;
|
onChange?: (event: React.ChangeEvent<any>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
box: {
|
||||||
box: {
|
"&$checked": {
|
||||||
"&$checked": {
|
|
||||||
"&:before": {
|
|
||||||
background: theme.palette.primary.main,
|
|
||||||
color: theme.palette.background.paper,
|
|
||||||
content: '"\\2713"',
|
|
||||||
fontWeight: "bold",
|
|
||||||
textAlign: "center"
|
|
||||||
},
|
|
||||||
borderColor: theme.palette.primary.main
|
|
||||||
},
|
|
||||||
"&$disabled": {
|
|
||||||
borderColor: theme.palette.grey[200]
|
|
||||||
},
|
|
||||||
"&$indeterminate": {
|
|
||||||
"&:before": {
|
|
||||||
background: theme.palette.primary.main,
|
|
||||||
height: 2,
|
|
||||||
top: 5
|
|
||||||
},
|
|
||||||
borderColor: theme.palette.primary.main
|
|
||||||
},
|
|
||||||
"&:before": {
|
"&:before": {
|
||||||
background: "rgba(0, 0, 0, 0)",
|
background: theme.palette.primary.main,
|
||||||
content: '""',
|
color: theme.palette.background.paper,
|
||||||
height: 14,
|
content: '"\\2713"',
|
||||||
left: -1,
|
fontWeight: "bold",
|
||||||
position: "absolute",
|
textAlign: "center"
|
||||||
top: -1,
|
|
||||||
transition: theme.transitions.duration.short + "ms",
|
|
||||||
width: 14
|
|
||||||
},
|
},
|
||||||
|
borderColor: theme.palette.primary.main
|
||||||
WebkitAppearance: "none",
|
},
|
||||||
border: `1px solid ${theme.palette.action.active}`,
|
"&$disabled": {
|
||||||
boxSizing: "border-box",
|
borderColor: theme.palette.grey[200]
|
||||||
cursor: "pointer",
|
},
|
||||||
|
"&$indeterminate": {
|
||||||
|
"&:before": {
|
||||||
|
background: theme.palette.primary.main,
|
||||||
|
height: 2,
|
||||||
|
top: 5
|
||||||
|
},
|
||||||
|
borderColor: theme.palette.primary.main
|
||||||
|
},
|
||||||
|
"&:before": {
|
||||||
|
background: "rgba(0, 0, 0, 0)",
|
||||||
|
content: '""',
|
||||||
height: 14,
|
height: 14,
|
||||||
outline: "0",
|
left: -1,
|
||||||
position: "relative",
|
position: "absolute",
|
||||||
userSelect: "none",
|
top: -1,
|
||||||
|
transition: theme.transitions.duration.short + "ms",
|
||||||
width: 14
|
width: 14
|
||||||
},
|
},
|
||||||
checked: {},
|
|
||||||
disabled: {},
|
WebkitAppearance: "none",
|
||||||
indeterminate: {},
|
border: `1px solid ${theme.palette.action.active}`,
|
||||||
root: {
|
boxSizing: "border-box",
|
||||||
"&:hover": {
|
cursor: "pointer",
|
||||||
background: fade(theme.palette.primary.main, 0.1)
|
height: 14,
|
||||||
},
|
outline: "0",
|
||||||
alignSelf: "start",
|
position: "relative",
|
||||||
borderRadius: "100%",
|
userSelect: "none",
|
||||||
cursor: "pointer",
|
width: 14
|
||||||
display: "flex",
|
},
|
||||||
height: 30,
|
checked: {},
|
||||||
justifyContent: "center",
|
disabled: {},
|
||||||
margin: "5px 9px",
|
indeterminate: {},
|
||||||
width: 30
|
root: {
|
||||||
}
|
"&:hover": {
|
||||||
});
|
background: fade(theme.palette.primary.main, 0.1)
|
||||||
const Checkbox = withStyles(styles, { name: "Checkbox" })(
|
},
|
||||||
({
|
alignSelf: "start",
|
||||||
|
borderRadius: "100%",
|
||||||
|
cursor: "pointer",
|
||||||
|
display: "flex",
|
||||||
|
height: 30,
|
||||||
|
justifyContent: "center",
|
||||||
|
margin: "5px 9px",
|
||||||
|
width: 30
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
const Checkbox: React.FC<CheckboxProps> = props => {
|
||||||
|
const {
|
||||||
checked,
|
checked,
|
||||||
className,
|
className,
|
||||||
classes,
|
|
||||||
disabled,
|
disabled,
|
||||||
disableClickPropagation,
|
disableClickPropagation,
|
||||||
indeterminate,
|
indeterminate,
|
||||||
onChange,
|
onChange,
|
||||||
value,
|
value,
|
||||||
name,
|
name,
|
||||||
...props
|
...rest
|
||||||
}: CheckboxProps & WithStyles<typeof styles>) => {
|
} = props;
|
||||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
const classes = useStyles(props);
|
||||||
const handleClick = React.useCallback(
|
|
||||||
disableClickPropagation
|
|
||||||
? event => {
|
|
||||||
event.stopPropagation();
|
|
||||||
inputRef.current.click();
|
|
||||||
}
|
|
||||||
: () => inputRef.current.click(),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||||
<ButtonBase
|
const handleClick = React.useCallback(
|
||||||
{...props}
|
disableClickPropagation
|
||||||
centerRipple
|
? event => {
|
||||||
className={classNames(classes.root, className)}
|
event.stopPropagation();
|
||||||
|
inputRef.current.click();
|
||||||
|
}
|
||||||
|
: () => inputRef.current.click(),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ButtonBase
|
||||||
|
{...rest}
|
||||||
|
centerRipple
|
||||||
|
className={classNames(classes.root, className)}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
className={classNames(classes.box, {
|
||||||
|
[classes.checked]: checked,
|
||||||
|
[classes.disabled]: disabled,
|
||||||
|
[classes.indeterminate]: indeterminate
|
||||||
|
})}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={handleClick}
|
type="checkbox"
|
||||||
>
|
name={name}
|
||||||
<input
|
value={checked !== undefined && checked.toString()}
|
||||||
className={classNames(classes.box, {
|
ref={inputRef}
|
||||||
[classes.checked]: checked,
|
onChange={onChange}
|
||||||
[classes.disabled]: disabled,
|
/>
|
||||||
[classes.indeterminate]: indeterminate
|
</ButtonBase>
|
||||||
})}
|
);
|
||||||
disabled={disabled}
|
};
|
||||||
type="checkbox"
|
|
||||||
name={name}
|
|
||||||
value={checked !== undefined && checked.toString()}
|
|
||||||
ref={inputRef}
|
|
||||||
onChange={onChange}
|
|
||||||
/>
|
|
||||||
</ButtonBase>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
Checkbox.displayName = "Checkbox";
|
Checkbox.displayName = "Checkbox";
|
||||||
export default Checkbox;
|
export default Checkbox;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './Checkbox';
|
export { default } from "./Checkbox";
|
||||||
export * from './Checkbox';
|
export * from "./Checkbox";
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import CloseIcon from "@material-ui/icons/Close";
|
import CloseIcon from "@material-ui/icons/Close";
|
||||||
|
@ -16,32 +11,30 @@ export interface ChipProps {
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
closeIcon: {
|
||||||
closeIcon: {
|
cursor: "pointer",
|
||||||
cursor: "pointer",
|
fontSize: 16,
|
||||||
fontSize: 16,
|
marginLeft: theme.spacing(),
|
||||||
marginLeft: theme.spacing(),
|
verticalAlign: "middle"
|
||||||
verticalAlign: "middle"
|
},
|
||||||
},
|
label: {
|
||||||
label: {
|
color: theme.palette.common.white
|
||||||
color: theme.palette.common.white
|
},
|
||||||
},
|
root: {
|
||||||
root: {
|
background: fade(theme.palette.secondary.main, 0.8),
|
||||||
background: fade(theme.palette.secondary.main, 0.8),
|
borderRadius: 8,
|
||||||
borderRadius: 8,
|
display: "inline-block",
|
||||||
display: "inline-block",
|
marginRight: theme.spacing(2),
|
||||||
marginRight: theme.spacing(2),
|
padding: "6px 12px"
|
||||||
padding: "6px 12px"
|
}
|
||||||
}
|
}));
|
||||||
});
|
const Chip: React.FC<ChipProps> = props => {
|
||||||
const Chip = withStyles(styles, { name: "Chip" })(
|
const { className, label, onClose } = props;
|
||||||
({
|
|
||||||
classes,
|
const classes = useStyles(props);
|
||||||
className,
|
|
||||||
label,
|
return (
|
||||||
onClose
|
|
||||||
}: ChipProps & WithStyles<typeof styles>) => (
|
|
||||||
<div className={classNames(classes.root, className)}>
|
<div className={classNames(classes.root, className)}>
|
||||||
<Typography className={classes.label} variant="caption">
|
<Typography className={classes.label} variant="caption">
|
||||||
{label}
|
{label}
|
||||||
|
@ -50,7 +43,7 @@ const Chip = withStyles(styles, { name: "Chip" })(
|
||||||
)}
|
)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
Chip.displayName = "Chip";
|
Chip.displayName = "Chip";
|
||||||
export default Chip;
|
export default Chip;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './Chip';
|
export { default } from "./Chip";
|
||||||
export * from './Chip';
|
export * from "./Chip";
|
||||||
|
|
|
@ -55,7 +55,7 @@ const useStyles = makeStyles(theme => ({
|
||||||
padding: 0
|
padding: 0
|
||||||
},
|
},
|
||||||
dropShadow: {
|
dropShadow: {
|
||||||
boxShadow: `0px -5px 10px 0px ${theme.overrides.MuiCard.root.borderColor}`
|
boxShadow: `0px -5px 10px 0px ${theme.palette.divider}`
|
||||||
},
|
},
|
||||||
loadMoreLoaderContainer: {
|
loadMoreLoaderContainer: {
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { Omit } from "@material-ui/core";
|
|
||||||
import Button, { ButtonProps } from "@material-ui/core/Button";
|
import Button, { ButtonProps } from "@material-ui/core/Button";
|
||||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||||
import {
|
import {
|
||||||
createStyles,
|
createStyles,
|
||||||
Theme,
|
Theme,
|
||||||
withStyles,
|
WithStyles,
|
||||||
WithStyles
|
withStyles
|
||||||
} from "@material-ui/core/styles";
|
} from "@material-ui/core/styles";
|
||||||
import CheckIcon from "@material-ui/icons/Check";
|
import CheckIcon from "@material-ui/icons/Check";
|
||||||
import { buttonMessages } from "@saleor/intl";
|
import { buttonMessages } from "@saleor/intl";
|
||||||
|
@ -19,7 +18,7 @@ export type ConfirmButtonTransitionState =
|
||||||
| "error"
|
| "error"
|
||||||
| "default";
|
| "default";
|
||||||
|
|
||||||
const styles = theme =>
|
const styles = (theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
error: {
|
error: {
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
|
|
|
@ -1,35 +1,31 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
root: {
|
||||||
root: {
|
[theme.breakpoints.up("lg")]: {
|
||||||
[theme.breakpoints.up("lg")]: {
|
marginLeft: "auto",
|
||||||
marginLeft: "auto",
|
marginRight: "auto",
|
||||||
marginRight: "auto",
|
maxWidth: theme.breakpoints.width("lg")
|
||||||
maxWidth: theme.breakpoints.width("lg")
|
},
|
||||||
},
|
[theme.breakpoints.up("sm")]: {
|
||||||
[theme.breakpoints.up("sm")]: {
|
padding: theme.spacing(0, 3)
|
||||||
padding: theme.spacing(0, 3)
|
},
|
||||||
},
|
padding: theme.spacing(0, 1)
|
||||||
padding: theme.spacing(0, 1)
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface ContainerProps extends WithStyles<typeof styles> {
|
interface ContainerProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Container = withStyles(styles, {
|
export const Container: React.FC<ContainerProps> = props => {
|
||||||
name: "Container"
|
const { className, ...rest } = props;
|
||||||
})(({ classes, className, ...props }: ContainerProps) => (
|
|
||||||
<div className={classNames(classes.root, className)} {...props} />
|
const classes = useStyles(props);
|
||||||
));
|
|
||||||
|
return <div className={classNames(classes.root, className)} {...rest} />;
|
||||||
|
};
|
||||||
Container.displayName = "Container";
|
Container.displayName = "Container";
|
||||||
export default Container;
|
export default Container;
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
import { createStyles, Theme, withStyles, WithStyles } from "@material-ui/core";
|
import { makeStyles } from "@material-ui/core";
|
||||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
||||||
import Switch from "@material-ui/core/Switch";
|
import Switch from "@material-ui/core/Switch";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
label: {
|
||||||
label: {
|
marginLeft: theme.spacing(3.5)
|
||||||
marginLeft: theme.spacing(3.5)
|
},
|
||||||
},
|
labelText: {
|
||||||
labelText: {
|
fontSize: 14
|
||||||
fontSize: 14
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface ControlledSwitchProps extends WithStyles<typeof styles> {
|
interface ControlledSwitchProps {
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
label: string | React.ReactNode;
|
label: string | React.ReactNode;
|
||||||
|
@ -23,11 +22,8 @@ interface ControlledSwitchProps extends WithStyles<typeof styles> {
|
||||||
onChange?(event: React.ChangeEvent<any>);
|
onChange?(event: React.ChangeEvent<any>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ControlledSwitch = withStyles(styles, {
|
export const ControlledSwitch: React.FC<ControlledSwitchProps> = props => {
|
||||||
name: "ControlledSwitch"
|
const {
|
||||||
})(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
checked,
|
checked,
|
||||||
disabled,
|
disabled,
|
||||||
onChange,
|
onChange,
|
||||||
|
@ -35,7 +31,11 @@ export const ControlledSwitch = withStyles(styles, {
|
||||||
name,
|
name,
|
||||||
secondLabel,
|
secondLabel,
|
||||||
uncheckedLabel
|
uncheckedLabel
|
||||||
}: ControlledSwitchProps) => (
|
} = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={
|
control={
|
||||||
<Switch
|
<Switch
|
||||||
|
@ -65,7 +65,7 @@ export const ControlledSwitch = withStyles(styles, {
|
||||||
}
|
}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
ControlledSwitch.displayName = "ControlledSwitch";
|
ControlledSwitch.displayName = "ControlledSwitch";
|
||||||
export default ControlledSwitch;
|
export default ControlledSwitch;
|
||||||
|
|
|
@ -2,12 +2,7 @@ import Button from "@material-ui/core/Button";
|
||||||
import Card from "@material-ui/core/Card";
|
import Card from "@material-ui/core/Card";
|
||||||
import CardContent from "@material-ui/core/CardContent";
|
import CardContent from "@material-ui/core/CardContent";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@material-ui/core/Table";
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody";
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
|
@ -32,158 +27,155 @@ export interface CountryListProps {
|
||||||
onCountryUnassign: (country: string) => void;
|
onCountryUnassign: (country: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
iconCell: {
|
||||||
iconCell: {
|
"&:last-child": {
|
||||||
"&:last-child": {
|
paddingRight: 0
|
||||||
paddingRight: 0
|
|
||||||
},
|
|
||||||
width: 48 + theme.spacing(2)
|
|
||||||
},
|
},
|
||||||
indicator: {
|
width: 48 + theme.spacing(2)
|
||||||
color: theme.palette.text.disabled,
|
},
|
||||||
display: "inline-block",
|
indicator: {
|
||||||
left: 0,
|
color: theme.palette.text.disabled,
|
||||||
marginRight: theme.spacing(.5),
|
display: "inline-block",
|
||||||
position: "absolute"
|
left: 0,
|
||||||
|
marginRight: theme.spacing(0.5),
|
||||||
|
position: "absolute"
|
||||||
|
},
|
||||||
|
offsetCell: {
|
||||||
|
"&:first-child": {
|
||||||
|
paddingLeft: theme.spacing(3)
|
||||||
},
|
},
|
||||||
offsetCell: {
|
position: "relative"
|
||||||
"&:first-child": {
|
},
|
||||||
paddingLeft: theme.spacing(3)
|
pointer: {
|
||||||
},
|
cursor: "pointer"
|
||||||
position: "relative"
|
},
|
||||||
|
root: {
|
||||||
|
"&:last-child": {
|
||||||
|
paddingBottom: 0
|
||||||
},
|
},
|
||||||
pointer: {
|
paddingTop: 0
|
||||||
cursor: "pointer"
|
},
|
||||||
},
|
rotate: {
|
||||||
root: {
|
transform: "rotate(180deg)"
|
||||||
"&:last-child": {
|
},
|
||||||
paddingBottom: 0
|
textRight: {
|
||||||
},
|
textAlign: "right"
|
||||||
paddingTop: 0
|
},
|
||||||
},
|
toLeft: {
|
||||||
rotate: {
|
"&:first-child": {
|
||||||
transform: "rotate(180deg)"
|
paddingLeft: 0
|
||||||
},
|
|
||||||
textRight: {
|
|
||||||
textAlign: "right"
|
|
||||||
},
|
|
||||||
toLeft: {
|
|
||||||
"&:first-child": {
|
|
||||||
paddingLeft: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
wideColumn: {
|
|
||||||
width: "100%"
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
wideColumn: {
|
||||||
|
width: "100%"
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
const CountryList = withStyles(styles, {
|
const CountryList: React.FC<CountryListProps> = props => {
|
||||||
name: "CountryList"
|
const {
|
||||||
})(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
countries,
|
countries,
|
||||||
disabled,
|
disabled,
|
||||||
emptyText,
|
emptyText,
|
||||||
title,
|
title,
|
||||||
onCountryAssign,
|
onCountryAssign,
|
||||||
onCountryUnassign
|
onCountryUnassign
|
||||||
}: CountryListProps & WithStyles<typeof styles>) => {
|
} = props;
|
||||||
const [isCollapsed, setCollapseStatus] = React.useState(true);
|
const classes = useStyles(props);
|
||||||
const toggleCollapse = () => setCollapseStatus(!isCollapsed);
|
|
||||||
|
|
||||||
return (
|
const [isCollapsed, setCollapseStatus] = React.useState(true);
|
||||||
<Card>
|
const toggleCollapse = () => setCollapseStatus(!isCollapsed);
|
||||||
<CardTitle
|
|
||||||
title={title}
|
return (
|
||||||
toolbar={
|
<Card>
|
||||||
<Button color="primary" onClick={onCountryAssign}>
|
<CardTitle
|
||||||
<FormattedMessage
|
title={title}
|
||||||
defaultMessage="Assign countries"
|
toolbar={
|
||||||
description="button"
|
<Button color="primary" onClick={onCountryAssign}>
|
||||||
/>
|
<FormattedMessage
|
||||||
</Button>
|
defaultMessage="Assign countries"
|
||||||
}
|
description="button"
|
||||||
/>
|
/>
|
||||||
<CardContent className={classes.root}>
|
</Button>
|
||||||
<Table>
|
}
|
||||||
<TableBody>
|
/>
|
||||||
<TableRow className={classes.pointer} onClick={toggleCollapse}>
|
<CardContent className={classes.root}>
|
||||||
<TableCell
|
<Table>
|
||||||
className={classNames(classes.wideColumn, classes.toLeft)}
|
<TableBody>
|
||||||
>
|
<TableRow className={classes.pointer} onClick={toggleCollapse}>
|
||||||
<FormattedMessage
|
<TableCell
|
||||||
defaultMessage="{number} Countries"
|
className={classNames(classes.wideColumn, classes.toLeft)}
|
||||||
description="number of countries"
|
>
|
||||||
values={{
|
<FormattedMessage
|
||||||
number: maybe(() => countries.length.toString(), "...")
|
defaultMessage="{number} Countries"
|
||||||
}}
|
description="number of countries"
|
||||||
|
values={{
|
||||||
|
number: maybe(() => countries.length.toString(), "...")
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
className={classNames(classes.textRight, classes.iconCell)}
|
||||||
|
>
|
||||||
|
<IconButton>
|
||||||
|
<ArrowDropDownIcon
|
||||||
|
className={classNames({
|
||||||
|
[classes.rotate]: !isCollapsed
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</IconButton>
|
||||||
<TableCell
|
</TableCell>
|
||||||
className={classNames(classes.textRight, classes.iconCell)}
|
</TableRow>
|
||||||
>
|
{!isCollapsed &&
|
||||||
<IconButton>
|
renderCollection(
|
||||||
<ArrowDropDownIcon
|
countries,
|
||||||
className={classNames({
|
(country, countryIndex) => (
|
||||||
[classes.rotate]: !isCollapsed
|
<TableRow key={country ? country.code : "skeleton"}>
|
||||||
})}
|
<TableCell className={classes.offsetCell}>
|
||||||
/>
|
{maybe<React.ReactNode>(
|
||||||
</IconButton>
|
() => (
|
||||||
</TableCell>
|
<>
|
||||||
</TableRow>
|
{(countryIndex === 0 ||
|
||||||
{!isCollapsed &&
|
countries[countryIndex].country[0] !==
|
||||||
renderCollection(
|
countries[countryIndex - 1].country[0]) && (
|
||||||
countries,
|
<span className={classes.indicator}>
|
||||||
(country, countryIndex) => (
|
{country.country[0]}
|
||||||
<TableRow key={country ? country.code : "skeleton"}>
|
</span>
|
||||||
<TableCell className={classes.offsetCell}>
|
)}
|
||||||
{maybe<React.ReactNode>(
|
{country.country}
|
||||||
() => (
|
</>
|
||||||
<>
|
),
|
||||||
{(countryIndex === 0 ||
|
<Skeleton />
|
||||||
countries[countryIndex].country[0] !==
|
)}
|
||||||
countries[countryIndex - 1].country[0]) && (
|
</TableCell>
|
||||||
<span className={classes.indicator}>
|
<TableCell
|
||||||
{country.country[0]}
|
className={classNames(
|
||||||
</span>
|
classes.textRight,
|
||||||
)}
|
classes.iconCell
|
||||||
{country.country}
|
)}
|
||||||
</>
|
>
|
||||||
),
|
<IconButton
|
||||||
<Skeleton />
|
color="primary"
|
||||||
)}
|
disabled={!country || disabled}
|
||||||
</TableCell>
|
onClick={() => onCountryUnassign(country.code)}
|
||||||
<TableCell
|
|
||||||
className={classNames(
|
|
||||||
classes.textRight,
|
|
||||||
classes.iconCell
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<IconButton
|
<DeleteIcon />
|
||||||
color="primary"
|
</IconButton>
|
||||||
disabled={!country || disabled}
|
</TableCell>
|
||||||
onClick={() => onCountryUnassign(country.code)}
|
</TableRow>
|
||||||
>
|
),
|
||||||
<DeleteIcon />
|
() => (
|
||||||
</IconButton>
|
<TableRow>
|
||||||
</TableCell>
|
<TableCell className={classes.toLeft} colSpan={2}>
|
||||||
</TableRow>
|
{emptyText}
|
||||||
),
|
</TableCell>
|
||||||
() => (
|
</TableRow>
|
||||||
<TableRow>
|
)
|
||||||
<TableCell className={classes.toLeft} colSpan={2}>
|
)}
|
||||||
{emptyText}
|
</TableBody>
|
||||||
</TableCell>
|
</Table>
|
||||||
</TableRow>
|
</CardContent>
|
||||||
)
|
</Card>
|
||||||
)}
|
);
|
||||||
</TableBody>
|
};
|
||||||
</Table>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
export default CountryList;
|
export default CountryList;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export interface DebounceProps<T> {
|
export interface DebounceProps<T> {
|
||||||
children: ((props: (...args: T[]) => void) => React.ReactNode);
|
children: (props: (...args: T[]) => void) => React.ReactNode;
|
||||||
debounceFn: (...args: T[]) => void;
|
debounceFn: (...args: T[]) => void;
|
||||||
time?: number;
|
time?: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './DeleteFilterTabDialog';
|
export { default } from "./DeleteFilterTabDialog";
|
||||||
export * from './DeleteFilterTabDialog';
|
export * from "./DeleteFilterTabDialog";
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
import Card from "@material-ui/core/Card";
|
import Card from "@material-ui/core/Card";
|
||||||
import CardContent from "@material-ui/core/CardContent";
|
import CardContent from "@material-ui/core/CardContent";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
import TextField, { TextFieldProps } from "@material-ui/core/TextField";
|
import TextField, { TextFieldProps } from "@material-ui/core/TextField";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
@ -14,38 +9,37 @@ import React from "react";
|
||||||
|
|
||||||
import useForm from "@saleor/hooks/useForm";
|
import useForm from "@saleor/hooks/useForm";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
card: {
|
||||||
card: {
|
border: `1px solid ${theme.palette.divider}`
|
||||||
border: `1px solid ${theme.overrides.MuiCard.root.borderColor}`
|
},
|
||||||
},
|
container: {
|
||||||
container: {
|
position: "relative"
|
||||||
position: "relative"
|
},
|
||||||
},
|
overlay: {
|
||||||
overlay: {
|
cursor: "pointer",
|
||||||
cursor: "pointer",
|
height: "100vh",
|
||||||
height: "100vh",
|
left: 0,
|
||||||
left: 0,
|
position: "fixed",
|
||||||
position: "fixed",
|
top: 0,
|
||||||
top: 0,
|
width: "100vw",
|
||||||
width: "100vw",
|
zIndex: 1
|
||||||
zIndex: 1
|
},
|
||||||
},
|
root: {
|
||||||
root: {
|
left: 0,
|
||||||
left: 0,
|
minWidth: theme.spacing(20),
|
||||||
minWidth: theme.spacing(20),
|
position: "absolute",
|
||||||
position: "absolute",
|
top: 0,
|
||||||
top: 0,
|
width: `calc(100% + ${theme.spacing(4)}px)`,
|
||||||
width: `calc(100% + ${theme.spacing(4)}px)`,
|
zIndex: 2
|
||||||
zIndex: 2
|
},
|
||||||
},
|
text: {
|
||||||
text: {
|
cursor: "pointer",
|
||||||
cursor: "pointer",
|
fontSize: "0.8125rem"
|
||||||
fontSize: "0.8125rem"
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface EditableTableCellProps extends WithStyles<typeof styles> {
|
interface EditableTableCellProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
defaultValue?: string;
|
defaultValue?: string;
|
||||||
focused?: boolean;
|
focused?: boolean;
|
||||||
|
@ -54,54 +48,52 @@ interface EditableTableCellProps extends WithStyles<typeof styles> {
|
||||||
onConfirm(value: string): any;
|
onConfirm(value: string): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EditableTableCell = withStyles(styles, {
|
export const EditableTableCell: React.FC<EditableTableCellProps> = props => {
|
||||||
name: "EditableTableCell"
|
const {
|
||||||
})(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
className,
|
className,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
focused,
|
focused,
|
||||||
InputProps,
|
InputProps,
|
||||||
value,
|
value,
|
||||||
onConfirm
|
onConfirm
|
||||||
}: EditableTableCellProps) => {
|
} = props;
|
||||||
const handleConfirm = (data: { value: string }) => {
|
const classes = useStyles(props);
|
||||||
disable();
|
|
||||||
onConfirm(data.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const [opened, setOpenStatus] = React.useState(focused);
|
const handleConfirm = (data: { value: string }) => {
|
||||||
const { change, data } = useForm({ value }, [], handleConfirm);
|
disable();
|
||||||
const enable = () => setOpenStatus(true);
|
onConfirm(data.value);
|
||||||
const disable = () => setOpenStatus(false);
|
};
|
||||||
|
|
||||||
return (
|
const [opened, setOpenStatus] = React.useState(focused);
|
||||||
<TableCell className={classNames(classes.container, className)}>
|
const { change, data } = useForm({ value }, [], handleConfirm);
|
||||||
{opened && <div className={classes.overlay} onClick={disable} />}
|
const enable = () => setOpenStatus(true);
|
||||||
<Typography variant="caption" onClick={enable} className={classes.text}>
|
const disable = () => setOpenStatus(false);
|
||||||
{value || defaultValue}
|
|
||||||
</Typography>
|
return (
|
||||||
{opened && (
|
<TableCell className={classNames(classes.container, className)}>
|
||||||
<div className={classes.root}>
|
{opened && <div className={classes.overlay} onClick={disable} />}
|
||||||
<Card className={classes.card}>
|
<Typography variant="caption" onClick={enable} className={classes.text}>
|
||||||
<CardContent>
|
{value || defaultValue}
|
||||||
<TextField
|
</Typography>
|
||||||
name="value"
|
{opened && (
|
||||||
autoFocus
|
<div className={classes.root}>
|
||||||
fullWidth
|
<Card className={classes.card}>
|
||||||
onChange={change}
|
<CardContent>
|
||||||
value={data.value}
|
<TextField
|
||||||
variant="standard"
|
name="value"
|
||||||
{...InputProps}
|
autoFocus
|
||||||
/>
|
fullWidth
|
||||||
</CardContent>
|
onChange={change}
|
||||||
</Card>
|
value={data.value}
|
||||||
</div>
|
variant="standard"
|
||||||
)}
|
{...InputProps}
|
||||||
</TableCell>
|
/>
|
||||||
);
|
</CardContent>
|
||||||
}
|
</Card>
|
||||||
);
|
</div>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
);
|
||||||
|
};
|
||||||
EditableTableCell.displayName = "EditableTableCell";
|
EditableTableCell.displayName = "EditableTableCell";
|
||||||
export default EditableTableCell;
|
export default EditableTableCell;
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import SVG from "react-inlinesvg";
|
import SVG from "react-inlinesvg";
|
||||||
|
@ -12,57 +7,60 @@ import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import notFoundImage from "@assets/images/what.svg";
|
import notFoundImage from "@assets/images/what.svg";
|
||||||
|
|
||||||
export interface ErrorPageProps extends WithStyles<typeof styles> {
|
export interface ErrorPageProps {
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
bottomHeader: {
|
||||||
bottomHeader: {
|
fontWeight: 600 as 600,
|
||||||
fontWeight: 600 as 600,
|
textTransform: "uppercase"
|
||||||
textTransform: "uppercase"
|
},
|
||||||
|
button: {
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
padding: 20
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
[theme.breakpoints.down("sm")]: {
|
||||||
|
gridTemplateColumns: "1fr",
|
||||||
|
padding: theme.spacing(3),
|
||||||
|
width: "100%"
|
||||||
},
|
},
|
||||||
button: {
|
display: "grid",
|
||||||
marginTop: theme.spacing(2),
|
gridTemplateColumns: "1fr 487px",
|
||||||
padding: 20
|
margin: "0 auto",
|
||||||
|
width: 830
|
||||||
|
},
|
||||||
|
innerContainer: {
|
||||||
|
[theme.breakpoints.down("sm")]: {
|
||||||
|
order: 1,
|
||||||
|
textAlign: "center"
|
||||||
},
|
},
|
||||||
container: {
|
display: "flex",
|
||||||
[theme.breakpoints.down("sm")]: {
|
flexDirection: "column",
|
||||||
gridTemplateColumns: "1fr",
|
justifyContent: "center"
|
||||||
padding: theme.spacing(3),
|
},
|
||||||
width: "100%"
|
notFoundImage: {
|
||||||
},
|
"& svg": {
|
||||||
display: "grid",
|
width: "100%"
|
||||||
gridTemplateColumns: "1fr 487px",
|
|
||||||
margin: "0 auto",
|
|
||||||
width: 830
|
|
||||||
},
|
|
||||||
innerContainer: {
|
|
||||||
[theme.breakpoints.down("sm")]: {
|
|
||||||
order: 1,
|
|
||||||
textAlign: "center"
|
|
||||||
},
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center"
|
|
||||||
},
|
|
||||||
notFoundImage: {
|
|
||||||
"& svg": {
|
|
||||||
width: "100%"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
alignItems: "center",
|
|
||||||
display: "flex",
|
|
||||||
height: "calc(100vh - 88px)"
|
|
||||||
},
|
|
||||||
upperHeader: {
|
|
||||||
fontWeight: 600 as 600
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
root: {
|
||||||
|
alignItems: "center",
|
||||||
|
display: "flex",
|
||||||
|
height: "calc(100vh - 88px)"
|
||||||
|
},
|
||||||
|
upperHeader: {
|
||||||
|
fontWeight: 600 as 600
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
const ErrorPage = withStyles(styles, { name: "NotFoundPage" })(
|
const ErrorPage: React.FC<ErrorPageProps> = props => {
|
||||||
({ classes, onBack }: ErrorPageProps) => (
|
const { onBack } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<div className={classes.container}>
|
<div className={classes.container}>
|
||||||
<div className={classes.innerContainer}>
|
<div className={classes.innerContainer}>
|
||||||
|
@ -99,7 +97,7 @@ const ErrorPage = withStyles(styles, { name: "NotFoundPage" })(
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
ErrorPage.displayName = "ErrorPage";
|
ErrorPage.displayName = "ErrorPage";
|
||||||
export default ErrorPage;
|
export default ErrorPage;
|
||||||
|
|
|
@ -1,55 +1,53 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
action: {
|
||||||
action: {
|
flex: "0 0 auto"
|
||||||
flex: "0 0 auto"
|
},
|
||||||
},
|
grid: {
|
||||||
grid: {
|
padding: theme.spacing(2)
|
||||||
padding: theme.spacing(2)
|
},
|
||||||
},
|
menuButton: {
|
||||||
menuButton: {
|
flex: "0 0 auto",
|
||||||
flex: "0 0 auto",
|
marginLeft: -theme.spacing(2),
|
||||||
marginLeft: -theme.spacing(2),
|
marginRight: theme.spacing(3),
|
||||||
marginRight: theme.spacing(3),
|
marginTop: -theme.spacing(2)
|
||||||
marginTop: -theme.spacing(2)
|
},
|
||||||
},
|
root: {
|
||||||
root: {
|
alignItems: "center",
|
||||||
alignItems: "center",
|
display: "flex",
|
||||||
display: "flex",
|
marginBottom: theme.spacing(3)
|
||||||
marginBottom: theme.spacing(3)
|
},
|
||||||
},
|
subtitle: {
|
||||||
subtitle: {
|
alignItems: "center",
|
||||||
alignItems: "center",
|
display: "flex",
|
||||||
display: "flex",
|
marginBottom: theme.spacing(2)
|
||||||
marginBottom: theme.spacing(2)
|
},
|
||||||
},
|
title: {
|
||||||
title: {
|
flex: 1,
|
||||||
flex: 1,
|
paddingBottom: theme.spacing(2)
|
||||||
paddingBottom: theme.spacing(2)
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface ExtendedPageHeaderProps extends WithStyles<typeof styles> {
|
interface ExtendedPageHeaderProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
title?: React.ReactNode;
|
title?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExtendedPageHeader = withStyles(styles, { name: "ExtendedPageHeader" })(
|
const ExtendedPageHeader: React.FC<ExtendedPageHeaderProps> = props => {
|
||||||
({ children, classes, className, title }: ExtendedPageHeaderProps) => (
|
const { children, className, title } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className={classNames(classes.root, className)}>
|
<div className={classNames(classes.root, className)}>
|
||||||
{title}
|
{title}
|
||||||
<div className={classes.action}>{children}</div>
|
<div className={classes.action}>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
ExtendedPageHeader.displayName = "ExtendedPageHeader";
|
ExtendedPageHeader.displayName = "ExtendedPageHeader";
|
||||||
export default ExtendedPageHeader;
|
export default ExtendedPageHeader;
|
||||||
|
|
|
@ -1,36 +1,31 @@
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Typography, { TypographyProps } from "@material-ui/core/Typography";
|
import Typography, { TypographyProps } from "@material-ui/core/Typography";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = createStyles({
|
const useStyles = makeStyles({
|
||||||
link: {
|
link: {
|
||||||
textDecoration: "none"
|
textDecoration: "none"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface ExternalLinkProps
|
interface ExternalLinkProps extends React.HTMLProps<HTMLAnchorElement> {
|
||||||
extends React.HTMLProps<HTMLAnchorElement>,
|
|
||||||
WithStyles<typeof styles> {
|
|
||||||
href: string;
|
href: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
typographyProps?: TypographyProps;
|
typographyProps?: TypographyProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExternalLink = withStyles(styles, { name: "ExternalLink" })(
|
const ExternalLink: React.FC<ExternalLinkProps> = props => {
|
||||||
({
|
const { className, children, href, typographyProps, ...rest } = props;
|
||||||
classes,
|
|
||||||
className,
|
const classes = useStyles(props);
|
||||||
children,
|
|
||||||
href,
|
return (
|
||||||
typographyProps,
|
<a href={href} className={classes.link} {...rest}>
|
||||||
...props
|
|
||||||
}: ExternalLinkProps) => (
|
|
||||||
<a href={href} className={classes.link} {...props}>
|
|
||||||
<Typography className={className} color="primary" {...typographyProps}>
|
<Typography className={className} color="primary" {...typographyProps}>
|
||||||
{children}
|
{children}
|
||||||
</Typography>
|
</Typography>
|
||||||
</a>
|
</a>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
ExternalLink.displayName = "ExternalLink";
|
ExternalLink.displayName = "ExternalLink";
|
||||||
export default ExternalLink;
|
export default ExternalLink;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
const styles = createStyles({
|
const useStyles = makeStyles({
|
||||||
fileUploadField: {
|
fileUploadField: {
|
||||||
display: "none"
|
display: "none"
|
||||||
},
|
},
|
||||||
|
@ -16,15 +16,19 @@ const styles = createStyles({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface FileUploadProps extends WithStyles<typeof styles> {
|
interface FileUploadProps {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
name?: string;
|
name?: string;
|
||||||
value?: any;
|
value?: any;
|
||||||
onChange?(event: React.ChangeEvent<any>);
|
onChange?(event: React.ChangeEvent<any>);
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileUpload = withStyles(styles, { name: "FileUpload" })(
|
const FileUpload: React.FC<FileUploadProps> = props => {
|
||||||
({ classes, disabled, name, value, onChange }: FileUploadProps) => (
|
const { disabled, name, value, onChange } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<input
|
<input
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -48,7 +52,7 @@ const FileUpload = withStyles(styles, { name: "FileUpload" })(
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
FileUpload.displayName = "FileUpload";
|
FileUpload.displayName = "FileUpload";
|
||||||
export default FileUpload;
|
export default FileUpload;
|
||||||
|
|
|
@ -2,7 +2,7 @@ import ButtonBase from "@material-ui/core/ButtonBase";
|
||||||
import Grow from "@material-ui/core/Grow";
|
import Grow from "@material-ui/core/Grow";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import Popper from "@material-ui/core/Popper";
|
import Popper from "@material-ui/core/Popper";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown";
|
import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown";
|
||||||
|
@ -21,129 +21,120 @@ export interface FilterProps<TFilterKeys = string> {
|
||||||
onFilterAdd: (filter: FilterContentSubmitData) => void;
|
onFilterAdd: (filter: FilterContentSubmitData) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
addFilterButton: {
|
||||||
addFilterButton: {
|
"&$filterButton": {
|
||||||
"&$filterButton": {
|
"&:hover, &:focus": {
|
||||||
"&:hover, &:focus": {
|
|
||||||
backgroundColor: fade(theme.palette.primary.main, 0.1)
|
|
||||||
},
|
|
||||||
backgroundColor: theme.palette.background.paper,
|
|
||||||
border: `1px solid ${theme.palette.primary.main}`,
|
|
||||||
cursor: "pointer",
|
|
||||||
marginBottom: 0,
|
|
||||||
marginRight: theme.spacing(2),
|
|
||||||
marginTop: 0,
|
|
||||||
transition: theme.transitions.duration.short + "ms"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addFilterButtonActive: {
|
|
||||||
"&$addFilterButton": {
|
|
||||||
backgroundColor: fade(theme.palette.primary.main, 0.1)
|
backgroundColor: fade(theme.palette.primary.main, 0.1)
|
||||||
}
|
|
||||||
},
|
|
||||||
addFilterIcon: {
|
|
||||||
transition: theme.transitions.duration.short + "ms"
|
|
||||||
},
|
|
||||||
addFilterText: {
|
|
||||||
color: theme.palette.primary.main,
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: 600 as 600,
|
|
||||||
marginRight: 4,
|
|
||||||
textTransform: "uppercase"
|
|
||||||
},
|
|
||||||
filterButton: {
|
|
||||||
alignItems: "center",
|
|
||||||
backgroundColor: fade(theme.palette.primary.main, 0.6),
|
|
||||||
borderRadius: "4px",
|
|
||||||
display: "flex",
|
|
||||||
height: 40,
|
|
||||||
justifyContent: "space-around",
|
|
||||||
margin: theme.spacing(2, 1),
|
|
||||||
marginLeft: 0,
|
|
||||||
padding: theme.spacing(0, 2),
|
|
||||||
position: "relative"
|
|
||||||
},
|
|
||||||
paper: {
|
|
||||||
"& p": {
|
|
||||||
paddingBottom: 10
|
|
||||||
},
|
},
|
||||||
marginTop: theme.spacing(2),
|
backgroundColor: theme.palette.background.paper,
|
||||||
padding: theme.spacing(2),
|
border: `1px solid ${theme.palette.primary.main}`,
|
||||||
width: 240
|
cursor: "pointer",
|
||||||
},
|
marginBottom: 0,
|
||||||
popover: {
|
marginRight: theme.spacing(2),
|
||||||
zIndex: 1
|
marginTop: 0,
|
||||||
},
|
transition: theme.transitions.duration.short + "ms"
|
||||||
rotate: {
|
|
||||||
transform: "rotate(180deg)"
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
const Filter = withStyles(styles, { name: "Filter" })(
|
addFilterButtonActive: {
|
||||||
({
|
"&$addFilterButton": {
|
||||||
classes,
|
backgroundColor: fade(theme.palette.primary.main, 0.1)
|
||||||
currencySymbol,
|
}
|
||||||
filterLabel,
|
},
|
||||||
menu,
|
addFilterIcon: {
|
||||||
onFilterAdd
|
transition: theme.transitions.duration.short + "ms"
|
||||||
}: FilterProps & WithStyles<typeof styles>) => {
|
},
|
||||||
const anchor = React.useRef<HTMLDivElement>();
|
addFilterText: {
|
||||||
const [isFilterMenuOpened, setFilterMenuOpened] = React.useState(false);
|
color: theme.palette.primary.main,
|
||||||
|
fontSize: 14,
|
||||||
return (
|
fontWeight: 600 as 600,
|
||||||
<div ref={anchor}>
|
marginRight: 4,
|
||||||
<ButtonBase
|
textTransform: "uppercase"
|
||||||
className={classNames(classes.filterButton, classes.addFilterButton, {
|
},
|
||||||
[classes.addFilterButtonActive]: isFilterMenuOpened
|
filterButton: {
|
||||||
})}
|
alignItems: "center",
|
||||||
onClick={() => setFilterMenuOpened(!isFilterMenuOpened)}
|
backgroundColor: fade(theme.palette.primary.main, 0.6),
|
||||||
>
|
borderRadius: "4px",
|
||||||
<Typography className={classes.addFilterText}>
|
display: "flex",
|
||||||
<FormattedMessage
|
height: 40,
|
||||||
defaultMessage="Add Filter"
|
justifyContent: "space-around",
|
||||||
description="button"
|
margin: theme.spacing(2, 1),
|
||||||
/>
|
marginLeft: 0,
|
||||||
</Typography>
|
padding: theme.spacing(0, 2),
|
||||||
<ArrowDropDownIcon
|
position: "relative"
|
||||||
color="primary"
|
},
|
||||||
className={classNames(classes.addFilterIcon, {
|
paper: {
|
||||||
[classes.rotate]: isFilterMenuOpened
|
"& p": {
|
||||||
})}
|
paddingBottom: 10
|
||||||
/>
|
},
|
||||||
</ButtonBase>
|
marginTop: theme.spacing(2),
|
||||||
<Popper
|
padding: theme.spacing(2),
|
||||||
className={classes.popover}
|
width: 240
|
||||||
open={isFilterMenuOpened}
|
},
|
||||||
anchorEl={anchor.current}
|
popover: {
|
||||||
transition
|
zIndex: 1
|
||||||
disablePortal
|
},
|
||||||
placement="bottom-start"
|
rotate: {
|
||||||
>
|
transform: "rotate(180deg)"
|
||||||
{({ TransitionProps, placement }) => (
|
|
||||||
<Grow
|
|
||||||
{...TransitionProps}
|
|
||||||
style={{
|
|
||||||
transformOrigin:
|
|
||||||
placement === "bottom" ? "right top" : "right bottom"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Paper className={classes.paper}>
|
|
||||||
<Typography>{filterLabel}</Typography>
|
|
||||||
<FilterContent
|
|
||||||
currencySymbol={currencySymbol}
|
|
||||||
filters={menu}
|
|
||||||
onSubmit={data => {
|
|
||||||
onFilterAdd(data);
|
|
||||||
setFilterMenuOpened(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Paper>
|
|
||||||
</Grow>
|
|
||||||
)}
|
|
||||||
</Popper>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
}));
|
||||||
|
const Filter: React.FC<FilterProps> = props => {
|
||||||
|
const { currencySymbol, filterLabel, menu, onFilterAdd } = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
const anchor = React.useRef<HTMLDivElement>();
|
||||||
|
const [isFilterMenuOpened, setFilterMenuOpened] = React.useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={anchor}>
|
||||||
|
<ButtonBase
|
||||||
|
className={classNames(classes.filterButton, classes.addFilterButton, {
|
||||||
|
[classes.addFilterButtonActive]: isFilterMenuOpened
|
||||||
|
})}
|
||||||
|
onClick={() => setFilterMenuOpened(!isFilterMenuOpened)}
|
||||||
|
>
|
||||||
|
<Typography className={classes.addFilterText}>
|
||||||
|
<FormattedMessage defaultMessage="Add Filter" description="button" />
|
||||||
|
</Typography>
|
||||||
|
<ArrowDropDownIcon
|
||||||
|
color="primary"
|
||||||
|
className={classNames(classes.addFilterIcon, {
|
||||||
|
[classes.rotate]: isFilterMenuOpened
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</ButtonBase>
|
||||||
|
<Popper
|
||||||
|
className={classes.popover}
|
||||||
|
open={isFilterMenuOpened}
|
||||||
|
anchorEl={anchor.current}
|
||||||
|
transition
|
||||||
|
disablePortal
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
{({ TransitionProps, placement }) => (
|
||||||
|
<Grow
|
||||||
|
{...TransitionProps}
|
||||||
|
style={{
|
||||||
|
transformOrigin:
|
||||||
|
placement === "bottom" ? "right top" : "right bottom"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Paper className={classes.paper}>
|
||||||
|
<Typography>{filterLabel}</Typography>
|
||||||
|
<FilterContent
|
||||||
|
currencySymbol={currencySymbol}
|
||||||
|
filters={menu}
|
||||||
|
onSubmit={data => {
|
||||||
|
onFilterAdd(data);
|
||||||
|
setFilterMenuOpened(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
)}
|
||||||
|
</Popper>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
Filter.displayName = "Filter";
|
Filter.displayName = "Filter";
|
||||||
export default Filter;
|
export default Filter;
|
||||||
|
|
|
@ -17,6 +17,7 @@ const useInputStyles = makeStyles({
|
||||||
|
|
||||||
const Search: React.FC<TextFieldProps> = props => {
|
const Search: React.FC<TextFieldProps> = props => {
|
||||||
const classes = useInputStyles({});
|
const classes = useInputStyles({});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './FilterBar';
|
export { default } from "./FilterBar";
|
||||||
export * from './FilterBar';
|
export * from "./FilterBar";
|
||||||
|
|
|
@ -1,27 +1,23 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
spacer: {
|
||||||
spacer: {
|
marginTop: theme.spacing(3)
|
||||||
marginTop: theme.spacing(3)
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface FormSpacerProps extends WithStyles<typeof styles> {
|
interface FormSpacerProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FormSpacer = withStyles(styles, { name: "FormSpacer" })(
|
export const FormSpacer: React.FC<FormSpacerProps> = props => {
|
||||||
({ classes, children }: FormSpacerProps) => (
|
const { children } = props;
|
||||||
<div className={classes.spacer}>{children}</div>
|
|
||||||
)
|
const classes = useStyles(props);
|
||||||
);
|
|
||||||
|
return <div className={classes.spacer}>{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
FormSpacer.displayName = "FormSpacer";
|
FormSpacer.displayName = "FormSpacer";
|
||||||
export default FormSpacer;
|
export default FormSpacer;
|
||||||
|
|
|
@ -1,43 +1,41 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export type GridVariant = "default" | "inverted" | "uniform";
|
export type GridVariant = "default" | "inverted" | "uniform";
|
||||||
export interface GridProps extends WithStyles<typeof styles> {
|
export interface GridProps {
|
||||||
children: React.ReactNodeArray | React.ReactNode;
|
children: React.ReactNodeArray | React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
variant?: GridVariant;
|
variant?: GridVariant;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
default: {
|
||||||
default: {
|
gridTemplateColumns: "9fr 4fr"
|
||||||
gridTemplateColumns: "9fr 4fr"
|
},
|
||||||
},
|
inverted: {
|
||||||
inverted: {
|
gridTemplateColumns: "4fr 9fr"
|
||||||
gridTemplateColumns: "4fr 9fr"
|
},
|
||||||
},
|
root: {
|
||||||
root: {
|
display: "grid",
|
||||||
display: "grid",
|
gridColumnGap: theme.spacing(3),
|
||||||
gridColumnGap: theme.spacing(3),
|
gridRowGap: theme.spacing(3),
|
||||||
gridRowGap: theme.spacing(3),
|
[theme.breakpoints.down("sm")]: {
|
||||||
[theme.breakpoints.down("sm")]: {
|
gridRowGap: theme.spacing(1),
|
||||||
gridRowGap: theme.spacing(1),
|
gridTemplateColumns: "1fr"
|
||||||
gridTemplateColumns: "1fr"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
uniform: {
|
|
||||||
gridTemplateColumns: "1fr 1fr"
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
uniform: {
|
||||||
|
gridTemplateColumns: "1fr 1fr"
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
export const Grid = withStyles(styles, { name: "Grid" })(
|
export const Grid: React.FC<GridProps> = props => {
|
||||||
({ className, children, classes, variant }: GridProps) => (
|
const { className, children, variant } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(className, classes.root, {
|
className={classNames(className, classes.root, {
|
||||||
[classes.default]: variant === "default",
|
[classes.default]: variant === "default",
|
||||||
|
@ -47,8 +45,8 @@ export const Grid = withStyles(styles, { name: "Grid" })(
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
Grid.displayName = "Grid";
|
Grid.displayName = "Grid";
|
||||||
Grid.defaultProps = {
|
Grid.defaultProps = {
|
||||||
variant: "default"
|
variant: "default"
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
@ -11,22 +6,23 @@ interface HrProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
root: {
|
||||||
root: {
|
backgroundColor: theme.palette.divider,
|
||||||
backgroundColor: theme.overrides.MuiCard.root.borderColor,
|
border: "none",
|
||||||
border: "none",
|
display: "block",
|
||||||
display: "block",
|
height: 1,
|
||||||
height: 1,
|
margin: 0,
|
||||||
margin: 0,
|
width: "100%"
|
||||||
width: "100%"
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
export const Hr = withStyles(styles, { name: "Hr" })(
|
export const Hr: React.FC<HrProps> = props => {
|
||||||
({ className, classes }: HrProps & WithStyles<typeof styles>) => (
|
const { className } = props;
|
||||||
<hr className={classNames(classes.root, className)} />
|
|
||||||
)
|
const classes = useStyles(props);
|
||||||
);
|
|
||||||
|
return <hr className={classNames(classes.root, className)} />;
|
||||||
|
};
|
||||||
Hr.displayName = "Hr";
|
Hr.displayName = "Hr";
|
||||||
export default Hr;
|
export default Hr;
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
@ -17,23 +12,26 @@ export interface IconButtonTableCellProps {
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
root: {
|
||||||
root: {
|
"&:last-child": {
|
||||||
"&:last-child": {
|
paddingRight: 0
|
||||||
paddingRight: 0
|
},
|
||||||
},
|
paddingRight: 0,
|
||||||
paddingRight: 0,
|
width: ICONBUTTON_SIZE + theme.spacing(0.5)
|
||||||
width: ICONBUTTON_SIZE + theme.spacing(.5)
|
}
|
||||||
}
|
}));
|
||||||
});
|
const IconButtonTableCell: React.FC<IconButtonTableCellProps> = props => {
|
||||||
const IconButtonTableCell = withStyles(styles, { name: "IconButtonTableCell" })(
|
const {
|
||||||
({
|
|
||||||
children,
|
children,
|
||||||
classes,
|
|
||||||
disabled,
|
disabled,
|
||||||
onClick
|
onClick
|
||||||
}: IconButtonTableCellProps & WithStyles<typeof styles>) => (
|
} = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<TableCell className={classes.root}>
|
<TableCell className={classes.root}>
|
||||||
<IconButton
|
<IconButton
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -43,7 +41,7 @@ const IconButtonTableCell = withStyles(styles, { name: "IconButtonTableCell" })(
|
||||||
{children}
|
{children}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
IconButtonTableCell.displayName = "IconButtonTableCell";
|
IconButtonTableCell.displayName = "IconButtonTableCell";
|
||||||
export default IconButtonTableCell;
|
export default IconButtonTableCell;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './IconButtonTableCell';
|
export { default } from "./IconButtonTableCell";
|
||||||
export * from './IconButtonTableCell';
|
export * from "./IconButtonTableCell";
|
||||||
|
|
|
@ -1,55 +1,49 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import DeleteIcon from "@material-ui/icons/Delete";
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
import EditIcon from "@material-ui/icons/Edit";
|
import EditIcon from "@material-ui/icons/Edit";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
image: {
|
||||||
image: {
|
height: "100%",
|
||||||
height: "100%",
|
objectFit: "contain",
|
||||||
objectFit: "contain",
|
userSelect: "none",
|
||||||
userSelect: "none",
|
width: "100%"
|
||||||
width: "100%"
|
},
|
||||||
|
imageContainer: {
|
||||||
|
"&:hover, &.dragged": {
|
||||||
|
"& $imageOverlay": {
|
||||||
|
display: "block"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
imageContainer: {
|
background: theme.palette.background.paper,
|
||||||
"&:hover, &.dragged": {
|
border: `1px solid ${theme.palette.divider}`,
|
||||||
"& $imageOverlay": {
|
borderRadius: theme.spacing(),
|
||||||
display: "block"
|
height: 148,
|
||||||
}
|
overflow: "hidden",
|
||||||
},
|
padding: theme.spacing(2),
|
||||||
background: theme.palette.background.paper,
|
position: "relative",
|
||||||
border: `1px solid ${theme.overrides.MuiCard.root.borderColor}`,
|
width: 148
|
||||||
borderRadius: theme.spacing(),
|
},
|
||||||
height: 148,
|
imageOverlay: {
|
||||||
overflow: "hidden",
|
background: "rgba(0, 0, 0, 0.6)",
|
||||||
padding: theme.spacing(2),
|
cursor: "move",
|
||||||
position: "relative",
|
display: "none",
|
||||||
width: 148
|
height: 148,
|
||||||
},
|
left: 0,
|
||||||
imageOverlay: {
|
position: "absolute",
|
||||||
background: "rgba(0, 0, 0, 0.6)",
|
top: 0,
|
||||||
cursor: "move",
|
width: 148
|
||||||
display: "none",
|
},
|
||||||
height: 148,
|
imageOverlayToolbar: {
|
||||||
left: 0,
|
display: "flex",
|
||||||
position: "absolute",
|
justifyContent: "flex-end"
|
||||||
top: 0,
|
}
|
||||||
width: 148
|
}));
|
||||||
},
|
|
||||||
imageOverlayToolbar: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "flex-end"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
interface ImageTileProps extends WithStyles<typeof styles> {
|
interface ImageTileProps {
|
||||||
image: {
|
image: {
|
||||||
alt?: string;
|
alt?: string;
|
||||||
url: string;
|
url: string;
|
||||||
|
@ -58,8 +52,12 @@ interface ImageTileProps extends WithStyles<typeof styles> {
|
||||||
onImageEdit?: (event: React.ChangeEvent<any>) => void;
|
onImageEdit?: (event: React.ChangeEvent<any>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImageTile = withStyles(styles, { name: "ImageTile" })(
|
const ImageTile: React.FC<ImageTileProps> = props => {
|
||||||
({ classes, onImageDelete, onImageEdit, image }: ImageTileProps) => (
|
const { onImageDelete, onImageEdit, image } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className={classes.imageContainer} data-tc="product-image">
|
<div className={classes.imageContainer} data-tc="product-image">
|
||||||
<div className={classes.imageOverlay}>
|
<div className={classes.imageOverlay}>
|
||||||
<div className={classes.imageOverlayToolbar}>
|
<div className={classes.imageOverlayToolbar}>
|
||||||
|
@ -77,7 +75,7 @@ const ImageTile = withStyles(styles, { name: "ImageTile" })(
|
||||||
</div>
|
</div>
|
||||||
<img className={classes.image} src={image.url} alt={image.alt} />
|
<img className={classes.image} src={image.url} alt={image.alt} />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
ImageTile.displayName = "ImageTile";
|
ImageTile.displayName = "ImageTile";
|
||||||
export default ImageTile;
|
export default ImageTile;
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -22,55 +17,58 @@ interface ImageUploadProps {
|
||||||
onImageUpload: (file: File) => void;
|
onImageUpload: (file: File) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
containerDragActive: {
|
||||||
containerDragActive: {
|
background: fade(theme.palette.primary.main, 0.1),
|
||||||
background: fade(theme.palette.primary.main, 0.1),
|
color: theme.palette.primary.main
|
||||||
color: theme.palette.primary.main
|
},
|
||||||
},
|
fileField: {
|
||||||
fileField: {
|
display: "none"
|
||||||
display: "none"
|
},
|
||||||
},
|
imageContainer: {
|
||||||
imageContainer: {
|
background: "#ffffff",
|
||||||
background: "#ffffff",
|
border: "1px solid #eaeaea",
|
||||||
border: "1px solid #eaeaea",
|
borderRadius: theme.spacing(),
|
||||||
borderRadius: theme.spacing(),
|
height: 148,
|
||||||
height: 148,
|
justifySelf: "start",
|
||||||
justifySelf: "start",
|
overflow: "hidden",
|
||||||
overflow: "hidden",
|
padding: theme.spacing(2),
|
||||||
padding: theme.spacing(2),
|
position: "relative",
|
||||||
position: "relative",
|
transition: theme.transitions.duration.standard + "s",
|
||||||
transition: theme.transitions.duration.standard + "s",
|
width: 148
|
||||||
width: 148
|
},
|
||||||
},
|
photosIcon: {
|
||||||
photosIcon: {
|
height: "64px",
|
||||||
height: "64px",
|
margin: "0 auto",
|
||||||
margin: "0 auto",
|
width: "64px"
|
||||||
width: "64px"
|
},
|
||||||
},
|
photosIconContainer: {
|
||||||
photosIconContainer: {
|
padding: theme.spacing(5, 0),
|
||||||
padding: theme.spacing(5, 0),
|
textAlign: "center"
|
||||||
textAlign: "center"
|
},
|
||||||
},
|
uploadText: {
|
||||||
uploadText: {
|
color: theme.typography.body1.color,
|
||||||
color: theme.typography.body1.color,
|
fontSize: 12,
|
||||||
fontSize: 12,
|
fontWeight: 600,
|
||||||
fontWeight: 600,
|
textTransform: "uppercase"
|
||||||
textTransform: "uppercase"
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
export const ImageUpload = withStyles(styles, { name: "ImageUpload" })(
|
export const ImageUpload: React.FC<ImageUploadProps> = props => {
|
||||||
({
|
const {
|
||||||
children,
|
children,
|
||||||
classes,
|
|
||||||
className,
|
className,
|
||||||
disableClick,
|
disableClick,
|
||||||
isActiveClassName,
|
isActiveClassName,
|
||||||
iconContainerActiveClassName,
|
iconContainerActiveClassName,
|
||||||
iconContainerClassName,
|
iconContainerClassName,
|
||||||
onImageUpload
|
onImageUpload
|
||||||
}: ImageUploadProps & WithStyles<typeof styles>) => (
|
} = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<Dropzone
|
<Dropzone
|
||||||
disableClick={disableClick}
|
disableClick={disableClick}
|
||||||
onDrop={files => onImageUpload(files[0])}
|
onDrop={files => onImageUpload(files[0])}
|
||||||
|
@ -107,7 +105,7 @@ export const ImageUpload = withStyles(styles, { name: "ImageUpload" })(
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Dropzone>
|
</Dropzone>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
ImageUpload.displayName = "ImageUpload";
|
ImageUpload.displayName = "ImageUpload";
|
||||||
export default ImageUpload;
|
export default ImageUpload;
|
||||||
|
|
|
@ -5,12 +5,7 @@ import MenuItem from "@material-ui/core/MenuItem";
|
||||||
import Menu from "@material-ui/core/MenuList";
|
import Menu from "@material-ui/core/MenuList";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import Popper from "@material-ui/core/Popper";
|
import Popper from "@material-ui/core/Popper";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import ArrowDropDown from "@material-ui/icons/ArrowDropDown";
|
import ArrowDropDown from "@material-ui/icons/ArrowDropDown";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -26,109 +21,104 @@ export interface LanguageSwitchProps {
|
||||||
onLanguageChange: (lang: LanguageCodeEnum) => void;
|
onLanguageChange: (lang: LanguageCodeEnum) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
arrow: {
|
||||||
arrow: {
|
color: theme.palette.primary.main,
|
||||||
color: theme.palette.primary.main,
|
transition: theme.transitions.duration.standard + "ms"
|
||||||
transition: theme.transitions.duration.standard + "ms"
|
},
|
||||||
},
|
container: {
|
||||||
container: {
|
paddingBottom: theme.spacing(1)
|
||||||
paddingBottom: theme.spacing(1)
|
},
|
||||||
},
|
menuContainer: {
|
||||||
menuContainer: {
|
cursor: "pointer",
|
||||||
cursor: "pointer",
|
display: "flex",
|
||||||
display: "flex",
|
justifyContent: "space-between",
|
||||||
justifyContent: "space-between",
|
minWidth: 90,
|
||||||
minWidth: 90,
|
padding: theme.spacing(),
|
||||||
padding: theme.spacing(),
|
position: "relative"
|
||||||
position: "relative"
|
},
|
||||||
},
|
menuItem: {
|
||||||
menuItem: {
|
textAlign: "justify"
|
||||||
textAlign: "justify"
|
},
|
||||||
},
|
menuPaper: {
|
||||||
menuPaper: {
|
maxHeight: `calc(100vh - ${theme.spacing(2)}px)`,
|
||||||
maxHeight: `calc(100vh - ${theme.spacing(2)}px)`,
|
overflow: "scroll"
|
||||||
overflow: "scroll"
|
},
|
||||||
},
|
popover: {
|
||||||
popover: {
|
zIndex: 1
|
||||||
zIndex: 1
|
},
|
||||||
},
|
rotate: {
|
||||||
rotate: {
|
transform: "rotate(180deg)"
|
||||||
transform: "rotate(180deg)"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const LanguageSwitch = withStyles(styles, { name: "LanguageSwitch" })(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
currentLanguage,
|
|
||||||
languages,
|
|
||||||
onLanguageChange
|
|
||||||
}: LanguageSwitchProps & WithStyles<typeof styles>) => {
|
|
||||||
const [isExpanded, setExpandedState] = React.useState(false);
|
|
||||||
const anchor = React.useRef();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.container} ref={anchor}>
|
|
||||||
<Card
|
|
||||||
className={classes.menuContainer}
|
|
||||||
onClick={() => setExpandedState(!isExpanded)}
|
|
||||||
>
|
|
||||||
<Typography>{currentLanguage}</Typography>
|
|
||||||
<ArrowDropDown
|
|
||||||
className={classNames(classes.arrow, {
|
|
||||||
[classes.rotate]: isExpanded
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
<Popper
|
|
||||||
className={classes.popover}
|
|
||||||
open={isExpanded}
|
|
||||||
anchorEl={anchor.current}
|
|
||||||
transition
|
|
||||||
disablePortal
|
|
||||||
placement="bottom-end"
|
|
||||||
>
|
|
||||||
{({ TransitionProps, placement }) => (
|
|
||||||
<Grow
|
|
||||||
{...TransitionProps}
|
|
||||||
style={{
|
|
||||||
transformOrigin:
|
|
||||||
placement === "bottom" ? "right top" : "right bottom"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Paper className={classes.menuPaper}>
|
|
||||||
<ClickAwayListener
|
|
||||||
onClickAway={() => setExpandedState(false)}
|
|
||||||
mouseEvent="onClick"
|
|
||||||
>
|
|
||||||
{languages.map(lang => (
|
|
||||||
<Menu>
|
|
||||||
<MenuItem
|
|
||||||
className={classes.menuItem}
|
|
||||||
onClick={() => {
|
|
||||||
setExpandedState(false);
|
|
||||||
onLanguageChange(lang.code);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="{languageName} - {languageCode}"
|
|
||||||
description="button"
|
|
||||||
values={{
|
|
||||||
languageCode: lang.code,
|
|
||||||
languageName: lang.language
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
))}
|
|
||||||
</ClickAwayListener>
|
|
||||||
</Paper>
|
|
||||||
</Grow>
|
|
||||||
)}
|
|
||||||
</Popper>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
}));
|
||||||
|
const LanguageSwitch: React.FC<LanguageSwitchProps> = props => {
|
||||||
|
const { currentLanguage, languages, onLanguageChange } = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
const [isExpanded, setExpandedState] = React.useState(false);
|
||||||
|
const anchor = React.useRef();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.container} ref={anchor}>
|
||||||
|
<Card
|
||||||
|
className={classes.menuContainer}
|
||||||
|
onClick={() => setExpandedState(!isExpanded)}
|
||||||
|
>
|
||||||
|
<Typography>{currentLanguage}</Typography>
|
||||||
|
<ArrowDropDown
|
||||||
|
className={classNames(classes.arrow, {
|
||||||
|
[classes.rotate]: isExpanded
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
<Popper
|
||||||
|
className={classes.popover}
|
||||||
|
open={isExpanded}
|
||||||
|
anchorEl={anchor.current}
|
||||||
|
transition
|
||||||
|
disablePortal
|
||||||
|
placement="bottom-end"
|
||||||
|
>
|
||||||
|
{({ TransitionProps, placement }) => (
|
||||||
|
<Grow
|
||||||
|
{...TransitionProps}
|
||||||
|
style={{
|
||||||
|
transformOrigin:
|
||||||
|
placement === "bottom" ? "right top" : "right bottom"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Paper className={classes.menuPaper}>
|
||||||
|
<ClickAwayListener
|
||||||
|
onClickAway={() => setExpandedState(false)}
|
||||||
|
mouseEvent="onClick"
|
||||||
|
>
|
||||||
|
{languages.map(lang => (
|
||||||
|
<Menu>
|
||||||
|
<MenuItem
|
||||||
|
className={classes.menuItem}
|
||||||
|
onClick={() => {
|
||||||
|
setExpandedState(false);
|
||||||
|
onLanguageChange(lang.code);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="{languageName} - {languageCode}"
|
||||||
|
description="button"
|
||||||
|
values={{
|
||||||
|
languageCode: lang.code,
|
||||||
|
languageName: lang.language
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
))}
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
)}
|
||||||
|
</Popper>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
LanguageSwitch.displayName = "LanguageSwitch";
|
LanguageSwitch.displayName = "LanguageSwitch";
|
||||||
export default LanguageSwitch;
|
export default LanguageSwitch;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './LanguageSwitch';
|
export { default } from "./LanguageSwitch";
|
||||||
export * from './LanguageSwitch';
|
export * from "./LanguageSwitch";
|
||||||
|
|
|
@ -1,49 +1,44 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography, { TypographyProps } from "@material-ui/core/Typography";
|
import Typography, { TypographyProps } from "@material-ui/core/Typography";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
primary: {
|
||||||
primary: {
|
color: theme.palette.primary.main
|
||||||
color: theme.palette.primary.main
|
},
|
||||||
},
|
root: {
|
||||||
root: {
|
cursor: "pointer",
|
||||||
cursor: "pointer",
|
display: "inline"
|
||||||
display: "inline"
|
},
|
||||||
},
|
secondary: {
|
||||||
secondary: {
|
color: theme.palette.primary.main
|
||||||
color: theme.palette.primary.main
|
},
|
||||||
},
|
underline: {
|
||||||
underline: {
|
textDecoration: "underline"
|
||||||
textDecoration: "underline"
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface LinkProps
|
interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
||||||
extends React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
||||||
WithStyles<typeof styles> {
|
|
||||||
color?: "primary" | "secondary";
|
color?: "primary" | "secondary";
|
||||||
underline?: boolean;
|
underline?: boolean;
|
||||||
typographyProps?: TypographyProps;
|
typographyProps?: TypographyProps;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Link = withStyles(styles, { name: "Link" })(
|
const Link: React.FC<LinkProps> = props => {
|
||||||
({
|
const {
|
||||||
classes,
|
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
color = "primary",
|
color = "primary",
|
||||||
underline = false,
|
underline = false,
|
||||||
onClick,
|
onClick,
|
||||||
...linkProps
|
...linkProps
|
||||||
}: LinkProps) => (
|
} = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<Typography
|
<Typography
|
||||||
component="a"
|
component="a"
|
||||||
className={classNames({
|
className={classNames({
|
||||||
|
@ -59,7 +54,7 @@ const Link = withStyles(styles, { name: "Link" })(
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Typography>
|
</Typography>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
Link.displayName = "Link";
|
Link.displayName = "Link";
|
||||||
export default Link;
|
export default Link;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { Omit } from "@material-ui/core";
|
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
import {
|
import {
|
||||||
createStyles,
|
createStyles,
|
||||||
|
@ -17,7 +16,7 @@ interface ListFieldState {
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const styles = (theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
chip: {
|
chip: {
|
||||||
marginBottom: theme.spacing(1)
|
marginBottom: theme.spacing(1)
|
||||||
|
|
|
@ -2,15 +2,13 @@ import React from "react";
|
||||||
|
|
||||||
interface MenuToggleProps {
|
interface MenuToggleProps {
|
||||||
ariaOwns?: string;
|
ariaOwns?: string;
|
||||||
children: ((
|
children: (props: {
|
||||||
props: {
|
actions: {
|
||||||
actions: {
|
open: () => void;
|
||||||
open: () => void;
|
close: () => void;
|
||||||
close: () => void;
|
};
|
||||||
};
|
open: boolean;
|
||||||
open: boolean;
|
}) => React.ReactElement<any>;
|
||||||
}
|
|
||||||
) => React.ReactElement<any>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MenuToggleState {
|
interface MenuToggleState {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import Money from "./Money";
|
import { IMoney } from "./Money";
|
||||||
|
|
||||||
export { default } from "./Money";
|
export { default } from "./Money";
|
||||||
export * from "./Money";
|
export * from "./Money";
|
||||||
|
|
||||||
export function addMoney(init: Money, ...args: Money[]): Money {
|
export function addMoney(init: IMoney, ...args: IMoney[]): IMoney {
|
||||||
return {
|
return {
|
||||||
amount: args.reduce((acc, curr) => acc + curr.amount, init.amount),
|
amount: args.reduce((acc, curr) => acc + curr.amount, init.amount),
|
||||||
currency: init.currency
|
currency: init.currency
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export function subtractMoney(init: Money, ...args: Money[]): Money {
|
export function subtractMoney(init: IMoney, ...args: IMoney[]): IMoney {
|
||||||
return {
|
return {
|
||||||
amount: args.reduce((acc, curr) => acc - curr.amount, init.amount),
|
amount: args.reduce((acc, curr) => acc - curr.amount, init.amount),
|
||||||
currency: init.currency
|
currency: init.currency
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import { LocaleConsumer } from "../Locale";
|
import { LocaleConsumer } from "../Locale";
|
||||||
import IMoney from "../Money";
|
import { IMoney } from "../Money";
|
||||||
|
|
||||||
export interface MoneyRangeProps {
|
export interface MoneyRangeProps {
|
||||||
from?: IMoney;
|
from?: IMoney;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './MoneyRange';
|
export { default } from "./MoneyRange";
|
||||||
export * from './MoneyRange';
|
export * from "./MoneyRange";
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import CloseIcon from "@material-ui/icons/Close";
|
import CloseIcon from "@material-ui/icons/Close";
|
||||||
|
@ -20,43 +15,42 @@ import MultiAutocompleteSelectFieldContent, {
|
||||||
MultiAutocompleteChoiceType
|
MultiAutocompleteChoiceType
|
||||||
} from "./MultiAutocompleteSelectFieldContent";
|
} from "./MultiAutocompleteSelectFieldContent";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
chip: {
|
||||||
chip: {
|
width: "100%"
|
||||||
width: "100%"
|
},
|
||||||
},
|
chipClose: {
|
||||||
chipClose: {
|
height: 32,
|
||||||
height: 32,
|
padding: 0,
|
||||||
padding: 0,
|
width: 32
|
||||||
width: 32
|
},
|
||||||
},
|
chipContainer: {
|
||||||
chipContainer: {
|
display: "flex",
|
||||||
display: "flex",
|
flexDirection: "column",
|
||||||
flexDirection: "column",
|
marginTop: theme.spacing(1)
|
||||||
marginTop: theme.spacing(1)
|
},
|
||||||
},
|
chipInner: {
|
||||||
chipInner: {
|
"& svg": {
|
||||||
"& svg": {
|
|
||||||
color: theme.palette.primary.contrastText
|
|
||||||
},
|
|
||||||
alignItems: "center",
|
|
||||||
background: fade(theme.palette.primary.main, 0.8),
|
|
||||||
borderRadius: 18,
|
|
||||||
color: theme.palette.primary.contrastText,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
margin: theme.spacing(1, 0),
|
|
||||||
paddingLeft: theme.spacing(2),
|
|
||||||
paddingRight: theme.spacing(1)
|
|
||||||
},
|
|
||||||
chipLabel: {
|
|
||||||
color: theme.palette.primary.contrastText
|
color: theme.palette.primary.contrastText
|
||||||
},
|
},
|
||||||
container: {
|
alignItems: "center",
|
||||||
flexGrow: 1,
|
background: fade(theme.palette.primary.main, 0.8),
|
||||||
position: "relative"
|
borderRadius: 18,
|
||||||
}
|
color: theme.palette.primary.contrastText,
|
||||||
});
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
margin: theme.spacing(1, 0),
|
||||||
|
paddingLeft: theme.spacing(2),
|
||||||
|
paddingRight: theme.spacing(1)
|
||||||
|
},
|
||||||
|
chipLabel: {
|
||||||
|
color: theme.palette.primary.contrastText
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
flexGrow: 1,
|
||||||
|
position: "relative"
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
export interface MultiAutocompleteSelectFieldProps
|
export interface MultiAutocompleteSelectFieldProps
|
||||||
extends Partial<FetchMoreProps> {
|
extends Partial<FetchMoreProps> {
|
||||||
|
@ -77,14 +71,15 @@ const DebounceAutocomplete: React.ComponentType<
|
||||||
DebounceProps<string>
|
DebounceProps<string>
|
||||||
> = Debounce;
|
> = Debounce;
|
||||||
|
|
||||||
export const MultiAutocompleteSelectFieldComponent = withStyles(styles, {
|
const MultiAutocompleteSelectFieldComponent: React.FC<
|
||||||
name: "MultiAutocompleteSelectField"
|
MultiAutocompleteSelectFieldProps
|
||||||
})(
|
> = props => {
|
||||||
({
|
const {
|
||||||
allowCustomValues,
|
allowCustomValues,
|
||||||
choices,
|
choices,
|
||||||
classes,
|
|
||||||
displayValues,
|
displayValues,
|
||||||
|
|
||||||
hasMore,
|
hasMore,
|
||||||
helperText,
|
helperText,
|
||||||
label,
|
label,
|
||||||
|
@ -95,107 +90,109 @@ export const MultiAutocompleteSelectFieldComponent = withStyles(styles, {
|
||||||
fetchChoices,
|
fetchChoices,
|
||||||
onChange,
|
onChange,
|
||||||
onFetchMore,
|
onFetchMore,
|
||||||
...props
|
...rest
|
||||||
}: MultiAutocompleteSelectFieldProps & WithStyles<typeof styles>) => {
|
} = props;
|
||||||
const handleSelect = (
|
const classes = useStyles(props);
|
||||||
item: string,
|
|
||||||
downshiftOpts?: ControllerStateAndHelpers
|
|
||||||
) => {
|
|
||||||
if (downshiftOpts) {
|
|
||||||
downshiftOpts.reset({ inputValue: "" });
|
|
||||||
}
|
|
||||||
onChange({
|
|
||||||
target: { name, value: item }
|
|
||||||
} as any);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
const handleSelect = (
|
||||||
<>
|
item: string,
|
||||||
<Downshift
|
downshiftOpts?: ControllerStateAndHelpers
|
||||||
onInputValueChange={fetchChoices}
|
) => {
|
||||||
onSelect={handleSelect}
|
if (downshiftOpts) {
|
||||||
itemToString={() => ""}
|
downshiftOpts.reset({ inputValue: "" });
|
||||||
>
|
}
|
||||||
{({
|
onChange({
|
||||||
getInputProps,
|
target: { name, value: item }
|
||||||
getItemProps,
|
} as any);
|
||||||
isOpen,
|
};
|
||||||
toggleMenu,
|
|
||||||
highlightedIndex,
|
|
||||||
inputValue
|
|
||||||
}) => {
|
|
||||||
const displayCustomValue =
|
|
||||||
inputValue &&
|
|
||||||
inputValue.length > 0 &&
|
|
||||||
allowCustomValues &&
|
|
||||||
!choices.find(
|
|
||||||
choice =>
|
|
||||||
choice.label.toLowerCase() === inputValue.toLowerCase()
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.container} {...props}>
|
<>
|
||||||
<TextField
|
<Downshift
|
||||||
InputProps={{
|
onInputValueChange={fetchChoices}
|
||||||
...getInputProps({
|
onSelect={handleSelect}
|
||||||
placeholder
|
itemToString={() => ""}
|
||||||
}),
|
>
|
||||||
endAdornment: (
|
{({
|
||||||
<div>
|
getInputProps,
|
||||||
<ArrowDropdownIcon onClick={toggleMenu} />
|
getItemProps,
|
||||||
</div>
|
isOpen,
|
||||||
),
|
toggleMenu,
|
||||||
id: undefined,
|
highlightedIndex,
|
||||||
onClick: toggleMenu
|
inputValue
|
||||||
}}
|
}) => {
|
||||||
helperText={helperText}
|
const displayCustomValue =
|
||||||
label={label}
|
inputValue &&
|
||||||
fullWidth={true}
|
inputValue.length > 0 &&
|
||||||
/>
|
allowCustomValues &&
|
||||||
{isOpen && (!!inputValue || !!choices.length) && (
|
!choices.find(
|
||||||
<MultiAutocompleteSelectFieldContent
|
choice => choice.label.toLowerCase() === inputValue.toLowerCase()
|
||||||
choices={choices.filter(
|
|
||||||
choice => !value.includes(choice.value)
|
|
||||||
)}
|
|
||||||
displayCustomValue={displayCustomValue}
|
|
||||||
displayValues={displayValues}
|
|
||||||
getItemProps={getItemProps}
|
|
||||||
hasMore={hasMore}
|
|
||||||
highlightedIndex={highlightedIndex}
|
|
||||||
loading={loading}
|
|
||||||
inputValue={inputValue}
|
|
||||||
onFetchMore={onFetchMore}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}}
|
|
||||||
</Downshift>
|
return (
|
||||||
<div className={classes.chipContainer}>
|
<div className={classes.container} {...rest}>
|
||||||
{displayValues.map(value => (
|
<TextField
|
||||||
<div className={classes.chip} key={value.value}>
|
InputProps={{
|
||||||
<div className={classes.chipInner}>
|
...getInputProps({
|
||||||
<Typography className={classes.chipLabel}>
|
placeholder
|
||||||
{value.label}
|
}),
|
||||||
</Typography>
|
endAdornment: (
|
||||||
<IconButton
|
<div>
|
||||||
className={classes.chipClose}
|
<ArrowDropdownIcon onClick={() => toggleMenu()} />
|
||||||
onClick={() => handleSelect(value.value)}
|
</div>
|
||||||
>
|
),
|
||||||
<CloseIcon fontSize="small" />
|
id: undefined,
|
||||||
</IconButton>
|
onClick: toggleMenu
|
||||||
</div>
|
}}
|
||||||
|
helperText={helperText}
|
||||||
|
label={label}
|
||||||
|
fullWidth={true}
|
||||||
|
/>
|
||||||
|
{isOpen && (!!inputValue || !!choices.length) && (
|
||||||
|
<MultiAutocompleteSelectFieldContent
|
||||||
|
choices={choices.filter(
|
||||||
|
choice => !value.includes(choice.value)
|
||||||
|
)}
|
||||||
|
displayCustomValue={displayCustomValue}
|
||||||
|
displayValues={displayValues}
|
||||||
|
getItemProps={getItemProps}
|
||||||
|
hasMore={hasMore}
|
||||||
|
highlightedIndex={highlightedIndex}
|
||||||
|
loading={loading}
|
||||||
|
inputValue={inputValue}
|
||||||
|
onFetchMore={onFetchMore}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
);
|
||||||
</div>
|
}}
|
||||||
</>
|
</Downshift>
|
||||||
);
|
<div className={classes.chipContainer}>
|
||||||
}
|
{displayValues.map(value => (
|
||||||
);
|
<div className={classes.chip} key={value.value}>
|
||||||
|
<div className={classes.chipInner}>
|
||||||
|
<Typography className={classes.chipLabel}>
|
||||||
|
{value.label}
|
||||||
|
</Typography>
|
||||||
|
<IconButton
|
||||||
|
className={classes.chipClose}
|
||||||
|
onClick={() => handleSelect(value.value)}
|
||||||
|
>
|
||||||
|
<CloseIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const MultiAutocompleteSelectField: React.FC<
|
const MultiAutocompleteSelectField: React.FC<
|
||||||
MultiAutocompleteSelectFieldProps
|
MultiAutocompleteSelectFieldProps
|
||||||
> = ({ choices, fetchChoices, ...props }) => {
|
> = ({ choices, fetchChoices, ...props }) => {
|
||||||
const [query, setQuery] = React.useState("");
|
const [query, setQuery] = React.useState("");
|
||||||
|
|
||||||
if (fetchChoices) {
|
if (fetchChoices) {
|
||||||
return (
|
return (
|
||||||
<DebounceAutocomplete debounceFn={fetchChoices}>
|
<DebounceAutocomplete debounceFn={fetchChoices}>
|
||||||
|
@ -220,5 +217,6 @@ const MultiAutocompleteSelectField: React.FC<
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
MultiAutocompleteSelectField.displayName = "MultiAutocompleteSelectField";
|
MultiAutocompleteSelectField.displayName = "MultiAutocompleteSelectField";
|
||||||
export default MultiAutocompleteSelectField;
|
export default MultiAutocompleteSelectField;
|
||||||
|
|
|
@ -4,34 +4,28 @@ import FormHelperText from "@material-ui/core/FormHelperText";
|
||||||
import InputLabel from "@material-ui/core/InputLabel";
|
import InputLabel from "@material-ui/core/InputLabel";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@material-ui/core/MenuItem";
|
||||||
import Select, { SelectProps } from "@material-ui/core/Select";
|
import Select, { SelectProps } from "@material-ui/core/Select";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import Checkbox from "../Checkbox";
|
import Checkbox from "../Checkbox";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
checkbox: {
|
||||||
checkbox: {
|
marginRight: -theme.spacing(2)
|
||||||
marginRight: -theme.spacing(2)
|
},
|
||||||
},
|
formControl: {
|
||||||
formControl: {
|
width: "100%"
|
||||||
width: "100%"
|
},
|
||||||
},
|
menuItem: {
|
||||||
menuItem: {
|
alignItems: "center",
|
||||||
alignItems: "center",
|
display: "flex",
|
||||||
display: "flex",
|
justifyContent: "space-between",
|
||||||
justifyContent: "space-between",
|
width: "100%"
|
||||||
width: "100%"
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface MultiSelectFieldProps extends WithStyles<typeof styles> {
|
interface MultiSelectFieldProps {
|
||||||
choices: Array<{
|
choices: Array<{
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
@ -46,11 +40,8 @@ interface MultiSelectFieldProps extends WithStyles<typeof styles> {
|
||||||
onChange(event: any);
|
onChange(event: any);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MultiSelectField = withStyles(styles, {
|
export const MultiSelectField: React.FC<MultiSelectFieldProps> = props => {
|
||||||
name: "MultiSelectField"
|
const {
|
||||||
})(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
disabled,
|
disabled,
|
||||||
error,
|
error,
|
||||||
label,
|
label,
|
||||||
|
@ -60,66 +51,67 @@ export const MultiSelectField = withStyles(styles, {
|
||||||
name,
|
name,
|
||||||
hint,
|
hint,
|
||||||
selectProps
|
selectProps
|
||||||
}: MultiSelectFieldProps) => {
|
} = props;
|
||||||
const choicesByKey = disabled
|
const classes = useStyles(props);
|
||||||
? {}
|
|
||||||
: choices.reduce((prev, curr) => {
|
|
||||||
prev[curr.value] = curr.label;
|
|
||||||
return prev;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
return (
|
const choicesByKey = disabled
|
||||||
<FormControl
|
? {}
|
||||||
className={classes.formControl}
|
: choices.reduce((prev, curr) => {
|
||||||
error={error}
|
prev[curr.value] = curr.label;
|
||||||
disabled={disabled}
|
return prev;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl
|
||||||
|
className={classes.formControl}
|
||||||
|
error={error}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
{label && <InputLabel>{label}</InputLabel>}
|
||||||
|
<Select
|
||||||
|
multiple
|
||||||
|
fullWidth
|
||||||
|
renderValue={choiceValues =>
|
||||||
|
(choiceValues as string[])
|
||||||
|
.map(choiceValue => choicesByKey[choiceValue])
|
||||||
|
.join(", ")
|
||||||
|
}
|
||||||
|
value={value}
|
||||||
|
name={name}
|
||||||
|
onChange={onChange}
|
||||||
|
input={<FilledInput name={name} />}
|
||||||
|
{...selectProps}
|
||||||
>
|
>
|
||||||
{label && <InputLabel>{label}</InputLabel>}
|
{choices.length > 0 ? (
|
||||||
<Select
|
choices.map(choice => {
|
||||||
multiple
|
const isSelected = !!value.find(
|
||||||
fullWidth
|
selectedChoice => selectedChoice === choice.value
|
||||||
renderValue={choiceValues =>
|
);
|
||||||
(choiceValues as string[])
|
|
||||||
.map(choiceValue => choicesByKey[choiceValue])
|
|
||||||
.join(", ")
|
|
||||||
}
|
|
||||||
value={value}
|
|
||||||
name={name}
|
|
||||||
onChange={onChange}
|
|
||||||
input={<FilledInput name={name} />}
|
|
||||||
{...selectProps}
|
|
||||||
>
|
|
||||||
{choices.length > 0 ? (
|
|
||||||
choices.map(choice => {
|
|
||||||
const isSelected = !!value.find(
|
|
||||||
selectedChoice => selectedChoice === choice.value
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuItem value={choice.value} key={choice.value}>
|
<MenuItem value={choice.value} key={choice.value}>
|
||||||
<div className={classes.menuItem}>
|
<div className={classes.menuItem}>
|
||||||
<span>{choice.label}</span>
|
<span>{choice.label}</span>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className={classes.checkbox}
|
className={classes.checkbox}
|
||||||
checked={isSelected}
|
checked={isSelected}
|
||||||
disableRipple={true}
|
disableRipple={true}
|
||||||
disableTouchRipple={true}
|
disableTouchRipple={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
) : (
|
) : (
|
||||||
<MenuItem disabled={true}>
|
<MenuItem disabled={true}>
|
||||||
<FormattedMessage defaultMessage="No results found" />
|
<FormattedMessage defaultMessage="No results found" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
</Select>
|
</Select>
|
||||||
{hint && <FormHelperText>{hint}</FormHelperText>}
|
{hint && <FormHelperText>{hint}</FormHelperText>}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
);
|
|
||||||
MultiSelectField.defaultProps = {
|
MultiSelectField.defaultProps = {
|
||||||
value: []
|
value: []
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import SVG from "react-inlinesvg";
|
import SVG from "react-inlinesvg";
|
||||||
|
@ -12,54 +7,57 @@ import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import notFoundImage from "@assets/images/not-found-404.svg";
|
import notFoundImage from "@assets/images/not-found-404.svg";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
button: {
|
||||||
button: {
|
marginTop: theme.spacing(2),
|
||||||
marginTop: theme.spacing(2),
|
padding: 20
|
||||||
padding: 20
|
},
|
||||||
|
container: {
|
||||||
|
[theme.breakpoints.down("sm")]: {
|
||||||
|
gridTemplateColumns: "1fr",
|
||||||
|
padding: theme.spacing(3),
|
||||||
|
width: "100%"
|
||||||
},
|
},
|
||||||
container: {
|
display: "grid",
|
||||||
[theme.breakpoints.down("sm")]: {
|
gridTemplateColumns: "1fr 487px",
|
||||||
gridTemplateColumns: "1fr",
|
margin: "0 auto",
|
||||||
padding: theme.spacing(3),
|
width: 830
|
||||||
width: "100%"
|
},
|
||||||
},
|
header: {
|
||||||
display: "grid",
|
fontWeight: 600 as 600
|
||||||
gridTemplateColumns: "1fr 487px",
|
},
|
||||||
margin: "0 auto",
|
innerContainer: {
|
||||||
width: 830
|
[theme.breakpoints.down("sm")]: {
|
||||||
|
order: 1,
|
||||||
|
textAlign: "center"
|
||||||
},
|
},
|
||||||
header: {
|
display: "flex",
|
||||||
fontWeight: 600 as 600
|
flexDirection: "column",
|
||||||
},
|
justifyContent: "center"
|
||||||
innerContainer: {
|
},
|
||||||
[theme.breakpoints.down("sm")]: {
|
notFoundImage: {
|
||||||
order: 1,
|
"& svg": {
|
||||||
textAlign: "center"
|
width: "100%"
|
||||||
},
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
justifyContent: "center"
|
|
||||||
},
|
|
||||||
notFoundImage: {
|
|
||||||
"& svg": {
|
|
||||||
width: "100%"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
alignItems: "center",
|
|
||||||
display: "flex",
|
|
||||||
height: "100vh",
|
|
||||||
width: "100vw"
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
root: {
|
||||||
|
alignItems: "center",
|
||||||
|
display: "flex",
|
||||||
|
height: "100vh",
|
||||||
|
width: "100vw"
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
interface NotFoundPageProps extends WithStyles<typeof styles> {
|
interface NotFoundPageProps {
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NotFoundPage = withStyles(styles, { name: "NotFoundPage" })(
|
const NotFoundPage: React.FC<NotFoundPageProps> = props => {
|
||||||
({ classes, onBack }: NotFoundPageProps) => (
|
const { onBack } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<div className={classes.container}>
|
<div className={classes.container}>
|
||||||
<div className={classes.innerContainer}>
|
<div className={classes.innerContainer}>
|
||||||
|
@ -93,7 +91,7 @@ const NotFoundPage = withStyles(styles, { name: "NotFoundPage" })(
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
NotFoundPage.displayName = "NotFoundPage";
|
NotFoundPage.displayName = "NotFoundPage";
|
||||||
export default NotFoundPage;
|
export default NotFoundPage;
|
||||||
|
|
|
@ -1,35 +1,33 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import ExtendedPageHeader from "../ExtendedPageHeader";
|
import ExtendedPageHeader from "../ExtendedPageHeader";
|
||||||
import Skeleton from "../Skeleton";
|
import Skeleton from "../Skeleton";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
root: {
|
||||||
root: {
|
display: "flex"
|
||||||
display: "flex"
|
},
|
||||||
},
|
title: {
|
||||||
title: {
|
flex: 1,
|
||||||
flex: 1,
|
fontSize: 24,
|
||||||
fontSize: 24,
|
paddingBottom: theme.spacing(2)
|
||||||
paddingBottom: theme.spacing(2)
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface PageHeaderProps extends WithStyles<typeof styles> {
|
interface PageHeaderProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PageHeader = withStyles(styles)(
|
const PageHeader: React.FC<PageHeaderProps> = props => {
|
||||||
({ children, classes, className, title }: PageHeaderProps) => (
|
const { children, className, title } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<ExtendedPageHeader
|
<ExtendedPageHeader
|
||||||
className={className}
|
className={className}
|
||||||
title={
|
title={
|
||||||
|
@ -40,7 +38,8 @@ const PageHeader = withStyles(styles)(
|
||||||
>
|
>
|
||||||
<div className={classes.root}>{children}</div>
|
<div className={classes.root}>{children}</div>
|
||||||
</ExtendedPageHeader>
|
</ExtendedPageHeader>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
|
|
||||||
PageHeader.displayName = "PageHeader";
|
PageHeader.displayName = "PageHeader";
|
||||||
export default PageHeader;
|
export default PageHeader;
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import SingleSelectField from "@saleor/components/SingleSelectField";
|
import SingleSelectField from "@saleor/components/SingleSelectField";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
root: {
|
||||||
root: {
|
display: "grid",
|
||||||
display: "grid",
|
gridColumnGap: theme.spacing(2),
|
||||||
gridColumnGap: theme.spacing(2),
|
gridTemplateColumns: "5rem 1fr"
|
||||||
gridTemplateColumns: "5rem 1fr"
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface PhoneFieldProps extends WithStyles<typeof styles> {
|
interface PhoneFieldProps {
|
||||||
name: string;
|
name: string;
|
||||||
prefix: string;
|
prefix: string;
|
||||||
number: string;
|
number: string;
|
||||||
|
@ -27,16 +21,19 @@ interface PhoneFieldProps extends WithStyles<typeof styles> {
|
||||||
onChange(event: React.ChangeEvent<any>);
|
onChange(event: React.ChangeEvent<any>);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PhoneField = withStyles(styles, { name: "PhoneField" })(
|
const PhoneField: React.FC<PhoneFieldProps> = props => {
|
||||||
({
|
const {
|
||||||
classes,
|
|
||||||
name,
|
name,
|
||||||
number: phoneNumber,
|
number: phoneNumber,
|
||||||
prefix,
|
prefix,
|
||||||
prefixes,
|
prefixes,
|
||||||
label,
|
label,
|
||||||
onChange
|
onChange
|
||||||
}: PhoneFieldProps) => (
|
} = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<SingleSelectField
|
<SingleSelectField
|
||||||
name={name + "_prefix"}
|
name={name + "_prefix"}
|
||||||
|
@ -52,7 +49,7 @@ const PhoneField = withStyles(styles, { name: "PhoneField" })(
|
||||||
label=" "
|
label=" "
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
PhoneField.displayName = "PhoneField";
|
PhoneField.displayName = "PhoneField";
|
||||||
export default PhoneField;
|
export default PhoneField;
|
||||||
|
|
|
@ -1,32 +1,31 @@
|
||||||
import { InputProps } from "@material-ui/core/Input";
|
import { InputProps } from "@material-ui/core/Input";
|
||||||
import InputAdornment from "@material-ui/core/InputAdornment";
|
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
currencySymbol: {
|
||||||
currencySymbol: {
|
fontSize: "0.875rem"
|
||||||
fontSize: "0.875rem"
|
},
|
||||||
},
|
inputContainer: {
|
||||||
inputContainer: {
|
display: "grid",
|
||||||
display: "grid",
|
gridTemplateColumns: "1fr 2rem 1fr"
|
||||||
gridTemplateColumns: "1fr 2rem 1fr"
|
},
|
||||||
},
|
pullDown: {
|
||||||
pullDown: {
|
marginTop: theme.spacing(2)
|
||||||
marginTop: theme.spacing(2)
|
},
|
||||||
},
|
separator: {
|
||||||
separator: {
|
marginTop: theme.spacing(3),
|
||||||
marginTop: theme.spacing(3),
|
textAlign: "center",
|
||||||
textAlign: "center",
|
width: "100%"
|
||||||
width: "100%"
|
},
|
||||||
},
|
widgetContainer: {
|
||||||
widgetContainer: {
|
marginTop: theme.spacing(2)
|
||||||
marginTop: theme.spacing(2)
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface PriceFieldProps extends WithStyles<typeof styles> {
|
interface PriceFieldProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
currencySymbol?: string;
|
currencySymbol?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
@ -39,8 +38,8 @@ interface PriceFieldProps extends WithStyles<typeof styles> {
|
||||||
onChange(event: any);
|
onChange(event: any);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PriceField = withStyles(styles, { name: "PriceField" })(
|
export const PriceField: React.FC<PriceFieldProps> = props => {
|
||||||
({
|
const {
|
||||||
className,
|
className,
|
||||||
disabled,
|
disabled,
|
||||||
error,
|
error,
|
||||||
|
@ -48,11 +47,14 @@ export const PriceField = withStyles(styles, { name: "PriceField" })(
|
||||||
hint,
|
hint,
|
||||||
currencySymbol,
|
currencySymbol,
|
||||||
name,
|
name,
|
||||||
classes,
|
|
||||||
onChange,
|
onChange,
|
||||||
value,
|
value,
|
||||||
InputProps
|
InputProps
|
||||||
}: PriceFieldProps) => (
|
} = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
className={className}
|
className={className}
|
||||||
error={error}
|
error={error}
|
||||||
|
@ -75,8 +77,8 @@ export const PriceField = withStyles(styles, { name: "PriceField" })(
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
PriceField.defaultProps = {
|
PriceField.defaultProps = {
|
||||||
name: "price"
|
name: "price"
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,11 +2,11 @@ import FormControl from "@material-ui/core/FormControl";
|
||||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
||||||
import Radio from "@material-ui/core/Radio";
|
import Radio from "@material-ui/core/Radio";
|
||||||
import RadioGroup from "@material-ui/core/RadioGroup";
|
import RadioGroup from "@material-ui/core/RadioGroup";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = createStyles({
|
const useStyles = makeStyles({
|
||||||
formControl: {
|
formControl: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
width: "100%"
|
width: "100%"
|
||||||
|
@ -37,12 +37,9 @@ interface RadioSwitchFieldProps {
|
||||||
onChange: (event: React.ChangeEvent<any>) => void;
|
onChange: (event: React.ChangeEvent<any>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RadioSwitchField = withStyles(styles, {
|
export const RadioSwitchField: React.FC<RadioSwitchFieldProps> = props => {
|
||||||
name: "RadioSwitchField"
|
const {
|
||||||
})(
|
|
||||||
({
|
|
||||||
className,
|
className,
|
||||||
classes,
|
|
||||||
disabled,
|
disabled,
|
||||||
error,
|
error,
|
||||||
firstOptionLabel,
|
firstOptionLabel,
|
||||||
|
@ -50,48 +47,49 @@ export const RadioSwitchField = withStyles(styles, {
|
||||||
name,
|
name,
|
||||||
secondOptionLabel,
|
secondOptionLabel,
|
||||||
value
|
value
|
||||||
}: RadioSwitchFieldProps & WithStyles<typeof styles>) => {
|
} = props;
|
||||||
const initialValue = value ? "true" : "false";
|
const classes = useStyles(props);
|
||||||
|
|
||||||
const change = event => {
|
const initialValue = value ? "true" : "false";
|
||||||
onChange({
|
|
||||||
target: {
|
|
||||||
name: event.target.name,
|
|
||||||
value: event.target.value === "true" ? true : false
|
|
||||||
}
|
|
||||||
} as any);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
const change = event => {
|
||||||
<FormControl
|
onChange({
|
||||||
className={classNames(classes.formControl, className)}
|
target: {
|
||||||
error={error}
|
name: event.target.name,
|
||||||
disabled={disabled}
|
value: event.target.value === "true" ? true : false
|
||||||
|
}
|
||||||
|
} as any);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl
|
||||||
|
className={classNames(classes.formControl, className)}
|
||||||
|
error={error}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
<RadioGroup
|
||||||
|
aria-label={name}
|
||||||
|
name={name}
|
||||||
|
value={initialValue}
|
||||||
|
onChange={event => change(event)}
|
||||||
>
|
>
|
||||||
<RadioGroup
|
<FormControlLabel
|
||||||
aria-label={name}
|
value="true"
|
||||||
|
className={classes.radioLabel}
|
||||||
|
control={<Radio color="primary" />}
|
||||||
|
label={firstOptionLabel}
|
||||||
name={name}
|
name={name}
|
||||||
value={initialValue}
|
/>
|
||||||
onChange={event => change(event)}
|
<FormControlLabel
|
||||||
>
|
value="false"
|
||||||
<FormControlLabel
|
className={classes.radioLabel}
|
||||||
value="true"
|
control={<Radio color="primary" />}
|
||||||
className={classes.radioLabel}
|
label={secondOptionLabel}
|
||||||
control={<Radio color="primary" />}
|
name={name}
|
||||||
label={firstOptionLabel}
|
/>
|
||||||
name={name}
|
</RadioGroup>
|
||||||
/>
|
</FormControl>
|
||||||
<FormControlLabel
|
);
|
||||||
value="false"
|
};
|
||||||
className={classes.radioLabel}
|
|
||||||
control={<Radio color="primary" />}
|
|
||||||
label={secondOptionLabel}
|
|
||||||
name={name}
|
|
||||||
/>
|
|
||||||
</RadioGroup>
|
|
||||||
</FormControl>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
RadioSwitchField.displayName = "RadioSwitchField";
|
RadioSwitchField.displayName = "RadioSwitchField";
|
||||||
export default RadioSwitchField;
|
export default RadioSwitchField;
|
||||||
|
|
|
@ -4,12 +4,7 @@ import Grow from "@material-ui/core/Grow";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import Popper from "@material-ui/core/Popper";
|
import Popper from "@material-ui/core/Popper";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import DeleteIcon from "@material-ui/icons/Delete";
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
import { ContentState } from "draft-js";
|
import { ContentState } from "draft-js";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
@ -23,92 +18,84 @@ interface ImageEntityProps {
|
||||||
onRemove: (entityKey: string) => void;
|
onRemove: (entityKey: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
anchor: {
|
||||||
anchor: {
|
display: "inline-block"
|
||||||
display: "inline-block"
|
},
|
||||||
},
|
container: {
|
||||||
container: {
|
alignItems: "center",
|
||||||
alignItems: "center",
|
display: "flex"
|
||||||
display: "flex"
|
},
|
||||||
},
|
image: { maxWidth: "100%" },
|
||||||
image: { maxWidth: "100%" },
|
inline: {
|
||||||
inline: {
|
display: "inline-block"
|
||||||
display: "inline-block"
|
},
|
||||||
},
|
root: {
|
||||||
root: {
|
alignItems: "center",
|
||||||
alignItems: "center",
|
display: "flex",
|
||||||
display: "flex",
|
minHeight: 72,
|
||||||
minHeight: 72,
|
padding: theme.spacing(1.5)
|
||||||
padding: theme.spacing(1.5)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const ImageEntity = withStyles(styles, {
|
|
||||||
name: "ImageEntity"
|
|
||||||
})(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
contentState,
|
|
||||||
entityKey,
|
|
||||||
onEdit,
|
|
||||||
onRemove
|
|
||||||
}: ImageEntityProps & WithStyles<typeof styles>) => {
|
|
||||||
const [isOpened, setOpenStatus] = React.useState(false);
|
|
||||||
const anchor = React.useRef<HTMLDivElement>();
|
|
||||||
|
|
||||||
const disable = () => setOpenStatus(false);
|
|
||||||
const toggle = () => setOpenStatus(!isOpened);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={classes.anchor} ref={anchor}>
|
|
||||||
<Popper
|
|
||||||
open={isOpened}
|
|
||||||
anchorEl={anchor.current}
|
|
||||||
transition
|
|
||||||
disablePortal
|
|
||||||
placement="bottom"
|
|
||||||
>
|
|
||||||
{({ TransitionProps, placement }) => (
|
|
||||||
<Grow
|
|
||||||
{...TransitionProps}
|
|
||||||
style={{
|
|
||||||
transformOrigin: placement
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Paper className={classes.root}>
|
|
||||||
<ClickAwayListener onClickAway={disable} mouseEvent="onClick">
|
|
||||||
<div className={classes.container}>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
disable();
|
|
||||||
onEdit(entityKey);
|
|
||||||
}}
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Replace"
|
|
||||||
description="replace image, button"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
<IconButton onClick={() => onRemove(entityKey)}>
|
|
||||||
<DeleteIcon color="primary" />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
</ClickAwayListener>
|
|
||||||
</Paper>
|
|
||||||
</Grow>
|
|
||||||
)}
|
|
||||||
</Popper>
|
|
||||||
</div>
|
|
||||||
<img
|
|
||||||
className={classes.image}
|
|
||||||
src={contentState.getEntity(entityKey).getData().href}
|
|
||||||
onClick={toggle}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
}));
|
||||||
|
|
||||||
|
const ImageEntity: React.FC<ImageEntityProps> = props => {
|
||||||
|
const { contentState, entityKey, onEdit, onRemove } = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
const [isOpened, setOpenStatus] = React.useState(false);
|
||||||
|
const anchor = React.useRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
const disable = () => setOpenStatus(false);
|
||||||
|
const toggle = () => setOpenStatus(!isOpened);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={classes.anchor} ref={anchor}>
|
||||||
|
<Popper
|
||||||
|
open={isOpened}
|
||||||
|
anchorEl={anchor.current}
|
||||||
|
transition
|
||||||
|
disablePortal
|
||||||
|
placement="bottom"
|
||||||
|
>
|
||||||
|
{({ TransitionProps, placement }) => (
|
||||||
|
<Grow
|
||||||
|
{...TransitionProps}
|
||||||
|
style={{
|
||||||
|
transformOrigin: placement
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Paper className={classes.root}>
|
||||||
|
<ClickAwayListener onClickAway={disable} mouseEvent="onClick">
|
||||||
|
<div className={classes.container}>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
disable();
|
||||||
|
onEdit(entityKey);
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Replace"
|
||||||
|
description="replace image, button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
<IconButton onClick={() => onRemove(entityKey)}>
|
||||||
|
<DeleteIcon color="primary" />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
)}
|
||||||
|
</Popper>
|
||||||
|
</div>
|
||||||
|
<img
|
||||||
|
className={classes.image}
|
||||||
|
src={contentState.getEntity(entityKey).getData().href}
|
||||||
|
onClick={toggle}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
export default ImageEntity;
|
export default ImageEntity;
|
||||||
|
|
|
@ -4,12 +4,7 @@ import Grow from "@material-ui/core/Grow";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import Popper from "@material-ui/core/Popper";
|
import Popper from "@material-ui/core/Popper";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import DeleteIcon from "@material-ui/icons/Delete";
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
import { ContentState } from "draft-js";
|
import { ContentState } from "draft-js";
|
||||||
|
@ -27,106 +22,97 @@ interface LinkEntityProps {
|
||||||
onRemove: (entityKey: string) => void;
|
onRemove: (entityKey: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
anchor: {
|
||||||
anchor: {
|
display: "inline-block"
|
||||||
display: "inline-block"
|
},
|
||||||
},
|
container: {
|
||||||
container: {
|
alignItems: "center",
|
||||||
alignItems: "center",
|
display: "flex"
|
||||||
display: "flex"
|
},
|
||||||
},
|
inline: {
|
||||||
inline: {
|
display: "inline-block"
|
||||||
display: "inline-block"
|
},
|
||||||
},
|
popover: {
|
||||||
popover: {
|
zIndex: 1
|
||||||
zIndex: 1
|
},
|
||||||
},
|
root: {
|
||||||
root: {
|
alignItems: "center",
|
||||||
alignItems: "center",
|
display: "flex",
|
||||||
display: "flex",
|
minHeight: 72,
|
||||||
minHeight: 72,
|
padding: theme.spacing(1.5, 1.5, 1.5, 3)
|
||||||
padding: theme.spacing(1.5, 1.5, 1.5, 3)
|
},
|
||||||
},
|
separator: {
|
||||||
separator: {
|
backgroundColor: theme.palette.grey[300],
|
||||||
backgroundColor: theme.palette.grey[300],
|
display: "inline-block",
|
||||||
display: "inline-block",
|
height: 30,
|
||||||
height: 30,
|
marginLeft: theme.spacing(2),
|
||||||
marginLeft: theme.spacing(2),
|
marginRight: theme.spacing(),
|
||||||
marginRight: theme.spacing(),
|
width: 1
|
||||||
width: 1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const LinkEntity = withStyles(styles, {
|
|
||||||
name: "LinkEntity"
|
|
||||||
})(
|
|
||||||
({
|
|
||||||
classes,
|
|
||||||
children,
|
|
||||||
contentState,
|
|
||||||
entityKey,
|
|
||||||
onEdit,
|
|
||||||
onRemove
|
|
||||||
}: LinkEntityProps & WithStyles<typeof styles>) => {
|
|
||||||
const [isOpened, setOpenStatus] = React.useState(false);
|
|
||||||
const anchor = React.useRef<HTMLDivElement>();
|
|
||||||
|
|
||||||
const disable = () => setOpenStatus(false);
|
|
||||||
const toggle = () => setOpenStatus(!isOpened);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={classes.anchor} ref={anchor}>
|
|
||||||
<Popper
|
|
||||||
className={classes.popover}
|
|
||||||
open={isOpened}
|
|
||||||
anchorEl={anchor.current}
|
|
||||||
transition
|
|
||||||
disablePortal
|
|
||||||
placement="bottom"
|
|
||||||
>
|
|
||||||
{({ TransitionProps, placement }) => (
|
|
||||||
<Grow
|
|
||||||
{...TransitionProps}
|
|
||||||
style={{
|
|
||||||
transformOrigin: placement
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Paper className={classes.root}>
|
|
||||||
<ClickAwayListener onClickAway={disable} mouseEvent="onClick">
|
|
||||||
<div className={classes.container}>
|
|
||||||
<Typography className={classes.inline} variant="body1">
|
|
||||||
{contentState.getEntity(entityKey).getData().url}
|
|
||||||
</Typography>
|
|
||||||
<span className={classes.separator} />
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
disable();
|
|
||||||
onEdit(entityKey);
|
|
||||||
}}
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<FormattedMessage {...buttonMessages.edit} />
|
|
||||||
</Button>
|
|
||||||
<IconButton onClick={() => onRemove(entityKey)}>
|
|
||||||
<DeleteIcon color="primary" />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
</ClickAwayListener>
|
|
||||||
</Paper>
|
|
||||||
</Grow>
|
|
||||||
)}
|
|
||||||
</Popper>
|
|
||||||
</div>
|
|
||||||
<Link
|
|
||||||
href={contentState.getEntity(entityKey).getData().url}
|
|
||||||
onClick={toggle}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Link>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
}));
|
||||||
|
|
||||||
|
const LinkEntity: React.FC<LinkEntityProps> = props => {
|
||||||
|
const { children, contentState, entityKey, onEdit, onRemove } = props;
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
const [isOpened, setOpenStatus] = React.useState(false);
|
||||||
|
const anchor = React.useRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
const disable = () => setOpenStatus(false);
|
||||||
|
const toggle = () => setOpenStatus(!isOpened);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={classes.anchor} ref={anchor}>
|
||||||
|
<Popper
|
||||||
|
className={classes.popover}
|
||||||
|
open={isOpened}
|
||||||
|
anchorEl={anchor.current}
|
||||||
|
transition
|
||||||
|
disablePortal
|
||||||
|
placement="bottom"
|
||||||
|
>
|
||||||
|
{({ TransitionProps, placement }) => (
|
||||||
|
<Grow
|
||||||
|
{...TransitionProps}
|
||||||
|
style={{
|
||||||
|
transformOrigin: placement
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Paper className={classes.root}>
|
||||||
|
<ClickAwayListener onClickAway={disable} mouseEvent="onClick">
|
||||||
|
<div className={classes.container}>
|
||||||
|
<Typography className={classes.inline} variant="body1">
|
||||||
|
{contentState.getEntity(entityKey).getData().url}
|
||||||
|
</Typography>
|
||||||
|
<span className={classes.separator} />
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
disable();
|
||||||
|
onEdit(entityKey);
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<FormattedMessage {...buttonMessages.edit} />
|
||||||
|
</Button>
|
||||||
|
<IconButton onClick={() => onRemove(entityKey)}>
|
||||||
|
<DeleteIcon color="primary" />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
)}
|
||||||
|
</Popper>
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
href={contentState.getEntity(entityKey).getData().url}
|
||||||
|
onClick={toggle}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
export default LinkEntity;
|
export default LinkEntity;
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -45,159 +40,158 @@ export interface RichTextEditorProps {
|
||||||
onChange: (event: React.ChangeEvent<any>) => void;
|
onChange: (event: React.ChangeEvent<any>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
error: {
|
||||||
error: {
|
color: theme.palette.error.main
|
||||||
color: theme.palette.error.main
|
},
|
||||||
},
|
helperText: {
|
||||||
helperText: {
|
marginTop: theme.spacing(0.75)
|
||||||
marginTop: theme.spacing(0.75)
|
},
|
||||||
},
|
input: {
|
||||||
input: {
|
position: "relative"
|
||||||
position: "relative"
|
},
|
||||||
},
|
label: {
|
||||||
label: {
|
fontSize: theme.typography.caption.fontSize,
|
||||||
fontSize: theme.typography.caption.fontSize,
|
left: 12,
|
||||||
left: 12,
|
position: "absolute",
|
||||||
position: "absolute",
|
top: 9
|
||||||
top: 9
|
},
|
||||||
},
|
linkIcon: {
|
||||||
linkIcon: {
|
marginTop: 2
|
||||||
marginTop: 2
|
},
|
||||||
},
|
root: {
|
||||||
root: {
|
"& .DraftEditor": {
|
||||||
"& .DraftEditor": {
|
"&-editorContainer": {
|
||||||
"&-editorContainer": {
|
"& .public-DraftEditor-content": {
|
||||||
"& .public-DraftEditor-content": {
|
lineHeight: 1.62
|
||||||
lineHeight: 1.62
|
|
||||||
},
|
|
||||||
"& a": {
|
|
||||||
color: theme.palette.primary.light
|
|
||||||
},
|
|
||||||
"&:after": {
|
|
||||||
background: theme.palette.getContrastText(
|
|
||||||
theme.palette.background.default
|
|
||||||
),
|
|
||||||
bottom: -11,
|
|
||||||
content: "''",
|
|
||||||
display: "block",
|
|
||||||
height: 2,
|
|
||||||
left: -12,
|
|
||||||
position: "absolute",
|
|
||||||
transform: "scaleX(0) scaleY(0)",
|
|
||||||
width: "calc(100% + 24px)"
|
|
||||||
},
|
|
||||||
position: "relative"
|
|
||||||
},
|
},
|
||||||
"&-root": {
|
"& a": {
|
||||||
...theme.typography.body1
|
color: theme.palette.primary.light
|
||||||
}
|
},
|
||||||
|
"&:after": {
|
||||||
|
background: theme.palette.getContrastText(
|
||||||
|
theme.palette.background.default
|
||||||
|
),
|
||||||
|
bottom: -11,
|
||||||
|
content: "''",
|
||||||
|
display: "block",
|
||||||
|
height: 2,
|
||||||
|
left: -12,
|
||||||
|
position: "absolute",
|
||||||
|
transform: "scaleX(0) scaleY(0)",
|
||||||
|
width: "calc(100% + 24px)"
|
||||||
|
},
|
||||||
|
position: "relative"
|
||||||
},
|
},
|
||||||
"& .Draftail": {
|
"&-root": {
|
||||||
"&-Editor": {
|
...theme.typography.body1
|
||||||
"&--focus": {
|
}
|
||||||
boxShadow: `inset 0px 0px 0px 2px ${theme.palette.primary.main}`
|
},
|
||||||
},
|
"& .Draftail": {
|
||||||
"&:hover": {
|
"&-Editor": {
|
||||||
borderColor: theme.palette.primary.main
|
"&--focus": {
|
||||||
},
|
boxShadow: `inset 0px 0px 0px 2px ${theme.palette.primary.main}`
|
||||||
border: `1px ${theme.overrides.MuiOutlinedInput.root.borderColor} solid`,
|
|
||||||
borderRadius: 4,
|
|
||||||
padding: "27px 12px 10px",
|
|
||||||
position: "relative",
|
|
||||||
transition: theme.transitions.duration.shortest + "ms"
|
|
||||||
},
|
},
|
||||||
"&-Toolbar": {
|
"&:hover": {
|
||||||
"&Button": {
|
borderColor: theme.palette.primary.main
|
||||||
"& svg": {
|
},
|
||||||
padding: 2
|
border: `1px ${theme.palette.divider} solid`,
|
||||||
},
|
borderRadius: 4,
|
||||||
"&--active": {
|
padding: "27px 12px 10px",
|
||||||
"&:hover": {
|
position: "relative",
|
||||||
background: theme.palette.primary.main
|
transition: theme.transitions.duration.shortest + "ms"
|
||||||
},
|
},
|
||||||
"&:not(:hover)": {
|
"&-Toolbar": {
|
||||||
borderRightColor: theme.palette.primary.main
|
"&Button": {
|
||||||
},
|
"& svg": {
|
||||||
|
padding: 2
|
||||||
|
},
|
||||||
|
"&--active": {
|
||||||
|
"&:hover": {
|
||||||
background: theme.palette.primary.main
|
background: theme.palette.primary.main
|
||||||
},
|
},
|
||||||
"&:focus": {
|
"&:not(:hover)": {
|
||||||
"&:active": {
|
borderRightColor: theme.palette.primary.main
|
||||||
"&:after": {
|
|
||||||
background: fade(theme.palette.primary.main, 0.3),
|
|
||||||
borderRadius: "100%",
|
|
||||||
content: "''",
|
|
||||||
display: "block",
|
|
||||||
height: "100%",
|
|
||||||
width: "100%"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"&:hover": {
|
background: theme.palette.primary.main
|
||||||
background: fade(theme.palette.primary.main, 0.3)
|
|
||||||
},
|
|
||||||
alignItems: "center",
|
|
||||||
background: "none",
|
|
||||||
border: "none",
|
|
||||||
borderRight: `1px ${theme.overrides.MuiCard.root.borderColor} solid`,
|
|
||||||
color: theme.typography.body1.color,
|
|
||||||
cursor: "pointer",
|
|
||||||
display: "inline-flex",
|
|
||||||
height: 36,
|
|
||||||
justifyContent: "center",
|
|
||||||
padding: theme.spacing(1) + 2,
|
|
||||||
transition: theme.transitions.duration.short + "ms",
|
|
||||||
width: 36
|
|
||||||
},
|
},
|
||||||
"&Group": {
|
"&:focus": {
|
||||||
"&:last-of-type": {
|
"&:active": {
|
||||||
"& .Draftail-ToolbarButton": {
|
"&:after": {
|
||||||
"&:last-of-type": {
|
background: fade(theme.palette.primary.main, 0.3),
|
||||||
border: "none"
|
borderRadius: "100%",
|
||||||
}
|
content: "''",
|
||||||
|
display: "block",
|
||||||
|
height: "100%",
|
||||||
|
width: "100%"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
display: "flex"
|
|
||||||
},
|
},
|
||||||
background: theme.palette.background.default,
|
"&:hover": {
|
||||||
border: `1px ${theme.overrides.MuiCard.root.borderColor} solid`,
|
background: fade(theme.palette.primary.main, 0.3)
|
||||||
|
},
|
||||||
|
alignItems: "center",
|
||||||
|
background: "none",
|
||||||
|
border: "none",
|
||||||
|
borderRight: `1px ${theme.palette.divider} solid`,
|
||||||
|
color: theme.typography.body1.color,
|
||||||
|
cursor: "pointer",
|
||||||
display: "inline-flex",
|
display: "inline-flex",
|
||||||
flexWrap: "wrap",
|
height: 36,
|
||||||
marginBottom: theme.spacing(),
|
justifyContent: "center",
|
||||||
marginTop: 10,
|
padding: theme.spacing(1) + 2,
|
||||||
[theme.breakpoints.down(460)]: {
|
transition: theme.transitions.duration.short + "ms",
|
||||||
width: "min-content"
|
width: 36
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"&-block": {
|
"&Group": {
|
||||||
"&--blockquote": {
|
"&:last-of-type": {
|
||||||
borderLeft: `2px solid ${theme.overrides.MuiCard.root.borderColor}`,
|
"& .Draftail-ToolbarButton": {
|
||||||
margin: 0,
|
"&:last-of-type": {
|
||||||
padding: theme.spacing(1, 2)
|
border: "none"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
display: "flex"
|
||||||
|
},
|
||||||
|
background: theme.palette.background.default,
|
||||||
|
border: `1px ${theme.palette.divider} solid`,
|
||||||
|
display: "inline-flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
marginBottom: theme.spacing(),
|
||||||
|
marginTop: 10,
|
||||||
|
[theme.breakpoints.down(460)]: {
|
||||||
|
width: "min-content"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"&$error": {
|
"&-block": {
|
||||||
"& .Draftail": {
|
"&--blockquote": {
|
||||||
"&-Editor": {
|
borderLeft: `2px solid ${theme.palette.divider}`,
|
||||||
borderColor: theme.palette.error.main
|
margin: 0,
|
||||||
}
|
padding: theme.spacing(1, 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scroll: {
|
"&$error": {
|
||||||
"& .DraftEditor": {
|
"& .Draftail": {
|
||||||
"&-editorContainer": {
|
"&-Editor": {
|
||||||
"& .public-DraftEditor-content": {
|
borderColor: theme.palette.error.main
|
||||||
lineHeight: 1.62
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
smallIcon: {
|
|
||||||
marginLeft: 10
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
scroll: {
|
||||||
|
"& .DraftEditor": {
|
||||||
|
"&-editorContainer": {
|
||||||
|
"& .public-DraftEditor-content": {
|
||||||
|
lineHeight: 1.62
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
smallIcon: {
|
||||||
|
marginLeft: 10
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
function handleSave(
|
function handleSave(
|
||||||
value: any,
|
value: any,
|
||||||
|
@ -215,17 +209,12 @@ function handleSave(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const RichTextEditor = withStyles(styles, { name: "RichTextEditor" })(
|
const RichTextEditor: React.FC<RichTextEditorProps> = props => {
|
||||||
({
|
const { error, helperText, initial, label, name, scroll, onChange } = props;
|
||||||
classes,
|
|
||||||
error,
|
const classes = useStyles(props);
|
||||||
helperText,
|
|
||||||
initial,
|
return (
|
||||||
label,
|
|
||||||
name,
|
|
||||||
scroll,
|
|
||||||
onChange
|
|
||||||
}: RichTextEditorProps & WithStyles<typeof styles>) => (
|
|
||||||
<div
|
<div
|
||||||
className={classNames({
|
className={classNames({
|
||||||
[classes.error]: error,
|
[classes.error]: error,
|
||||||
|
@ -302,8 +291,9 @@ const RichTextEditor = withStyles(styles, { name: "RichTextEditor" })(
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
|
|
||||||
RichTextEditor.displayName = "RichTextEditor";
|
RichTextEditor.displayName = "RichTextEditor";
|
||||||
RichTextEditor.defaultProps = {
|
RichTextEditor.defaultProps = {
|
||||||
scroll: true
|
scroll: true
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './RichTextEditor';
|
export { default } from "./RichTextEditor";
|
||||||
export * from './RichTextEditor';
|
export * from "./RichTextEditor";
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
import Portal from "@material-ui/core/Portal";
|
import Portal from "@material-ui/core/Portal";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
@ -19,48 +14,47 @@ import ConfirmButton, {
|
||||||
} from "../ConfirmButton/ConfirmButton";
|
} from "../ConfirmButton/ConfirmButton";
|
||||||
import Container from "../Container";
|
import Container from "../Container";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
button: {
|
||||||
button: {
|
marginRight: theme.spacing(1)
|
||||||
marginRight: theme.spacing(1)
|
},
|
||||||
},
|
cancelButton: {
|
||||||
cancelButton: {
|
marginRight: theme.spacing(2)
|
||||||
marginRight: theme.spacing(2)
|
},
|
||||||
},
|
container: {
|
||||||
container: {
|
display: "flex",
|
||||||
display: "flex",
|
paddingBottom: theme.spacing(2),
|
||||||
paddingBottom: theme.spacing(2),
|
paddingTop: theme.spacing(2),
|
||||||
paddingTop: theme.spacing(2),
|
[theme.breakpoints.down("sm")]: {
|
||||||
[theme.breakpoints.down("sm")]: {
|
marginTop: theme.spacing(1)
|
||||||
marginTop: theme.spacing(1)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deleteButton: {
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: theme.palette.error.dark
|
|
||||||
},
|
|
||||||
backgroundColor: theme.palette.error.main,
|
|
||||||
color: theme.palette.error.contrastText
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
background: theme.palette.background.default,
|
|
||||||
borderTop: "1px solid transparent",
|
|
||||||
boxShadow: `0 -5px 5px 0 ${theme.overrides.MuiCard.root.borderColor}`,
|
|
||||||
height: "100%",
|
|
||||||
transition: `box-shadow ${theme.transitions.duration.shortest}ms`
|
|
||||||
},
|
|
||||||
spacer: {
|
|
||||||
flex: "1"
|
|
||||||
},
|
|
||||||
stop: {
|
|
||||||
"&$root": {
|
|
||||||
borderTopColor: theme.overrides.MuiCard.root.borderColor,
|
|
||||||
boxShadow: `0 0 0 0 ${theme.overrides.MuiCard.root.borderColor}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
deleteButton: {
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.error.dark
|
||||||
|
},
|
||||||
|
backgroundColor: theme.palette.error.main,
|
||||||
|
color: theme.palette.error.contrastText
|
||||||
|
},
|
||||||
|
root: {
|
||||||
|
background: theme.palette.background.default,
|
||||||
|
borderTop: "1px solid transparent",
|
||||||
|
boxShadow: `0 -5px 5px 0 ${theme.palette.divider}`,
|
||||||
|
height: "100%",
|
||||||
|
transition: `box-shadow ${theme.transitions.duration.shortest}ms`
|
||||||
|
},
|
||||||
|
spacer: {
|
||||||
|
flex: "1"
|
||||||
|
},
|
||||||
|
stop: {
|
||||||
|
"&$root": {
|
||||||
|
borderTopColor: theme.palette.divider,
|
||||||
|
boxShadow: `0 0 0 0 ${theme.palette.divider}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
interface SaveButtonBarProps extends WithStyles<typeof styles> {
|
interface SaveButtonBarProps {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
state: ConfirmButtonTransitionState;
|
state: ConfirmButtonTransitionState;
|
||||||
labels?: {
|
labels?: {
|
||||||
|
@ -73,77 +67,77 @@ interface SaveButtonBarProps extends WithStyles<typeof styles> {
|
||||||
onSave(event: any);
|
onSave(event: any);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SaveButtonBar = withStyles(styles, { name: "SaveButtonBar" })(
|
export const SaveButtonBar: React.FC<SaveButtonBarProps> = props => {
|
||||||
({
|
const {
|
||||||
classes,
|
|
||||||
disabled,
|
disabled,
|
||||||
labels,
|
labels,
|
||||||
state,
|
state,
|
||||||
onCancel,
|
onCancel,
|
||||||
onDelete,
|
onDelete,
|
||||||
onSave,
|
onSave,
|
||||||
...props
|
...rest
|
||||||
}: SaveButtonBarProps) => {
|
} = props;
|
||||||
const intl = useIntl();
|
const classes = useStyles(props);
|
||||||
const scrollPosition = useWindowScroll();
|
|
||||||
const scrolledToBottom =
|
|
||||||
scrollPosition.y + window.innerHeight >= document.body.scrollHeight;
|
|
||||||
|
|
||||||
return (
|
const intl = useIntl();
|
||||||
<AppActionContext.Consumer>
|
const scrollPosition = useWindowScroll();
|
||||||
{anchor =>
|
const scrolledToBottom =
|
||||||
anchor ? (
|
scrollPosition.y + window.innerHeight >= document.body.scrollHeight;
|
||||||
<Portal container={anchor.current}>
|
|
||||||
<div
|
return (
|
||||||
className={classNames(classes.root, {
|
<AppActionContext.Consumer>
|
||||||
[classes.stop]: scrolledToBottom
|
{anchor =>
|
||||||
})}
|
anchor ? (
|
||||||
{...props}
|
<Portal container={anchor.current}>
|
||||||
>
|
<div
|
||||||
<Container className={classes.container}>
|
className={classNames(classes.root, {
|
||||||
{!!onDelete && (
|
[classes.stop]: scrolledToBottom
|
||||||
<Button
|
})}
|
||||||
variant="contained"
|
{...rest}
|
||||||
onClick={onDelete}
|
>
|
||||||
className={classes.deleteButton}
|
<Container className={classes.container}>
|
||||||
data-tc="button-bar-delete"
|
{!!onDelete && (
|
||||||
>
|
|
||||||
{labels && labels.delete
|
|
||||||
? labels.delete
|
|
||||||
: intl.formatMessage(buttonMessages.delete)}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
<div className={classes.spacer} />
|
|
||||||
<Button
|
<Button
|
||||||
className={classes.cancelButton}
|
variant="contained"
|
||||||
variant="text"
|
onClick={onDelete}
|
||||||
onClick={onCancel}
|
className={classes.deleteButton}
|
||||||
data-tc="button-bar-cancel"
|
data-tc="button-bar-delete"
|
||||||
>
|
>
|
||||||
{maybe(
|
{labels && labels.delete
|
||||||
() => labels.cancel,
|
? labels.delete
|
||||||
intl.formatMessage(buttonMessages.back)
|
: intl.formatMessage(buttonMessages.delete)}
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
<ConfirmButton
|
)}
|
||||||
disabled={disabled}
|
<div className={classes.spacer} />
|
||||||
onClick={onSave}
|
<Button
|
||||||
transitionState={state}
|
className={classes.cancelButton}
|
||||||
data-tc="button-bar-confirm"
|
variant="text"
|
||||||
>
|
onClick={onCancel}
|
||||||
{maybe(
|
data-tc="button-bar-cancel"
|
||||||
() => labels.save,
|
>
|
||||||
intl.formatMessage(buttonMessages.save)
|
{maybe(
|
||||||
)}
|
() => labels.cancel,
|
||||||
</ConfirmButton>
|
intl.formatMessage(buttonMessages.back)
|
||||||
</Container>
|
)}
|
||||||
</div>
|
</Button>
|
||||||
</Portal>
|
<ConfirmButton
|
||||||
) : null
|
disabled={disabled}
|
||||||
}
|
onClick={onSave}
|
||||||
</AppActionContext.Consumer>
|
transitionState={state}
|
||||||
);
|
data-tc="button-bar-confirm"
|
||||||
}
|
>
|
||||||
);
|
{maybe(
|
||||||
|
() => labels.save,
|
||||||
|
intl.formatMessage(buttonMessages.save)
|
||||||
|
)}
|
||||||
|
</ConfirmButton>
|
||||||
|
</Container>
|
||||||
|
</div>
|
||||||
|
</Portal>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
</AppActionContext.Consumer>
|
||||||
|
);
|
||||||
|
};
|
||||||
SaveButtonBar.displayName = "SaveButtonBar";
|
SaveButtonBar.displayName = "SaveButtonBar";
|
||||||
export default SaveButtonBar;
|
export default SaveButtonBar;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './SaveFilterTabDialog';
|
export { default } from "./SaveFilterTabDialog";
|
||||||
export * from './SaveFilterTabDialog';
|
export * from "./SaveFilterTabDialog";
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
import Card from "@material-ui/core/Card";
|
import Card from "@material-ui/core/Card";
|
||||||
import CardContent from "@material-ui/core/CardContent";
|
import CardContent from "@material-ui/core/CardContent";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -16,55 +11,54 @@ import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import CardTitle from "../CardTitle";
|
import CardTitle from "../CardTitle";
|
||||||
import FormSpacer from "../FormSpacer";
|
import FormSpacer from "../FormSpacer";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
addressBar: {
|
||||||
addressBar: {
|
color: "#006621",
|
||||||
color: "#006621",
|
fontSize: "13px",
|
||||||
fontSize: "13px",
|
lineHeight: "16px",
|
||||||
lineHeight: "16px",
|
marginBottom: "2px",
|
||||||
marginBottom: "2px",
|
overflow: "hidden",
|
||||||
overflow: "hidden",
|
textOverflow: "ellipsis",
|
||||||
textOverflow: "ellipsis",
|
whiteSpace: "nowrap"
|
||||||
whiteSpace: "nowrap"
|
},
|
||||||
|
container: {
|
||||||
|
width: "100%"
|
||||||
|
},
|
||||||
|
descriptionBar: {
|
||||||
|
color: "#545454",
|
||||||
|
fontSize: "13px",
|
||||||
|
lineHeight: "18px",
|
||||||
|
overflowWrap: "break-word"
|
||||||
|
},
|
||||||
|
helperText: {
|
||||||
|
marginBottom: theme.spacing(3)
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
flex: 1
|
||||||
|
},
|
||||||
|
labelContainer: {
|
||||||
|
"& span": {
|
||||||
|
paddingRight: 30
|
||||||
},
|
},
|
||||||
container: {
|
display: "flex"
|
||||||
width: "100%"
|
},
|
||||||
},
|
preview: {
|
||||||
descriptionBar: {
|
minHeight: theme.spacing(10)
|
||||||
color: "#545454",
|
},
|
||||||
fontSize: "13px",
|
title: {
|
||||||
lineHeight: "18px",
|
padding: 0
|
||||||
overflowWrap: "break-word"
|
},
|
||||||
},
|
titleBar: {
|
||||||
helperText: {
|
color: "#1a0dab",
|
||||||
marginBottom: theme.spacing(3)
|
fontSize: "18px",
|
||||||
},
|
lineHeight: "21px",
|
||||||
label: {
|
overflowWrap: "break-word",
|
||||||
flex: 1
|
textDecoration: "none",
|
||||||
},
|
wordWrap: "break-word"
|
||||||
labelContainer: {
|
}
|
||||||
"& span": {
|
}));
|
||||||
paddingRight: 30
|
|
||||||
},
|
|
||||||
display: "flex"
|
|
||||||
},
|
|
||||||
preview: {
|
|
||||||
minHeight: theme.spacing(10)
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
padding: 0
|
|
||||||
},
|
|
||||||
titleBar: {
|
|
||||||
color: "#1a0dab",
|
|
||||||
fontSize: "18px",
|
|
||||||
lineHeight: "21px",
|
|
||||||
overflowWrap: "break-word",
|
|
||||||
textDecoration: "none",
|
|
||||||
wordWrap: "break-word"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
interface SeoFormProps extends WithStyles<typeof styles> {
|
interface SeoFormProps {
|
||||||
description?: string;
|
description?: string;
|
||||||
descriptionPlaceholder: string;
|
descriptionPlaceholder: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
@ -76,9 +70,8 @@ interface SeoFormProps extends WithStyles<typeof styles> {
|
||||||
onClick?();
|
onClick?();
|
||||||
}
|
}
|
||||||
|
|
||||||
const SeoForm = withStyles(styles, { name: "SeoForm" })(
|
const SeoForm: React.FC<SeoFormProps> = props => {
|
||||||
({
|
const {
|
||||||
classes,
|
|
||||||
description,
|
description,
|
||||||
descriptionPlaceholder,
|
descriptionPlaceholder,
|
||||||
disabled,
|
disabled,
|
||||||
|
@ -87,107 +80,108 @@ const SeoForm = withStyles(styles, { name: "SeoForm" })(
|
||||||
title,
|
title,
|
||||||
titlePlaceholder,
|
titlePlaceholder,
|
||||||
onChange
|
onChange
|
||||||
}: SeoFormProps) => {
|
} = props;
|
||||||
const intl = useIntl();
|
const classes = useStyles(props);
|
||||||
const [expanded, setExpansionStatus] = React.useState(false);
|
|
||||||
const toggleExpansion = () => setExpansionStatus(!expanded);
|
|
||||||
|
|
||||||
return (
|
const intl = useIntl();
|
||||||
<Card>
|
const [expanded, setExpansionStatus] = React.useState(false);
|
||||||
<CardTitle
|
const toggleExpansion = () => setExpansionStatus(!expanded);
|
||||||
title={intl.formatMessage({
|
|
||||||
defaultMessage: "Search Engine Preview"
|
return (
|
||||||
})}
|
<Card>
|
||||||
toolbar={
|
<CardTitle
|
||||||
<Button color="primary" variant="text" onClick={toggleExpansion}>
|
title={intl.formatMessage({
|
||||||
<FormattedMessage
|
defaultMessage: "Search Engine Preview"
|
||||||
defaultMessage="Edit website SEO"
|
})}
|
||||||
description="button"
|
toolbar={
|
||||||
/>
|
<Button color="primary" variant="text" onClick={toggleExpansion}>
|
||||||
</Button>
|
<FormattedMessage
|
||||||
}
|
defaultMessage="Edit website SEO"
|
||||||
/>
|
description="button"
|
||||||
<CardContent>
|
/>
|
||||||
{helperText && (
|
</Button>
|
||||||
<Typography
|
}
|
||||||
className={classNames({ [classes.helperText]: expanded })}
|
/>
|
||||||
>
|
<CardContent>
|
||||||
{helperText}
|
{helperText && (
|
||||||
</Typography>
|
<Typography
|
||||||
)}
|
className={classNames({ [classes.helperText]: expanded })}
|
||||||
{expanded && (
|
>
|
||||||
<div className={classes.container}>
|
{helperText}
|
||||||
<TextField
|
</Typography>
|
||||||
name="seoTitle"
|
)}
|
||||||
label={
|
{expanded && (
|
||||||
<div className={classes.labelContainer}>
|
<div className={classes.container}>
|
||||||
<div className={classes.label}>
|
<TextField
|
||||||
<FormattedMessage defaultMessage="Search engine title" />
|
name="seoTitle"
|
||||||
</div>
|
label={
|
||||||
{title.length > 0 && (
|
<div className={classes.labelContainer}>
|
||||||
<span>
|
<div className={classes.label}>
|
||||||
<FormattedMessage
|
<FormattedMessage defaultMessage="Search engine title" />
|
||||||
defaultMessage="{numberOfCharacters} of {maxCharacters} characters"
|
|
||||||
description="character limit"
|
|
||||||
values={{
|
|
||||||
maxCharacters: 70,
|
|
||||||
numberOfCharacters: title.length
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
{title.length > 0 && (
|
||||||
helperText={intl.formatMessage({
|
<span>
|
||||||
defaultMessage:
|
<FormattedMessage
|
||||||
"If empty, the preview shows what will be autogenerated."
|
defaultMessage="{numberOfCharacters} of {maxCharacters} characters"
|
||||||
})}
|
description="character limit"
|
||||||
value={title.slice(0, 69)}
|
values={{
|
||||||
disabled={loading || disabled}
|
maxCharacters: 70,
|
||||||
placeholder={titlePlaceholder}
|
numberOfCharacters: title.length
|
||||||
onChange={onChange}
|
}}
|
||||||
fullWidth
|
/>
|
||||||
/>
|
</span>
|
||||||
<FormSpacer />
|
)}
|
||||||
<TextField
|
</div>
|
||||||
name="seoDescription"
|
}
|
||||||
label={
|
helperText={intl.formatMessage({
|
||||||
<div className={classes.labelContainer}>
|
defaultMessage:
|
||||||
<div className={classes.label}>
|
"If empty, the preview shows what will be autogenerated."
|
||||||
<FormattedMessage defaultMessage="Search engine description" />
|
})}
|
||||||
</div>
|
value={title.slice(0, 69)}
|
||||||
{description.length > 0 && (
|
disabled={loading || disabled}
|
||||||
<span>
|
placeholder={titlePlaceholder}
|
||||||
<FormattedMessage
|
onChange={onChange}
|
||||||
defaultMessage="{numberOfCharacters} of {maxCharacters} characters"
|
fullWidth
|
||||||
description="character limit"
|
/>
|
||||||
values={{
|
<FormSpacer />
|
||||||
maxCharacters: 300,
|
<TextField
|
||||||
numberOfCharacters: description.length
|
name="seoDescription"
|
||||||
}}
|
label={
|
||||||
/>
|
<div className={classes.labelContainer}>
|
||||||
</span>
|
<div className={classes.label}>
|
||||||
)}
|
<FormattedMessage defaultMessage="Search engine description" />
|
||||||
</div>
|
</div>
|
||||||
}
|
{description.length > 0 && (
|
||||||
helperText={intl.formatMessage({
|
<span>
|
||||||
defaultMessage:
|
<FormattedMessage
|
||||||
"If empty, the preview shows what will be autogenerated."
|
defaultMessage="{numberOfCharacters} of {maxCharacters} characters"
|
||||||
})}
|
description="character limit"
|
||||||
value={description ? description.slice(0, 299) : undefined}
|
values={{
|
||||||
onChange={onChange}
|
maxCharacters: 300,
|
||||||
disabled={loading || disabled}
|
numberOfCharacters: description.length
|
||||||
fullWidth
|
}}
|
||||||
multiline
|
/>
|
||||||
placeholder={descriptionPlaceholder}
|
</span>
|
||||||
rows={10}
|
)}
|
||||||
/>
|
</div>
|
||||||
</div>
|
}
|
||||||
)}
|
helperText={intl.formatMessage({
|
||||||
</CardContent>
|
defaultMessage:
|
||||||
</Card>
|
"If empty, the preview shows what will be autogenerated."
|
||||||
);
|
})}
|
||||||
}
|
value={description ? description.slice(0, 299) : undefined}
|
||||||
);
|
onChange={onChange}
|
||||||
|
disabled={loading || disabled}
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
placeholder={descriptionPlaceholder}
|
||||||
|
rows={10}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
SeoForm.displayName = "SeoForm";
|
SeoForm.displayName = "SeoForm";
|
||||||
export default SeoForm;
|
export default SeoForm;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { InputProps } from "@material-ui/core/Input";
|
import { InputProps } from "@material-ui/core/Input";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import Downshift from "downshift";
|
import Downshift from "downshift";
|
||||||
import { filter } from "fuzzaldrin";
|
import { filter } from "fuzzaldrin";
|
||||||
|
@ -13,7 +13,7 @@ import { FetchMoreProps } from "@saleor/types";
|
||||||
import ArrowDropdownIcon from "../../icons/ArrowDropdown";
|
import ArrowDropdownIcon from "../../icons/ArrowDropdown";
|
||||||
import Debounce, { DebounceProps } from "../Debounce";
|
import Debounce, { DebounceProps } from "../Debounce";
|
||||||
|
|
||||||
const styles = createStyles({
|
const useStyles = makeStyles({
|
||||||
container: {
|
container: {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
position: "relative"
|
position: "relative"
|
||||||
|
@ -42,12 +42,12 @@ const DebounceAutocomplete: React.ComponentType<
|
||||||
DebounceProps<string>
|
DebounceProps<string>
|
||||||
> = Debounce;
|
> = Debounce;
|
||||||
|
|
||||||
const SingleAutocompleteSelectFieldComponent = withStyles(styles, {
|
const SingleAutocompleteSelectFieldComponent: React.FC<
|
||||||
name: "SingleAutocompleteSelectField"
|
SingleAutocompleteSelectFieldProps
|
||||||
})(
|
> = props => {
|
||||||
({
|
const {
|
||||||
choices,
|
choices,
|
||||||
classes,
|
|
||||||
allowCustomValues,
|
allowCustomValues,
|
||||||
disabled,
|
disabled,
|
||||||
displayValue,
|
displayValue,
|
||||||
|
@ -64,110 +64,111 @@ const SingleAutocompleteSelectFieldComponent = withStyles(styles, {
|
||||||
fetchChoices,
|
fetchChoices,
|
||||||
onChange,
|
onChange,
|
||||||
onFetchMore,
|
onFetchMore,
|
||||||
...props
|
...rest
|
||||||
}: SingleAutocompleteSelectFieldProps & WithStyles<typeof styles>) => {
|
} = props;
|
||||||
const [prevDisplayValue] = useStateFromProps(displayValue);
|
const classes = useStyles(props);
|
||||||
|
|
||||||
const handleChange = item =>
|
const [prevDisplayValue] = useStateFromProps(displayValue);
|
||||||
onChange({
|
|
||||||
target: {
|
|
||||||
name,
|
|
||||||
value: item
|
|
||||||
}
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
return (
|
const handleChange = item =>
|
||||||
<DebounceAutocomplete debounceFn={fetchChoices}>
|
onChange({
|
||||||
{debounceFn => (
|
target: {
|
||||||
<Downshift
|
name,
|
||||||
defaultInputValue={displayValue}
|
value: item
|
||||||
itemToString={() => displayValue}
|
}
|
||||||
onInputValueChange={value => debounceFn(value)}
|
} as any);
|
||||||
onSelect={handleChange}
|
|
||||||
selectedItem={value}
|
|
||||||
>
|
|
||||||
{({
|
|
||||||
getInputProps,
|
|
||||||
getItemProps,
|
|
||||||
isOpen,
|
|
||||||
inputValue,
|
|
||||||
selectedItem,
|
|
||||||
toggleMenu,
|
|
||||||
closeMenu,
|
|
||||||
highlightedIndex,
|
|
||||||
reset
|
|
||||||
}) => {
|
|
||||||
const isCustomValueSelected =
|
|
||||||
choices && selectedItem
|
|
||||||
? choices.filter(c => c.value === selectedItem).length === 0
|
|
||||||
: false;
|
|
||||||
const hasInputValueChanged = prevDisplayValue !== displayValue;
|
|
||||||
|
|
||||||
if (hasInputValueChanged) {
|
return (
|
||||||
reset({ inputValue: displayValue });
|
<DebounceAutocomplete debounceFn={fetchChoices}>
|
||||||
}
|
{debounceFn => (
|
||||||
|
<Downshift
|
||||||
|
defaultInputValue={displayValue}
|
||||||
|
itemToString={() => displayValue}
|
||||||
|
onInputValueChange={value => debounceFn(value)}
|
||||||
|
onSelect={handleChange}
|
||||||
|
selectedItem={value}
|
||||||
|
>
|
||||||
|
{({
|
||||||
|
getInputProps,
|
||||||
|
getItemProps,
|
||||||
|
isOpen,
|
||||||
|
inputValue,
|
||||||
|
selectedItem,
|
||||||
|
toggleMenu,
|
||||||
|
closeMenu,
|
||||||
|
highlightedIndex,
|
||||||
|
reset
|
||||||
|
}) => {
|
||||||
|
const isCustomValueSelected =
|
||||||
|
choices && selectedItem
|
||||||
|
? choices.filter(c => c.value === selectedItem).length === 0
|
||||||
|
: false;
|
||||||
|
const hasInputValueChanged = prevDisplayValue !== displayValue;
|
||||||
|
|
||||||
const displayCustomValue =
|
if (hasInputValueChanged) {
|
||||||
inputValue &&
|
reset({ inputValue: displayValue });
|
||||||
inputValue.length > 0 &&
|
}
|
||||||
allowCustomValues &&
|
|
||||||
!choices.find(
|
|
||||||
choice =>
|
|
||||||
choice.label.toLowerCase() === inputValue.toLowerCase()
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
const displayCustomValue =
|
||||||
<div className={classes.container} {...props}>
|
inputValue &&
|
||||||
<TextField
|
inputValue.length > 0 &&
|
||||||
InputProps={{
|
allowCustomValues &&
|
||||||
...InputProps,
|
!choices.find(
|
||||||
...getInputProps({
|
choice =>
|
||||||
placeholder
|
choice.label.toLowerCase() === inputValue.toLowerCase()
|
||||||
}),
|
|
||||||
endAdornment: (
|
|
||||||
<div>
|
|
||||||
<ArrowDropdownIcon />
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
error,
|
|
||||||
id: undefined,
|
|
||||||
onBlur: closeMenu,
|
|
||||||
onClick: toggleMenu
|
|
||||||
}}
|
|
||||||
error={error}
|
|
||||||
disabled={disabled}
|
|
||||||
helperText={helperText}
|
|
||||||
label={label}
|
|
||||||
fullWidth={true}
|
|
||||||
/>
|
|
||||||
{isOpen && (!!inputValue || !!choices.length) && (
|
|
||||||
<SingleAutocompleteSelectFieldContent
|
|
||||||
choices={choices}
|
|
||||||
displayCustomValue={displayCustomValue}
|
|
||||||
emptyOption={emptyOption}
|
|
||||||
getItemProps={getItemProps}
|
|
||||||
hasMore={hasMore}
|
|
||||||
highlightedIndex={highlightedIndex}
|
|
||||||
loading={loading}
|
|
||||||
inputValue={inputValue}
|
|
||||||
isCustomValueSelected={isCustomValueSelected}
|
|
||||||
selectedItem={selectedItem}
|
|
||||||
onFetchMore={onFetchMore}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}}
|
|
||||||
</Downshift>
|
return (
|
||||||
)}
|
<div className={classes.container} {...rest}>
|
||||||
</DebounceAutocomplete>
|
<TextField
|
||||||
);
|
InputProps={{
|
||||||
}
|
...InputProps,
|
||||||
);
|
...getInputProps({
|
||||||
|
placeholder
|
||||||
|
}),
|
||||||
|
endAdornment: (
|
||||||
|
<div>
|
||||||
|
<ArrowDropdownIcon />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
error,
|
||||||
|
id: undefined,
|
||||||
|
onBlur: closeMenu,
|
||||||
|
onClick: toggleMenu
|
||||||
|
}}
|
||||||
|
error={error}
|
||||||
|
disabled={disabled}
|
||||||
|
helperText={helperText}
|
||||||
|
label={label}
|
||||||
|
fullWidth={true}
|
||||||
|
/>
|
||||||
|
{isOpen && (!!inputValue || !!choices.length) && (
|
||||||
|
<SingleAutocompleteSelectFieldContent
|
||||||
|
choices={choices}
|
||||||
|
displayCustomValue={displayCustomValue}
|
||||||
|
emptyOption={emptyOption}
|
||||||
|
getItemProps={getItemProps}
|
||||||
|
hasMore={hasMore}
|
||||||
|
highlightedIndex={highlightedIndex}
|
||||||
|
loading={loading}
|
||||||
|
inputValue={inputValue}
|
||||||
|
isCustomValueSelected={isCustomValueSelected}
|
||||||
|
selectedItem={selectedItem}
|
||||||
|
onFetchMore={onFetchMore}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Downshift>
|
||||||
|
)}
|
||||||
|
</DebounceAutocomplete>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const SingleAutocompleteSelectField: React.FC<
|
const SingleAutocompleteSelectField: React.FC<
|
||||||
SingleAutocompleteSelectFieldProps
|
SingleAutocompleteSelectFieldProps
|
||||||
> = ({ choices, fetchChoices, ...props }) => {
|
> = ({ choices, fetchChoices, ...rest }) => {
|
||||||
const [query, setQuery] = React.useState("");
|
const [query, setQuery] = React.useState("");
|
||||||
if (fetchChoices) {
|
if (fetchChoices) {
|
||||||
return (
|
return (
|
||||||
|
@ -175,7 +176,7 @@ const SingleAutocompleteSelectField: React.FC<
|
||||||
{debounceFn => (
|
{debounceFn => (
|
||||||
<SingleAutocompleteSelectFieldComponent
|
<SingleAutocompleteSelectFieldComponent
|
||||||
choices={choices}
|
choices={choices}
|
||||||
{...props}
|
{...rest}
|
||||||
fetchChoices={debounceFn}
|
fetchChoices={debounceFn}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -189,7 +190,7 @@ const SingleAutocompleteSelectField: React.FC<
|
||||||
choices={filter(choices, query, {
|
choices={filter(choices, query, {
|
||||||
key: "label"
|
key: "label"
|
||||||
})}
|
})}
|
||||||
{...props}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,12 +4,12 @@ import InputLabel from "@material-ui/core/InputLabel";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
import MenuItem from "@material-ui/core/MenuItem";
|
||||||
import OutlinedInput from "@material-ui/core/OutlinedInput";
|
import OutlinedInput from "@material-ui/core/OutlinedInput";
|
||||||
import Select, { SelectProps } from "@material-ui/core/Select";
|
import Select, { SelectProps } from "@material-ui/core/Select";
|
||||||
import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
const styles = createStyles({
|
const useStyles = makeStyles({
|
||||||
formControl: {
|
formControl: {
|
||||||
"& label": {
|
"& label": {
|
||||||
top: "-3px"
|
top: "-3px"
|
||||||
|
@ -18,7 +18,7 @@ const styles = createStyles({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface SingleSelectFieldProps extends WithStyles<typeof styles> {
|
interface SingleSelectFieldProps {
|
||||||
choices: Array<{
|
choices: Array<{
|
||||||
value: string;
|
value: string;
|
||||||
label: string | React.ReactNode;
|
label: string | React.ReactNode;
|
||||||
|
@ -35,12 +35,10 @@ interface SingleSelectFieldProps extends WithStyles<typeof styles> {
|
||||||
onChange(event: any);
|
onChange(event: any);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SingleSelectField = withStyles(styles, {
|
export const SingleSelectField: React.FC<SingleSelectFieldProps> = props => {
|
||||||
name: "SingleSelectField"
|
const {
|
||||||
})(
|
|
||||||
({
|
|
||||||
className,
|
className,
|
||||||
classes,
|
|
||||||
disabled,
|
disabled,
|
||||||
error,
|
error,
|
||||||
label,
|
label,
|
||||||
|
@ -51,49 +49,50 @@ export const SingleSelectField = withStyles(styles, {
|
||||||
hint,
|
hint,
|
||||||
selectProps,
|
selectProps,
|
||||||
placeholder
|
placeholder
|
||||||
}: SingleSelectFieldProps) => {
|
} = props;
|
||||||
const choicesByKey: { [key: string]: string } =
|
const classes = useStyles(props);
|
||||||
choices === undefined
|
|
||||||
? {}
|
|
||||||
: choices.reduce((prev, curr) => {
|
|
||||||
prev[curr.value] = curr.label;
|
|
||||||
return prev;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
return (
|
const choicesByKey: { [key: string]: string } =
|
||||||
<FormControl
|
choices === undefined
|
||||||
className={classNames(classes.formControl, className)}
|
? {}
|
||||||
error={error}
|
: choices.reduce((prev, curr) => {
|
||||||
disabled={disabled}
|
prev[curr.value] = curr.label;
|
||||||
|
return prev;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl
|
||||||
|
className={classNames(classes.formControl, className)}
|
||||||
|
error={error}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
<InputLabel shrink={!!value}>{label}</InputLabel>
|
||||||
|
<Select
|
||||||
|
variant="outlined"
|
||||||
|
fullWidth
|
||||||
|
renderValue={choiceValue =>
|
||||||
|
choiceValue ? choicesByKey[choiceValue.toString()] : placeholder
|
||||||
|
}
|
||||||
|
value={value || ""}
|
||||||
|
onChange={onChange}
|
||||||
|
input={<OutlinedInput name={name} labelWidth={180} />}
|
||||||
|
{...selectProps}
|
||||||
>
|
>
|
||||||
<InputLabel shrink={!!value}>{label}</InputLabel>
|
{choices.length > 0 ? (
|
||||||
<Select
|
choices.map(choice => (
|
||||||
variant="outlined"
|
<MenuItem value={choice.value} key={choice.value}>
|
||||||
fullWidth
|
{choice.label}
|
||||||
renderValue={choiceValue =>
|
|
||||||
choiceValue ? choicesByKey[choiceValue.toString()] : placeholder
|
|
||||||
}
|
|
||||||
value={value || ""}
|
|
||||||
onChange={onChange}
|
|
||||||
input={<OutlinedInput name={name} labelWidth={180} />}
|
|
||||||
{...selectProps}
|
|
||||||
>
|
|
||||||
{choices.length > 0 ? (
|
|
||||||
choices.map(choice => (
|
|
||||||
<MenuItem value={choice.value} key={choice.value}>
|
|
||||||
{choice.label}
|
|
||||||
</MenuItem>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<MenuItem disabled={true}>
|
|
||||||
<FormattedMessage defaultMessage="No results found" />
|
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
))
|
||||||
</Select>
|
) : (
|
||||||
{hint && <FormHelperText>{hint}</FormHelperText>}
|
<MenuItem disabled={true}>
|
||||||
</FormControl>
|
<FormattedMessage defaultMessage="No results found" />
|
||||||
);
|
</MenuItem>
|
||||||
}
|
)}
|
||||||
);
|
</Select>
|
||||||
|
{hint && <FormHelperText>{hint}</FormHelperText>}
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
};
|
||||||
SingleSelectField.displayName = "SingleSelectField";
|
SingleSelectField.displayName = "SingleSelectField";
|
||||||
export default SingleSelectField;
|
export default SingleSelectField;
|
||||||
|
|
|
@ -1,45 +1,43 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
"@keyframes skeleton-animation": {
|
||||||
"@keyframes skeleton-animation": {
|
"0%": {
|
||||||
"0%": {
|
opacity: 0.6
|
||||||
opacity: 0.6
|
|
||||||
},
|
|
||||||
"100%": {
|
|
||||||
opacity: 1
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
primary: {
|
"100%": {
|
||||||
"&$skeleton": {
|
opacity: 1
|
||||||
background: theme.palette.primary.main
|
|
||||||
}
|
|
||||||
},
|
|
||||||
skeleton: {
|
|
||||||
animation: "skeleton-animation .75s linear infinite forwards alternate",
|
|
||||||
background: theme.palette.background.default,
|
|
||||||
borderRadius: 4,
|
|
||||||
display: "block",
|
|
||||||
height: "0.8em",
|
|
||||||
margin: "0.2em 0"
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
primary: {
|
||||||
|
"&$skeleton": {
|
||||||
|
background: theme.palette.primary.main
|
||||||
|
}
|
||||||
|
},
|
||||||
|
skeleton: {
|
||||||
|
animation: "skeleton-animation .75s linear infinite forwards alternate",
|
||||||
|
background: theme.palette.background.default,
|
||||||
|
borderRadius: 4,
|
||||||
|
display: "block",
|
||||||
|
height: "0.8em",
|
||||||
|
margin: "0.2em 0"
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
interface SkeletonProps extends WithStyles<typeof styles> {
|
interface SkeletonProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
primary?: boolean;
|
primary?: boolean;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Skeleton = withStyles(styles, { name: "Skeleton" })(
|
const Skeleton: React.FC<SkeletonProps> = props => {
|
||||||
({ className, classes, primary, style }: SkeletonProps) => (
|
const { className, primary, style } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<span
|
<span
|
||||||
className={classNames(classes.skeleton, className, {
|
className={classNames(classes.skeleton, className, {
|
||||||
[classes.primary]: primary
|
[classes.primary]: primary
|
||||||
|
@ -48,8 +46,8 @@ const Skeleton = withStyles(styles, { name: "Skeleton" })(
|
||||||
>
|
>
|
||||||
‌
|
‌
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
|
|
||||||
Skeleton.displayName = "Skeleton";
|
Skeleton.displayName = "Skeleton";
|
||||||
export default Skeleton;
|
export default Skeleton;
|
||||||
|
|
|
@ -20,13 +20,14 @@ const useStyles = makeStyles(theme => ({
|
||||||
},
|
},
|
||||||
background: theme.palette.background.paper,
|
background: theme.palette.background.paper,
|
||||||
fontFamily: theme.typography.fontFamily,
|
fontFamily: theme.typography.fontFamily,
|
||||||
fontSize: theme.overrides.MuiTableCell.root.fontSize,
|
// FIXME: you damn know what
|
||||||
|
// fontSize: theme.overrides.MuiTableCell.root.fontSize,
|
||||||
opacity: 0.5
|
opacity: 0.5
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const SortableTableBody: React.FC<
|
const SortableTableBody: React.FC<
|
||||||
TableBodyProps & SortableTableBodyProps
|
Omit<TableBodyProps & SortableTableBodyProps, "ref">
|
||||||
> = props => {
|
> = props => {
|
||||||
const classes = useStyles({});
|
const classes = useStyles({});
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
import yellow from "@material-ui/core/colors/yellow";
|
import yellow from "@material-ui/core/colors/yellow";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Typography, { TypographyProps } from "@material-ui/core/Typography";
|
import Typography, { TypographyProps } from "@material-ui/core/Typography";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme => {
|
const useStyles = makeStyles(theme => {
|
||||||
const dot = {
|
const dot = {
|
||||||
borderRadius: "100%",
|
borderRadius: "100%",
|
||||||
content: "''",
|
content: "''",
|
||||||
|
@ -20,7 +15,8 @@ const styles = theme => {
|
||||||
top: "calc(50% - 5px)",
|
top: "calc(50% - 5px)",
|
||||||
width: 8
|
width: 8
|
||||||
};
|
};
|
||||||
return createStyles({
|
|
||||||
|
return {
|
||||||
errorDot: {
|
errorDot: {
|
||||||
"&:before": { backgroundColor: theme.palette.error.main, ...dot }
|
"&:before": { backgroundColor: theme.palette.error.main, ...dot }
|
||||||
},
|
},
|
||||||
|
@ -38,24 +34,22 @@ const styles = theme => {
|
||||||
successDot: {
|
successDot: {
|
||||||
"&:before": { backgroundColor: theme.palette.primary.main, ...dot }
|
"&:before": { backgroundColor: theme.palette.primary.main, ...dot }
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
};
|
});
|
||||||
|
|
||||||
interface StatusLabelProps extends WithStyles<typeof styles> {
|
interface StatusLabelProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
label: string | React.ReactNode;
|
label: string | React.ReactNode;
|
||||||
status: "success" | "neutral" | "error" | string;
|
status: "success" | "neutral" | "error" | string;
|
||||||
typographyProps?: TypographyProps;
|
typographyProps?: TypographyProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatusLabel = withStyles(styles, { name: "StatusLabel" })(
|
const StatusLabel: React.FC<StatusLabelProps> = props => {
|
||||||
({
|
const { className, label, status, typographyProps } = props;
|
||||||
classes,
|
|
||||||
className,
|
const classes = useStyles(props);
|
||||||
label,
|
|
||||||
status,
|
return (
|
||||||
typographyProps
|
|
||||||
}: StatusLabelProps) => (
|
|
||||||
<div
|
<div
|
||||||
className={classNames({
|
className={classNames({
|
||||||
[classes.root]: true,
|
[classes.root]: true,
|
||||||
|
@ -77,7 +71,7 @@ const StatusLabel = withStyles(styles, { name: "StatusLabel" })(
|
||||||
label
|
label
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
StatusLabel.displayName = "StatusLabel";
|
StatusLabel.displayName = "StatusLabel";
|
||||||
export default StatusLabel;
|
export default StatusLabel;
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(
|
||||||
createStyles({
|
theme => ({
|
||||||
active: {
|
active: {
|
||||||
color: theme.typography.caption.color
|
color: theme.typography.caption.color
|
||||||
},
|
},
|
||||||
|
@ -35,17 +30,23 @@ const styles = theme =>
|
||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
transition: theme.transitions.duration.short + "ms"
|
transition: theme.transitions.duration.short + "ms"
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
{ name: "Tab" }
|
||||||
|
);
|
||||||
|
|
||||||
interface TabProps<T> extends WithStyles<typeof styles> {
|
interface TabProps<T> {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
changeTab: (index: T) => void;
|
changeTab: (index: T) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Tab<T>(value: T) {
|
export function Tab<T>(value: T) {
|
||||||
return withStyles(styles, { name: "Tab" })(
|
const Component: React.FC<TabProps<T>> = props => {
|
||||||
({ classes, children, isActive, changeTab }: TabProps<T>) => (
|
const { children, isActive, changeTab } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<Typography
|
<Typography
|
||||||
component="span"
|
component="span"
|
||||||
className={classNames({
|
className={classNames({
|
||||||
|
@ -56,8 +57,10 @@ export function Tab<T>(value: T) {
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Typography>
|
</Typography>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
|
|
||||||
|
return Component;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Tab;
|
export default Tab;
|
||||||
|
|
|
@ -1,27 +1,23 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export interface TabContainerProps {
|
export interface TabContainerProps {
|
||||||
children: React.ReactNode | React.ReactNodeArray;
|
children: React.ReactNode | React.ReactNodeArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
root: {
|
||||||
root: {
|
borderBottom: `1px solid ${theme.palette.divider}`
|
||||||
borderBottom: `1px solid ${theme.overrides.MuiCard.root.borderColor}`
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
const TabContainer = withStyles(styles, {
|
const TabContainer: React.FC<TabContainerProps> = props => {
|
||||||
name: "TabContainer"
|
const { children } = props;
|
||||||
})(({ classes, children }: TabContainerProps & WithStyles<typeof styles>) => (
|
|
||||||
<div className={classes.root}>{children}</div>
|
const classes = useStyles(props);
|
||||||
));
|
|
||||||
|
return <div className={classes.root}>{children}</div>;
|
||||||
|
};
|
||||||
TabContainer.displayName = "TabContainer";
|
TabContainer.displayName = "TabContainer";
|
||||||
|
|
||||||
export default TabContainer;
|
export default TabContainer;
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export interface TabsProps {
|
export interface TabsProps {
|
||||||
children: (
|
children: (props: {
|
||||||
props: {
|
changeTab: (index: number) => void;
|
||||||
changeTab: (index: number) => void;
|
currentTab: number;
|
||||||
currentTab: number;
|
}) => React.ReactNode;
|
||||||
}
|
|
||||||
) => React.ReactNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TabsState {
|
interface TabsState {
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
import Avatar from "@material-ui/core/Avatar";
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell";
|
||||||
import Cached from "@material-ui/icons/Cached";
|
import Cached from "@material-ui/icons/Cached";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -14,48 +9,44 @@ import Image from "../../icons/Image";
|
||||||
|
|
||||||
export const AVATAR_MARGIN = 56;
|
export const AVATAR_MARGIN = 56;
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
avatar: {
|
||||||
avatar: {
|
background: "none",
|
||||||
background: "none",
|
border: `1px solid ${theme.palette}`,
|
||||||
border: `1px solid ${theme.overrides.MuiCard.root.borderColor}`,
|
borderRadius: 2,
|
||||||
borderRadius: 2,
|
color: "#bdbdbd",
|
||||||
color: "#bdbdbd",
|
display: "inline-flex",
|
||||||
display: "inline-flex",
|
padding: theme.spacing(0.5)
|
||||||
padding: theme.spacing(.5)
|
},
|
||||||
},
|
children: {
|
||||||
children: {
|
alignSelf: "center",
|
||||||
alignSelf: "center",
|
marginLeft: theme.spacing(2),
|
||||||
marginLeft: theme.spacing(2),
|
width: "100%"
|
||||||
width: "100%"
|
},
|
||||||
},
|
content: {
|
||||||
content: {
|
alignItems: "center",
|
||||||
alignItems: "center",
|
display: "flex"
|
||||||
display: "flex"
|
},
|
||||||
},
|
root: {
|
||||||
root: {
|
paddingRight: theme.spacing(3),
|
||||||
paddingRight: theme.spacing(3),
|
width: "1%"
|
||||||
width: "1%"
|
}
|
||||||
}
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
interface TableCellAvatarProps extends WithStyles<typeof styles> {
|
interface TableCellAvatarProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
thumbnail?: string;
|
thumbnail?: string;
|
||||||
avatarProps?: string;
|
avatarProps?: string;
|
||||||
children?: React.ReactNode | React.ReactNodeArray;
|
children?: React.ReactNode | React.ReactNodeArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TableCellAvatar = withStyles(styles, { name: "TableCellAvatar" })(
|
const TableCellAvatar: React.FC<TableCellAvatarProps> = props => {
|
||||||
({
|
const { children, className, thumbnail, avatarProps, ...rest } = props;
|
||||||
classes,
|
|
||||||
children,
|
const classes = useStyles(props);
|
||||||
className,
|
|
||||||
thumbnail,
|
return (
|
||||||
avatarProps,
|
<TableCell className={classNames(classes.root, className)} {...rest}>
|
||||||
...props
|
|
||||||
}: TableCellAvatarProps) => (
|
|
||||||
<TableCell className={classNames(classes.root, className)} {...props}>
|
|
||||||
<div className={classes.content}>
|
<div className={classes.content}>
|
||||||
{thumbnail === undefined ? (
|
{thumbnail === undefined ? (
|
||||||
<Avatar className={classNames(classes.avatar, avatarProps)}>
|
<Avatar className={classNames(classes.avatar, avatarProps)}>
|
||||||
|
@ -74,7 +65,7 @@ const TableCellAvatar = withStyles(styles, { name: "TableCellAvatar" })(
|
||||||
<div className={classes.children}>{children}</div>
|
<div className={classes.children}>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
TableCellAvatar.displayName = "TableCellAvatar";
|
TableCellAvatar.displayName = "TableCellAvatar";
|
||||||
export default TableCellAvatar;
|
export default TableCellAvatar;
|
||||||
|
|
|
@ -6,7 +6,6 @@ import ClearIcon from "@material-ui/icons/Clear";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import Filter from "../Filter";
|
|
||||||
import FilterActions, { FilterActionsProps } from "../Filter/FilterActions";
|
import FilterActions, { FilterActionsProps } from "../Filter/FilterActions";
|
||||||
import Hr from "../Hr";
|
import Hr from "../Hr";
|
||||||
import Link from "../Link";
|
import Link from "../Link";
|
||||||
|
|
|
@ -1,45 +1,43 @@
|
||||||
import {
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
createStyles,
|
|
||||||
Theme,
|
|
||||||
withStyles,
|
|
||||||
WithStyles
|
|
||||||
} from "@material-ui/core/styles";
|
|
||||||
import Tab from "@material-ui/core/Tab";
|
import Tab from "@material-ui/core/Tab";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const styles = theme =>
|
const useStyles = makeStyles(theme => ({
|
||||||
createStyles({
|
selectedTabLabel: {
|
||||||
selectedTabLabel: {
|
"&$tabLabel": {
|
||||||
"&$tabLabel": {
|
color: theme.typography.body1.color
|
||||||
color: theme.typography.body1.color
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tabLabel: {
|
|
||||||
"&:hover": {
|
|
||||||
color: theme.typography.body1.color
|
|
||||||
},
|
|
||||||
color: theme.typography.caption.color,
|
|
||||||
fontSize: "1rem",
|
|
||||||
fontWeight: 400
|
|
||||||
},
|
|
||||||
tabRoot: {
|
|
||||||
minWidth: "80px",
|
|
||||||
opacity: 1,
|
|
||||||
paddingTop: theme.spacing(1),
|
|
||||||
textTransform: "initial" as "initial"
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
tabLabel: {
|
||||||
|
"&:hover": {
|
||||||
|
color: theme.typography.body1.color
|
||||||
|
},
|
||||||
|
color: theme.typography.caption.color,
|
||||||
|
fontSize: "1rem",
|
||||||
|
fontWeight: 400
|
||||||
|
},
|
||||||
|
tabRoot: {
|
||||||
|
minWidth: "80px",
|
||||||
|
opacity: 1,
|
||||||
|
paddingTop: theme.spacing(1),
|
||||||
|
textTransform: "initial" as "initial"
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
interface FilterTabProps extends WithStyles<typeof styles> {
|
interface FilterTabProps {
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
label: string;
|
label: string;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
value?: number;
|
value?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FilterTab = withStyles(styles, { name: "FilterTab" })(
|
export const FilterTab: React.FC<FilterTabProps> = props => {
|
||||||
({ classes, onClick, label, selected, value }: FilterTabProps) => (
|
const { onClick, label, selected, value } = props;
|
||||||
|
|
||||||
|
const classes = useStyles(props);
|
||||||
|
|
||||||
|
return (
|
||||||
<Tab
|
<Tab
|
||||||
disableRipple
|
disableRipple
|
||||||
label={label}
|
label={label}
|
||||||
|
@ -52,7 +50,7 @@ export const FilterTab = withStyles(styles, { name: "FilterTab" })(
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
value={value}
|
value={value}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
);
|
};
|
||||||
FilterTab.displayName = "FilterTab";
|
FilterTab.displayName = "FilterTab";
|
||||||
export default FilterTab;
|
export default FilterTab;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue