@dashadmin/dash-admin 1.3.73 → 1.3.74-srcfree.1
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/dist/components/tenant/TenancyPlan.js +307 -0
- package/dist/systemResources.js +18 -2
- package/package.json +25 -22
- package/src/AppAsyncWrapper.tsx +0 -42
- package/src/AppWrapper.tsx +0 -45
- package/src/DASHAdmin.tsx +0 -502
- package/src/DASHAdmin.tsx.old +0 -456
- package/src/RoutingWrapper.tsx +0 -143
- package/src/classes/DASHStorageClass.tsx +0 -8
- package/src/components/Input/RichTextField.tsx +0 -27
- package/src/components/Redirect.tsx +0 -46
- package/src/components/avatar/Avatar.tsx +0 -71
- package/src/components/avatar/SingleImageUploader.tsx +0 -107
- package/src/components/currency/Format.tsx +0 -79
- package/src/components/custom/Redirect.tsx +0 -23
- package/src/components/error/Error.tsx +0 -168
- package/src/components/geocoding/GeocodingField.tsx +0 -167
- package/src/components/i18n/BridgedLocalesMenuButton.tsx +0 -160
- package/src/components/i18n/LangSwitcher.tsx +0 -204
- package/src/components/loader/GlobalLoader.tsx +0 -49
- package/src/components/logs/LogFile.tsx +0 -88
- package/src/components/logs/LogFileById.tsx +0 -68
- package/src/components/logs/LogViewer.tsx +0 -43
- package/src/components/menu/AppMenu.tsx +0 -22
- package/src/components/menu/CustomMenuItemLink.tsx +0 -61
- package/src/components/menu/DarkToggleMode.tsx +0 -65
- package/src/components/menu/LanguageToggleMode.tsx +0 -120
- package/src/components/misc/CustomImageInput.tsx +0 -62
- package/src/components/misc/DASHGlobalErrorHandler.tsx +0 -194
- package/src/components/misc/DarkModeSwitcher.tsx +0 -112
- package/src/components/misc/HorizontalScroller.tsx +0 -225
- package/src/components/misc/LanguageSwitcher.tsx +0 -199
- package/src/components/misc/MUIHtmlToolTip.tsx +0 -15
- package/src/components/misc/MuiSimpleJsonTable.tsx +0 -279
- package/src/components/misc/MultiLevelTable.tsx +0 -229
- package/src/components/misc/NoResults.tsx +0 -28
- package/src/components/misc/PDFViewer.tsx +0 -85
- package/src/components/navigation/Breadcrumbs.tsx +0 -220
- package/src/components/navigation/BreadcrumbsManager.tsx +0 -310
- package/src/components/navigation/index.tsx +0 -5
- package/src/components/panel/Error.tsx +0 -168
- package/src/components/permission/AvailablePermissionsContext.tsx +0 -173
- package/src/components/permission/PermissionsSelector.tsx +0 -834
- package/src/components/permission/PermissionsSelectorList.tsx +0 -473
- package/src/components/permission/tsx +0 -0
- package/src/components/racustombuttons/CustomRAButton.tsx +0 -87
- package/src/components/racustombuttons/QuickButton.tsx +0 -117
- package/src/components/racustombuttons/QuickEditButton.tsx +0 -115
- package/src/components/racustombuttons/QuickIconButton.tsx +0 -122
- package/src/components/scrollbar/Scrollbar.tsx +0 -31
- package/src/components/selects/MultiSelect.tsx +0 -53
- package/src/components/selects/RASearchableSelect.tsx +0 -282
- package/src/components/selects/RASearchableSelectChips.tsx +0 -308
- package/src/components/selects/SearchableSelect.tsx +0 -139
- package/src/components/serviceAccount/ApiKeyRevealDialog.tsx +0 -129
- package/src/components/serviceAccount/ServiceAccountStatusSwitch.tsx +0 -99
- package/src/components/subscription/BillingCycleSelectInput.tsx +0 -68
- package/src/components/subscription/PlanAddonsSettings.tsx +0 -563
- package/src/components/subscription/PlanAuditLog.tsx +0 -453
- package/src/components/subscription/PlanFeaturesSettings.tsx +0 -243
- package/src/components/subscription/PlanLimitsSettings.tsx +0 -230
- package/src/components/subscription/PlanMetadataSettings.tsx +0 -306
- package/src/components/subscription/PlanPricesSettings.tsx +0 -307
- package/src/components/subscription/index.ts +0 -7
- package/src/components/svgelements/SvgLoading.tsx +0 -229
- package/src/components/svgelements/SvgLogo.tsx +0 -53
- package/src/components/svgelements/SvgLogoMin.tsx +0 -64
- package/src/components/svgelements/SvgShipping.tsx +0 -673
- package/src/components/tenancy/GlobalTenantWrapper.tsx +0 -84
- package/src/components/tenancy/TenantSwitcher.tsx +0 -514
- package/src/components/tenant/AvailablePermissionsContext.tsx +0 -0
- package/src/components/tenant/SettingsSections.tsx +0 -151
- package/src/components/tenant/TenancySettings.tsx +0 -122
- package/src/components/tenant/TenantAttributes.tsx +0 -153
- package/src/components/tenant/TenantAttributesContext.tsx +0 -163
- package/src/components/tenant/TenantSelector.tsx +0 -142
- package/src/components/tenant/TenantSettings.tsx +0 -184
- package/src/components/tenant/TenantSettingsContext.tsx +0 -165
- package/src/components/tenant/TenantTheme.tsx +0 -172
- package/src/components/user/AvatarComponent.tsx +0 -317
- package/src/components/user/TenantAvatarComponent.tsx +0 -99
- package/src/components/user/UserPreferences.tsx +0 -677
- package/src/config/ACTIONS.tsx +0 -26
- package/src/config/ConstantsService.tsx +0 -44
- package/src/config/DASHAdminSystemConstants.tsx +0 -183
- package/src/config/PARSERS.tsx +0 -9
- package/src/contexts/DashQueryClientContext.tsx +0 -113
- package/src/contexts/DashResourceContext.tsx +0 -34
- package/src/contexts/I18nBridgeContext.tsx +0 -156
- package/src/contexts/I18nBridgeSetter.tsx +0 -39
- package/src/contexts/I18nReduxSync.tsx +0 -27
- package/src/contexts/SubscriptionPlanFormatsProvider.tsx +0 -217
- package/src/contexts/SystemRequestsCache.tsx +0 -215
- package/src/contexts/auth/AuthContext.tsx +0 -567
- package/src/contexts/auth/AuthContextLocalStorage.tsx +0 -140
- package/src/contexts/auth/DASHAuthenticationService.tsx +0 -915
- package/src/contexts/auth/WindowContext.tsx +0 -15
- package/src/contexts/auth/index.tsx +0 -3
- package/src/contexts/com/FCMContext.tsx +0 -415
- package/src/contexts/com/LaravelEchoContext.tsx +0 -41
- package/src/contexts/com/LaravelEchoMgr.tsx +0 -155
- package/src/contexts/com/components/DefaultNotificationComponent.tsx +0 -20
- package/src/contexts/com/components/EchoNotificationsCenter.tsx +0 -65
- package/src/contexts/com/components/NotificationAttributesTable.tsx +0 -54
- package/src/contexts/com/components/NotificationRenderer.tsx +0 -42
- package/src/contexts/com/components/NotificationsWidget.tsx +0 -182
- package/src/contexts/com/components/notificationFormats.tsx +0 -50
- package/src/contexts/com/useLaravelEcho.tsx +0 -432
- package/src/contexts/dictionary/DictionaryContext.tsx +0 -94
- package/src/declarations.d.ts +0 -17
- package/src/default-theme/DASHAppProviders.tsx +0 -117
- package/src/default-theme/DashThemeContext.tsx +0 -209
- package/src/default-theme/DashThemeContext.tsx.fast +0 -143
- package/src/default-theme/DashThemeContext.tsx.old +0 -306
- package/src/default-theme/DashThemeHelperProvider.tsx +0 -98
- package/src/default-theme/DomainAppLayout.tsx +0 -166
- package/src/default-theme/DomainHeader.tsx +0 -162
- package/src/default-theme/DomainTheme.tsx +0 -59
- package/src/default-theme/FullLayoutMarkup.tsx +0 -231
- package/src/default-theme/StaticLayout.tsx +0 -47
- package/src/default-theme/index.tsx +0 -11
- package/src/default-theme/menu/AppDashboardGrid.tsx +0 -279
- package/src/default-theme/menu/AppMaterialMenu.tsx +0 -546
- package/src/default-theme/menu/AppMenuComponents/SubmenuPortal.tsx +0 -61
- package/src/default-theme/menu/AppMenuComponents/collapsed/CollapsedSidebarItem.tsx +0 -264
- package/src/default-theme/menu/AppMenuComponents/collapsed/CollapsedSidebarItems.tsx +0 -31
- package/src/default-theme/menu/AppMenuComponents/expanded/CollapsableSidebarMenu.tsx +0 -293
- package/src/default-theme/menu/AppMenuComponents/expanded/SidebarItem.tsx +0 -92
- package/src/default-theme/menu/AppMenuComponents/getItem.tsx +0 -17
- package/src/default-theme/menu/AppMenuComponents/interfaces.tsx +0 -41
- package/src/default-theme/menu/AppMenuComponents/submenuConstants.ts +0 -90
- package/src/default-theme/menu/AppSidebarMaterial.tsx +0 -339
- package/src/default-theme/menu/SidebarActions.tsx +0 -84
- package/src/default-theme/updateDomCssVariables.tsx +0 -176
- package/src/helpers/checkRole.tsx +0 -66
- package/src/helpers/parseAxiosError.tsx +0 -41
- package/src/hooks/audio/useAudio.tsx +0 -39
- package/src/hooks/axios.tsx +0 -165
- package/src/hooks/data/useDashboardStats.tsx +0 -65
- package/src/hooks/data/usePackageByClientsStats.tsx +0 -44
- package/src/hooks/data/usePackageByCommunesStats.tsx +0 -44
- package/src/hooks/data/usePackageStats.tsx +0 -69
- package/src/hooks/data/usePackageWithdrawDetails.tsx +0 -61
- package/src/hooks/data/useStats.tsx +0 -86
- package/src/hooks/isCurrentPath.tsx +0 -22
- package/src/hooks/notifications/WSMessagesManager.tsx +0 -152
- package/src/hooks/notifications/WSPusherManager.tsx +0 -92
- package/src/hooks/useBreadcrumbs.tsx +0 -329
- package/src/hooks/useClickOutside.tsx +0 -57
- package/src/hooks/useFormPersistance.tsx +0 -150
- package/src/hooks/useGlobalErrorMediator.tsx +0 -43
- package/src/hooks/useGlobalLoaderMgr.tsx +0 -21
- package/src/hooks/useHash.tsx +0 -27
- package/src/hooks/useLocalStorage.tsx +0 -196
- package/src/hooks/usePolyglotTranslation.tsx +0 -62
- package/src/hooks/usePrevious.tsx +0 -9
- package/src/hooks/usePrintSelected.tsx +0 -37
- package/src/hooks/useVirtualHash.tsx +0 -33
- package/src/hooks/window/useWindowSize.tsx +0 -36
- package/src/index.tsx +0 -134
- package/src/interfaces/IAppResourceConfig.tsx +0 -20
- package/src/interfaces/Log.tsx +0 -16
- package/src/interfaces/Tenant.tsx +0 -25
- package/src/interfaces/communication/IActions.tsx +0 -5
- package/src/interfaces/communication/INotification.tsx +0 -21
- package/src/interfaces/communication/IPayload.tsx +0 -3
- package/src/interfaces/communication/IRequestAction.tsx +0 -10
- package/src/interfaces/communication/IRequestPayload.tsx +0 -7
- package/src/interfaces/communication/IResponseAction.tsx +0 -7
- package/src/interfaces/misc/IAny.tsx +0 -3
- package/src/interfaces/misc/IFlashMessage.tsx +0 -10
- package/src/interfaces/navigation/IAppMenu.ts +0 -14
- package/src/interfaces/navigation/ICollapsableSidebarMenu.ts +0 -12
- package/src/interfaces/navigation/IMenuItem.ts +0 -16
- package/src/interfaces/notifications/IModel.tsx +0 -6
- package/src/interfaces/notifications/IModelField.tsx +0 -8
- package/src/interfaces/notifications/IUserNotification.tsx +0 -12
- package/src/interfaces/notifications/IUserNotificationData.tsx +0 -13
- package/src/interfaces/notifications/IUserNotificationPayload.tsx +0 -8
- package/src/interfaces/user/IGetAuth.tsx +0 -92
- package/src/interfaces/user/ITenantSettings.tsx +0 -3
- package/src/interfaces/user/IUser.tsx +0 -60
- package/src/interfaces/user/IUserSettings.tsx +0 -43
- package/src/interfaces.tsx +0 -6
- package/src/layout/AppLayout.tsx +0 -112
- package/src/layout/ApplicationLayout.tsx +0 -197
- package/src/layout/MotionWrapper.original.tsx +0 -236
- package/src/layout/MotionWrapper.tsx +0 -236
- package/src/layout/ResourceMenu.tsx +0 -164
- package/src/layout/ResoureLayout.tsx +0 -105
- package/src/layout/TransitionWrapper.tsx +0 -125
- package/src/pages/ChangePassword.tsx +0 -179
- package/src/pages/DASHLanding.tsx +0 -22
- package/src/pages/DASHLightWeightLogin.tsx +0 -611
- package/src/pages/DASHSimpleLogin.tsx +0 -260
- package/src/pages/Login.tsx +0 -111
- package/src/pages/Profile.tsx +0 -357
- package/src/pages/RecoverPassword.tsx +0 -175
- package/src/pages/SingleImageUploader.tsx +0 -55
- package/src/pages/VerifyAccount.tsx +0 -128
- package/src/providers/authProvider.tsx +0 -217
- package/src/providers/dataProvider.tsx +0 -672
- package/src/providers/i18n/en.ts +0 -646
- package/src/providers/i18n/es.ts +0 -652
- package/src/providers/i18n/languages.tsx +0 -8
- package/src/providers/i18n/mergeTranslations.ts +0 -53
- package/src/providers/i18nProvider.tsx +0 -23
- package/src/react-admin-dash/RADashComponent.tsx +0 -240
- package/src/react-admin-dash/Resource.tsx +0 -77
- package/src/resources/Brand/BrandResource.tsx +0 -130
- package/src/resources/DASHResourceLoader.ts +0 -180
- package/src/resources/Log/LogResource.tsx +0 -73
- package/src/resources/Tenant/ImpersonateTenantResource.tsx +0 -113
- package/src/resources/Trash/TrashTemplate.tsx +0 -180
- package/src/resources/User/components/AvatarUploadField.tsx +0 -57
- package/src/resources/User/components/PasswordFields.tsx +0 -73
- package/src/resources/User/getProfileMenu.ts +0 -57
- package/src/resources/User/profileResource.tsx +0 -51
- package/src/resources/User/userLayout.tsx +0 -62
- package/src/resources/User/userResource.tsx +0 -111
- package/src/resources/User/userSchema.tsx +0 -213
- package/src/resources/User/usersFilters.tsx +0 -21
- package/src/resources.tsx +0 -280
- package/src/schemas/log.tsx +0 -45
- package/src/schemas/notification.tsx +0 -42
- package/src/schemas/permissions.tsx +0 -44
- package/src/schemas/roles.tsx +0 -48
- package/src/schemas/rolesDataGrid.tsx +0 -48
- package/src/schemas/subscription/components/SubscriptionActions.tsx +0 -153
- package/src/schemas/subscription/components/SubscriptionPaymentHistory.tsx +0 -127
- package/src/schemas/subscription/components/SubscriptionPlanFeatures.tsx +0 -162
- package/src/schemas/subscription/components/SubscriptionPlanPreview.tsx +0 -141
- package/src/schemas/subscription/components/SubscriptionPlanStats.tsx +0 -318
- package/src/schemas/subscription/components/SubscriptionStatusIndicator.tsx +0 -72
- package/src/schemas/subscription/subscriptionPlanSchema.tsx +0 -185
- package/src/schemas/subscription/subscriptionSchema.tsx +0 -152
- package/src/schemas/subscriptionPlan.ts +0 -422
- package/src/schemas/tenant.tsx +0 -129
- package/src/schemas/tenantUser.tsx +0 -96
- package/src/schemas/tenant_superadmin.tsx +0 -119
- package/src/schemas/user.tsx +0 -26
- package/src/systemResources.old.tsx +0 -928
- package/src/systemResources.tsx +0 -1369
- package/src/templates/ResourceTemplate.tsx +0 -240
- package/src/templates/ResourceTemplate.tsx.memoized_experiment +0 -350
- package/src/templates/ResourceTemplate.tsx.original +0 -396
- package/src/templates/ResourceTemplateCreate.tsx +0 -182
- package/src/templates/ResourceTemplateEdit.tsx +0 -176
- package/src/templates/ResourceTemplateFull.tsx +0 -581
- package/src/templates/ResourceTemplateList.tsx +0 -340
- package/src/templates/ResourceTemplateOld.tsx.bkup +0 -567
- package/src/templates/ResourceTemplateShow.tsx +0 -88
- package/src/templates/TrashTemplate.tsx +0 -179
- package/src/tenantResources.tsx +0 -223
- package/src/test_portal_bubbles.tsx +0 -40
- package/src/theme/AppHeader.tsx +0 -52
- package/src/theme/AppLayoutSetting.tsx +0 -33
- package/src/theme/AppLogo.tsx +0 -13
- package/src/theme/AppSidebar.tsx +0 -12
- package/src/theme/AppSidebarContent.tsx +0 -105
- package/src/theme/AppSidebarLogo.tsx +0 -48
- package/src/theme/components/PageTitle.tsx +0 -37
- package/src/utils/cache/CacheInvalidatorContext.tsx +0 -125
- package/src/utils/cache/CacheInvalidatorListenerComponent.tsx +0 -10
- package/src/utils/cache/useCacheInvalidatorListener.tsx +0 -27
- package/src/utils/convertFileToBase64.tsx +0 -9
- package/src/utils/convertToFile.tsx +0 -14
- package/src/utils/cookies.tsx +0 -33
- package/src/utils/dashDefaultQueryClient.tsx +0 -34
- package/src/utils/dataUrlToBlob.tsx +0 -30
- package/src/utils/deepReplace.tsx +0 -19
- package/src/utils/getProfileMenu.tsx +0 -41
- package/src/utils/getTenantSettings.tsx +0 -9
- package/src/utils/getType.tsx +0 -8
- package/src/utils/getUserSettings.tsx +0 -8
- package/src/utils/hasCode.tsx +0 -14
- package/src/utils/index.ts +0 -19
- package/src/utils/injectTenantStyles.ts +0 -28
- package/src/utils/isComponent.tsx +0 -45
- package/src/utils/navEvents.tsx +0 -91
- package/src/utils/prototypes.tsx +0 -5
- package/src/utils/regexp.tsx +0 -4
- package/src/utils/resolveObjectPath.tsx +0 -4
- package/src/utils/setNativeValue.tsx +0 -24
- package/src/utils/slugify.tsx +0 -11
- package/src/utils/validators/emailValidator.tsx +0 -6
- package/src/utils/validators/requiredValidator.tsx +0 -5
- package/src/utils/validators/rutValidator.tsx +0 -31
- package/src/utils/validators.tsx +0 -96
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GlobalTenantWrapper
|
|
3
|
-
*
|
|
4
|
-
* Tenant Data Fetcher Component that runs inside DashThemeProvider — takes
|
|
5
|
-
* tenant data (fetched by a mall/self-service session flow, before any user
|
|
6
|
-
* authentication exists) and:
|
|
7
|
-
* - Sets panel-settings logos in Redux from the tenant's images
|
|
8
|
-
* - Recreates the MUI theme from the tenant's theme settings
|
|
9
|
-
* - Persists a "public" auth shape (tenant only, no user) via
|
|
10
|
-
* AuthPersistenceService, so the rest of the app can read tenant context
|
|
11
|
-
*
|
|
12
|
-
* Consolidated 2026-08-03 from seven byte-identical app-level copies. Two of
|
|
13
|
-
* its five real consumers (kitchntabs-app's and vanexa-app's
|
|
14
|
-
* kt-kiosk/components/MallClientWrapper.tsx) had a stale, commented-out
|
|
15
|
-
* import with a wrong path — GlobalTenantWrapper was referenced in JSX but
|
|
16
|
-
* never actually imported, a pre-existing bug fixed as part of repointing
|
|
17
|
-
* those call sites here.
|
|
18
|
-
*/
|
|
19
|
-
import { AuthPersistenceService } from "dash-auth";
|
|
20
|
-
import { DASH_REDUX_ACTIONS } from "dash-admin-state";
|
|
21
|
-
import { useDispatch } from "react-redux";
|
|
22
|
-
import DashThemeContext from '../../default-theme/DashThemeContext';
|
|
23
|
-
import React, { PropsWithChildren, useEffect } from "react";
|
|
24
|
-
|
|
25
|
-
export interface IGlobalTenantWrapper extends PropsWithChildren {
|
|
26
|
-
tenantData?: any;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Tenant Data Fetcher Component that runs inside DashThemeProvider
|
|
30
|
-
const GlobalTenantWrapper: React.FC<IGlobalTenantWrapper> = (props) => {
|
|
31
|
-
const {
|
|
32
|
-
tenantData = null,
|
|
33
|
-
children
|
|
34
|
-
} = props;
|
|
35
|
-
|
|
36
|
-
const dispatch = useDispatch();
|
|
37
|
-
const themeContext = React.useContext(DashThemeContext);
|
|
38
|
-
const recreateTheme = themeContext?.recreateTheme;
|
|
39
|
-
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
if (!tenantData) {
|
|
42
|
-
// No data to process
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Process tenant images for panel settings
|
|
47
|
-
if (tenantData.tenantImages) {
|
|
48
|
-
const logos = {
|
|
49
|
-
...(tenantData.tenantImages.horizontal_logo?.original && {
|
|
50
|
-
horizontalLogo: tenantData.tenantImages.horizontal_logo.original
|
|
51
|
-
}),
|
|
52
|
-
...(tenantData.tenantImages.squared_logo?.original && {
|
|
53
|
-
squaredLogo: tenantData.tenantImages.squared_logo.original
|
|
54
|
-
}),
|
|
55
|
-
...(tenantData.tenantImages.banner?.original && {
|
|
56
|
-
loginBackground: tenantData.tenantImages.banner.original
|
|
57
|
-
})
|
|
58
|
-
};
|
|
59
|
-
dispatch(DASH_REDUX_ACTIONS.setPanelSettings(logos));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Process tenant settings for theme
|
|
63
|
-
if (tenantData.tenantSettings && recreateTheme) {
|
|
64
|
-
recreateTheme(tenantData.tenantSettings);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Store tenant data for persistence (without user authentication)
|
|
68
|
-
const publicAuthData = {
|
|
69
|
-
auth: {
|
|
70
|
-
tenantImages: tenantData.tenantImages,
|
|
71
|
-
tenantSettings: tenantData.tenantSettings,
|
|
72
|
-
tenant: tenantData.tenant,
|
|
73
|
-
},
|
|
74
|
-
systemValues: tenantData.systemValues
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
AuthPersistenceService.saveAuth(publicAuthData);
|
|
78
|
-
|
|
79
|
-
}, [tenantData]);
|
|
80
|
-
|
|
81
|
-
return <></>;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export default GlobalTenantWrapper;
|
|
@@ -1,514 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TenantSwitcher
|
|
3
|
-
*
|
|
4
|
-
* A dropdown component that allows switching between the Tenancy Account and
|
|
5
|
-
* individual Tenants. It reads the available tenants from the persisted
|
|
6
|
-
* systemValues (populated by the tenancyAuth endpoint) and allows the user
|
|
7
|
-
* to select one, triggering a full environment switch:
|
|
8
|
-
*
|
|
9
|
-
* - Persists the selected tenant_id to dashStorage
|
|
10
|
-
* - Dispatches a 'tenant_switch' CustomEvent so the PrivateAppLoader can
|
|
11
|
-
* reload the correct resources, routes, and auth data
|
|
12
|
-
* - Re-fetches the appropriate getAuth endpoint (tenancyAuth vs getauth)
|
|
13
|
-
* - Updates CSS variables and logos from the new tenant's settings
|
|
14
|
-
*
|
|
15
|
-
* Consolidated 2026-08-03 from four byte-identical app-level copies
|
|
16
|
-
* (kitchntabs-app, kitchntabs-web, vanexa-app, vanexa-web). The only per-app
|
|
17
|
-
* difference was which local brand assets each app fell back to when
|
|
18
|
-
* switching back to the tenancy level — that's now the defaultHorizontalLogo/
|
|
19
|
-
* defaultSquaredLogo/defaultLoginBackground props instead of hardcoded
|
|
20
|
-
* relative imports (a relative image import moved into this package would
|
|
21
|
-
* have resolved against dash-admin's own assets, not each app's brand).
|
|
22
|
-
*/
|
|
23
|
-
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
24
|
-
import {
|
|
25
|
-
Avatar,
|
|
26
|
-
Box,
|
|
27
|
-
Typography,
|
|
28
|
-
CircularProgress,
|
|
29
|
-
} from '@mui/material';
|
|
30
|
-
import BusinessIcon from '@mui/icons-material/Business';
|
|
31
|
-
import StoreIcon from '@mui/icons-material/Store';
|
|
32
|
-
import SwapHorizIcon from '@mui/icons-material/SwapHoriz';
|
|
33
|
-
import ReactDOM from 'react-dom';
|
|
34
|
-
import { dashStorage } from 'dash-utils';
|
|
35
|
-
import { AuthPersistenceService } from 'dash-auth';
|
|
36
|
-
import { DASHAdminSystemConstants } from 'dash-constants';
|
|
37
|
-
import { useAxios } from 'dash-axios-hook';
|
|
38
|
-
import { updateDomCssVariables } from 'dash-utils';
|
|
39
|
-
import DASHLayoutSettings from '../../theme/AppLayoutSetting';
|
|
40
|
-
import { useDispatch, useSelector } from 'react-redux';
|
|
41
|
-
import { setPanelSettings } from 'dash-admin-state/redux/actions/Common';
|
|
42
|
-
import { IDASHAppState } from 'dash-admin-state';
|
|
43
|
-
import { useWindowSize } from 'dash-utils';
|
|
44
|
-
import { setAuthEvent } from '../../contexts/auth';
|
|
45
|
-
import useClickOutside from '../../hooks/useClickOutside';
|
|
46
|
-
|
|
47
|
-
export interface TenantSwitcherProps {
|
|
48
|
-
/** Fallback horizontal logo used when switching back to the tenancy level */
|
|
49
|
-
defaultHorizontalLogo?: string;
|
|
50
|
-
/** Fallback squared logo used when switching back to the tenancy level */
|
|
51
|
-
defaultSquaredLogo?: string;
|
|
52
|
-
/** Fallback login background used when switching back to the tenancy level */
|
|
53
|
-
defaultLoginBackground?: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Shape of a tenant from systemValues.tenants */
|
|
57
|
-
interface TenantOption {
|
|
58
|
-
id: string;
|
|
59
|
-
name: string;
|
|
60
|
-
slug: string | null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** The value emitted in the tenant_switch CustomEvent */
|
|
64
|
-
export interface TenantSwitchEventDetail {
|
|
65
|
-
tenantId: string | null; // null = tenancy account level
|
|
66
|
-
tenantName: string;
|
|
67
|
-
isTenanancyLevel: boolean;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Dispatch a tenant_switch event so other parts of the app can react.
|
|
72
|
-
*/
|
|
73
|
-
export const dispatchTenantSwitchEvent = (detail: TenantSwitchEventDetail) => {
|
|
74
|
-
window.dispatchEvent(new CustomEvent('tenant_switch', { detail }));
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Get the currently active tenant_id from storage (null = tenancy level).
|
|
79
|
-
*/
|
|
80
|
-
export const getActiveTenantId = (): string | null => {
|
|
81
|
-
if (!isTenantImpersonationEnabled()) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
return dashStorage.getItem('active_tenant_id') || null;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Check whether tenant impersonation is enabled.
|
|
89
|
-
*/
|
|
90
|
-
export const isTenantImpersonationEnabled = (): boolean => {
|
|
91
|
-
const val = DASHAdminSystemConstants.system.ENABLE_TENANT_IMPERSONATION;
|
|
92
|
-
if (typeof val === 'boolean') return val;
|
|
93
|
-
if (typeof val === 'string') return val === 'true' || val === '1';
|
|
94
|
-
return !!val;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const TenantSwitcher: React.FC<TenantSwitcherProps> = ({
|
|
100
|
-
defaultHorizontalLogo,
|
|
101
|
-
defaultSquaredLogo,
|
|
102
|
-
defaultLoginBackground,
|
|
103
|
-
}) => {
|
|
104
|
-
const axios = useAxios();
|
|
105
|
-
const dispatch = useDispatch();
|
|
106
|
-
const windowSize = useWindowSize();
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const [open, setOpen] = useState(false);
|
|
111
|
-
const [switching, setSwitching] = useState(false);
|
|
112
|
-
const avatarRef = useRef<HTMLDivElement>(null);
|
|
113
|
-
const menuRef = useRef<HTMLDivElement>(null);
|
|
114
|
-
const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
|
|
115
|
-
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
116
|
-
const [webView, setWebView] = useState(false);
|
|
117
|
-
|
|
118
|
-
// Current active tenant id
|
|
119
|
-
const [activeTenantId, setActiveTenantId] = useState<string | null>(
|
|
120
|
-
getActiveTenantId()
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
// Read panel settings for logos
|
|
124
|
-
const panelSettings = useSelector(
|
|
125
|
-
(state: IDASHAppState<any, any, any>) => state.common?.panelSettings
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
// Get primary and secondary sidebar positions from Redux panelSettings
|
|
129
|
-
const sidebarPosition = panelSettings?.sidebarPosition || 'left';
|
|
130
|
-
|
|
131
|
-
// Get tenants from persisted systemValues
|
|
132
|
-
const systemValues = AuthPersistenceService.getSystemValues();
|
|
133
|
-
const tenants: TenantOption[] = systemValues?.tenants || [];
|
|
134
|
-
const tenancy = systemValues?.tenancy;
|
|
135
|
-
|
|
136
|
-
// Get current tenant auth data for display
|
|
137
|
-
const auth = AuthPersistenceService.getAuth();
|
|
138
|
-
const currentTenantName = activeTenantId
|
|
139
|
-
? tenants.find(t => t.id === activeTenantId)?.name || 'Tenant'
|
|
140
|
-
: tenancy?.public_name || auth?.tenant?.name || 'Tenancy Account';
|
|
141
|
-
|
|
142
|
-
useEffect(() => {
|
|
143
|
-
if (document.body.classList.contains('webview')) {
|
|
144
|
-
setWebView(true);
|
|
145
|
-
}
|
|
146
|
-
}, []);
|
|
147
|
-
|
|
148
|
-
// Close on click/tap outside the trigger AND the portal-rendered menu
|
|
149
|
-
// (both refs — the menu isn't a DOM descendant of the trigger since it's
|
|
150
|
-
// rendered via createPortal). Declared above the early-return guard
|
|
151
|
-
// below, alongside the component's other hooks, so hook order stays
|
|
152
|
-
// stable across renders regardless of whether that guard ends up
|
|
153
|
-
// returning null.
|
|
154
|
-
useClickOutside([avatarRef, menuRef], () => setOpen(false), open);
|
|
155
|
-
|
|
156
|
-
// Don't render if impersonation is disabled or no tenants available
|
|
157
|
-
if (!isTenantImpersonationEnabled() || tenants.length === 0) {
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const calculateMenuPosition = () => {
|
|
162
|
-
if (avatarRef.current && windowSize.width && windowSize.height) {
|
|
163
|
-
const rect = avatarRef.current.getBoundingClientRect();
|
|
164
|
-
const menuWidth = 230; // minWidth from styles
|
|
165
|
-
const menuHeight = 120; // approximate menu height
|
|
166
|
-
|
|
167
|
-
let left = rect.left + window.scrollX;
|
|
168
|
-
let top = rect.top + window.scrollY;
|
|
169
|
-
|
|
170
|
-
// Ensure menu doesn't go off-screen horizontally
|
|
171
|
-
if (left + menuWidth > windowSize.width) {
|
|
172
|
-
left = windowSize.width - menuWidth - 10; // 10px margin
|
|
173
|
-
}
|
|
174
|
-
if (left < 10) {
|
|
175
|
-
left = 10; // 10px margin
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// For bottom sidebar position, open menu above the avatar
|
|
179
|
-
if (sidebarPosition === 'bottom') {
|
|
180
|
-
top = rect.top + window.scrollY - menuHeight - 10; // Open above
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
setMenuPosition({
|
|
184
|
-
top: top,
|
|
185
|
-
left: left + 40
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
191
|
-
e.preventDefault();
|
|
192
|
-
if (timeoutRef.current) {
|
|
193
|
-
clearTimeout(timeoutRef.current);
|
|
194
|
-
timeoutRef.current = null;
|
|
195
|
-
}
|
|
196
|
-
setOpen(true);
|
|
197
|
-
calculateMenuPosition();
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
201
|
-
e.preventDefault();
|
|
202
|
-
setOpen(prev => !prev);
|
|
203
|
-
calculateMenuPosition();
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
const handleMouseLeave = () => {
|
|
207
|
-
if (!webView) {
|
|
208
|
-
timeoutRef.current = setTimeout(() => setOpen(false), 150);
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
const handleMenuMouseEnter = () => {
|
|
213
|
-
if (timeoutRef.current) {
|
|
214
|
-
clearTimeout(timeoutRef.current);
|
|
215
|
-
timeoutRef.current = null;
|
|
216
|
-
}
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const handleMenuMouseLeave = () => {
|
|
220
|
-
if (!webView) {
|
|
221
|
-
setOpen(false);
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
useEffect(() => {
|
|
226
|
-
return () => {
|
|
227
|
-
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
228
|
-
};
|
|
229
|
-
}, []);
|
|
230
|
-
|
|
231
|
-
useEffect(() => {
|
|
232
|
-
if (open) calculateMenuPosition();
|
|
233
|
-
}, [open, windowSize.width]);
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Core switching logic.
|
|
237
|
-
* - Always uses tenancyAuth endpoint (preserves tenancy/tenants in response)
|
|
238
|
-
* - Passes X-Tenant-Id header when switching to a specific tenant
|
|
239
|
-
* - Persists auth data
|
|
240
|
-
* - Updates CSS variables, logos
|
|
241
|
-
* - Dispatches tenant_switch event for PrivateAppLoader
|
|
242
|
-
*/
|
|
243
|
-
const handleSwitch = useCallback(async (tenantId: string | null) => {
|
|
244
|
-
if (switching) return;
|
|
245
|
-
if (tenantId === activeTenantId) {
|
|
246
|
-
setOpen(false);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
setSwitching(true);
|
|
251
|
-
setOpen(false);
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
const isTenancyLevel = tenantId === null;
|
|
255
|
-
// Always use tenancyAuth - it returns tenancy/tenants list + respects
|
|
256
|
-
// X-Tenant-Id header. Deliberately NOT reading APP_GETAUTH_ENDPOINT
|
|
257
|
-
// here (every app's env has it set to 'auth/getauth') — that
|
|
258
|
-
// endpoint ignores X-Tenant-Id entirely and always resolves off the
|
|
259
|
-
// user's raw tenant_id FK, so every switch silently kept returning
|
|
260
|
-
// the same tenant's data regardless of which one was picked. This
|
|
261
|
-
// component only ever renders once TenancyContextService has
|
|
262
|
-
// already put at least one tenant in scope (see the render guard
|
|
263
|
-
// below), so hitting the TenancyAdmin-only endpoint unconditionally
|
|
264
|
-
// is always correct here.
|
|
265
|
-
const authEndpoint = 'auth/tenancyAuth';
|
|
266
|
-
|
|
267
|
-
// If switching to a specific tenant, set the header so backend knows
|
|
268
|
-
const headers: Record<string, string> = {};
|
|
269
|
-
if (!isTenancyLevel && tenantId) {
|
|
270
|
-
headers['X-Tenant-Id'] = tenantId;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Persist active_tenant_id BEFORE the request so the axios interceptor picks it up
|
|
274
|
-
if (tenantId) {
|
|
275
|
-
dashStorage.setItem('active_tenant_id', tenantId);
|
|
276
|
-
dashStorage.setItem('tenant_id', tenantId);
|
|
277
|
-
} else {
|
|
278
|
-
dashStorage.removeItem('active_tenant_id');
|
|
279
|
-
dashStorage.removeItem('tenant_id');
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Persist the choice server-side so it survives a reload and
|
|
283
|
-
// shows up on another device — not just in this browser's
|
|
284
|
-
// storage. Best-effort: a failed write here still leaves the
|
|
285
|
-
// switch working for the rest of this session via the local
|
|
286
|
-
// storage above, it just won't be remembered next time.
|
|
287
|
-
try {
|
|
288
|
-
await axios.put('auth/active-tenant', { tenant_id: tenantId });
|
|
289
|
-
} catch (err) {
|
|
290
|
-
console.error('[TenantSwitcher] Failed to persist active tenant:', err);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Fetch new auth data from the correct endpoint
|
|
294
|
-
const { data: authData } = await axios.get(authEndpoint, { headers });
|
|
295
|
-
|
|
296
|
-
// Persist auth data using the standard service
|
|
297
|
-
AuthPersistenceService.saveAuth(authData);
|
|
298
|
-
|
|
299
|
-
// Update basic localStorage for react-admin compatibility
|
|
300
|
-
dashStorage.setItem('authenticated', 'true');
|
|
301
|
-
dashStorage.setItem('user', JSON.stringify(authData.user));
|
|
302
|
-
if (authData.user?.roles) {
|
|
303
|
-
dashStorage.setItem('roles', JSON.stringify(authData.user.roles));
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Trigger auth context update
|
|
307
|
-
setAuthEvent({
|
|
308
|
-
authenticated: true,
|
|
309
|
-
user: authData.user,
|
|
310
|
-
auth: authData.auth,
|
|
311
|
-
token: dashStorage.getItem('token'),
|
|
312
|
-
roles: authData.user?.roles,
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
// Update CSS variables from new tenant settings
|
|
316
|
-
const tenantSettings = authData.auth?.tenantSettings;
|
|
317
|
-
try {
|
|
318
|
-
|
|
319
|
-
// Read current theme mode instead of hardcoding 'dark'
|
|
320
|
-
const currentThemeMode = document.documentElement.getAttribute('data-theme') || DASHLayoutSettings.THEME_TYPE_DARK;
|
|
321
|
-
// Always call updateDomCssVariables — when colors is undefined,
|
|
322
|
-
// it correctly resets to compiled LESS defaults for tenants without custom colors.
|
|
323
|
-
updateDomCssVariables(currentThemeMode, tenantSettings?.colors, tenantSettings?.values);
|
|
324
|
-
} catch (err) {
|
|
325
|
-
console.error('[TenantSwitcher] Error updating CSS variables:', err);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Update logos in Redux panel settings
|
|
329
|
-
const tenantImages = authData.auth?.tenantImages;
|
|
330
|
-
if (tenantImages) {
|
|
331
|
-
AuthPersistenceService.setTenantImages(tenantImages);
|
|
332
|
-
dispatch(setPanelSettings({
|
|
333
|
-
...(panelSettings || {}),
|
|
334
|
-
horizontalLogo: tenantImages.horizontal_logo?.original || panelSettings?.horizontalLogo,
|
|
335
|
-
squaredLogo: tenantImages.squared_logo?.original || panelSettings?.squaredLogo,
|
|
336
|
-
loginBackground: tenantImages.banner?.original || panelSettings?.loginBackground,
|
|
337
|
-
}));
|
|
338
|
-
} else {
|
|
339
|
-
// Switching to tenancy level — clear stale tenant images
|
|
340
|
-
// and reset Redux logos to system defaults
|
|
341
|
-
AuthPersistenceService.clearTenantImages();
|
|
342
|
-
dispatch(setPanelSettings({
|
|
343
|
-
...(panelSettings || {}),
|
|
344
|
-
horizontalLogo: defaultHorizontalLogo,
|
|
345
|
-
squaredLogo: defaultSquaredLogo,
|
|
346
|
-
loginBackground: defaultLoginBackground,
|
|
347
|
-
}));
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Update tenant settings in persistence
|
|
351
|
-
if (tenantSettings) {
|
|
352
|
-
AuthPersistenceService.setTenantSettings(tenantSettings);
|
|
353
|
-
} else {
|
|
354
|
-
// Switching to tenancy level — clear stale tenant settings
|
|
355
|
-
// so DashThemeProvider reads null on remount and uses defaults
|
|
356
|
-
AuthPersistenceService.clearTenantSettings();
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
setActiveTenantId(tenantId);
|
|
360
|
-
|
|
361
|
-
// Find tenant name for event
|
|
362
|
-
const tenantName = isTenancyLevel
|
|
363
|
-
? (tenancy?.public_name || 'Tenancy Account')
|
|
364
|
-
: (tenants.find(t => t.id === tenantId)?.name || 'Tenant');
|
|
365
|
-
|
|
366
|
-
// Dispatch switch event so PrivateAppLoader can reload resources
|
|
367
|
-
dispatchTenantSwitchEvent({
|
|
368
|
-
tenantId,
|
|
369
|
-
tenantName,
|
|
370
|
-
isTenanancyLevel: isTenancyLevel,
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
console.log(`[TenantSwitcher] Switched to ${isTenancyLevel ? 'Tenancy Account' : tenantName} (${tenantId})`);
|
|
374
|
-
|
|
375
|
-
} catch (error) {
|
|
376
|
-
console.error('[TenantSwitcher] Switch failed:', error);
|
|
377
|
-
// Revert storage on failure
|
|
378
|
-
if (activeTenantId) {
|
|
379
|
-
dashStorage.setItem('active_tenant_id', activeTenantId);
|
|
380
|
-
dashStorage.setItem('tenant_id', activeTenantId);
|
|
381
|
-
} else {
|
|
382
|
-
dashStorage.removeItem('active_tenant_id');
|
|
383
|
-
dashStorage.removeItem('tenant_id');
|
|
384
|
-
}
|
|
385
|
-
} finally {
|
|
386
|
-
setSwitching(false);
|
|
387
|
-
}
|
|
388
|
-
}, [activeTenantId, switching, axios, dispatch, panelSettings, tenants, tenancy, defaultHorizontalLogo, defaultSquaredLogo, defaultLoginBackground]);
|
|
389
|
-
|
|
390
|
-
const isSelected = (id: string | null) => id === activeTenantId;
|
|
391
|
-
|
|
392
|
-
return (
|
|
393
|
-
<>
|
|
394
|
-
<div
|
|
395
|
-
ref={avatarRef}
|
|
396
|
-
className="dash-tenant-switcher-trigger"
|
|
397
|
-
{...(!webView
|
|
398
|
-
? { onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave }
|
|
399
|
-
: { onClick: handleClick }
|
|
400
|
-
)}
|
|
401
|
-
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center' }}
|
|
402
|
-
>
|
|
403
|
-
{switching ? (
|
|
404
|
-
<CircularProgress
|
|
405
|
-
className='dash-icon-button-color dash-icon-button-bg'
|
|
406
|
-
size={30} />
|
|
407
|
-
) : (
|
|
408
|
-
<Avatar
|
|
409
|
-
className='dash-icon-button-color dash-icon-button-bg'
|
|
410
|
-
sx={{
|
|
411
|
-
width: 30,
|
|
412
|
-
height: 30,
|
|
413
|
-
fontSize: '0.8rem',
|
|
414
|
-
}}
|
|
415
|
-
>
|
|
416
|
-
{activeTenantId ? <StoreIcon sx={{ fontSize: 18 }} /> : <BusinessIcon sx={{ fontSize: 18 }} />}
|
|
417
|
-
</Avatar>
|
|
418
|
-
)}
|
|
419
|
-
</div>
|
|
420
|
-
|
|
421
|
-
{open && ReactDOM.createPortal(
|
|
422
|
-
<div
|
|
423
|
-
ref={menuRef}
|
|
424
|
-
className="dash-tenant-switcher-portal"
|
|
425
|
-
onMouseEnter={!webView ? handleMenuMouseEnter : undefined}
|
|
426
|
-
onMouseLeave={!webView ? handleMenuMouseLeave : undefined}
|
|
427
|
-
>
|
|
428
|
-
<div
|
|
429
|
-
className="dash-tenant-switcher-menu"
|
|
430
|
-
style={{
|
|
431
|
-
top: menuPosition.top,
|
|
432
|
-
left: menuPosition.left,
|
|
433
|
-
zIndex: 10000,
|
|
434
|
-
position: 'absolute',
|
|
435
|
-
}}
|
|
436
|
-
>
|
|
437
|
-
{/* Header */}
|
|
438
|
-
<Box sx={{ px: 2, py: 1.5, borderBottom: '1px solid rgba(255,255,255,0.08)' }}>
|
|
439
|
-
<Typography variant="caption" sx={{ color: 'text.secondary', fontWeight: 600, textTransform: 'uppercase', letterSpacing: 0.5 }}>
|
|
440
|
-
<SwapHorizIcon sx={{ fontSize: 14, mr: 0.5, verticalAlign: 'middle' }} />
|
|
441
|
-
Switch Environment
|
|
442
|
-
</Typography>
|
|
443
|
-
</Box>
|
|
444
|
-
|
|
445
|
-
{/* Tenancy Account option */}
|
|
446
|
-
<div
|
|
447
|
-
onClick={() => handleSwitch(null)}
|
|
448
|
-
style={{
|
|
449
|
-
padding: '10px 16px',
|
|
450
|
-
cursor: 'pointer',
|
|
451
|
-
display: 'flex',
|
|
452
|
-
alignItems: 'center',
|
|
453
|
-
gap: 10,
|
|
454
|
-
backgroundColor: isSelected(null) ? 'rgba(var(--dash-primary-rgb, 25, 118, 210), 0.15)' : 'transparent',
|
|
455
|
-
borderLeft: isSelected(null) ? '3px solid var(--dash-primary, #1976d2)' : '3px solid transparent',
|
|
456
|
-
transition: 'background-color 0.15s ease',
|
|
457
|
-
}}
|
|
458
|
-
onMouseOver={(e) => { if (!isSelected(null)) (e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.05)'); }}
|
|
459
|
-
onMouseOut={(e) => { if (!isSelected(null)) (e.currentTarget.style.backgroundColor = 'transparent'); }}
|
|
460
|
-
>
|
|
461
|
-
<BusinessIcon sx={{ fontSize: 20, color: isSelected(null) ? 'primary.main' : 'text.secondary' }} />
|
|
462
|
-
<Box>
|
|
463
|
-
<Typography variant="body2" sx={{ fontWeight: isSelected(null) ? 600 : 400, color: isSelected(null) ? 'primary.main' : 'text.primary' }}>
|
|
464
|
-
{tenancy?.public_name || 'Tenancy Account'}
|
|
465
|
-
</Typography>
|
|
466
|
-
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
|
467
|
-
Manager Account
|
|
468
|
-
</Typography>
|
|
469
|
-
</Box>
|
|
470
|
-
</div>
|
|
471
|
-
|
|
472
|
-
{/* Divider */}
|
|
473
|
-
<Box sx={{ borderTop: '1px solid rgba(255,255,255,0.06)', mx: 1 }} />
|
|
474
|
-
|
|
475
|
-
{/* Tenant options */}
|
|
476
|
-
{tenants.map((tenant) => (
|
|
477
|
-
<div
|
|
478
|
-
key={tenant.id}
|
|
479
|
-
onClick={() => handleSwitch(tenant.id)}
|
|
480
|
-
style={{
|
|
481
|
-
padding: '10px 16px',
|
|
482
|
-
cursor: 'pointer',
|
|
483
|
-
display: 'flex',
|
|
484
|
-
alignItems: 'center',
|
|
485
|
-
gap: 10,
|
|
486
|
-
backgroundColor: isSelected(tenant.id) ? 'rgba(var(--dash-primary-rgb, 25, 118, 210), 0.15)' : 'transparent',
|
|
487
|
-
borderLeft: isSelected(tenant.id) ? '3px solid var(--dash-primary, #1976d2)' : '3px solid transparent',
|
|
488
|
-
transition: 'background-color 0.15s ease',
|
|
489
|
-
}}
|
|
490
|
-
onMouseOver={(e) => { if (!isSelected(tenant.id)) (e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.05)'); }}
|
|
491
|
-
onMouseOut={(e) => { if (!isSelected(tenant.id)) (e.currentTarget.style.backgroundColor = 'transparent'); }}
|
|
492
|
-
>
|
|
493
|
-
<StoreIcon sx={{ fontSize: 20, color: isSelected(tenant.id) ? 'primary.main' : 'text.secondary' }} />
|
|
494
|
-
<Box>
|
|
495
|
-
<Typography variant="body2" sx={{ fontWeight: isSelected(tenant.id) ? 600 : 400, color: isSelected(tenant.id) ? 'primary.main' : 'text.primary' }}>
|
|
496
|
-
{tenant.name}
|
|
497
|
-
</Typography>
|
|
498
|
-
{tenant.slug && (
|
|
499
|
-
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
|
500
|
-
{tenant.slug}
|
|
501
|
-
</Typography>
|
|
502
|
-
)}
|
|
503
|
-
</Box>
|
|
504
|
-
</div>
|
|
505
|
-
))}
|
|
506
|
-
</div>
|
|
507
|
-
</div>,
|
|
508
|
-
document.body
|
|
509
|
-
)}
|
|
510
|
-
</>
|
|
511
|
-
);
|
|
512
|
-
};
|
|
513
|
-
|
|
514
|
-
export default TenantSwitcher;
|
|
File without changes
|