Build a Card for the Customer Profile

Prev Next

Background

This tutorial demonstrates how to build and configure Cards for displaying data in Gladly. Cards provide a flexible framework for visualizing your app data and presenting it based on customizable UI layouts (also known as “card templates” or simply “cards”), allowing you to display rich customer information directly in Gladly Hero. The card templates are an integral part of the app. They provide a reusable way of displaying your app data in various Gladly Hero. For more in-depth information about the Cards, please see this help article.

In this tutorial, we'll create a card that is ready to be rendered in Gladly Hero customer profile and display a list of the customer’s orders. The card will look similar to the image below:
Card.png

This tutorial should be used as a learning tool and demonstrates the core concepts of building Cards with real customer data!

What You'll Build

By the end of this tutorial, you'll have created a Card template that displays:

  • Dynamic title showing total number of orders

  • Collapsible “drawers” for each order

  • Order management integration links

  • Product images and details

  • Formatted shipping addresses

  • Order status and shipping information

The card will look like this in Gladly Hero:

  • A profile card titled "N Orders" (the number “N” is dynamically calculated)

  • A list of customer orders

  • Each order displayed in an expandable “drawer” that has:

    • A fixed section showing order number, date, and total

    • An expandable section with management links, status, and product details

Card with Expanded Drawer-Annotations.png

Before you begin

To get the most out of this tutorial, you should have a working app that provides customer order data. You are welcome to use your own app or to fork Gladly “sample OMS” learning app. In this tutorial, we assume that you are working with Gladly’s “sample OMS” app fork - which also comes with some prebuilt card templates that you can use as a reference. If you don’t know how to get access to the sample app, your Gladly representative will help you.

What you need to know

Before you start, you need to:

  • Have a good understanding of Gladly’s App platform. If you are new to the App platform, please take a moment to study this first:

    • https://help.gladly.com/developer-tutorials/docs/app-platform-overview

    • https://help.gladly.com/developer-tutorials/docs/architecture-2

  • Have some basic working knowledge of XML-like markup. There are many excellent resources on the Internet: W3Schools, Tutorialspoint, MDN and many more. You are welcome to choose any resource that suits your style. You don’t need to become an expert in XML but you need to understand:

    • What a well-formed tag is

    • How to work with tag properties

What tools you will need

About the Card Framework

Cards use template-based rendering where data is merged into XML-like templates to create fully rendered cards. The framework provides:

  • Data Value Components Display formatted data (StringValue, CurrencyValue, DateTimeValue, etc.)

  • Container Components Organize content (Card, Section, Drawer, Block)

  • Layout Components Arrange content side-by-side (ColumnGroup, Column)

  • Iterators Loop through data arrays (List)

  • Decorators Enhance appearance (Divider, Spacer)

Helpful links

  • Quick start guide that provides an in-depth overview of the Card Framework: https://help.gladly.com/developer-tutorials/docs/cards-introduction-and-reference-guide. It also has some commonly used recipes for building cards.

  • Reference of the available Card components: https://help.gladly.com/developer-tutorials/docs/card-language-reference

Step-by-Step Tutorial

Overview

It is very important to understand that the Card Framework is not a general purpose UI toolkit, it is a way of visualizing your app data. That’s why the first step in developing a new card is to make sure that your app provides you with the right data that has all the required elements in a simple to handle form. While the Card Framework has built-in support for data interpolation, math and basic logic statements, it is not intended for data transformation tasks. Your app should provide the data in the shape that is display-ready, with the exception of some minor cosmetic treatment (e.g. the card may choose to display some value in Title Case instead of lowercase).

In the following steps, we will do the following:

  • We will make sure your appcfg CLI tool is configured and ready

  • We will use it to generate sample data - a very important step - that will be later used for modeling the Card

  • We will then create a new empty Card template

  • Then, we will work in the Visualizer to build out the Card

  • After that, we will save the newly developed card template to the app

  • Finally, we will verify the app, build it and submit to Gladly for review and enablement

While we will be working with the sample app, the “real life” process is exactly the same and the following steps will apply to your app and card template - either verbatim or with some very minor tweaks.

Step 1: Verify Your Development Environment

  1. Navigate to your app directory:

cd /path/to/your/app

  1. Verify appcfg is working:

appcfg version

  1. Check your app configuration:

appcfg apps list

Step 2: Generate Sample Data Using appcfg Commands

This is a very important step - the sample data shape must match the actual app data, otherwise your card may not display as intended - or in some cases, may not display at all.

