Build a field sales app on Retool Mobile

Build a mobile app for a sales team to manage opportunities while in the field.

πŸŽ‰

beta

Retool Mobile is currently in private beta. Sign up to join the waitlist β†’

Retool Mobile enables you to build native mobile apps that interact with your data and deploy them to your workforce.

Use case

A common use case for Retool Mobile is sales account management, enabling sales representatives in the field to manage accounts and opportunities wherever they are. This tutorial explains how to build a field sales mobile app for users to: browse, filter, and edit opportunities.

Field sales mobile appField sales mobile app

Prerequisites

This tutorial demonstrates a real-world use case of Retool Mobile and uses sample data from a PostgreSQL database. Retool cloud organizations include a basic PostgreSQL database named managed_db that you can interact with for testing purposes.

Before you begin, download the provided sample data in CSV format. Each CSV file corresponds to a database table.

TableDescriptionDownload CSV
field_sales_opportunitiesSales opportunities.Download
field_sales_contactsContacts for each sales opportunity.Download

Use the Data Editor to create the required tables, using the provided names, and then upload each CSV. Once complete, you can use the same queries and resource used by this tutorial.

Upload CSV using the Data EditorUpload CSV using the Data Editor

Much of what this tutorial covers can apply to other resources and data types. You can also use your own SQL database that's connected to Retool.

Get started

πŸ‘

You can download a JSON export of this mobile app and import it into Retool.

Once you're ready to begin, sign into Retool and click Create > Mobile app. Set the name to Field Sales.

View and filter opportunities

The first part of the tutorial explains how to look up, filter, and display sales opportunities.

1. Configure the Opportunities screen

Retool Mobile organizes mobile components into separate screens and creates pathways for your users to follow. Users navigate between screens using the tab bar or by interactions, such as pressing a button or selecting an item from a list.

New Retool Mobile apps initially contain two screens. Select Screen 1 in the Screens section of the mobile panel (left) to display its settings in the Inspector (right panel).

  • The screen's name (screen1) is used internally when you configure settings or write queries. Click on screen1 in the Inspector to edit this and set it to Opportunities.
  • The screen’s title is displayed in at the top of your app and in the tab bar at the bottom, if visible. In the Inspector, set the value for Title to Opportunities.

Configure screenConfigure screen

3. Retrieve opportunities data

Sales data for this app comes from a PostgreSQL database. You write queries to interact with connected data sources using SQL.

This mobile app uses three queries to retrieve data about opportunities. Click + New in the bottom panel to create a query, select the managed_db resource, then write the following SQL statement:

select * from field_sales_opportunities order by id;

Save the query as getOpportunities.

4. Assemble components for the Opportunities screen

You add mobile components to each screen of a mobile app to build the interface by clicking + in the Components section of the left panel. You then configure component properties using the Inspector.

Add the following mobile components to the Opportunities screen, then configure their respective settings:

  • Text Input
    • Name: opportunitiesSearchInput
    • Placeholder: Search opportunities...
  • List Collection
    • Name: opportunitiesCollection
    • Data source: getOpportunities

The Text Input mobile component is used to search for opportunities. Update the getOpportunities query to reference this new input field's value:

SELECT * FROM field_sales_opportunities
WHERE company ILIKE {{"%" + textInput1.value + "%"}}
ORDER BY id

Final version of the queryFinal version of the query

The List Collection component automatically configures list options by dynamically mapping values from the query data. Use the Mapped options settings to configure what values to use by referencing item. For instance, setting Title to {{ item.name }} displays each item name as the list option's title.

SettingsValue
Title{{ item.type }}
BodyARR: {{('$' + numbro(item.amount).format({thousandSeparated: true})) }}
Caption{{item.sales}}
Source{{ item.image_url }}

The Body field displays a dollar amount that's formatted using Numbro.js, a JavaScript library that's automatically available in Retool apps.

Configure mapped optionsConfigure mapped options

View selected opportunity details

This part of the tutorial explains how to display details of a selected opportunity. This involves getting details of the selected item and populating components in a screen with the details.

1. Configure the Opportunity Details screen

Add an opportunityDetails screen with a Title of Opportunity Details.

Configure screenConfigure screen

2. Assemble components for the Opportunity Details screen

When an opportunity is selected in the list, its data is available at the List Collection component's selectedItem. The components in this details screen use this information to display relevant details.

Add a List Collection component to the Opportunity Details screen with the name opportunityDetailsCollection, then set the Data source to Use JavaScript. The following script transforms the selected opportunity's data into an array for use with mapped options:

{
  {
    Object.entries(opportunityDetailsCollection.selectedItem)
      .map((a) => {
        return Object.assign({
          title: a[0],
          body: a[1],
        });
      })
      .filter((a) => a.title != "id");
  }
}

As before, use the Mapped options settings to configure what values to use by referencing item.

