Fluent Store Dashboard: new dashboard tile based on fulfilment expiry time
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
Prerequisites
Steps
Create 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},

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


Create 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 |
|
Filters |
|
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:
|
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

Refresh the Fluent Store screen:

Tile 2: Fulfilment expiring between 30 and 60 mins
Parameter | Configuration |
Data Source |
|
Filters |
|
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:
|
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:

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}
