Fluent Commerce Logo
Sign In

Fluent Store Dashboard: new dashboard tile based on fulfilment expiry time

How-to Guide
Extend

Author:

Randy Chan

Changed on:

16 Apr 2025

Key Points

  • A guide to extend Fluent STORE UI capabilities to allow the store users to have a better visibility on the fulfilments by expiry time.
  • The use case where the store staff would like to see number of fulfilments for the next 2 hours so that they can plan their pick and pack process accordingly. 
  • One of the solutions is by using OOTB component and manifest to display the fulfilments number based on the expiry time.  Hence, there are no custom rules nor custom component is required for this solution.
  • Here are the steps to archive the outcome:
    • Create a new screen in fluent Store
    • Create dashboard tiles

Steps

Step arrow right iconCreate a new screen in Fluent Store

Create a new setting for the new empty screen:

Name: fc...store.fragment.store_dashboard

Context:

Context ID: 0

Value Type: JSON

JSON Value:

1{
2    "manifestVersion": "2.0",
3    "routes": [
4        {
5            "type": "page",
6            "path": "store_dashboard",
7            "component": "fc.page",
8            "nav": {
9                "label": "Store Dashboard",
10                "icon": "store"
11            },
12            "props": {
13                "title": "Store Dashboard"
14            },
15            "descendants": []
16        }
17    ]
18}

Then add the new setting to the fc...store

1{
2    "type": "reference",
3    "settingName": "fc.mystique.manifest.store.fragment.store_dashboard"
4},
No alt provided

Refresh the store screen and you should able to see the new Store Dashboard page:

No alt providedNo alt provided

Step arrow right iconCreate dashboard tiles

This step is to create 4 dashboard tiles where:

  • Tile 1:  display the number of (AWAITING_WAVE) fulfilments with the expiry Time is less than 30 mins.
  • Tile 2: display the number of (AWAITING_WAVE) fulfilments with the expiry Time is between 30 and 60 mins.
  • Tile 3: display the number of (AWAITING_WAVE) fulfilments with the expiry Time is between 60 and 120 mins.
  • Tile 4: display the number of (AWAITING_WAVE) fulfilments assigned to this location.
Tile 1: Fulfilment expiring less than 30 mins

Parameter

Configuration

Data Source

`fulfilment_expired30Mins:fulfilment` query

Filters

  • `activeLocation.ref` of the current Location
  • `status` set to `AWAITING_WAVE`
  • `ExpiryTime from:Now, to:+30mins`

Min Threshold

0

Max Threshold

0

link

awaiting-pick page has a default filter of and status. Hence we only need to provide the fulfilments_expiryTime:

`#/waves/list/awaiting-pick?fulfilments_expiryTime={\"from\":\"{{dateStringFormatter (dateAdd day=0) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\",\"to\":\"{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\"}`

1{
2    "manifestVersion": "2.0",
3    "routes": [
4        {
5            "type": "page",
6            "path": "store_dashboard",
7            "component": "fc.page",
8            "nav": {
9                "label": "Store Dashboard",
10                "icon": "store"
11            },
12            "props": {
13                "title": "Store Dashboard"
14            },
15            "data": {
16                "query": "query ($ordersAwaitingPickFromLocationRef: String!, $ordersAwaitingPickStatus: [String]!,  $fulfilmentExpiryNow:DateTime!, $fulfilmentExpiry30mins:DateTime!) {  fulfilment_expired30Mins:fulfilments(fromLocation: {ref: $ordersAwaitingPickFromLocationRef}, status: $ordersAwaitingPickStatus, expiryTime:{from:$fulfilmentExpiryNow, to:$fulfilmentExpiry30mins}) {    edges {      node {        id        ref        order {          ref          totalPrice          customer {            firstName            lastName          }        }        expiryTime        deliveryType      }    }  }  }",
17                "variables": {
18                    "ordersAwaitingPickFromLocationRef": "{{activeLocation.ref}}",
19                    "ordersAwaitingPickStatus": [
20                        "AWAITING_WAVE"
21                    ],
22                    "fulfilmentExpiryNow": "{{dateStringFormatter (dateAdd day=0) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}",
23                    "fulfilmentExpiry30mins": "{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}"
24                }
25            },
26            "descendants": [
27                {
28                    "component": "fc.dashboard.threshold",
29                    "dataSource": "fulfilment_expired30Mins",
30                    "props": {
31                        "label": "i18n:fc.sf.ui.waves.detail.dashboard.ordersAwaitingPickExpired30Mins.title",
32                        "subTitle": "Expiring in 30 mins",
33                        "value": "{{edges.length}}",
34                        "thresholdLow": 0,
35                        "thresholdHigh": 0,
36                        "width": "third",
37                        "link": "#/waves/list/awaiting-pick?fulfilments_expiryTime={\"from\":\"{{dateStringFormatter (dateAdd day=0) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\",\"to\":\"{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\"}"
38                    }
39                }
40            ]
41        }
42    ]
43}

