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";
|
2019-08-26 17:44:42 +00:00
|
|
|
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";
|
2019-08-26 17:44:42 +00:00
|
|
|
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) => {
|
2019-08-26 17:44:42 +00:00
|
|
|
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
|
2019-08-26 17:44:42 +00:00
|
|
|
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}
|
|
|
|
>
|
2019-08-26 17:44:42 +00:00
|
|
|
{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}
|
2019-08-26 17:44:42 +00:00
|
|
|
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 ? (
|
2019-08-26 17:44:42 +00:00
|
|
|
<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}
|
|
|
|
>
|
2019-08-26 17:44:42 +00:00
|
|
|
<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>
|
2019-08-26 17:44:42 +00:00
|
|
|
<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}>
|
2019-08-26 17:44:42 +00:00
|
|
|
<FormattedMessage
|
2019-10-09 15:33:55 +00:00
|
|
|
defaultMessage="Contact Information"
|
2019-08-26 17:44:42 +00:00
|
|
|
description="subheader"
|
|
|
|
/>
|
2019-06-19 14:40:52 +00:00
|
|
|
</Typography>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{maybe(() => order.userEmail) === undefined ? (
|
|
|
|
<Skeleton />
|
|
|
|
) : order.userEmail === null ? (
|
2019-08-26 17:44:42 +00:00
|
|
|
<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}>
|
2019-08-26 17:44:42 +00:00
|
|
|
<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}
|
|
|
|
>
|
2019-08-26 17:44:42 +00:00
|
|
|
<FormattedMessage {...buttonMessages.edit} />
|
2019-06-19 14:40:52 +00:00
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
{shippingAddress === undefined ? (
|
|
|
|
<Skeleton />
|
|
|
|
) : shippingAddress === null ? (
|
2019-08-26 17:44:42 +00:00
|
|
|
<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}>
|
2019-08-26 17:44:42 +00:00
|
|
|
<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}
|
|
|
|
>
|
2019-08-26 17:44:42 +00:00
|
|
|
<FormattedMessage {...buttonMessages.edit} />
|
2019-06-19 14:40:52 +00:00
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
{billingAddress === undefined ? (
|
|
|
|
<Skeleton />
|
|
|
|
) : billingAddress === null ? (
|
2019-08-26 17:44:42 +00:00
|
|
|
<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 ? (
|
2019-08-26 17:44:42 +00:00
|
|
|
<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;
|