Saleor 1946 expose user metadata in customer details view (#912)

* Add metadata component

* Update types

* Add metadata handler

* Update fixture and storybook

* Update storybook
This commit is contained in:
Marek Choiński 2021-01-07 11:03:48 +01:00 committed by GitHub
parent 59b87f8940
commit 63a2969808
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 1188 additions and 62 deletions

View file

@ -4,11 +4,15 @@ import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import Container from "@saleor/components/Container";
import Form from "@saleor/components/Form";
import Grid from "@saleor/components/Grid";
import Metadata from "@saleor/components/Metadata/Metadata";
import { MetadataFormData } from "@saleor/components/Metadata/types";
import PageHeader from "@saleor/components/PageHeader";
import SaveButtonBar from "@saleor/components/SaveButtonBar";
import { AccountErrorFragment } from "@saleor/fragments/types/AccountErrorFragment";
import { SubmitPromise } from "@saleor/hooks/useForm";
import { sectionNames } from "@saleor/intl";
import { mapMetadataItemToInput } from "@saleor/utils/maps";
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
import React from "react";
import { useIntl } from "react-intl";
@ -20,7 +24,7 @@ import CustomerInfo from "../CustomerInfo";
import CustomerOrders from "../CustomerOrders";
import CustomerStats from "../CustomerStats";
export interface CustomerDetailsPageFormData {
export interface CustomerDetailsPageFormData extends MetadataFormData {
firstName: string;
lastName: string;
email: string;
@ -55,68 +59,78 @@ const CustomerDetailsPage: React.FC<CustomerDetailsPageProps> = ({
}: CustomerDetailsPageProps) => {
const intl = useIntl();
const initialForm: CustomerDetailsPageFormData = {
email: customer?.email || "",
firstName: customer?.firstName || "",
isActive: customer?.isActive || false,
lastName: customer?.lastName || "",
note: customer?.note || "",
metadata: customer?.metadata.map(mapMetadataItemToInput),
privateMetadata: customer?.privateMetadata.map(mapMetadataItemToInput)
};
const {
makeChangeHandler: makeMetadataChangeHandler
} = useMetadataChangeTrigger();
return (
<Form
initial={{
email: maybe(() => customer.email, ""),
firstName: maybe(() => customer.firstName, ""),
isActive: maybe(() => customer.isActive, false),
lastName: maybe(() => customer.lastName, ""),
note: maybe(() => customer.note, "")
<Form initial={initialForm} onSubmit={onSubmit} confirmLeave>
{({ change, data, hasChanged, submit }) => {
const changeMetadata = makeMetadataChangeHandler(change);
return (
<Container>
<AppHeader onBack={onBack}>
{intl.formatMessage(sectionNames.customers)}
</AppHeader>
<PageHeader title={getUserName(customer, true)} />
<Grid>
<div>
<CustomerDetails
customer={customer}
data={data}
disabled={disabled}
errors={errors}
onChange={change}
/>
<CardSpacer />
<CustomerInfo
data={data}
disabled={disabled}
errors={errors}
onChange={change}
/>
<CardSpacer />
<CustomerOrders
orders={maybe(() =>
customer.orders.edges.map(edge => edge.node)
)}
onViewAllOrdersClick={onViewAllOrdersClick}
onRowClick={onRowClick}
/>
<CardSpacer />
<Metadata data={data} onChange={changeMetadata} />
</div>
<div>
<CustomerAddresses
customer={customer}
disabled={disabled}
onAddressManageClick={onAddressManageClick}
/>
<CardSpacer />
<CustomerStats customer={customer} />
</div>
</Grid>
<SaveButtonBar
disabled={disabled || !hasChanged}
state={saveButtonBar}
onSave={submit}
onCancel={onBack}
onDelete={onDelete}
/>
</Container>
);
}}
onSubmit={onSubmit}
confirmLeave
>
{({ change, data, hasChanged, submit }) => (
<Container>
<AppHeader onBack={onBack}>
{intl.formatMessage(sectionNames.customers)}
</AppHeader>
<PageHeader title={getUserName(customer, true)} />
<Grid>
<div>
<CustomerDetails
customer={customer}
data={data}
disabled={disabled}
errors={errors}
onChange={change}
/>
<CardSpacer />
<CustomerInfo
data={data}
disabled={disabled}
errors={errors}
onChange={change}
/>
<CardSpacer />
<CustomerOrders
orders={maybe(() =>
customer.orders.edges.map(edge => edge.node)
)}
onViewAllOrdersClick={onViewAllOrdersClick}
onRowClick={onRowClick}
/>
</div>
<div>
<CustomerAddresses
customer={customer}
disabled={disabled}
onAddressManageClick={onAddressManageClick}
/>
<CardSpacer />
<CustomerStats customer={customer} />
</div>
</Grid>
<SaveButtonBar
disabled={disabled || !hasChanged}
state={saveButtonBar}
onSave={submit}
onCancel={onBack}
onDelete={onDelete}
/>
</Container>
)}
</Form>
);
};

View file

@ -946,6 +946,8 @@ export const customerList: ListCustomers_customers_edges_node[] = [
];
export const customer: CustomerDetails_user & CustomerAddresses_user = {
__typename: "User",
metadata: [],
privateMetadata: [],
addresses: [
{
__typename: "Address",

View file

@ -8,6 +8,18 @@ import { PaymentChargeStatusEnum } from "./../../types/globalTypes";
// GraphQL query operation: CustomerDetails
// ====================================================
export interface CustomerDetails_user_metadata {
__typename: "MetadataItem";
key: string;
value: string;
}
export interface CustomerDetails_user_privateMetadata {
__typename: "MetadataItem";
key: string;
value: string;
}
export interface CustomerDetails_user_defaultShippingAddress_country {
__typename: "CountryDisplay";
code: string;
@ -104,6 +116,8 @@ export interface CustomerDetails_user {
email: string;
firstName: string;
lastName: string;
metadata: (CustomerDetails_user_metadata | null)[];
privateMetadata: (CustomerDetails_user_privateMetadata | null)[];
dateJoined: any;
lastLogin: any | null;
defaultShippingAddress: CustomerDetails_user_defaultShippingAddress | null;

View file

@ -14,6 +14,18 @@ export interface UpdateCustomer_customerUpdate_errors {
field: string | null;
}
export interface UpdateCustomer_customerUpdate_user_metadata {
__typename: "MetadataItem";
key: string;
value: string;
}
export interface UpdateCustomer_customerUpdate_user_privateMetadata {
__typename: "MetadataItem";
key: string;
value: string;
}
export interface UpdateCustomer_customerUpdate_user_defaultShippingAddress_country {
__typename: "CountryDisplay";
code: string;
@ -64,6 +76,8 @@ export interface UpdateCustomer_customerUpdate_user {
email: string;
firstName: string;
lastName: string;
metadata: (UpdateCustomer_customerUpdate_user_metadata | null)[];
privateMetadata: (UpdateCustomer_customerUpdate_user_privateMetadata | null)[];
dateJoined: any;
lastLogin: any | null;
defaultShippingAddress: UpdateCustomer_customerUpdate_user_defaultShippingAddress | null;

View file

@ -5,6 +5,11 @@ import { WindowTitle } from "@saleor/components/WindowTitle";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import { commonMessages } from "@saleor/intl";
import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler";
import {
useMetadataUpdate,
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
@ -78,7 +83,10 @@ export const CustomerDetailsView: React.FC<CustomerDetailsViewProps> = ({
return <NotFoundPage onBack={handleBack} />;
}
const handleSubmit = async (
const [updateMetadata] = useMetadataUpdate({});
const [updatePrivateMetadata] = usePrivateMetadataUpdate({});
const updateData = async (
data: CustomerDetailsPageFormData
) => {
const result = await updateCustomer({
@ -97,6 +105,13 @@ export const CustomerDetailsView: React.FC<CustomerDetailsViewProps> = ({
return result.data.customerUpdate.errors;
};
const handleSubmit = createMetadataUpdateHandler(
user,
updateData,
variables => updateMetadata({ variables }),
variables => updatePrivateMetadata({ variables })
);
return (
<>
<WindowTitle

View file

@ -1,6 +1,7 @@
import gql from "graphql-tag";
import { fragmentAddress } from "./address";
import { metadataFragment } from "./metadata";
export const customerFragment = gql`
fragment CustomerFragment on User {
@ -12,10 +13,12 @@ export const customerFragment = gql`
`;
export const customerDetailsFragment = gql`
${metadataFragment}
${customerFragment}
${fragmentAddress}
fragment CustomerDetailsFragment on User {
...CustomerFragment
...MetadataFragment
dateJoined
lastLogin
defaultShippingAddress {

View file

@ -6,6 +6,18 @@
// GraphQL fragment: CustomerDetailsFragment
// ====================================================
export interface CustomerDetailsFragment_metadata {
__typename: "MetadataItem";
key: string;
value: string;
}
export interface CustomerDetailsFragment_privateMetadata {
__typename: "MetadataItem";
key: string;
value: string;
}
export interface CustomerDetailsFragment_defaultShippingAddress_country {
__typename: "CountryDisplay";
code: string;
@ -56,6 +68,8 @@ export interface CustomerDetailsFragment {
email: string;
firstName: string;
lastName: string;
metadata: (CustomerDetailsFragment_metadata | null)[];
privateMetadata: (CustomerDetailsFragment_privateMetadata | null)[];
dateJoined: any;
lastLogin: any | null;
defaultShippingAddress: CustomerDetailsFragment_defaultShippingAddress | null;

File diff suppressed because it is too large Load diff