SettingsValue
Title{{ _.startCase(item.title) }}
Body{{item.title == 'amount' ? ('$' + numbro(item.body).format({thousandSeparated: true})) : item.body}}

Configure mapped options with custom JavaScript dataConfigure mapped options with custom JavaScript data

3. Display selected opportunity details

You configure event handlers to perform actions in response to certain events. In this case, selecting an opportunity in the Opportunities screen will open the Opportunity Details screen.

Return to the Opportunities screen, select the opportunitiesCollection component, and add an event handler that navigates to the opportunityDetails screen on selection:

  • Event: Press
  • Action: Navigation
  • Method: Navigate to screen
  • Screen: opportunityDetails

Configure event handlingConfigure event handling

4. Include associated contact data

Opportunity details should include any associated contact information. Add a new query to retrieve contact data for the selected opportunity:

select * from field_sales_contacts
where opp_id = {{ opportunitiesCollection.selectedItem.id }}
order by id;

To display relevant contacts, add a Card Collection component to the Opportunity Details screen, set its name to opportunityDetailsContactsCollection, then set the Data source to getOpportunityContacts.

Since there can be multiple contacts for an opportunity, you can configure Card Collection to scroll horizontally with smaller thumbnails and save space. In the Data layout section of the Inspector, set Scroll to Horizontal and Size to Half.

Configure mapped options and card layoutConfigure mapped options and card layout

Update an existing opportunity

The final part of the tutorial explains how to enable users to edit a selected opportunity and save changes. This uses the same principles previously covered.

1. Configure the Edit Opportunity screen

Add an editOpportunity screen with a Title of Edit Opportunity.

Configure screenConfigure screen

2. Assemble components for the Edit Opportunity screen

The Edit Opportunity screen contains a set of input components that initially display values from the selected opportunity using selectedItem. Add the following mobile components to this screen, then configure their respective settings:

  • Text Input (Company name)
    • Name: opportunityEditCompany
    • Default value: {{ opportunitiesCollection.selectedItem.company }}
  • Number Input (ARR amount)
    • Name: opportunityEditAmount
    • Default value: {{ opportunitiesCollection.selectedItem.amount }}
  • Date Picker (Close date)
    • Name: opportunityEditDate
    • Default value: {{ opportunitiesCollection.selectedItem.close_date }}
  • Select (Opportunity stage)
    • Name: opportunityEditStage
    • Default value: {{ opportunitiesCollection.selectedItem.stage }}
    • Values: ['Discovery', 'Demo', 'POC', 'Validating Business Case', 'Signature']
    • Labels: {{ self.values }}
    • Label: Stage
  • Select (Probability of closing)
    • Name: opportunityEditProbability
    • Default value: {{ opportunitiesCollection.selectedItem.probability }}
    • Values: [0,10,20,30,40,50,60,70,80,90,100]
    • Labels: ['0%','10%','20%','30%','40%','50%','60%','70%','80%','90%','100%']
  • Button
  • Name: opportunityEditSave
    • Text: Save

The components for this screenThe components for this screen

3. Update the selected opportunity

The final step is to write a query that updates the opportunity with the information entered into this screen, saving those changes back to the database.

Click + New in the bottom panel to create a new query named updateOpportunity, then select GUI mode. This mode uses an interface that makes it easier and safer to write queries that manipulate data.

Queries that make changes to data use Filter by fields to determine which record to update. You can specify a field that contains a unique value, such as an ID, or specify multiple fields on which to filter. This query uses opportunitiesCollection.selectedItem.id to reference the selected opportunity's ID.

  1. Set Table to field_sales_opportunities.
  2. Change the action type to Update an existing record.
  3. Set Filter by to id = {{ opportunitiesCollection.selectedItem.id }}

Next, update the Changeset to configure the query with each field name and the input value to use.

KeyValue
company{{ opportunityEditCompany.value }}
amount{{ opportunityEditAmount.value }}
close_date{{ opportunityEditDate.value }}
stage{{ opportunityEditStage.value }}
probability{{ opportunityEditProbability.value }}

Query to update existing opportunity dataQuery to update existing opportunity data

Finally, add two Success event handlers to the query that:

  • Trigger the getOpportunities query to refresh opportunity data so it reflects the changes.
  • Navigate back to the Opportunity Details screen

Click Save to save this query.

4. Add a button to edit opportunity details

The final step is to include an action button when viewing an opportunity so that users can make changes.

Select the opportunityDetailsScreen screen, then add a Right action button from the Actions section of the Inspector:

  • Action: Navigation
  • Method: Navigate to screen
  • Screen: editOpportunityScreen

Configure action buttonConfigure action button

Wrap up

You have now built a field sales app that enables users in the field to read, filter, and update sales opportunities. Each opportunity also includes a list of related contacts.

By applying the lessons learned here and following the same patterns, you could extend the mobile app's functionality with features like managing accounts or performing common actions like notifying contacts.


Did this page help you?