@vtex/faststore-plugin-buyer-portal 1.1.96 → 1.1.97

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore-plugin-buyer-portal",
3
- "version": "1.1.96",
3
+ "version": "1.1.97",
4
4
  "description": "A plugin for faststore with buyer portal",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -7,6 +7,7 @@ import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
7
7
  import { useAddBuyingPolicy } from "../../hooks";
8
8
  import { buyingPolicyDefault } from "../../utils";
9
9
 
10
+ import type { BudgetListResponse } from "../../../budgets/types";
10
11
  import type { BuyingPolicy } from "../../types";
11
12
 
12
13
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -19,6 +20,7 @@ export type AddBuyingPolicyDrawerProps = Omit<
19
20
  onCreate?: () => void;
20
21
  orgUnitId: string;
21
22
  contractId: string;
23
+ budgetData?: BudgetListResponse;
22
24
  };
23
25
 
24
26
  export const AddBuyingPolicyDrawer = ({
@@ -26,6 +28,7 @@ export const AddBuyingPolicyDrawer = ({
26
28
  onCreate,
27
29
  orgUnitId,
28
30
  contractId,
31
+ budgetData = { data: [], total: 0 },
29
32
  ...props
30
33
  }: AddBuyingPolicyDrawerProps) => {
31
34
  const { pushToast } = useUI();
@@ -85,6 +88,7 @@ export const AddBuyingPolicyDrawer = ({
85
88
  orgUnitId={orgUnitId}
86
89
  contractId={contractId}
87
90
  initialValues={defaultBuyingPolicyValues}
91
+ budgetData={budgetData}
88
92
  {...props}
89
93
  />
90
94
  );
@@ -23,11 +23,15 @@ import { type BuyingPolicy } from "../../types";
23
23
  import {
24
24
  BUYING_POLICIES_WORKFLOW_TYPES,
25
25
  buyingPolicyDefault,
26
+ BUDGET_CRITERIA,
26
27
  orderFieldsCriteriaOptions,
27
28
  spendingLimitsCriteriaOptions,
28
29
  } from "../../utils";
29
30
  import { BUYING_POLICIES_WORKFLOW_LABELS } from "../../utils/buyingPoliciesWorkflowTypes";
30
31
  import { getHighlightedText } from "../../utils/criteriaHighlightSyntax";
32
+ import { BudgetCriteriaSelector } from "../BudgetCriteriaSelector";
33
+
34
+ import type { BudgetListResponse } from "../../../budgets/types";
31
35
 
32
36
  const LIMIT_OF_LEVELS = 5;
33
37
 
@@ -50,6 +54,7 @@ export type BasicBuyingPolicyDrawerProps = Omit<
50
54
  drawerTitle?: string;
51
55
  saveButtonLabel?: string;
52
56
  isDrawerLoading?: boolean;
57
+ budgetData?: BudgetListResponse;
53
58
  };
54
59
 
55
60
  export const BasicBuyingPolicyDrawer = ({
@@ -62,6 +67,7 @@ export const BasicBuyingPolicyDrawer = ({
62
67
  orgUnitId,
63
68
  contractId,
64
69
  initialValues = defaultBuyingPolicyValues,
70
+ budgetData = { data: [], total: 0 },
65
71
  ...props
66
72
  }: BasicBuyingPolicyDrawerProps) => {
67
73
  const [form, setForm] = useState<BuyingPolicyForm>(initialValues);
@@ -167,6 +173,27 @@ export const BasicBuyingPolicyDrawer = ({
167
173
  });
168
174
  };
169
175
 
176
+ const isBudgetCriteria =
177
+ criteria === BUDGET_CRITERIA ||
178
+ criteria.includes('$exists(budgetData.unitAllocations.*[budgetId="');
179
+
180
+ const renderCriteria = (criteria: string) => {
181
+ if (isBudgetCriteria) {
182
+ return (
183
+ <BudgetCriteriaSelector
184
+ budgetData={budgetData}
185
+ currentCriteria={criteria}
186
+ onCriteriaChange={(newCriteria) =>
187
+ updateField("criteria", newCriteria)
188
+ }
189
+ onEditablePartClick={() => setCriteriaFocused(true)}
190
+ />
191
+ );
192
+ }
193
+
194
+ return getHighlightedText(criteria);
195
+ };
196
+
170
197
  const isConfirmButtonEnabled = isAllFieldsFilled && !isLoading;
171
198
 
172
199
  return (
@@ -258,10 +285,14 @@ export const BasicBuyingPolicyDrawer = ({
258
285
  {!criteriaFocused && (
259
286
  <div
260
287
  data-fs-bp-basic-buying-policy-criteria-input-highlighted
261
- onClick={() => setCriteriaFocused(true)}
288
+ onClick={() => {
289
+ if (!isBudgetCriteria) {
290
+ setCriteriaFocused(true);
291
+ }
292
+ }}
262
293
  >
263
294
  {criteria ? (
264
- getHighlightedText(criteria)
295
+ renderCriteria(criteria)
265
296
  ) : (
266
297
  <span data-fs-bp-label>Example: value {">"} 10000</span>
267
298
  )}
@@ -280,7 +311,7 @@ export const BasicBuyingPolicyDrawer = ({
280
311
  label: option.label,
281
312
  value: option.criteria,
282
313
  }))}
283
- onSelect={(value) => updateField("criteria", value)}
314
+ onSelect={(value: string) => updateField("criteria", value)}
284
315
  triggerLabel="Set spending limit criteria"
285
316
  highlightText={getHighlightedText}
286
317
  />
@@ -290,7 +321,7 @@ export const BasicBuyingPolicyDrawer = ({
290
321
  label: option.label,
291
322
  value: option.criteria,
292
323
  }))}
293
- onSelect={(value) => updateField("criteria", value)}
324
+ onSelect={(value: string) => updateField("criteria", value)}
294
325
  triggerLabel="Set order field criteria"
295
326
  highlightText={getHighlightedText}
296
327
  />
@@ -1,6 +1,7 @@
1
1
  @import "../../../shared/components/BasicDrawer/basic-drawer.scss";
2
2
  @import "../../../shared/components/OrgUnitInputSearch/org-unit-input-search.scss";
3
3
  @import "../../../shared/components/CustomDropdown/custom-dropdown.scss";
4
+ @import "../BudgetCriteriaSelector/budget-criteria-selector.scss";
4
5
 
5
6
  [data-fs-bp-basic-buying-policy-drawer] {
6
7
  @import "../../../shared/components/InputText/input-text.scss";
@@ -105,7 +106,6 @@
105
106
  var(--fs-spacing-3);
106
107
  border-radius: calc(var(--fs-border-radius) * 2);
107
108
  text-wrap: nowrap;
108
- overflow: hidden;
109
109
  text-overflow: ellipsis;
110
110
  white-space: nowrap;
111
111
  cursor: pointer;
@@ -124,6 +124,7 @@
124
124
  }
125
125
  }
126
126
 
127
+
127
128
  [data-fs-bp-input-text-criteria] {
128
129
  color: #5c5c5c;
129
130
 
@@ -0,0 +1,113 @@
1
+ import { useState, useEffect } from "react";
2
+
3
+ import { CustomDropdown } from "../../../shared/components/CustomDropdown/CustomDropdown";
4
+
5
+ import type { BudgetListResponse } from "../../../budgets/types";
6
+
7
+ export type BudgetCriteriaSelectorProps = {
8
+ onCriteriaChange: (criteria: string) => void;
9
+ currentCriteria: string;
10
+ onEditablePartClick?: () => void;
11
+ budgetData?: BudgetListResponse;
12
+ };
13
+
14
+ export const BudgetCriteriaSelector = ({
15
+ onCriteriaChange,
16
+ currentCriteria,
17
+ onEditablePartClick,
18
+ budgetData = { data: [], total: 0 },
19
+ }: BudgetCriteriaSelectorProps) => {
20
+ const extractBudgetValueFromCriteria = (criteria: string): string => {
21
+ const match = criteria.match(/budgetId="([^"]+)"/);
22
+ return match ? match[1] : "budget-001";
23
+ };
24
+
25
+ const [currentBudgetValue, setCurrentBudgetValue] = useState<string>(
26
+ extractBudgetValueFromCriteria(currentCriteria)
27
+ );
28
+
29
+ useEffect(() => {
30
+ const extractedValue = extractBudgetValueFromCriteria(currentCriteria);
31
+ setCurrentBudgetValue(extractedValue);
32
+ }, [currentCriteria]);
33
+
34
+ const getMatchingBudget = () => {
35
+ return budgetData.data.find(
36
+ (budget) =>
37
+ budget.id === currentBudgetValue || budget.id === currentBudgetValue
38
+ );
39
+ };
40
+
41
+ const generateCriteriaString = (value: string) => {
42
+ return `$exists(budgetData.unitAllocations.*[budgetId="${value}"])`;
43
+ };
44
+
45
+ const handleBudgetSelect = (budgetId: string) => {
46
+ const selectedBudget = budgetData.data.find(
47
+ (budget) => budget.id === budgetId
48
+ );
49
+ if (selectedBudget) {
50
+ const newValue = selectedBudget.id;
51
+ setCurrentBudgetValue(newValue);
52
+ const newCriteria = generateCriteriaString(newValue);
53
+ onCriteriaChange(newCriteria);
54
+ }
55
+ };
56
+
57
+ const handleBudgetSelectorClick = (e: React.MouseEvent) => {
58
+ e.stopPropagation();
59
+ };
60
+
61
+ const handleEditablePartClick = (e: React.MouseEvent) => {
62
+ e.stopPropagation();
63
+ onEditablePartClick?.();
64
+ };
65
+
66
+ const matchingBudget = getMatchingBudget();
67
+ const displayValue = matchingBudget ? matchingBudget.id : currentBudgetValue;
68
+ const hasBudgetData = budgetData.data.length > 0;
69
+
70
+ return (
71
+ <div
72
+ data-fs-bp-budget-criteria-selector
73
+ onClick={handleBudgetSelectorClick}
74
+ >
75
+ <div data-fs-bp-budget-criteria-string>
76
+ <span onClick={handleEditablePartClick} data-fs-bp-editable-part>
77
+ $exists(budgetData.unitAllocations.*[budgetId="
78
+ </span>
79
+ {hasBudgetData ? (
80
+ <div onClick={handleBudgetSelectorClick}>
81
+ <CustomDropdown
82
+ options={budgetData.data.map((budget) => ({
83
+ label: budget.name,
84
+ value: budget.id,
85
+ }))}
86
+ onSelect={handleBudgetSelect}
87
+ triggerLabel={displayValue}
88
+ highlightText={(text) => (
89
+ <div data-fs-bp-dropdown-option>
90
+ <div data-fs-bp-dropdown-option-label>{text}</div>
91
+ <div data-fs-bp-dropdown-option-uuid>
92
+ {budgetData.data.find((b) => b.name === text)?.id}
93
+ </div>
94
+ </div>
95
+ )}
96
+ />
97
+ </div>
98
+ ) : (
99
+ <span
100
+ onClick={handleEditablePartClick}
101
+ data-fs-bp-editable-part
102
+ data-fs-bp-budget-value
103
+ >
104
+ {displayValue}
105
+ </span>
106
+ )}
107
+ <span onClick={handleEditablePartClick} data-fs-bp-editable-part>
108
+ "])
109
+ </span>
110
+ </div>
111
+ </div>
112
+ );
113
+ };
@@ -0,0 +1,139 @@
1
+ [data-fs-bp-budget-criteria-selector] {
2
+ position: absolute;
3
+ top: 0;
4
+ left: 0;
5
+ width: 100%;
6
+ height: 100%;
7
+ margin: 0;
8
+ background-color: #f5f5f5;
9
+ border: var(--fs-border-width) solid #d6d6d6;
10
+ border-radius: calc(var(--fs-border-radius) * 2);
11
+ display: flex;
12
+ flex-direction: column;
13
+ align-items: flex-start;
14
+
15
+ [data-fs-bp-budget-criteria-string] {
16
+ font-family: "Roboto", monospace;
17
+ font-size: var(--fs-text-size-1);
18
+ color: #5c5c5c;
19
+ display: flex;
20
+ align-items: center;
21
+ padding: var(--fs-spacing-3) var(--fs-spacing-3);
22
+ gap: 0;
23
+ flex-wrap: wrap;
24
+ width: 100%;
25
+
26
+ > span {
27
+ white-space: nowrap;
28
+ }
29
+
30
+ [data-fs-bp-editable-part] {
31
+ cursor: pointer;
32
+ transition: background-color 0.2s ease;
33
+ padding: 0.125rem 0 0.25rem;
34
+ border-radius: calc(var(--fs-border-radius) * 0.5);
35
+
36
+ &:hover {
37
+ background-color: #f5f5f5;
38
+ color: #1f1f1f;
39
+ }
40
+ }
41
+
42
+ [data-fs-bp-custom-dropdown] {
43
+ display: inline-flex;
44
+
45
+ [data-fs-bp-custom-dropdown-trigger] {
46
+ color: #b521b6;
47
+ border: none;
48
+ min-width: 0;
49
+ border-radius: calc(var(--fs-border-radius) * 1.5);
50
+ font-family: "Roboto", monospace;
51
+ font-size: calc(var(--fs-text-size-1) * 0.9);
52
+ padding: 0;
53
+ cursor: pointer;
54
+ transition: background-color 0.2s ease;
55
+ background-color: transparent;
56
+
57
+ &:hover {
58
+ background-color: #f5f5f5;
59
+ }
60
+ }
61
+
62
+ [data-fs-bp-custom-dropdown-menu] {
63
+ position: absolute;
64
+ top: 100%;
65
+ left: 0;
66
+ margin-top: var(--fs-spacing-1);
67
+ padding: var(--fs-spacing-1) 0;
68
+ background-color: #fff;
69
+ box-shadow: 0rem 0.5rem 0.625rem 0rem rgba(0, 0, 0, 0.0784313725);
70
+ max-height: 15rem;
71
+ min-width: 20rem;
72
+ overflow-y: auto;
73
+ z-index: 1;
74
+ border-radius: calc(var(--fs-border-radius) * 2);
75
+
76
+ &::-webkit-scrollbar {
77
+ width: 0.75rem;
78
+ height: 0.75rem;
79
+ background-color: #fff;
80
+ }
81
+
82
+ &::-webkit-scrollbar-thumb {
83
+ background-color: #adadad;
84
+ border: 0.25rem solid transparent;
85
+ border-radius: 0.375rem;
86
+ background-clip: content-box;
87
+ }
88
+
89
+ [data-fs-bp-custom-dropdown-item] {
90
+ padding: var(--fs-spacing-2) var(--fs-spacing-3);
91
+ cursor: pointer;
92
+ border-bottom: var(--fs-border-width) solid #f0f0f0;
93
+
94
+ &:last-child {
95
+ border-bottom: none;
96
+ }
97
+
98
+ &:hover,
99
+ &[data-focused="true"] {
100
+ background-color: #ebebeb;
101
+ }
102
+
103
+ [data-fs-bp-dropdown-option] {
104
+ font-family: Inter;
105
+
106
+ [data-fs-bp-dropdown-option-label] {
107
+ font-weight: var(--fs-text-weight-semibold);
108
+ color: #1f1f1f;
109
+ font-size: var(--fs-text-size-1);
110
+ margin-bottom: var(--fs-spacing-0);
111
+ }
112
+
113
+ [data-fs-bp-dropdown-option-uuid] {
114
+ font-size: var(--fs-text-size-0);
115
+ color: #5c5c5c;
116
+ }
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
122
+
123
+ [data-fs-bp-custom-value-indicator] {
124
+ font-size: calc(var(--fs-text-size-0) * 0.85);
125
+ color: #666666;
126
+ font-style: italic;
127
+ padding: 0 var(--fs-spacing-3) calc(var(--fs-spacing-1) * 0.5);
128
+ border-top: 0.0625rem solid #e0e0e0;
129
+ margin-top: auto;
130
+ width: 100%;
131
+ background-color: #fafafa;
132
+ border-radius: 0 0 calc(var(--fs-border-radius) * 2)
133
+ calc(var(--fs-border-radius) * 2);
134
+ }
135
+
136
+ [data-fs-bp-budget-value] {
137
+ color: #b521b6;
138
+ }
139
+ }
@@ -0,0 +1,4 @@
1
+ export {
2
+ BudgetCriteriaSelector,
3
+ type BudgetCriteriaSelectorProps,
4
+ } from "./BudgetCriteriaSelector";
@@ -7,11 +7,14 @@ import { BasicDropdownMenu, Icon } from "../../../shared/components";
7
7
  import { useBuyerPortal, useDrawerProps } from "../../../shared/hooks";
8
8
  import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
9
9
 
10
+ import type { BudgetListResponse } from "../../../budgets/types";
11
+
10
12
  export type BuyingPolicyDropdownMenuProps = {
11
13
  id: string;
12
14
  name: string;
13
15
  onDelete?: () => void;
14
16
  onUpdate?: () => void;
17
+ budgetData?: BudgetListResponse;
15
18
  };
16
19
 
17
20
  export const BuyingPolicyDropdownMenu = ({
@@ -19,6 +22,7 @@ export const BuyingPolicyDropdownMenu = ({
19
22
  name,
20
23
  onDelete,
21
24
  onUpdate,
25
+ budgetData = { data: [], total: 0 },
22
26
  }: BuyingPolicyDropdownMenuProps) => {
23
27
  const { currentContract, currentOrgUnit } = useBuyerPortal();
24
28
 
@@ -80,6 +84,7 @@ export const BuyingPolicyDropdownMenu = ({
80
84
  contractId={currentContract?.id ?? ""}
81
85
  buyingPolicyId={id}
82
86
  onUpdate={onUpdate}
87
+ budgetData={budgetData}
83
88
  {...updateBuyingPolicyDrawerProps}
84
89
  isOpen={isUpdateBuyingPolicyDrawerOpen}
85
90
  />
@@ -7,6 +7,8 @@ import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
7
7
  import { useGetBuyingPolicy, useUpdateBuyingPolicy } from "../../hooks";
8
8
  import { buyingPolicyDefault } from "../../utils";
9
9
 
10
+ import type { BudgetListResponse } from "../../../budgets/types";
11
+
10
12
  export type UpdateBuyingPolicyDrawerProps = Omit<
11
13
  BasicBuyingPolicyDrawerProps,
12
14
  "children" | "initialValues"
@@ -15,6 +17,7 @@ export type UpdateBuyingPolicyDrawerProps = Omit<
15
17
  orgUnitId: string;
16
18
  contractId: string;
17
19
  buyingPolicyId: string;
20
+ budgetData?: BudgetListResponse;
18
21
  };
19
22
 
20
23
  export const UpdateBuyingPolicyDrawer = ({
@@ -23,6 +26,7 @@ export const UpdateBuyingPolicyDrawer = ({
23
26
  orgUnitId,
24
27
  contractId,
25
28
  buyingPolicyId,
29
+ budgetData = { data: [], total: 0 },
26
30
  ...props
27
31
  }: UpdateBuyingPolicyDrawerProps) => {
28
32
  const { buyingPolicy, isBuyingPolicyLoading } = useGetBuyingPolicy(
@@ -93,6 +97,7 @@ export const UpdateBuyingPolicyDrawer = ({
93
97
  initialValues={{ ...buyingPolicyDefault, ...(buyingPolicy ?? {}) }}
94
98
  orgUnitId={orgUnitId}
95
99
  contractId={contractId}
100
+ budgetData={budgetData}
96
101
  {...props}
97
102
  />
98
103
  );
@@ -21,6 +21,7 @@ import { BuyingPolicyDropdownMenu } from "../../components";
21
21
  import { AddBuyingPolicyDrawer } from "../../components/AddBuyingPolicyDrawer/AddBuyingPolicyDrawer";
22
22
  import { useGetBuyingPolicies } from "../../hooks/useGetBuyingPolicies";
23
23
 
24
+ import type { BudgetListResponse } from "../../../budgets/types";
24
25
  import type { BuyingPolicy } from "../../types";
25
26
 
26
27
  export type BuyingPoliciesLayoutProps = {
@@ -28,12 +29,14 @@ export type BuyingPoliciesLayoutProps = {
28
29
  total: number;
29
30
  search: string;
30
31
  page: number;
32
+ budgetData?: BudgetListResponse;
31
33
  };
32
34
 
33
35
  export const BuyingPoliciesLayout = ({
34
36
  buyingPolicies: initialBuyingPolicies,
35
37
  search,
36
38
  page,
39
+ budgetData = { data: [], total: 0 },
37
40
  }: BuyingPoliciesLayoutProps) => {
38
41
  const { currentContract, currentOrgUnit } = useBuyerPortal();
39
42
 
@@ -108,7 +111,7 @@ export const BuyingPoliciesLayout = ({
108
111
  return renderLoading();
109
112
  }
110
113
 
111
- if (buyingPolicies.length > 0) {
114
+ if (buyingPolicies.length === 0) {
112
115
  return renderEmptyState();
113
116
  }
114
117
 
@@ -133,6 +136,7 @@ export const BuyingPoliciesLayout = ({
133
136
  name={buyingPolicy.name}
134
137
  onUpdate={handleRefetchBuyingPolicies}
135
138
  onDelete={handleRefetchBuyingPolicies}
139
+ budgetData={budgetData}
136
140
  />
137
141
  }
138
142
  />
@@ -187,6 +191,7 @@ export const BuyingPoliciesLayout = ({
187
191
  contractId={currentContract?.id ?? ""}
188
192
  isOpen={isAddBuyingPolicyDrawerOpen}
189
193
  onCreate={handleRefetchBuyingPolicies}
194
+ budgetData={budgetData}
190
195
  {...addBuyingPolicyDrawerProps}
191
196
  />
192
197
  )}
@@ -1,5 +1,8 @@
1
1
  export { buyingPolicyDefault } from "./buyingPolicyDefault";
2
- export { orderFieldsCriteriaOptions } from "./orderFieldsCriteriaOptions";
2
+ export {
3
+ BUDGET_CRITERIA,
4
+ orderFieldsCriteriaOptions,
5
+ } from "./orderFieldsCriteriaOptions";
3
6
  export { spendingLimitsCriteriaOptions } from "./spendingLimitsCriteriaOptions";
4
7
  export {
5
8
  BUYING_POLICIES_WORKFLOW_TYPES,
@@ -1,39 +1,42 @@
1
+ export const BUDGET_CRITERIA =
2
+ '$exists(budgetData.unitAllocations.*[budgetId="${budget-id}"])';
3
+
1
4
  export const orderFieldsCriteriaOptions = [
2
5
  {
3
6
  label: "If the order contains a budget",
4
- criteria: "$count(budgetData.unitAllocations) > 0",
7
+ criteria: "$exists(budgetData.unitAllocations.*[])",
5
8
  },
6
9
  {
7
10
  label: "If the order contains the budgets X, Y, Z",
8
- criteria:
9
- 'budgetData.unitAllocations.budgetId = "Tech" or budgetData.unitAllocations.budgetId = "Growth"',
11
+ criteria: BUDGET_CRITERIA,
10
12
  },
11
13
  {
12
14
  label: "If the order contains an exceeded budget",
13
- criteria: "budgetData.unitAllocations.budgetBalance.remaining < 0",
15
+ criteria:
16
+ "$exists(budgetData.unitAllocations.**.budgetBalance[remaining < 0])",
14
17
  },
15
18
  {
16
19
  label: "If the order contains an expired budget Pending confirmation",
17
- criteria: "budgetData.unitAllocations.cycleConfiguration.endDate < now()",
20
+ criteria: "$exists(budgetData.unitAllocations.*[budgetEndDate < $now()])",
18
21
  },
19
22
  {
20
23
  label: "If the order contains a PO number",
21
- criteria: '$exists(customData.customFields.fields[name="poNumber"].value)',
24
+ criteria: '$exists(customData.customFields.fields[name="PO Number"].value)',
22
25
  },
23
26
  {
24
27
  label: "If the order contains the PO numbers X, Y, Z",
25
28
  criteria:
26
- 'customData.customFields.fields[name="poNumber"].value = "1112223334444" or customData.customFields.fields[name="poNumber"].value = "1234567890"',
29
+ 'customData.customFields.fields[name="PO Number"].value = "1112223334444" or customData.customFields.fields[name="PO Number"].value = "1234567890"',
27
30
  },
28
31
  {
29
32
  label: "If the order contains a cost center",
30
33
  criteria:
31
- '$exists(customData.customFields.fields[name="costCenter"].value)',
34
+ '$exists(customData.customFields.fields[name="Cost Center"].value)',
32
35
  },
33
36
  {
34
37
  label: "If the order contains the cost centers X, Y, Z",
35
38
  criteria:
36
- 'customData.customFields.fields[name="costCenter"].value = "CC1" or customData.customFields.fields[name="costCenter"].value = "CC2"',
39
+ 'customData.customFields.fields[name="Cost Center"].value = "CC1" or customData.customFields.fields[name="Cost Center"].value = "CC2"',
37
40
  },
38
41
  {
39
42
  label: "If all order items are negotiated items",
@@ -1,6 +1,5 @@
1
1
  import { BudgetsLayout } from "../features/budgets/layouts";
2
2
  import { listBudgetsService } from "../features/budgets/services";
3
- import { BudgetListResponse } from "../features/budgets/types";
4
3
  import { getContractDetailsService } from "../features/contracts/services";
5
4
  import { getOrgUnitBasicDataService } from "../features/org-units/services";
6
5
  import {
@@ -16,6 +15,7 @@ import {
16
15
  } from "../features/shared/utils";
17
16
  import { getUserByIdService } from "../features/users/services";
18
17
 
18
+ import type { BudgetListResponse } from "../features/budgets/types";
19
19
  import type { ContractData } from "../features/contracts/types";
20
20
  import type { OrgUnitBasicData } from "../features/org-units/types";
21
21
  import type { LoaderData } from "../features/shared/types";
@@ -1,3 +1,4 @@
1
+ import { listBudgetsService } from "../features/budgets/services";
1
2
  import { BuyingPoliciesLayout } from "../features/buying-policies/layouts";
2
3
  import { getBuyingPoliciesService } from "../features/buying-policies/services";
3
4
  import { getContractDetailsService } from "../features/contracts/services";
@@ -17,6 +18,7 @@ import {
17
18
  import { getUserByIdService } from "../features/users/services";
18
19
 
19
20
  import type { GetAddressesServiceProps } from "../features/addresses/services";
21
+ import type { BudgetListResponse } from "../features/budgets/types";
20
22
  import type { BuyingPolicy } from "../features/buying-policies/types";
21
23
  import type { ContractData } from "../features/contracts/types";
22
24
  import type { OrgUnitBasicData } from "../features/org-units/types";
@@ -34,6 +36,7 @@ export type BuyingPoliciesPageData = {
34
36
  currentOrgUnit: OrgUnitBasicData | null;
35
37
  currentUser: UserData | null;
36
38
  };
39
+ budgetData?: BudgetListResponse;
37
40
  hasError?: boolean;
38
41
  error?: ErrorBoundaryProps;
39
42
  };
@@ -54,7 +57,7 @@ const loaderFunction = async (
54
57
 
55
58
  const { cookie, userId, ...clientContext } = await getClientContext(data);
56
59
 
57
- const [currentOrgUnit, user, contract, buyingPoliciesResponse] =
60
+ const [currentOrgUnit, user, contract, budgetData, buyingPoliciesResponse] =
58
61
  await Promise.all([
59
62
  getOrgUnitBasicDataService({
60
63
  id: orgUnitId,
@@ -66,6 +69,13 @@ const loaderFunction = async (
66
69
  cookie,
67
70
  unitId: orgUnitId,
68
71
  }),
72
+
73
+ listBudgetsService({
74
+ customerId: clientContext.customerId,
75
+ cookie,
76
+ unitId: orgUnitId,
77
+ }),
78
+
69
79
  getBuyingPoliciesService({
70
80
  orgUnitId,
71
81
  contractId,
@@ -94,6 +104,7 @@ const loaderFunction = async (
94
104
  currentUser: user,
95
105
  currentContract: contract,
96
106
  },
107
+ budgetData: budgetData ?? { data: [], total: 0 },
97
108
  };
98
109
  };
99
110
 
@@ -110,6 +121,7 @@ const BuyingPoliciesPage = ({
110
121
  total,
111
122
  hasError,
112
123
  error,
124
+ budgetData = { data: [], total: 0 },
113
125
  }: BuyingPoliciesPageData) => (
114
126
  <BuyerPortalProvider {...context}>
115
127
  {hasError ? (
@@ -120,6 +132,7 @@ const BuyingPoliciesPage = ({
120
132
  search={search}
121
133
  page={page}
122
134
  total={total}
135
+ budgetData={budgetData}
123
136
  />
124
137
  )}
125
138
  </BuyerPortalProvider>