Override UI elements of product modules in the InStore colleague app to match brand, workflow, and localization requirements.
modular_store share a default UI theme that is configured in the InStore Center on the Theme tab of the environment.
You can override the theme and other presentation aspects for the following product modules that run inside the InStore colleague app:InStore_PaymentInStore_RefundInStore_DeviceManagementInStore_CashManagement
You must call the relevant API before these modules are called. You can override the following:
Override theme
- Import the
useStorehook fromInStore_State. This was previously called/store. - Access
configurationfromuseStorein your top-level layout (for example,InStore_Shell/src/views/layout.tsx). - Call
configuration.setOverrideCoreTheme(true)before any product module mounts. - Provide custom
themeOptionsthrough the theme provider (for example,InStore_Shell/src/providers/theme.tsx).
import { useStore } from "InStore_State/store";
const Layout = () => {
const { configuration } = useStore();
// ...
};
useEffect(() => {
configuration.setOverrideCoreTheme(true);
}, []);
import React, { PropsWithChildren } from 'react';
import { ThemeProvider as TP } from 'InStore_State/theme';
import customTheme from '../theme/customTheme';
const ThemeProvider = ({ children }: PropsWithChildren) => (
<TP rootElementId="app" themeOptions={customTheme}>
{children}
</TP>
);
- MUI base v. 5.0.0-beta.34
- MUI icons-material v. 5.8.0
- MUI material v. 5.8.1
- MUI system v. 5.15.0
The following examples show how to configure the elements' size and color, but not the text.
Payment types structure
<Grid className="instore-payment-entry-container">
<Grid item xs={12} md={6} className="instore-payment-amount-section">
<Grid item xs={12}>
<Typography className="instore-payment-amount-header" />
</Grid>
<Grid item xs={12}>
<KeypadEntry className="instore-payment-amount-keypad" />
</Grid>
</Grid>
<Grid item xs={12} md={6} className="instore-payment-types-section">
<Grid item xs={12}>
<Typography className="instore-payment-types-header" />
</Grid>
<Grid item xs={12}>
<Grid>
<TenderButton className="instore-payment-types-button-${type}" />
{/* {type} is cash, credit, paybylink, etc. */}
</Grid>
</Grid>
</Grid>
</Grid>
Cash structure
<Grid className="instore-payment-entry-container">
<Grid item xs={12} md={6} className="instore-payment-amount-section">
<Grid item xs={12}>
<Typography className="instore-payment-amount-header" />
</Grid>
<Grid item xs={12}>
<KeypadEntry className="instore-payment-amount-keypad" />
</Grid>
</Grid>
<Grid item xs={12} md={6} className="instore-cash-section">
<Grid item xs={12}>
<Typography className="instore-cash-header" />
</Grid>
<Grid item xs={12}>
<Grid>
<Button className="instore-cash-button-${value}" /> {/* List of buttons */}
</Grid>
</Grid>
</Grid>
</Grid>
Cash drawer structure
<Grid>
<Grid item xs={12} md={6}>
<Grid item xs={12}>
<Typography className="instore-cash-promp-drawer" />
</Grid>
</Grid>
</Grid>
Change due structure
<Grid className="instore-change-due-container">
<Grid item xs={12}>
<Typography className="instore-cash-change-row-0" />
<Typography className="instore-cash-change-row-1" />
<Typography className="instore-cash-change-row-2" />
<Typography className="instore-cash-change-row-3" />
</Grid>
</Grid>
Credit processing structure
<Grid className="instore-payment-entry-container">
<Grid item xs={12}>
<Typography className="instore-credit-process-label" />
<Typography className="instore-credit-process-amount" />
</Grid>
</Grid>
Gift card entry structure
<Grid>
<Grid item xs={12} md={6}>
<Grid className="instore-gift-cart-header">
<Grid item xs={12}>
<Button className="instore-gift-cart-camera-button" />
<Typography className="instore-gift-cart-label" />
</Grid>
<Grid item xs={12}>
<KeypadEntry className="instore-gift-cart-keypad" />
</Grid>
</Grid>
</Grid>
</Grid>
HTML structures for Pay On Account
Use this wrapper to introduce the POA component:
<Paper elevation={0} className='instore-POA-paper-background'>
<Container className='instore-POA-confirmation-container'>
HTML structure for POA Company Name label and field
<>
<Grid item xs={12} sm={6}>
<Typography
className='instore-POA-company-name-label'
>
{t('POA.companyName')}
</Typography>
</Grid>
<Grid
item
xs={12}
sm={6}
className='instore-POA-company-name-field'
>
<Typography
variant='subtitle1'
id='customer-company-name'
>
{customer.company}
</Typography>
</Grid>
</>
HTML structure for POA Customer Number label and field
<>
<Grid item xs={12} sm={6}>
<Typography
variant='h6'
className='instore-customer-number-label'
>
{t('POA.customerNumber')}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<Typography
variant='subtitle1'
className='instore-customer-number-field'
>
{customer.customer_number}
</Typography>
</Grid>
</>
HTML structure for POA Customer Email label and field
<>
<Grid item xs={12} sm={6}>
<Typography variant='h6' className='instore-customer-email-label'
>
{t('POA.customerEmail')}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<Typography variant='subtitle1' className='instore-customer-email-field'
>
{customer.email}
</Typography>
</Grid>
</>
HTML structure for POA Account IDs label and drop-down
<>
<Grid item xs={12} sm={6}>
<Typography variant='h6' className='instore-POA-account-id-label'
>
{t('POA.accountID')}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<Typography variant='subtitle1' className='instore-customer-account-number'
>
{accountNumber}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<FormControl className='instore-POA-account-dropdown'
>
<Select
>
<MenuItem
>
{account}
</MenuItem>
</Select>
</FormControl>
</Grid>
</>
HTML structure for POA page divider
<Grid item xs={12} sm={6}>
<Divider variant='middle' className='instore-POA-divider' />
</Grid>
HTML structure for POA Payment Amount label and field
<>
<Grid item xs={12} sm={6}>
<Typography variant='h6' className='instore-POA-payment-amount-label'
>
{t('POA.paymentAmount')}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<Typography variant='subtitle1' className='instore-poa-payment-amount'>
{currentTenderAmount.toFormat(currencyInstance.currencyFormat)}
</Typography>
</Grid>
</>
HTML structure for POA Purchase Order label and field
<>
<Grid item xs={12} sm={6}>
<Typography variant='h6' className='instore-purchase-order-label'
>
{t('POA.purchaseOrderLabel')}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
value={purchaseOrder}
className='instore-POA-purchase-order-input'
/>
</Grid>
</>
Pay On Account HTML rendered on the UI
Override strings
InStore retrieves UI strings from predefined language bundles. Override only the keys you want to change. Other keys fall back to defaults.
Follow these steps to override strings:
- In the InStore GitHub repository, in the client/public folder, locate and copy the
localeslanguage bundles for product modules. You can use the bundles as a reference when specifying strings to override. - Specify overrides as shown in this example. If you have multiple languages, add a section for each language as shown.
- Define a payload
{ ... }for each section based on the main payload in the example. The payload only needs to include the strings to be overridden, you don't need to include strings in the payload if you don’t want to override them. - Get an administrator access token. The credentials used here are the same as the ones you use with all InStore APIs.
- Send a PUT request to
/:tenantId/translations, and then send the payload. You must include{{login_token}}in the header of your request. For example, in the PUT call, insert the{{login_token}}as the value for the token key that pairs with the header. - The returned response is the updated bundle in JSON format.
Route
| Path | Type | Description |
|---|---|---|
| /:tenantId/translations | PUT | Override default translations for supported locales. |
Request
| Field | Type | Description |
|---|---|---|
translations | object | Container for per-locale override objects. |
Example
Cash Drawer with Till in the en-GB bundle.{
"translations": {
"en-CA": { },
"fr-CA": { },
"en-GB": {
"App": {
"system_error": "Undefined system error",
"initialization_error": "Unable to initialize session!",
"invalid_request": "Invalid process requested"
},
"PaymentEntry": {
"promptMessage": "Enter Remaining Balance, then select Payment Type.",
"promptMessageAdditionalPayment": "Enter additional remaining balance, then select Payment Type.",
"promptMessageCancel": "Cancelling payment...",
"userMessageCash": "Partial cash tender added",
"buttons": {
"cash": "CASH",
"card": "CREDIT / DEBIT",
"gift": "GIFT CARD",
"wallet": "DIGITAL WALLET"
}
}
}
}
}
Override tender labels
- Log in to the InStore API server with administrator credentials and obtain a token.
- Add the token to the request header.
- Send
PUT /:tenantId/translationswith a payload containing updated button labels under the relevant module key (for example,Checkout). - A successful update returns status code
202and the updated labels.
Route
| Path | Type | Description |
|---|---|---|
| /:tenantId/translations | PUT | Override default translations for supported locales. |
Request
| Field | Type | Description |
|---|---|---|
translations | object | Container for per-locale translation overrides. |
Example
{
"translations": {
"en-US": {
"Checkout": {
"buttons": {
"cash": "CASH",
"typeCards": "CREDIT / DEBIT",
"giftCard": "GIFT CARD",
"digitalWallet": "DIGITAL WALLET",
"poa": "PAY-ON-ACCOUNT",
"payByLink": "PAY BY LINK"
}
}
}
}
}
Override tender order and icons
- Log in to the InStore API server with administrator credentials and obtain a token.
- Add the token to the request header.
- Send
PUT /:tenantId/payment-buttonswith a payload describing order and icons. - A successful update returns status code
202and the updated configuration.
Route
| Path | Type | Description |
|---|---|---|
| /:tenantId/payment-buttons | PUT | Update tender display configuration and return the tenant document. |
Request fields
| Field | Type | Description | Example |
|---|---|---|---|
paymentButtons | array | Array of button configuration objects. | See example |
paymentButtons[].key | string | Identifier of the payment button to update. | creditCard |
paymentButtons[].icon | string | Material UI icon component name. | CreditCard |
paymentButtons[].order | integer | Display order (1–10). | 1 |
Example
{
"paymentButtons": [
{ "key": "creditCard", "icon": "CreditCard", "order": 1 },
{ "key": "cash", "icon": "Money1", "order": 2 }
]
}
Override print options
modular_store. For example, you can omit a receipt option on the cart if certain conditions on the customer record are not met.- Import
useStorefromInStore_State/store. - Access
configurationfromuseStore. - Call
configuration.setOverridePrintOptions([...])to set allowed print options for Checkout or Refund in theInStore_Coremodule.
import { useStore } from 'InStore_State/store';
-
Call
setOverridePrintOptionsin any part of the component to override print options on Checkout or Refund in the InStore core application.configuration.setOverridePrintOptions(['Paper']); //Options: Paper, Email, Text, and None
setOverridePrintOptions is either an array of strings or null. If this override consists of null, then InStore uses the values that were set by the Receipt_Print_Options administration parameter in the InStore Center.An array will replace the values that were configured by the administration parameter.
Add payment details to the Totals box
MoneyBoxInjection. You can call the InStore moneyBoxInjection property at render time.-
Follow the steps for overriding the theme and add the following to the
configuration:Injector.inject({ tenantId: "SF-29299292", moneyBoxInjection: { items: [ { label: "Promo: Buy 1 Get 1 Free!", alignment: "center" }, { type: "divider" }, { label: "Offer ends 31/12", alignment: "right" }, { type: "divider" }, { label: "Order Total", value: "£180.50", alignment: "left" }, ] } }); -
For each item in the
itemsarray, assign one of the following options:
{
"label": "Promo: Buy 1 Get 1 Free!",
"value": "-£1.00",
"alignment": "center"
}
-
Implement a divider (a horizontal line) by inserting the following text:
{ "type": "divider" }
Use theming described elsewhere in this topic to style line thickness, color, and spacing.
- Use theming overrides to style the
MoneyBoxInjectioncomponent. For example:MoneyBoxInjection: { styleOverrides: { root: { "&.instore-moneybox-injection": { textAlign: themeOptions.defaultTextAlign || "left", margin: themeOptions.moneyBoxMargin || "4px 0", fontSize: themeOptions.moneyBoxFontSize || "14px", color: themeOptions.moneyBoxTextColor || "#000", "& .instore-moneybox-item-left": { textAlign: "left" }, "& .instore-moneybox-item-center": { textAlign: "center" }, "& .instore-moneybox-item-right": { textAlign: "right" }, "& .instore-moneybox-separator": { borderTop: `1px solid ${themeOptions.moneyBoxSeparatorColor || "rgba(0,0,0,0.3)"}`, margin: themeOptions.moneyBoxSeparatorSpacing || "4px 0", }, } } } }