Click here to Skip to main content
15,879,535 members
Articles / UI
Article

Build a Teams Power App for Manufacturing 2: Create the Customer UI

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
10 Jun 2021CPOL9 min read 3.4K   6  
In this article, we'll create our app, focusing on the customer user interface.
Here we create a customer UI for our app, and enable customer employees to enter orders and customer managers to approve and send orders to the manufacturer's Teams channel.

This article is a sponsored article. Articles such as these are intended to provide you with information on products and services that we consider useful and of value to developers

This is the second article in a three-part series on Power Apps development in Teams.

Introduction

This article builds the customer user interface (UI) to our HVAC manufacturer's order app. We'll create a shopping cart-style interface where customers can choose products and send their orders to a manager for approval.

Before we get started, let's take a quick tour of the tools we need and familiarize ourselves with the development environment.

Image 1

Make your way through most of the Power Apps on the left bar. You'll be able to see the screens you created in the Tree view. You can add items to your screen capture on the Insert tab. Interact with the data for your app on the Data tab.

Just as in normal development, Power Apps has coding standards. To learn more about these, check out the white paper PowerApps Canvas App Coding Standards and Guideline. This paper contains a wealth of information, from naming conventions to performance enhancement advice.

Create the Home Screen

Let's start by adding a blank screen to create a Home screen. It's handy to name screens as you go.

Working with Users

Customizing the app's home screen and security access, depending on the person logged in, is straightforward.

In this example, we'll set a global variable, varUser, to prevent multiple system calls to Active Directory. Bear in mind that the end users may use our app on mobile devices. It's undoubtedly worth maximizing performance where possible. The variable User returns the user details of the user currently logged in, providing an authentication layer to our app.

To set this global variable, in the Tree view, select App, and set the OnStart event to Set(varUser,User()). Then, select the ellipses to the right of App and click Run OnStart.

Image 2

Our global variable is now ready for use.

We added a rectangle at the top of the home screen, with the label's Text property set to: "Welcome " & varUser. FullName. We added a close icon at the top with the OnSelect property set to Exit(true). This closes the app and logs the user out.

Image 3

Next, we add a button and an image and group the button and image. Change the button's Text property to Create New Order and its OnSelect property to Navigate('New Order Screen'). Add a new screen and name it "New Order Screen." We encourage investigating all the properties available to you here.

We need two new screens to go with the two new buttons, View Orders and Approve Orders. Use the copy and paste function to copy your first button, then adapt the properties as follows:

Text "View Orders"
OnSelect Navigate('View Orders' )
Visible User().Email in HVAC_Manufacturers.Email

 

Text "Approve Orders"
OnSelect Navigate('Approve Orders Screen')
Visible User().Email in HVAC_Managers.Email

The code we've added to the Visible property ensures that employees cannot approve their own orders, and "Ready for Processing'' orders are only visible to the manufacturer. There are many ways to achieve this. Depending on the company's setup, you can also make the button's visibility rely on the user's group membership, using the Office365Groups connector. We're keeping this simple for now but have fun and experiment.

Image 4

At this point, you'll find it helpful to add your email address to the data sources HVAC_Managers and HVAC_Manufacturers. The buttons will then become visible for development purposes.

This is how our Home screen looks at this point:

Image 5

With a Tree view like this:

Image 6

How To Preview Your App

You can preview your app at any time by selecting the Preview button on the top right or, to check something quick, hold down the Alt key and interact with the screen. This is a convenient feature for quickly confirming something works.

Create the Customer Order UI

Let's now move on to creating a screen for our customers to place an order for approval.

We reuse the rectangular bar from the Home screen on the New Order Screen. Change the label's text to "Create New Order for " & varUser.FullName and the icon to a home shape with OnSelect set to Navigate('Home Screen').

Now we must add a gallery and connect it to the Products table.

Image 7

Set Layout as Title, subtitle, and body, and then edit Fields to display Product Name, Description, and Price. Remember, we added some products to the database in the first article because it's helpful to have data.

Let's format as we create the Customer Order UI. It would be nice to display our price in the correct format. We can do this by changing the Price label Text property to Text(ThisItem.Price, "[$-en-US]$#,##0.00"). Now our prices look like prices!

Image 8

We can drag the following items to the gallery. Make sure you drop them onto the top row so they repeat for all rows.

Label Text "Quantity"
Slider Value 0
  Min 0
  Max 10
Reset Icon OnSelect Reset(sliQuantity)
Label Text "Subtotal =" & Text(ThisItem.Price * sliQuantity.Value, "[$-en-US]$#,##0.00")

