Update @material-ui to v4

This commit is contained in:
dominik-zeglen 2019-10-30 15:34:24 +01:00
parent d84ba84e91
commit 74d6794679
276 changed files with 13094 additions and 13943 deletions

6
package-lock.json generated
View file

@ -20308,9 +20308,9 @@
"dev": true
},
"typescript": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
"integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g=="
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.2.tgz",
"integrity": "sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ=="
},
"ua-parser-js": {
"version": "0.7.20",

View file

@ -62,7 +62,7 @@
"react-sortable-tree": "^2.6.2",
"react-svg": "^2.2.11",
"slugify": "^1.3.4",
"typescript": "^3.5.3",
"typescript": "^3.6.4",
"url-join": "^4.0.1",
"use-react-router": "^1.0.7"
},

View file

@ -1,2 +1,2 @@
export { default } from './AttributeBulkDeleteDialog';
export * from './AttributeBulkDeleteDialog';
export { default } from "./AttributeBulkDeleteDialog";
export * from "./AttributeBulkDeleteDialog";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeDeleteDialog';
export * from './AttributeDeleteDialog';
export { default } from "./AttributeDeleteDialog";
export * from "./AttributeDeleteDialog";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeDetails';
export * from './AttributeDetails';
export { default } from "./AttributeDetails";
export * from "./AttributeDetails";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeList';
export * from './AttributeList';
export { default } from "./AttributeList";
export * from "./AttributeList";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeListPage';
export * from './AttributeListPage';
export { default } from "./AttributeListPage";
export * from "./AttributeListPage";

View file

@ -1,2 +1,2 @@
export { default } from './AttributePage';
export * from './AttributePage';
export { default } from "./AttributePage";
export * from "./AttributePage";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeProperties';
export * from './AttributeProperties';
export { default } from "./AttributeProperties";
export * from "./AttributeProperties";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeValueDeleteDialog';
export * from './AttributeValueDeleteDialog';
export { default } from "./AttributeValueDeleteDialog";
export * from "./AttributeValueDeleteDialog";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeValueEditDialog';
export * from './AttributeValueEditDialog';
export { default } from "./AttributeValueEditDialog";
export * from "./AttributeValueEditDialog";

View file

@ -1,2 +1,2 @@
export { default } from './AttributeValues';
export * from './AttributeValues';
export { default } from "./AttributeValues";
export * from "./AttributeValues";

View file

@ -12,12 +12,12 @@ import {
export const PRODUCT_FILTERS_KEY = "productFilters";
export function getFilterVariables(
params: AttributeListUrlFilters
): AttributeFilterInput {
return {
search: params.query
};
}
params: AttributeListUrlFilters
): AttributeFilterInput {
return {
search: params.query
};
}
export const {
deleteFilterTab,

View file

@ -1,21 +1,26 @@
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";
const styles = createStyles({
root: {
alignItems: "center",
display: "flex",
height: "100vh",
justifyContent: "center"
}
});
const LoginLoading = withStyles(styles, { name: "LoginLoading" })(
({ classes }: WithStyles<typeof styles>) => (
const useStyles = makeStyles(
{
root: {
alignItems: "center",
display: "flex",
height: "100vh",
justifyContent: "center"
}
},
{ name: "LoginLoading" }
);
const LoginLoading: React.FC = props => {
const classes = useStyles(props);
return (
<div className={classes.root}>
<CircularProgress size={128} />
</div>
)
);
);
};
LoginLoading.displayName = "LoginLoading";
export default LoginLoading;

View file

@ -1,10 +1,5 @@
import Button from "@material-ui/core/Button";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography";
import React from "react";
@ -19,8 +14,8 @@ export interface FormData {
password: string;
}
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
buttonContainer: {
display: "flex",
justifyContent: "flex-end"
@ -42,89 +37,86 @@ const styles = theme =>
marginBottom: theme.spacing(3),
padding: theme.spacing(1.5)
}
});
}),
{ name: "LoginCard" }
);
export interface LoginCardProps extends WithStyles<typeof styles> {
export interface LoginCardProps {
error: boolean;
disableLoginButton: boolean;
onPasswordRecovery: () => void;
onSubmit?(event: FormData);
}
const LoginCard = withStyles(styles, { name: "LoginCard" })(
({
classes,
error,
disableLoginButton,
onPasswordRecovery,
onSubmit
}: LoginCardProps) => {
const intl = useIntl();
const LoginCard: React.FC<LoginCardProps> = props => {
const { error, disableLoginButton, onPasswordRecovery, onSubmit } = props;
return (
<Form initial={{ email: "", password: "" }} onSubmit={onSubmit}>
{({ change: handleChange, data, submit: handleSubmit }) => (
<>
{error && (
<div className={classes.panel}>
<Typography variant="caption">
<FormattedMessage defaultMessage="Sorry, your username and/or password are incorrect. Please try again." />
</Typography>
</div>
)}
<TextField
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>
const classes = useStyles(props);
const intl = useIntl();
return (
<Form initial={{ email: "", password: "" }} onSubmit={onSubmit}>
{({ change: handleChange, data, submit: handleSubmit }) => (
<>
{error && (
<div className={classes.panel}>
<Typography variant="caption">
<FormattedMessage defaultMessage="Sorry, your username and/or password are incorrect. Please try again." />
</Typography>
</div>
<FormSpacer />
<Typography className={classes.link} onClick={onPasswordRecovery}>
<FormattedMessage
defaultMessage="Reset your password"
description="button"
/>
</Typography>
</>
)}
</Form>
);
}
);
)}
<TextField
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>
<FormSpacer />
<Typography className={classes.link} onClick={onPasswordRecovery}>
<FormattedMessage
defaultMessage="Reset your password"
description="button"
/>
</Typography>
</>
)}
</Form>
);
};
LoginCard.displayName = "LoginCard";
export default LoginCard;

View file

@ -1,4 +1,4 @@
import { PermissionEnum } from '../types/globalTypes'
import { PermissionEnum } from "../types/globalTypes";
import { User } from "./types/User";
export const hasPermission = (permission: PermissionEnum, user: User) =>

View file

@ -4,19 +4,14 @@ import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import DialogTitle from "@material-ui/core/DialogTitle";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import React from "react";
import { FormattedMessage } from "react-intl";
import { buttonMessages } from "@saleor/intl";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
deleteButton: {
"&:hover": {
backgroundColor: theme.palette.error.main
@ -24,49 +19,58 @@ const styles = theme =>
backgroundColor: theme.palette.error.main,
color: theme.palette.error.contrastText
}
});
}),
{
name: "CategoryDeleteDialog"
}
);
export interface CategoryDeleteDialogProps extends WithStyles<typeof styles> {
export interface CategoryDeleteDialogProps {
open: boolean;
name: string;
onClose();
onConfirm();
}
const CategoryDeleteDialog = withStyles(styles, {
name: "CategoryDeleteDialog"
})(({ classes, name, open, onConfirm, onClose }: CategoryDeleteDialogProps) => (
<Dialog onClose={onClose} open={open}>
<DialogTitle>
<FormattedMessage
defaultMessage="Delete category"
description="dialog title"
/>
</DialogTitle>
<DialogContent>
<DialogContentText>
const CategoryDeleteDialog: React.FC<CategoryDeleteDialogProps> = props => {
const { name, open, onConfirm, onClose } = props;
const classes = useStyles(props);
return (
<Dialog onClose={onClose} open={open}>
<DialogTitle>
<FormattedMessage
defaultMessage="Are you sure you want to delete {categoryName}?"
description="delete category"
values={{
categoryName: <strong>{name}</strong>
}}
defaultMessage="Delete category"
description="dialog title"
/>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
<FormattedMessage {...buttonMessages.back} />
</Button>
<Button
className={classes.deleteButton}
variant="contained"
onClick={onConfirm}
>
<FormattedMessage {...buttonMessages.save} />
</Button>
</DialogActions>
</Dialog>
));
</DialogTitle>
<DialogContent>
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to delete {categoryName}?"
description="delete category"
values={{
categoryName: <strong>{name}</strong>
}}
/>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={onClose}>
<FormattedMessage {...buttonMessages.back} />
</Button>
<Button
className={classes.deleteButton}
variant="contained"
onClick={onConfirm}
>
<FormattedMessage {...buttonMessages.save} />
</Button>
</DialogActions>
</Dialog>
);
};
CategoryDeleteDialog.displayName = "CategoryDeleteDialog";
export default CategoryDeleteDialog;

View file

@ -1,9 +1,4 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
@ -20,8 +15,8 @@ import TablePagination from "@saleor/components/TablePagination";
import { maybe, renderCollection } from "@saleor/misc";
import { ListActions, ListProps } from "@saleor/types";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
[theme.breakpoints.up("lg")]: {
colName: {
width: 840
@ -45,7 +40,9 @@ const styles = theme =>
tableRow: {
cursor: "pointer"
}
});
}),
{ name: "CategoryList" }
);
interface CategoryListProps extends ListProps, ListActions {
categories?: CategoryFragment[];
@ -55,10 +52,9 @@ interface CategoryListProps extends ListProps, ListActions {
const numberOfColumns = 4;
const CategoryList = withStyles(styles, { name: "CategoryList" })(
({
const CategoryList: React.FC<CategoryListProps> = props => {
const {
categories,
classes,
disabled,
settings,
pageInfo,
@ -72,7 +68,11 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
onPreviousPage,
onUpdateListSettings,
onRowClick
}: CategoryListProps & WithStyles<typeof styles>) => (
} = props;
const classes = useStyles(props);
return (
<Table>
<TableHead
colSpan={numberOfColumns}
@ -175,7 +175,8 @@ const CategoryList = withStyles(styles, { name: "CategoryList" })(
)}
</TableBody>
</Table>
)
);
);
};
CategoryList.displayName = "CategoryList";
export default CategoryList;

View file

@ -1,9 +1,4 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
@ -25,8 +20,8 @@ import { ListActions, ListProps } from "@saleor/types";
import React from "react";
import { CategoryDetails_category_products_edges_node } from "../../types/CategoryDetails";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
[theme.breakpoints.up("lg")]: {
colName: {
width: "auto"
@ -69,20 +64,20 @@ const styles = theme =>
textRight: {
textAlign: "right"
}
});
}),
{
name: "CategoryProductList"
}
);
interface CategoryProductListProps
extends ListProps,
ListActions,
WithStyles<typeof styles> {
interface CategoryProductListProps extends ListProps, ListActions {
products: CategoryDetails_category_products_edges_node[];
}
export const CategoryProductList = withStyles(styles, {
name: "CategoryProductList"
})(
({
classes,
export const CategoryProductList: React.FC<
CategoryProductListProps
> = props => {
const {
disabled,
isChecked,
pageInfo,
@ -94,150 +89,150 @@ export const CategoryProductList = withStyles(styles, {
onNextPage,
onPreviousPage,
onRowClick
}: CategoryProductListProps) => {
const intl = useIntl();
} = props;
const numberOfColumns = 5;
const classes = useStyles(props);
const intl = useIntl();
return (
<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;
const numberOfColumns = 5;
return (
<TableRow
selected={isSelected}
hover={!!product}
key={product ? product.id : "skeleton"}
onClick={product && onRowClick(product.id)}
className={classes.link}
return (
<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 (
<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">
<Checkbox
checked={isSelected}
disabled={disabled}
disableClickPropagation
onChange={() => toggle(product.id)}
{product ? product.name : <Skeleton />}
</TableCellAvatar>
<TableCell className={classes.colType}>
{product && product.productType ? (
product.productType.name
) : (
<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
className={classes.colName}
thumbnail={maybe(() => product.thumbnail.url)}
>
{product ? product.name : <Skeleton />}
</TableCellAvatar>
<TableCell className={classes.colType}>
{product && product.productType ? (
product.productType.name
) : (
<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" />
) : (
<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>
)
)}
</TableBody>
</Table>
</div>
);
}
);
);
},
() => (
<TableRow>
<TableCell colSpan={numberOfColumns}>
<FormattedMessage defaultMessage="No products found" />
</TableCell>
</TableRow>
)
)}
</TableBody>
</Table>
</div>
);
};
CategoryProductList.displayName = "CategoryProductList";
export default CategoryProductList;

View file

@ -1,9 +1,4 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
@ -19,8 +14,8 @@ import Skeleton from "@saleor/components/Skeleton";
import { commonMessages } from "@saleor/intl";
import { CollectionDetails_collection_backgroundImage } from "../../types/CollectionDetails";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
PhotosIcon: {
height: "64px",
margin: "0 auto",
@ -50,7 +45,11 @@ const styles = theme =>
position: "relative",
width: 148
}
});
}),
{
name: "CollectionImage"
}
);
export interface CollectionImageProps {
data: {
@ -62,83 +61,78 @@ export interface CollectionImageProps {
onImageUpload: (file: File) => void;
}
export const CollectionImage = withStyles(styles)(
({
classes,
data,
onImageUpload,
image,
onChange,
onImageDelete
}: CollectionImageProps & WithStyles<typeof styles>) => {
const anchor = React.useRef<HTMLInputElement>();
const intl = useIntl();
export const CollectionImage: React.FC<CollectionImageProps> = props => {
const { data, onImageUpload, image, onChange, onImageDelete } = props;
const handleImageUploadButtonClick = () => anchor.current.click();
const anchor = React.useRef<HTMLInputElement>();
const classes = useStyles(props);
const intl = useIntl();
return (
<Card>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Background Image (optional)",
description: "section header"
})}
toolbar={
<>
<Button
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 && (
const handleImageUploadButtonClick = () => anchor.current.click();
return (
<Card>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Background Image (optional)",
description: "section header"
})}
toolbar={
<>
<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>
<Button
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}
/>
</>
)}
</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";
export default CollectionImage;

View file

@ -1,9 +1,4 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
@ -21,8 +16,8 @@ import { maybe, renderCollection } from "@saleor/misc";
import { ListActions, ListProps } from "@saleor/types";
import { CollectionList_collections_edges_node } from "../../types/CollectionList";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
[theme.breakpoints.up("lg")]: {
colAvailability: {
width: 240
@ -42,20 +37,18 @@ const styles = theme =>
tableRow: {
cursor: "pointer" as "pointer"
}
});
}),
{ name: "CollectionList" }
);
interface CollectionListProps
extends ListProps,
ListActions,
WithStyles<typeof styles> {
interface CollectionListProps extends ListProps, ListActions {
collections: CollectionList_collections_edges_node[];
}
const numberOfColumns = 5;
const CollectionList = withStyles(styles, { name: "CollectionList" })(
({
classes,
const CollectionList: React.FC<CollectionListProps> = props => {
const {
collections,
disabled,
settings,
@ -69,122 +62,121 @@ const CollectionList = withStyles(styles, { name: "CollectionList" })(
toggle,
toggleAll,
toolbar
}: CollectionListProps) => {
const intl = useIntl();
} = props;
return (
<Table>
<TableHead
colSpan={numberOfColumns}
selected={selected}
disabled={disabled}
items={collections}
toggleAll={toggleAll}
toolbar={toolbar}
>
<TableCell className={classes.colName}>
<FormattedMessage defaultMessage="Category Name" />
</TableCell>
<TableCell className={classes.colProducts}>
<FormattedMessage defaultMessage="No. of Products" />
</TableCell>
<TableCell className={classes.colAvailability}>
<FormattedMessage
defaultMessage="Availability"
description="collection availability"
/>
</TableCell>
</TableHead>
<TableFooter>
<TableRow>
<TablePagination
colSpan={numberOfColumns}
settings={settings}
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
onNextPage={onNextPage}
onUpdateListSettings={onUpdateListSettings}
hasPreviousPage={
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
}
onPreviousPage={onPreviousPage}
/>
</TableRow>
</TableFooter>
<TableBody>
{renderCollection(
collections,
collection => {
const isSelected = collection ? isChecked(collection.id) : false;
return (
<TableRow
className={classes.tableRow}
hover={!!collection}
onClick={collection ? onRowClick(collection.id) : undefined}
key={collection ? collection.id : "skeleton"}
selected={isSelected}
data-tc="id"
data-tc-id={maybe(() => collection.id)}
const classes = useStyles(props);
const intl = useIntl();
return (
<Table>
<TableHead
colSpan={numberOfColumns}
selected={selected}
disabled={disabled}
items={collections}
toggleAll={toggleAll}
toolbar={toolbar}
>
<TableCell className={classes.colName}>
<FormattedMessage defaultMessage="Category Name" />
</TableCell>
<TableCell className={classes.colProducts}>
<FormattedMessage defaultMessage="No. of Products" />
</TableCell>
<TableCell className={classes.colAvailability}>
<FormattedMessage
defaultMessage="Availability"
description="collection availability"
/>
</TableCell>
</TableHead>
<TableFooter>
<TableRow>
<TablePagination
colSpan={numberOfColumns}
settings={settings}
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
onNextPage={onNextPage}
onUpdateListSettings={onUpdateListSettings}
hasPreviousPage={
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
}
onPreviousPage={onPreviousPage}
/>
</TableRow>
</TableFooter>
<TableBody>
{renderCollection(
collections,
collection => {
const isSelected = collection ? isChecked(collection.id) : false;
return (
<TableRow
className={classes.tableRow}
hover={!!collection}
onClick={collection ? onRowClick(collection.id) : undefined}
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">
<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)}
>
{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" />
{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>
)
)}
</TableBody>
</Table>
);
}
);
);
},
() => (
<TableRow>
<TableCell colSpan={numberOfColumns}>
<FormattedMessage defaultMessage="No collections found" />
</TableCell>
</TableRow>
)
)}
</TableBody>
</Table>
);
};
CollectionList.displayName = "CollectionList";
export default CollectionList;

View file

@ -1,12 +1,7 @@
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import IconButton from "@material-ui/core/IconButton";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
@ -29,13 +24,13 @@ import { maybe, renderCollection } from "../../../misc";
import { ListActions, PageListProps } from "../../../types";
import { CollectionDetails_collection } from "../../types/CollectionDetails";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
colActions: {
"&:last-child": {
paddingRight: 0
},
width: 76 + theme.spacing(0.5)
width: 76 + theme.spacing(0.5)
},
colName: {
paddingLeft: 0,
@ -56,21 +51,19 @@ const styles = theme =>
tableRow: {
cursor: "pointer"
}
});
}),
{ name: "CollectionProducts" }
);
export interface CollectionProductsProps
extends PageListProps,
ListActions,
WithStyles<typeof styles> {
export interface CollectionProductsProps extends PageListProps, ListActions {
collection: CollectionDetails_collection;
onProductUnassign: (id: string, event: React.MouseEvent<any>) => void;
}
const numberOfColumns = 5;
const CollectionProducts = withStyles(styles, { name: "CollectionProducts" })(
({
classes,
const CollectionProducts: React.FC<CollectionProductsProps> = props => {
const {
collection,
disabled,
onAdd,
@ -84,165 +77,165 @@ const CollectionProducts = withStyles(styles, { name: "CollectionProducts" })(
toggle,
toggleAll,
toolbar
}: CollectionProductsProps) => {
const intl = useIntl();
} = props;
return (
<Card>
<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;
const classes = useStyles(props);
const intl = useIntl();
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>
</TableRow>
);
return (
<Card>
<CardTitle
title={
!!collection ? (
intl.formatMessage(
{
defaultMessage: "Products in {name}",
description: "products in collection"
},
() => (
<TableRow>
<TableCell />
<TableCell colSpan={numberOfColumns}>
<FormattedMessage defaultMessage="No products found" />
{
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 (
<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>
</TableRow>
)
)}
</TableBody>
</Table>
</Card>
);
}
);
);
},
() => (
<TableRow>
<TableCell />
<TableCell colSpan={numberOfColumns}>
<FormattedMessage defaultMessage="No products found" />
</TableCell>
</TableRow>
)
)}
</TableBody>
</Table>
</Card>
);
};
CollectionProducts.displayName = "CollectionProducts";
export default CollectionProducts;

