
In this walkthrough, we’ll be examining how we built the commerce app’s my account page. Primarily, we’ll look at the different sections and what API calls were necessary to fill them out.
Two pre-requisites before we continue are to obtain the application context and have a session with an authenticated user. Here’s a brief overview:
Resolve the tenant and application
Send a request to authenticate the user and determine permissions, whether as anonymous or signed-in
Let’s take a look at the Account Details. The Account Details are centered around the customer’s login information.
Here we can update the customer’s name, email and password. The actions rely on two services,
Authentication and Customer.
You will be using the SDK packages that reflect those services, which are the auth package (in this case the react specific project), '@broadleaf/auth-react'
,
and the customer SDK package, '@broadleaf/commerce-customer'
.
When we arrive on the page we notice that the Full Name and Email pages are populated on arrival.
These are populated from the Customer
that can be fetched with CustomerClient.getCustomer
from the Commerce SDK.
This method takes a customerId
(from the authenticated user) and an accessToken
that is passed as the authorization header in the request.
Tip
|
You will need to get an access token for any API requests for user-specific data such as the Customer DTO or pricing.
|
In the case of using a React application, we will use the useAuth
react hook.
This hook will return an AuthContextShape
that contains two important properties: The user
object
that contains customer_id
and the getAccessToken
method which will get a valid accessToken
that
will enable us to securely obtain a customers information. The result is a Customer
object that
contains the properties such as email
and fullName
;
import { useAuth } from '@broadleaf/auth-react';
import { CustomerClient } from '@broadleaf/commerce-customer';
import { ClientOptions } from '@broadleaf/commerce-core';
async function getCustomer(options: ClientOptions) {
const { user, getAccessToken } = useAuth();
const customerId = user?.customer_id;
const accessToken = await getCustomerToken();
const client = new CustomerClient(options);
const customer = await client.getCustomer(customerId, {
accessToken
});
return customer;
}
METHOD |
URL |
SDK |
|
Read Customer by ID |
GET |
/customers/<CUSTOMER_ID> |
getCustomer(customerId, { accessToken }) |
{
"firstName": "Alan",
"middleName": "Mathison",
"lastName": "Turning",
"fullName": "Alan Turning",
"username": "alan_turing",
"email": "alan@turning.net",
"externalId": "hl123gh4",
"phone": {
"countryCode": "+1",
"phoneNumber": "555-5555",
"extension": "666"
},
"additionalPhones": [ ... ],
"id": "1234",
"contextState": { ... }
}
The values from the inputs both rely on a updateCustomer
in which we create an updated customer object with
the the updated properties. Updating the password is handled by the method changePasswordWithRedirect
which
will launch a new page where they will be able to change the password.
import { useAuth } from '@broadleaf/auth-react';
import { CustomerClient } from '@broadleaf/commerce-customer';
import { ClientOptions } from '@broadleaf/commerce-core';
async function getCustomer(options: ClientOptions, updatedCustomer: Customer) {
const { user, getAccessToken } = useAuth();
const customerId = user?.customer_id;
const accessToken = await getCustomerToken();
const client = new CustomerClient(options);
await client.updateCustomer(customerId, updatedCustomer {
accessToken
});
}
Now we take a look at the Saved Address Page, which contains the customers address and give the ability to modify the addresses on file. image::maw-1.png[Saved Addresses]
In order to list the addresses on file, we follow similar steps that we used to populate the Account Details Page, which is obtain the current user’s
customer_id
and accessToken
and use the CustomerClient
to call listCustomerAddresses
to get a list of Address
objects.
import { useAuth } from '@broadleaf/auth-react';
import { CustomerClient } from '@broadleaf/commerce-customer';
import { ClientOptions } from '@broadleaf/commerce-core';
async function getAddresses(options: ClientOptions) {
const { user, getAccessToken } = useAuth();
const customerId = user?.customer_id;
const accessToken = await getCustomerToken();
const client = new CustomerClient(options);
const addresses = await client.listCustomerAddresses(customerId, {
accessToken
});
return addresses;
}
METHOD |
URL |
SDK |
|
List Customer Addresses |
GET |
/customers/<CUSTOMER_ID>/addresses |
listCustomerAddresses(customerId, { accessToken }) |
This is an example of the response for obtaining a list of Address.
{
"first": "John",
"last": "Doe",
"numberOfElements": 0,
"pageable": { ... },
"sort": [ ... ],
"content": [
{
"name": "Home Address",
"defaultShippingAddress": true,
"defaultBillingAddress": true,
"firstName": "John",
"lastName": "Doe",
"fullName": "John Doe",
"emailAddress": "john@doe.com",
"companyName": "Broadleaf LLC",
"addressLine1": "1234 Main St",
"addressLine2": "Apt 1",
"addressLine3": null,
"city": "Austin",
"county": "Travis",
"stateProvinceRegion": "TX",
"country": "United States",
"postalCode": "78727",
"phonePrimary": { ... },
"phoneSecondary": { ... },
"phoneFax": {
"countryCode": "string",
"phoneNumber": "string",
"extension": "string"
},
"isActive": true,
"id": "string",
"customer": {
"id": "string",
"username": "string",
"email": "string"
},
.... }
}
]
}
Now CRUD (Create, Read, Update, Delete) Operations on an address are done through the
endpoint /customers/<customerId>/addresses/
which the SDK mirrors through the methods addCustomerAddress
,
getCustomerAddress
, updateCustomerAddress
, and deleteCustomerAddress
. Note just as we have done for prior
actions, we must obtain the customer_id
, and accessToken
from the Auth.
METHOD |
URL |
SDK |
|
Create Address |
POST |
/customers/<CUSTOMER_ID>/addresses |
addCustomerAddress(customerId, address, { accessToken }) |
Read Address |
POST |
/customers/<CUSTOMER_ID>/addresses/<ADDRESS_ID> |
getCustomerAddress(customerId, customerAddressId, { accessToken }) |
Update Address |
PUT |
/customers/<CUSTOMER_ID>/addresses/<ADDRESS_ID> |
updateCustomerAddress(customerId, customerAddressId, updatedAddress, { accessToken }) |
Delete Address |
DELETE |
/customers/<CUSTOMER_ID>/addresses/<ADDRESS_ID> |
deleteCustomerAddress(customerId, customerAddressId, { accessToken }) |
This is an example of a Address
object.
{
"name": "Home Address",
"defaultShippingAddress": true,
"defaultBillingAddress": true,
"firstName": "John",
"lastName": "Doe",
"fullName": "John Doe",
"emailAddress": "john@doe.com",
"companyName": "Broadleaf LLC",
"addressLine1": "1234 Main St",
"addressLine2": "Apt 1",
"addressLine3": null,
"city": "Austin",
"county": "Travis",
"stateProvinceRegion": "TX",
"country": "United States",
"postalCode": "78727",
"phonePrimary": { ... },
"phoneSecondary": { ... },
"phoneFax": {
"countryCode": "string",
"phoneNumber": "string",
"extension": "string"
},
"isActive": true,
"id": "string",
"customer": {
"id": "string",
"username": "string",
"email": "string"
},
.... }
}
Now we take a look at the Saved Payments Page, which contains the customers payments accounts and gives the ability to modify only the name and address on the payment account on file.
In order to list the payment accounts on file, we obtain the current user’s customer_id
and accessToken
and
use the CustomerClient
to call listCustomerPaymentAccounts
to get a list of PaymentAccount
objects.
import { useAuth } from '@broadleaf/auth-react';
import { CustomerClient } from '@broadleaf/commerce-customer';
import { ClientOptions } from '@broadleaf/commerce-core';
async function getPaymentAccounts(options: ClientOptions) {
const { user, getAccessToken } = useAuth();
const customerId = user?.customer_id;
const accessToken = await getCustomerToken();
const client = new CustomerClient(options);
const accounts = await client.listCustomerPaymentAccounts(customerId, {
accessToken
});
return accounts;
}
CRUD (Create, Read, Update, Delete) Operations on a payment account are done through the
endpoint /customers/<customerId>/payment-accounts/
which the SDK mirrors through the methods addCustomerPaymentAccount
,
getCustomerPaymentAccount
, updateCustomerPaymentAccount
, and deleteCustomerPaymentAccount
. Note just as we have done for prior
actions, we must obtain the customer_id
, and accessToken
from the Auth.
METHOD |
URL |
SDK |
|
Create Payment Account |
POST |
/customers/<CUSTOMER_ID>/payment-accounts |
addCustomerPaymentAccount(customerId, paymentAccount, { accessToken }) |
Read Payment Account |
POST |
/customers/<CUSTOMER_ID>/payment-accounts/<PAYMENT_ACCOUNT_ID> |
getCustomerPaymentAccount(customerId, paymentAccountId, { accessToken }) |
Update Payment Account |
PUT |
/customers/<CUSTOMER_ID>/payment-accounts/<PAYMENT_ACCOUNT_ID> |
updateCustomerPaymentAccount(customerId, paymentAccountId, updatedPaymentAccount, { accessToken }) |
Delete Payment Account |
DELETE |
/customers/<CUSTOMER_ID>/payment-accounts/<PAYMENT_ACCOUNT_ID> |
deleteCustomerPaymentAccount(customerId, paymentAccountId, { accessToken }) |
This is an example of a PaymentAccount
object.
{
"customerRef": {
"customerId": "12345",
"username": "john_doe",
"isRegistered": true
},
"displayName": "Chase Card",
"accountType": "Credit Card",
"cardType": "VISA",
"gatewayType": "string",
"paymentGatewayProperties": { ... },
"maskedAccountNumber": "1234",
"nameOnAccount": "John Doe",
"expirationMonth": 12,
"expirationYear": 21,
"fullName": "John Doe",
"addressLine1": "1234 Main St",
"addressLine2": "Apt 5",
"city": "Austin",
"stateProvinceRegion": "TX",
"country": "United States",
"postalCode": "78727",
"phonePrimary": { ... },
"lastTransactionDateTime": "2021-07-08T15:55:31.395Z",
"lastTransactionResultCode": "SUCCESS"
}