Update the language setting:

1"fc.sf.ui.waves.detail.dashboard.ordersAwaitingPickExpired30Mins.title": "ORDER AWAITING PICK EXPIRING in 30 mins",
2"fc.sf.ui.waves.detail.dashboard.ordersAwaitingPickExpired60Mins.title": "ORDER AWAITING PICK EXPIRING in 60 mins",
3"fc.sf.ui.waves.detail.dashboard.ordersAwaitingPickExpired120Mins.title": "ORDER AWAITING PICK EXPIRING in 2 hours",   
4
No alt provided

Refresh the Fluent Store screen:

No alt provided
Tile 2: Fulfilment expiring between 30 and 60 mins

Parameter

Configuration

Data Source

`fulfilment_expired60Mins:fulfilment` query

Filters

  • `activeLocation.ref` of the current Location
  • `status` set to `AWAITING_WAVE`
  • `ExpiryTime from:+30mins, to:+60mins`

Min Threshold

1

Max Threshold

10

link

awaiting-pick page has a default filter of and status. Hence we only need to provide the fulfilments_expiryTime:

`#/waves/list/awaiting-pick?fulfilments_expiryTime={\"from\":\"{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\",\"to\":\"{{dateStringFormatter (dateAdd minute=60) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\"}`

1
2// 1. In the query section:
3//
4// 1.a Add a new parameter:
5, $fulfilmentExpiry60mins:DateTime!
6
7// 1.b add a new subquery:
8fulfilment_expired60Mins:fulfilments(fromLocation: {ref: $ordersAwaitingPickFromLocationRef}, status: $ordersAwaitingPickStatus, expiryTime:{from:$fulfilmentExpiry30mins, to:$fulfilmentExpiry60mins }) {    edges {      node {        id        ref        order {          ref          totalPrice          customer {            firstName            lastName          }        }        expiryTime        deliveryType      }    }  }
9
10// 2. In the variables section:
11//
12,
13"fulfilmentExpiry60mins": "{{dateStringFormatter (dateAdd minute=60) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}"
14
15// 3. In the descendants section:
16,
17    {
18        "component": "fc.dashboard.threshold",
19        "dataSource": "fulfilment_expired60Mins",
20        "props": {
21            "label": "i18n:fc.sf.ui.waves.detail.dashboard.ordersAwaitingPickExpired60Mins.title",
22            "subTitle": "Expiring in 60 mins",
23            "value": "{{edges.length}}",
24            "thresholdLow": 1,
25            "thresholdHigh": 10,
26            "width": "third",
27            "link": "#/waves/list/awaiting-pick?fulfilments_expiryTime={\"from\":\"{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\",\"to\":\"{{dateStringFormatter (dateAdd minute=60) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\"}"
28        }
29    } 
30
1{
2    "manifestVersion": "2.0",
3    "routes": [
4        {
5            "type": "page",
6            "path": "store_dashboard",
7            "component": "fc.page",
8            "nav": {
9                "label": "Store Dashboard",
10                "icon": "store"
11            },
12            "props": {
13                "title": "Store Dashboard"
14            },
15            "data": {
16                "query": "query ($ordersAwaitingPickFromLocationRef: String!, $ordersAwaitingPickStatus: [String]!,  $fulfilmentExpiryNow:DateTime!, $fulfilmentExpiry30mins:DateTime!, $fulfilmentExpiry60mins:DateTime!) {  fulfilment_expired30Mins:fulfilments(fromLocation: {ref: $ordersAwaitingPickFromLocationRef}, status: $ordersAwaitingPickStatus, expiryTime:{from:$fulfilmentExpiryNow, to:$fulfilmentExpiry30mins}) {    edges {      node {        id        ref        order {          ref          totalPrice          customer {            firstName            lastName          }        }        expiryTime        deliveryType      }    }  } \n fulfilment_expired60Mins:fulfilments(fromLocation: {ref: $ordersAwaitingPickFromLocationRef}, status: $ordersAwaitingPickStatus, expiryTime:{from:$fulfilmentExpiry30mins, to:$fulfilmentExpiry60mins }) {    edges {      node {        id        ref        order {          ref          totalPrice          customer {            firstName            lastName          }        }        expiryTime        deliveryType      }    }  } }",
17                "variables": {
18                    "ordersAwaitingPickFromLocationRef": "{{activeLocation.ref}}",
19                    "ordersAwaitingPickStatus": [
20                        "AWAITING_WAVE"
21                    ],
22                    "fulfilmentExpiryNow": "{{dateStringFormatter (dateAdd day=0) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}",
23                    "fulfilmentExpiry30mins": "{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}",
24                    "fulfilmentExpiry60mins": "{{dateStringFormatter (dateAdd minute=60) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}"
25                }
26            },
27            "descendants": [
28                {
29                    "component": "fc.dashboard.threshold",
30                    "dataSource": "fulfilment_expired30Mins",
31                    "props": {
32                        "label": "i18n:fc.sf.ui.waves.detail.dashboard.ordersAwaitingPickExpired30Mins.title",
33                        "subTitle": "Expiring in 30 mins",
34                        "value": "{{edges.length}}",
35                        "thresholdLow": 0,
36                        "thresholdHigh": 0,
37                        "width": "third",
38                        "link": "#/waves/list/awaiting-pick?fulfilments_expiryTime={\"from\":\"{{dateStringFormatter (dateAdd day=0) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\",\"to\":\"{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\"}"
39                    }
40                },
41                {
42                    "component": "fc.dashboard.threshold",
43                    "dataSource": "fulfilment_expired60Mins",
44                    "props": {
45                        "label": "i18n:fc.sf.ui.waves.detail.dashboard.ordersAwaitingPickExpired60Mins.title",
46                        "subTitle": "Expiring in 60 mins",
47                        "value": "{{edges.length}}",
48                        "thresholdLow": 1,
49                        "thresholdHigh": 10,
50                        "width": "third",
51                        "link": "#/waves/list/awaiting-pick?fulfilments_expiryTime={\"from\":\"{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\",\"to\":\"{{dateStringFormatter (dateAdd minute=60) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\"}"
52                    }
53                }                
54            ]
55        }
56    ]
57}

