Lab - Building Blocks
Lab - Building Blocks
Lab - Building Blocks
You’ve previously scaffolded a new Overview page in the Buyer Portal. In this exercise, we’ll start to flesh out the contents of this page with the components provided by Material UI and the Buyer Portal core.
This exercise continues where you left off previously. Make sure the dev server is started in your Buyer Portal project:
If you need a fresh start, you can follow the instructions below to set up a new project complete with previous exercise code.
Remember!
Script Manager in your store control panel must contain appropriate header/footer scripts to load the Buyer Portal from your local environment on the appropriate port.
Revisit the initial setup lab for full details on setting up your environment.
If it’s helpful to compare your own code as you go, you can clone or download the completed version of this labs as a reference.
By the end of this exercise, the Overview page will be fleshed out to include:
Card components.
Remember, all file paths referenced in these exercises are relative to apps/storefront/src in your Buyer Portal project.
Boilerplate for the Identity component already exists in pages/Overview/components/Identity.tsx. Already present in this component is logic that retrieves the user’s information from the session:
We’re not focused on the use of useAppSelector in this exercise, but this will make more sense when we discuss Redux.
pages/Overview/index.tsx.Identity and replace the current placeholder text with the component.pages/Overview/components/Identity.tsx and return JSX with a Box component.You should see your “TODO” text rendered on the page.
For our starter content, we’re wrapping the page in a Box component from Material UI. This is one of the most generic layout components. It is rendered as a div by default, but the HTML element can be changed with the component prop.
The sx prop demonstrates a core Material UI pattern for styling single instances of components:
paddingX and paddingY values demonstrate the support properties provide for responsive values. Our configuration provides certain padding values for extra small (xs) screens but overrides them with different values for large (lg) screens and above.sx is “theme-aware”, meaning that many properties accept strings referring to named values in the Material UI theme. The “primary.main” string refers to a value in the “palette” theme config. See the documentation for the available schema.In addition to the sx pattern, Box supports all MUI System props.
We’re using two additional Material UI components here:
Grid facilitates simple responsive grid layouts.
Grid (with the container prop) contains multiple Grid items (with the item prop).xs value of 12 means each item spans the full width of the container by default, while the lg value overrides this with 4 (meaning three items per row) for larger screens.Card is a simple content container. Note that it contains a CardHeader and CardContent.The Overview page should now render a basic display of the user’s identity details.

Try resizing your browser window to observe the responsive behavior.
In this step, we’ll restyle the cards used to present the identity information. While we could use the sx prop for each card, we want to avoid unnecessary duplication and centralize our styles for consistency.
pages/Overview/components/Identity.tsx and add a definition for IdentityCard as shown.Card with IdentityCard.The use of the styled utility follows a standard pattern used by popular libraries like Emotion and Styled Components. It decorates an existing component with additional styling, resulting in a new component that retains the features of the base component while applying the new styles.
Like the sx prop, the Material UI styled utility is theme-aware. Note that as demonstrated in our IdentityCard component, a callback wrapper takes a parameter including theme, allowing theme values to be accessed with object syntax.
Note that the Buyer Portal core also uses the styled utility from the @emotion/styled package when values from the Material UI theme aren’t necessary. Pay attention to where styled is imported from.
We’ll also apply two other enhancements: the use of icons and standard typography.
PersonIcon, BusinessIcon and SecurityIcon render SVG icons from the Material Icons library (via @mui/icons-material).Typography component is theme-aware, meaning the text will respect the typography schema of the Material UI theme, based on the specified props.Your “identity” section should now reflect the enhanced styles and icons you’ve applied.

Now we’ll turn our attention to the page’s “Recent Orders” content. As with the previous steps, we’re starting with a boilerplate RecentOrders component that is already defined.
pages/Overview/index.tsx to add the appropriate import and render the component.Note that we’re passing the setOpenPage function down to the new component, which will handle navigation links.
Button and HeadlessRoutes directly in this component, remove the imports.Removing these unused imports is important to avoid build errors later on!
pages/Overview/components/RecentOrders.tsx and update the component props signature to accept setOpenPage.The notable new components we’re using are provided by the Buyer Portal core:
B3Spin displays a spinner until content is ready to be displayed. For now, isSpinning is set to false, but later we’ll wire it to React state.B3Table provides sophisticated rendering for lists of records.
onClickRow callback, which accepts one of the rendered items. We’re using setOpenPage here, but we’re using a manual path based on item.orderId instead of a constant.listItems should be an array of the items to be rendered. orders is a React state value not yet being populated.columnItems should be an object defining the table’s columns. We haven’t yet defined orderColumns.Our code also includes a custom OverviewCard component, which is another simple example of styled.
We’ve put a simple React side effect in place, which will execute once when the component mounts. We’re not yet worrying about fetching real order data, instead setting the orders state value with an array of mock orders.
You can inspect mockOrders in the same file to see the format of the order records. This matches the schema the real data will eventually have:
The orderColumns array defines each column we want to display, with a key matching one of the properties in the record data. By default, each row will render the value of the specified field as simple text. For two of these columns, we’ve provided a render callback that formats the rendered value uniquely.
You should now have the “Recent Orders” table rendered on the page with mock data.

For our last step, we will wrap the “Recent Orders” table in an accordion component, collapsed by default. We will eventually be adding other data types to this page, so we’ll allow users to expand the sections they want to view.
pages/Overview/index.tsx and add the wrapping Accordion.Accordion is our new component here. Its children, AccordionSummary and AccordionDetails, are fairly self-explanatory.
Now that the orders table isn’t displayed initially, we can also defer fetching its data until the accordion is expanded. Once we’re loading data with real GraphQL requests, this will save us from unnecessary queries.
We’re using a change handler on Accordion to set the ordersOpen state value, and we’re passing this to a new startLoad prop on RecentOrders to let that component know the status.
pages/Overview/components/RecentOrders.tsx and add the new prop.useEffect to depend on this state value, and to avoid loading data if startLoad is false.Navigate to your Overview page and verify that the “Recent Orders” table is rendered in a working accordion.

styled version of Accordion and apply your own styles. Explore with responsive values and the use of theme values.