@finos/legend-application-marketplace 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/lib/__lib__/LegendMarketplaceAppEvent.d.ts +3 -0
  2. package/lib/__lib__/LegendMarketplaceAppEvent.d.ts.map +1 -1
  3. package/lib/__lib__/LegendMarketplaceAppEvent.js +3 -0
  4. package/lib/__lib__/LegendMarketplaceAppEvent.js.map +1 -1
  5. package/lib/__lib__/LegendMarketplaceNavigation.d.ts +7 -1
  6. package/lib/__lib__/LegendMarketplaceNavigation.d.ts.map +1 -1
  7. package/lib/__lib__/LegendMarketplaceNavigation.js +9 -1
  8. package/lib/__lib__/LegendMarketplaceNavigation.js.map +1 -1
  9. package/lib/__lib__/LegendMarketplaceTelemetryHelper.d.ts +3 -1
  10. package/lib/__lib__/LegendMarketplaceTelemetryHelper.d.ts.map +1 -1
  11. package/lib/__lib__/LegendMarketplaceTelemetryHelper.js +18 -2
  12. package/lib/__lib__/LegendMarketplaceTelemetryHelper.js.map +1 -1
  13. package/lib/application/LegendMarketplaceWebApplication.d.ts.map +1 -1
  14. package/lib/application/LegendMarketplaceWebApplication.js +4 -1
  15. package/lib/application/LegendMarketplaceWebApplication.js.map +1 -1
  16. package/lib/application/providers/LegendMarketplaceFieldSearchResultsStoreProvider.d.ts +22 -0
  17. package/lib/application/providers/LegendMarketplaceFieldSearchResultsStoreProvider.d.ts.map +1 -0
  18. package/lib/application/providers/LegendMarketplaceFieldSearchResultsStoreProvider.js +37 -0
  19. package/lib/application/providers/LegendMarketplaceFieldSearchResultsStoreProvider.js.map +1 -0
  20. package/lib/components/AddToCart/CartDrawer.d.ts.map +1 -1
  21. package/lib/components/AddToCart/CartDrawer.js +36 -4
  22. package/lib/components/AddToCart/CartDrawer.js.map +1 -1
  23. package/lib/components/AddToCart/RecommendedAddOnsModal.d.ts +2 -1
  24. package/lib/components/AddToCart/RecommendedAddOnsModal.d.ts.map +1 -1
  25. package/lib/components/AddToCart/RecommendedAddOnsModal.js +23 -13
  26. package/lib/components/AddToCart/RecommendedAddOnsModal.js.map +1 -1
  27. package/lib/components/AddToCart/RecommendedItemsCard.d.ts +3 -1
  28. package/lib/components/AddToCart/RecommendedItemsCard.d.ts.map +1 -1
  29. package/lib/components/AddToCart/RecommendedItemsCard.js +14 -11
  30. package/lib/components/AddToCart/RecommendedItemsCard.js.map +1 -1
  31. package/lib/components/FieldSearchFiltersPanel/FieldSearchFiltersPanel.d.ts +23 -0
  32. package/lib/components/FieldSearchFiltersPanel/FieldSearchFiltersPanel.d.ts.map +1 -0
  33. package/lib/components/FieldSearchFiltersPanel/FieldSearchFiltersPanel.js +22 -0
  34. package/lib/components/FieldSearchFiltersPanel/FieldSearchFiltersPanel.js.map +1 -0
  35. package/lib/components/LegendServiceCard/LegendServiceCard.d.ts +2 -0
  36. package/lib/components/LegendServiceCard/LegendServiceCard.d.ts.map +1 -1
  37. package/lib/components/LegendServiceCard/LegendServiceCard.js +12 -8
  38. package/lib/components/LegendServiceCard/LegendServiceCard.js.map +1 -1
  39. package/lib/components/LegendServiceCard/LegendServiceGrid.d.ts +24 -0
  40. package/lib/components/LegendServiceCard/LegendServiceGrid.d.ts.map +1 -0
  41. package/lib/components/LegendServiceCard/LegendServiceGrid.js +124 -0
  42. package/lib/components/LegendServiceCard/LegendServiceGrid.js.map +1 -0
  43. package/lib/components/LegendServiceCard/LegendServiceListRow.d.ts +2 -0
  44. package/lib/components/LegendServiceCard/LegendServiceListRow.d.ts.map +1 -1
  45. package/lib/components/LegendServiceCard/LegendServiceListRow.js +8 -4
  46. package/lib/components/LegendServiceCard/LegendServiceListRow.js.map +1 -1
  47. package/lib/components/MarketplaceCard/FieldSearchResultListItem.d.ts +25 -0
  48. package/lib/components/MarketplaceCard/FieldSearchResultListItem.d.ts.map +1 -0
  49. package/lib/components/MarketplaceCard/FieldSearchResultListItem.js +58 -0
  50. package/lib/components/MarketplaceCard/FieldSearchResultListItem.js.map +1 -0
  51. package/lib/components/MarketplaceSearchFiltersPanel/MarketplaceSearchFiltersPanel.d.ts +10 -0
  52. package/lib/components/MarketplaceSearchFiltersPanel/MarketplaceSearchFiltersPanel.d.ts.map +1 -1
  53. package/lib/components/MarketplaceSearchFiltersPanel/MarketplaceSearchFiltersPanel.js +2 -2
  54. package/lib/components/MarketplaceSearchFiltersPanel/MarketplaceSearchFiltersPanel.js.map +1 -1
  55. package/lib/components/Pagination/PaginationControls.d.ts +1 -0
  56. package/lib/components/Pagination/PaginationControls.d.ts.map +1 -1
  57. package/lib/components/Pagination/PaginationControls.js +2 -2
  58. package/lib/components/Pagination/PaginationControls.js.map +1 -1
  59. package/lib/components/ProviderCard/LegendMarketplaceTerminalCard.d.ts.map +1 -1
  60. package/lib/components/ProviderCard/LegendMarketplaceTerminalCard.js +5 -2
  61. package/lib/components/ProviderCard/LegendMarketplaceTerminalCard.js.map +1 -1
  62. package/lib/components/SearchBar/LegendMarketplaceSearchBar.d.ts +2 -1
  63. package/lib/components/SearchBar/LegendMarketplaceSearchBar.d.ts.map +1 -1
  64. package/lib/components/SearchBar/LegendMarketplaceSearchBar.js +20 -7
  65. package/lib/components/SearchBar/LegendMarketplaceSearchBar.js.map +1 -1
  66. package/lib/index.css +2 -2
  67. package/lib/index.css.map +1 -1
  68. package/lib/package.json +1 -1
  69. package/lib/pages/DataAPIs/LegendMarketplaceDataAPIs.d.ts.map +1 -1
  70. package/lib/pages/DataAPIs/LegendMarketplaceDataAPIs.js +17 -11
  71. package/lib/pages/DataAPIs/LegendMarketplaceDataAPIs.js.map +1 -1
  72. package/lib/pages/Lakehouse/MarketplaceLakehouseHome.d.ts.map +1 -1
  73. package/lib/pages/Lakehouse/MarketplaceLakehouseHome.js +10 -5
  74. package/lib/pages/Lakehouse/MarketplaceLakehouseHome.js.map +1 -1
  75. package/lib/pages/Lakehouse/searchResults/LegendMarketplaceFieldSearchResults.d.ts +17 -0
  76. package/lib/pages/Lakehouse/searchResults/LegendMarketplaceFieldSearchResults.d.ts.map +1 -0
  77. package/lib/pages/Lakehouse/searchResults/LegendMarketplaceFieldSearchResults.js +126 -0
  78. package/lib/pages/Lakehouse/searchResults/LegendMarketplaceFieldSearchResults.js.map +1 -0
  79. package/lib/pages/Lakehouse/searchResults/LegendMarketplaceSearchResults.d.ts.map +1 -1
  80. package/lib/pages/Lakehouse/searchResults/LegendMarketplaceSearchResults.js +14 -5
  81. package/lib/pages/Lakehouse/searchResults/LegendMarketplaceSearchResults.js.map +1 -1
  82. package/lib/pages/TerminalsAddons/LegendMarketplaceTerminalsAddons.d.ts.map +1 -1
  83. package/lib/pages/TerminalsAddons/LegendMarketplaceTerminalsAddons.js +2 -2
  84. package/lib/pages/TerminalsAddons/LegendMarketplaceTerminalsAddons.js.map +1 -1
  85. package/lib/stores/cart/CartStore.d.ts +10 -3
  86. package/lib/stores/cart/CartStore.d.ts.map +1 -1
  87. package/lib/stores/cart/CartStore.js +66 -42
  88. package/lib/stores/cart/CartStore.js.map +1 -1
  89. package/lib/stores/dataAPIs/LegendMarketplaceDataAPIsStore.d.ts +8 -1
  90. package/lib/stores/dataAPIs/LegendMarketplaceDataAPIsStore.d.ts.map +1 -1
  91. package/lib/stores/dataAPIs/LegendMarketplaceDataAPIsStore.js +37 -3
  92. package/lib/stores/dataAPIs/LegendMarketplaceDataAPIsStore.js.map +1 -1
  93. package/lib/stores/lakehouse/LegendMarketplaceFieldSearchResultsStore.d.ts +63 -0
  94. package/lib/stores/lakehouse/LegendMarketplaceFieldSearchResultsStore.d.ts.map +1 -0
  95. package/lib/stores/lakehouse/LegendMarketplaceFieldSearchResultsStore.js +228 -0
  96. package/lib/stores/lakehouse/LegendMarketplaceFieldSearchResultsStore.js.map +1 -0
  97. package/lib/stores/lakehouse/LegendMarketplaceProductViewerStore.d.ts.map +1 -1
  98. package/lib/stores/lakehouse/LegendMarketplaceProductViewerStore.js +9 -13
  99. package/lib/stores/lakehouse/LegendMarketplaceProductViewerStore.js.map +1 -1
  100. package/lib/stores/lakehouse/LegendMarketplaceSearchResultsStore.d.ts +2 -0
  101. package/lib/stores/lakehouse/LegendMarketplaceSearchResultsStore.d.ts.map +1 -1
  102. package/lib/stores/lakehouse/LegendMarketplaceSearchResultsStore.js +8 -4
  103. package/lib/stores/lakehouse/LegendMarketplaceSearchResultsStore.js.map +1 -1
  104. package/lib/stores/lakehouse/fieldSearch/FieldSearchResultState.d.ts +40 -0
  105. package/lib/stores/lakehouse/fieldSearch/FieldSearchResultState.d.ts.map +1 -0
  106. package/lib/stores/lakehouse/fieldSearch/FieldSearchResultState.js +84 -0
  107. package/lib/stores/lakehouse/fieldSearch/FieldSearchResultState.js.map +1 -0
  108. package/package.json +13 -13
  109. package/src/__lib__/LegendMarketplaceAppEvent.ts +3 -0
  110. package/src/__lib__/LegendMarketplaceNavigation.ts +18 -1
  111. package/src/__lib__/LegendMarketplaceTelemetryHelper.ts +32 -1
  112. package/src/application/LegendMarketplaceWebApplication.tsx +13 -0
  113. package/src/application/providers/LegendMarketplaceFieldSearchResultsStoreProvider.tsx +67 -0
  114. package/src/components/AddToCart/CartDrawer.tsx +49 -4
  115. package/src/components/AddToCart/RecommendedAddOnsModal.tsx +86 -24
  116. package/src/components/AddToCart/RecommendedItemsCard.tsx +143 -120
  117. package/src/components/FieldSearchFiltersPanel/FieldSearchFiltersPanel.tsx +65 -0
  118. package/src/components/LegendServiceCard/LegendServiceCard.tsx +25 -3
  119. package/src/components/LegendServiceCard/LegendServiceGrid.tsx +206 -0
  120. package/src/components/LegendServiceCard/LegendServiceListRow.tsx +27 -3
  121. package/src/components/MarketplaceCard/FieldSearchResultListItem.tsx +163 -0
  122. package/src/components/MarketplaceSearchFiltersPanel/MarketplaceSearchFiltersPanel.tsx +2 -2
  123. package/src/components/Pagination/PaginationControls.tsx +7 -4
  124. package/src/components/ProviderCard/LegendMarketplaceTerminalCard.tsx +7 -0
  125. package/src/components/SearchBar/LegendMarketplaceSearchBar.tsx +44 -3
  126. package/src/pages/DataAPIs/LegendMarketplaceDataAPIs.tsx +80 -14
  127. package/src/pages/Lakehouse/MarketplaceLakehouseHome.tsx +16 -3
  128. package/src/pages/Lakehouse/searchResults/LegendMarketplaceFieldSearchResults.tsx +380 -0
  129. package/src/pages/Lakehouse/searchResults/LegendMarketplaceSearchResults.tsx +34 -3
  130. package/src/pages/TerminalsAddons/LegendMarketplaceTerminalsAddons.tsx +6 -2
  131. package/src/stores/cart/CartStore.ts +86 -51
  132. package/src/stores/dataAPIs/LegendMarketplaceDataAPIsStore.ts +58 -2
  133. package/src/stores/lakehouse/LegendMarketplaceFieldSearchResultsStore.ts +309 -0
  134. package/src/stores/lakehouse/LegendMarketplaceProductViewerStore.ts +23 -30
  135. package/src/stores/lakehouse/LegendMarketplaceSearchResultsStore.ts +11 -6
  136. package/src/stores/lakehouse/fieldSearch/FieldSearchResultState.ts +122 -0
  137. package/tsconfig.json +7 -0
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Copyright (c) 2026-present, Goldman Sachs
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { createContext, useContext, useEffect } from 'react';
18
+ import { useLocalObservable } from 'mobx-react-lite';
19
+ import { guaranteeNonNullable } from '@finos/legend-shared';
20
+ import { useLegendMarketplaceBaseStore } from './LegendMarketplaceFrameworkProvider.js';
21
+ import { LegendMarketplaceFieldSearchResultsStore } from '../../stores/lakehouse/LegendMarketplaceFieldSearchResultsStore.js';
22
+
23
+ const LegendMarketplaceFieldSearchResultsStoreContext = createContext<
24
+ LegendMarketplaceFieldSearchResultsStore | undefined
25
+ >(undefined);
26
+
27
+ export const LegendMarketplaceFieldSearchResultsStoreProvider: React.FC<{
28
+ children: React.ReactNode;
29
+ }> = ({ children }) => {
30
+ const legendMarketplaceBaseStore = useLegendMarketplaceBaseStore();
31
+ const fieldSearchResultsStore = useLocalObservable(
32
+ () =>
33
+ new LegendMarketplaceFieldSearchResultsStore(legendMarketplaceBaseStore),
34
+ );
35
+
36
+ useEffect(() => {
37
+ return () => {
38
+ fieldSearchResultsStore.dispose();
39
+ };
40
+ }, [fieldSearchResultsStore]);
41
+
42
+ return (
43
+ <LegendMarketplaceFieldSearchResultsStoreContext.Provider
44
+ value={fieldSearchResultsStore}
45
+ >
46
+ {children}
47
+ </LegendMarketplaceFieldSearchResultsStoreContext.Provider>
48
+ );
49
+ };
50
+
51
+ export const useLegendMarketplaceFieldSearchResultsStore =
52
+ (): LegendMarketplaceFieldSearchResultsStore =>
53
+ guaranteeNonNullable(
54
+ useContext(LegendMarketplaceFieldSearchResultsStoreContext),
55
+ `Can't find field search results store in context`,
56
+ );
57
+
58
+ export const withLegendMarketplaceFieldSearchResultsStore = (
59
+ WrappedComponent: React.FC,
60
+ ): React.FC =>
61
+ function WithLegendMarketplaceFieldSearchResultsStore() {
62
+ return (
63
+ <LegendMarketplaceFieldSearchResultsStoreProvider>
64
+ <WrappedComponent />
65
+ </LegendMarketplaceFieldSearchResultsStoreProvider>
66
+ );
67
+ };
@@ -15,7 +15,7 @@
15
15
  */