Refresh the Fluent Store:

No alt provided

Follow the same pattern as above for tile 3 (with expiryTime from:60mins and to:120mins) and for tile 4 expiryTime parameter does not require:

1{
2    "manifestVersion": "2.0",
3    "routes": [
4        {
5            "type": "page",
6            "path": "store_dashboard",
7            "component": "fc.page",
8            "nav": {
9                "label": "Store Dashboard",
10                "icon": "store"
11            },
12            "props": {
13                "title": "Store Dashboard"
14            },
15            "data": {
16                "query": "query ($ordersAwaitingPickFromLocationRef: String!, $ordersAwaitingPickStatus: [String]!,  $fulfilmentExpiryNow:DateTime!, $fulfilmentExpiry30mins:DateTime!, $fulfilmentExpiry60mins:DateTime!, $fulfilmentExpiry120mins:DateTime!) {  fulfilment_expired30Mins:fulfilments(fromLocation: {ref: $ordersAwaitingPickFromLocationRef}, status: $ordersAwaitingPickStatus, expiryTime:{from:$fulfilmentExpiryNow, to:$fulfilmentExpiry30mins}) {    edges {      node {        id        ref        order {          ref          totalPrice          customer {            firstName            lastName          }        }        expiryTime        deliveryType      }    }  } \n fulfilment_expired60Mins:fulfilments(fromLocation: {ref: $ordersAwaitingPickFromLocationRef}, status: $ordersAwaitingPickStatus, expiryTime:{from:$fulfilmentExpiry30mins, to:$fulfilmentExpiry60mins }) {    edges {      node {        id        ref        order {          ref          totalPrice          customer {            firstName            lastName          }        }        expiryTime        deliveryType      }    }  } \n fulfilment_expired120Mins:fulfilments(fromLocation: {ref: $ordersAwaitingPickFromLocationRef}, status: $ordersAwaitingPickStatus, expiryTime:{from:$fulfilmentExpiry60mins, to:$fulfilmentExpiry120mins }) {    edges {      node {        id        ref        order {          ref          totalPrice          customer {            firstName            lastName          }        }        expiryTime        deliveryType      }    }  }\n fulfilment_awaitingwave:fulfilments(fromLocation: {ref: $ordersAwaitingPickFromLocationRef}, status: $ordersAwaitingPickStatus) {    edges {      node {        id        ref        order {          ref          totalPrice          customer {            firstName            lastName          }        }        expiryTime        deliveryType      }    }  } \n }",
17                "variables": {
18                    "ordersAwaitingPickFromLocationRef": "{{activeLocation.ref}}",
19                    "ordersAwaitingPickStatus": [
20                        "AWAITING_WAVE"
21                    ],
22                    "fulfilmentExpiryNow": "{{dateStringFormatter (dateAdd day=0) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}",
23                    "fulfilmentExpiry30mins": "{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}",
24                    "fulfilmentExpiry60mins": "{{dateStringFormatter (dateAdd minute=60) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}",
25                    "fulfilmentExpiry120mins": "{{dateStringFormatter (dateAdd minute=120) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}"
26                }
27            },
28            "descendants": [
29                {
30                    "component": "fc.dashboard.threshold",
31                    "dataSource": "fulfilment_expired30Mins",
32                    "props": {
33                        "label": "i18n:fc.sf.ui.waves.detail.dashboard.ordersAwaitingPickExpired30Mins.title",
34                        "subTitle": "Expiring in 30 mins",
35                        "value": "{{edges.length}}",
36                        "thresholdLow": 0,
37                        "thresholdHigh": 0,
38                        "width": "third",
39                        "link": "#/waves/list/awaiting-pick?fulfilments_expiryTime={\"from\":\"{{dateStringFormatter (dateAdd day=0) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\",\"to\":\"{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\"}"
40                    }
41                },
42                {
43                    "component": "fc.dashboard.threshold",
44                    "dataSource": "fulfilment_expired60Mins",
45                    "props": {
46                        "label": "i18n:fc.sf.ui.waves.detail.dashboard.ordersAwaitingPickExpired60Mins.title",
47                        "subTitle": "Expiring in 60 mins",
48                        "value": "{{edges.length}}",
49                        "thresholdLow": 1,
50                        "thresholdHigh": 10,
51                        "width": "third",
52                        "link": "#/waves/list/awaiting-pick?fulfilments_expiryTime={\"from\":\"{{dateStringFormatter (dateAdd minute=30) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\",\"to\":\"{{dateStringFormatter (dateAdd minute=60) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\"}"
53                    }
54                },
55                {
56                    "component": "fc.dashboard.threshold",
57                    "dataSource": "fulfilment_expired120Mins",
58                    "props": {
59                        "label": "i18n:fc.sf.ui.waves.detail.dashboard.ordersAwaitingPickExpired120Mins.title",
60                        "subTitle": "Expiring in 120 mins",
61                        "value": "{{edges.length}}",
62                        "thresholdLow": 1,
63                        "thresholdHigh": 10,
64                        "width": "third",
65                        "link": "#/waves/list/awaiting-pick?fulfilments_expiryTime={\"from\":\"{{dateStringFormatter (dateAdd minute=60) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\",\"to\":\"{{dateStringFormatter (dateAdd minute=120) 'YYYY-MM-DD[T]HH:mm:ss.SSS' true}}Z\"}"
66                    }
67                },
68                {
69                    "component": "fc.dashboard.threshold",
70                    "dataSource": "fulfilment_awaitingwave",
71                    "props": {
72                        "label": "i18n:fc.sf.ui.waves.detail.dashboard.ordersAwaitingPick.title",
73                        "subTitle": "subTile text1",
74                        "value": "{{edges.length}}",
75                        "thresholdLow": 1,
76                        "thresholdHigh": 10,
77                        "width": "third"
78                    }
79                }
80            ]
81        }
82    ]
83}
No alt provided