@vtex/faststore-plugin-buyer-portal 1.3.87 → 1.3.88
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/CHANGELOG.md +17 -0
- package/cypress/constants.ts +0 -8
- package/package.json +1 -1
- package/plugin.config.js +0 -12
- package/specs/deprecate-address-locations.md +497 -0
- package/specs/deprecate-custom-fields.md +473 -0
- package/src/features/addresses/components/AddressDropdownMenu/AddressDropdownMenu.tsx +1 -15
- package/src/features/addresses/components/CreateAddressDrawer/CreateAddressDrawer.tsx +4 -13
- package/src/features/addresses/components/CreateAddressDrawer/create-address-drawer.scss +0 -1
- package/src/features/addresses/components/CreateAddressSettingsDrawer/create-address-settings-drawer.scss +0 -1
- package/src/features/addresses/components/RemoveAddressDrawer/remove-address-drawer.scss +0 -1
- package/src/features/addresses/components/index.ts +0 -3
- package/src/features/addresses/hooks/index.ts +0 -4
- package/src/features/addresses/layouts/AddressDetailsLayout/AddressDetailsLayout.tsx +14 -55
- package/src/features/addresses/layouts/AddressDetailsLayout/address-details-layout.scss +0 -49
- package/src/features/addresses/layouts/AddressesLayout/addresses-layout.scss +0 -2
- package/src/features/addresses/services/default-values/get-default-address.service.ts +0 -1
- package/src/features/addresses/types/AddressData.ts +0 -50
- package/src/features/budgets/hooks/useGetAllocations.ts +1 -34
- package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/BasicBuyingPolicyDrawer.tsx +0 -43
- package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/basic-buying-policy-drawer.scss +0 -1
- package/src/features/buying-policies/utils/__tests__/orderFieldsCriteriaOptions.test.ts +41 -0
- package/src/features/buying-policies/utils/index.ts +0 -2
- package/src/features/buying-policies/utils/orderFieldsCriteriaOptions.ts +0 -21
- package/src/features/org-units/components/AddAllToOrgUnitDropdown/AddAllToOrgUnitDropdown.tsx +3 -49
- package/src/features/org-units/layouts/OrgUnitDetailsLayout/OrgUnitDetailsLayout.tsx +14 -2
- package/src/features/org-units/layouts/OrgUnitDetailsLayout/org-units-details.scss +1 -0
- package/src/features/shared/components/BasicDropdownMenu/basic-dropdown-menu.scss +5 -0
- package/src/features/shared/components/CustomFieldsDeprecationAlert/CustomFieldsDeprecationAlert.tsx +27 -0
- package/src/features/shared/components/CustomFieldsDeprecationAlert/custom-fields-deprecation-alert.scss +33 -0
- package/src/features/shared/components/Tab/TabOption.tsx +8 -1
- package/src/features/shared/components/Tab/tab.scss +5 -0
- package/src/features/shared/components/VerticalNav/VerticalNavLink.tsx +30 -4
- package/src/features/shared/components/VerticalNav/vertical-nav.scss +9 -0
- package/src/features/shared/components/index.ts +4 -0
- package/src/features/shared/hooks/usePageItems.ts +0 -2
- package/src/features/shared/layouts/BaseTabsLayout/SidebarMenu.tsx +9 -2
- package/src/features/shared/layouts/index.ts +0 -4
- package/src/features/shared/services/logger/analytics/constants.ts +0 -16
- package/src/features/shared/utils/__tests__/getContractSettingsLinks.test.ts +47 -0
- package/src/features/shared/utils/__tests__/getKeyByValue.test.ts +28 -0
- package/src/features/shared/utils/buyerPortalRoutes.ts +0 -9
- package/src/features/shared/utils/constants.ts +4 -3
- package/src/features/shared/utils/getContractSettingsLinks.ts +15 -4
- package/src/features/shared/utils/getKeyByValue.ts +0 -3
- package/src/features/shared/utils/routeLayoutMapping.ts +0 -16
- package/src/pages/address-details.tsx +1 -29
- package/src/themes/layouts.scss +0 -3
- package/cypress/integration/locations.test.ts +0 -196
- package/src/features/addresses/clients/LocationsClient.ts +0 -98
- package/src/features/addresses/components/AddressLocationsList/AddressLocationsList.tsx +0 -219
- package/src/features/addresses/components/DeleteAddressLocationDrawer/DeleteAddressLocationDrawer.tsx +0 -126
- package/src/features/addresses/components/DeleteAddressLocationDrawer/delete-address-location-drawer.scss +0 -20
- package/src/features/addresses/components/EditAddressLocationDrawer/EditAddressLocationDrawer.tsx +0 -151
- package/src/features/addresses/components/EditAddressLocationDrawer/edit-address-location-drawer.scss +0 -14
- package/src/features/addresses/components/LocationForm/LocationField/LocationField.tsx +0 -43
- package/src/features/addresses/components/LocationForm/LocationField/location-field.scss +0 -34
- package/src/features/addresses/components/LocationForm/LocationForm.tsx +0 -54
- package/src/features/addresses/components/LocationForm/location-form.scss +0 -41
- package/src/features/addresses/components/LocationsDrawer/LocationsDrawer.tsx +0 -146
- package/src/features/addresses/hooks/useAddLocationsToAddress.ts +0 -25
- package/src/features/addresses/hooks/useAddressLocationDelete.ts +0 -26
- package/src/features/addresses/hooks/useAddressLocationEdit.ts +0 -27
- package/src/features/addresses/hooks/useAddressLocationList.ts +0 -35
- package/src/features/addresses/services/locations/add-address-locations.service.ts +0 -6
- package/src/features/addresses/services/locations/delete-address-location.service.ts +0 -7
- package/src/features/addresses/services/locations/edit-address-location.service.ts +0 -6
- package/src/features/addresses/services/locations/get-address-locations.service.ts +0 -28
- package/src/features/buying-policies/components/CustomFieldCriteriaSelector/CustomFieldCriteriaSelector.tsx +0 -154
- package/src/features/buying-policies/components/CustomFieldCriteriaSelector/custom-field-criteria-selector.scss +0 -139
- package/src/features/custom-fields/components/CreateCustomFieldValueDrawer/CreateCustomFieldValueDrawer.tsx +0 -208
- package/src/features/custom-fields/components/CustomFieldSettingsDrawer/CustomFieldSettingsDrawer.tsx +0 -379
- package/src/features/custom-fields/components/DeleteCustomFieldValueDrawer/DeleteCustomFieldValueDrawer.tsx +0 -183
- package/src/features/custom-fields/components/UpdateCustomFieldValueDrawer/UpdateCustomFieldValueDrawer.tsx +0 -108
- package/src/features/custom-fields/components/index.ts +0 -4
- package/src/features/custom-fields/layouts/CustomFieldsLayout/CustomFieldsLayout.tsx +0 -325
- package/src/features/custom-fields/layouts/CustomFieldsLayout/custom-fields-layout.scss +0 -37
- package/src/features/custom-fields/layouts/index.ts +0 -1
- package/src/features/custom-fields/types/index.ts +0 -5
- package/src/features/shared/clients/CustomField.ts +0 -204
- package/src/features/shared/clients/DefaultValueClient.ts +0 -62
- package/src/features/shared/components/CustomField/create-custom-field/CreateCustomFieldDrawer.tsx +0 -155
- package/src/features/shared/components/CustomField/create-custom-field/create-custom-field-drawer.scss +0 -30
- package/src/features/shared/components/CustomField/delete-custom-field/DeleteCustomFieldDrawer.tsx +0 -127
- package/src/features/shared/components/CustomField/delete-custom-field/delete-custom-field-drawer.scss +0 -34
- package/src/features/shared/components/CustomField/index.ts +0 -6
- package/src/features/shared/components/CustomField/selected-card-item/CustomFieldSelectedCardItem.tsx +0 -31
- package/src/features/shared/components/CustomField/selected-card-item/custom-field-selected-card-item.scss +0 -53
- package/src/features/shared/components/CustomField/settings-drawer/CustomFieldSettingsDrawer.tsx +0 -159
- package/src/features/shared/components/CustomField/settings-drawer/custom-field-settings-drawer.scss +0 -98
- package/src/features/shared/components/CustomField/table/CustomFieldTable.tsx +0 -151
- package/src/features/shared/components/CustomField/table/custom-field-table.scss +0 -41
- package/src/features/shared/components/CustomField/update-custom-field/UpdateCustomFieldDrawer.tsx +0 -184
- package/src/features/shared/components/CustomField/update-custom-field/update-custom-field-drawer.scss +0 -46
- package/src/features/shared/hooks/custom-field/index.ts +0 -11
- package/src/features/shared/hooks/custom-field/useAddCustomFieldValueToScope.ts +0 -25
- package/src/features/shared/hooks/custom-field/useAddDefaultValue.ts +0 -25
- package/src/features/shared/hooks/custom-field/useCreateCustomFieldValue.ts +0 -25
- package/src/features/shared/hooks/custom-field/useCustomFieldSettings.ts +0 -18
- package/src/features/shared/hooks/custom-field/useDeleteCustomFieldValue.ts +0 -25
- package/src/features/shared/hooks/custom-field/useDeleteCustomFieldValueAndUpdateUnitScope.ts +0 -27
- package/src/features/shared/hooks/custom-field/useDeleteCustomFieldValueToScope.ts +0 -27
- package/src/features/shared/hooks/custom-field/useGetCustomFieldValues.ts +0 -20
- package/src/features/shared/hooks/custom-field/useGetDefaultValue.ts +0 -18
- package/src/features/shared/hooks/custom-field/useRemoveDefaultValue.ts +0 -25
- package/src/features/shared/hooks/custom-field/useUpdateCustomFieldSettings.ts +0 -27
- package/src/features/shared/hooks/custom-field/useUpdateCustomFieldValue.ts +0 -25
- package/src/features/shared/layouts/CustomFieldLayout/CustomFieldLayout.tsx +0 -108
- package/src/features/shared/layouts/CustomFieldLayout/custom-field-layout.scss +0 -67
- package/src/features/shared/services/custom-field/add-custom-field-value-to-scope.service.ts +0 -26
- package/src/features/shared/services/custom-field/add-default-value.service.ts +0 -27
- package/src/features/shared/services/custom-field/create-custom-field-value.service.ts +0 -26
- package/src/features/shared/services/custom-field/delete-custom-field-value-and-update-unit-scope.service.ts +0 -26
- package/src/features/shared/services/custom-field/delete-custom-field-value-to-unit-scope.service.ts +0 -26
- package/src/features/shared/services/custom-field/delete-custom-field-value.service.ts +0 -26
- package/src/features/shared/services/custom-field/get-custom-field-settings.service.ts +0 -22
- package/src/features/shared/services/custom-field/get-custom-fields-values.service.ts +0 -30
- package/src/features/shared/services/custom-field/get-default-value.service.ts +0 -20
- package/src/features/shared/services/custom-field/index.ts +0 -59
- package/src/features/shared/services/custom-field/remove-default-value.service.ts +0 -25
- package/src/features/shared/services/custom-field/update-custom-field-settings.service.ts +0 -28
- package/src/features/shared/services/custom-field/update-custom-field-value.service.ts +0 -34
- package/src/features/shared/types/CustomFields.ts +0 -6
- package/src/pages/cost-centers.tsx +0 -104
- package/src/pages/po-numbers.tsx +0 -98
- package/src/pages/releases.tsx +0 -98
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.3.88] - 2026-07-23
|
|
11
|
+
|
|
12
|
+
### Removed
|
|
13
|
+
|
|
14
|
+
- PO Numbers, Cost Centers, and Releases pages, routes, and every dedicated client/hook/service/component (the `custom-fields` feature and the shared `custom-field` building blocks) — the underlying BFF service is discontinued on 2026-07-30
|
|
15
|
+
- Address Locations client, hooks, services, and dedicated components/drawers, and the "Locations" tab from the "Add address" drawer (same discontinued BFF service)
|
|
16
|
+
- PO Number/Cost Center/Release as selectable allocation types in "Add budget allocations" and as criteria presets in "Set order field criteria" (existing budget allocations and buying policy criteria created before this change keep displaying normally)
|
|
17
|
+
- "Add cost center"/"Add PO number"/"Add release" shortcuts in the Org Unit "Add" dropdown (now disabled, no action)
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- A persistent deprecation alert on the Org Unit Details page, explaining that PO Numbers, Cost Centers, and Releases were replaced by Accounting Fields and pointing to the upgrade path (buyer-portal plugin `v2.0.1+`, FastStore `v4`)
|
|
22
|
+
- A persistent deprecation alert on the Address Details page, explaining that Address Locations was replaced by Accounting Fields and pointing to the same upgrade path
|
|
23
|
+
- Support for a disabled, tooltip-carrying state on `VerticalNav.Link`, used to keep the "PO numbers"/"Cost centers"/"Releases" navigation entries visible (but disabled) in the Org Unit Details cards and the Contract-settings sidebar
|
|
24
|
+
- Support for a disabled state on `TabOption`, used to keep the "Locations" tab visible (but disabled) on the Address Details page; the "Add Locations" shortcut in the address actions dropdown is disabled the same way
|
|
25
|
+
|
|
10
26
|
## [1.3.87] - 2026-05-21
|
|
11
27
|
|
|
12
28
|
### Fixed
|
|
@@ -731,5 +747,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
731
747
|
[1.3.70]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.69...v1.3.70
|
|
732
748
|
[1.3.85]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.3.85
|
|
733
749
|
|
|
750
|
+
[1.3.88]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.87...v1.3.88
|
|
734
751
|
[1.3.87]: https://github.com/vtex/faststore-plugin-buyer-portal/compare/v1.3.86...v1.3.87
|
|
735
752
|
[1.3.86]: https://github.com/vtex/faststore-plugin-buyer-portal/releases/tag/1.3.86
|
package/cypress/constants.ts
CHANGED
|
@@ -89,14 +89,6 @@ export const TEST_DATA = {
|
|
|
89
89
|
NEW_ADDRESS_STATE: "RJ",
|
|
90
90
|
NEW_ADDRESS_POSTAL_CODE: "22250-905",
|
|
91
91
|
},
|
|
92
|
-
LOCATIONS: {
|
|
93
|
-
LOCATION_ADDRESS_NAME: "LOCATIONS",
|
|
94
|
-
FIRST_LOCATION: "Location 1",
|
|
95
|
-
SECOND_LOCATION: "Location 2",
|
|
96
|
-
THIRD_LOCATION: "Location 3",
|
|
97
|
-
FOURTH_LOCATION: "Location 4",
|
|
98
|
-
EDITED_LOCATION: "Edited Location",
|
|
99
|
-
},
|
|
100
92
|
RECIPIENTS: {
|
|
101
93
|
RECIPIENTS_ADDRESS_NAME: "RECIPIENTS",
|
|
102
94
|
FIRST_RECIPIENT_NAME: "First Recipient",
|
package/package.json
CHANGED
package/plugin.config.js
CHANGED
|
@@ -40,18 +40,6 @@ module.exports = {
|
|
|
40
40
|
path: "/pvt/organization-account/product-assortment/[orgUnitId]/[contractId]",
|
|
41
41
|
appLayout: false,
|
|
42
42
|
},
|
|
43
|
-
"po-numbers": {
|
|
44
|
-
path: "/pvt/organization-account/po-numbers/[orgUnitId]/[contractId]",
|
|
45
|
-
appLayout: false,
|
|
46
|
-
},
|
|
47
|
-
"cost-centers": {
|
|
48
|
-
path: "/pvt/organization-account/cost-centers/[orgUnitId]/[contractId]",
|
|
49
|
-
appLayout: false,
|
|
50
|
-
},
|
|
51
|
-
releases: {
|
|
52
|
-
path: "/pvt/organization-account/releases/[orgUnitId]/[contractId]",
|
|
53
|
-
appLayout: false,
|
|
54
|
-
},
|
|
55
43
|
roles: {
|
|
56
44
|
path: "/pvt/organization-account/roles/[orgUnitId]",
|
|
57
45
|
appLayout: false,
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
# Deprecate Address Locations (Custom Field)
|
|
2
|
+
|
|
3
|
+
> **Status**: Done
|
|
4
|
+
> **Created**: 2026-07-23
|
|
5
|
+
> **Updated**: 2026-07-23 — implemented via `/implementing` (all 10 implementation-plan steps landed as commits on PR [#409](https://github.com/vtex/faststore-plugin-buyer-portal/pull/409)); Decision 9 (the `TabOption` unit test) was reverted post-implementation — see Decision 9
|
|
6
|
+
> **Branch**: `feat/deprecate-custom-fields` (continues the work started in `specs/deprecate-custom-fields.md`; no separate branch — this spec, and its implementation, land as additional commits on the same open PR [#409](https://github.com/vtex/faststore-plugin-buyer-portal/pull/409), which had no review/approval yet at the time of this decision, and folds into the still-unpublished `1.3.88` release — confirmed via `npm view` that `1.3.88` has not been published yet, the latest on the `1.3.x` line is `1.3.87`)
|
|
7
|
+
|
|
8
|
+
## 1. Business Context
|
|
9
|
+
|
|
10
|
+
### Problem Statement
|
|
11
|
+
|
|
12
|
+
`specs/deprecate-custom-fields.md` covered PO Numbers, Cost Centers, and Releases — three standalone custom-field pages. **Address Locations is the same underlying custom field type (`Location`)**, but surfaced differently: as a tab inside the Address Details page and inside the "Add address" / "Add Locations" drawers, not as a dedicated page. The BFF's retirement of the custom-fields API on **2026-07-30** (confirmed 2026-07-22, see the prior spec) covers this endpoint too — `LocationsClient` calls the same `custom-fields/location/values` routes that are being discontinued.
|
|
13
|
+
|
|
14
|
+
This means the `addresses` feature has its own, self-contained slice of now-obsolete code: a client, four hooks, four services, and half a dozen components/drawers dedicated to creating, listing, editing, and deleting "locations" attached to an address. Unlike PO Numbers/Cost Centers/Releases, this slice has no dedicated route/page of its own — it is embedded inside `AddressDetailsLayout` (a tab) and `CreateAddressDrawer` (a tab), plus a quick-add shortcut in `AddressDropdownMenu`.
|
|
15
|
+
|
|
16
|
+
Following the same pattern already established for the other three custom fields:
|
|
17
|
+
|
|
18
|
+
- Every piece of code that exists solely to support Locations (client, hooks, services, drawers, components) is removed.
|
|
19
|
+
- The "Locations" **tab** in `CreateAddressDrawer` is removed entirely (drawer keeps only "Details" and "Recipients").
|
|
20
|
+
- The "Locations" **tab** in `AddressDetailsLayout` stays visible, but disabled (matches the "keep the entry visible, don't let it vanish silently" decision from the prior spec) — no tooltip needed here, since a new persistent alert on the same page already explains the deprecation.
|
|
21
|
+
- The "Add Locations" quick-add shortcut in `AddressDropdownMenu` stays visible, but disabled (same native-`disabled` pattern used for the Org Units quick-add shortcuts in the prior spec).
|
|
22
|
+
- The existing `CustomFieldsDeprecationAlert` component is generalized (accepts its message as `children` instead of hardcoded copy) and reused here with Locations-specific copy — and relocated to `shared/components/` since it now has two feature consumers (`org-units` and `addresses`), which the project's plugin boundary/domain rules require ("No domain may import directly from another domain").
|
|
23
|
+
|
|
24
|
+
### Goals
|
|
25
|
+
|
|
26
|
+
- Remove the entire Locations custom-field slice from `addresses`: `LocationsClient`, its 4 hooks, its 4 services, and every component/drawer that exists only to support it.
|
|
27
|
+
- Remove the "Locations" tab from `CreateAddressDrawer` (Details + Recipients only).
|
|
28
|
+
- Keep the "Locations" tab visible but disabled in `AddressDetailsLayout`, and stop fetching location data in the page loader.
|
|
29
|
+
- Keep the "Add Locations" shortcut visible but disabled in `AddressDropdownMenu`.
|
|
30
|
+
- Show a persistent deprecation alert on the Address Details page, reusing the generalized `CustomFieldsDeprecationAlert`.
|
|
31
|
+
- Preserve everything shared with Address Recipients untouched (generic list/table/drawer building blocks in `shared/components`, `RecipientsForm`/`RecipientItem`, recipients hooks/services/client).
|
|
32
|
+
- Ship in the same release as `specs/deprecate-custom-fields.md` (still targets the `1.3.x` line, still before 2026-07-30) — no separate version bump; folded into the same patch.
|
|
33
|
+
|
|
34
|
+
### User Stories
|
|
35
|
+
|
|
36
|
+
#### US-1: The Locations client/hooks/services/components are removed
|
|
37
|
+
|
|
38
|
+
- **Story**: As a maintainer, I want `LocationsClient`, its hooks, services, and every dedicated component/drawer removed, since the BFF will no longer serve any of their requests after 2026-07-30.
|
|
39
|
+
- **Acceptance Criteria**:
|
|
40
|
+
- **Given** the codebase after this change, **when** I search for `LocationsClient`, `useAddLocationsToAddress`, `useAddressLocationList`, `useAddressLocationEdit`, `useAddressLocationDelete`, `AddressLocationsList`, `LocationForm`, `LocationField`, `LocationDrawer`/`LocationsDrawer`, `EditAddressLocationDrawer`, or `DeleteAddressLocationDrawer`, **then** none of them exist anymore.
|
|
41
|
+
- **Given** the same search, **when** I look at `RecipientsForm`, `RecipientItem`, `AddressRecipientsList`, and their hooks/services/client, **then** all of them are untouched and still work exactly as before.
|
|
42
|
+
|
|
43
|
+
#### US-2: "Add address" drawer no longer has a Locations tab
|
|
44
|
+
|
|
45
|
+
- **Story**: As a contract administrator, I want the "Add address" drawer to only show "Details" and "Recipients", since adding locations during address creation is no longer possible.
|
|
46
|
+
- **Acceptance Criteria**:
|
|
47
|
+
- **Given** I open "Add address", **when** the drawer renders, **then** the tab bar shows only "Details" and "Recipients" — no "Locations" tab.
|
|
48
|
+
- **Given** I fill in the address details and confirm, **when** the address is created, **then** it succeeds exactly as before (creation never actually sent `locations` to the BFF — confirmed dead field on the create-address payload).
|
|
49
|
+
|
|
50
|
+
#### US-3: Address Details keeps the Locations tab visible, but disabled, with a page-level deprecation alert
|
|
51
|
+
|
|
52
|
+
- **Story**: As a contract administrator, I want to still see a "Locations" tab on an address's details page, but visibly disabled, and a clear message explaining that Address Locations were replaced by Accounting Fields and discontinued on 2026-07-30.
|
|
53
|
+
- **Acceptance Criteria**:
|
|
54
|
+
- **Given** I open an address's details page, **when** I look at the tab bar, **then** "Details" and "Recipients" work normally, and "Locations" appears visually disabled (greyed out, not clickable).
|
|
55
|
+
- **Given** I click the disabled "Locations" tab, **when** nothing happens, **then** the active tab does not change.
|
|
56
|
+
- **Given** I navigate directly to the address details page with `?tab=location-tab` in the URL (a link from before this change, or a stale bookmark), **when** the page loads, **then** it falls back to the "Details" tab instead of erroring or trying to render removed components.
|
|
57
|
+
- **Given** I open the page, **when** it renders, **then** a deprecation alert is visible (no dismiss control), stating Address Locations was replaced by Accounting Fields and discontinued on 2026-07-30, with the upgrade path.
|
|
58
|
+
|
|
59
|
+
#### US-4: The "Add Locations" quick-add shortcut is disabled
|
|
60
|
+
|
|
61
|
+
- **Story**: As a contract administrator, I want the "Add Locations" item in an address's actions dropdown to be visibly disabled, so there is no remaining path to create location values.
|
|
62
|
+
- **Acceptance Criteria**:
|
|
63
|
+
- **Given** I open an address's actions dropdown, **when** the menu renders, **then** "Add Locations" appears visually disabled and produces no action on click.
|
|
64
|
+
- **Given** the same dropdown, **when** I look at unrelated items ("Edit details", "Add Recipients", "Remove address", "Delete address"), **then** they remain fully functional.
|
|
65
|
+
|
|
66
|
+
### Key Scenarios
|
|
67
|
+
|
|
68
|
+
| Scenario | Pre-conditions | Steps | Expected Result |
|
|
69
|
+
|---|---|---|---|
|
|
70
|
+
| Happy path — Address Details with disabled Locations tab | Any existing address | Open the address's details page | "Locations" tab renders disabled; "Details"/"Recipients" work normally; deprecation alert visible |
|
|
71
|
+
| Happy path — Create address without Locations | — | Open "Add address", fill Details, go to Recipients, confirm | Address created successfully; no Locations tab was ever shown |
|
|
72
|
+
| Error case — stale deep link to the removed tab | Any existing address | Visit `.../address-details?...&tab=location-tab` directly | Page falls back to the "Details" tab; no crash, no attempt to fetch/render removed location data |
|
|
73
|
+
| Edge case — address created before this change with existing location values | Address has locations attached via the (now-discontinued) BFF endpoint | Open its details page | Page renders normally (no listing call is made anymore); the disabled "Locations" tab and the alert are the only trace of the feature — no data loss, just no more UI to browse/manage it |
|
|
74
|
+
|
|
75
|
+
### Functional Requirements
|
|
76
|
+
|
|
77
|
+
- FR-1: Delete `src/features/addresses/clients/LocationsClient.ts`.
|
|
78
|
+
- FR-2: Delete `src/features/addresses/services/locations/**` (`get-address-locations.service.ts`, `add-address-locations.service.ts`, `edit-address-location.service.ts`, `delete-address-location.service.ts`).
|
|
79
|
+
- FR-3: Delete `src/features/addresses/hooks/useAddLocationsToAddress.ts`, `useAddressLocationList.ts`, `useAddressLocationEdit.ts`, `useAddressLocationDelete.ts`, and their exports from `hooks/index.ts`.
|
|
80
|
+
- FR-4: Delete `src/features/addresses/components/LocationsDrawer/**`, `LocationForm/**` (including `LocationField/**`), `AddressLocationsList/**`, `EditAddressLocationDrawer/**`, `DeleteAddressLocationDrawer/**`, and their exports from `components/index.ts`.
|
|
81
|
+
- FR-5: `CreateAddressDrawer.tsx` must remove the "Locations" `TabOption`/`TabContent`, the `locations` state, and the `LocationForm` import/usage. The `locations_count` field in its analytics payload (`address_creation` event) is kept, now hardcoded to `0`, to avoid changing the shape of an existing analytics event for any downstream consumer.
|
|
82
|
+
- FR-6: `TabOption` (`src/features/shared/components/Tab/TabOption.tsx`) must support an optional `disabled` prop; when set, render a native `disabled` `<button>` (no click handler fires, `aria-disabled`, standard disabled styling) instead of the normal clickable option.
|
|
83
|
+
- FR-7: `AddressDetailsLayout.tsx` must keep a "Locations" `TabOption` in the tab bar, marked `disabled`, and reordered to the end (`Details`, `Recipients`, `Locations`) so the two functional tabs stay adjacent and the deprecated one is visually isolated. `"location-tab"` is removed from the set of valid `activeTabId` values (both the initial-state derivation and the query-param sync effect) so a stale `?tab=location-tab` falls back to `"address-tab"`.
|
|
84
|
+
- FR-8: `AddressDetailsLayout.tsx` must remove the `locationsData` prop, the `AddressLocationsList`/`LocationDrawer` imports and their wiring (`openLocationsDrawer`, `isOpenLocationsDrawer`, `addressLocationsListRef`), the `"location-tab"` branch of `renderActionButton`, and the `<TabContent id="location-tab">` block.
|
|
85
|
+
- FR-9: `AddressDetailsLayout.tsx` must render the generalized `CustomFieldsDeprecationAlert` (Locations-specific copy) once, near the top of the page (after `HeaderInside`, before the tab bar / info wrapper).
|
|
86
|
+
- FR-10: `AddressDropdownMenu.tsx` must remove its `LocationDrawer` import and wiring (`openLocationDrawer`, `isOpenLocationDrawer`), and set the native `disabled` prop on the "Add Locations" `DropdownItem` (no `onClick`). Its position in the dropdown stays unchanged (between "Edit details" and "Add Recipients") — unlike the tab bar, a dropdown menu doesn't warrant reordering a single disabled item.
|
|
87
|
+
- FR-11: `src/pages/address-details.tsx` (loader) must stop calling `getAddressLocationService`, drop `locationsData`/`LocationsPageData` from `AddressDetailsPageData`, drop the `searchLocations`/`pageLocations` query fields, and stop passing `locationsData` to `AddressDetailsLayout`.
|
|
88
|
+
- FR-12: `usePageItems.ts` (`src/features/shared/hooks/`) must drop the now-unused `LOCATIONS` entries from the `SEARCH_PARAMS`/`PAGE_PARAMS` enums (no remaining consumer once `AddressLocationsList` is gone).
|
|
89
|
+
- FR-13: `AddressData.ts` (`src/features/addresses/types/`) must drop the Locations-only types (`LocationData`, `LocationResponse`, `LocationParams`, `LocationCreatedResponse`, `ListLocationsParams`, `LocationInput`, `ApiLocationBaseParams`, `LocationsPageData`, `AddLocationsParams`, `EditDeleteLocationParams`) and the dead `locations` field from `AddressData`/`AddressInput` (never sent to, or read from, the address create/edit/list endpoints — confirmed unused outside the removed Locations slice).
|
|
90
|
+
- FR-14: `CustomFieldsDeprecationAlert` must be generalized to accept its message via `children` (instead of hardcoded PO Numbers/Cost Centers/Releases copy) and moved to `src/features/shared/components/CustomFieldsDeprecationAlert/` (+ its `.scss`), since it now has two feature consumers (`org-units`, `addresses`) and cross-domain imports are not allowed by this project's conventions. `OrgUnitsDetailsLayout` is updated to import it from `shared` and pass its existing copy as `children`.
|
|
91
|
+
- FR-15: `AddressDetailsLayout.tsx` renders `CustomFieldsDeprecationAlert` with Address-Locations-specific copy: replaced by Accounting Fields, discontinued 2026-07-30, upgrade path to plugin `v2.0.1+` / FastStore `v4`.
|
|
92
|
+
- FR-16: Remove the now-orphaned `[data-fs-address-details-locations]` / `[data-fs-address-details-location]` dead CSS block and the `&[data-fs-bp-address-location-list]` selector from `address-details-layout.scss` (no longer referenced by any component after FR-4).
|
|
93
|
+
- FR-17: Remove `LOCAL_STORAGE_LOCATION_EDIT_KEY` from `shared/utils/constants.ts` (only consumer was the removed `EditAddressLocationDrawer`).
|
|
94
|
+
- FR-18: Delete the now-orphaned Cypress spec `cypress/integration/locations.test.ts` and the `TEST_DATA.LOCATIONS` block in `cypress/constants.ts`.
|
|
95
|
+
- FR-19: Existing addresses that already have location values (created via the discontinued endpoint before 2026-07-30) must not error or lose data — there is simply no more UI to browse/manage them (see US-3, edge case).
|
|
96
|
+
|
|
97
|
+
### Non-Functional Requirements
|
|
98
|
+
|
|
99
|
+
- No feature flag — same rationale as the prior spec: fixed deadline (2026-07-30), targets a specific version line.
|
|
100
|
+
- Pass `make lint`, `make typecheck`, and `make test`.
|
|
101
|
+
- `TabOption`'s new `disabled` behavior ships without an automated unit test (see Decision 9) — verified manually instead, to avoid introducing a component-rendering test toolchain (`react-test-renderer`, `@types/react-test-renderer`, and a `@types/react` `resolutions` pin) for a single test file.
|
|
102
|
+
- Folded into the same `1.3.88` release as `specs/deprecate-custom-fields.md` — no additional version bump; the `CHANGELOG.md` entry for `1.3.88` is extended to mention Address Locations alongside PO Numbers/Cost Centers/Releases.
|
|
103
|
+
- The BFF team's 2026-07-22 confirmation (entire custom-fields API retired on 2026-07-30) already covers the `Location` custom field — no separate confirmation needed.
|
|
104
|
+
|
|
105
|
+
### Out of Scope
|
|
106
|
+
|
|
107
|
+
- Any change to the BFF/API.
|
|
108
|
+
- The Accounting Fields feature itself (not backported to this version line).
|
|
109
|
+
- A FeatureHub feature flag.
|
|
110
|
+
- Localization of the new alert copy.
|
|
111
|
+
- Any change to `main` (`v2.0.x`).
|
|
112
|
+
- Data migration or cleanup of existing address location values created via the discontinued endpoint.
|
|
113
|
+
- New Cypress/E2E coverage (removing the orphaned Cypress spec is in scope; adding new Cypress coverage is not).
|
|
114
|
+
- Automated unit test coverage for `TabOption`'s new `disabled` behavior (see Decision 9 — reverted after implementation to avoid a component-testing toolchain for a single test file).
|
|
115
|
+
- Renaming `CustomFieldsDeprecationAlert` — kept as-is (Address Locations is itself a custom field, so the name still fits), only its location and props change.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 2. Arch Decisions
|
|
120
|
+
|
|
121
|
+
### Proposed Solution
|
|
122
|
+
|
|
123
|
+
Mirror the approach already accepted in `specs/deprecate-custom-fields.md`: delete every piece of code that exists solely to support Address Locations (client, hooks, services, drawers, components), remove the Locations tab from the creation flow entirely (no more room to create new location values anywhere), and keep the two remaining "entry points" that historically pointed at this feature — the Address Details tab and the dropdown quick-add shortcut — visible but disabled, consistent with how the prior spec treated navigation entries and quick-add shortcuts. Generalize and relocate `CustomFieldsDeprecationAlert` to `shared/components/` so both `org-units` and `addresses` can render it with their own copy, respecting the project's "no cross-domain imports" rule.
|
|
124
|
+
|
|
125
|
+
### Architecture Overview
|
|
126
|
+
|
|
127
|
+
```mermaid
|
|
128
|
+
flowchart TB
|
|
129
|
+
subgraph removed [Removed entirely]
|
|
130
|
+
Client["LocationsClient"]
|
|
131
|
+
Hooks["useAddLocationsToAddress, useAddressLocationList,\nuseAddressLocationEdit, useAddressLocationDelete"]
|
|
132
|
+
Services["services/locations/**"]
|
|
133
|
+
Components["LocationsDrawer, LocationForm, LocationField,\nAddressLocationsList, EditAddressLocationDrawer,\nDeleteAddressLocationDrawer"]
|
|
134
|
+
Types["Location*, ListLocationsParams, AddLocationsParams, etc."]
|
|
135
|
+
E2E["cypress/integration/locations.test.ts"]
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
subgraph createFlow ["CreateAddressDrawer — tab removed"]
|
|
139
|
+
CAD[CreateAddressDrawer]
|
|
140
|
+
CAD -->|Details, Recipients only| Tabs1["Tab / TabBar / TabContent"]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
subgraph detailsFlow ["AddressDetailsLayout — tab disabled"]
|
|
144
|
+
TO["TabOption\n(+ disabled support)"]
|
|
145
|
+
ADL[AddressDetailsLayout]
|
|
146
|
+
Loader["address-details.tsx loader\n(stops fetching locationsData)"]
|
|
147
|
+
ADL --> TO
|
|
148
|
+
Loader --> ADL
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
subgraph dropdown ["AddressDropdownMenu — shortcut disabled"]
|
|
152
|
+
ADM[AddressDropdownMenu]
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
subgraph alert ["Generalized alert, moved to shared/"]
|
|
156
|
+
CFA["shared/components/CustomFieldsDeprecationAlert\n(children-driven copy)"]
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
ADL --> CFA
|
|
160
|
+
OUDL[OrgUnitsDetailsLayout] --> CFA
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Root Cause / Context Analysis
|
|
164
|
+
|
|
165
|
+
| Aspect | Current state | Why it must change |
|
|
166
|
+
|---|---|---|
|
|
167
|
+
| `LocationsClient` | Calls `customers/{contractId}/units/{unitId}/custom-fields/location/values` | Same retiring endpoint family as PO Number/Cost Center/Release — confirmed by BFF |
|
|
168
|
+
| "Locations" tab in `CreateAddressDrawer` | Fully functional; lets users add locations while creating an address | The underlying "add locations" call will fail after 2026-07-30; the field it collects (`locations`) is not even sent by `createNewAddressService`/`AddressesClient.createNewAddress` today — already effectively dead on the create path |
|
|
169
|
+
| "Locations" tab in `AddressDetailsLayout` | Lists, adds, edits, deletes location values for an existing address | Same retiring endpoint; per the established pattern, the entry stays visible-but-disabled rather than vanishing |
|
|
170
|
+
| `AddressDropdownMenu` "Add Locations" shortcut | Opens `LocationDrawer` to add locations to an existing address | Same retiring endpoint; matches how the prior spec disabled Org Units' quick-add shortcuts |
|
|
171
|
+
| `CustomFieldsDeprecationAlert` | Lives in `org-units/components`, hardcoded PO Numbers/Cost Centers/Releases copy | `addresses` needs the same alert with different copy; per this project's Feature-per-Domain principle ("No domain may import directly from another domain"), it must move to `shared/components/` to be a legal import for both |
|
|
172
|
+
|
|
173
|
+
### Alternatives Considered
|
|
174
|
+
|
|
175
|
+
| Alternative | Pros | Cons | Verdict |
|
|
176
|
+
|---|---|---|---|
|
|
177
|
+
| A. Disable the Locations tab's content in place, but keep `AddressLocationsList`/drawers as dead code behind the disabled tab | Smaller diff | Dead code calling a retiring endpoint if ever re-enabled by mistake; contradicts the "delete, don't disable" precedent for CRUD/listing code from the prior spec | Rejected |
|
|
178
|
+
| B. Remove the Locations tab entirely from `AddressDetailsLayout` (not just disable it) | Simplest | User explicitly wants the entry to stay visible so it doesn't look like it "vanished"; also breaks the parallel with how PO Numbers/Cost Centers/Releases nav entries were handled | Rejected |
|
|
179
|
+
| C. Keep `CustomFieldsDeprecationAlert` in `org-units` and let `addresses` import it directly | No file move needed | Violates the project's Feature-per-Domain rule (no direct cross-domain imports); `shared/` is the sanctioned way to share a component between two domains | Rejected |
|
|
180
|
+
| D. Generalize + relocate `CustomFieldsDeprecationAlert` to `shared/components/` (this version) | Respects domain boundaries; single implementation, two copies of content | One extra file move + import update in `org-units` | **Accepted** |
|
|
181
|
+
| E. Add a tooltip to the disabled "Locations" `TabOption`, matching `VerticalNavLink` | Consistent with the nav-link pattern | Redundant — the page already shows a persistent, more detailed alert; per user decision, adds UI noise for no benefit here | Rejected (user decision) |
|
|
182
|
+
|
|
183
|
+
### Risks & Mitigations
|
|
184
|
+
|
|
185
|
+
| Risk | Impact | Likelihood | Mitigation |
|
|
186
|
+
|---|---|---|---|
|
|
187
|
+
| Addresses with pre-existing location values break when their details page is opened | Med | Low | The page no longer calls any location-listing endpoint at all — nothing left to fail; confirmed no other code reads `AddressData.locations` |
|
|
188
|
+
| Relocating `CustomFieldsDeprecationAlert` breaks the existing `OrgUnitsDetailsLayout` usage | Med | Low | Update its import path and pass the exact same copy as `children`; no visual/behavioral change expected there |
|
|
189
|
+
| `TabOption`'s new `disabled` prop breaks `CreateAddressDrawer`'s usage (its only other consumer) | Low | Low | `disabled` is optional, defaults to `false`/unset; `CreateAddressDrawer` doesn't pass it and is otherwise only losing its Locations tab, not touching `TabOption` itself |
|
|
190
|
+
| Stale bookmarks/links with `?tab=location-tab` break | Low | Low | `AddressDetailsLayout`'s existing "invalid tab falls back to `address-tab`" logic is extended to treat `location-tab` as invalid (FR-7) |
|
|
191
|
+
| Removing `usePageItems`'s `LOCATIONS` enum entries breaks another consumer | Med | Low | Verified via full-repo search: only `AddressLocationsList` (removed) and `address-details.tsx` (updated) reference them |
|
|
192
|
+
|
|
193
|
+
### Key Decisions
|
|
194
|
+
|
|
195
|
+
#### Decision 1: No tooltip on the disabled "Locations" tab — the page alert is enough
|
|
196
|
+
|
|
197
|
+
- **Status**: Accepted (user decision)
|
|
198
|
+
- **Context**: The prior spec added tooltips to disabled nav links because there was no other explanation on those pages. Here, a persistent alert is added to the same page as the disabled tab.
|
|
199
|
+
- **Decision**: `TabOption`'s `disabled` state is purely visual (greyed out, `aria-disabled`, no click) — no `Tooltip` wrapper.
|
|
200
|
+
- **Consequences**: Simpler `TabOption` implementation; no risk of repeating the clipping/positioning issues seen with `Tooltip` in narrow containers.
|
|
201
|
+
|
|
202
|
+
#### Decision 2: Stale `?tab=location-tab` deep links fall back to "Details"
|
|
203
|
+
|
|
204
|
+
- **Status**: Accepted (user decision)
|
|
205
|
+
- **Context**: `AddressDetailsLayout` already has fallback logic for unrecognized tab query params.
|
|
206
|
+
- **Decision**: Remove `"location-tab"` from the `AddressDetailTabId`/`validTabs` list used by that fallback logic, so it's treated exactly like any other invalid value.
|
|
207
|
+
- **Consequences**: No special-casing needed; reuses existing, already-tested logic.
|
|
208
|
+
|
|
209
|
+
#### Decision 3: "Add Locations" shortcut disabled, not removed
|
|
210
|
+
|
|
211
|
+
- **Status**: Accepted (user decision)
|
|
212
|
+
- **Context**: Matches the pattern used for the Org Units quick-add shortcuts in the prior spec (native `disabled`, no `onClick`), for consistency across the app.
|
|
213
|
+
- **Decision**: Keep the `DropdownItem` in `AddressDropdownMenu`, set its native `disabled` prop, drop `onClick` and the `LocationDrawer` wiring.
|
|
214
|
+
- **Consequences**: One less special case to remember; consistent visual language for "deprecated action" everywhere in the app.
|
|
215
|
+
|
|
216
|
+
#### Decision 4: Generalize and relocate `CustomFieldsDeprecationAlert` to `shared/components/`
|
|
217
|
+
|
|
218
|
+
- **Status**: Accepted
|
|
219
|
+
- **Context**: The component currently lives in `org-units/components` with hardcoded copy. `addresses` needs the same visual treatment with different copy. This project's Feature-per-Domain principle forbids direct cross-domain imports (`org-units` → `addresses` or vice versa); `shared/` is the sanctioned path.
|
|
220
|
+
- **Decision**: Move `CustomFieldsDeprecationAlert.tsx` (+ `.scss`) to `src/features/shared/components/CustomFieldsDeprecationAlert/`, change it to accept `children: ReactNode` for the message instead of hardcoding it, export it from `shared/components/index.ts`, and update `OrgUnitsDetailsLayout` to import it from `shared` and pass its existing copy as `children`. `AddressDetailsLayout` imports the same component from `shared` with its own copy.
|
|
221
|
+
- **Consequences**: Single implementation (icon, alert styling, non-dismissible behavior) shared by both usages; each usage owns its own copy.
|
|
222
|
+
|
|
223
|
+
#### Decision 5: Locations-only types and the dead `locations` field are removed, not just the client/hooks
|
|
224
|
+
|
|
225
|
+
- **Status**: Accepted
|
|
226
|
+
- **Context**: `AddressData.locations`/`AddressInput.locations` are never read or sent anywhere outside the removed Locations slice (confirmed via full-repo search — `AddressesClient.createNewAddress`/`editAddress` build an explicit field allowlist that never includes `locations`).
|
|
227
|
+
- **Decision**: Remove the Locations-only types from `AddressData.ts` and drop the `locations` field from `AddressData`/`AddressInput`.
|
|
228
|
+
- **Consequences**: Slightly smaller, more accurate type surface; no behavior change (the field was already write-only/dead).
|
|
229
|
+
|
|
230
|
+
#### Decision 6: Implementation lands on the same open PR #409, no separate PR/branch
|
|
231
|
+
|
|
232
|
+
- **Status**: Accepted (user decision, `/grill-me` round)
|
|
233
|
+
- **Context**: PR #409 (branch `feat/deprecate-custom-fields`) was still `OPEN` with no `reviewDecision` at the time of this decision — i.e., unreviewed. Both specs also target the same still-unpublished `1.3.88` release (confirmed via `npm view`: latest published on `1.3.x` is `1.3.87`).
|
|
234
|
+
- **Decision**: Implement this spec as additional commits on top of PR #409, rather than waiting for it to merge and opening a new PR.
|
|
235
|
+
- **Consequences**: One consolidated PR/release for all custom-field deprecations; if #409 review drags on, this feature's rollout is coupled to it. Re-evaluate if #409 gets approved/merged before this spec is implemented.
|
|
236
|
+
|
|
237
|
+
#### Decision 7: The disabled "Locations" tab moves to the end of the tab bar
|
|
238
|
+
|
|
239
|
+
- **Status**: Accepted (user decision, `/grill-me` round)
|
|
240
|
+
- **Context**: Current order is Details, Locations, Recipients. Disabling in place would leave a non-interactive tab between two functional ones.
|
|
241
|
+
- **Decision**: Reorder to Details, Recipients, Locations (disabled) in `AddressDetailsLayout.tsx`. The "Add Locations" `DropdownItem` in `AddressDropdownMenu`, by contrast, keeps its current position — a dropdown doesn't carry the same "adjacent functional tabs" concern as a persistent tab bar.
|
|
242
|
+
- **Consequences**: `AddressDetailTabId`/`validTabs` order is cosmetic only (doesn't affect fallback logic); only the JSX order of `<TabOption>` elements changes.
|
|
243
|
+
|
|
244
|
+
#### Decision 8: `locations_count` analytics field is kept, hardcoded to `0`, not removed
|
|
245
|
+
|
|
246
|
+
- **Status**: Accepted (user decision, `/grill-me` round)
|
|
247
|
+
- **Context**: `CreateAddressDrawer`'s `address_creation` analytics event includes `locations_count`, computed from the `locations` state being removed. No downstream analytics consumer of this field could be verified from the codebase alone.
|
|
248
|
+
- **Decision**: Keep the field in the event payload, hardcoded to `0`, instead of removing it from the event shape.
|
|
249
|
+
- **Consequences**: Downstream dashboards/queries expecting this field keep working unchanged; the field becomes permanently `0` going forward (acceptable, since it always reflects "no locations creatable here anymore").
|
|
250
|
+
|
|
251
|
+
#### Decision 9: Add one unit test for `TabOption`'s new `disabled` behavior — later reverted
|
|
252
|
+
|
|
253
|
+
- **Status**: Superseded (user decision, post-implementation)
|
|
254
|
+
- **Context**: The `addresses` feature has zero existing unit tests, which could justify skipping tests for consistency. However, `TabOption.disabled` is new logic (not a removal), and the project's constitution requires new features/logic to ship with at least one unit test. This was implemented (`TabOption.test.tsx`, using `react-test-renderer`), but pulled in `react-test-renderer`, `@types/react-test-renderer`, a `resolutions` pin for `@types/react` (needed to resolve a duplicate-`@types/react` typecheck conflict introduced by `@types/react-test-renderer`), and an `esbuild.jsx: "automatic"` change to `vitest.config.ts` — all solely to support this one test file.
|
|
255
|
+
- **Decision**: Remove `TabOption.test.tsx` and revert every dependency/config change that existed only to support it: drop `react-test-renderer`, `@types/react-test-renderer`, and the `@types/react` `resolutions` pin from `package.json`; revert `vitest.config.ts`'s `esbuild.jsx: "automatic"` addition. `TabOption`'s `disabled` behavior (FR-6) ships without automated test coverage.
|
|
256
|
+
- **Consequences**: No component-rendering test infrastructure is introduced by this spec; `TabOption`'s `disabled` prop relies on manual verification only. Re-introducing a similar test later would require re-adding the same dependencies (or an equivalent renderer/testing setup) and re-solving the same `@types/react` conflict.
|
|
257
|
+
|
|
258
|
+
#### Decision 10: The Address Locations alert is non-dismissible, like the Org Units one
|
|
259
|
+
|
|
260
|
+
- **Status**: Accepted (user decision, `/grill-me` round)
|
|
261
|
+
- **Context**: Unlike the Org Units alert (shown once per org unit), this alert renders on every address's details page, raising a fatigue concern.
|
|
262
|
+
- **Decision**: Keep `CustomFieldsDeprecationAlert` non-dismissible in both usages — no `onDismiss`/close affordance is added.
|
|
263
|
+
- **Consequences**: Consistent behavior between the two usages with a single, simpler component; the short copy mitigates fatigue enough to not warrant the added complexity of a dismiss state (and its own persistence concerns, e.g. per-address dismissal storage).
|
|
264
|
+
|
|
265
|
+
### Implementation Plan
|
|
266
|
+
|
|
267
|
+
1. **Generalize and relocate the deprecation alert**
|
|
268
|
+
- Move `CustomFieldsDeprecationAlert.tsx` (+ `.scss`) from `src/features/org-units/components/` to `src/features/shared/components/CustomFieldsDeprecationAlert/`.
|
|
269
|
+
- Change its signature to accept `children: ReactNode` instead of hardcoded copy.
|
|
270
|
+
- Export it from `shared/components/index.ts`; update `OrgUnitsDetailsLayout.tsx`'s import and wrap its existing copy as `children`.
|
|
271
|
+
|
|
272
|
+
2. **Remove the Locations tab from `CreateAddressDrawer`**
|
|
273
|
+
- Drop the `location-tab` `TabOption`/`TabContent`, the `locations` state, and the `LocationForm` import/usage. Keep `locations_count` in the analytics payload, hardcoded to `0` (Decision 8).
|
|
274
|
+
|
|
275
|
+
3. **Add `disabled` support to `TabOption`, disable it in `AddressDetailsLayout`**
|
|
276
|
+
- `TabOption.tsx`: add optional `disabled` prop; render a native `disabled` `<button>` when set.
|
|
277
|
+
- `tab.scss`: add disabled-state styling (opacity + `cursor: not-allowed`), matching the project's established disabled-state visual language.
|
|
278
|
+
- `AddressDetailsLayout.tsx`: mark the "Locations" `TabOption` `disabled` and move it to the end of the tab bar (`Details`, `Recipients`, `Locations` — Decision 7); remove `"location-tab"` from `validTabs`/`AddressDetailTabId`; remove the `locationsData` prop, `AddressLocationsList`/`LocationDrawer` wiring, the `"location-tab"` `renderActionButton` branch, and the `<TabContent id="location-tab">` block; render the (relocated) `CustomFieldsDeprecationAlert` with Address-Locations copy near the top of the page.
|
|
279
|
+
|
|
280
|
+
4. **Disable the "Add Locations" shortcut in `AddressDropdownMenu`**
|
|
281
|
+
- Remove `LocationDrawer` import/wiring; set native `disabled` on the "Add Locations" `DropdownItem`. Keep its current position in the menu (Decision 7).
|
|
282
|
+
|
|
283
|
+
5. **Delete the Locations client/hooks/services/components**
|
|
284
|
+
- `clients/LocationsClient.ts`; `services/locations/**`; `hooks/useAddLocationsToAddress.ts`, `useAddressLocationList.ts`, `useAddressLocationEdit.ts`, `useAddressLocationDelete.ts`; `components/LocationsDrawer/**`, `LocationForm/**`, `AddressLocationsList/**`, `EditAddressLocationDrawer/**`, `DeleteAddressLocationDrawer/**`; update `hooks/index.ts` and `components/index.ts`.
|
|
285
|
+
|
|
286
|
+
6. **Update the page loader**
|
|
287
|
+
- `src/pages/address-details.tsx`: remove the `getAddressLocationService` call, `locationsData`/`LocationsPageData`, and the `searchLocations`/`pageLocations` query fields.
|
|
288
|
+
- `usePageItems.ts`: remove the `LOCATIONS` entries from `SEARCH_PARAMS`/`PAGE_PARAMS`.
|
|
289
|
+
|
|
290
|
+
7. **Trim types and dead CSS/constants**
|
|
291
|
+
- `AddressData.ts`: remove the Locations-only types and the `locations` field from `AddressData`/`AddressInput`.
|
|
292
|
+
- `get-default-address.service.ts`: drop `locations: []` from the mapped object.
|
|
293
|
+
- `address-details-layout.scss`: remove the orphaned `[data-fs-address-details-locations]`/`[data-fs-address-details-location]` block and the `&[data-fs-bp-address-location-list]` selector.
|
|
294
|
+
- `shared/utils/constants.ts`: remove `LOCAL_STORAGE_LOCATION_EDIT_KEY`.
|
|
295
|
+
- `shared/services/logger/analytics/constants.ts`: remove the now-unused `LOCATION_CREATED`/`LOCATION_EDITED`/`LOCATION_DELETED`/`LOCATION_*_ERROR` events.
|
|
296
|
+
|
|
297
|
+
8. **Clean up Cypress**
|
|
298
|
+
- Delete `cypress/integration/locations.test.ts` and the `TEST_DATA.LOCATIONS` block in `cypress/constants.ts`.
|
|
299
|
+
|
|
300
|
+
9. **Changelog**
|
|
301
|
+
- Extend the existing `[1.3.88]` `CHANGELOG.md` entry (from `specs/deprecate-custom-fields.md`) to mention Address Locations — no separate version bump (Decision 6: still unpublished, same PR #409).
|
|
302
|
+
|
|
303
|
+
10. **Verification**
|
|
304
|
+
- Run `make check` (lint, typecheck, test).
|
|
305
|
+
- Manually verify against a linked host store: "Add address" shows only Details/Recipients; an address's details page shows a disabled "Locations" tab plus the alert; `?tab=location-tab` falls back to Details; the address actions dropdown's "Add Locations" is disabled; the Org Units alert (relocated component) still renders unchanged.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## 3. Technical Contract
|
|
310
|
+
|
|
311
|
+
### Data Models
|
|
312
|
+
|
|
313
|
+
`AddressData` / `AddressInput` (trimmed — `locations` field removed):
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
export type AddressData = AddressSummaryData &
|
|
317
|
+
AddressOption & {
|
|
318
|
+
geoCoordinates: string;
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
export type AddressInput = {
|
|
322
|
+
id?: string;
|
|
323
|
+
isActive?: boolean;
|
|
324
|
+
profileId?: string;
|
|
325
|
+
name: string;
|
|
326
|
+
streetAddress: string;
|
|
327
|
+
streetAddress2: string;
|
|
328
|
+
streetNumber?: string;
|
|
329
|
+
country: string;
|
|
330
|
+
countryCode: string;
|
|
331
|
+
zip: string;
|
|
332
|
+
state: string;
|
|
333
|
+
geoCoordinates: string;
|
|
334
|
+
city: string;
|
|
335
|
+
types: string[];
|
|
336
|
+
neighborhood?: string;
|
|
337
|
+
};
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Removed entirely from `AddressData.ts`: `LocationData`, `LocationResponse`, `LocationParams`, `LocationCreatedResponse`, `ListLocationsParams`, `LocationInput`, `ApiLocationBaseParams`, `LocationsPageData`, `AddLocationsParams`, `EditDeleteLocationParams`.
|
|
341
|
+
|
|
342
|
+
### Interfaces
|
|
343
|
+
|
|
344
|
+
#### `CustomFieldsDeprecationAlert` (generalized, moved to `shared/components/`)
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
export type CustomFieldsDeprecationAlertProps = {
|
|
348
|
+
children: ReactNode;
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
export const CustomFieldsDeprecationAlert = ({
|
|
352
|
+
children,
|
|
353
|
+
}: CustomFieldsDeprecationAlertProps) => (
|
|
354
|
+
<Alert
|
|
355
|
+
data-fs-bp-custom-fields-deprecation-alert
|
|
356
|
+
icon={
|
|
357
|
+
<Icon
|
|
358
|
+
name="Warning"
|
|
359
|
+
width={20}
|
|
360
|
+
height={20}
|
|
361
|
+
data-fs-bp-custom-fields-deprecation-alert-icon
|
|
362
|
+
/>
|
|
363
|
+
}
|
|
364
|
+
>
|
|
365
|
+
{children}
|
|
366
|
+
</Alert>
|
|
367
|
+
);
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Usage in `OrgUnitsDetailsLayout.tsx` (unchanged copy, now passed as `children`):
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
<CustomFieldsDeprecationAlert>
|
|
374
|
+
PO Numbers, Cost Centers, and Releases management has been replaced by
|
|
375
|
+
Accounting Fields and was discontinued on <strong>07/30/2026</strong>.
|
|
376
|
+
Update to buyer-portal plugin <strong>v2.0.1</strong> or above and
|
|
377
|
+
FastStore <strong>v4</strong> to keep managing these fields.
|
|
378
|
+
</CustomFieldsDeprecationAlert>
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Usage in `AddressDetailsLayout.tsx` (new):
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
<CustomFieldsDeprecationAlert>
|
|
385
|
+
Address Locations management has been replaced by Accounting Fields and
|
|
386
|
+
was discontinued on <strong>07/30/2026</strong>. Update to buyer-portal
|
|
387
|
+
plugin <strong>v2.0.1</strong> or above and FastStore <strong>v4</strong>{" "}
|
|
388
|
+
to keep managing locations.
|
|
389
|
+
</CustomFieldsDeprecationAlert>
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
#### `TabOption` (updated)
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
export type TabOptionProps = {
|
|
396
|
+
children?: React.ReactNode;
|
|
397
|
+
id: string;
|
|
398
|
+
disabled?: boolean;
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
export const TabOption = ({ children, id, disabled = false }: TabOptionProps) => {
|
|
402
|
+
const { setActiveTabId, activeTabId } = useTab();
|
|
403
|
+
|
|
404
|
+
return (
|
|
405
|
+
<button
|
|
406
|
+
data-fs-bp-tab-option
|
|
407
|
+
data-fs-bp-tab-option-is-active={activeTabId === id}
|
|
408
|
+
disabled={disabled}
|
|
409
|
+
aria-disabled={disabled}
|
|
410
|
+
onClick={() => setActiveTabId(id)}
|
|
411
|
+
>
|
|
412
|
+
{children}
|
|
413
|
+
</button>
|
|
414
|
+
);
|
|
415
|
+
};
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
#### `AddressDetailsLayout` (updated tab set)
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
type AddressDetailTabId = "address-tab" | "recipient-tab"; // "location-tab" removed
|
|
422
|
+
|
|
423
|
+
const validTabs: AddressDetailTabId[] = ["address-tab", "recipient-tab"];
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
`AddressDetailsLayoutProps` drops `locationsData: LocationsPageData`.
|
|
427
|
+
|
|
428
|
+
#### `address-details.tsx` loader (trimmed)
|
|
429
|
+
|
|
430
|
+
`AddressDetailsPageData.data` drops `locationsData: LocationsPageData | null`; the loader stops calling `getAddressLocationService` and stops reading `searchLocations`/`pageLocations` from the query.
|
|
431
|
+
|
|
432
|
+
### Component Boundaries
|
|
433
|
+
|
|
434
|
+
| Module | Responsibility after this change |
|
|
435
|
+
|---|---|
|
|
436
|
+
| `shared/components/CustomFieldsDeprecationAlert` | Generic, non-dismissible deprecation alert; message supplied by each caller via `children` |
|
|
437
|
+
| `TabOption` (`shared/components/Tab`) | Renders a normal clickable tab, or (when `disabled`) a native-disabled, non-interactive one |
|
|
438
|
+
| `CreateAddressDrawer` | Details + Recipients only; no Locations tab, no `locations` state |
|
|
439
|
+
| `AddressDetailsLayout` | Details/Recipients tabs fully functional; Locations tab visible-but-disabled; renders the deprecation alert; no location data fetching |
|
|
440
|
+
| `AddressDropdownMenu` | Edit details / Add Recipients / Remove / Delete fully functional; "Add Locations" disabled |
|
|
441
|
+
| `OrgUnitsDetailsLayout` | Unchanged behavior; now imports the alert from `shared` instead of `org-units/components` |
|
|
442
|
+
|
|
443
|
+
### Integration Points
|
|
444
|
+
|
|
445
|
+
- **BFF** — same retiring custom-fields API as the prior spec; the `Location` field type is covered by the same 2026-07-30 date.
|
|
446
|
+
- **`org-units`** — only affected by the `CustomFieldsDeprecationAlert` relocation (import path change, no behavior change).
|
|
447
|
+
- **Host store** — no route changes; the Address Details page keeps the same URL, just with one fewer valid tab.
|
|
448
|
+
|
|
449
|
+
### Invariants & Constraints
|
|
450
|
+
|
|
451
|
+
- The "Locations" tab and the "Add Locations" dropdown item must remain present (label-wise) — only their interactivity changes, matching the precedent set for PO Numbers/Cost Centers/Releases nav entries.
|
|
452
|
+
- No domain may import another domain's components directly — `CustomFieldsDeprecationAlert` must live under `shared/components/`.
|
|
453
|
+
- Existing addresses with pre-existing location values must not error when their details page is loaded.
|
|
454
|
+
- No feature flag gates this behavior.
|
|
455
|
+
|
|
456
|
+
### Files to Change / Remove
|
|
457
|
+
|
|
458
|
+
| File | Change |
|
|
459
|
+
|---|---|
|
|
460
|
+
| `src/features/addresses/clients/LocationsClient.ts` | **Remove** |
|
|
461
|
+
| `src/features/addresses/services/locations/**` | **Remove entirely** |
|
|
462
|
+
| `src/features/addresses/hooks/useAddLocationsToAddress.ts`, `useAddressLocationList.ts`, `useAddressLocationEdit.ts`, `useAddressLocationDelete.ts` | **Remove** |
|
|
463
|
+
| `src/features/addresses/hooks/index.ts` | Drop the 4 removed exports |
|
|
464
|
+
| `src/features/addresses/components/LocationsDrawer/**` | **Remove entirely** |
|
|
465
|
+
| `src/features/addresses/components/LocationForm/**` (incl. `LocationField/**`) | **Remove entirely** |
|
|
466
|
+
| `src/features/addresses/components/AddressLocationsList/**` | **Remove entirely** |
|
|
467
|
+
| `src/features/addresses/components/EditAddressLocationDrawer/**` | **Remove entirely** |
|
|
468
|
+
| `src/features/addresses/components/DeleteAddressLocationDrawer/**` | **Remove entirely** |
|
|
469
|
+
| `src/features/addresses/components/index.ts` | Drop `LocationForm`, `LocationDrawer`, `AddressLocationsList` exports |
|
|
470
|
+
| `src/features/addresses/components/CreateAddressDrawer/CreateAddressDrawer.tsx` | Remove Locations tab, `locations` state, `LocationForm` usage; keep `locations_count` analytics field hardcoded to `0` |
|
|
471
|
+
| `src/features/addresses/components/AddressDropdownMenu/AddressDropdownMenu.tsx` | Remove `LocationDrawer` wiring; set native `disabled` on "Add Locations" (position unchanged) |
|
|
472
|
+
| `src/features/addresses/layouts/AddressDetailsLayout/AddressDetailsLayout.tsx` | Disable Locations tab and move it to the end of the tab bar; drop `location-tab` from valid tabs; remove `locationsData`/list/drawer wiring; render the (relocated) alert |
|
|
473
|
+
| `src/features/addresses/layouts/AddressDetailsLayout/address-details-layout.scss` | Remove orphaned Locations CSS blocks |
|
|
474
|
+
| `src/features/addresses/types/AddressData.ts` | Remove Locations-only types; drop `locations` field from `AddressData`/`AddressInput` |
|
|
475
|
+
| `src/features/addresses/services/default-values/get-default-address.service.ts` | Drop `locations: []` from the mapped object |
|
|
476
|
+
| `src/features/shared/components/Tab/TabOption.tsx` | Add `disabled` support |
|
|
477
|
+
| `src/features/shared/components/Tab/tab.scss` | Add disabled-state styling |
|
|
478
|
+
| `src/features/org-units/components/CustomFieldsDeprecationAlert/**` | **Move** to `src/features/shared/components/CustomFieldsDeprecationAlert/**`; generalize to accept `children` |
|
|
479
|
+
| `src/features/shared/components/index.ts` | Export the relocated `CustomFieldsDeprecationAlert` |
|
|
480
|
+
| `src/features/org-units/components/index.ts` | Drop the local `CustomFieldsDeprecationAlert` export |
|
|
481
|
+
| `src/features/org-units/layouts/OrgUnitDetailsLayout/OrgUnitDetailsLayout.tsx` | Update import path; pass existing copy as `children` |
|
|
482
|
+
| `src/features/org-units/layouts/OrgUnitDetailsLayout/org-units-details.scss` | Update the relocated `.scss` import path |
|
|
483
|
+
| `src/pages/address-details.tsx` | Remove `getAddressLocationService` call and `locationsData`/query fields |
|
|
484
|
+
| `src/features/shared/hooks/usePageItems.ts` | Remove `LOCATIONS` entries from `SEARCH_PARAMS`/`PAGE_PARAMS` |
|
|
485
|
+
| `src/features/shared/utils/constants.ts` | Remove `LOCAL_STORAGE_LOCATION_EDIT_KEY` |
|
|
486
|
+
| `src/features/shared/services/logger/analytics/constants.ts` | Remove `LOCATION_*` analytics events |
|
|
487
|
+
| `cypress/integration/locations.test.ts` | **Remove** |
|
|
488
|
+
| `cypress/constants.ts` | Remove `TEST_DATA.LOCATIONS` block |
|
|
489
|
+
| `CHANGELOG.md` | Extend the existing `[1.3.88]` entry to mention Address Locations |
|
|
490
|
+
|
|
491
|
+
### Explicitly Not Touched
|
|
492
|
+
|
|
493
|
+
- `RecipientsForm`, `RecipientItem`, `AddressRecipientsList`, their hooks (`useSearchAddressRecipients`, `useAddRecipientsToAddress`, `useDeleteRecipientAddress`, `useEditRecipientsToAddress`), services (`services/recipients/**`), and `RecipientsClient`.
|
|
494
|
+
- Generic `shared/components` used by both Locations (removed) and Recipients (kept): `Table`, `InternalSearch`, `EmptyState`, `Paginator`, `BasicDrawer`, `IconButton`, `Icon`, `InputText` — none of them are Locations-specific.
|
|
495
|
+
- `AddressForm`, `ExistingAddress`, `AddressLine`, `AddressesCard` — confirmed no reference to the removed `locations` field.
|
|
496
|
+
- Everything already covered by `specs/deprecate-custom-fields.md` (PO Numbers, Cost Centers, Releases, `budgets`, `buying-policies`, `org-units` quick-add for those three fields) — unaffected by this spec beyond the `CustomFieldsDeprecationAlert` relocation.
|
|
497
|
+
- Version bump / release mechanics — reuses the `1.3.88` release already planned in the prior spec.
|