Use a Collection for Order Items

We'll also add a new button, which appears when we change the slider quantity to greater than 0, giving users the ability to add the product to their cart. Here we make use of a collection, a kind of temporary table.

Image 9

The button needs the following properties:

OnSelect:
```
Collect(colOrderDetails, {CustomerName: varUser.FullName , ProductName:     ThisItem.ProductName,Quantity:sliQuantity.Value, Subtotal: (ThisItem.Price *   sliQuantity.Value)});
Reset(sliQuantity)
```
Text: "Add to Cart"
Visible: `sliQuantity.Value >0`

These properties create a collection, colOrderDetails, which holds data until updating the actual data source (HVAC_Ordered_Items). The CustomerName field is filled by varUser. This could be a text input box if you prefer.

Now is an excellent time to ensure we start our screen with a fresh collection. Select New Order Screen and add Clear(colOrderDetails) to the OnVisible property.

Next, let's make the Cart details section of our screen.

Image 10

This includes:

  • A rectangle to hold the purple background
  • A label with the text "Order Details"
  • A rectangle to hold a background for the Order Details Heading
  • A gallery
Name galOrderDetails
Data source colOrderDetails
Layout Title and subtitle
Fields ProductName and Quantity

Image 11

  • A trash icon with its OnSelect property set to Remove(colOrderDetails, ThisItem)
  • A label with text set to ("Total: " & Text(Sum(colOrderDetails, Subtotal), "[$-en-US]$#,##0.00"))
  • A reset icon with the tooltip "Reset Order" and its OnSelect property set to Clear(colOrderDetails)
  • A button
Text "Send Order for Approval"
OnSelect
UpdateContext(
	{
    	ReturnedRecord: Patch(
        	HVAC_Orders,
        	Defaults(HVAC_Orders),
        	{
            	CustomerName: varUser.FullName,
            	Total: Sum(
                	colOrderDetails,
                	Subtotal
            	),
            	OrderStatus: 'OrderStatus (HVAC_Orders)'.'Awaiting Approval'
        	}
    	)
	}
);
Refresh(HVAC_Orders);
ForAll(
	colOrderDetails,
	Patch(
    	HVAC_Ordered_Items,
    	Defaults(HVAC_Ordered_Items),
    	{
    	    CustomerName: colOrderDetails[@CustomerName],
        	ProductName: colOrderDetails[@ProductName],
        	OrderID: RetunedRecord.OrderID,
        	Subtotal: colOrderDetails[@Subtotal],
        	Quantity: colOrderDetails[@Quantity]
    	}
	)
);
Clear(colOrderDetails);
Notify("Order sent for approval. For reference, your order number is " & ReturnedRecord.OrderID,NotificationType.Information, 6000);
Navigate('Home Screen')

This button is our most complex code so far. When a user presses the button, the app creates a new order (with order status set to Awaiting Approval) in the HVAC_Orders table, and we return the record just created.

Then, for every record in our shopping cart collection colOrderDetails, we make a new record in our HVAC_Ordered_Items table, with the OrderID set to the OrderID of the returned record. A six-second notification appears to users with their order number and a message that they will return to the home screen.

For additional validation, we group everything in the large order details rectangle and set the group's visible section to !IsEmpty(colOrderDetails).

We have a pretty advanced app with an Order screen that's only taken a fraction of the time of normal development, and we haven't even left Teams!

Try out your creation, adding orders, and then verifying that all are saved correctly in the data tables.

If you want to inspect the temporary collection table contents as you add items to your cart, select the ellipses beside the settings and select Collections.

Image 12

Let's press on with the next stage of our approval system.

Create the Manager Approval UI

We must create our Approve Orders screen for management to either approve or reject employee's orders. Spend a little time applying a similar theme to the rest of the app, with the rectangular bar at the top with the Home button and title.

Image 13

Awaiting Approval Panel

Image 14

To create the Awaiting Approval panel, on the left side of our screen, we must add:

  • A rectangle to act as a background to our gallery, with a border
  • A label with the Text property set to "Awaiting Approval"
  • A gallery
