Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Fixed
- UserWidget now displays organization selector modal when current organization status is "on-hold" or "inactive"
- Allow widget rendering even when cost center is unavailable for organizations with "on-hold" or "inactive" status
- Add visual warning messages in modal for organizations with "on-hold" or "inactive" status

### Added
- New translation keys for organization status warnings: `user-widget.organization-on-hold-warning` and `user-widget.organization-inactive-warning`
- "Change Organization" button now appears when organization is "on-hold" or "inactive", even with single organization
- ErrorPolicy 'all' to GraphQL query to handle partial data when organization has non-active status

## [3.1.3] - 2026-01-15

### Fixed
Expand Down
2 changes: 2 additions & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -418,5 +418,7 @@
"store/b2b-organizations.user-widget.status.active": "Active",
"store/b2b-organizations.user-widget.status.inactive": "Inactive",
"store/b2b-organizations.user-widget.status.on-hold": "On Hold",
"store/b2b-organizations.user-widget.organization-on-hold-warning": "Your current organization is on hold. Please select an active organization to continue.",
"store/b2b-organizations.user-widget.organization-inactive-warning": "Your current organization is inactive. Please select an active organization to continue.",
"store/b2b-organizations.warning-topbar-inative-org.message": "Your organization's account is paused, and you cannot complete purchases now."
}
2 changes: 2 additions & 0 deletions messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -418,5 +418,7 @@
"store/b2b-organizations.user-widget.status.active": "Ativa",
"store/b2b-organizations.user-widget.status.inactive": "Inativa",
"store/b2b-organizations.user-widget.status.on-hold": "Em espera",
"store/b2b-organizations.user-widget.organization-on-hold-warning": "Sua organização atual está em espera. Por favor, selecione uma organização ativa para continuar.",
"store/b2b-organizations.user-widget.organization-inactive-warning": "Sua organização atual está inativa. Por favor, selecione uma organização ativa para continuar.",
"store/b2b-organizations.warning-topbar-inative-org.message": "A conta da sua organização está pausada e você não pode concluir compras agora. Entre em contato conosco para obter mais informações."
}
84 changes: 66 additions & 18 deletions react/components/UserWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ const UserWidget: VtexFunctionComponent<UserWidgetProps> = ({
{
ssr: false,
skip: !isAuthenticated,
errorPolicy: 'all',
}
) as any

Expand Down Expand Up @@ -324,6 +325,11 @@ const UserWidget: VtexFunctionComponent<UserWidgetProps> = ({
}

const uiSettings = userWidgetData?.getB2BSettings?.uiSettings
const currentOrgStatus =
userWidgetData?.getOrganizationByIdStorefront?.status

const isCurrentOrgOnHold =
currentOrgStatus === 'on-hold' || currentOrgStatus === 'inactive'

if (uiSettings?.showModal) {
const totalCompanies =
Expand All @@ -333,9 +339,14 @@ const UserWidget: VtexFunctionComponent<UserWidgetProps> = ({
SESSION_STORAGE_SHOW_MODAL
)

setShowModal(totalCompanies > 1 && !storageShowModal)
// Forçar modal se organização atual está on-hold/inactive OU se há múltiplas organizações
setShowModal(
(totalCompanies > 1 && !storageShowModal) || isCurrentOrgOnHold
)

sessionStorage.setItem(SESSION_STORAGE_SHOW_MODAL, 'true')
if (!isCurrentOrgOnHold) {
sessionStorage.setItem(SESSION_STORAGE_SHOW_MODAL, 'true')
}
}

const currentOrganization =
Expand Down Expand Up @@ -446,16 +457,29 @@ const UserWidget: VtexFunctionComponent<UserWidgetProps> = ({
)
}

// Permitir renderização se houver organizações ativas, mesmo que a atual esteja on-hold
// Quando organização está on-hold, o cost center pode ser null, mas ainda assim deve mostrar o modal
if (
!isAuthenticated ||
!userWidgetData?.checkUserPermission ||
!userWidgetData?.getOrganizationByIdStorefront ||
!userWidgetData?.getCostCenterByIdStorefront
!userWidgetData?.getActiveOrganizationsByEmail
)
return null

// Se não há cost center e a org está on-hold/inactive, ainda permitir renderização para trocar
const isOrgOnHoldOrInactive =
userWidgetData?.getOrganizationByIdStorefront?.status === 'on-hold' ||
userWidgetData?.getOrganizationByIdStorefront?.status === 'inactive'

if (!userWidgetData?.getCostCenterByIdStorefront && !isOrgOnHoldOrInactive) {
return null
}

const handleSearchOrganizations = (e: any) => setSearchTerm(e.target.value)

const hasMultipleOrganizations =
(userWidgetData?.getActiveOrganizationsByEmail?.length ?? 0) > 1

const dataList =
userWidgetData?.getActiveOrganizationsByEmail
?.sort(sortOrganizations)
Expand Down Expand Up @@ -529,12 +553,34 @@ const UserWidget: VtexFunctionComponent<UserWidgetProps> = ({
<h2 className={`${handles.userWidgetModalH2} flex`}>
{formatMessage(messages.currentOrganization)}
</h2>
<h3
className={`${handles.userWidgetModalH3} flex`}
>{`${userWidgetData?.getOrganizationByIdStorefront?.name}`}</h3>
<h4
className={`${handles.userWidgetModalH4} flex`}
>{`${userWidgetData?.getCostCenterByIdStorefront?.name}`}</h4>
{userWidgetData?.getOrganizationByIdStorefront?.status !==
'active' && (
<div className="bg-warning--faded pa4 br2 mb4">
<p className="f5 fw6 c-warning">
{userWidgetData?.getOrganizationByIdStorefront?.status ===
'on-hold'
? formatMessage(messages.organizationOnHoldWarning)
: formatMessage(messages.organizationInactiveWarning)}
</p>
</div>
)}
{userWidgetData?.getOrganizationByIdStorefront?.name && (
<h3 className={`${handles.userWidgetModalH3} flex`}>
{userWidgetData.getOrganizationByIdStorefront.name}
</h3>
)}
{userWidgetData?.getCostCenterByIdStorefront?.name && (
<h4 className={`${handles.userWidgetModalH4} flex`}>
{userWidgetData.getCostCenterByIdStorefront.name}
</h4>
)}
{userWidgetData?.getOrganizationByIdStorefront?.status && (
<div className="mt3">
{handleStatusMessage(
userWidgetData.getOrganizationByIdStorefront.status
)}
</div>
)}
</div>
</div>
</Modal>
Expand All @@ -546,21 +592,23 @@ const UserWidget: VtexFunctionComponent<UserWidgetProps> = ({
>
<div className={`${handles.userWidgetCompanyName} mr4`}>
{`${formatMessage(messages.organization)} ${
userWidgetData?.getOrganizationByIdStorefront?.name
}`}
</div>
<div className={`${handles.userWidgetCostCenterName} mr4`}>
{`${formatMessage(messages.costCenter)} ${
userWidgetData?.getCostCenterByIdStorefront?.name
userWidgetData?.getOrganizationByIdStorefront?.name ?? ''
}`}
</div>
{userWidgetData?.getCostCenterByIdStorefront?.name && (
<div className={`${handles.userWidgetCostCenterName} mr4`}>
{`${formatMessage(messages.costCenter)} ${
userWidgetData?.getCostCenterByIdStorefront?.name
}`}
</div>
)}
<div className={`${handles.userWidgetRole}`}>
{`${formatMessage(messages.role)} ${
organizationsState.currentRoleName
organizationsState.currentRoleName ?? ''
}`}
</div>
<div className="ml-auto">
{userWidgetData?.getActiveOrganizationsByEmail?.length > 1 && (
{(hasMultipleOrganizations || isOrgOnHoldOrInactive) && (
<Button variant="primary" onClick={() => setShowModal(true)}>
{formatMessage(messages.changeOrganization)}
</Button>
Expand Down
6 changes: 6 additions & 0 deletions react/components/utils/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,4 +375,10 @@ export const userWidgetMessages = defineMessages({
organizationsFound: {
id: `${storePrefix}organizations-found`,
},
organizationOnHoldWarning: {
id: `${storePrefix}user-widget.organization-on-hold-warning`,
},
organizationInactiveWarning: {
id: `${storePrefix}user-widget.organization-inactive-warning`,
},
})
Loading