We will use the appcfg tool to run a query against the app and generate the data, then we will “cull” the data in the text editor and save for the future iterations. But before we run any commands, we need to decide what data we want to display. All the available data types are found in the app graphQL schema (see app/data/data_schema.graphql) and when we check the Query type (it’s a special type that describes all possible queries and the result data types), we see that we have a choice of using either the output from the query named orders (just a list of orders) or from the query named customer (customer data with the list orders). You can’t go wrong with either one, but for the purpose of this tutorial we will use the latter.

A. Get the raw data

Run appcfg run data-graphql command and redirect output to a file. Make sure to save the file outside of the app root folder.
For example, if we were to capture the dump of the customer graphQL query in sample-oms app, the command would look like:

appcfg run data-graphql -d customer -q customer -s '{"apiToken": "none"}' > /path/to/your/working/folder/sample-data.txt

NOTES

  • In the above command, we provided the “app secrets” (via the -s flag) as '{"apiToken":"none"}' . This is specific to the “sample OMS” app - your own app will likely use different “secrets”. Please remember that the content of the -s flag must be a valid JSON.

  • The command uses a “dataset” (-d switch) to simplify the command and to make re-running the command easier. Datasets are folders in the app structure that contain “canned” data files so that you would not have to type the same information over and over. In case of “sample OMS” app, you may want to take a look at the content of the app/data/_run_/data/customer folder - that is the “customer” dataset that is being used in the command.

B. “Calling” the raw data and creating the sample data JSON

Now that we have captured the raw graphQL query output, we need to extract the portion that will be used when the card is displayed in Gladly Hero. Open the file you created on the previous step in your favorite text editor and scroll to the end. Towards the end, you will see the combined data structure that would look like:

{
	data: {                        // <<- This is the "envelope" that every GraphQL response will have
		customer: {                  // <<- This is the name of the query (in our example, "customer")
			fullName: "...",
			gladlyAppConfigId: "...",
			...
		}
	}
}

Extract the attributes inside the <query name> object (”customer” object in our example above). This is the data that you need:

{                  
  fullName: "...",
	gladlyAppConfigId: "...",
	...
}

Format the data as JSON (you can use your IDE or any of the online JSON formatters) and save it to a file with .json extension.

Step 3. Add an Empty Card Template to the App

Even though “sample OMS” app comes with a prebuilt Card template, we will create a new one from scratch. You are welcome to use the existing card as a reference.

First, we will use appcfg tool to create a new card skeleton and the required folders. Let’s assume that we want to call the new card file customer-orders. On the previous step, we created a sample data file that was based on the graphQL query called customer that returns a result of type Customer. Based on that, let’s create a new Card:

appcfg add ui-template "customer-orders" -s "data" -t Customer -d "Display customer's recent orders"

NOTES

  • The name that we choose for the new Card becomes a part of the folder structure (see below). Because if that, it cannot contain slashes or special characters (such as “double dots” or emoji). Try to limit the characters used in the card name to Latin letters and digits plus dashes and underscores. While other characters may also work, it is not recommended for compatibility reasons.

  • Please try to provide a meaningful card description (-d flag). This description is used by Gladly when configuring the card. Using a good description greatly reduces the chances of errors when enabling the card in Gladly Hero.

Once the appcfg has finished, go to app/ui/templates/customer-orders folder and locate the file named flexible.card. Open it in the text editor of your choice and replace directive <?Template languageVersion="1.0" ?> at the beginning of the file, with <?Template languageVersion="1.1" ?> (1.1 is our current GA version and it has the features that we will need in order to build the order card). Save the file.

Step 4. Use Visualizer to Build Out the New Card

A. Start the Visualizer

Open the following URL in your browser: https://redesigned-adventure-wg6zn5l.pages.github.io. On the first start, it may take a few seconds to load all required scripts. Please note that while the tool should work in most modern browsers, only the latest version of Chrome is officially supported.

B. Upload the Sample Data and the Card Template

Once Visualizer is loaded and you see the panels on the left and preview pane on the right:

  • Begin by uploading the sample data. In the Test Data panel (bottom left), locate “Upload from file” link next to the panel title and click it. Navigate to the JSON file you created on step 2 (Step 2: Generate Sample Data Using appcfg Commands) and click OK.

  • Now upload the card template. In the top left panel (titled “Template Code”), locate and click “Upload from file”. Navigate to the empty card template we created on the previous step (the file name will be app/ui/templates/customer-orders/flexible.card) and click OK.

You should see your sample data populated in the bottom panel and the card template code in the top panel:

<?Template languageVersion="1.1" ?>
<Card>
</Card>

The preview panel on the right should display no syntax errors. If you see any syntax errors either in the data or in the template code, fix them before continuing with the tutorial.