Name galApproveOrder
Data source HVAC_Orders
Layout Title
Fields ThisItem.OrderID
Items Filter(HVAC_Orders, OrderStatus = 'OrderStatus (HVAC_Orders)'.'Awaiting Approval'

The Awaiting Approval panel should display only orders that are not yet approved.

Image 15

Set TemplateFill to If(ThisItem.IsSelected, RGBA(224,224,237,1)). This makes it easier for the manager to see which item in the gallery is selected.

All other items on the screen should have their Visible property set to If(!IsBlank(galApproveOrder), true) to prevent items from being visible if nothing needs approval.

Order Details Panel

Next, we create the Order Details panel. Managers will select an Order ID to approve. Then the order details appear in the middle of the screen with a button to approve or reject. The app then adds approved orders to a collection, colBatchOrders, and submits the collection for processing.

Image 16

For the middle section, we need:

  • A rectangle to act as a background for the order details
  • A rectangle with a label inside it with the Text property set to "Order Details for " & galApproveOrder.Selected.CustomerName
  • A gallery
Name galOrderDetailsApproval
Data source HVAC_Ordered_Items
Layout Title and subtitle
Fields ProductName and Quantity
Items Filter(HVAC_Ordered_Items, OrderID=galApproveOrder.Selected.OrderID
  • A label with the Text properties set to "Total: " & Text(galApproveOrder.Selected.Total, "[$-en- US]$#,##0.00")
  • An Approve button
Text "Approve"
OnSelect
Collect(colBatchOrders, {OrderID: galApproveOrder.Selected.OrderID});
Patch(HVAC_Orders, galApproveOrder.Selected, {OrderStatus:'OrderStatus (HVAC_Orders)'.Approved});
  • A Reject button
Text "Reject"
OnSelect Patch(HVAC_Orders, galApproveOrder.Selected, {OrderStatus:'OrderStatus (HVAC_Orders)'.Rejected});

Approved Orders Panel

Now we must make the final section of our screen, which displays the approved orders, ready to submit to the manufacturer as Ready for Processing.

Image 17

Create:

  • A rectangle to act as a background for the approved orders
  • A rectangle with a label inside it with the Text property set to Approved
  • A gallery
Name galApprovedOrders
Data source colBatchOrders
Layout Title
Fields OrderID
Items
Filter(HVAC_Ordered_Items, OrderID=galApproveOrder.Selected.OrderID
  • A button to send orders for processing
Text "Send for Processing"
Visible !IsEmpty(colBatchOrders)
OnSelect
ForAll(
	colBatchOrders,
	Patch(
    	HVAC_Orders,
    	LookUp(
        	HVAC_Orders,
        	OrderID = colBatchOrders[@OrderID]
    	),
    	{OrderStatus: 'OrderStatus (HVAC_Orders)'.'Ready for Processing'}
	)
);
Clear(colBatchOrders);
MicrosoftTeams.PostMessageToChannelV3(
	"a15e2e15-8592-4d89-ac3f-419baefe3943",
	"19:e45661661372454886f656b60500a97f@thread.tacv2",
	{
    	content: "<p>New order ready for processing</p>",
    	contentType: "html"
	},
	{subject: "ALERT: NEW ORDER"}
);
Navigate(‘Home Screen’);

Again, there is quite a bit going on here. When the manager selects the Send for Processing button, the status of all the collected orders updates to Ready for Processing. The app sends a message to the manufacturer's Teams channel, alerting them a new order is ready. The app then redirects the manager to the Home screen.

Post to a Teams Channel

Before our app can post a message to a Teams channel, it needs some information, namely, the group ID and Channel ID. This information is difficult to find, but the results are certainly worth the effort, and the skill is worth sharing here.

We need some temporary galleries to find these IDs.

Add two to a screen, somewhere in your app. Set the Items property of the first gallery to MicrosoftTeams.GetAllTeams().value

Set the second to MicrosoftTeams.GetChannelsForGroup(YourGallery.Selected.id).value

You can then inspect these galleries and retrieve the required ChannelID and GroupID to enable you to post messages to the Teams channel of your choosing. Don't forget to delete the temporary galleries.

Image 18

Summary

We have achieved so much in this tutorial. We created a customer UI for our app, enabling customer employees to enter orders and customer managers to approve and send orders to the manufacturer's Teams channel.

In the final article of this series, we'll create a viewing screen for manufacturer employees to view orders and send them on to the processing department. We're sure you're already itching to fine-tune your app!

This article is part of the series 'Build a Teams Power App for Manufacturing View All

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
Ben is the Principal Developer at a gov.uk and .NET Foundation foundation member. He previously worked for over 9 years as a school teacher, teaching programming and Computer Science. He enjoys making complex topics accessible and practical for busy developers.


Comments and Discussions

 
-- There are no messages in this forum --
Build a Teams Power App for Manufacturing