@vtex/faststore-plugin-buyer-portal 2.0.13 → 2.0.14
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 +18 -1
- package/cms/b2b/components/.gitkeep +0 -0
- package/cms/b2b/pages/cms_content_type__i18n.jsonc +36 -0
- package/cypress/integration/localization.test.ts +482 -0
- package/cypress/support/commands.ts +8 -0
- package/docs/i18n/i18n-messages-format.md +391 -0
- package/docs/i18n/locales.json +701 -0
- package/docs/i18n/migration-inventory.md +959 -0
- package/package.json +3 -3
- package/specs/custom-localization-system.md +711 -0
- package/specs/multi-locale-e2e-validation.md +277 -0
- package/src/__mocks__/discovery.config.ts +12 -0
- package/src/features/accounting-fields/components/AccountingConfirmDelete/AccountingConfirmDelete.tsx +14 -4
- package/src/features/accounting-fields/components/AccountingFieldConfirmEdit/AccountingFieldConfirmEdit.tsx +11 -6
- package/src/features/accounting-fields/components/AccountingFieldDropdown/AccountingFieldDropdown.tsx +5 -3
- package/src/features/accounting-fields/components/AccountingFieldForm/AccountingFieldForm.tsx +33 -23
- package/src/features/accounting-fields/components/AccountingValueConfirmEdit/AccountingValueConfirmEdit.tsx +10 -6
- package/src/features/accounting-fields/components/AccountingValueDropdown/AccountingValueDropdown.tsx +19 -9
- package/src/features/accounting-fields/components/AccountingValueForm/AccountingValueForm.tsx +21 -10
- package/src/features/accounting-fields/components/CreateAccountingFieldDrawer/CreateAccountingFieldDrawer.tsx +11 -8
- package/src/features/accounting-fields/components/CreateAccountingValueDrawer/CreateAccountingValueDrawer.tsx +18 -7
- package/src/features/accounting-fields/components/DeleteAccountingFieldDrawer/DeleteAccountingFieldDrawer.tsx +14 -12
- package/src/features/accounting-fields/components/DeleteAccountingValueDrawer/DeleteAccountingValueDrawer.tsx +20 -10
- package/src/features/accounting-fields/components/EditAccountingFieldDrawer/EditAccountingFieldDrawer.tsx +5 -3
- package/src/features/accounting-fields/components/EditAccountingValueDrawer/EditAccountingValueDrawer.tsx +13 -6
- package/src/features/accounting-fields/components/RemoveValueFromUnitDrawer/RemoveValueFromUnitDrawer.tsx +19 -8
- package/src/features/accounting-fields/layouts/AccountingFieldLayout/AccountingFieldLayout.tsx +11 -9
- package/src/features/addresses/components/AddRecipientsDrawer/AddRecipientsDrawer.tsx +13 -7
- package/src/features/addresses/components/AddressDropdownMenu/AddressDropdownMenu.tsx +22 -20
- package/src/features/addresses/components/AddressForm/AddressForm.tsx +33 -22
- package/src/features/addresses/components/AddressLine/AddressLine.tsx +29 -25
- package/src/features/addresses/components/AddressLocationsList/AddressLocationsList.tsx +15 -6
- package/src/features/addresses/components/AddressRecipientsList/AddressRecipientsList.tsx +9 -4
- package/src/features/addresses/components/AddressesCard/AddressesCard.tsx +8 -5
- package/src/features/addresses/components/CreateAddressDrawer/CreateAddressDrawer.tsx +27 -14
- package/src/features/addresses/components/CreateAddressSettingsDrawer/CreateAddressSettingsDrawer.tsx +26 -21
- package/src/features/addresses/components/DeleteAddressDrawer/DeleteAddressDrawer.tsx +20 -16
- package/src/features/addresses/components/DeleteAddressLocationDrawer/DeleteAddressLocationDrawer.tsx +26 -14
- package/src/features/addresses/components/DeleteRecipientAddressDrawer/DeleteRecipientAddressDrawer.tsx +20 -17
- package/src/features/addresses/components/EditAddressDrawer/EditAddressDrawer.tsx +12 -6
- package/src/features/addresses/components/EditAddressLocationDrawer/EditAddressLocationDrawer.tsx +24 -17
- package/src/features/addresses/components/EditRecipientAddressDrawer/EditRecipientAddressDrawer.tsx +17 -15
- package/src/features/addresses/components/LocationForm/LocationField/LocationField.tsx +8 -5
- package/src/features/addresses/components/LocationForm/LocationForm.tsx +9 -3
- package/src/features/addresses/components/LocationsDrawer/LocationsDrawer.tsx +15 -9
- package/src/features/addresses/components/RecipientsForm/RecipientItem/RecipientItem.tsx +55 -46
- package/src/features/addresses/components/RecipientsForm/RecipientsForm.tsx +4 -1
- package/src/features/addresses/components/RemoveAddressDrawer/RemoveAddressDrawer.tsx +21 -14
- package/src/features/addresses/layouts/AddressDetailsLayout/AddressDetailsLayout.tsx +16 -9
- package/src/features/addresses/layouts/AddressesLayout/AddressesLayout.tsx +11 -8
- package/src/features/b2b-agent/layouts/B2BAgentLayout/B2BAgentLayout.tsx +3 -1
- package/src/features/budgets/components/BudgetAddForm/BudgetAddForm.tsx +14 -12
- package/src/features/budgets/components/BudgetAddSuccess/BudgetAddSuccess.tsx +16 -14
- package/src/features/budgets/components/BudgetAllocationsSelection/BudgetAllocationsSelection.tsx +8 -5
- package/src/features/budgets/components/BudgetAllocationsTable/BudgetAllocationsTable.tsx +9 -6
- package/src/features/budgets/components/BudgetDeleteDrawer/BudgetDeleteDrawer.tsx +23 -17
- package/src/features/budgets/components/BudgetEditNotificationDrawer/BudgetEditNotificationDrawer.tsx +13 -6
- package/src/features/budgets/components/BudgetNotificationForm/BudgetNotificationForm.tsx +31 -24
- package/src/features/budgets/components/BudgetNotificationsInfo/BudgetNotificationsInfo.tsx +15 -9
- package/src/features/budgets/components/BudgetRemainingBalance/BudgetRemainingBalance.tsx +6 -2
- package/src/features/budgets/components/BudgetSettingsInfo/BudgetSettingsInfo.tsx +27 -10
- package/src/features/budgets/components/BudgetUsersTable/BudgetUsersTable.tsx +14 -7
- package/src/features/budgets/components/BudgetsTable/BudgetsTable.tsx +11 -8
- package/src/features/budgets/components/CreateBudgetAllocationDrawer/CreateBudgetAllocationDrawer.tsx +8 -5
- package/src/features/budgets/components/CreateBudgetDrawer/CreateBudgetDrawer.tsx +31 -18
- package/src/features/budgets/components/DeleteBudgetAllocationDrawer/DeleteBudgetAllocationDrawer.tsx +17 -12
- package/src/features/budgets/components/EditBudgetDrawer/EditBudgetDrawer.tsx +14 -8
- package/src/features/budgets/components/EmptyState.tsx/EmptyState.tsx +4 -1
- package/src/features/budgets/layouts/BudgetsDetailsLayout/BudgetsDetailsLayout.tsx +7 -5
- package/src/features/budgets/layouts/BudgetsLayout/BudgetsLayout.tsx +5 -3
- package/src/features/budgets/messages/budgetNotifications.ts +5 -5
- package/src/features/budgets/utils/handleBudgetError.tsx +5 -8
- package/src/features/budgets/utils/handleBudgetError.types.ts +3 -0
- package/src/features/buying-policies/components/AccountingFieldCriteriaSelector/AccountingFieldCriteriaSelector.tsx +5 -3
- package/src/features/buying-policies/components/AccountingFieldCriteriaSelector/AccountingValueCriteriaSelector.tsx +20 -9
- package/src/features/buying-policies/components/AddBuyingPolicyDrawer/AddBuyingPolicyDrawer.tsx +8 -5
- package/src/features/buying-policies/components/BasicBuyingPolicyDrawer/BasicBuyingPolicyDrawer.tsx +49 -33
- package/src/features/buying-policies/components/BudgetCriteriaSelector/BudgetCriteriaSelector.tsx +8 -2
- package/src/features/buying-policies/components/BuyingPolicyDropdownMenu/BuyingPolicyDropdownMenu.tsx +5 -3
- package/src/features/buying-policies/components/DeleteBuyingPolicyDrawer/DeleteBuyingPolicyDrawer.tsx +28 -24
- package/src/features/buying-policies/components/UpdateBuyingPolicyDrawer/UpdateBuyingPolicyDrawer.tsx +10 -7
- package/src/features/buying-policies/layouts/BuyingPoliciesLayout/BuyingPoliciesLayout.tsx +11 -4
- package/src/features/buying-policies/layouts/BuyingPolicyDetailsLayout/BuyingPolicyDetailsLayout.tsx +26 -9
- package/src/features/buying-policies/utils/accountingFieldCriteriaHelpers.ts +2 -2
- package/src/features/buying-policies/utils/buyingPoliciesWorkflowTypes.ts +3 -3
- package/src/features/buying-policies/utils/orderFieldsCriteriaOptions.ts +8 -8
- package/src/features/buying-policies/utils/spendingLimitsCriteriaOptions.ts +6 -6
- package/src/features/contracts/components/ContractsCard/ContractsCard.tsx +7 -5
- package/src/features/contracts/layouts/ContractsLayout/ContractsLayout.tsx +9 -4
- package/src/features/credit-cards/components/CreateCreditCardDrawer/CreateCreditCardDrawer.tsx +17 -11
- package/src/features/credit-cards/components/CreditCardDropdownMenu/CreditCardDropdownMenu.tsx +17 -11
- package/src/features/credit-cards/components/CreditCardForm/CreditCardForm.tsx +8 -5
- package/src/features/credit-cards/components/CreditCardSettingsDrawer/CreditCardSettingsDrawer.tsx +10 -8
- package/src/features/credit-cards/components/DeleteCreditCardDrawer/DeleteCreditCardDrawer.tsx +19 -14
- package/src/features/credit-cards/components/EditCreditCardDrawer/EditCreditCardDrawer.tsx +14 -13
- package/src/features/credit-cards/components/RemoveCreditCardDrawer/RemoveCreditCardDrawer.tsx +18 -15
- package/src/features/credit-cards/layouts/CreditCardsLayout/CreditCardLayout.tsx +10 -4
- package/src/features/order-entry/layouts/OrderEntryLayout.tsx +3 -1
- package/src/features/org-units/components/AddAllToOrgUnitDropdown/AddAllToOrgUnitDropdown.tsx +11 -9
- package/src/features/org-units/components/AuthSetupDrawer/AuthSetupDrawer.tsx +28 -16
- package/src/features/org-units/components/CreateOrgUnitDrawer/CreateOrgUnitDrawer.tsx +18 -12
- package/src/features/org-units/components/DeleteOrgUnitDrawer/DeleteOrgUnitDrawer.tsx +28 -29
- package/src/features/org-units/components/OrgUnitBreadcrumb/OrgUnitBreadcrumbLink.tsx +4 -4
- package/src/features/org-units/components/OrgUnitDetailsDropdownMenu/OrgUnitDetailsDropdownMenu.tsx +4 -2
- package/src/features/org-units/components/OrgUnitDetailsNavbar/OrgUnitDetailsNavbar.tsx +23 -5
- package/src/features/org-units/components/OrgUnitDetailsNavbar/org-unit-details-navbar.scss +18 -2
- package/src/features/org-units/components/OrgUnitsDropdownMenu/OrgUnitsDropdownMenu.tsx +6 -4
- package/src/features/org-units/components/OrgUnitsHierarchyTree/OrgUnitsHierarchyTree.tsx +9 -6
- package/src/features/org-units/components/OrganizationalUnitsCard/OrganizationalUnitsCard.tsx +15 -7
- package/src/features/org-units/components/UpdateOrgUnitDrawer/UpdateOrgUnitDrawer.tsx +15 -9
- package/src/features/org-units/layouts/OrgUnitDetailsLayout/OrgUnitDetailsLayout.tsx +27 -26
- package/src/features/org-units/layouts/OrgUnitsLayout/OrgUnitsLayout.tsx +8 -3
- package/src/features/payment-methods/components/AddPaymentMethodsDrawer/AddPaymentMethodsDrawer.tsx +29 -18
- package/src/features/payment-methods/components/PaymentMethodSettingsDrawer/PaymentMethodSettingsDrawer.tsx +13 -9
- package/src/features/payment-methods/components/RemoveMethodButton/RemoveMethodButton.tsx +5 -2
- package/src/features/payment-methods/components/RemovePaymentMethodsDrawer/RemovePaymentMethodsDrawer.tsx +10 -7
- package/src/features/payment-methods/hooks/useRemovePaymentMethodSubmit.ts +6 -4
- package/src/features/payment-methods/layouts/PaymentMethodsLayout/PaymentMethodsLayout.tsx +21 -15
- package/src/features/product-assortment/components/ProductAssortmentTable/ProductAssortmentTable.tsx +11 -7
- package/src/features/product-assortment/layouts/ProductAssortmentLayout/ProductAssortmentLayout.tsx +9 -6
- package/src/features/profile/components/ProfileCard/ProfileCard.tsx +8 -5
- package/src/features/profile/components/ProfileSummary/ProfileSummary.tsx +13 -6
- package/src/features/profile/layouts/ProfileLayout/ProfileLayout.tsx +16 -6
- package/src/features/roles/layout/RoleDetailsLayout/RoleDetailsLayout.tsx +4 -2
- package/src/features/roles/layout/RolesLayout/RolesLayout.tsx +5 -3
- package/src/features/shared/components/BasicCard/BasicCard.tsx +6 -4
- package/src/features/shared/components/BasicCard/BasicCardLine.tsx +5 -4
- package/src/features/shared/components/CustomerSwitch/CustomerSwitchDrawer.tsx +10 -2
- package/src/features/shared/components/CustomerSwitch/CustomerSwitchSearch.tsx +4 -1
- package/src/features/shared/components/DropdownFilter/DropdownFilter.tsx +11 -7
- package/src/features/shared/components/Error/Error.tsx +13 -6
- package/src/features/shared/components/HeaderInside/HeaderInside.tsx +5 -2
- package/src/features/shared/components/InternalSearch/InternalSearch.tsx +4 -1
- package/src/features/shared/components/InternalTopbar/InternalTopbar.tsx +7 -5
- package/src/features/shared/components/MainLinksDropdownMenu/MainLinksDropdownMenu.tsx +23 -8
- package/src/features/shared/components/OrgUnitInputSearch/OrgUnitInputSearch.tsx +7 -2
- package/src/features/shared/components/Pagination/Pagination.tsx +6 -2
- package/src/features/shared/components/Paginator/Counter.tsx +11 -5
- package/src/features/shared/components/Paginator/Interval.tsx +4 -3
- package/src/features/shared/components/Paginator/NextPageButton.tsx +6 -2
- package/src/features/shared/components/SettingsDrawer/SettingsDrawer.tsx +6 -4
- package/src/features/shared/components/SettingsDrawer/SettingsDrawerListType.tsx +11 -10
- package/src/features/shared/components/SettingsDrawer/listTypeOptions.ts +10 -7
- package/src/features/shared/components/SortFilter/SortFilter.tsx +15 -8
- package/src/features/shared/components/Table/TableRow/TableRow.tsx +5 -1
- package/src/features/shared/components/VerticalNav/VerticalNavLink.tsx +7 -3
- package/src/features/shared/layouts/BaseTabsLayout/Navbar.tsx +28 -4
- package/src/features/shared/layouts/BaseTabsLayout/about-drawer/AboutDrawer.tsx +15 -5
- package/src/features/shared/layouts/BaseTabsLayout/base-tabs-layout.scss +24 -9
- package/src/features/shared/layouts/BaseTabsLayout/sidebar-drawer/SidebarDrawer.tsx +5 -2
- package/src/features/shared/layouts/ContractTabsLayout/ContractTabsLayout.tsx +10 -5
- package/src/features/shared/layouts/ErrorTabsLayout/ErrorTabsLayout.tsx +7 -4
- package/src/features/shared/layouts/FinanceTabsLayout/FinanceTabsLayout.tsx +9 -4
- package/src/features/shared/layouts/LoadingTabsLayout/LoadingTabsLayout.tsx +7 -4
- package/src/features/shared/layouts/OrgUnitTabsLayout/OrgUnitTabLayout.tsx +3 -0
- package/src/features/shared/layouts/SumaPageLayout/FullSidebarNav.tsx +13 -7
- package/src/features/shared/layouts/SumaPageLayout/SumaSidebar.tsx +9 -5
- package/src/features/shared/localization/LocalizationContext.tsx +35 -0
- package/src/features/shared/localization/__tests__/createLocalize.test.ts +166 -0
- package/src/features/shared/localization/__tests__/get-localization-labels.service.test.ts +202 -0
- package/src/features/shared/localization/clients/LocalizationClient.ts +19 -0
- package/src/features/shared/localization/constants.ts +31 -0
- package/src/features/shared/localization/createLocalize.ts +78 -0
- package/src/features/shared/localization/services/get-localization-labels.service.ts +76 -0
- package/src/features/shared/localization/types.ts +66 -0
- package/src/features/shared/localization/withLocalization.tsx +22 -0
- package/src/features/shared/types/AuthRouteProps.ts +5 -0
- package/src/features/shared/types/LoaderData.ts +1 -0
- package/src/features/shared/utils/addresLabelToPropMapping.ts +10 -10
- package/src/features/shared/utils/constants.ts +1 -4
- package/src/features/shared/utils/getContractSettingsLinks.ts +17 -12
- package/src/features/shared/utils/getFinanceSettingsLinks.ts +14 -9
- package/src/features/shared/utils/getKeyByValue.ts +2 -2
- package/src/features/shared/utils/getOrganizationSettingsLinks.ts +13 -3
- package/src/features/shared/utils/getSumaListingSidebarLinks.ts +15 -10
- package/src/features/shared/utils/index.ts +2 -0
- package/src/features/shared/utils/routeLayoutMapping.ts +30 -30
- package/src/features/shared/utils/search.tsx +10 -0
- package/src/features/shared/utils/withAuth.tsx +6 -0
- package/src/features/shared/utils/withAuthLoader.ts +11 -0
- package/src/features/shared/utils/withLoaderErrorBoundary.ts +9 -0
- package/src/features/shared/utils/withProviders.tsx +13 -2
- package/src/features/users/components/CreateUserDrawer/CreateUserDrawer.tsx +39 -27
- package/src/features/users/components/CreateUserDrawerWithUsername/CreateUserDrawerWithUsername.tsx +41 -39
- package/src/features/users/components/DeleteUserDrawer/DeleteUserDrawer.tsx +27 -23
- package/src/features/users/components/EmailTransactionalSection/EmailTransactionalSection.tsx +6 -8
- package/src/features/users/components/LoginField/LoginField.tsx +4 -4
- package/src/features/users/components/ReassignOrgUnitDrawer/ReassignOrgUnitDrawer.tsx +22 -19
- package/src/features/users/components/ResetPasswordDrawer/ResetPasswordDrawer.tsx +16 -21
- package/src/features/users/components/UpdateUserDrawer/UpdateUserDrawer.tsx +26 -15
- package/src/features/users/components/UpdateUserDrawerWithUsername/UpdateUserDrawerWithUsername.tsx +22 -8
- package/src/features/users/components/UserDropdownMenu/UserDropdownMenu.tsx +7 -5
- package/src/features/users/components/UserFormFields/UserFormFields.tsx +9 -8
- package/src/features/users/components/UsersCard/UsersCard.tsx +4 -2
- package/src/features/users/layouts/UserDetailsLayout/UserDetailsLayout.tsx +26 -10
- package/src/features/users/layouts/UsersLayout/UsersLayout.tsx +12 -8
- package/src/pages/accounting-field.tsx +28 -15
- package/src/pages/address-details.tsx +37 -26
- package/src/pages/addresses.tsx +27 -12
- package/src/pages/budgets-details.tsx +25 -15
- package/src/pages/budgets.tsx +31 -17
- package/src/pages/buyer-organization-manager.tsx +23 -12
- package/src/pages/buying-policies.tsx +38 -20
- package/src/pages/buying-policy-details.tsx +20 -19
- package/src/pages/contracts.tsx +15 -1
- package/src/pages/credit-cards.tsx +30 -17
- package/src/pages/order-entry.tsx +26 -15
- package/src/pages/org-unit-details.tsx +20 -6
- package/src/pages/org-units.tsx +20 -6
- package/src/pages/payment-groups.tsx +15 -12
- package/src/pages/productAssortment.tsx +10 -1
- package/src/pages/profile.tsx +14 -1
- package/src/pages/role-details.tsx +19 -6
- package/src/pages/roles.tsx +27 -14
- package/src/pages/user-details.tsx +29 -17
- package/src/pages/users.tsx +11 -0
- package/vitest.config.ts +13 -0
- package/src/features/addresses/constants/messages.ts +0 -8
- package/src/features/credit-cards/constants/messages.ts +0 -6
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps each buyer portal feature to its CMS localization entry UUID.
|
|
3
|
+
* These UUIDs identify the localization entries in the Content Platform API
|
|
4
|
+
* (see LOCALIZATION_BASE_URL) and are used to fetch localized strings per feature at runtime.
|
|
5
|
+
*/
|
|
6
|
+
export const LOCALIZATION_ENTRY_IDS = {
|
|
7
|
+
addresses: "29747c90-344b-45db-9ef0-192b537b12e7",
|
|
8
|
+
budgets: "54f982e2-a823-40c6-954d-f35945413bde",
|
|
9
|
+
users: "7cba4de2-c752-4ee6-96c1-a7cbd6a39b19",
|
|
10
|
+
shared: "4785424c-3eb7-4ab7-b13e-78a1029c8f4d",
|
|
11
|
+
accountingFields: "588dab31-0afe-437e-9f3b-63c76ff7552b",
|
|
12
|
+
buyingPolicies: "e3603de6-d427-44de-aba0-e77d597b9f22",
|
|
13
|
+
creditCards: "cccdd4dc-f73d-4b43-85a3-3e1a2bbc8b1c",
|
|
14
|
+
orgUnits: "2bf471ed-736d-40b7-8162-139ce9ed5a99",
|
|
15
|
+
paymentMethods: "7a8cde2e-3fac-4f30-b264-e135d0ded2d7",
|
|
16
|
+
productAssortment: "cd636c6c-37cf-4078-bc83-378e55751718",
|
|
17
|
+
profile: "57c0716a-12bf-460c-aa57-1679bf48c043",
|
|
18
|
+
contracts: "81d0f596-15f5-4fa8-a6a7-f3e5040e6eb9",
|
|
19
|
+
roles: "13ce6df5-7fdc-4b4b-be9d-f8c4f0a0a488",
|
|
20
|
+
b2bAgent: "dc4fcf7d-00a6-4c9f-ac26-94833288cc46",
|
|
21
|
+
orderEntry: "3cd8c183-129f-4622-ac48-0db54154ecf8",
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
export type LocalizationFeature = keyof typeof LOCALIZATION_ENTRY_IDS;
|
|
25
|
+
export type LocalizationEntryId =
|
|
26
|
+
(typeof LOCALIZATION_ENTRY_IDS)[LocalizationFeature];
|
|
27
|
+
|
|
28
|
+
/** Content type slug in the Content Platform API path (see cms_content_type__i18n.jsonc). */
|
|
29
|
+
export const LOCALIZATION_CONTENT_TYPE = "b2bLocalization";
|
|
30
|
+
|
|
31
|
+
export const LOCALIZATION_BASE_URL = `https://vtex.vtexcommercestable.com.br/api/content-platform/data/vtex/b2b/${LOCALIZATION_CONTENT_TYPE}`;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
import type { LabelMap, LocalizeFn } from "./types";
|
|
4
|
+
|
|
5
|
+
const PLACEHOLDER_PATTERN = /\{(\d+)\}/g;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Returns true when the interpolations array contains at least one value that is
|
|
9
|
+
* not a plain string or number — i.e. a React node (element, fragment, etc.).
|
|
10
|
+
*/
|
|
11
|
+
const hasReactNodes = (
|
|
12
|
+
interpolations: (string | number | ReactNode)[]
|
|
13
|
+
): boolean =>
|
|
14
|
+
interpolations.some(
|
|
15
|
+
(v) =>
|
|
16
|
+
v !== null &&
|
|
17
|
+
v !== undefined &&
|
|
18
|
+
typeof v !== "string" &&
|
|
19
|
+
typeof v !== "number"
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Builds an array of alternating text segments and React nodes by walking the
|
|
24
|
+
* template string with exec() rather than replace(), so non-string values can
|
|
25
|
+
* be inserted at placeholder positions without stringification.
|
|
26
|
+
*/
|
|
27
|
+
const interpolateNodes = (
|
|
28
|
+
template: string,
|
|
29
|
+
interpolations: ReactNode[]
|
|
30
|
+
): ReactNode[] => {
|
|
31
|
+
const result: ReactNode[] = [];
|
|
32
|
+
const regex = new RegExp(PLACEHOLDER_PATTERN.source, "g");
|
|
33
|
+
let lastIndex = 0;
|
|
34
|
+
let match: RegExpExecArray | null;
|
|
35
|
+
|
|
36
|
+
while ((match = regex.exec(template)) !== null) {
|
|
37
|
+
if (match.index > lastIndex) {
|
|
38
|
+
result.push(template.slice(lastIndex, match.index));
|
|
39
|
+
}
|
|
40
|
+
const idx = Number(match[1]);
|
|
41
|
+
const value = interpolations[idx];
|
|
42
|
+
result.push(value !== undefined ? value : match[0]);
|
|
43
|
+
lastIndex = match.index + match[0].length;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (lastIndex < template.length) {
|
|
47
|
+
result.push(template.slice(lastIndex));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const createLocalize = (labels: LabelMap): LocalizeFn => {
|
|
54
|
+
function t(key: string, interpolations?: (string | number)[]): string;
|
|
55
|
+
function t(key: string, interpolations: ReactNode[]): ReactNode;
|
|
56
|
+
function t(
|
|
57
|
+
key: string,
|
|
58
|
+
interpolations?: (string | number | ReactNode)[]
|
|
59
|
+
): string | ReactNode {
|
|
60
|
+
const template = labels[key];
|
|
61
|
+
|
|
62
|
+
if (template === undefined) return key;
|
|
63
|
+
|
|
64
|
+
if (!interpolations || interpolations.length === 0) return template;
|
|
65
|
+
|
|
66
|
+
if (hasReactNodes(interpolations)) {
|
|
67
|
+
return interpolateNodes(template, interpolations as ReactNode[]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Pure string/number path — O(1) replace, same as before.
|
|
71
|
+
return template.replace(PLACEHOLDER_PATTERN, (token, index: string) => {
|
|
72
|
+
const value = (interpolations as (string | number)[])[Number(index)];
|
|
73
|
+
return value === undefined ? token : String(value);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return t as LocalizeFn;
|
|
78
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { logError } from "../../services/logger";
|
|
2
|
+
import { localizationClient } from "../clients/LocalizationClient";
|
|
3
|
+
import { LOCALIZATION_ENTRY_IDS, type LocalizationEntryId } from "../constants";
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
LocalizationLabelType,
|
|
7
|
+
LabelMap,
|
|
8
|
+
GetLocalizationLabelsParams,
|
|
9
|
+
} from "../types";
|
|
10
|
+
|
|
11
|
+
// Permanent process-local cache + single-flight, keyed by (entryId, locale).
|
|
12
|
+
const resolved = new Map<string, LabelMap>();
|
|
13
|
+
const inFlight = new Map<string, Promise<LabelMap>>();
|
|
14
|
+
|
|
15
|
+
const toLabelMap = (labels: LocalizationLabelType[]): LabelMap =>
|
|
16
|
+
labels.reduce<LabelMap>((acc, { key, value }) => {
|
|
17
|
+
acc[key] = value;
|
|
18
|
+
return acc;
|
|
19
|
+
}, {});
|
|
20
|
+
|
|
21
|
+
// Fetches (and permanently caches) a single entry.
|
|
22
|
+
// Logs an error and falls back to {} on failure — never throws.
|
|
23
|
+
const fetchEntry = (entryId: string, locale: string): Promise<LabelMap> => {
|
|
24
|
+
const cacheKey = `${entryId}::${locale}`;
|
|
25
|
+
|
|
26
|
+
const cached = resolved.get(cacheKey);
|
|
27
|
+
if (cached) return Promise.resolve(cached);
|
|
28
|
+
|
|
29
|
+
const ongoing = inFlight.get(cacheKey);
|
|
30
|
+
if (ongoing) return ongoing;
|
|
31
|
+
|
|
32
|
+
const promise = localizationClient
|
|
33
|
+
.getEntry(entryId, locale)
|
|
34
|
+
.then((data) => {
|
|
35
|
+
const map = toLabelMap(data?.labels ?? []);
|
|
36
|
+
resolved.set(cacheKey, map); // permanent cache (no TTL)
|
|
37
|
+
return map;
|
|
38
|
+
})
|
|
39
|
+
.catch((error: unknown) => {
|
|
40
|
+
logError("Failed to fetch localization labels", {
|
|
41
|
+
entryId,
|
|
42
|
+
locale,
|
|
43
|
+
error_message: error instanceof Error ? error.message : String(error),
|
|
44
|
+
});
|
|
45
|
+
return {} as LabelMap; // do NOT write to `resolved`; allow retry on next request
|
|
46
|
+
})
|
|
47
|
+
.finally(() => {
|
|
48
|
+
inFlight.delete(cacheKey);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
inFlight.set(cacheKey, promise);
|
|
52
|
+
return promise;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** Clears the process-local cache. Intended for use in tests only. */
|
|
56
|
+
export const _resetLocalizationCache = () => {
|
|
57
|
+
resolved.clear();
|
|
58
|
+
inFlight.clear();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const getLocalizationLabelsService = async ({
|
|
62
|
+
entryIds,
|
|
63
|
+
locale = "",
|
|
64
|
+
}: GetLocalizationLabelsParams): Promise<LabelMap> => {
|
|
65
|
+
const requested = Array.isArray(entryIds) ? entryIds : [entryIds];
|
|
66
|
+
|
|
67
|
+
// Always include `shared`; de-duplicate via Set.
|
|
68
|
+
const ids = Array.from(
|
|
69
|
+
new Set<LocalizationEntryId>([LOCALIZATION_ENTRY_IDS.shared, ...requested])
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const maps = await Promise.all(ids.map((id) => fetchEntry(id, locale)));
|
|
73
|
+
|
|
74
|
+
// Namespaced keys make this merge collision-safe.
|
|
75
|
+
return Object.assign({}, ...maps) as LabelMap;
|
|
76
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type LocalizationLanguageType = {
|
|
2
|
+
name: string;
|
|
3
|
+
language_code: string;
|
|
4
|
+
native_name: string;
|
|
5
|
+
script: string;
|
|
6
|
+
text_direction: "ltr" | "rtl" | string;
|
|
7
|
+
utf_encoding: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type LocalizationRegionType = {
|
|
11
|
+
name: string;
|
|
12
|
+
flag: string;
|
|
13
|
+
country_code: string;
|
|
14
|
+
continent: string;
|
|
15
|
+
date_format: string;
|
|
16
|
+
time_format: "12h" | "24h" | string;
|
|
17
|
+
time_format_mask: string;
|
|
18
|
+
unit_system: "imperial" | "metric" | string;
|
|
19
|
+
default_timezone: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type LocalizationLocaleMetadataType = {
|
|
23
|
+
code: string;
|
|
24
|
+
locale: string;
|
|
25
|
+
language: LocalizationLanguageType;
|
|
26
|
+
region: LocalizationRegionType;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type LocalizationLabelType = {
|
|
30
|
+
key: string;
|
|
31
|
+
value: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type LocalizationLocaleDataType = {
|
|
35
|
+
locale_metadata: LocalizationLocaleMetadataType; // typed, not consumed yet
|
|
36
|
+
labels: LocalizationLabelType[];
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
import type { ReactNode } from "react";
|
|
40
|
+
|
|
41
|
+
import type { LocalizationEntryId } from "./constants";
|
|
42
|
+
|
|
43
|
+
/** Flat, O(1)-lookup label map produced by the service. */
|
|
44
|
+
export type LabelMap = Record<string, string>;
|
|
45
|
+
|
|
46
|
+
/** Parameters accepted by `getLocalizationLabelsService`. */
|
|
47
|
+
export type GetLocalizationLabelsParams = {
|
|
48
|
+
entryIds: LocalizationEntryId | LocalizationEntryId[];
|
|
49
|
+
locale?: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Translation function exposed to components.
|
|
54
|
+
*
|
|
55
|
+
* Two call signatures:
|
|
56
|
+
* - `t(key, (string | number)[])` → `string` – pure text interpolation (O(1) replace)
|
|
57
|
+
* - `t(key, ReactNode[])` → `ReactNode` – node interpolation; returns an array of
|
|
58
|
+
* alternating text segments and the supplied React nodes, ready to spread inside JSX.
|
|
59
|
+
*
|
|
60
|
+
* The second overload is selected automatically by TypeScript whenever at least one
|
|
61
|
+
* interpolation value is not a `string` or `number` (e.g. a JSX element).
|
|
62
|
+
*/
|
|
63
|
+
export type LocalizeFn = {
|
|
64
|
+
(key: string, interpolations?: (string | number)[]): string;
|
|
65
|
+
(key: string, interpolations: ReactNode[]): ReactNode;
|
|
66
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ComponentType } from "react";
|
|
2
|
+
|
|
3
|
+
import { LocalizationProvider } from "./LocalizationContext";
|
|
4
|
+
|
|
5
|
+
import type { LabelMap } from "./types";
|
|
6
|
+
|
|
7
|
+
export const withLocalization = <T extends Record<string, unknown>>(
|
|
8
|
+
Component: ComponentType<T>
|
|
9
|
+
) =>
|
|
10
|
+
function WrappedWithLocalization(
|
|
11
|
+
props: T & { context: { localization?: { labels: LabelMap } } }
|
|
12
|
+
) {
|
|
13
|
+
const labels = props.context?.localization?.labels ?? {};
|
|
14
|
+
return (
|
|
15
|
+
<LocalizationProvider labels={labels}>
|
|
16
|
+
{/* Forward ALL props (including `context`) so `withBuyerPortal` downstream
|
|
17
|
+
still receives it. `withLocalization` must sit BEFORE `withBuyerPortal`,
|
|
18
|
+
which strips `context` (see Decision 1 in specs/custom-localization-system.md). */}
|
|
19
|
+
<Component {...props} />
|
|
20
|
+
</LocalizationProvider>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ErrorBoundaryProps } from "../components/ErrorBoundary/types";
|
|
2
2
|
import { ClientContext } from "../utils";
|
|
3
3
|
|
|
4
|
+
import type { LabelMap } from "../localization/types";
|
|
5
|
+
|
|
4
6
|
export type AuthRouteProps<T> =
|
|
5
7
|
| {
|
|
6
8
|
authorized: true;
|
|
@@ -15,4 +17,7 @@ export type AuthRouteProps<T> =
|
|
|
15
17
|
error?: ErrorBoundaryProps;
|
|
16
18
|
data?: T;
|
|
17
19
|
clientContext?: ClientContext;
|
|
20
|
+
context?: {
|
|
21
|
+
localization?: { labels: LabelMap };
|
|
22
|
+
};
|
|
18
23
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export const addressLabelToPropMapping = {
|
|
2
|
-
name: "
|
|
3
|
-
streetAddress: "
|
|
4
|
-
streetNumber: "
|
|
5
|
-
streetAddress2: "
|
|
6
|
-
country: "
|
|
7
|
-
zip: "
|
|
8
|
-
state: "
|
|
9
|
-
city: "
|
|
10
|
-
geoCoordinates: "
|
|
11
|
-
types: "
|
|
2
|
+
name: "shared.labels.addressName",
|
|
3
|
+
streetAddress: "shared.labels.streetAddress",
|
|
4
|
+
streetNumber: "shared.labels.streetNumber",
|
|
5
|
+
streetAddress2: "shared.labels.streetAddress2",
|
|
6
|
+
country: "shared.labels.country",
|
|
7
|
+
zip: "shared.labels.postalCode",
|
|
8
|
+
state: "shared.labels.state",
|
|
9
|
+
city: "shared.labels.city",
|
|
10
|
+
geoCoordinates: "shared.labels.geoCoordinate",
|
|
11
|
+
types: "shared.labels.addressType",
|
|
12
12
|
};
|
|
@@ -1,30 +1,35 @@
|
|
|
1
1
|
import { buyerPortalRoutes } from "./buyerPortalRoutes";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
3
|
+
import type { LocalizeFn } from "../localization/types";
|
|
4
|
+
|
|
5
|
+
export const getContractSettingsLinks = (
|
|
6
|
+
{
|
|
7
|
+
orgUnitId,
|
|
8
|
+
contractId,
|
|
9
|
+
}: {
|
|
10
|
+
orgUnitId: string;
|
|
11
|
+
contractId: string;
|
|
12
|
+
},
|
|
13
|
+
t: LocalizeFn
|
|
14
|
+
) => [
|
|
10
15
|
{
|
|
11
|
-
name: "
|
|
16
|
+
name: t("layouts.navigation.profile"),
|
|
12
17
|
link: buyerPortalRoutes.profileDetails({ orgUnitId, contractId }),
|
|
13
18
|
},
|
|
14
19
|
{
|
|
15
|
-
name: "
|
|
20
|
+
name: t("layouts.navigation.addresses"),
|
|
16
21
|
link: buyerPortalRoutes.addresses({ orgUnitId, contractId }),
|
|
17
22
|
},
|
|
18
23
|
{
|
|
19
|
-
name: "
|
|
24
|
+
name: t("layouts.navigation.paymentMethods"),
|
|
20
25
|
link: buyerPortalRoutes.paymentMethods({ orgUnitId, contractId }),
|
|
21
26
|
},
|
|
22
27
|
{
|
|
23
|
-
name: "
|
|
28
|
+
name: t("layouts.navigation.creditCards"),
|
|
24
29
|
link: buyerPortalRoutes.creditCards({ orgUnitId, contractId }),
|
|
25
30
|
},
|
|
26
31
|
{
|
|
27
|
-
name: "
|
|
32
|
+
name: t("layouts.navigation.assortments"),
|
|
28
33
|
link: buyerPortalRoutes.productAssortment({ orgUnitId, contractId }),
|
|
29
34
|
},
|
|
30
35
|
];
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import { buyerPortalRoutes } from "./buyerPortalRoutes";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
3
|
+
import type { LocalizeFn } from "../localization/types";
|
|
4
|
+
|
|
5
|
+
export const getFinanceSettingsLinks = (
|
|
6
|
+
{
|
|
7
|
+
orgUnitId,
|
|
8
|
+
contractId,
|
|
9
|
+
}: {
|
|
10
|
+
orgUnitId: string;
|
|
11
|
+
contractId: string;
|
|
12
|
+
},
|
|
13
|
+
t: LocalizeFn
|
|
14
|
+
) => [
|
|
10
15
|
{
|
|
11
|
-
name: "
|
|
16
|
+
name: t("layouts.navigation.budgets"),
|
|
12
17
|
link: buyerPortalRoutes.budgets({ orgUnitId, contractId }),
|
|
13
18
|
},
|
|
14
19
|
{
|
|
15
|
-
name: "
|
|
20
|
+
name: t("layouts.navigation.buyingPolicies"),
|
|
16
21
|
link: buyerPortalRoutes.buyingPolicies({ orgUnitId, contractId }),
|
|
17
22
|
},
|
|
18
23
|
];
|
|
@@ -5,6 +5,6 @@ export const getKeyByValue = (object: Dictionary<string>, value: string) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
export const sortingOptions: Dictionary<string> = {
|
|
8
|
-
|
|
9
|
-
"
|
|
8
|
+
"shared.labels.users": "users",
|
|
9
|
+
"shared.labels.shippingAddresses": "addresses",
|
|
10
10
|
};
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import { buyerPortalRoutes } from "./buyerPortalRoutes";
|
|
2
2
|
|
|
3
|
+
import type { LocalizeFn } from "../localization/types";
|
|
4
|
+
|
|
3
5
|
export const getOrganizationSettingsLinks = ({
|
|
4
6
|
orgUnitId,
|
|
5
7
|
contractId,
|
|
8
|
+
t,
|
|
6
9
|
}: {
|
|
7
10
|
orgUnitId: string;
|
|
8
11
|
contractId?: string;
|
|
12
|
+
t: LocalizeFn;
|
|
9
13
|
}) => [
|
|
10
|
-
{ name: "Users", link: buyerPortalRoutes.users({ orgUnitId, contractId }) },
|
|
11
|
-
{ name: "Roles", link: buyerPortalRoutes.roles({ orgUnitId, contractId }) },
|
|
12
14
|
{
|
|
13
|
-
name: "
|
|
15
|
+
name: t("layouts.navigation.users"),
|
|
16
|
+
link: buyerPortalRoutes.users({ orgUnitId, contractId }),
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: t("layouts.navigation.roles"),
|
|
20
|
+
link: buyerPortalRoutes.roles({ orgUnitId, contractId }),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: t("layouts.navigation.organizationalUnits"),
|
|
14
24
|
link: buyerPortalRoutes.orgUnits({ orgUnitId, contractId }),
|
|
15
25
|
},
|
|
16
26
|
];
|
|
@@ -2,17 +2,22 @@ import { buyerPortalRoutes } from "./buyerPortalRoutes";
|
|
|
2
2
|
import { getFinanceSettingsLinks } from "./getFinanceSettingsLinks";
|
|
3
3
|
import { getOrganizationSettingsLinks } from "./getOrganizationSettingsLinks";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
5
|
+
import type { LocalizeFn } from "../localization/types";
|
|
6
|
+
|
|
7
|
+
export const getSumaListingSidebarLinks = (
|
|
8
|
+
{
|
|
9
|
+
orgUnitId,
|
|
10
|
+
contractId,
|
|
11
|
+
}: {
|
|
12
|
+
orgUnitId: string;
|
|
13
|
+
contractId: string;
|
|
14
|
+
},
|
|
15
|
+
t: LocalizeFn
|
|
16
|
+
) => [
|
|
12
17
|
{
|
|
13
|
-
name: "
|
|
18
|
+
name: t("layouts.navigation.contracts"),
|
|
14
19
|
link: buyerPortalRoutes.contracts({ orgUnitId }),
|
|
15
20
|
},
|
|
16
|
-
...getOrganizationSettingsLinks({ orgUnitId,
|
|
17
|
-
...getFinanceSettingsLinks({ orgUnitId, contractId }),
|
|
21
|
+
...getOrganizationSettingsLinks({ orgUnitId, t }),
|
|
22
|
+
...getFinanceSettingsLinks({ orgUnitId, contractId }, t),
|
|
18
23
|
];
|
|
@@ -14,81 +14,81 @@ export const ROUTE_TABS_LAYOUT_MAPPING: Record<string, RouteTabsLayoutConfig> =
|
|
|
14
14
|
{
|
|
15
15
|
"/pvt/organization-account/profile/[orgUnitId]/[contractId]": {
|
|
16
16
|
layout: "ContractTabsLayout",
|
|
17
|
-
pageName: "
|
|
18
|
-
pageTitle: "
|
|
17
|
+
pageName: "layouts.tabs.contract",
|
|
18
|
+
pageTitle: "layouts.titles.profile",
|
|
19
19
|
},
|
|
20
20
|
"/pvt/organization-account/addresses/[orgUnitId]/[contractId]": {
|
|
21
21
|
layout: "ContractTabsLayout",
|
|
22
|
-
pageName: "
|
|
23
|
-
pageTitle: "
|
|
22
|
+
pageName: "layouts.tabs.contract",
|
|
23
|
+
pageTitle: "layouts.titles.addresses",
|
|
24
24
|
},
|
|
25
25
|
"/pvt/organization-account/address/[orgUnitId]/[contractId]/[addressId]": {
|
|
26
26
|
layout: "ContractTabsLayout",
|
|
27
|
-
pageName: "
|
|
28
|
-
pageTitle: "
|
|
27
|
+
pageName: "layouts.tabs.contract",
|
|
28
|
+
pageTitle: "layouts.titles.addressDetails",
|
|
29
29
|
},
|
|
30
30
|
"/pvt/organization-account/payment-groups/[orgUnitId]/[contractId]": {
|
|
31
31
|
layout: "ContractTabsLayout",
|
|
32
|
-
pageName: "
|
|
33
|
-
pageTitle: "
|
|
32
|
+
pageName: "layouts.tabs.contract",
|
|
33
|
+
pageTitle: "layouts.titles.paymentMethods",
|
|
34
34
|
},
|
|
35
35
|
"/pvt/organization-account/credit-cards/[orgUnitId]/[contractId]": {
|
|
36
36
|
layout: "ContractTabsLayout",
|
|
37
|
-
pageName: "
|
|
38
|
-
pageTitle: "
|
|
37
|
+
pageName: "layouts.tabs.contract",
|
|
38
|
+
pageTitle: "layouts.titles.creditCards",
|
|
39
39
|
},
|
|
40
40
|
"/pvt/organization-account/product-assortment/[orgUnitId]/[contractId]": {
|
|
41
41
|
layout: "ContractTabsLayout",
|
|
42
|
-
pageName: "
|
|
43
|
-
pageTitle: "
|
|
42
|
+
pageName: "layouts.tabs.contract",
|
|
43
|
+
pageTitle: "layouts.titles.assortments",
|
|
44
44
|
},
|
|
45
45
|
"/pvt/organization-account/accounting-field/[orgUnitId]/[contractId]/[accountingFieldId]":
|
|
46
46
|
{
|
|
47
47
|
layout: "ContractTabsLayout",
|
|
48
|
-
pageName: "
|
|
49
|
-
pageTitle: "
|
|
48
|
+
pageName: "layouts.tabs.contract",
|
|
49
|
+
pageTitle: "layouts.titles.accountingField",
|
|
50
50
|
},
|
|
51
51
|
"/pvt/organization-account/buying-policies/[orgUnitId]/[contractId]": {
|
|
52
52
|
layout: "FinanceTabsLayout",
|
|
53
|
-
pageName: "
|
|
54
|
-
pageTitle: "
|
|
53
|
+
pageName: "layouts.tabs.financeAndCompliance",
|
|
54
|
+
pageTitle: "layouts.titles.buyingPolicies",
|
|
55
55
|
},
|
|
56
56
|
"/pvt/organization-account/buying-policy/[orgUnitId]/[contractId]/[buyingPolicyId]":
|
|
57
57
|
{
|
|
58
58
|
layout: "FinanceTabsLayout",
|
|
59
|
-
pageName: "
|
|
60
|
-
pageTitle: "
|
|
59
|
+
pageName: "layouts.tabs.financeAndCompliance",
|
|
60
|
+
pageTitle: "layouts.titles.buyingPolicyDetails",
|
|
61
61
|
},
|
|
62
62
|
|
|
63
63
|
"/pvt/organization-account/roles/[orgUnitId]": {
|
|
64
64
|
layout: "OrgUnitTabsLayout",
|
|
65
|
-
pageName: "
|
|
66
|
-
pageTitle: "
|
|
65
|
+
pageName: "layouts.tabs.organization",
|
|
66
|
+
pageTitle: "layouts.titles.roles",
|
|
67
67
|
},
|
|
68
68
|
"/pvt/organization-account/roles/[orgUnitId]/[roleName]": {
|
|
69
69
|
layout: "OrgUnitTabsLayout",
|
|
70
|
-
pageName: "
|
|
71
|
-
pageTitle: "
|
|
70
|
+
pageName: "layouts.tabs.organization",
|
|
71
|
+
pageTitle: "layouts.titles.roleDetails",
|
|
72
72
|
},
|
|
73
73
|
"/pvt/organization-account/users/[orgUnitId]": {
|
|
74
74
|
layout: "OrgUnitTabsLayout",
|
|
75
|
-
pageName: "
|
|
76
|
-
pageTitle: "
|
|
75
|
+
pageName: "layouts.tabs.organization",
|
|
76
|
+
pageTitle: "layouts.titles.users",
|
|
77
77
|
},
|
|
78
78
|
"/pvt/organization-account/user/[orgUnitId]/[userId]": {
|
|
79
79
|
layout: "OrgUnitTabsLayout",
|
|
80
|
-
pageName: "
|
|
81
|
-
pageTitle: "
|
|
80
|
+
pageName: "layouts.tabs.organization",
|
|
81
|
+
pageTitle: "layouts.titles.userDetails",
|
|
82
82
|
},
|
|
83
83
|
"/pvt/organization-account/org-units/[orgUnitId]": {
|
|
84
84
|
layout: "OrgUnitTabsLayout",
|
|
85
|
-
pageName: "
|
|
86
|
-
pageTitle: "
|
|
85
|
+
pageName: "layouts.tabs.organization",
|
|
86
|
+
pageTitle: "layouts.titles.organizationDetails",
|
|
87
87
|
},
|
|
88
88
|
"/pvt/organization-account/org-unit/[orgUnitId]": {
|
|
89
89
|
layout: "OrgUnitDetailsLayout",
|
|
90
|
-
pageName: "
|
|
91
|
-
pageTitle: "
|
|
90
|
+
pageName: "layouts.tabs.organization",
|
|
91
|
+
pageTitle: "layouts.titles.organizationDetails",
|
|
92
92
|
},
|
|
93
93
|
};
|
|
94
94
|
|
|
@@ -8,6 +8,11 @@ export const statusFilters: Dictionary<boolean> = {
|
|
|
8
8
|
Inativo: false,
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
export const statusFilterI18nKeys: Dictionary<string> = {
|
|
12
|
+
Ativo: "shared.labels.active",
|
|
13
|
+
Inativo: "shared.labels.inactive",
|
|
14
|
+
};
|
|
15
|
+
|
|
11
16
|
export const userTypesFilters = ["Admin", "Buyer"];
|
|
12
17
|
|
|
13
18
|
export const sortingOptions: Dictionary<string> = {
|
|
@@ -15,6 +20,11 @@ export const sortingOptions: Dictionary<string> = {
|
|
|
15
20
|
"Alphabetical Order Desc": "name",
|
|
16
21
|
};
|
|
17
22
|
|
|
23
|
+
export const sortingOptionI18nKeys: Dictionary<string> = {
|
|
24
|
+
"Alphabetical Order": "shared.labels.alphabeticalOrder",
|
|
25
|
+
"Alphabetical Order Desc": "shared.labels.alphabeticalOrderDesc",
|
|
26
|
+
};
|
|
27
|
+
|
|
18
28
|
export const updateSort = (arrayToSort: any[], selectedOption: string) => {
|
|
19
29
|
switch (selectedOption) {
|
|
20
30
|
case "Alphabetical Order": {
|
|
@@ -31,10 +31,16 @@ export const withAuth = <T extends Record<string, unknown>>(
|
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// In the error case props.data is undefined; forward props.context so withLocalization
|
|
35
|
+
// can read localization labels. In the success case context comes from props.data spread.
|
|
36
|
+
const errorContext =
|
|
37
|
+
!props?.authorized && "context" in props ? props.context : undefined;
|
|
38
|
+
|
|
34
39
|
// If authorized, render the component with the data
|
|
35
40
|
return (
|
|
36
41
|
<Component
|
|
37
42
|
{...(props.data as T)}
|
|
43
|
+
{...(errorContext ? { context: errorContext } : {})}
|
|
38
44
|
hasError={props?.hasError}
|
|
39
45
|
error={props?.error}
|
|
40
46
|
/>
|