Fluent Commerce Logo
Sign In

Author:

Siarhei Vaitsiakhovich

Changed on:

4 July 2024

Key Points

  • Data Modification: Ensure that users can modify customer data, including the ability to correct typos in existing information.
  • Error Handling: Implement error handling procedures in case the edit fails or invalid data is submitted.
  • User Experience: Aim for a seamless and intuitive editing process to minimize the risk of user errors.

Steps

Step arrow right iconUse Case

To effectively manage customer information within our system, the Edit Customer feature is used. This functionality allows users to update customer details such as contact information, ensuring that the customer database remains accurate and up-to-date.

Step arrow right iconSolution Approach

The feature can be implemented via the declaration of a custom mutation user action

`updateCustomer`
in the manifest (see Page Component). For a better user experience, some of the default mutation field components have to be overridden. List of fields to override:

  • Country
  • Timezone
  • Promotion Opted In

Additionally, the fields have to be reordered to enhance the logical flow of the user interface, making it more intuitive for users to navigate and input their information efficiently. New fields order:

  • Title
  • First Name
  • Last Name
  • Primary Email
  • Primary Phone
  • Country
  • Timezone
  • Promotion Opted In
  • Customer attributes

To save data consistency, options for Timezone and Country selectors can be loaded from settings. All fields have to be prefilled with current user information. Additionally, the field username has to be loaded as a customer reference but hidden to avoid reference change.

Step arrow right icon Technical Design Overview

To support the business solution design, the following technical areas need to be enhanced:

  • New custom UI components (by using Component SDK) -
    `SettingBaseStringSelector`
    ,
    `BooleanSelector`
  • Declare settings to use it for Country and Timezone selectors
  • Update manifest to add a new Edit Customer action (for example, on the Customer Details page)
  • Update localization files to modify field labels

Each of these tasks will be described below in steps.

Step arrow right iconUI Component: SettingBaseStringSelector

`SettingBaseStringSelector`
component can be used for use cases when user has to have a combo box with options filled from the setting. On edit customer drawer the component will be used to present Country and Timezone selectors.

Create a new file:

`SettingBaseStringSelector.tsx`
.

1import { FC, useEffect, useState } from 'react';
2import { FormFieldProps } from 'mystique/registry/FieldRegistry';
3import { getSettings } from 'mystique/hooks/getSettings';
4import {
5  FormControl,
6  FormHelperText,
7  InputLabel,
8  MenuItem,
9  Select,
10} from '@material-ui/core';
11import { useAuth } from 'mystique/hooks/useAuth';
12
13const SettingBaseStringSelector: FC<FormFieldProps<any>> = (props) => {
14  const auth = useAuth();
15
16  const settingName = props.extensions?.settingName;
17  const [items, setItems] = useState<string[]>([]);
18  const [currentItem, setCurrentItem] = useState<string | undefined>(
19    props.value,
20  );
21
22  useEffect(() => {
23    if (settingName) {
24      getSettings(
25        { setting: settingName },
26        parseInt(auth.context.current.contextId),
27      ).then((value) => {
28        if (value.setting.status == 'ok') {
29          const list: string[] = [...value.setting.result.value];
30          if (props.value && !list.includes(props.value)) {
31            list.push(props.value);
32          }
33          setItems(list);
34        }
35      });
36    } else {
37      setItems([]);
38    }
39  }, [settingName]);
40
41  useEffect(() => {
42    if (currentItem) {
43      props.onChange(currentItem);
44    } else {
45      props.onChange(undefined);
46    }
47  }, [currentItem]);
48
49  const handleChange = (event: any) => {
50    setCurrentItem(event.target.value as string);
51  };
52
53  const handleOnBlur = () => {
54    props && props.onBlur && props.onBlur();
55  };
56
57  return (
58    <FormControl fullWidth error={!!props.error}>
59      <InputLabel id="string-select-label">{props.label}</InputLabel>
60      <Select
61        labelId="string-select-label"
62        id="string-select"
63        label={props.label}
64        onChange={handleChange}
65        onBlur={handleOnBlur}
66        value={currentItem}
67      >
68        {items.map((value, idx) => {
69          return (
70            <MenuItem key={idx} value={value} selected={currentItem === value}>
71              {value}
72            </MenuItem>
73          );
74        })}
75      </Select>
76      {props.error && <FormHelperText>{props.error}</FormHelperText>}
77    </FormControl>
78  );
79};
80
81export default SettingBaseStringSelector;

Language: typescript

Name: SettingBaseStringSelector.tsx

Description:

SettingBaseStringSelector component implementation example

1import SettingBaseStringSelector from './fields/SettingBaseStringSelector';
2
3
4
5
6
7FieldRegistry.register(
8  ['settingBaseStringSelector'],
9  SettingBaseStringSelector,
10);

Language: typescript

Name: index.tsx

Description:

SettingBaseStringSelector field component registration

Step arrow right iconUI Component: BooleanSelector

`BooleanSelector`
component is used to customize the look and feel of the default boolean field component (check box with the label after instead of a switcher with the label before).

Create a new file:

`BooleanSelector.tsx`
.

1import { FC, useEffect, useState } from 'react';
2import { FormFieldProps } from 'mystique/registry/FieldRegistry';
3import {
4  Checkbox,
5  FormControl,
6  FormControlLabel,
7  FormHelperText,
8} from '@material-ui/core';
9
10
11const BooleanSelector: FC<FormFieldProps<any>> = (props) => {
12  const [checked, setChecked] = useState<boolean>(
13    props.extensions?.checked || props.value || false,
14  );
15
16  useEffect(() => {
17    props.onChange(`${checked}`);
18  }, [checked]);
19
20  const handleChange = (event: any) => {
21    setChecked(event.target.checked as boolean);
22  };
23
24  const handleOnBlur = () => {
25    props && props.onBlur && props.onBlur();
26  };
27
28  return (
29    <FormControl fullWidth error={!!props.error}>
30      <FormControlLabel
31        control={
32          <Checkbox
33            id="checkbox-selector"
34            onChange={handleChange}
35            onBlur={handleOnBlur}
36            checked={checked}
37          />
38        }
39        label={props.label}
40      />
41      {props.error && <FormHelperText>{props.error}</FormHelperText>}
42    </FormControl>
43  );
44};
45
46export default BooleanSelector;

Language: typescript

Name: BooleanSelector.tsx

Description:

BooleanSelector component implementation example

1import BooleanSelector from './fields/BooleanSelector';
2
3
4
5FieldRegistry.register(['booleanSelector'], BooleanSelector);

Language: typescript

Name: index.tsx

Description:

BooleanSelector field component registration

Step arrow right iconSetting: EDIT_LOCATION_COUNTRIES

`EDIT_LOCATION_COUNTRIES`
setting represents a list of countries available to select for customer information updates.

Name

EDIT_LOCATION_COUNTRIES

Value Type

JSON

Context

ACCOUNT or RETAILER

Context ID

0 or Retailer ID

JSON Value

`["Australia","Canada","France","Germany","United Kingdom","United States"]`

Create Setting

1POST: {{fluentApiHost}}/graphql
2
3## create a postman environment variable:
4## Variable: json_value
5## initial val + current value: 
6[
7    "Australia",
8    "Canada",
9    "France",
10    "Germany",
11    "United Kingdom",
12    "United States"
13]
14
15
16# GraphQL variables:
17{
18	"retailerId": {{retailer_id}},
19    "lobValue" : {{json_value}}
20}
21
22
23#GraphQL Query:
24mutation CreateSetting($retailerId:Int! , $lobValue:Json)  {
25createSetting(input: {
26		name: "EDIT_LOCATION_COUNTRIES", 
27		valueType: "JSON", 
28		lobValue:$lobValue , 
29		context: "RETAILER", 
30		contextId:$retailerId}) {
31    id
32    name
33  }
34}

Language: graphqlschema

Name: create setting EDIT_LOCATION_COUNTRIES

Description:

[Warning: empty required content area]

Update Setting

1POST: {{fluentApiHost}}/graphql
2
3## create a postman environment variable:
4## Variable: json_value
5## initial val + current value: 
6[
7    "Australia",
8    "Canada",
9    "France",
10    "Germany",
11    "United Kingdom",
12    "United States"
13]
14
15
16# GraphQL variables:
17{
18	"retailerId": {{retailer_id}},
19    "lobValue" : {{json_value}}
20}
21
22
23#GraphQL Query:
24mutation updateSetting($retailerId:Int! , $lobValue:Json) {
25updateSetting(input: {
26        id: 5001471,
27		name: "EDIT_LOCATION_COUNTRIES", 
28		valueType: "JSON", 
29        lobValue: $lobValue,
30		context: "RETAILER", 
31		contextId: $retailerId}) {
32    id
33    name
34  }
35}
36

Language: graphqlschema

Name: update setting EDIT_LOCATION_COUNTRIES

Description:

[Warning: empty required content area]

Step arrow right iconSetting: EDIT_LOCATION_TIME_ZONES

`EDIT_LOCATION_TIME_ZONES`
setting represents a list of timezones available to select for customer information updates.

Name

EDIT_LOCATION_TIME_ZONES

Value Type

JSON

Context

ACCOUNT or RETAILER

Context ID

0 or Retailer ID

JSON Value

`[`

`"GMT",`

`"UTC",`

`"ECT",`

`"EET",`

`"ACT",`

`"AET",`

`"HST",`

`"AST",`

`"PST",`

`"PNT",`

`"MST",`

`"CST",`

`"EST",`

`"IET",`

`"PRT",`

`"CNT"`

`]`


Create Setting