View file

@ -1,11 +1,6 @@
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import React from "react";
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 Skeleton from "@saleor/components/Skeleton";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
checkboxContainer: {
marginTop: theme.spacing()
},
hr: {
backgroundColor: theme.overrides.MuiCard.root.borderColor,
backgroundColor: theme.palette.divider,
border: "none",
height: 1,
marginBottom: 0,
marginTop: 0
}
});
}),
{ name: "AccountPermissions" }
);
interface AccountPermissionsProps extends WithStyles<typeof styles> {
interface AccountPermissionsProps {
permissions: ShopInfo_shop_permissions[];
data: {
hasFullAccess: boolean;
@ -39,89 +36,85 @@ interface AccountPermissionsProps extends WithStyles<typeof styles> {
onChange: (event: React.ChangeEvent<any>, cb?: () => void) => void;
}
const AccountPermissions = withStyles(styles, { name: "AccountPermissions" })(
({
classes,
data,
disabled,
permissions,
onChange
}: AccountPermissionsProps) => {
const intl = useIntl();
const AccountPermissions: React.FC<AccountPermissionsProps> = props => {
const { data, disabled, permissions, onChange } = props;
const handleFullAccessChange = (event: React.ChangeEvent<any>) =>
onChange(event, () =>
onChange({
target: {
name: "permissions",
value: event.target.value ? permissions.map(perm => perm.code) : []
}
} as any)
);
const handlePermissionChange = (event: React.ChangeEvent<any>) => {
const classes = useStyles(props);
const intl = useIntl();
const handleFullAccessChange = (event: React.ChangeEvent<any>) =>
onChange(event, () =>
onChange({
target: {
name: "permissions",
value: event.target.value
? data.permissions.concat([event.target.name])
: data.permissions.filter(perm => perm !== event.target.name)
value: event.target.value ? permissions.map(perm => perm.code) : []
}
} 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>
} as any)
);
}
);
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";
export default AccountPermissions;

View file

@ -3,12 +3,7 @@ import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import classNames from "classnames";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
@ -18,8 +13,8 @@ import ConfirmButton, {
ConfirmButtonTransitionState
} from "../ConfirmButton/ConfirmButton";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
deleteButton: {
"&:hover": {
backgroundColor: theme.palette.error.main
@ -27,9 +22,11 @@ const styles = theme =>
backgroundColor: theme.palette.error.main,
color: theme.palette.error.contrastText
}
});
}),
{ name: "ActionDialog" }
);
interface ActionDialogProps extends WithStyles<typeof styles> {
interface ActionDialogProps {
children?: React.ReactNode;
confirmButtonLabel?: string;
confirmButtonState: ConfirmButtonTransitionState;
@ -40,10 +37,9 @@ interface ActionDialogProps extends WithStyles<typeof styles> {
onConfirm();
}
const ActionDialog = withStyles(styles, { name: "ActionDialog" })(
({
const ActionDialog: React.FC<ActionDialogProps> = props => {
const {
children,
classes,
confirmButtonLabel,
confirmButtonState,
open,
@ -51,35 +47,37 @@ const ActionDialog = withStyles(styles, { name: "ActionDialog" })(
variant,
onConfirm,
onClose
}: ActionDialogProps) => {
const intl = useIntl();
} = props;
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";
export default ActionDialog;

View file

@ -1,9 +1,4 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import React from "react";
import { useIntl } from "react-intl";
@ -16,16 +11,15 @@ import SingleAutocompleteSelectField, {
SingleAutocompleteChoiceType
} from "../SingleAutocompleteSelectField";
const styles = theme =>
createStyles({
root: {
display: "grid",
gridColumnGap: theme.spacing(2),
gridTemplateColumns: "1fr 1fr"
}
});
const useStyles = makeStyles(theme => ({
root: {
display: "grid",
gridColumnGap: theme.spacing(2),
gridTemplateColumns: "1fr 1fr"
}
}));
interface AddressEditProps extends WithStyles<typeof styles> {
interface AddressEditProps {
countries: SingleAutocompleteChoiceType[];
countryDisplayValue: string;
data: AddressTypeInput;
@ -35,9 +29,8 @@ interface AddressEditProps extends WithStyles<typeof styles> {
onCountryChange(event: React.ChangeEvent<any>);
}
const AddressEdit = withStyles(styles, { name: "AddressEdit" })(
({
classes,
const AddressEdit: React.FC<AddressEditProps> = props => {
const {
countries,
countryDisplayValue,
data,
@ -45,164 +38,165 @@ const AddressEdit = withStyles(styles, { name: "AddressEdit" })(
errors,
onChange,
onCountryChange
}: AddressEditProps) => {
const intl = useIntl();
} = props;
const classes = useStyles(props);
return (
<>
<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>
const intl = useIntl();
<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>
return (
<>
<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 />
<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";
export default AddressEdit;

View file

@ -1,10 +1,5 @@
import Portal from "@material-ui/core/Portal";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import ArrowBackIcon from "@material-ui/icons/ArrowBack";
import React from "react";
@ -16,45 +11,44 @@ export interface AppHeaderProps {
onBack();
}
const styles = theme =>
createStyles({
backArrow: {
fontSize: 30
const useStyles = makeStyles(theme => ({
backArrow: {
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: {
flex: "0 0 auto",
marginLeft: -theme.spacing(2),
marginRight: theme.spacing(),
marginTop: -theme.spacing(2)
},
root: {
"&:hover": {
color: theme.typography.body1.color
},
alignItems: "center",
color: theme.palette.grey[500],
cursor: "pointer",
display: "flex",
marginTop: theme.spacing(0.5),
transition: theme.transitions.duration.standard + "ms"
},
skeleton: {
marginBottom: theme.spacing(2),
width: "10rem"
},
title: {
color: "inherit",
flex: 1,
marginLeft: theme.spacing(),
textTransform: "uppercase"
}
});
const AppHeader = withStyles(styles, { name: "AppHeader" })(
({
children,
classes,
onBack
}: AppHeaderProps & WithStyles<typeof styles>) => (
alignItems: "center",
color: theme.palette.grey[500],
cursor: "pointer",
display: "flex",
marginTop: theme.spacing(0.5),
transition: theme.transitions.duration.standard + "ms"
},
skeleton: {
marginBottom: theme.spacing(2),
width: "10rem"
},
title: {
color: "inherit",
flex: 1,
marginLeft: theme.spacing(),
textTransform: "uppercase"
}
}));
const AppHeader: React.FC<AppHeaderProps> = props => {
const { children, onBack } = props;
const classes = useStyles(props);
return (
<AppHeaderContext.Consumer>
{anchor =>
anchor ? (
@ -71,7 +65,7 @@ const AppHeader = withStyles(styles, { name: "AppHeader" })(
) : null
}
</AppHeaderContext.Consumer>
)
);
);
};
AppHeader.displayName = "AppHeader";
export default AppHeader;

View file

@ -1,2 +1,2 @@
export { default } from './AppHeader';
export * from './AppHeader';
export { default } from "./AppHeader";
export * from "./AppHeader";

View file

@ -8,7 +8,7 @@ import MenuItem from "@material-ui/core/MenuItem";
import Menu from "@material-ui/core/MenuList";
import Paper from "@material-ui/core/Paper";
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 React from "react";
import SVG from "react-inlinesvg";
@ -36,8 +36,8 @@ import createMenuStructure from "./menuStructure";
import ResponsiveDrawer from "./ResponsiveDrawer";
import ThemeSwitch from "./ThemeSwitch";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
appAction: {
[theme.breakpoints.down("sm")]: {
left: 0,
@ -263,249 +263,232 @@ const styles = theme =>
viewContainer: {
minHeight: `calc(100vh - ${theme.spacing(2) + appLoaderHeight + 70}px)`
}
});
}),
{
name: "AppLayout"
}
);
interface AppLayoutProps {
children: React.ReactNode;
}
const AppLayout = withStyles(styles, {
name: "AppLayout"
})(
withRouter<AppLayoutProps & RouteComponentProps<any>, any>(
({
classes,
children,
location
}: AppLayoutProps &
WithStyles<typeof styles> &
RouteComponentProps<any>) => {
const { isDark, toggleTheme } = useTheme();
const [isMenuSmall, setMenuSmall] = useLocalStorage("isMenuSmall", false);
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 AppLayout = withRouter<AppLayoutProps & RouteComponentProps<any>, any>(
({ children, location }: AppLayoutProps & RouteComponentProps<any>) => {
const classes = useStyles({});
const { isDark, toggleTheme } = useTheme();
const [isMenuSmall, setMenuSmall] = useLocalStorage("isMenuSmall", false);
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 configurationMenu = createConfigurationMenu(intl);
const userPermissions = maybe(() => user.permissions, []);
const menuStructure = createMenuStructure(intl);
const configurationMenu = createConfigurationMenu(intl);
const userPermissions = maybe(() => user.permissions, []);
const renderConfigure = configurationMenu.some(section =>
section.menuItems.some(
menuItem =>
!!userPermissions.find(
userPermission => userPermission.code === menuItem.permission
)
)
);
const renderConfigure = configurationMenu.some(section =>
section.menuItems.some(
menuItem =>
!!userPermissions.find(
userPermission => userPermission.code === menuItem.permission
)
)
);
const handleLogout = () => {
setMenuState(false);
logout();
};
const handleLogout = () => {
setMenuState(false);
logout();
};
const handleViewerProfile = () => {
setMenuState(false);
navigate(staffMemberDetailsUrl(user.id));
};
const handleViewerProfile = () => {
setMenuState(false);
navigate(staffMemberDetailsUrl(user.id));
};
const handleMenuItemClick = (
url: string,
event: React.MouseEvent<any>
) => {
event.stopPropagation();
event.preventDefault();
setDrawerState(false);
navigate(url);
};
const handleMenuItemClick = (url: string, event: React.MouseEvent<any>) => {
event.stopPropagation();
event.preventDefault();
setDrawerState(false);
navigate(url);
};
const handleIsMenuSmall = () => {
setMenuSmall(!isMenuSmall);
};
const handleIsMenuSmall = () => {
setMenuSmall(!isMenuSmall);
};
return (
<AppProgressProvider>
{({ isProgress }) => (
<AppHeaderContext.Provider value={appHeaderAnchor}>
<AppActionContext.Provider value={appActionAnchor}>
<div className={classes.root}>
<div className={classes.sideBar}>
<ResponsiveDrawer
onClose={() => setDrawerState(false)}
open={isDrawerOpened}
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
})}
return (
<AppProgressProvider>
{({ isProgress }) => (
<AppHeaderContext.Provider value={appHeaderAnchor}>
<AppActionContext.Provider value={appActionAnchor}>
<div className={classes.root}>
<div className={classes.sideBar}>
<ResponsiveDrawer
onClose={() => setDrawerState(false)}
open={isDrawerOpened}
small={!isMenuSmall}
>
{isProgress ? (
<LinearProgress
className={classes.appLoader}
color="primary"
<div
className={classNames(classes.logo, {
[classes.logoSmall]: isMenuSmall,
[classes.logoDark]: isDark
})}
>
<SVG
src={isMenuSmall ? saleorDarkLogoSmall : saleorDarkLogo}
/>
) : (
<div className={classes.appLoaderPlaceholder} />
)}
<div className={classes.viewContainer}>
<div>
<Container>
<div className={classes.header}>
</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 ? (
<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
className={classNames(classes.menuIcon, {
[classes.menuIconOpen]: isDrawerOpened,
[classes.menuIconDark]: isDark
})}
onClick={() => setDrawerState(!isDrawerOpened)}
className={classes.userMenuContainer}
ref={anchor}
>
<span />
<span />
<span />
<span />
</div>
<div ref={appHeaderAnchor} />
<div className={classes.spacer} />
<div className={classes.userBar}>
<ThemeSwitch
className={classes.darkThemeSwitch}
checked={isDark}
onClick={toggleTheme}
<Chip
avatar={
user.avatar && (
<Avatar alt="user" src={user.avatar.url} />
)
}
className={classes.userChip}
label={
<>
{user.email}
<ArrowDropdown
className={classNames(classes.arrow, {
[classes.rotate]: isMenuOpened
})}
/>
</>
}
onClick={() => setMenuState(!isMenuOpened)}
/>
<div
className={classes.userMenuContainer}
ref={anchor}
<Popper
className={classes.popover}
open={isMenuOpened}
anchorEl={anchor.current}
transition
disablePortal
placement="bottom-end"
>
<Chip
avatar={
user.avatar && (
<Avatar
alt="user"
src={user.avatar.url}
/>
)
}
className={classes.userChip}
label={
<>
{user.email}
<ArrowDropdown
className={classNames(classes.arrow, {
[classes.rotate]: isMenuOpened
})}
/>
</>
}
onClick={() => setMenuState(!isMenuOpened)}
/>
<Popper
className={classes.popover}
open={isMenuOpened}
anchorEl={anchor.current}
transition
disablePortal
placement="bottom-end"
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom"
? "right top"
: "right bottom"
}}
>
<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>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === "bottom"
? "right top"
: "right bottom"
}}
>
<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>
</Container>
</div>
<main className={classes.view}>{children}</main>
</div>
</Container>
</div>
<div className={classes.appAction} ref={appActionAnchor} />
<main className={classes.view}>{children}</main>
</div>
<div className={classes.appAction} ref={appActionAnchor} />
</div>
</AppActionContext.Provider>
</AppHeaderContext.Provider>
)}
</AppProgressProvider>
);
}
)
</div>
</AppActionContext.Provider>
</AppHeaderContext.Provider>
)}
</AppProgressProvider>
);
}
);
export default AppLayout;

View file

@ -1,9 +1,4 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import classNames from "classnames";
import React from "react";
@ -24,92 +19,41 @@ import { orderDraftListUrl, orderListUrl } from "../../orders/urls";
import MenuNested from "./MenuNested";
import { IMenuItem } from "./menuStructure";
const styles = theme =>
createStyles({
menuIcon: {
"& svg": {
height: 32,
width: 32
},
display: "inline-block",
position: "relative",
top: 8
const useStyles = makeStyles(theme => ({
menuIcon: {
"& svg": {
height: 32,
width: 32
},
menuIconDark: {
"& path": {
fill: theme.palette.common.white
}
display: "inline-block",
position: "relative",
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: {
left: -5
"& path": {
transition: "fill 0.5s ease"
},
menuIsActive: {
boxShadow: "0px 0px 12px 1px rgba(0,0,0,0.2)"
},
menuItemHover: {
"&:hover": {
"& 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
},
"& path": {
color: 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": {
borderLeft: `solid 2px ${theme.palette.primary.main}`,
@ -119,47 +63,97 @@ const styles = theme =>
position: "absolute",
top: 8
},
position: "relative"
color: theme.palette.primary.main
},
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"
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
},
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`
"& path": {
color: 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": {
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 {
className?: string;
@ -176,9 +170,8 @@ export interface IActiveSubMenu {
label: string | null;
}
const MenuList = withStyles(styles, { name: "MenuList" })(
({
classes,
const MenuList: React.FC<MenuListProps> = props => {
const {
className,
menuItems,
isMenuSmall,
@ -186,134 +179,89 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
user,
renderConfigure,
onMenuItemClick
}: MenuListProps & WithStyles<typeof styles>) => {
const { isDark } = useTheme();
const [activeSubMenu, setActiveSubMenu] = React.useState<IActiveSubMenu>({
} = props;
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,
label: null
});
const intl = useIntl();
if (menuItemUrl && event) {
onMenuItemClick(menuItemUrl, event);
event.stopPropagation();
event.preventDefault();
}
};
const configutationMenu = createConfigurationMenu(intl).map(menu => {
menu.menuItems.map(item =>
user.permissions.map(perm => perm.code).includes(item.permission)
);
});
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]
});
const handleSubMenu = itemLabel => {
setActiveSubMenu({
isActive:
itemLabel === activeSubMenu.label ? !activeSubMenu.isActive : true,
label: itemLabel
});
};
if (
menuItem.permission &&
!user.permissions.map(perm => perm.code).includes(menuItem.permission)
) {
return null;
}
const closeSubMenu = (menuItemUrl, event) => {
setActiveSubMenu({
isActive: false,
label: null
});
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>
);
}
if (!menuItem.url) {
const isAnyChildActive = menuItem.children.reduce(
(acc, child) => acc || isActive(child),
false
);
return (
<a
<div
className={classNames(classes.menuListItem, {
[classes.menuListItemActive]: isActive(menuItem)
[classes.menuListItemActive]: isAnyChildActive
})}
href={createHref(menuItem.url)}
onClick={event => closeSubMenu(menuItem.url, event)}
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
className={classNames(classes.menuIcon, {
[classes.menuIconDark]: isDark,
@ -330,14 +278,34 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
{menuItem.label}
</Typography>
</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
className={classes.menuListItem}
href={createHref(configurationMenuUrl)}
onClick={event => closeSubMenu(configurationMenuUrl, event)}
className={classNames(classes.menuListItem, {
[classes.menuListItemActive]: isActive(menuItem)
})}
href={createHref(menuItem.url)}
onClick={event => closeSubMenu(menuItem.url, event)}
key={menuItem.label}
>
<div className={classes.menuItemHover}>
<SVG
@ -345,21 +313,48 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
[classes.menuIconDark]: isDark,
[classes.menuIconSmall]: !isMenuSmall
})}
src={configureIcon}
src={menuItem.icon}
/>
<Typography
aria-label="configuration"
aria-label={menuItem.ariaLabel}
className={classNames(classes.menuListItemText, {
[classes.menuListItemTextHide]: !isMenuSmall
})}
>
<FormattedMessage {...sectionNames.configuration} />
{menuItem.label}
</Typography>
</div>
</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;

View file

@ -1,10 +1,5 @@
import Hidden from "@material-ui/core/Hidden";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import classNames from "classnames";
import React from "react";
@ -17,89 +12,88 @@ import { drawerWidthExpanded } from "./consts";
import { IActiveSubMenu } from "./MenuList";
import { IMenuItem } from "./menuStructure";
const styles = theme =>
createStyles({
menuListNested: {
background: theme.palette.background.paper,
height: "100vh",
position: "absolute",
right: 0,
top: 0,
transition: `right ${theme.transitions.duration.shorter}ms ease`,
width: 300,
zIndex: -1
const useStyles = makeStyles(theme => ({
menuListNested: {
background: theme.palette.background.paper,
height: "100vh",
position: "absolute",
right: 0,
top: 0,
transition: `right ${theme.transitions.duration.shorter}ms ease`,
width: 300,
zIndex: -1
},
menuListNestedClose: {
"& svg": {
fill: theme.palette.primary.main,
left: 7,
position: "relative",
top: -2
},
menuListNestedClose: {
"& svg": {
fill: theme.palette.primary.main,
left: 7,
position: "relative",
top: -2
},
border: `solid 1px #EAEAEA`,
borderRadius: "100%",
cursor: "pointer",
height: 32,
position: "absolute",
right: 32,
top: 35,
transform: "rotate(180deg)",
width: 32
border: `solid 1px #EAEAEA`,
borderRadius: "100%",
cursor: "pointer",
height: 32,
position: "absolute",
right: 32,
top: 35,
transform: "rotate(180deg)",
width: 32
},
menuListNestedCloseDark: {
border: `solid 1px #252728`
},
menuListNestedHide: {
opacity: 0
},
menuListNestedIcon: {
"& path": {
fill: "initial"
},
menuListNestedCloseDark: {
border: `solid 1px #252728`
},
menuListNestedHide: {
opacity: 0
},
menuListNestedIcon: {
"& path": {
fill: "initial"
},
"& svg": { height: 32, position: "relative", top: 7, width: 32 }
},
menuListNestedIconDark: {
"& path": {
fill: theme.palette.common.white
"& svg": { height: 32, position: "relative", top: 7, width: 32 }
},
menuListNestedIconDark: {
"& path": {
fill: theme.palette.common.white
}
},
menuListNestedItem: {
"&:hover": {
"& p": {
color: theme.palette.primary.main
}
},
menuListNestedItem: {
"&:hover": {
"& p": {
color: theme.palette.primary.main
}
},
display: "block",
marginBottom: theme.spacing(2),
padding: "0px 30px",
textDecoration: "none"
display: "block",
marginBottom: theme.spacing(2),
padding: "0px 30px",
textDecoration: "none"
},
menuListNestedOpen: {
[theme.breakpoints.down("sm")]: {
right: 0,
width: drawerWidthExpanded,
zIndex: 2
},
menuListNestedOpen: {
[theme.breakpoints.down("sm")]: {
right: 0,
width: drawerWidthExpanded,
zIndex: 2
},
right: -300,
zIndex: -1
right: -300,
zIndex: -1
},
subHeader: {
borderBottom: "solid 1px #EAEAEA",
margin: "30px",
marginBottom: 39,
paddingBottom: 22
},
subHeaderDark: {
borderBottom: "solid 1px #252728"
},
subHeaderTitle: {
[theme.breakpoints.up("md")]: {
paddingLeft: 0
},
subHeader: {
borderBottom: "solid 1px #EAEAEA",
margin: "30px",
marginBottom: 39,
paddingBottom: 22
},
subHeaderDark: {
borderBottom: "solid 1px #252728"
},
subHeaderTitle: {
[theme.breakpoints.up("md")]: {
paddingLeft: 0
},
display: "inline",
paddingLeft: 10
}
});
display: "inline",
paddingLeft: 10
}
}));
export interface MenuNestedProps {
activeItem: IActiveSubMenu;
@ -112,86 +106,85 @@ export interface MenuNestedProps {
onMenuItemClick: (url: string, event: React.MouseEvent<any>) => void;
}
const MenuNested = withStyles(styles, { name: "MenuNested" })(
({
const MenuNested: React.FC<MenuNestedProps> = props => {
const {
activeItem,
ariaLabel,
classes,
closeSubMenu,
icon,
menuItem,
onMenuItemClick,
title
}: MenuNestedProps & WithStyles<typeof styles>) => {
const menuItems = menuItem.children;
const { isDark } = useTheme();
const closeMenu = (menuItemUrl, event) => {
onMenuItemClick(menuItemUrl, event);
closeSubMenu({
isActive: false,
label: null
});
event.stopPropagation();
event.preventDefault();
};
return (
<>
<div
className={classNames(classes.menuListNested, {
[classes.menuListNestedOpen]:
activeItem.label === ariaLabel && activeItem.isActive
} = props;
const classes = useStyles(props);
const menuItems = menuItem.children;
const { isDark } = useTheme();
const closeMenu = (menuItemUrl, event) => {
onMenuItemClick(menuItemUrl, event);
closeSubMenu({
isActive: false,
label: null
});
event.stopPropagation();
event.preventDefault();
};
return (
<>
<div
className={classNames(classes.menuListNested, {
[classes.menuListNestedOpen]:
activeItem.label === ariaLabel && activeItem.isActive
})}
>
<Typography
className={classNames(classes.subHeader, {
[classes.subHeaderDark]: isDark
})}
variant="h5"
>
<Typography
className={classNames(classes.subHeader, {
[classes.subHeaderDark]: isDark
})}
variant="h5"
<Hidden mdUp>
<SVG
className={classNames(classes.menuListNestedIcon, {
[classes.menuListNestedIconDark]: isDark
})}
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>
<SVG
className={classNames(classes.menuListNestedIcon, {
[classes.menuListNestedIconDark]: isDark
})}
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 => {
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>
</>
);
}
);
<Typography aria-label={item.ariaLabel}>{item.label}</Typography>
</a>
))}
</div>
</>
);
};
MenuNested.displayName = "MenuNested";
export default MenuNested;

View file

@ -1,16 +1,11 @@
import Drawer from "@material-ui/core/Drawer";
import Hidden from "@material-ui/core/Hidden";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import React from "react";
import { drawerWidth, drawerWidthExpanded } from "./consts";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
drawerDesktop: {
backgroundColor: theme.palette.background.paper,
border: "none",
@ -29,17 +24,23 @@ const styles = theme =>
drawerMobile: {
width: drawerWidthExpanded
}
});
}),
{ name: "ResponsiveDrawer" }
);
interface ResponsiveDrawerProps extends WithStyles<typeof styles> {
interface ResponsiveDrawerProps {
children?: React.ReactNode;
open: boolean;
small: boolean;
onClose?();
}
const ResponsiveDrawer = withStyles(styles, { name: "ResponsiveDrawer" })(
({ children, classes, onClose, open, small }: ResponsiveDrawerProps) => (
const ResponsiveDrawer: React.FC<ResponsiveDrawerProps> = props => {
const { children, onClose, open, small } = props;
const classes = useStyles(props);
return (
<>
<Hidden smDown>
<Drawer
@ -63,6 +64,6 @@ const ResponsiveDrawer = withStyles(styles, { name: "ResponsiveDrawer" })(
</Drawer>
</Hidden>
</>
)
);
);
};
export default ResponsiveDrawer;

View file

@ -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 React from "react";
import MoonIcon from "../../icons/Moon";
import SunIcon from "../../icons/Sun";
const switchStyles = theme => ({
bar: {
"$colorPrimary$checked + &": {
backgroundColor: theme.palette.background.paper
const useStyles = makeStyles(
theme => ({
bar: {
"$colorPrimary$checked + &": {
backgroundColor: theme.palette.background.paper
},
background: theme.palette.background.paper
},
background: theme.palette.background.paper
},
checked: {
"& svg": {
background: theme.palette.primary.main,
color: theme.palette.background.paper
checked: {
"& svg": {
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: {
"& svg": {
background: theme.palette.primary.main,
borderRadius: "100%",
height: 20,
width: 20
},
width: 58
}),
{
name: "ThemeSwitch"
}
});
const ThemeSwitch = withStyles(switchStyles, {
name: "ThemeSwitch"
})((props: SwitchProps) => (
<Switch
{...props}
color="primary"
icon={<SunIcon />}
checkedIcon={<MoonIcon />}
/>
));
);
const ThemeSwitch: React.FC<SwitchProps> = props => {
const classes = useStyles(props);
return (
<Switch
{...props}
classes={classes}
color="primary"
icon={<SunIcon />}
checkedIcon={<MoonIcon />}
/>
);
};
ThemeSwitch.displayName = "ThemeSwitch";
export default ThemeSwitch;

View file

@ -1,2 +1,2 @@
export { default } from './AppLayout';
export * from './AppLayout';
export { default } from "./AppLayout";
export * from "./AppLayout";

View file

@ -4,7 +4,7 @@ import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
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 TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
@ -27,7 +27,7 @@ export interface FormData {
query: string;
}
const styles = createStyles({
const useStyles = makeStyles({
avatar: {
"&:first-child": {
paddingLeft: 0
@ -44,7 +44,7 @@ const styles = createStyles({
}
});
interface AssignCategoriesDialogProps extends WithStyles<typeof styles> {
interface AssignCategoriesDialogProps {
categories: SearchCategories_search_edges_node[];
confirmButtonState: ConfirmButtonTransitionState;
open: boolean;
@ -71,11 +71,8 @@ function handleCategoryAssign(
}
}
const AssignCategoriesDialog = withStyles(styles, {
name: "AssignCategoriesDialog"
})(
({
classes,
const AssignCategoriesDialog: React.FC<AssignCategoriesDialogProps> = props => {
const {
confirmButtonState,
open,
loading,
@ -83,102 +80,103 @@ const AssignCategoriesDialog = withStyles(styles, {
onClose,
onFetch,
onSubmit
}: AssignCategoriesDialogProps) => {
const intl = useIntl();
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedCategories, setSelectedCategories] = React.useState<
SearchCategories_search_edges_node[]
>([]);
} = props;
const classes = useStyles(props);
const handleSubmit = () => onSubmit(selectedCategories);
const intl = useIntl();
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedCategories, setSelectedCategories] = React.useState<
SearchCategories_search_edges_node[]
>([]);
return (
<Dialog
open={open}
onClose={onClose}
classes={{ paper: classes.overflow }}
fullWidth
maxWidth="sm"
>
<DialogTitle>
const handleSubmit = () => onSubmit(selectedCategories);
return (
<Dialog
open={open}
onClose={onClose}
classes={{ paper: classes.overflow }}
fullWidth
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
defaultMessage="Assign Categories"
description="dialog header"
defaultMessage="Assign categories"
description="button"
/>
</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
defaultMessage="Assign categories"
description="button"
/>
</ConfirmButton>
</DialogActions>
</Dialog>
);
}
);
</ConfirmButton>
</DialogActions>
</Dialog>
);
};
AssignCategoriesDialog.displayName = "AssignCategoriesDialog";
export default AssignCategoriesDialog;

View file

@ -4,7 +4,7 @@ import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
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 TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
@ -27,7 +27,7 @@ export interface FormData {
query: string;
}
const styles = createStyles({
const useStyles = makeStyles({
avatar: {
"&:first-child": {
paddingLeft: 0
@ -44,7 +44,7 @@ const styles = createStyles({
}
});
interface AssignCollectionDialogProps extends WithStyles<typeof styles> {
interface AssignCollectionDialogProps {
collections: SearchCollections_search_edges_node[];
confirmButtonState: ConfirmButtonTransitionState;
open: boolean;
@ -71,11 +71,8 @@ function handleCollectionAssign(
}
}
const AssignCollectionDialog = withStyles(styles, {
name: "AssignCollectionDialog"
})(
({
classes,
const AssignCollectionDialog: React.FC<AssignCollectionDialogProps> = props => {
const {
confirmButtonState,
open,
loading,
@ -83,103 +80,103 @@ const AssignCollectionDialog = withStyles(styles, {
onClose,
onFetch,
onSubmit
}: AssignCollectionDialogProps) => {
const intl = useIntl();
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedCollections, setSelectedCollections] = React.useState<
SearchCollections_search_edges_node[]
>([]);
} = props;
const classes = useStyles(props);
const handleSubmit = () => onSubmit(selectedCollections);
const intl = useIntl();
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedCollections, setSelectedCollections] = React.useState<
SearchCollections_search_edges_node[]
>([]);
return (
<Dialog
onClose={onClose}
open={open}
classes={{ paper: classes.overflow }}
fullWidth
maxWidth="sm"
>
<DialogTitle>
const handleSubmit = () => onSubmit(selectedCollections);
return (
<Dialog
onClose={onClose}
open={open}
classes={{ paper: classes.overflow }}
fullWidth
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
defaultMessage="Assign Collection"
description="dialog header"
defaultMessage="Assign collections"
description="button"
/>
</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
defaultMessage="Assign collections"
description="button"
/>
</ConfirmButton>
</DialogActions>
</Dialog>
);
}
);
</ConfirmButton>
</DialogActions>
</Dialog>
);
};
AssignCollectionDialog.displayName = "AssignCollectionDialog";
export default AssignCollectionDialog;

View file

@ -4,7 +4,7 @@ import Dialog from "@material-ui/core/Dialog";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContent from "@material-ui/core/DialogContent";
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 TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
@ -29,7 +29,7 @@ export interface FormData {
query: string;
}
const styles = createStyles({
const useStyles = makeStyles({
avatar: {
"&:first-child": {
paddingLeft: 0
@ -77,11 +77,8 @@ function handleProductAssign(
}
}
const AssignProductDialog = withStyles(styles, {
name: "AssignProductDialog"
})(
({
classes,
const AssignProductDialog: React.FC<AssignProductDialogProps> = props => {
const {
confirmButtonState,
open,
loading,
@ -89,109 +86,110 @@ const AssignProductDialog = withStyles(styles, {
onClose,
onFetch,
onSubmit
}: AssignProductDialogProps & WithStyles<typeof styles>) => {
const intl = useIntl();
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedProducts, setSelectedProducts] = React.useState<
SearchProducts_search_edges_node[]
>([]);
} = props;
const classes = useStyles(props);
const handleSubmit = () => onSubmit(selectedProducts);
const intl = useIntl();
const [query, onQueryChange] = useSearchQuery(onFetch);
const [selectedProducts, setSelectedProducts] = React.useState<
SearchProducts_search_edges_node[]
>([]);
return (
<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
);
const handleSubmit = () => onSubmit(selectedProducts);
return (
<TableRow key={product.id}>
<TableCellAvatar
className={classes.avatar}
thumbnail={maybe(() => product.thumbnail.url)}
return (
<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 (
<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}>
{product.name}
</TableCell>
<TableCell
padding="checkbox"
className={classes.checkboxCell}
>
<Checkbox
checked={isSelected}
onChange={() =>
handleProductAssign(
product,
isSelected,
selectedProducts,
setSelectedProducts
)
}
/>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
</DialogContent>
<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>
);
}
);
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
</DialogContent>
<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";
export default AssignProductDialog;

View file

@ -1,12 +1,7 @@
import CircularProgress from "@material-ui/core/CircularProgress";
import MenuItem from "@material-ui/core/MenuItem";
import Paper from "@material-ui/core/Paper";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import ArrowBack from "@material-ui/icons/ArrowBack";
import Downshift from "downshift";
@ -43,31 +38,27 @@ const DebounceAutocomplete: React.ComponentType<
DebounceProps<string>
> = Debounce;
const styles = theme =>
createStyles({
container: {
flexGrow: 1,
position: "relative"
},
menuBack: {
marginLeft: -theme.spacing(.5),
marginRight: theme.spacing(1)
},
paper: {
left: 0,
marginTop: theme.spacing(),
padding: theme.spacing(),
position: "absolute",
right: 0,
zIndex: 2
},
root: {}
});
const AutocompleteSelectMenu = withStyles(styles, {
name: "AutocompleteSelectMenu"
})(
({
classes,
const useStyles = makeStyles(theme => ({
container: {
flexGrow: 1,
position: "relative"
},
menuBack: {
marginLeft: -theme.spacing(0.5),
marginRight: theme.spacing(1)
},
paper: {
left: 0,
marginTop: theme.spacing(),
padding: theme.spacing(),
position: "absolute",
right: 0,
zIndex: 2
},
root: {}
}));
const AutocompleteSelectMenu: React.FC<AutocompleteSelectMenuProps> = props => {
const {
disabled,
displayValue,
error,
@ -79,117 +70,118 @@ const AutocompleteSelectMenu = withStyles(styles, {
placeholder,
onChange,
onInputChange
}: AutocompleteSelectMenuProps & WithStyles<typeof styles>) => {
const [inputValue, setInputValue] = React.useState(displayValue || "");
const [menuPath, setMenuPath] = React.useState<number[]>([]);
} = props;
const classes = useStyles(props);
const handleChange = (value: string) =>
onChange({
target: {
name,
value
}
} as any);
const [inputValue, setInputValue] = React.useState(displayValue || "");
const [menuPath, setMenuPath] = React.useState<number[]>([]);
// Validate if option values are duplicated
React.useEffect(() => {
if (!validateMenuOptions(options)) {
throw validationError;
const handleChange = (value: string) =>
onChange({
target: {
name,
value
}
}, []);
} as any);
// Navigate back to main menu after input field change
React.useEffect(() => setMenuPath([]), [options]);
// Validate if option values are duplicated
React.useEffect(() => {
if (!validateMenuOptions(options)) {
throw validationError;
}
}, []);
// Reset input value after displayValue change
React.useEffect(() => setInputValue(displayValue), [displayValue]);
// Navigate back to main menu after input field change
React.useEffect(() => setMenuPath([]), [options]);
return (
<DebounceAutocomplete debounceFn={onInputChange}>
{debounceFn => (
<Downshift
itemToString={item => (item ? item.label : "")}
onSelect={handleChange}
>
{({ getItemProps, isOpen, openMenu, closeMenu, selectItem }) => {
return (
<div className={classes.container}>
<TextField
InputProps={{
endAdornment: loading && <CircularProgress size={16} />,
id: undefined,
onBlur: () => {
closeMenu();
setMenuPath([]);
setInputValue(displayValue);
},
onChange: event => {
debounceFn(event.target.value);
setInputValue(event.target.value);
},
onFocus: () => openMenu(),
placeholder
}}
disabled={disabled}
error={error}
helperText={helperText}
label={label}
fullWidth={true}
value={inputValue}
/>
{isOpen && (
<Paper className={classes.paper} square>
{options.length ? (
<>
{menuPath.length > 0 && (
<MenuItem
component="div"
{...getItemProps({
item: null
})}
onClick={() =>
setMenuPath(
menuPath.slice(0, menuPath.length - 2)
)
}
>
<ArrowBack className={classes.menuBack} />
<FormattedMessage {...buttonMessages.back} />
</MenuItem>
)}
{(menuPath.length
? getMenuItemByPath(options, menuPath).children
: options
).map((suggestion, index) => (
<MenuItem
key={suggestion.value}
component="div"
{...getItemProps({ item: suggestion })}
onClick={() =>
suggestion.value
? selectItem(suggestion.value)
: setMenuPath([...menuPath, index])
}
>
{suggestion.label}
</MenuItem>
))}
</>
) : (
<MenuItem disabled component="div">
<FormattedMessage defaultMessage="No results" />
</MenuItem>
)}
</Paper>
)}
</div>
);
}}
</Downshift>
)}
</DebounceAutocomplete>
);
}
);
// Reset input value after displayValue change
React.useEffect(() => setInputValue(displayValue), [displayValue]);
return (
<DebounceAutocomplete debounceFn={onInputChange}>
{debounceFn => (
<Downshift
itemToString={item => (item ? item.label : "")}
onSelect={handleChange}
>
{({ getItemProps, isOpen, openMenu, closeMenu, selectItem }) => {
return (
<div className={classes.container}>
<TextField
InputProps={{
endAdornment: loading && <CircularProgress size={16} />,
id: undefined,
onBlur: () => {
closeMenu();
setMenuPath([]);
setInputValue(displayValue);
},
onChange: event => {
debounceFn(event.target.value);
setInputValue(event.target.value);
},
onFocus: () => openMenu(),
placeholder
}}
disabled={disabled}
error={error}
helperText={helperText}
label={label}
fullWidth={true}
value={inputValue}
/>
{isOpen && (
<Paper className={classes.paper} square>
{options.length ? (
<>
{menuPath.length > 0 && (
<MenuItem
component="div"
{...getItemProps({
item: null
})}
onClick={() =>
setMenuPath(
menuPath.slice(0, menuPath.length - 2)
)
}
>
<ArrowBack className={classes.menuBack} />
<FormattedMessage {...buttonMessages.back} />
</MenuItem>
)}
{(menuPath.length
? getMenuItemByPath(options, menuPath).children
: options
).map((suggestion, index) => (
<MenuItem
key={suggestion.value}
component="div"
{...getItemProps({ item: suggestion })}
onClick={() =>
suggestion.value
? selectItem(suggestion.value)
: setMenuPath([...menuPath, index])
}
>
{suggestion.label}
</MenuItem>
))}
</>
) : (
<MenuItem disabled component="div">
<FormattedMessage defaultMessage="No results" />
</MenuItem>
)}
</Paper>
)}
</div>
);
}}
</Downshift>
)}
</DebounceAutocomplete>
);
};
AutocompleteSelectMenu.displayName = "AutocompleteSelectMenu";
export default AutocompleteSelectMenu;

View file

@ -1,2 +1,2 @@
export { default } from './AutocompleteSelectMenu';
export * from './AutocompleteSelectMenu';
export { default } from "./AutocompleteSelectMenu";
export * from "./AutocompleteSelectMenu";

View file

@ -1,12 +1,7 @@
import IconButton from "@material-ui/core/IconButton";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import MoreVertIcon from "@material-ui/icons/MoreVert";
import React from "react";
@ -23,80 +18,73 @@ export interface CardMenuProps {
menuItems: CardMenuItem[];
}
const styles = theme =>
createStyles({
iconButton: {
background: theme.palette.background.paper,
borderRadius: "100%",
height: 32,
padding: 0,
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 useStyles = makeStyles(theme => ({
iconButton: {
background: theme.palette.background.paper,
borderRadius: "100%",
height: 32,
padding: 0,
width: 32
}
);
}));
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";
export default CardMenu;

View file

@ -1,29 +1,25 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import React from "react";
const styles = theme =>
createStyles({
spacer: {
[theme.breakpoints.down("sm")]: {
marginTop: theme.spacing(1)
},
marginTop: theme.spacing(3)
}
});
const useStyles = makeStyles(theme => ({
spacer: {
[theme.breakpoints.down("sm")]: {
marginTop: theme.spacing(1)
},
marginTop: theme.spacing(3)
}
}));
interface CardSpacerProps extends WithStyles<typeof styles> {
interface CardSpacerProps {
children?: React.ReactNode;
}
export const CardSpacer = withStyles(styles, { name: "CardSpacer" })(
({ classes, children }: CardSpacerProps) => (
<div className={classes.spacer}>{children}</div>
)
);
export const CardSpacer: React.FC<CardSpacerProps> = props => {
const { children } = props;
const classes = useStyles(props);
return <div className={classes.spacer}>{children}</div>;
};
CardSpacer.displayName = "CardSpacer";
export default CardSpacer;

View file

@ -1,42 +1,36 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import classNames from "classnames";
import React from "react";
const styles = theme =>
createStyles({
children: theme.mixins.gutters({}),
constantHeight: {
height: 56
},
hr: {
border: "none",
borderTop: `1px solid ${theme.overrides.MuiCard.root.borderColor}`,
height: 0,
marginBottom: 0,
marginTop: 0,
width: "100%"
},
root: theme.mixins.gutters({
alignItems: "center",
display: "flex",
minHeight: 56
}),
title: {
flex: 1,
lineHeight: 1
},
toolbar: {
marginRight: -theme.spacing(1)
}
});
const useStyles = makeStyles(theme => ({
children: theme.mixins.gutters({}),
constantHeight: {
height: 56
},
hr: {
border: "none",
borderTop: `1px solid ${theme.palette.divider}`,
height: 0,
marginBottom: 0,
marginTop: 0,
width: "100%"
},
root: theme.mixins.gutters({
alignItems: "center",
display: "flex",
minHeight: 56
}),
title: {
flex: 1,
lineHeight: 1
},
toolbar: {
marginRight: -theme.spacing(1)
}
}));
interface CardTitleProps extends WithStyles<typeof styles> {
interface CardTitleProps {
children?: React.ReactNode;
className?: string;
height?: "default" | "const";
@ -45,24 +39,27 @@ interface CardTitleProps extends WithStyles<typeof styles> {
onClick?: (event: React.MouseEvent<any>) => void;
}
const CardTitle = withStyles(styles, { name: "CardTitle" })(
({
classes,
const CardTitle: React.FC<CardTitleProps> = props => {
const {
className,
children,
height,
title,
toolbar,
onClick,
...props
}: CardTitleProps) => (
...rest
} = props;
const classes = useStyles(props);
return (
<>
<div
className={classNames(classes.root, {
[className]: !!className,
[classes.constantHeight]: height === "const"
})}
{...props}
{...rest}
>
<Typography
className={classes.title}
@ -77,7 +74,7 @@ const CardTitle = withStyles(styles, { name: "CardTitle" })(
<div className={classes.children}>{children}</div>
<hr className={classes.hr} />
</>
)
);
);
};
CardTitle.displayName = "CardTitle";
export default CardTitle;

View file

@ -1,12 +1,6 @@
import { Omit } from "@material-ui/core";
import ButtonBase from "@material-ui/core/ButtonBase";
import { CheckboxProps as MuiCheckboxProps } from "@material-ui/core/Checkbox";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator";
import classNames from "classnames";
import React from "react";
@ -25,116 +19,116 @@ export type CheckboxProps = Omit<
onChange?: (event: React.ChangeEvent<any>) => void;
};
const styles = theme =>
createStyles({
box: {
"&$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
},
const useStyles = makeStyles(theme => ({
box: {
"&$checked": {
"&:before": {
background: "rgba(0, 0, 0, 0)",
content: '""',
height: 14,
left: -1,
position: "absolute",
top: -1,
transition: theme.transitions.duration.short + "ms",
width: 14
background: theme.palette.primary.main,
color: theme.palette.background.paper,
content: '"\\2713"',
fontWeight: "bold",
textAlign: "center"
},
WebkitAppearance: "none",
border: `1px solid ${theme.palette.action.active}`,
boxSizing: "border-box",
cursor: "pointer",
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": {
background: "rgba(0, 0, 0, 0)",
content: '""',
height: 14,
outline: "0",
position: "relative",
userSelect: "none",
left: -1,
position: "absolute",
top: -1,
transition: theme.transitions.duration.short + "ms",
width: 14
},
checked: {},
disabled: {},
indeterminate: {},
root: {
"&:hover": {
background: fade(theme.palette.primary.main, 0.1)
},
alignSelf: "start",
borderRadius: "100%",
cursor: "pointer",
display: "flex",
height: 30,
justifyContent: "center",
margin: "5px 9px",
width: 30
}
});
const Checkbox = withStyles(styles, { name: "Checkbox" })(
({
WebkitAppearance: "none",
border: `1px solid ${theme.palette.action.active}`,
boxSizing: "border-box",
cursor: "pointer",
height: 14,
outline: "0",
position: "relative",
userSelect: "none",
width: 14
},
checked: {},
disabled: {},
indeterminate: {},
root: {
"&:hover": {
background: fade(theme.palette.primary.main, 0.1)
},
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,
className,
classes,
disabled,
disableClickPropagation,
indeterminate,
onChange,
value,
name,
...props
}: CheckboxProps & WithStyles<typeof styles>) => {
const inputRef = React.useRef<HTMLInputElement>(null);
const handleClick = React.useCallback(
disableClickPropagation
? event => {
event.stopPropagation();
inputRef.current.click();
}
: () => inputRef.current.click(),
[]
);
...rest
} = props;
const classes = useStyles(props);
return (
<ButtonBase
{...props}
centerRipple
className={classNames(classes.root, className)}
const inputRef = React.useRef<HTMLInputElement>(null);
const handleClick = React.useCallback(
disableClickPropagation
? event => {
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}
onClick={handleClick}
>
<input
className={classNames(classes.box, {
[classes.checked]: checked,
[classes.disabled]: disabled,
[classes.indeterminate]: indeterminate
})}
disabled={disabled}
type="checkbox"
name={name}
value={checked !== undefined && checked.toString()}
ref={inputRef}
onChange={onChange}
/>
</ButtonBase>
);
}
);
type="checkbox"
name={name}
value={checked !== undefined && checked.toString()}
ref={inputRef}
onChange={onChange}
/>
</ButtonBase>
);
};
Checkbox.displayName = "Checkbox";
export default Checkbox;

View file

@ -1,2 +1,2 @@
export { default } from './Checkbox';
export * from './Checkbox';
export { default } from "./Checkbox";
export * from "./Checkbox";

View file

@ -1,9 +1,4 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator";
import Typography from "@material-ui/core/Typography";
import CloseIcon from "@material-ui/icons/Close";
@ -16,32 +11,30 @@ export interface ChipProps {
onClose?: () => void;
}
const styles = theme =>
createStyles({
closeIcon: {
cursor: "pointer",
fontSize: 16,
marginLeft: theme.spacing(),
verticalAlign: "middle"
},
label: {
color: theme.palette.common.white
},
root: {
background: fade(theme.palette.secondary.main, 0.8),
borderRadius: 8,
display: "inline-block",
marginRight: theme.spacing(2),
padding: "6px 12px"
}
});
const Chip = withStyles(styles, { name: "Chip" })(
({
classes,
className,
label,
onClose
}: ChipProps & WithStyles<typeof styles>) => (
const useStyles = makeStyles(theme => ({
closeIcon: {
cursor: "pointer",
fontSize: 16,
marginLeft: theme.spacing(),
verticalAlign: "middle"
},
label: {
color: theme.palette.common.white
},
root: {
background: fade(theme.palette.secondary.main, 0.8),
borderRadius: 8,
display: "inline-block",
marginRight: theme.spacing(2),
padding: "6px 12px"
}
}));
const Chip: React.FC<ChipProps> = props => {
const { className, label, onClose } = props;
const classes = useStyles(props);
return (
<div className={classNames(classes.root, className)}>
<Typography className={classes.label} variant="caption">
{label}
@ -50,7 +43,7 @@ const Chip = withStyles(styles, { name: "Chip" })(
)}
</Typography>
</div>
)
);
);
};
Chip.displayName = "Chip";
export default Chip;

View file

@ -1,2 +1,2 @@
export { default } from './Chip';
export * from './Chip';
export { default } from "./Chip";
export * from "./Chip";

View file

@ -55,7 +55,7 @@ const useStyles = makeStyles(theme => ({
padding: 0
},
dropShadow: {
boxShadow: `0px -5px 10px 0px ${theme.overrides.MuiCard.root.borderColor}`
boxShadow: `0px -5px 10px 0px ${theme.palette.divider}`
},
loadMoreLoaderContainer: {
alignItems: "center",

View file

@ -1,11 +1,10 @@
import { Omit } from "@material-ui/core";
import Button, { ButtonProps } from "@material-ui/core/Button";
import CircularProgress from "@material-ui/core/CircularProgress";
import {
createStyles,
Theme,
withStyles,
WithStyles
WithStyles,
withStyles
} from "@material-ui/core/styles";
import CheckIcon from "@material-ui/icons/Check";
import { buttonMessages } from "@saleor/intl";
@ -19,7 +18,7 @@ export type ConfirmButtonTransitionState =
| "error"
| "default";
const styles = theme =>
const styles = (theme: Theme) =>
createStyles({
error: {
"&:hover": {

View file

@ -1,35 +1,31 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import classNames from "classnames";
import React from "react";
const styles = theme =>
createStyles({
root: {
[theme.breakpoints.up("lg")]: {
marginLeft: "auto",
marginRight: "auto",
maxWidth: theme.breakpoints.width("lg")
},
[theme.breakpoints.up("sm")]: {
padding: theme.spacing(0, 3)
},
padding: theme.spacing(0, 1)
}
});
const useStyles = makeStyles(theme => ({
root: {
[theme.breakpoints.up("lg")]: {
marginLeft: "auto",
marginRight: "auto",
maxWidth: theme.breakpoints.width("lg")
},
[theme.breakpoints.up("sm")]: {
padding: theme.spacing(0, 3)
},
padding: theme.spacing(0, 1)
}
}));
interface ContainerProps extends WithStyles<typeof styles> {
interface ContainerProps {
className?: string;
}
export const Container = withStyles(styles, {
name: "Container"
})(({ classes, className, ...props }: ContainerProps) => (
<div className={classNames(classes.root, className)} {...props} />
));
export const Container: React.FC<ContainerProps> = props => {
const { className, ...rest } = props;
const classes = useStyles(props);
return <div className={classNames(classes.root, className)} {...rest} />;
};
Container.displayName = "Container";
export default Container;

View file

@ -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 Switch from "@material-ui/core/Switch";
import React from "react";
const styles = theme =>
createStyles({
label: {
marginLeft: theme.spacing(3.5)
},
labelText: {
fontSize: 14
}
});
const useStyles = makeStyles(theme => ({
label: {
marginLeft: theme.spacing(3.5)
},
labelText: {
fontSize: 14
}
}));
interface ControlledSwitchProps extends WithStyles<typeof styles> {
interface ControlledSwitchProps {
checked: boolean;
disabled?: boolean;
label: string | React.ReactNode;
@ -23,11 +22,8 @@ interface ControlledSwitchProps extends WithStyles<typeof styles> {
onChange?(event: React.ChangeEvent<any>);
}
export const ControlledSwitch = withStyles(styles, {
name: "ControlledSwitch"
})(
({
classes,
export const ControlledSwitch: React.FC<ControlledSwitchProps> = props => {
const {
checked,
disabled,
onChange,
@ -35,7 +31,11 @@ export const ControlledSwitch = withStyles(styles, {
name,
secondLabel,
uncheckedLabel
}: ControlledSwitchProps) => (
} = props;
const classes = useStyles(props);
return (
<FormControlLabel
control={
<Switch
@ -65,7 +65,7 @@ export const ControlledSwitch = withStyles(styles, {
}
disabled={disabled}
/>
)
);
);
};
ControlledSwitch.displayName = "ControlledSwitch";
export default ControlledSwitch;

View file

@ -2,12 +2,7 @@ import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import IconButton from "@material-ui/core/IconButton";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
@ -32,158 +27,155 @@ export interface CountryListProps {
onCountryUnassign: (country: string) => void;
}
const styles = theme =>
createStyles({
iconCell: {
"&:last-child": {
paddingRight: 0
},
width: 48 + theme.spacing(2)
const useStyles = makeStyles(theme => ({
iconCell: {
"&:last-child": {
paddingRight: 0
},
indicator: {
color: theme.palette.text.disabled,
display: "inline-block",
left: 0,
marginRight: theme.spacing(.5),
position: "absolute"
width: 48 + theme.spacing(2)
},
indicator: {
color: theme.palette.text.disabled,
display: "inline-block",
left: 0,
marginRight: theme.spacing(0.5),
position: "absolute"
},
offsetCell: {
"&:first-child": {
paddingLeft: theme.spacing(3)
},
offsetCell: {
"&:first-child": {
paddingLeft: theme.spacing(3)
},
position: "relative"
position: "relative"
},
pointer: {
cursor: "pointer"
},
root: {
"&:last-child": {
paddingBottom: 0
},
pointer: {
cursor: "pointer"
},
root: {
"&:last-child": {
paddingBottom: 0
},
paddingTop: 0
},
rotate: {
transform: "rotate(180deg)"
},
textRight: {
textAlign: "right"
},
toLeft: {
"&:first-child": {
paddingLeft: 0
}
},
wideColumn: {
width: "100%"
paddingTop: 0
},
rotate: {
transform: "rotate(180deg)"
},
textRight: {
textAlign: "right"
},
toLeft: {
"&:first-child": {
paddingLeft: 0
}
});
},
wideColumn: {
width: "100%"
}
}));
const CountryList = withStyles(styles, {
name: "CountryList"
})(
({
classes,
const CountryList: React.FC<CountryListProps> = props => {
const {
countries,
disabled,
emptyText,
title,
onCountryAssign,
onCountryUnassign
}: CountryListProps & WithStyles<typeof styles>) => {
const [isCollapsed, setCollapseStatus] = React.useState(true);
const toggleCollapse = () => setCollapseStatus(!isCollapsed);
} = props;
const classes = useStyles(props);
return (
<Card>
<CardTitle
title={title}
toolbar={
<Button color="primary" onClick={onCountryAssign}>
<FormattedMessage
defaultMessage="Assign countries"
description="button"
/>
</Button>
}
/>
<CardContent className={classes.root}>
<Table>
<TableBody>
<TableRow className={classes.pointer} onClick={toggleCollapse}>
<TableCell
className={classNames(classes.wideColumn, classes.toLeft)}
>
<FormattedMessage
defaultMessage="{number} Countries"
description="number of countries"
values={{
number: maybe(() => countries.length.toString(), "...")
}}
const [isCollapsed, setCollapseStatus] = React.useState(true);
const toggleCollapse = () => setCollapseStatus(!isCollapsed);
return (
<Card>
<CardTitle
title={title}
toolbar={
<Button color="primary" onClick={onCountryAssign}>
<FormattedMessage
defaultMessage="Assign countries"
description="button"
/>
</Button>
}
/>
<CardContent className={classes.root}>
<Table>
<TableBody>
<TableRow className={classes.pointer} onClick={toggleCollapse}>
<TableCell
className={classNames(classes.wideColumn, classes.toLeft)}
>
<FormattedMessage
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>
<TableCell
className={classNames(classes.textRight, classes.iconCell)}
>
<IconButton>
<ArrowDropDownIcon
className={classNames({
[classes.rotate]: !isCollapsed
})}
/>
</IconButton>
</TableCell>
</TableRow>
{!isCollapsed &&
renderCollection(
countries,
(country, countryIndex) => (
<TableRow key={country ? country.code : "skeleton"}>
<TableCell className={classes.offsetCell}>
{maybe<React.ReactNode>(
() => (
<>
{(countryIndex === 0 ||
countries[countryIndex].country[0] !==
countries[countryIndex - 1].country[0]) && (
<span className={classes.indicator}>
{country.country[0]}
</span>
)}
{country.country}
</>
),
<Skeleton />
)}
</TableCell>
<TableCell
className={classNames(
classes.textRight,
classes.iconCell
)}
</IconButton>
</TableCell>
</TableRow>
{!isCollapsed &&
renderCollection(
countries,
(country, countryIndex) => (
<TableRow key={country ? country.code : "skeleton"}>
<TableCell className={classes.offsetCell}>
{maybe<React.ReactNode>(
() => (
<>
{(countryIndex === 0 ||
countries[countryIndex].country[0] !==
countries[countryIndex - 1].country[0]) && (
<span className={classes.indicator}>
{country.country[0]}
</span>
)}
{country.country}
</>
),
<Skeleton />
)}
</TableCell>
<TableCell
className={classNames(
classes.textRight,
classes.iconCell
)}
>
<IconButton
color="primary"
disabled={!country || disabled}
onClick={() => onCountryUnassign(country.code)}
>
<IconButton
color="primary"
disabled={!country || disabled}
onClick={() => onCountryUnassign(country.code)}
>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
),
() => (
<TableRow>
<TableCell className={classes.toLeft} colSpan={2}>
{emptyText}
</TableCell>
</TableRow>
)
)}
</TableBody>
</Table>
</CardContent>
</Card>
);
}
);
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
),
() => (
<TableRow>
<TableCell className={classes.toLeft} colSpan={2}>
{emptyText}
</TableCell>
</TableRow>
)
)}
</TableBody>
</Table>
</CardContent>
</Card>
);
};
export default CountryList;

View file

@ -1,7 +1,7 @@
import React from "react";
export interface DebounceProps<T> {
children: ((props: (...args: T[]) => void) => React.ReactNode);
children: (props: (...args: T[]) => void) => React.ReactNode;
debounceFn: (...args: T[]) => void;
time?: number;
}

View file

@ -1,2 +1,2 @@
export { default } from './DeleteFilterTabDialog';
export * from './DeleteFilterTabDialog';
export { default } from "./DeleteFilterTabDialog";
export * from "./DeleteFilterTabDialog";

View file

@ -1,11 +1,6 @@
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TableCell from "@material-ui/core/TableCell";
import TextField, { TextFieldProps } from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography";
@ -14,38 +9,37 @@ import React from "react";
import useForm from "@saleor/hooks/useForm";
const styles = theme =>
createStyles({
card: {
border: `1px solid ${theme.overrides.MuiCard.root.borderColor}`
},
container: {
position: "relative"
},
overlay: {
cursor: "pointer",
height: "100vh",
left: 0,
position: "fixed",
top: 0,
width: "100vw",
zIndex: 1
},
root: {
left: 0,
minWidth: theme.spacing(20),
position: "absolute",
top: 0,
width: `calc(100% + ${theme.spacing(4)}px)`,
zIndex: 2
},
text: {
cursor: "pointer",
fontSize: "0.8125rem"
}
});
const useStyles = makeStyles(theme => ({
card: {
border: `1px solid ${theme.palette.divider}`
},
container: {
position: "relative"
},
overlay: {
cursor: "pointer",
height: "100vh",
left: 0,
position: "fixed",
top: 0,
width: "100vw",
zIndex: 1
},
root: {
left: 0,
minWidth: theme.spacing(20),
position: "absolute",
top: 0,
width: `calc(100% + ${theme.spacing(4)}px)`,
zIndex: 2
},
text: {
cursor: "pointer",
fontSize: "0.8125rem"
}
}));
interface EditableTableCellProps extends WithStyles<typeof styles> {
interface EditableTableCellProps {
className?: string;
defaultValue?: string;
focused?: boolean;
@ -54,54 +48,52 @@ interface EditableTableCellProps extends WithStyles<typeof styles> {
onConfirm(value: string): any;
}
export const EditableTableCell = withStyles(styles, {
name: "EditableTableCell"
})(
({
classes,
export const EditableTableCell: React.FC<EditableTableCellProps> = props => {
const {
className,
defaultValue,
focused,
InputProps,
value,
onConfirm
}: EditableTableCellProps) => {
const handleConfirm = (data: { value: string }) => {
disable();
onConfirm(data.value);
};
} = props;
const classes = useStyles(props);
const [opened, setOpenStatus] = React.useState(focused);
const { change, data } = useForm({ value }, [], handleConfirm);
const enable = () => setOpenStatus(true);
const disable = () => setOpenStatus(false);
const handleConfirm = (data: { value: string }) => {
disable();
onConfirm(data.value);
};
return (
<TableCell className={classNames(classes.container, className)}>
{opened && <div className={classes.overlay} onClick={disable} />}
<Typography variant="caption" onClick={enable} className={classes.text}>
{value || defaultValue}
</Typography>
{opened && (
<div className={classes.root}>
<Card className={classes.card}>
<CardContent>
<TextField
name="value"
autoFocus
fullWidth
onChange={change}
value={data.value}
variant="standard"
{...InputProps}
/>
</CardContent>
</Card>
</div>
)}
</TableCell>
);
}
);
const [opened, setOpenStatus] = React.useState(focused);
const { change, data } = useForm({ value }, [], handleConfirm);
const enable = () => setOpenStatus(true);
const disable = () => setOpenStatus(false);
return (
<TableCell className={classNames(classes.container, className)}>
{opened && <div className={classes.overlay} onClick={disable} />}
<Typography variant="caption" onClick={enable} className={classes.text}>
{value || defaultValue}
</Typography>
{opened && (
<div className={classes.root}>
<Card className={classes.card}>
<CardContent>
<TextField
name="value"
autoFocus
fullWidth
onChange={change}
value={data.value}
variant="standard"
{...InputProps}
/>
</CardContent>
</Card>
</div>
)}
</TableCell>
);
};
EditableTableCell.displayName = "EditableTableCell";
export default EditableTableCell;

View file

@ -1,10 +1,5 @@
import Button from "@material-ui/core/Button";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import React from "react";
import SVG from "react-inlinesvg";
@ -12,57 +7,60 @@ import { FormattedMessage } from "react-intl";
import notFoundImage from "@assets/images/what.svg";
export interface ErrorPageProps extends WithStyles<typeof styles> {
export interface ErrorPageProps {
onBack: () => void;
}
const styles = theme =>
createStyles({
bottomHeader: {
fontWeight: 600 as 600,
textTransform: "uppercase"
const useStyles = makeStyles(theme => ({
bottomHeader: {
fontWeight: 600 as 600,
textTransform: "uppercase"
},
button: {
marginTop: theme.spacing(2),
padding: 20
},
container: {
[theme.breakpoints.down("sm")]: {
gridTemplateColumns: "1fr",
padding: theme.spacing(3),
width: "100%"
},
button: {
marginTop: theme.spacing(2),
padding: 20
display: "grid",
gridTemplateColumns: "1fr 487px",
margin: "0 auto",
width: 830
},
innerContainer: {
[theme.breakpoints.down("sm")]: {
order: 1,
textAlign: "center"
},
container: {
[theme.breakpoints.down("sm")]: {
gridTemplateColumns: "1fr",
padding: theme.spacing(3),
width: "100%"
},
display: "grid",
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
display: "flex",
flexDirection: "column",
justifyContent: "center"
},
notFoundImage: {
"& svg": {
width: "100%"
}
});
},
root: {
alignItems: "center",
display: "flex",
height: "calc(100vh - 88px)"
},
upperHeader: {
fontWeight: 600 as 600
}
}));
const ErrorPage = withStyles(styles, { name: "NotFoundPage" })(
({ classes, onBack }: ErrorPageProps) => (
const ErrorPage: React.FC<ErrorPageProps> = props => {
const { onBack } = props;
const classes = useStyles(props);
return (
<div className={classes.root}>
<div className={classes.container}>
<div className={classes.innerContainer}>
@ -99,7 +97,7 @@ const ErrorPage = withStyles(styles, { name: "NotFoundPage" })(
</div>
</div>
</div>
)
);
);
};
ErrorPage.displayName = "ErrorPage";
export default ErrorPage;

View file

@ -1,55 +1,53 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import classNames from "classnames";
import React from "react";
const styles = theme =>
createStyles({
action: {
flex: "0 0 auto"
},
grid: {
padding: theme.spacing(2)
},
menuButton: {
flex: "0 0 auto",
marginLeft: -theme.spacing(2),
marginRight: theme.spacing(3),
marginTop: -theme.spacing(2)
},
root: {
alignItems: "center",
display: "flex",
marginBottom: theme.spacing(3)
},
subtitle: {
alignItems: "center",
display: "flex",
marginBottom: theme.spacing(2)
},
title: {
flex: 1,
paddingBottom: theme.spacing(2)
}
});
const useStyles = makeStyles(theme => ({
action: {
flex: "0 0 auto"
},
grid: {
padding: theme.spacing(2)
},
menuButton: {
flex: "0 0 auto",
marginLeft: -theme.spacing(2),
marginRight: theme.spacing(3),
marginTop: -theme.spacing(2)
},
root: {
alignItems: "center",
display: "flex",
marginBottom: theme.spacing(3)
},
subtitle: {
alignItems: "center",
display: "flex",
marginBottom: theme.spacing(2)
},
title: {
flex: 1,
paddingBottom: theme.spacing(2)
}
}));
interface ExtendedPageHeaderProps extends WithStyles<typeof styles> {
interface ExtendedPageHeaderProps {
children?: React.ReactNode;
className?: string;
title?: React.ReactNode;
}
const ExtendedPageHeader = withStyles(styles, { name: "ExtendedPageHeader" })(
({ children, classes, className, title }: ExtendedPageHeaderProps) => (
const ExtendedPageHeader: React.FC<ExtendedPageHeaderProps> = props => {
const { children, className, title } = props;
const classes = useStyles(props);
return (
<div className={classNames(classes.root, className)}>
{title}
<div className={classes.action}>{children}</div>
</div>
)
);
);
};
ExtendedPageHeader.displayName = "ExtendedPageHeader";
export default ExtendedPageHeader;

View file

@ -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 React from "react";
const styles = createStyles({
const useStyles = makeStyles({
link: {
textDecoration: "none"
}
});
interface ExternalLinkProps
extends React.HTMLProps<HTMLAnchorElement>,
WithStyles<typeof styles> {
interface ExternalLinkProps extends React.HTMLProps<HTMLAnchorElement> {
href: string;
className?: string;
typographyProps?: TypographyProps;
}
const ExternalLink = withStyles(styles, { name: "ExternalLink" })(
({
classes,
className,
children,
href,
typographyProps,
...props
}: ExternalLinkProps) => (
<a href={href} className={classes.link} {...props}>
const ExternalLink: React.FC<ExternalLinkProps> = props => {
const { className, children, href, typographyProps, ...rest } = props;
const classes = useStyles(props);
return (
<a href={href} className={classes.link} {...rest}>
<Typography className={className} color="primary" {...typographyProps}>
{children}
</Typography>
</a>
)
);
);
};
ExternalLink.displayName = "ExternalLink";
export default ExternalLink;

View file

@ -1,10 +1,10 @@
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 React from "react";
import { FormattedMessage } from "react-intl";
const styles = createStyles({
const useStyles = makeStyles({
fileUploadField: {
display: "none"
},
@ -16,15 +16,19 @@ const styles = createStyles({
}
});
interface FileUploadProps extends WithStyles<typeof styles> {
interface FileUploadProps {
disabled?: boolean;
name?: string;
value?: any;
onChange?(event: React.ChangeEvent<any>);
}
const FileUpload = withStyles(styles, { name: "FileUpload" })(
({ classes, disabled, name, value, onChange }: FileUploadProps) => (
const FileUpload: React.FC<FileUploadProps> = props => {
const { disabled, name, value, onChange } = props;
const classes = useStyles(props);
return (
<div className={classes.root}>
<input
disabled={disabled}
@ -48,7 +52,7 @@ const FileUpload = withStyles(styles, { name: "FileUpload" })(
/>
</Button>
</div>
)
);
);
};
FileUpload.displayName = "FileUpload";
export default FileUpload;

View file

@ -2,7 +2,7 @@ import ButtonBase from "@material-ui/core/ButtonBase";
import Grow from "@material-ui/core/Grow";
import Paper from "@material-ui/core/Paper";
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 Typography from "@material-ui/core/Typography";
import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown";
@ -21,129 +21,120 @@ export interface FilterProps<TFilterKeys = string> {
onFilterAdd: (filter: FilterContentSubmitData) => void;
}
const styles = theme =>
createStyles({
addFilterButton: {
"&$filterButton": {
"&: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": {
const useStyles = makeStyles(theme => ({
addFilterButton: {
"&$filterButton": {
"&:hover, &:focus": {
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),
padding: theme.spacing(2),
width: 240
},
popover: {
zIndex: 1
},
rotate: {
transform: "rotate(180deg)"
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"
}
});
const Filter = withStyles(styles, { name: "Filter" })(
({
classes,
currencySymbol,
filterLabel,
menu,
onFilterAdd
}: FilterProps & WithStyles<typeof styles>) => {
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>
);
},
addFilterButtonActive: {
"&$addFilterButton": {
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),
padding: theme.spacing(2),
width: 240
},
popover: {
zIndex: 1
},
rotate: {
transform: "rotate(180deg)"
}
);
}));
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";
export default Filter;

View file

@ -17,6 +17,7 @@ const useInputStyles = makeStyles({
const Search: React.FC<TextFieldProps> = props => {
const classes = useInputStyles({});
return (
<TextField
{...props}

View file

@ -1,2 +1,2 @@
export { default } from './FilterBar';
export * from './FilterBar';
export { default } from "./FilterBar";
export * from "./FilterBar";

View file

@ -1,27 +1,23 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import React from "react";
const styles = theme =>
createStyles({
spacer: {
marginTop: theme.spacing(3)
}
});
const useStyles = makeStyles(theme => ({
spacer: {
marginTop: theme.spacing(3)
}
}));
interface FormSpacerProps extends WithStyles<typeof styles> {
interface FormSpacerProps {
children?: React.ReactNode;
}
export const FormSpacer = withStyles(styles, { name: "FormSpacer" })(
({ classes, children }: FormSpacerProps) => (
<div className={classes.spacer}>{children}</div>
)
);
export const FormSpacer: React.FC<FormSpacerProps> = props => {
const { children } = props;
const classes = useStyles(props);
return <div className={classes.spacer}>{children}</div>;
};
FormSpacer.displayName = "FormSpacer";
export default FormSpacer;

View file

@ -1,43 +1,41 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import classNames from "classnames";
import React from "react";
export type GridVariant = "default" | "inverted" | "uniform";
export interface GridProps extends WithStyles<typeof styles> {
export interface GridProps {
children: React.ReactNodeArray | React.ReactNode;
className?: string;
variant?: GridVariant;
}
const styles = theme =>
createStyles({
default: {
gridTemplateColumns: "9fr 4fr"
},
inverted: {
gridTemplateColumns: "4fr 9fr"
},
root: {
display: "grid",
gridColumnGap: theme.spacing(3),
gridRowGap: theme.spacing(3),
[theme.breakpoints.down("sm")]: {
gridRowGap: theme.spacing(1),
gridTemplateColumns: "1fr"
}
},
uniform: {
gridTemplateColumns: "1fr 1fr"
const useStyles = makeStyles(theme => ({
default: {
gridTemplateColumns: "9fr 4fr"
},
inverted: {
gridTemplateColumns: "4fr 9fr"
},
root: {
display: "grid",
gridColumnGap: theme.spacing(3),
gridRowGap: theme.spacing(3),
[theme.breakpoints.down("sm")]: {
gridRowGap: theme.spacing(1),
gridTemplateColumns: "1fr"
}
});
},
uniform: {
gridTemplateColumns: "1fr 1fr"
}
}));
export const Grid = withStyles(styles, { name: "Grid" })(
({ className, children, classes, variant }: GridProps) => (
export const Grid: React.FC<GridProps> = props => {
const { className, children, variant } = props;
const classes = useStyles(props);
return (
<div
className={classNames(className, classes.root, {
[classes.default]: variant === "default",
@ -47,8 +45,8 @@ export const Grid = withStyles(styles, { name: "Grid" })(
>
{children}
</div>
)
);
);
};
Grid.displayName = "Grid";
Grid.defaultProps = {
variant: "default"

View file

@ -1,9 +1,4 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import classNames from "classnames";
import React from "react";
@ -11,22 +6,23 @@ interface HrProps {
className?: string;
}
const styles = theme =>
createStyles({
root: {
backgroundColor: theme.overrides.MuiCard.root.borderColor,
border: "none",
display: "block",
height: 1,
margin: 0,
width: "100%"
}
});
const useStyles = makeStyles(theme => ({
root: {
backgroundColor: theme.palette.divider,
border: "none",
display: "block",
height: 1,
margin: 0,
width: "100%"
}
}));
export const Hr = withStyles(styles, { name: "Hr" })(
({ className, classes }: HrProps & WithStyles<typeof styles>) => (
<hr className={classNames(classes.root, className)} />
)
);
export const Hr: React.FC<HrProps> = props => {
const { className } = props;
const classes = useStyles(props);
return <hr className={classNames(classes.root, className)} />;
};
Hr.displayName = "Hr";
export default Hr;

View file

@ -1,10 +1,5 @@
import IconButton from "@material-ui/core/IconButton";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TableCell from "@material-ui/core/TableCell";
import React from "react";
@ -17,23 +12,26 @@ export interface IconButtonTableCellProps {
onClick: () => void;
}
const styles = theme =>
createStyles({
root: {
"&:last-child": {
paddingRight: 0
},
paddingRight: 0,
width: ICONBUTTON_SIZE + theme.spacing(.5)
}
});
const IconButtonTableCell = withStyles(styles, { name: "IconButtonTableCell" })(
({
const useStyles = makeStyles(theme => ({
root: {
"&:last-child": {
paddingRight: 0
},
paddingRight: 0,
width: ICONBUTTON_SIZE + theme.spacing(0.5)
}
}));
const IconButtonTableCell: React.FC<IconButtonTableCellProps> = props => {
const {
children,
classes,
disabled,
onClick
}: IconButtonTableCellProps & WithStyles<typeof styles>) => (
} = props;
const classes = useStyles(props);
return (
<TableCell className={classes.root}>
<IconButton
color="primary"
@ -43,7 +41,7 @@ const IconButtonTableCell = withStyles(styles, { name: "IconButtonTableCell" })(
{children}
</IconButton>
</TableCell>
)
);
);
};
IconButtonTableCell.displayName = "IconButtonTableCell";
export default IconButtonTableCell;

View file

@ -1,2 +1,2 @@
export { default } from './IconButtonTableCell';
export * from './IconButtonTableCell';
export { default } from "./IconButtonTableCell";
export * from "./IconButtonTableCell";

View file

@ -1,55 +1,49 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import React from "react";
import IconButton from "@material-ui/core/IconButton";
import DeleteIcon from "@material-ui/icons/Delete";
import EditIcon from "@material-ui/icons/Edit";
const styles = theme =>
createStyles({
image: {
height: "100%",
objectFit: "contain",
userSelect: "none",
width: "100%"
const useStyles = makeStyles(theme => ({
image: {
height: "100%",
objectFit: "contain",
userSelect: "none",
width: "100%"
},
imageContainer: {
"&:hover, &.dragged": {
"& $imageOverlay": {
display: "block"
}
},
imageContainer: {
"&:hover, &.dragged": {
"& $imageOverlay": {
display: "block"
}
},
background: theme.palette.background.paper,
border: `1px solid ${theme.overrides.MuiCard.root.borderColor}`,
borderRadius: theme.spacing(),
height: 148,
overflow: "hidden",
padding: theme.spacing(2),
position: "relative",
width: 148
},
imageOverlay: {
background: "rgba(0, 0, 0, 0.6)",
cursor: "move",
display: "none",
height: 148,
left: 0,
position: "absolute",
top: 0,
width: 148
},
imageOverlayToolbar: {
display: "flex",
justifyContent: "flex-end"
}
});
background: theme.palette.background.paper,
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.spacing(),
height: 148,
overflow: "hidden",
padding: theme.spacing(2),
position: "relative",
width: 148
},
imageOverlay: {
background: "rgba(0, 0, 0, 0.6)",
cursor: "move",
display: "none",
height: 148,
left: 0,
position: "absolute",
top: 0,
width: 148
},
imageOverlayToolbar: {
display: "flex",
justifyContent: "flex-end"
}
}));
interface ImageTileProps extends WithStyles<typeof styles> {
interface ImageTileProps {
image: {
alt?: string;
url: string;
@ -58,8 +52,12 @@ interface ImageTileProps extends WithStyles<typeof styles> {
onImageEdit?: (event: React.ChangeEvent<any>) => void;
}
const ImageTile = withStyles(styles, { name: "ImageTile" })(
({ classes, onImageDelete, onImageEdit, image }: ImageTileProps) => (
const ImageTile: React.FC<ImageTileProps> = props => {
const { onImageDelete, onImageEdit, image } = props;
const classes = useStyles(props);
return (
<div className={classes.imageContainer} data-tc="product-image">
<div className={classes.imageOverlay}>
<div className={classes.imageOverlayToolbar}>
@ -77,7 +75,7 @@ const ImageTile = withStyles(styles, { name: "ImageTile" })(
</div>
<img className={classes.image} src={image.url} alt={image.alt} />
</div>
)
);
);
};
ImageTile.displayName = "ImageTile";
export default ImageTile;

View file

@ -1,9 +1,4 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator";
import Typography from "@material-ui/core/Typography";
import classNames from "classnames";
@ -22,55 +17,58 @@ interface ImageUploadProps {
onImageUpload: (file: File) => void;
}
const styles = theme =>
createStyles({
containerDragActive: {
background: fade(theme.palette.primary.main, 0.1),
color: theme.palette.primary.main
},
fileField: {
display: "none"
},
imageContainer: {
background: "#ffffff",
border: "1px solid #eaeaea",
borderRadius: theme.spacing(),
height: 148,
justifySelf: "start",
overflow: "hidden",
padding: theme.spacing(2),
position: "relative",
transition: theme.transitions.duration.standard + "s",
width: 148
},
photosIcon: {
height: "64px",
margin: "0 auto",
width: "64px"
},
photosIconContainer: {
padding: theme.spacing(5, 0),
textAlign: "center"
},
uploadText: {
color: theme.typography.body1.color,
fontSize: 12,
fontWeight: 600,
textTransform: "uppercase"
}
});
const useStyles = makeStyles(theme => ({
containerDragActive: {
background: fade(theme.palette.primary.main, 0.1),
color: theme.palette.primary.main
},
fileField: {
display: "none"
},
imageContainer: {
background: "#ffffff",
border: "1px solid #eaeaea",
borderRadius: theme.spacing(),
height: 148,
justifySelf: "start",
overflow: "hidden",
padding: theme.spacing(2),
position: "relative",
transition: theme.transitions.duration.standard + "s",
width: 148
},
photosIcon: {
height: "64px",
margin: "0 auto",
width: "64px"
},
photosIconContainer: {
padding: theme.spacing(5, 0),
textAlign: "center"
},
uploadText: {
color: theme.typography.body1.color,
fontSize: 12,
fontWeight: 600,
textTransform: "uppercase"
}
}));
export const ImageUpload = withStyles(styles, { name: "ImageUpload" })(
({
export const ImageUpload: React.FC<ImageUploadProps> = props => {
const {
children,
classes,
className,
disableClick,
isActiveClassName,
iconContainerActiveClassName,
iconContainerClassName,
onImageUpload
}: ImageUploadProps & WithStyles<typeof styles>) => (
} = props;
const classes = useStyles(props);
return (
<Dropzone
disableClick={disableClick}
onDrop={files => onImageUpload(files[0])}
@ -107,7 +105,7 @@ export const ImageUpload = withStyles(styles, { name: "ImageUpload" })(
</>
)}
</Dropzone>
)
);
);
};
ImageUpload.displayName = "ImageUpload";
export default ImageUpload;

View file

@ -5,12 +5,7 @@ import MenuItem from "@material-ui/core/MenuItem";
import Menu from "@material-ui/core/MenuList";
import Paper from "@material-ui/core/Paper";
import Popper from "@material-ui/core/Popper";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import ArrowDropDown from "@material-ui/icons/ArrowDropDown";
import classNames from "classnames";
@ -26,109 +21,104 @@ export interface LanguageSwitchProps {
onLanguageChange: (lang: LanguageCodeEnum) => void;
}
const styles = theme =>
createStyles({
arrow: {
color: theme.palette.primary.main,
transition: theme.transitions.duration.standard + "ms"
},
container: {
paddingBottom: theme.spacing(1)
},
menuContainer: {
cursor: "pointer",
display: "flex",
justifyContent: "space-between",
minWidth: 90,
padding: theme.spacing(),
position: "relative"
},
menuItem: {
textAlign: "justify"
},
menuPaper: {
maxHeight: `calc(100vh - ${theme.spacing(2)}px)`,
overflow: "scroll"
},
popover: {
zIndex: 1
},
rotate: {
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 useStyles = makeStyles(theme => ({
arrow: {
color: theme.palette.primary.main,
transition: theme.transitions.duration.standard + "ms"
},
container: {
paddingBottom: theme.spacing(1)
},
menuContainer: {
cursor: "pointer",
display: "flex",
justifyContent: "space-between",
minWidth: 90,
padding: theme.spacing(),
position: "relative"
},
menuItem: {
textAlign: "justify"
},
menuPaper: {
maxHeight: `calc(100vh - ${theme.spacing(2)}px)`,
overflow: "scroll"
},
popover: {
zIndex: 1
},
rotate: {
transform: "rotate(180deg)"
}
);
}));
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";
export default LanguageSwitch;

View file

@ -1,2 +1,2 @@
export { default } from './LanguageSwitch';
export * from './LanguageSwitch';
export { default } from "./LanguageSwitch";
export * from "./LanguageSwitch";

View file

@ -1,49 +1,44 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography, { TypographyProps } from "@material-ui/core/Typography";
import classNames from "classnames";
import React from "react";
const styles = theme =>
createStyles({
primary: {
color: theme.palette.primary.main
},
root: {
cursor: "pointer",
display: "inline"
},
secondary: {
color: theme.palette.primary.main
},
underline: {
textDecoration: "underline"
}
});
const useStyles = makeStyles(theme => ({
primary: {
color: theme.palette.primary.main
},
root: {
cursor: "pointer",
display: "inline"
},
secondary: {
color: theme.palette.primary.main
},
underline: {
textDecoration: "underline"
}
}));
interface LinkProps
extends React.AnchorHTMLAttributes<HTMLAnchorElement>,
WithStyles<typeof styles> {
interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
color?: "primary" | "secondary";
underline?: boolean;
typographyProps?: TypographyProps;
onClick: () => void;
}
const Link = withStyles(styles, { name: "Link" })(
({
classes,
const Link: React.FC<LinkProps> = props => {
const {
className,
children,
color = "primary",
underline = false,
onClick,
...linkProps
}: LinkProps) => (
} = props;
const classes = useStyles(props);
return (
<Typography
component="a"
className={classNames({
@ -59,7 +54,7 @@ const Link = withStyles(styles, { name: "Link" })(
>
{children}
</Typography>
)
);
);
};
Link.displayName = "Link";
export default Link;

View file

@ -1,4 +1,3 @@
import { Omit } from "@material-ui/core";
import Button from "@material-ui/core/Button";
import {
createStyles,
@ -17,7 +16,7 @@ interface ListFieldState {
value: string;
}
const styles = theme =>
const styles = (theme: Theme) =>
createStyles({
chip: {
marginBottom: theme.spacing(1)

View file

@ -2,15 +2,13 @@ import React from "react";
interface MenuToggleProps {
ariaOwns?: string;
children: ((
props: {
actions: {
open: () => void;
close: () => void;
};
open: boolean;
}
) => React.ReactElement<any>);
children: (props: {
actions: {
open: () => void;
close: () => void;
};
open: boolean;
}) => React.ReactElement<any>;
}
interface MenuToggleState {

View file

@ -1,15 +1,15 @@
import Money from "./Money";
import { IMoney } from "./Money";
export { default } from "./Money";
export * from "./Money";
export function addMoney(init: Money, ...args: Money[]): Money {
export function addMoney(init: IMoney, ...args: IMoney[]): IMoney {
return {
amount: args.reduce((acc, curr) => acc + curr.amount, init.amount),
currency: init.currency
};
}
export function subtractMoney(init: Money, ...args: Money[]): Money {
export function subtractMoney(init: IMoney, ...args: IMoney[]): IMoney {
return {
amount: args.reduce((acc, curr) => acc - curr.amount, init.amount),
currency: init.currency

View file

@ -2,7 +2,7 @@ import React from "react";
import { useIntl } from "react-intl";
import { LocaleConsumer } from "../Locale";
import IMoney from "../Money";
import { IMoney } from "../Money";
export interface MoneyRangeProps {
from?: IMoney;

View file

@ -1,2 +1,2 @@
export { default } from './MoneyRange';
export * from './MoneyRange';
export { default } from "./MoneyRange";
export * from "./MoneyRange";

View file

@ -1,10 +1,5 @@
import IconButton from "@material-ui/core/IconButton";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography";
import CloseIcon from "@material-ui/icons/Close";
@ -20,43 +15,42 @@ import MultiAutocompleteSelectFieldContent, {
MultiAutocompleteChoiceType
} from "./MultiAutocompleteSelectFieldContent";
const styles = theme =>
createStyles({
chip: {
width: "100%"
},
chipClose: {
height: 32,
padding: 0,
width: 32
},
chipContainer: {
display: "flex",
flexDirection: "column",
marginTop: theme.spacing(1)
},
chipInner: {
"& 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: {
const useStyles = makeStyles(theme => ({
chip: {
width: "100%"
},
chipClose: {
height: 32,
padding: 0,
width: 32
},
chipContainer: {
display: "flex",
flexDirection: "column",
marginTop: theme.spacing(1)
},
chipInner: {
"& svg": {
color: theme.palette.primary.contrastText
},
container: {
flexGrow: 1,
position: "relative"
}
});
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
},
container: {
flexGrow: 1,
position: "relative"
}
}));
export interface MultiAutocompleteSelectFieldProps
extends Partial<FetchMoreProps> {
@ -77,14 +71,15 @@ const DebounceAutocomplete: React.ComponentType<
DebounceProps<string>
> = Debounce;
export const MultiAutocompleteSelectFieldComponent = withStyles(styles, {
name: "MultiAutocompleteSelectField"
})(
({
const MultiAutocompleteSelectFieldComponent: React.FC<
MultiAutocompleteSelectFieldProps
> = props => {
const {
allowCustomValues,
choices,
classes,
displayValues,
hasMore,
helperText,
label,
@ -95,107 +90,109 @@ export const MultiAutocompleteSelectFieldComponent = withStyles(styles, {
fetchChoices,
onChange,
onFetchMore,
...props
}: MultiAutocompleteSelectFieldProps & WithStyles<typeof styles>) => {
const handleSelect = (
item: string,
downshiftOpts?: ControllerStateAndHelpers
) => {
if (downshiftOpts) {
downshiftOpts.reset({ inputValue: "" });
}
onChange({
target: { name, value: item }
} as any);
};
...rest
} = props;
const classes = useStyles(props);
return (
<>
<Downshift
onInputValueChange={fetchChoices}
onSelect={handleSelect}
itemToString={() => ""}
>
{({
getInputProps,
getItemProps,
isOpen,
toggleMenu,
highlightedIndex,
inputValue
}) => {
const displayCustomValue =
inputValue &&
inputValue.length > 0 &&
allowCustomValues &&
!choices.find(
choice =>
choice.label.toLowerCase() === inputValue.toLowerCase()
);
const handleSelect = (
item: string,
downshiftOpts?: ControllerStateAndHelpers
) => {
if (downshiftOpts) {
downshiftOpts.reset({ inputValue: "" });
}
onChange({
target: { name, value: item }
} as any);
};
return (
<div className={classes.container} {...props}>
<TextField
InputProps={{
...getInputProps({
placeholder
}),
endAdornment: (
<div>
<ArrowDropdownIcon onClick={toggleMenu} />
</div>
),
id: undefined,
onClick: toggleMenu
}}
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>
return (
<>
<Downshift
onInputValueChange={fetchChoices}
onSelect={handleSelect}
itemToString={() => ""}
>
{({
getInputProps,
getItemProps,
isOpen,
toggleMenu,
highlightedIndex,
inputValue
}) => {
const displayCustomValue =
inputValue &&
inputValue.length > 0 &&
allowCustomValues &&
!choices.find(
choice => choice.label.toLowerCase() === inputValue.toLowerCase()
);
}}
</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>
return (
<div className={classes.container} {...rest}>
<TextField
InputProps={{
...getInputProps({
placeholder
}),
endAdornment: (
<div>
<ArrowDropdownIcon onClick={() => toggleMenu()} />
</div>
),
id: undefined,
onClick: toggleMenu
}}
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>
</>
);
}
);
);
}}
</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<
MultiAutocompleteSelectFieldProps
> = ({ choices, fetchChoices, ...props }) => {
const [query, setQuery] = React.useState("");
if (fetchChoices) {
return (
<DebounceAutocomplete debounceFn={fetchChoices}>
@ -220,5 +217,6 @@ const MultiAutocompleteSelectField: React.FC<
/>
);
};
MultiAutocompleteSelectField.displayName = "MultiAutocompleteSelectField";
export default MultiAutocompleteSelectField;

View file

@ -4,34 +4,28 @@ import FormHelperText from "@material-ui/core/FormHelperText";
import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
import Select, { SelectProps } from "@material-ui/core/Select";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import React from "react";
import { FormattedMessage } from "react-intl";
import Checkbox from "../Checkbox";
const styles = theme =>
createStyles({
checkbox: {
marginRight: -theme.spacing(2)
},
formControl: {
width: "100%"
},
menuItem: {
alignItems: "center",
display: "flex",
justifyContent: "space-between",
width: "100%"
}
});
const useStyles = makeStyles(theme => ({
checkbox: {
marginRight: -theme.spacing(2)
},
formControl: {
width: "100%"
},
menuItem: {
alignItems: "center",
display: "flex",
justifyContent: "space-between",
width: "100%"
}
}));
interface MultiSelectFieldProps extends WithStyles<typeof styles> {
interface MultiSelectFieldProps {
choices: Array<{
value: string;
label: string;
@ -46,11 +40,8 @@ interface MultiSelectFieldProps extends WithStyles<typeof styles> {
onChange(event: any);
}
export const MultiSelectField = withStyles(styles, {
name: "MultiSelectField"
})(
({
classes,
export const MultiSelectField: React.FC<MultiSelectFieldProps> = props => {
const {
disabled,
error,
label,
@ -60,66 +51,67 @@ export const MultiSelectField = withStyles(styles, {
name,
hint,
selectProps
}: MultiSelectFieldProps) => {
const choicesByKey = disabled
? {}
: choices.reduce((prev, curr) => {
prev[curr.value] = curr.label;
return prev;
}, {});
} = props;
const classes = useStyles(props);
return (
<FormControl
className={classes.formControl}
error={error}
disabled={disabled}
const choicesByKey = disabled
? {}
: choices.reduce((prev, curr) => {
prev[curr.value] = curr.label;
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>}
<Select
multiple
fullWidth
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
);
{choices.length > 0 ? (
choices.map(choice => {
const isSelected = !!value.find(
selectedChoice => selectedChoice === choice.value
);
return (
<MenuItem value={choice.value} key={choice.value}>
<div className={classes.menuItem}>
<span>{choice.label}</span>
<Checkbox
className={classes.checkbox}
checked={isSelected}
disableRipple={true}
disableTouchRipple={true}
/>
</div>
</MenuItem>
);
})
) : (
<MenuItem disabled={true}>
<FormattedMessage defaultMessage="No results found" />
</MenuItem>
)}
</Select>
{hint && <FormHelperText>{hint}</FormHelperText>}
</FormControl>
);
}
);
return (
<MenuItem value={choice.value} key={choice.value}>
<div className={classes.menuItem}>
<span>{choice.label}</span>
<Checkbox
className={classes.checkbox}
checked={isSelected}
disableRipple={true}
disableTouchRipple={true}
/>
</div>
</MenuItem>
);
})
) : (
<MenuItem disabled={true}>
<FormattedMessage defaultMessage="No results found" />
</MenuItem>
)}
</Select>
{hint && <FormHelperText>{hint}</FormHelperText>}
</FormControl>
);
};
MultiSelectField.defaultProps = {
value: []
};

View file

@ -1,10 +1,5 @@
import Button from "@material-ui/core/Button";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import React from "react";
import SVG from "react-inlinesvg";
@ -12,54 +7,57 @@ import { FormattedMessage } from "react-intl";
import notFoundImage from "@assets/images/not-found-404.svg";
const styles = theme =>
createStyles({
button: {
marginTop: theme.spacing(2),
padding: 20
const useStyles = makeStyles(theme => ({
button: {
marginTop: theme.spacing(2),
padding: 20
},
container: {
[theme.breakpoints.down("sm")]: {
gridTemplateColumns: "1fr",
padding: theme.spacing(3),
width: "100%"
},
container: {
[theme.breakpoints.down("sm")]: {
gridTemplateColumns: "1fr",
padding: theme.spacing(3),
width: "100%"
},
display: "grid",
gridTemplateColumns: "1fr 487px",
margin: "0 auto",
width: 830
display: "grid",
gridTemplateColumns: "1fr 487px",
margin: "0 auto",
width: 830
},
header: {
fontWeight: 600 as 600
},
innerContainer: {
[theme.breakpoints.down("sm")]: {
order: 1,
textAlign: "center"
},
header: {
fontWeight: 600 as 600
},
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: "100vh",
width: "100vw"
display: "flex",
flexDirection: "column",
justifyContent: "center"
},
notFoundImage: {
"& svg": {
width: "100%"
}
});
},
root: {
alignItems: "center",
display: "flex",
height: "100vh",
width: "100vw"
}
}));
interface NotFoundPageProps extends WithStyles<typeof styles> {
interface NotFoundPageProps {
onBack: () => void;
}
const NotFoundPage = withStyles(styles, { name: "NotFoundPage" })(
({ classes, onBack }: NotFoundPageProps) => (
const NotFoundPage: React.FC<NotFoundPageProps> = props => {
const { onBack } = props;
const classes = useStyles(props);
return (
<div className={classes.root}>
<div className={classes.container}>
<div className={classes.innerContainer}>
@ -93,7 +91,7 @@ const NotFoundPage = withStyles(styles, { name: "NotFoundPage" })(
</div>
</div>
</div>
)
);
);
};
NotFoundPage.displayName = "NotFoundPage";
export default NotFoundPage;

View file

@ -1,35 +1,33 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import React from "react";
import ExtendedPageHeader from "../ExtendedPageHeader";
import Skeleton from "../Skeleton";
const styles = theme =>
createStyles({
root: {
display: "flex"
},
title: {
flex: 1,
fontSize: 24,
paddingBottom: theme.spacing(2)
}
});
const useStyles = makeStyles(theme => ({
root: {
display: "flex"
},
title: {
flex: 1,
fontSize: 24,
paddingBottom: theme.spacing(2)
}
}));
interface PageHeaderProps extends WithStyles<typeof styles> {
interface PageHeaderProps {
children?: React.ReactNode;
className?: string;
title?: string;
}
const PageHeader = withStyles(styles)(
({ children, classes, className, title }: PageHeaderProps) => (
const PageHeader: React.FC<PageHeaderProps> = props => {
const { children, className, title } = props;
const classes = useStyles(props);
return (
<ExtendedPageHeader
className={className}
title={
@ -40,7 +38,8 @@ const PageHeader = withStyles(styles)(
>
<div className={classes.root}>{children}</div>
</ExtendedPageHeader>
)
);
);
};
PageHeader.displayName = "PageHeader";
export default PageHeader;

View file

@ -1,24 +1,18 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import React from "react";
import SingleSelectField from "@saleor/components/SingleSelectField";
const styles = theme =>
createStyles({
root: {
display: "grid",
gridColumnGap: theme.spacing(2),
gridTemplateColumns: "5rem 1fr"
}
});
const useStyles = makeStyles(theme => ({
root: {
display: "grid",
gridColumnGap: theme.spacing(2),
gridTemplateColumns: "5rem 1fr"
}
}));
interface PhoneFieldProps extends WithStyles<typeof styles> {
interface PhoneFieldProps {
name: string;
prefix: string;
number: string;
@ -27,16 +21,19 @@ interface PhoneFieldProps extends WithStyles<typeof styles> {
onChange(event: React.ChangeEvent<any>);
}
const PhoneField = withStyles(styles, { name: "PhoneField" })(
({
classes,
const PhoneField: React.FC<PhoneFieldProps> = props => {
const {
name,
number: phoneNumber,
prefix,
prefixes,
label,
onChange
}: PhoneFieldProps) => (
} = props;
const classes = useStyles(props);
return (
<div className={classes.root}>
<SingleSelectField
name={name + "_prefix"}
@ -52,7 +49,7 @@ const PhoneField = withStyles(styles, { name: "PhoneField" })(
label="&nbsp;"
/>
</div>
)
);
);
};
PhoneField.displayName = "PhoneField";
export default PhoneField;

View file

@ -1,32 +1,31 @@
import { InputProps } from "@material-ui/core/Input";
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 React from "react";
const styles = theme =>
createStyles({
currencySymbol: {
fontSize: "0.875rem"
},
inputContainer: {
display: "grid",
gridTemplateColumns: "1fr 2rem 1fr"
},
pullDown: {
marginTop: theme.spacing(2)
},
separator: {
marginTop: theme.spacing(3),
textAlign: "center",
width: "100%"
},
widgetContainer: {
marginTop: theme.spacing(2)
}
});
const useStyles = makeStyles(theme => ({
currencySymbol: {
fontSize: "0.875rem"
},
inputContainer: {
display: "grid",
gridTemplateColumns: "1fr 2rem 1fr"
},
pullDown: {
marginTop: theme.spacing(2)
},
separator: {
marginTop: theme.spacing(3),
textAlign: "center",
width: "100%"
},
widgetContainer: {
marginTop: theme.spacing(2)
}
}));
interface PriceFieldProps extends WithStyles<typeof styles> {
interface PriceFieldProps {
className?: string;
currencySymbol?: string;
disabled?: boolean;
@ -39,8 +38,8 @@ interface PriceFieldProps extends WithStyles<typeof styles> {
onChange(event: any);
}
export const PriceField = withStyles(styles, { name: "PriceField" })(
({
export const PriceField: React.FC<PriceFieldProps> = props => {
const {
className,
disabled,
error,
@ -48,11 +47,14 @@ export const PriceField = withStyles(styles, { name: "PriceField" })(
hint,
currencySymbol,
name,
classes,
onChange,
value,
InputProps
}: PriceFieldProps) => (
} = props;
const classes = useStyles(props);
return (
<TextField
className={className}
error={error}
@ -75,8 +77,8 @@ export const PriceField = withStyles(styles, { name: "PriceField" })(
disabled={disabled}
onChange={onChange}
/>
)
);
);
};
PriceField.defaultProps = {
name: "price"
};

View file

@ -2,11 +2,11 @@ import FormControl from "@material-ui/core/FormControl";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Radio from "@material-ui/core/Radio";
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 React from "react";
const styles = createStyles({
const useStyles = makeStyles({
formControl: {
padding: 0,
width: "100%"
@ -37,12 +37,9 @@ interface RadioSwitchFieldProps {
onChange: (event: React.ChangeEvent<any>) => void;
}
export const RadioSwitchField = withStyles(styles, {
name: "RadioSwitchField"
})(
({
export const RadioSwitchField: React.FC<RadioSwitchFieldProps> = props => {
const {
className,
classes,
disabled,
error,
firstOptionLabel,
@ -50,48 +47,49 @@ export const RadioSwitchField = withStyles(styles, {
name,
secondOptionLabel,
value
}: RadioSwitchFieldProps & WithStyles<typeof styles>) => {
const initialValue = value ? "true" : "false";
} = props;
const classes = useStyles(props);
const change = event => {
onChange({
target: {
name: event.target.name,
value: event.target.value === "true" ? true : false
}
} as any);
};
const initialValue = value ? "true" : "false";
return (
<FormControl
className={classNames(classes.formControl, className)}
error={error}
disabled={disabled}
const change = event => {
onChange({
target: {
name: event.target.name,
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
aria-label={name}
<FormControlLabel
value="true"
className={classes.radioLabel}
control={<Radio color="primary" />}
label={firstOptionLabel}
name={name}
value={initialValue}
onChange={event => change(event)}
>
<FormControlLabel
value="true"
className={classes.radioLabel}
control={<Radio color="primary" />}
label={firstOptionLabel}
name={name}
/>
<FormControlLabel
value="false"
className={classes.radioLabel}
control={<Radio color="primary" />}
label={secondOptionLabel}
name={name}
/>
</RadioGroup>
</FormControl>
);
}
);
/>
<FormControlLabel
value="false"
className={classes.radioLabel}
control={<Radio color="primary" />}
label={secondOptionLabel}
name={name}
/>
</RadioGroup>
</FormControl>
);
};
RadioSwitchField.displayName = "RadioSwitchField";
export default RadioSwitchField;

View file

@ -4,12 +4,7 @@ import Grow from "@material-ui/core/Grow";
import IconButton from "@material-ui/core/IconButton";
import Paper from "@material-ui/core/Paper";
import Popper from "@material-ui/core/Popper";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import DeleteIcon from "@material-ui/icons/Delete";
import { ContentState } from "draft-js";
import React from "react";
@ -23,92 +18,84 @@ interface ImageEntityProps {
onRemove: (entityKey: string) => void;
}
const styles = theme =>
createStyles({
anchor: {
display: "inline-block"
},
container: {
alignItems: "center",
display: "flex"
},
image: { maxWidth: "100%" },
inline: {
display: "inline-block"
},
root: {
alignItems: "center",
display: "flex",
minHeight: 72,
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 useStyles = makeStyles(theme => ({
anchor: {
display: "inline-block"
},
container: {
alignItems: "center",
display: "flex"
},
image: { maxWidth: "100%" },
inline: {
display: "inline-block"
},
root: {
alignItems: "center",
display: "flex",
minHeight: 72,
padding: theme.spacing(1.5)
}
);
}));
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;

View file

@ -4,12 +4,7 @@ import Grow from "@material-ui/core/Grow";
import IconButton from "@material-ui/core/IconButton";
import Paper from "@material-ui/core/Paper";
import Popper from "@material-ui/core/Popper";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import DeleteIcon from "@material-ui/icons/Delete";
import { ContentState } from "draft-js";
@ -27,106 +22,97 @@ interface LinkEntityProps {
onRemove: (entityKey: string) => void;
}
const styles = theme =>
createStyles({
anchor: {
display: "inline-block"
},
container: {
alignItems: "center",
display: "flex"
},
inline: {
display: "inline-block"
},
popover: {
zIndex: 1
},
root: {
alignItems: "center",
display: "flex",
minHeight: 72,
padding: theme.spacing(1.5, 1.5, 1.5, 3)
},
separator: {
backgroundColor: theme.palette.grey[300],
display: "inline-block",
height: 30,
marginLeft: theme.spacing(2),
marginRight: theme.spacing(),
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 useStyles = makeStyles(theme => ({
anchor: {
display: "inline-block"
},
container: {
alignItems: "center",
display: "flex"
},
inline: {
display: "inline-block"
},
popover: {
zIndex: 1
},
root: {
alignItems: "center",
display: "flex",
minHeight: 72,
padding: theme.spacing(1.5, 1.5, 1.5, 3)
},
separator: {
backgroundColor: theme.palette.grey[300],
display: "inline-block",
height: 30,
marginLeft: theme.spacing(2),
marginRight: theme.spacing(),
width: 1
}
);
}));
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;

View file

@ -1,9 +1,4 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator";
import Typography from "@material-ui/core/Typography";
import classNames from "classnames";
@ -45,159 +40,158 @@ export interface RichTextEditorProps {
onChange: (event: React.ChangeEvent<any>) => void;
}
const styles = theme =>
createStyles({
error: {
color: theme.palette.error.main
},
helperText: {
marginTop: theme.spacing(0.75)
},
input: {
position: "relative"
},
label: {
fontSize: theme.typography.caption.fontSize,
left: 12,
position: "absolute",
top: 9
},
linkIcon: {
marginTop: 2
},
root: {
"& .DraftEditor": {
"&-editorContainer": {
"& .public-DraftEditor-content": {
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"
const useStyles = makeStyles(theme => ({
error: {
color: theme.palette.error.main
},
helperText: {
marginTop: theme.spacing(0.75)
},
input: {
position: "relative"
},
label: {
fontSize: theme.typography.caption.fontSize,
left: 12,
position: "absolute",
top: 9
},
linkIcon: {
marginTop: 2
},
root: {
"& .DraftEditor": {
"&-editorContainer": {
"& .public-DraftEditor-content": {
lineHeight: 1.62
},
"&-root": {
...theme.typography.body1
}
"& 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"
},
"& .Draftail": {
"&-Editor": {
"&--focus": {
boxShadow: `inset 0px 0px 0px 2px ${theme.palette.primary.main}`
},
"&:hover": {
borderColor: 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"
"&-root": {
...theme.typography.body1
}
},
"& .Draftail": {
"&-Editor": {
"&--focus": {
boxShadow: `inset 0px 0px 0px 2px ${theme.palette.primary.main}`
},
"&-Toolbar": {
"&Button": {
"& svg": {
padding: 2
},
"&--active": {
"&:hover": {
background: theme.palette.primary.main
},
"&:not(:hover)": {
borderRightColor: theme.palette.primary.main
},
"&:hover": {
borderColor: theme.palette.primary.main
},
border: `1px ${theme.palette.divider} solid`,
borderRadius: 4,
padding: "27px 12px 10px",
position: "relative",
transition: theme.transitions.duration.shortest + "ms"
},
"&-Toolbar": {
"&Button": {
"& svg": {
padding: 2
},
"&--active": {
"&:hover": {
background: theme.palette.primary.main
},
"&:focus": {
"&:active": {
"&:after": {
background: fade(theme.palette.primary.main, 0.3),
borderRadius: "100%",
content: "''",
display: "block",
height: "100%",
width: "100%"
}
}
"&:not(:hover)": {
borderRightColor: theme.palette.primary.main
},
"&:hover": {
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
background: theme.palette.primary.main
},
"&Group": {
"&:last-of-type": {
"& .Draftail-ToolbarButton": {
"&:last-of-type": {
border: "none"
}
"&:focus": {
"&:active": {
"&:after": {
background: fade(theme.palette.primary.main, 0.3),
borderRadius: "100%",
content: "''",
display: "block",
height: "100%",
width: "100%"
}
},
display: "flex"
}
},
background: theme.palette.background.default,
border: `1px ${theme.overrides.MuiCard.root.borderColor} solid`,
"&:hover": {
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",
flexWrap: "wrap",
marginBottom: theme.spacing(),
marginTop: 10,
[theme.breakpoints.down(460)]: {
width: "min-content"
}
height: 36,
justifyContent: "center",
padding: theme.spacing(1) + 2,
transition: theme.transitions.duration.short + "ms",
width: 36
},
"&-block": {
"&--blockquote": {
borderLeft: `2px solid ${theme.overrides.MuiCard.root.borderColor}`,
margin: 0,
padding: theme.spacing(1, 2)
}
"&Group": {
"&:last-of-type": {
"& .Draftail-ToolbarButton": {
"&:last-of-type": {
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": {
"& .Draftail": {
"&-Editor": {
borderColor: theme.palette.error.main
}
"&-block": {
"&--blockquote": {
borderLeft: `2px solid ${theme.palette.divider}`,
margin: 0,
padding: theme.spacing(1, 2)
}
}
},
scroll: {
"& .DraftEditor": {
"&-editorContainer": {
"& .public-DraftEditor-content": {
lineHeight: 1.62
}
"&$error": {
"& .Draftail": {
"&-Editor": {
borderColor: theme.palette.error.main
}
}
},
smallIcon: {
marginLeft: 10
}
});
},
scroll: {
"& .DraftEditor": {
"&-editorContainer": {
"& .public-DraftEditor-content": {
lineHeight: 1.62
}
}
}
},
smallIcon: {
marginLeft: 10
}
}));
function handleSave(
value: any,
@ -215,17 +209,12 @@ function handleSave(
}
}
const RichTextEditor = withStyles(styles, { name: "RichTextEditor" })(
({
classes,
error,
helperText,
initial,
label,
name,
scroll,
onChange
}: RichTextEditorProps & WithStyles<typeof styles>) => (
const RichTextEditor: React.FC<RichTextEditorProps> = props => {
const { error, helperText, initial, label, name, scroll, onChange } = props;
const classes = useStyles(props);
return (
<div
className={classNames({
[classes.error]: error,
@ -302,8 +291,9 @@ const RichTextEditor = withStyles(styles, { name: "RichTextEditor" })(
</Typography>
)}
</div>
)
);
);
};
RichTextEditor.displayName = "RichTextEditor";
RichTextEditor.defaultProps = {
scroll: true

View file

@ -1,2 +1,2 @@
export { default } from './RichTextEditor';
export * from './RichTextEditor';
export { default } from "./RichTextEditor";
export * from "./RichTextEditor";

View file

@ -1,11 +1,6 @@
import Button from "@material-ui/core/Button";
import Portal from "@material-ui/core/Portal";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import classNames from "classnames";
import React from "react";
import { useIntl } from "react-intl";
@ -19,48 +14,47 @@ import ConfirmButton, {
} from "../ConfirmButton/ConfirmButton";
import Container from "../Container";
const styles = theme =>
createStyles({
button: {
marginRight: theme.spacing(1)
},
cancelButton: {
marginRight: theme.spacing(2)
},
container: {
display: "flex",
paddingBottom: theme.spacing(2),
paddingTop: theme.spacing(2),
[theme.breakpoints.down("sm")]: {
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}`
}
const useStyles = makeStyles(theme => ({
button: {
marginRight: theme.spacing(1)
},
cancelButton: {
marginRight: theme.spacing(2)
},
container: {
display: "flex",
paddingBottom: theme.spacing(2),
paddingTop: theme.spacing(2),
[theme.breakpoints.down("sm")]: {
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.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;
state: ConfirmButtonTransitionState;
labels?: {
@ -73,77 +67,77 @@ interface SaveButtonBarProps extends WithStyles<typeof styles> {
onSave(event: any);
}
export const SaveButtonBar = withStyles(styles, { name: "SaveButtonBar" })(
({
classes,
export const SaveButtonBar: React.FC<SaveButtonBarProps> = props => {
const {
disabled,
labels,
state,
onCancel,
onDelete,
onSave,
...props
}: SaveButtonBarProps) => {
const intl = useIntl();
const scrollPosition = useWindowScroll();
const scrolledToBottom =
scrollPosition.y + window.innerHeight >= document.body.scrollHeight;
...rest
} = props;
const classes = useStyles(props);
return (
<AppActionContext.Consumer>
{anchor =>
anchor ? (
<Portal container={anchor.current}>
<div
className={classNames(classes.root, {
[classes.stop]: scrolledToBottom
})}
{...props}
>
<Container className={classes.container}>
{!!onDelete && (
<Button
variant="contained"
onClick={onDelete}
className={classes.deleteButton}
data-tc="button-bar-delete"
>
{labels && labels.delete
? labels.delete
: intl.formatMessage(buttonMessages.delete)}
</Button>
)}
<div className={classes.spacer} />
const intl = useIntl();
const scrollPosition = useWindowScroll();
const scrolledToBottom =
scrollPosition.y + window.innerHeight >= document.body.scrollHeight;
return (
<AppActionContext.Consumer>
{anchor =>
anchor ? (
<Portal container={anchor.current}>
<div
className={classNames(classes.root, {
[classes.stop]: scrolledToBottom
})}
{...rest}
>
<Container className={classes.container}>
{!!onDelete && (
<Button
className={classes.cancelButton}
variant="text"
onClick={onCancel}
data-tc="button-bar-cancel"
variant="contained"
onClick={onDelete}
className={classes.deleteButton}
data-tc="button-bar-delete"
>
{maybe(
() => labels.cancel,
intl.formatMessage(buttonMessages.back)
)}
{labels && labels.delete
? labels.delete
: intl.formatMessage(buttonMessages.delete)}
</Button>
<ConfirmButton
disabled={disabled}
onClick={onSave}
transitionState={state}
data-tc="button-bar-confirm"
>
{maybe(
() => labels.save,
intl.formatMessage(buttonMessages.save)
)}
</ConfirmButton>
</Container>
</div>
</Portal>
) : null
}
</AppActionContext.Consumer>
);
}
);
)}
<div className={classes.spacer} />
<Button
className={classes.cancelButton}
variant="text"
onClick={onCancel}
data-tc="button-bar-cancel"
>
{maybe(
() => labels.cancel,
intl.formatMessage(buttonMessages.back)
)}
</Button>
<ConfirmButton
disabled={disabled}
onClick={onSave}
transitionState={state}
data-tc="button-bar-confirm"
>
{maybe(
() => labels.save,
intl.formatMessage(buttonMessages.save)
)}
</ConfirmButton>
</Container>
</div>
</Portal>
) : null
}
</AppActionContext.Consumer>
);
};
SaveButtonBar.displayName = "SaveButtonBar";
export default SaveButtonBar;

View file

@ -1,2 +1,2 @@
export { default } from './SaveFilterTabDialog';
export * from './SaveFilterTabDialog';
export { default } from "./SaveFilterTabDialog";
export * from "./SaveFilterTabDialog";

View file

@ -1,12 +1,7 @@
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography";
import classNames from "classnames";
@ -16,55 +11,54 @@ import { FormattedMessage, useIntl } from "react-intl";
import CardTitle from "../CardTitle";
import FormSpacer from "../FormSpacer";
const styles = theme =>
createStyles({
addressBar: {
color: "#006621",
fontSize: "13px",
lineHeight: "16px",
marginBottom: "2px",
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap"
const useStyles = makeStyles(theme => ({
addressBar: {
color: "#006621",
fontSize: "13px",
lineHeight: "16px",
marginBottom: "2px",
overflow: "hidden",
textOverflow: "ellipsis",
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: {
width: "100%"
},
descriptionBar: {
color: "#545454",
fontSize: "13px",
lineHeight: "18px",
overflowWrap: "break-word"
},
helperText: {
marginBottom: theme.spacing(3)
},
label: {
flex: 1
},
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"
}
});
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;
descriptionPlaceholder: string;
disabled?: boolean;
@ -76,9 +70,8 @@ interface SeoFormProps extends WithStyles<typeof styles> {
onClick?();
}
const SeoForm = withStyles(styles, { name: "SeoForm" })(
({
classes,
const SeoForm: React.FC<SeoFormProps> = props => {
const {
description,
descriptionPlaceholder,
disabled,
@ -87,107 +80,108 @@ const SeoForm = withStyles(styles, { name: "SeoForm" })(
title,
titlePlaceholder,
onChange
}: SeoFormProps) => {
const intl = useIntl();
const [expanded, setExpansionStatus] = React.useState(false);
const toggleExpansion = () => setExpansionStatus(!expanded);
} = props;
const classes = useStyles(props);
return (
<Card>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Search Engine Preview"
})}
toolbar={
<Button color="primary" variant="text" onClick={toggleExpansion}>
<FormattedMessage
defaultMessage="Edit website SEO"
description="button"
/>
</Button>
}
/>
<CardContent>
{helperText && (
<Typography
className={classNames({ [classes.helperText]: expanded })}
>
{helperText}
</Typography>
)}
{expanded && (
<div className={classes.container}>
<TextField
name="seoTitle"
label={
<div className={classes.labelContainer}>
<div className={classes.label}>
<FormattedMessage defaultMessage="Search engine title" />
</div>
{title.length > 0 && (
<span>
<FormattedMessage
defaultMessage="{numberOfCharacters} of {maxCharacters} characters"
description="character limit"
values={{
maxCharacters: 70,
numberOfCharacters: title.length
}}
/>
</span>
)}
const intl = useIntl();
const [expanded, setExpansionStatus] = React.useState(false);
const toggleExpansion = () => setExpansionStatus(!expanded);
return (
<Card>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Search Engine Preview"
})}
toolbar={
<Button color="primary" variant="text" onClick={toggleExpansion}>
<FormattedMessage
defaultMessage="Edit website SEO"
description="button"
/>
</Button>
}
/>
<CardContent>
{helperText && (
<Typography
className={classNames({ [classes.helperText]: expanded })}
>
{helperText}
</Typography>
)}
{expanded && (
<div className={classes.container}>
<TextField
name="seoTitle"
label={
<div className={classes.labelContainer}>
<div className={classes.label}>
<FormattedMessage defaultMessage="Search engine title" />
</div>
}
helperText={intl.formatMessage({
defaultMessage:
"If empty, the preview shows what will be autogenerated."
})}
value={title.slice(0, 69)}
disabled={loading || disabled}
placeholder={titlePlaceholder}
onChange={onChange}
fullWidth
/>
<FormSpacer />
<TextField
name="seoDescription"
label={
<div className={classes.labelContainer}>
<div className={classes.label}>
<FormattedMessage defaultMessage="Search engine description" />
</div>
{description.length > 0 && (
<span>
<FormattedMessage
defaultMessage="{numberOfCharacters} of {maxCharacters} characters"
description="character limit"
values={{
maxCharacters: 300,
numberOfCharacters: description.length
}}
/>
</span>
)}
{title.length > 0 && (
<span>
<FormattedMessage
defaultMessage="{numberOfCharacters} of {maxCharacters} characters"
description="character limit"
values={{
maxCharacters: 70,
numberOfCharacters: title.length
}}
/>
</span>
)}
</div>
}
helperText={intl.formatMessage({
defaultMessage:
"If empty, the preview shows what will be autogenerated."
})}
value={title.slice(0, 69)}
disabled={loading || disabled}
placeholder={titlePlaceholder}
onChange={onChange}
fullWidth
/>
<FormSpacer />
<TextField
name="seoDescription"
label={
<div className={classes.labelContainer}>
<div className={classes.label}>
<FormattedMessage defaultMessage="Search engine description" />
</div>
}
helperText={intl.formatMessage({
defaultMessage:
"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>
);
}
);
{description.length > 0 && (
<span>
<FormattedMessage
defaultMessage="{numberOfCharacters} of {maxCharacters} characters"
description="character limit"
values={{
maxCharacters: 300,
numberOfCharacters: description.length
}}
/>
</span>
)}
</div>
}
helperText={intl.formatMessage({
defaultMessage:
"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";
export default SeoForm;

View file

@ -1,5 +1,5 @@
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 Downshift from "downshift";
import { filter } from "fuzzaldrin";
@ -13,7 +13,7 @@ import { FetchMoreProps } from "@saleor/types";
import ArrowDropdownIcon from "../../icons/ArrowDropdown";
import Debounce, { DebounceProps } from "../Debounce";
const styles = createStyles({
const useStyles = makeStyles({
container: {
flexGrow: 1,
position: "relative"
@ -42,12 +42,12 @@ const DebounceAutocomplete: React.ComponentType<
DebounceProps<string>
> = Debounce;
const SingleAutocompleteSelectFieldComponent = withStyles(styles, {
name: "SingleAutocompleteSelectField"
})(
({
const SingleAutocompleteSelectFieldComponent: React.FC<
SingleAutocompleteSelectFieldProps
> = props => {
const {
choices,
classes,
allowCustomValues,
disabled,
displayValue,
@ -64,110 +64,111 @@ const SingleAutocompleteSelectFieldComponent = withStyles(styles, {
fetchChoices,
onChange,
onFetchMore,
...props
}: SingleAutocompleteSelectFieldProps & WithStyles<typeof styles>) => {
const [prevDisplayValue] = useStateFromProps(displayValue);
...rest
} = props;
const classes = useStyles(props);
const handleChange = item =>
onChange({
target: {
name,
value: item
}
} as any);
const [prevDisplayValue] = useStateFromProps(displayValue);
return (
<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 handleChange = item =>
onChange({
target: {
name,
value: item
}
} as any);
if (hasInputValueChanged) {
reset({ inputValue: displayValue });
}
return (
<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 =
inputValue &&
inputValue.length > 0 &&
allowCustomValues &&
!choices.find(
choice =>
choice.label.toLowerCase() === inputValue.toLowerCase()
);
if (hasInputValueChanged) {
reset({ inputValue: displayValue });
}
return (
<div className={classes.container} {...props}>
<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>
const displayCustomValue =
inputValue &&
inputValue.length > 0 &&
allowCustomValues &&
!choices.find(
choice =>
choice.label.toLowerCase() === inputValue.toLowerCase()
);
}}
</Downshift>
)}
</DebounceAutocomplete>
);
}
);
return (
<div className={classes.container} {...rest}>
<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<
SingleAutocompleteSelectFieldProps
> = ({ choices, fetchChoices, ...props }) => {
> = ({ choices, fetchChoices, ...rest }) => {
const [query, setQuery] = React.useState("");
if (fetchChoices) {
return (
@ -175,7 +176,7 @@ const SingleAutocompleteSelectField: React.FC<
{debounceFn => (
<SingleAutocompleteSelectFieldComponent
choices={choices}
{...props}
{...rest}
fetchChoices={debounceFn}
/>
)}
@ -189,7 +190,7 @@ const SingleAutocompleteSelectField: React.FC<
choices={filter(choices, query, {
key: "label"
})}
{...props}
{...rest}
/>
);
};

View file

@ -4,12 +4,12 @@ import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
import OutlinedInput from "@material-ui/core/OutlinedInput";
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 React from "react";
import { FormattedMessage } from "react-intl";
const styles = createStyles({
const useStyles = makeStyles({
formControl: {
"& label": {
top: "-3px"
@ -18,7 +18,7 @@ const styles = createStyles({
}
});
interface SingleSelectFieldProps extends WithStyles<typeof styles> {
interface SingleSelectFieldProps {
choices: Array<{
value: string;
label: string | React.ReactNode;
@ -35,12 +35,10 @@ interface SingleSelectFieldProps extends WithStyles<typeof styles> {
onChange(event: any);
}
export const SingleSelectField = withStyles(styles, {
name: "SingleSelectField"
})(
({
export const SingleSelectField: React.FC<SingleSelectFieldProps> = props => {
const {
className,
classes,
disabled,
error,
label,
@ -51,49 +49,50 @@ export const SingleSelectField = withStyles(styles, {
hint,
selectProps,
placeholder
}: SingleSelectFieldProps) => {
const choicesByKey: { [key: string]: string } =
choices === undefined
? {}
: choices.reduce((prev, curr) => {
prev[curr.value] = curr.label;
return prev;
}, {});
} = props;
const classes = useStyles(props);
return (
<FormControl
className={classNames(classes.formControl, className)}
error={error}
disabled={disabled}
const choicesByKey: { [key: string]: string } =
choices === undefined
? {}
: choices.reduce((prev, curr) => {
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>
<Select
variant="outlined"
fullWidth
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" />
{choices.length > 0 ? (
choices.map(choice => (
<MenuItem value={choice.value} key={choice.value}>
{choice.label}
</MenuItem>
)}
</Select>
{hint && <FormHelperText>{hint}</FormHelperText>}
</FormControl>
);
}
);
))
) : (
<MenuItem disabled={true}>
<FormattedMessage defaultMessage="No results found" />
</MenuItem>
)}
</Select>
{hint && <FormHelperText>{hint}</FormHelperText>}
</FormControl>
);
};
SingleSelectField.displayName = "SingleSelectField";
export default SingleSelectField;

View file

@ -1,45 +1,43 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import classNames from "classnames";
import React from "react";
const styles = theme =>
createStyles({
"@keyframes skeleton-animation": {
"0%": {
opacity: 0.6
},
"100%": {
opacity: 1
}
const useStyles = makeStyles(theme => ({
"@keyframes skeleton-animation": {
"0%": {
opacity: 0.6
},
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"
"100%": {
opacity: 1
}
});
},
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;
primary?: boolean;
style?: React.CSSProperties;
}
const Skeleton = withStyles(styles, { name: "Skeleton" })(
({ className, classes, primary, style }: SkeletonProps) => (
const Skeleton: React.FC<SkeletonProps> = props => {
const { className, primary, style } = props;
const classes = useStyles(props);
return (
<span
className={classNames(classes.skeleton, className, {
[classes.primary]: primary
@ -48,8 +46,8 @@ const Skeleton = withStyles(styles, { name: "Skeleton" })(
>
&zwnj;
</span>
)
);
);
};
Skeleton.displayName = "Skeleton";
export default Skeleton;

View file

@ -20,13 +20,14 @@ const useStyles = makeStyles(theme => ({
},
background: theme.palette.background.paper,
fontFamily: theme.typography.fontFamily,
fontSize: theme.overrides.MuiTableCell.root.fontSize,
// FIXME: you damn know what
// fontSize: theme.overrides.MuiTableCell.root.fontSize,
opacity: 0.5
}
}));
const SortableTableBody: React.FC<
TableBodyProps & SortableTableBodyProps
Omit<TableBodyProps & SortableTableBodyProps, "ref">
> = props => {
const classes = useStyles({});

View file

@ -1,15 +1,10 @@
import yellow from "@material-ui/core/colors/yellow";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Typography, { TypographyProps } from "@material-ui/core/Typography";
import classNames from "classnames";
import React from "react";
const styles = theme => {
const useStyles = makeStyles(theme => {
const dot = {
borderRadius: "100%",
content: "''",
@ -20,7 +15,8 @@ const styles = theme => {
top: "calc(50% - 5px)",
width: 8
};
return createStyles({
return {
errorDot: {
"&:before": { backgroundColor: theme.palette.error.main, ...dot }
},
@ -38,24 +34,22 @@ const styles = theme => {
successDot: {
"&:before": { backgroundColor: theme.palette.primary.main, ...dot }
}
});
};
};
});
interface StatusLabelProps extends WithStyles<typeof styles> {
interface StatusLabelProps {
className?: string;
label: string | React.ReactNode;
status: "success" | "neutral" | "error" | string;
typographyProps?: TypographyProps;
}
const StatusLabel = withStyles(styles, { name: "StatusLabel" })(
({
classes,
className,
label,
status,
typographyProps
}: StatusLabelProps) => (
const StatusLabel: React.FC<StatusLabelProps> = props => {
const { className, label, status, typographyProps } = props;
const classes = useStyles(props);
return (
<div
className={classNames({
[classes.root]: true,
@ -77,7 +71,7 @@ const StatusLabel = withStyles(styles, { name: "StatusLabel" })(
label
)}
</div>
)
);
);
};
StatusLabel.displayName = "StatusLabel";
export default StatusLabel;

View file

@ -1,16 +1,11 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import { fade } from "@material-ui/core/styles/colorManipulator";
import Typography from "@material-ui/core/Typography";
import classNames from "classnames";
import React from "react";
const styles = theme =>
createStyles({
const useStyles = makeStyles(
theme => ({
active: {
color: theme.typography.caption.color
},
@ -35,17 +30,23 @@ const styles = theme =>
padding: theme.spacing(1),
transition: theme.transitions.duration.short + "ms"
}
});
}),
{ name: "Tab" }
);
interface TabProps<T> extends WithStyles<typeof styles> {
interface TabProps<T> {
children?: React.ReactNode;
isActive: boolean;
changeTab: (index: T) => void;
}
export function Tab<T>(value: T) {
return withStyles(styles, { name: "Tab" })(
({ classes, children, isActive, changeTab }: TabProps<T>) => (
const Component: React.FC<TabProps<T>> = props => {
const { children, isActive, changeTab } = props;
const classes = useStyles(props);
return (
<Typography
component="span"
className={classNames({
@ -56,8 +57,10 @@ export function Tab<T>(value: T) {
>
{children}
</Typography>
)
);
);
};
return Component;
}
export default Tab;

View file

@ -1,27 +1,23 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import React from "react";
export interface TabContainerProps {
children: React.ReactNode | React.ReactNodeArray;
}
const styles = theme =>
createStyles({
root: {
borderBottom: `1px solid ${theme.overrides.MuiCard.root.borderColor}`
}
});
const useStyles = makeStyles(theme => ({
root: {
borderBottom: `1px solid ${theme.palette.divider}`
}
}));
const TabContainer = withStyles(styles, {
name: "TabContainer"
})(({ classes, children }: TabContainerProps & WithStyles<typeof styles>) => (
<div className={classes.root}>{children}</div>
));
const TabContainer: React.FC<TabContainerProps> = props => {
const { children } = props;
const classes = useStyles(props);
return <div className={classes.root}>{children}</div>;
};
TabContainer.displayName = "TabContainer";
export default TabContainer;

View file

@ -1,12 +1,10 @@
import React from "react";
export interface TabsProps {
children: (
props: {
changeTab: (index: number) => void;
currentTab: number;
}
) => React.ReactNode;
children: (props: {
changeTab: (index: number) => void;
currentTab: number;
}) => React.ReactNode;
}
interface TabsState {

View file

@ -1,10 +1,5 @@
import Avatar from "@material-ui/core/Avatar";
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import TableCell from "@material-ui/core/TableCell";
import Cached from "@material-ui/icons/Cached";
import classNames from "classnames";
@ -14,48 +9,44 @@ import Image from "../../icons/Image";
export const AVATAR_MARGIN = 56;
const styles = theme =>
createStyles({
avatar: {
background: "none",
border: `1px solid ${theme.overrides.MuiCard.root.borderColor}`,
borderRadius: 2,
color: "#bdbdbd",
display: "inline-flex",
padding: theme.spacing(.5)
},
children: {
alignSelf: "center",
marginLeft: theme.spacing(2),
width: "100%"
},
content: {
alignItems: "center",
display: "flex"
},
root: {
paddingRight: theme.spacing(3),
width: "1%"
}
});
const useStyles = makeStyles(theme => ({
avatar: {
background: "none",
border: `1px solid ${theme.palette}`,
borderRadius: 2,
color: "#bdbdbd",
display: "inline-flex",
padding: theme.spacing(0.5)
},
children: {
alignSelf: "center",
marginLeft: theme.spacing(2),
width: "100%"
},
content: {
alignItems: "center",
display: "flex"
},
root: {
paddingRight: theme.spacing(3),
width: "1%"
}
}));
interface TableCellAvatarProps extends WithStyles<typeof styles> {
interface TableCellAvatarProps {
className?: string;
thumbnail?: string;
avatarProps?: string;
children?: React.ReactNode | React.ReactNodeArray;
}
const TableCellAvatar = withStyles(styles, { name: "TableCellAvatar" })(
({
classes,
children,
className,
thumbnail,
avatarProps,
...props
}: TableCellAvatarProps) => (
<TableCell className={classNames(classes.root, className)} {...props}>
const TableCellAvatar: React.FC<TableCellAvatarProps> = props => {
const { children, className, thumbnail, avatarProps, ...rest } = props;
const classes = useStyles(props);
return (
<TableCell className={classNames(classes.root, className)} {...rest}>
<div className={classes.content}>
{thumbnail === undefined ? (
<Avatar className={classNames(classes.avatar, avatarProps)}>
@ -74,7 +65,7 @@ const TableCellAvatar = withStyles(styles, { name: "TableCellAvatar" })(
<div className={classes.children}>{children}</div>
</div>
</TableCell>
)
);
);
};
TableCellAvatar.displayName = "TableCellAvatar";
export default TableCellAvatar;

View file

@ -6,7 +6,6 @@ import ClearIcon from "@material-ui/icons/Clear";
import React from "react";
import { FormattedMessage } from "react-intl";
import Filter from "../Filter";
import FilterActions, { FilterActionsProps } from "../Filter/FilterActions";
import Hr from "../Hr";
import Link from "../Link";

View file

@ -1,45 +1,43 @@
import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import { makeStyles } from "@material-ui/core/styles";
import Tab from "@material-ui/core/Tab";
import classNames from "classnames";
import React from "react";
const styles = theme =>
createStyles({
selectedTabLabel: {
"&$tabLabel": {
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"
const useStyles = makeStyles(theme => ({
selectedTabLabel: {
"&$tabLabel": {
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"
}
}));
interface FilterTabProps extends WithStyles<typeof styles> {
interface FilterTabProps {
onClick: () => void;
label: string;
selected?: boolean;
value?: number;
}
export const FilterTab = withStyles(styles, { name: "FilterTab" })(
({ classes, onClick, label, selected, value }: FilterTabProps) => (
export const FilterTab: React.FC<FilterTabProps> = props => {
const { onClick, label, selected, value } = props;
const classes = useStyles(props);
return (
<Tab
disableRipple
label={label}
@ -52,7 +50,7 @@ export const FilterTab = withStyles(styles, { name: "FilterTab" })(
onClick={onClick}
value={value}
/>
)
);
);
};
FilterTab.displayName = "FilterTab";
export default FilterTab;

Some files were not shown because too many files have changed in this diff Show more