16
16
 
17
17
  import { observer } from 'mobx-react-lite';
18
- import { useEffect } from 'react';
18
+ import { useCallback, useEffect } from 'react';
19
19
  import { flowResult } from 'mobx';
20
20
  import {
21
21
  Drawer,
@@ -70,7 +70,9 @@ export const CartDrawer = observer((): React.ReactNode => {
70
70
  label: 'Clear Cart',
71
71
  type: ActionAlertActionType.PROCEED_WITH_CAUTION,
72
72
  handler: (): void => {
73
- cart.clearCart();
73
+ flowResult(cart.clearCart()).catch(
74
+ applicationStore.alertUnhandledError,
75
+ );
74
76
  },
75
77
  },
76
78
  {
@@ -82,6 +84,45 @@ export const CartDrawer = observer((): React.ReactNode => {
82
84
  });
83
85
  };
84
86
 
87
+ const handleDeleteItem = useCallback(
88
+ (cartId: number, productName: string) => {
89
+ const dependentAddOns = cart.getDependentAddOns(cartId);
90
+ if (dependentAddOns.length > 0) {
91
+ const addOnNames = dependentAddOns
92
+ .map((item) => item.productName)
93
+ .join(', ');
94
+ applicationStore.alertService.setActionAlertInfo({
95
+ title: 'Confirm Deletion',
96
+ message: `Delete '${productName}'?`,
97
+ messageClass: 'legend-marketplace-cart-drawer__alert-message',
98
+ prompt: `This will also remove ${dependentAddOns.length} associated add-on${dependentAddOns.length > 1 ? 's' : ''}: ${addOnNames}.`,
99
+ type: ActionAlertType.CAUTION,
100
+ actions: [
101
+ {
102
+ label: 'Delete All',
103
+ type: ActionAlertActionType.PROCEED_WITH_CAUTION,
104
+ handler: (): void => {
105
+ flowResult(cart.deleteCartItem(cartId, true)).catch(
106
+ applicationStore.alertUnhandledError,
107
+ );
108
+ },
109
+ },
110
+ {
111
+ label: 'Cancel',
112
+ type: ActionAlertActionType.PROCEED,
113
+ default: true,
114
+ },
115
+ ],
116
+ });
117
+ } else {
118
+ flowResult(cart.deleteCartItem(cartId)).catch(
119
+ applicationStore.alertUnhandledError,
120
+ );
121
+ }
122
+ },
123
+ [applicationStore.alertService, applicationStore.alertUnhandledError, cart],
124
+ );
125
+
85
126
  return (
86
127
  <Drawer
87
128
  anchor="right"
@@ -202,7 +243,9 @@ export const CartDrawer = observer((): React.ReactNode => {
202
243
  </Box>
203
244
  <IconButton
204
245
  size="small"
205
- onClick={() => cart.deleteCartItem(item.cartId)}
246
+ onClick={() =>
247
+ handleDeleteItem(item.cartId, item.productName)
248
+ }
206
249
  className="legend-marketplace-cart-drawer__item-card__remove-btn"
207
250
  disabled={cart.loadingState.isInProgress}
208
251
  >
@@ -261,7 +304,9 @@ export const CartDrawer = observer((): React.ReactNode => {
261
304
  cart.submitState.isInProgress
262
305
  }
263
306
  onClick={() => {
264
- cart.submitOrder();
307
+ flowResult(cart.submitOrder()).catch(
308
+ applicationStore.alertUnhandledError,
309
+ );
265
310
  }}
266
311
  size="small"
267
312
  className="legend-marketplace-cart-drawer__order-button"
@@ -69,7 +69,9 @@ interface RecommendedAddOnsModalProps {
69
69
  selectedTerminal: TerminalResult,
70
70
  recommendations: TerminalResult[],
71
71
  responseMessage: string,
72
+ totalCount?: number | null,
72
73
  ) => void;
74
+ totalCount?: number | null | undefined;
73
75
  }
74
76
 
75
77
  const MAX_DISPLAY_ITEMS_COUNT = 10;
@@ -115,11 +117,12 @@ export const RecommendedAddOnsModal = observer(
115
117
  setShowModal,
116
118
  onViewCart,
117
119
  onTerminalSelected,
120
+ totalCount: initialTotalCount,
118
121
  } = props;
119
122
 
120
123
  const legendMarketplaceBaseStore = useLegendMarketplaceBaseStore();
121
124
  const applicationStore = legendMarketplaceBaseStore.applicationStore;
122
- const currentUser = applicationStore.identityService.currentUser;
125
+ const cartUser = legendMarketplaceBaseStore.cartStore.cartUser;
123
126
 
124
127
  const [searchTerm, setSearchTerm] = useState('');
125
128
  const [sortOrder, setSortOrder] = useState<SortOrder | undefined>();
@@ -128,6 +131,9 @@ export const RecommendedAddOnsModal = observer(
128
131
  const [terminalSearchResults, setTerminalSearchResults] = useState<
129
132
  TerminalResult[] | undefined
130
133
  >(undefined);
134
+ const [searchTotalCount, setSearchTotalCount] = useState<
135
+ number | undefined
136
+ >(undefined);
131
137
  const [isSearching, setIsSearching] = useState(false);
132
138
  const [isAssociating, setIsAssociating] = useState(false);
133
139
  const [associatingItemId, setAssociatingItemId] = useState<
@@ -143,12 +149,16 @@ export const RecommendedAddOnsModal = observer(
143
149
  const hasCartItems = recommendedItems.some(
144
150
  (item) => item.source === RecommendationSource.CART,
145
151
  );
152
+ const hasInventoryItems = recommendedItems.some(
153
+ (item) => item.source === RecommendationSource.INVENTORY,
154
+ );
146
155
  const hasMarketplaceItems = recommendedItems.some(
147
- (item) =>
148
- item.source === RecommendationSource.MARKETPLACE ||
149
- item.source === RecommendationSource.INVENTORY,
156
+ (item) => item.source === RecommendationSource.MARKETPLACE,
157
+ );
158
+ return (
159
+ [hasCartItems, hasInventoryItems, hasMarketplaceItems].filter(Boolean)
160
+ .length >= 2
150
161
  );
151
- return hasCartItems && hasMarketplaceItems;
152
162
  }, [recommendedItems]);
153
163
 
154
164
  const cartSourceItems = useMemo(
@@ -158,12 +168,17 @@ export const RecommendedAddOnsModal = observer(
158
168
  ),
159
169
  [recommendedItems],
160
170
  );
171
+ const inventorySourceItems = useMemo(
172
+ () =>
173
+ recommendedItems.filter(
174
+ (item) => item.source === RecommendationSource.INVENTORY,
175
+ ),
176
+ [recommendedItems],
177
+ );
161
178
  const marketplaceSourceItems = useMemo(
162
179
  () =>
163
180
  recommendedItems.filter(
164
- (item) =>
165
- item.source === RecommendationSource.MARKETPLACE ||
166
- item.source === RecommendationSource.INVENTORY,
181
+ (item) => item.source === RecommendationSource.MARKETPLACE,
167
182
  ),
168
183
  [recommendedItems],
169
184
  );
@@ -181,7 +196,7 @@ export const RecommendedAddOnsModal = observer(
181
196
  try {
182
197
  const response =
183
198
  await legendMarketplaceBaseStore.marketplaceServerClient.searchVendorAddons(
184
- currentUser,
199
+ cartUser,
185
200
  terminal.providerName,
186
201
  {
187
202
  // SERVER_SEARCH_PAGE_SIZE is set high enough to cover all expected results and paginate client-side.
@@ -196,6 +211,7 @@ export const RecommendedAddOnsModal = observer(
196
211
  setTerminalSearchResults(
197
212
  response.marketplace_addons as TerminalResult[],
198
213
  );
214
+ setSearchTotalCount(response.total_count as number | undefined);
199
215
  }
200
216
  } catch (error) {
201
217
  assertErrorThrown(error);
@@ -218,7 +234,7 @@ export const RecommendedAddOnsModal = observer(
218
234
  [
219
235
  terminal,
220
236
  isTerminalAdded,
221
- currentUser,
237
+ cartUser,
222
238
  legendMarketplaceBaseStore.marketplaceServerClient,
223
239
  applicationStore.logService,
224
240
  ],
@@ -232,6 +248,7 @@ export const RecommendedAddOnsModal = observer(
232
248
 
233
249
  if (!isTerminalAdded || !query.trim()) {
234
250
  setTerminalSearchResults(undefined);
251
+ setSearchTotalCount(undefined);
235
252
  setIsSearching(false);
236
253
  return;
237
254
  }
@@ -300,6 +317,7 @@ export const RecommendedAddOnsModal = observer(
300
317
  setSortOrder(undefined);
301
318
  setCurrentPage(1);
302
319
  setTerminalSearchResults(undefined);
320
+ setSearchTotalCount(undefined);
303
321
  setIsSearching(false);
304
322
  setIsAssociating(false);
305
323
  setAssociatingItemId(undefined);
@@ -336,6 +354,7 @@ export const RecommendedAddOnsModal = observer(
336
354
  selectedTerminal,
337
355
  result.recommendations,
338
356
  result.message,
357
+ result.totalCount,
339
358
  );
340
359
  } else {
341
360
  closeModal();
@@ -526,6 +545,45 @@ export const RecommendedAddOnsModal = observer(
526
545
  )}
527
546
 
528
547
  {cartSourceItems.length > 0 &&
548
+ (inventorySourceItems.length > 0 ||
549
+ marketplaceSourceItems.length > 0) && (
550
+ <Divider sx={{ my: 2 }} />
551
+ )}
552
+
553
+ {inventorySourceItems.length > 0 && (
554
+ <Box className="recommended-addons-modal__source-section">
555
+ <Box className="recommended-addons-modal__source-header">
556
+ <Typography
557
+ variant="h6"
558
+ className="recommended-addons-modal__source-title"
559
+ >
560
+ From Your Inventory
561
+ </Typography>
562
+ <Typography
563
+ variant="body2"
564
+ className="recommended-addons-modal__source-description"
565
+ >
566
+ Select a terminal from your existing inventory to
567
+ associate
568
+ </Typography>
569
+ </Box>
570
+ <Box className="recommended-addons-modal__list">
571
+ <ListHeader headerName={headerName} />
572
+ {inventorySourceItems.map((item) => (
573
+ <RecommendedItemsCard
574
+ key={item.id}
575
+ recommendedItem={item}
576
+ onSelect={handleAssociateTerminal}
577
+ isSelecting={isAssociating}
578
+ selectedItemId={associatingItemId}
579
+ />
580
+ ))}
581
+ </Box>
582
+ </Box>
583
+ )}
584
+
585
+ {(cartSourceItems.length > 0 ||
586
+ inventorySourceItems.length > 0) &&
529
587
  marketplaceSourceItems.length > 0 && <Divider sx={{ my: 2 }} />}
530
588
 
531
589
  {marketplaceSourceItems.length > 0 && (
@@ -576,6 +634,7 @@ export const RecommendedAddOnsModal = observer(
576
634
  setCurrentPage(1);
577
635
  if (!e.target.value.trim()) {
578
636
  setTerminalSearchResults(undefined);
637
+ setSearchTotalCount(undefined);
579
638
  setIsSearching(false);
580
639
  abortControllerRef.current?.abort();
581
640
  }
@@ -705,24 +764,27 @@ export const RecommendedAddOnsModal = observer(
705
764
  currentPage * itemsPerPage,
706
765
  filteredAndSortedItems.length,
707
766
  )}{' '}
708
- of {filteredAndSortedItems.length} items
767
+ of{' '}
768
+ {(terminalSearchResults
769
+ ? searchTotalCount
770
+ : initialTotalCount) ??
771
+ filteredAndSortedItems.length}{' '}
772
+ items
709
773
  </Typography>
710
774
  </Box>
711
775
  <Box className="recommended-addons-modal__list">
712
776
  <ListHeader headerName={headerName} />
713
- {paginatedItems
714
- .filter((item) => !item.isMandatory)
715
- .map((item) => (
716
- <RecommendedItemsCard
717
- key={item.id}
718
- recommendedItem={item}
719
- {...(isAddOnAssociation && {
720
- onSelect: handleAssociateTerminal,
721
- isSelecting: isAssociating,
722
- selectedItemId: associatingItemId,
723
- })}
724
- />
725
- ))}
777
+ {paginatedItems.map((item) => (
778
+ <RecommendedItemsCard
779
+ key={item.id}
780
+ recommendedItem={item}
781
+ {...(isAddOnAssociation && {
782
+ onSelect: handleAssociateTerminal,
783
+ isSelecting: isAssociating,
784
+ selectedItemId: associatingItemId,
785
+ })}
786
+ />
787
+ ))}
726
788
  </Box>
727
789
  {totalPages > 1 && (
728
790
  <Box className="recommended-addons-modal__pagination">