1POST: {{fluentApiHost}}/graphql
2
3## create a postman environment variable:
4## Variable: json_value
5## initial val + current value: 
6[
7    "GMT",
8    "UTC",
9    "ECT",
10    "EET",
11    "ACT",
12    "AET",
13    "HST",
14    "AST",
15    "PST",
16    "PNT",
17    "MST",
18    "CST",
19    "EST",
20    "IET",
21    "PRT",
22    "CNT"
23]
24
25
26# GraphQL variables:
27{
28	"retailerId": {{retailer_id}},
29    "lobValue" : {{json_value}}
30}
31
32
33#GraphQL Query:
34mutation CreateSetting($retailerId:Int! , $lobValue:Json)  {
35createSetting(input: {
36		name: "EDIT_LOCATION_TIME_ZONES", 
37		valueType: "JSON", 
38		lobValue:$lobValue , 
39		context: "RETAILER", 
40		contextId:$retailerId}) {
41    id
42    name
43  }
44}

Language: graphqlschema

Name: create setting EDIT_LOCATION_TIME_ZONES

Description:

[Warning: empty required content area]

Update Setting

1POST: {{fluentApiHost}}/graphql
2
3## create a postman environment variable:
4## Variable: json_value
5## initial val + current value: 
6[
7    "GMT",
8    "UTC",
9    "ECT",
10    "EET",
11    "ACT",
12    "AET",
13    "HST",
14    "AST",
15    "PST",
16    "PNT",
17    "MST",
18    "CST",
19    "EST",
20    "IET",
21    "PRT",
22    "CNT"
23]
24
25
26# GraphQL variables:
27{
28	"retailerId": {{retailer_id}},
29    "lobValue" : {{json_value}}
30}
31
32
33#GraphQL Query:
34mutation updateSetting($retailerId:Int! , $lobValue:Json) {
35updateSetting(input: {
36        id: 5001471,
37		name: "EDIT_LOCATION_TIME_ZONES", 
38		valueType: "JSON", 
39        lobValue: $lobValue,
40		context: "RETAILER", 
41		contextId: $retailerId}) {
42    id
43    name
44  }
45}
46

Language: graphqlschema

Name: update setting EDIT_LOCATION_TIME_ZONES

Description:

[Warning: empty required content area]

Step arrow right iconManifest changes

`Edit Customer`
action has to be declared as mutation user action
`updateCustomer`
on page component (see Page Component).

1{
2    "type": "mutation",
3    "label": "i18n:fc.om.customers.updateCustomer.button.Label",
4    "name": "updateCustomer",
5    "args": {
6        "ref": "{{customerById.username}}"
7    },
8    "overrides": {
9        "title": {
10            "sortPrefix": 11
11        },
12        "firstName": {
13            "sortPrefix": 12
14        },
15        "lastName": {
16            "sortPrefix": 13
17        },
18        "primaryEmail": {
19            "sortPrefix": 14
20        },
21        "primaryPhone": {
22            "sortPrefix": 15
23        },
24        "country": {
25            "sortPrefix": 17,
26            "component": "settingBaseStringSelector",
27            "extensions": {
28                "settingName": "EDIT_LOCATION_COUNTRIES"
29            }
30        },
31        "timezone": {
32            "sortPrefix": 18,
33            "component": "settingBaseStringSelector",
34            "extensions": {
35                "settingName": "EDIT_LOCATION_TIME_ZONES"
36            }
37        },
38        "promotionOptIn": {
39            "component": "booleanSelector",
40            "sortPrefix": 19
41        },
42        "attributes": {
43            "sortPrefix": 21
44        },
45        "username": {
46            "sortPrefix": 22,
47            "component": "input",
48            "options": [
49                {
50                    "label": "current Username",
51                    "value": "{{customerById.username}}"
52                }
53            ]
54        }
55    }
56}

Language: json

Name: Edit Customer mutation user action

Description:

Edit Customer mutation user action declaration example. Property

`sortPrefix`
is used to configure order of fields on the drawer


Step arrow right iconUpdate Language Setting

Localization of fields is done by creating localization entries to mutation fields according to name convention (see Languages and Localisation, chapter 'Adding new Mutation Actions').

1{
2  "translation": {
3      "fc.om.customers.updateCustomer.button.Label": "Update Customer",
4    "fc.gql.customer.title": "Title",
5    "fc.gql.customer.firstName": "First Name",
6    "fc.gql.customer.lastName": "Last Name",
7    "fc.gql.customer.username": "Username",
8    "fc.gql.customer.primaryEmail": "Primary Email",
9    "fc.gql.customer.primaryPhone": "Primary Phone",
10    "fc.gql.customer.country": "Country",
11    "fc.gql.customer.timezone": "Timezone",
12    "fc.gql.customer.promotionOptIn": "Customer has opted to receive promotions",
13    "fc.gql.customer.retailer.label": "Retailer"
14  }
15}

Language: json

Name: New localization entries

Description:

Example of mutation field labels localisation with using name convention

Step arrow right iconResult

After all steps,

`Edit Customer`
action has to be available on the page. 

No alt providedNo alt provided

Step arrow right iconRelated Sources

Copyright © 2024 Fluent Retail Pty Ltd (trading as Fluent Commerce). All rights reserved. No materials on this docs.fluentcommerce.com site may be used in any way and/or for any purpose without prior written authorisation from Fluent Commerce. Current customers and partners shall use these materials strictly in accordance with the terms and conditions of their written agreements with Fluent Commerce or its affiliates.

Fluent Logo