Add and Edit Customer Address by using custom UI component
Author:
Siarhei Vaitsiakhovich
Changed on:
7 July 2024
Key Points
- Address Validation: Ensure that the address entered by the user is valid and correctly formatted to avoid shipping issues.
- Default Address: Allow customers to set a default address for a quicker checkout process.
- Edit Capability: Provide an option for users to edit customer address details in case of errors or changes.
- User Experience: Design the add and edit address process to be user-friendly and accessible, with clear instructions and error messages.
Prerequisites
Steps
Use Case
To ensure a seamless experience for users managing customers' address information, the following use cases outline the process for adding and editing customer addresses:
- Add a New Address: Customer can add a new address by filling out a form with their details. This form includes fields for the company name, street address, city, state, postal code, country, and timezone.
- Set Default Addresses: After adding an address, the address will be used as default to streamline future checkouts.
- Edit Existing Address: The user can edit the customer-saved address at any time. This is useful for correcting mistakes or updating the address information if they move.
Solution Approach
The feature can be implemented via the declaration of a custom mutation user actions
`createCustomerAddress`
`updateCustomerAddress`
For a better user experience, part of the default mutation field components have to be overridden. List of fields to override:
- Country
- Timezone
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:
- Reference (only for 'Add Customer Address' action)
- Company Name
- Street
- City
- State
- Postcode
- Region
- Country
- Timezone
To save data consistency, options for Timezone and Country selectors have to be loaded from settings. For 'Edit Customer Address' action, all fields have to be prefilled with current user information.
Technical Design Overview
To support the business solution design, the following technical areas need to be enhanced:
- New custom UI component (by using Component SDK) -
`SettingBaseStringSelector`
- Declare settings to use it for Country and Timezone selectors
- Update manifest to add new conditionally visible actions 'Add Customer Address' and 'Edit Customer Address' (for example on the Customer Details page)
- Update localization files to modify field labels
Each of these tasks will be described below in steps.
UI Component: SettingBaseStringSelector
`SettingBaseStringSelector`
Create a new file:
`SettingBaseStringSelector.tsx`
1const SettingBaseStringSelector: FC<FormFieldProps<any>> = (props) => {
2 const auth = useAuth();
3
4 const settingName = props.extensions?.settingName;
5 const [items, setItems] = useState<string[]>([]);
6 const [currentItem, setCurrentItem] = useState<string | undefined>(
7 props.value,
8 );
9
10 useEffect(() => {
11 if (settingName) {
12 getSettings(
13 { setting: settingName },
14 parseInt(auth.context.current.contextId),
15 ).then((value) => {
16 if (value.setting.status == 'ok') {
17 const list: string[] = [...value.setting.result.value];
18 if (props.value && !list.includes(props.value)) {
19 list.push(props.value);
20 }
21 setItems(list);
22 }
23 });
24 } else {
25 setItems([]);
26 }
27 }, [settingName]);
28
29 useEffect(() => {
30 if (currentItem) {
31 props.onChange(currentItem);
32 } else {
33 props.onChange(undefined);
34 }
35 }, [currentItem]);
36
37 const handleChange = (event: any) => {
38 setCurrentItem(event.target.value as string);
39 };
40
41 const handleOnBlur = () => {
42 props && props.onBlur && props.onBlur();
43 };
44
45 return (
46 <FormControl fullWidth error={!!props.error}>
47 <InputLabel id="string-select-label">{props.label}</InputLabel>
48 <Select
49 labelId="string-select-label"
50 id="string-select"
51 label={props.label}
52 onChange={handleChange}
53 onBlur={handleOnBlur}
54 value={currentItem}
55 >
56 {items.map((value, idx) => {
57 return (
58 <MenuItem key={idx} value={value} selected={currentItem === value}>
59 {value}
60 </MenuItem>
61 );
62 })}
63 </Select>
64 {props.error && <FormHelperText>{props.error}</FormHelperText>}
65 </FormControl>
66 );
67};
68
69export default SettingBaseStringSelector;
Language: typescript
Name: SettingBaseStringSelector.tsx
Description:
SettingBaseStringSelector component implementation example
1FieldRegistry.register(
2 ['settingBaseStringSelector'],
3 SettingBaseStringSelector,
4);
Language: typescript
Name: index.tsx
Description:
SettingBaseStringSelector field component registration
Setting: EDIT_LOCATION_COUNTRIES
`EDIT_LOCATION_COUNTRIES`
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" ] |
Setting: EDIT_LOCATION_TIME_ZONES
`EDIT_LOCATION_TIME_ZONES`
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" ] |
Manifest changes
`Add and Edit Customer Address`
`Add Customer Address`
`Edit Customer Address`
`createCustomerAddress`
`updateCustomerAddress`
`condition`
`Add Customer Address`
`Edit Customer Address`
1{
2 "type": "mutation",
3 "label": "Add Customer Address",
4 "name": "createCustomerAddress",
5 "condition": "{{eq customerAddresses.edges.length 0}}",
6 "filter": {
7 "type": "exclude",
8 "names": [
9 "latitude",
10 "longitude"
11 ]
12 },
13 "overrides": {
14 "ref": {
15 "sortPrefix": 11
16 },
17 "companyName": {
18 "sortPrefix": 12
19 },
20 "street": {
21 "sortPrefix": 13
22 },
23 "city": {
24 "sortPrefix": 14
25 },
26 "state": {
27 "sortPrefix": 15
28 },
29 "postcode": {
30 "sortPrefix": 16
31 },
32 "region": {
33 "sortPrefix": 17
34 },
35 "country": {
36 "sortPrefix": 18,
37 "component": "settingBaseStringSelector",
38 "extensions": {
39 "settingName": "EDIT_LOCATION_COUNTRIES"
40 }
41 },
42 "timeZone": {
43 "sortPrefix": 19,
44 "component": "settingBaseStringSelector",
45 "extensions": {
46 "settingName": "EDIT_LOCATION_TIME_ZONES"
47 }
48 },
49 "name": {
50 "component": "input",
51 "sortPrefix": 20,
52 "options": [
53 {
54 "label": "Customer Name",
55 "value": "{{customerById.firstName}} {{customerById.lastName}}"
56 }
57 ]
58 }
59 }
60},
61{
62 "type": "mutation",
63 "label": "Edit Customer Address",
64 "name": "updateCustomerAddress",
65 "condition": "{{gt customerAddresses.edges.length 0}}",
66 "filter": {
67 "type": "exclude",
68 "names": [
69 "name",
70 "latitude",
71 "longitude"
72 ]
73 },
74 "args": {
75 "id": "{{customerAddresses.edges.0.node.id}}"
76 },
77 "overrides": {
78 "companyName": {
79 "sortPrefix": 12
80 },
81 "street": {
82 "sortPrefix": 13
83 },
84 "city": {
85 "sortPrefix": 14
86 },
87 "state": {
88 "sortPrefix": 15
89 },
90 "postcode": {
91 "sortPrefix": 16
92 },
93 "region": {
94 "sortPrefix": 17
95 },
96 "country": {
97 "sortPrefix": 18,
98 "component": "settingBaseStringSelector",
99 "extensions": {
100 "settingName": "EDIT_LOCATION_COUNTRIES"
101 }
102 },
103 "timeZone": {
104 "sortPrefix": 19,
105 "component": "settingBaseStringSelector",
106 "extensions": {
107 "settingName": "EDIT_LOCATION_TIME_ZONES"
108 }
109 },
110 "name": {
111 "component": "input",
112 "sortPrefix": 20,
113 "options": [
114 {
115 "label": "Customer Name",
116 "value": "{{customerById.firstName}} {{customerById.lastName}}"
117 }
118 ]
119 }
120 }
121}
122
123
Language: json
Name: Add and Edit Customer Address actions
Description:
Add and Edit Customer Address mutation user actions declaration example. Property
`sortPrefix`
Update Language Setting
Localization of fields is done by creating localization entries for mutation fields according to name convention (see Languages and Localisation, chapter 'Adding new Mutation Actions').
1{
2 "translation": {
3 "fc.gql.customerAddress.ref": "Ref",
4 "fc.gql.customerAddress.companyName": "Company Name",
5 "fc.gql.customerAddress.street": "Street",
6 "fc.gql.customerAddress.city": "City",
7 "fc.gql.customerAddress.state": "State",
8 "fc.gql.customerAddress.postcode": "Postcode",
9 "fc.gql.customerAddress.region": "Region",
10 "fc.gql.customerAddress.country": "Country",
11 "fc.gql.customerAddress.timeZone": "Timezone"
12 }
13}
Language: json
Name: New localization entries
Description:
Example of mutation field labels localisation with using name convention
Result
After all steps,
`Add Customer Address`
`Edit Customer Address`
`Add Customer Address`


`Edit Customer Address`