C. Edit the Card Template

In the Template Code panel, edit the Card code:

<?Template languageVersion="1.1" ?>
<Card title="{{ orders | length }} Orders">
  <Text>Hello, world!</Text>
</Card>

NOTES

  • The <?Template languageVersion="1.1" ?> declaration is required

  • In the above template, we used {{...}} construct to calculate the order count based on the provided data and merge it with the static text. This technique is called “data interpolation”. Please refer to https://help.gladly.com/developer-tutorials/docs/cards-introduction-and-reference-guide for details on what interpolation commands are available and where in the template they can appear

By now, you should see a real time preview of the card on the right: a simple card with title “N Orders” and text “Hello, world!” in the body. If you see any errors instead, fix the errors before continuing.

D. Build Out the Order List

Now that you have a very simple card, let’s build it out. Since our goal is to display a list of orders, we need a way to display the data from the orders array. This is done by using an “iterator” component called List (see https://help.gladly.com/developer-tutorials/docs/card-language-reference for a complete list of available components). Edit your card code as follows:

<?Template languageVersion="1.1" ?>
<Card title="{{ orders | length }} Orders">
  <List dataSource="orders" separateItems="true">
    <StringValue dataSource="orderNumber" label="Order Number" />
  </List>
</Card>

Now the preview on the right should display some data in the card.

NOTE

  • The “dataSource” attribute tells the components where to get the data. Refer to https://help.gladly.com/developer-tutorials/docs/cards-introduction-and-reference-guide for more details. Data binding in particular is discussed in https://help.gladly.com/developer-tutorials/docs/cards-introduction-and-reference-guide#connecting-components-with-the-data

At this point, we can start building out the order information part of the card. We will get rid of the <StringValue> stand-in and replace it with a <Drawer> component that is much better suited for displaying complex structured data:

<?Template languageVersion="1.1" ?>
<Card title="{{ orders | length }} Orders">
  <List dataSource="orders" separateItems="true">
    <Drawer initialState="expandFirst">
	    <Fixed>
	      <StringValue dataSource="orderNumber" label="Order Number" />
	      <DateTimeValue dataSource="orderDate" format="MM/DD/YYYY" label="Order Date" />
	      <CurrencyValue dataSource="totalPrice" label="Total Amount" />
	    </Fixed>
	    <Expandable>
	      <Link linkText="Manage the order" linkUrl="https://www.example.com/my-oms/orders/{{- id }}" />
	    </Expandable>
	  </Drawer>
  </List>
</Card>

As you can see from the code, the <Drawer> component has two parts: the <Fixed> part that is always visible, and the <Expandable> part that gets displayed when the user clicks on the Drawer. The Expandable part is where we will put our order details, and the Fixed part is normally used for a quick summary or preview of the Expandable content. So far, we have not added any order details except the <Link> that mimics an actual order management link.

You may also have noticed that we added an initialState="expandFirst" parameter to the Drawer. This parameter will cause the very first order in the list to be expanded by default, while the rest of the Drawers will be collapsed. There are also other values available, refer to https://help.gladly.com/developer-tutorials/docs/card-language-reference#drawer for details.

Let’s review what we have built so far:

  • We have a card with a dynamically calculated title.

  • The card body is made of Drawer components that display individual orders in a compact and easy to read way.

  • We iterate over the array using a List component.

Overview of nine orders with details including order number, date, and total amount.

For the rest of this step, we will be adding more to the Expandable part of the Drawer:

<?Template languageVersion="1.1" ?>
<Card title="{{ orders | length }} Orders">
  <List dataSource="orders" separateItems="true">
    <Drawer initialState="expandFirst">
	    <Fixed>
	      <StringValue dataSource="orderNumber" label="Order Number" />
	      <DateTimeValue dataSource="orderDate" format="MM/DD/YYYY" label="Order Date" />
	      <CurrencyValue dataSource="totalPrice" label="Total Amount" />
	    </Fixed>
	    <Expandable>
	      <Link linkText="Manage the order" linkUrl="https://www.example.com/my-oms/orders/{{- id }}" />
	      
	      <!-- Additional "order details" fields -->
	      <Formula label="Order Status" valueAlignment="right" valueFontWeight="medium">
			    {{- status | title }}
			  </Formula>
			  <Formula label="Shipping" valueAlignment="right" valueFontWeight="medium">
			    {{- shippingSpeed | title }}
			  </Formula>
			  <StringValue dataSource="shippingAddress" maxLines="3" displayStyle="stacked" label="Shipping Address" />
			  <Spacer size="large" />
	    </Expandable>
	  </Drawer>
  </List>
</Card>

At this point, you should see a card that has a list of orders and when you click on the order, it should expand and collapse to reveal or hide additional information about the order.

E. Add Product Images. Side-by-side Layouts with Columns.

Now that we have the basic order information down, let’s add “product images”. Typically, the product image is displayed side-by-side with the product information. In order to achieve that, we will use Column component that allows us to split the card width between multiple pieces of content and display them side-by-side.

<?Template languageVersion="1.1" ?>
<Card title="{{ orders | length }} Orders">
  <List dataSource="orders" separateItems="true">
    <Drawer initialState="expandFirst">
	    <Fixed>
	      <StringValue dataSource="orderNumber" label="Order Number" />
	      <DateTimeValue dataSource="orderDate" format="MM/DD/YYYY" label="Order Date" />
	      <CurrencyValue dataSource="totalPrice" label="Total Amount" />
	    </Fixed>
	    <Expandable>
	      <Link linkText="Manage the order" linkUrl="https://www.example.com/my-oms/orders/{{- id }}" />
	      <Formula label="Order Status" valueAlignment="right" valueFontWeight="medium">
			    {{- status | title }}
			  </Formula>
			  <Formula label="Shipping" valueAlignment="right" valueFontWeight="medium">
			    {{- shippingSpeed | title }}
			  </Formula>
			  <StringValue dataSource="shippingAddress" maxLines="3" displayStyle="stacked" label="Shipping Address" />
			  <Spacer size="large" />
			  
			  <!-- Nested List that displays the line items in the order -->
			  <List dataSource="lineItems">
				  <ColumnGroup columnSpacing="large">
				    <Column width="25%" verticalAlignment="center">
				      <Image dataSource="product.imageUrl" border="true" />
				    </Column>
				    <Column width="stretch">
				      <Text fontWeight="medium" maxLines="2">{{ product.name }}</Text>
				      <NumericValue dataSource="quantity" label="Quantity" decimalPlaces="0" />
				      <CurrencyValue dataSource="price" label="Item Price" />
				    </Column>
				  </ColumnGroup>
				  <Spacer size="medium" />
				</List>
	    </Expandable>
	  </Drawer>
  </List>
</Card>

By now, the Visualizer preview should display a fully functional “order list” card with collapsible order information ”drawers” that show order information with product images and some basic product information. Congratulations!

Step 4. Save the Card to the App Folder

Click on the blue “Export” button in the top section (”Template Code” panel), navigate to app/ui/templates/customer-orders folder and save the file as flexible.card. You will be asked to confirm whether you want to overwrite the existing file - click “Yes”.

Step 6. Test the Layout

This step is optional but highly recommended. Once you have a working card layout, it’s a good time to “stress test” it by modifying the data in the bottom panel of the Visualizer and verifying that the card renders as expected.

Try the following test scenarios:

  • Imitate a customer with no orders by renaming or deleting the orders array. Confirm that the card does not render (the preview panel shows “nothing to display”).

  • Imitate a customer that has an order without line items. Rename or delete the lineItems array in one of the orders and then expand that order in the the card. Confirm that you don’t see product image placeholders and product information but the rest of the fields is displayed as expected.

  • Confirm that the dates and currency fields are formatted correctly.

Step 7. Build and Submit the App

Important

Before you build the app, remember to increment the app version (version field in the app/manifest.json file).

Follow semantic versioning rules, otherwise the app may not install correctly:

  • Increment major version (first digit) when making a breaking change (removing a field or data element, or replacing a field or data element with a different one)

  • Increment minor version (second digit) when making a backward-compatible change (such as adding a field or data element)

  • Increment patch version when making a purely cosmetic change (such as changing field alignment or font size)

Once you incremented the version and saved the manifest file, build the app

appcfg build

The build step includes card template validation. You may see error messages indicating wrong attributes or attribute values etc. Fix the errors and try again. Refer to https://help.gladly.com/developer-tutorials/docs/card-language-reference when in doubt.

Once the app is built, ask your Gladly representative for help with getting it deployed.

In Conclusion

While the main focus of this tutorial is adding a Card to the sample Gladly app, you should be able to apply the same steps to your own custom app. Your app may have a different graphQL schema and card names but aside from that, all the steps should translate verbatim.

Often times, the Card development process requires multiple iterations before the card is ready for production. You may need to repeat steps 4-7 multiple times. Remember to update app version number between iterations, otherwise you may see the old card being rendered or the card may not render at all.

The App Platform documentation and tutorials (https://help.gladly.com/developer-tutorials/docs/app-platform) have a lot of useful information that will make your app development process easier.