saleor-dashboard/src/orders/components/OrderCustomer/OrderCustomer.tsx

344 lines
12 KiB
TypeScript
Raw Normal View History

2019-06-19 14:40:52 +00:00
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 Typography from "@material-ui/core/Typography";
2019-08-09 10:26:22 +00:00
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
2019-06-19 14:40:52 +00:00
import CardTitle from "@saleor/components/CardTitle";
import ExternalLink from "@saleor/components/ExternalLink";
import Form from "@saleor/components/Form";
import Hr from "@saleor/components/Hr";
import Link from "@saleor/components/Link";
import SingleAutocompleteSelectField from "@saleor/components/SingleAutocompleteSelectField";
import Skeleton from "@saleor/components/Skeleton";
2019-08-09 11:14:35 +00:00
import useStateFromProps from "@saleor/hooks/useStateFromProps";
import { buttonMessages } from "@saleor/intl";
2019-08-09 11:14:35 +00:00
import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler";
2019-06-19 14:40:52 +00:00
import { SearchCustomers_customers_edges_node } from "../../../containers/SearchCustomers/types/SearchCustomers";
import { customerUrl } from "../../../customers/urls";
import { createHref, maybe } from "../../../misc";
import { OrderDetails_order } from "../../types/OrderDetails";
const styles = (theme: Theme) =>
createStyles({
sectionHeader: {
alignItems: "center",
display: "flex",
marginBottom: theme.spacing.unit * 3
},
sectionHeaderTitle: {
flex: 1,
fontWeight: 600 as 600,
lineHeight: 1,
textTransform: "uppercase"
},
sectionHeaderToolbar: {
marginRight: -theme.spacing.unit * 2
},
userEmail: {
fontWeight: 600 as 600,
marginBottom: theme.spacing.unit
}
});
export interface OrderCustomerProps extends WithStyles<typeof styles> {
order: OrderDetails_order;
users?: SearchCustomers_customers_edges_node[];
loading?: boolean;
canEditAddresses: boolean;
canEditCustomer: boolean;
fetchUsers?: (query: string) => void;
onCustomerEdit?: (data: { user?: string; userEmail?: string }) => void;
onProfileView: () => void;
onBillingAddressEdit?: () => void;
onShippingAddressEdit?: () => void;
}
const OrderCustomer = withStyles(styles, { name: "OrderCustomer" })(
({
classes,
canEditAddresses,
canEditCustomer,
fetchUsers,
loading,
order,
users,
onCustomerEdit,
onBillingAddressEdit,
onProfileView,
onShippingAddressEdit
}: OrderCustomerProps) => {
const intl = useIntl();
2019-08-09 11:14:35 +00:00
const user = maybe(() => order.user);
const [userDisplayName, setUserDisplayName] = useStateFromProps(
maybe(() => user.email, "")
);
2019-06-19 14:40:52 +00:00
const [isInEditMode, setEditModeStatus] = React.useState(false);
const toggleEditMode = () => setEditModeStatus(!isInEditMode);
const billingAddress = maybe(() => order.billingAddress);
const shippingAddress = maybe(() => order.shippingAddress);
2019-08-09 11:14:35 +00:00
2019-06-19 14:40:52 +00:00
return (
<Card>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Customer",
description: "section header"
})}
2019-06-19 14:40:52 +00:00
toolbar={
!!canEditCustomer && (
<Button
color="primary"
variant="text"
disabled={!onCustomerEdit}
onClick={toggleEditMode}
>
{intl.formatMessage(buttonMessages.edit)}
2019-06-19 14:40:52 +00:00
</Button>
)
}
/>
<CardContent>
{user === undefined ? (
<Skeleton />
) : isInEditMode && canEditCustomer ? (
2019-08-09 11:14:35 +00:00
<Form initial={{ query: "" }}>
2019-06-19 14:40:52 +00:00
{({ change, data }) => {
const handleChange = (event: React.ChangeEvent<any>) => {
change(event);
2019-08-09 11:14:35 +00:00
const value = event.target.value;
2019-06-19 14:40:52 +00:00
onCustomerEdit({
2019-08-09 11:14:35 +00:00
[value.includes("@") ? "userEmail" : "user"]: value
2019-06-19 14:40:52 +00:00
});
toggleEditMode();
};
2019-08-09 11:14:35 +00:00
const userChoices = maybe(() => users, []).map(user => ({
label: user.email,
value: user.id
}));
const handleUserChange = createSingleAutocompleteSelectHandler(
handleChange,
setUserDisplayName,
userChoices
);
2019-06-19 14:40:52 +00:00
return (
<SingleAutocompleteSelectField
2019-08-09 11:14:35 +00:00
allowCustomValues={true}
choices={userChoices}
displayValue={userDisplayName}
2019-06-19 14:40:52 +00:00
fetchChoices={fetchUsers}
loading={loading}
placeholder={intl.formatMessage({
defaultMessage: "Search Customers"
})}
2019-08-09 11:14:35 +00:00
onChange={handleUserChange}
2019-06-19 14:40:52 +00:00
name="query"
value={data.query}
/>
);
}}
</Form>
) : user === null ? (
<Typography>
<FormattedMessage defaultMessage="Anonymous user" />
</Typography>
2019-06-19 14:40:52 +00:00
) : (
<>
<Typography className={classes.userEmail}>
{user.email}
</Typography>
<div>
<Link
underline={false}
href={createHref(customerUrl(user.id))}
onClick={onProfileView}
>
<FormattedMessage
defaultMessage="View Profile"
description="link"
/>
2019-06-19 14:40:52 +00:00
</Link>
</div>
{/* TODO: Uncomment it after adding ability to filter
orders by customer */}
{/* <div>
<Link underline={false} href={}>
<FormattedMessage defaultMessage="View Orders"
description="link"
/>
</Link>
</div> */}
2019-06-19 14:40:52 +00:00
</>
)}
</CardContent>
<Hr />
<CardContent>
<div className={classes.sectionHeader}>
<Typography className={classes.sectionHeaderTitle}>
<FormattedMessage
2019-10-09 15:33:55 +00:00
defaultMessage="Contact Information"
description="subheader"
/>
2019-06-19 14:40:52 +00:00
</Typography>
</div>
{maybe(() => order.userEmail) === undefined ? (
<Skeleton />
) : order.userEmail === null ? (
<Typography>
<FormattedMessage
defaultMessage="Not set"
description="customer is not set in draft order"
id="orderCustomerCustomerNotSet"
/>
</Typography>
2019-06-19 14:40:52 +00:00
) : (
<ExternalLink
href={`mailto:${maybe(() => order.userEmail)}`}
typographyProps={{ color: "primary" }}
>
{maybe(() => order.userEmail)}
</ExternalLink>
)}
</CardContent>
<Hr />
<CardContent>
<div className={classes.sectionHeader}>
<Typography className={classes.sectionHeaderTitle}>
<FormattedMessage defaultMessage="Shipping Address" />
2019-06-19 14:40:52 +00:00
</Typography>
{canEditAddresses && (
<div className={classes.sectionHeaderToolbar}>
<Button
color="primary"
variant="text"
onClick={onShippingAddressEdit}
disabled={!onShippingAddressEdit && user === undefined}
>
<FormattedMessage {...buttonMessages.edit} />
2019-06-19 14:40:52 +00:00
</Button>
</div>
)}
</div>
{shippingAddress === undefined ? (
<Skeleton />
) : shippingAddress === null ? (
<Typography>
<FormattedMessage
defaultMessage="Not set"
description="shipping address is not set in draft order"
id="orderCustomerShippingAddressNotSet"
/>
</Typography>
2019-06-19 14:40:52 +00:00
) : (
<>
{shippingAddress.companyName && (
<Typography>{shippingAddress.companyName}</Typography>
)}
<Typography>
{shippingAddress.firstName} {shippingAddress.lastName}
</Typography>
<Typography>
{shippingAddress.streetAddress1}
<br />
{shippingAddress.streetAddress2}
</Typography>
<Typography>
{shippingAddress.postalCode} {shippingAddress.city}
{shippingAddress.cityArea
? ", " + shippingAddress.cityArea
: ""}
</Typography>
<Typography>
{shippingAddress.countryArea
? shippingAddress.countryArea +
", " +
shippingAddress.country.country
: shippingAddress.country.country}
</Typography>
<Typography>{shippingAddress.phone}</Typography>
</>
)}
</CardContent>
<Hr />
<CardContent>
<div className={classes.sectionHeader}>
<Typography className={classes.sectionHeaderTitle}>
<FormattedMessage defaultMessage="Billing Address" />
2019-06-19 14:40:52 +00:00
</Typography>
{canEditAddresses && (
<div className={classes.sectionHeaderToolbar}>
<Button
color="primary"
variant="text"
onClick={onBillingAddressEdit}
disabled={!onBillingAddressEdit && user === undefined}
>
<FormattedMessage {...buttonMessages.edit} />
2019-06-19 14:40:52 +00:00
</Button>
</div>
)}
</div>
{billingAddress === undefined ? (
<Skeleton />
) : billingAddress === null ? (
<Typography>
<FormattedMessage
defaultMessage="Not set"
description="no address is set in draft order"
id="orderCustomerBillingAddressNotSet"
/>
</Typography>
2019-06-19 14:40:52 +00:00
) : maybe(() => shippingAddress.id) === billingAddress.id ? (
<Typography>
<FormattedMessage
defaultMessage="Same as shipping address"
description="billing address"
/>
</Typography>
2019-06-19 14:40:52 +00:00
) : (
<>
{billingAddress.companyName && (
<Typography>{billingAddress.companyName}</Typography>
)}
<Typography>
{billingAddress.firstName} {billingAddress.lastName}
</Typography>
<Typography>
{billingAddress.streetAddress1}
<br />
{billingAddress.streetAddress2}
</Typography>
<Typography>
{billingAddress.postalCode} {billingAddress.city}
{billingAddress.cityArea ? ", " + billingAddress.cityArea : ""}
</Typography>
<Typography>
{billingAddress.countryArea
? billingAddress.countryArea +
", " +
billingAddress.country.country
: billingAddress.country.country}
</Typography>
<Typography>{billingAddress.phone}</Typography>
</>
)}
</CardContent>
</Card>
);
}
);
OrderCustomer.displayName = "OrderCustomer";
export default OrderCustomer;