@dashadmin/dash-admin 1.3.72 → 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.
Files changed (289) hide show
  1. package/dist/components/tenant/TenancyPlan.js +307 -0
  2. package/dist/systemResources.js +18 -2
  3. package/package.json +25 -22
  4. package/src/AppAsyncWrapper.tsx +0 -42
  5. package/src/AppWrapper.tsx +0 -45
  6. package/src/DASHAdmin.tsx +0 -502
  7. package/src/DASHAdmin.tsx.old +0 -456
  8. package/src/RoutingWrapper.tsx +0 -143
  9. package/src/classes/DASHStorageClass.tsx +0 -8
  10. package/src/components/Input/RichTextField.tsx +0 -27
  11. package/src/components/Redirect.tsx +0 -46
  12. package/src/components/avatar/Avatar.tsx +0 -71
  13. package/src/components/avatar/SingleImageUploader.tsx +0 -107
  14. package/src/components/currency/Format.tsx +0 -79
  15. package/src/components/custom/Redirect.tsx +0 -23
  16. package/src/components/error/Error.tsx +0 -168
  17. package/src/components/geocoding/GeocodingField.tsx +0 -167
  18. package/src/components/i18n/BridgedLocalesMenuButton.tsx +0 -160
  19. package/src/components/i18n/LangSwitcher.tsx +0 -204
  20. package/src/components/loader/GlobalLoader.tsx +0 -49
  21. package/src/components/logs/LogFile.tsx +0 -88
  22. package/src/components/logs/LogFileById.tsx +0 -68
  23. package/src/components/logs/LogViewer.tsx +0 -43
  24. package/src/components/menu/AppMenu.tsx +0 -22
  25. package/src/components/menu/CustomMenuItemLink.tsx +0 -61
  26. package/src/components/menu/DarkToggleMode.tsx +0 -65
  27. package/src/components/menu/LanguageToggleMode.tsx +0 -120
  28. package/src/components/misc/CustomImageInput.tsx +0 -62
  29. package/src/components/misc/DASHGlobalErrorHandler.tsx +0 -194
  30. package/src/components/misc/DarkModeSwitcher.tsx +0 -112
  31. package/src/components/misc/HorizontalScroller.tsx +0 -225
  32. package/src/components/misc/LanguageSwitcher.tsx +0 -199
  33. package/src/components/misc/MUIHtmlToolTip.tsx +0 -15
  34. package/src/components/misc/MuiSimpleJsonTable.tsx +0 -279
  35. package/src/components/misc/MultiLevelTable.tsx +0 -229
  36. package/src/components/misc/NoResults.tsx +0 -28
  37. package/src/components/misc/PDFViewer.tsx +0 -85
  38. package/src/components/navigation/Breadcrumbs.tsx +0 -220
  39. package/src/components/navigation/BreadcrumbsManager.tsx +0 -310
  40. package/src/components/navigation/index.tsx +0 -5
  41. package/src/components/panel/Error.tsx +0 -168
  42. package/src/components/permission/AvailablePermissionsContext.tsx +0 -173
  43. package/src/components/permission/PermissionsSelector.tsx +0 -834
  44. package/src/components/permission/PermissionsSelectorList.tsx +0 -473
  45. package/src/components/permission/tsx +0 -0
  46. package/src/components/racustombuttons/CustomRAButton.tsx +0 -87
  47. package/src/components/racustombuttons/QuickButton.tsx +0 -117
  48. package/src/components/racustombuttons/QuickEditButton.tsx +0 -115
  49. package/src/components/racustombuttons/QuickIconButton.tsx +0 -122
  50. package/src/components/scrollbar/Scrollbar.tsx +0 -31
  51. package/src/components/selects/MultiSelect.tsx +0 -53
  52. package/src/components/selects/RASearchableSelect.tsx +0 -282
  53. package/src/components/selects/RASearchableSelectChips.tsx +0 -308
  54. package/src/components/selects/SearchableSelect.tsx +0 -139
  55. package/src/components/serviceAccount/ApiKeyRevealDialog.tsx +0 -129
  56. package/src/components/serviceAccount/ServiceAccountStatusSwitch.tsx +0 -99
  57. package/src/components/subscription/BillingCycleSelectInput.tsx +0 -68
  58. package/src/components/subscription/PlanAddonsSettings.tsx +0 -563
  59. package/src/components/subscription/PlanAuditLog.tsx +0 -453
  60. package/src/components/subscription/PlanFeaturesSettings.tsx +0 -243
  61. package/src/components/subscription/PlanLimitsSettings.tsx +0 -230
  62. package/src/components/subscription/PlanMetadataSettings.tsx +0 -306
  63. package/src/components/subscription/PlanPricesSettings.tsx +0 -307
  64. package/src/components/subscription/index.ts +0 -7
  65. package/src/components/svgelements/SvgLoading.tsx +0 -229
  66. package/src/components/svgelements/SvgLogo.tsx +0 -53
  67. package/src/components/svgelements/SvgLogoMin.tsx +0 -64
  68. package/src/components/svgelements/SvgShipping.tsx +0 -673
  69. package/src/components/tenancy/GlobalTenantWrapper.tsx +0 -84
  70. package/src/components/tenancy/TenantSwitcher.tsx +0 -514
  71. package/src/components/tenant/AvailablePermissionsContext.tsx +0 -0
  72. package/src/components/tenant/SettingsSections.tsx +0 -151
  73. package/src/components/tenant/TenancySettings.tsx +0 -122
  74. package/src/components/tenant/TenantAttributes.tsx +0 -153
  75. package/src/components/tenant/TenantAttributesContext.tsx +0 -163
  76. package/src/components/tenant/TenantSelector.tsx +0 -142
  77. package/src/components/tenant/TenantSettings.tsx +0 -184
  78. package/src/components/tenant/TenantSettingsContext.tsx +0 -165
  79. package/src/components/tenant/TenantTheme.tsx +0 -172
  80. package/src/components/user/AvatarComponent.tsx +0 -317
  81. package/src/components/user/TenantAvatarComponent.tsx +0 -99
  82. package/src/components/user/UserPreferences.tsx +0 -677
  83. package/src/config/ACTIONS.tsx +0 -26
  84. package/src/config/ConstantsService.tsx +0 -44
  85. package/src/config/DASHAdminSystemConstants.tsx +0 -183
  86. package/src/config/PARSERS.tsx +0 -9
  87. package/src/contexts/DashQueryClientContext.tsx +0 -113
  88. package/src/contexts/DashResourceContext.tsx +0 -34
  89. package/src/contexts/I18nBridgeContext.tsx +0 -156
  90. package/src/contexts/I18nBridgeSetter.tsx +0 -39
  91. package/src/contexts/I18nReduxSync.tsx +0 -27
  92. package/src/contexts/SubscriptionPlanFormatsProvider.tsx +0 -217
  93. package/src/contexts/SystemRequestsCache.tsx +0 -215
  94. package/src/contexts/auth/AuthContext.tsx +0 -567
  95. package/src/contexts/auth/AuthContextLocalStorage.tsx +0 -140
  96. package/src/contexts/auth/DASHAuthenticationService.tsx +0 -915
  97. package/src/contexts/auth/WindowContext.tsx +0 -15
  98. package/src/contexts/auth/index.tsx +0 -3
  99. package/src/contexts/com/FCMContext.tsx +0 -415
  100. package/src/contexts/com/LaravelEchoContext.tsx +0 -41
  101. package/src/contexts/com/LaravelEchoMgr.tsx +0 -155
  102. package/src/contexts/com/components/DefaultNotificationComponent.tsx +0 -20
  103. package/src/contexts/com/components/EchoNotificationsCenter.tsx +0 -65
  104. package/src/contexts/com/components/NotificationAttributesTable.tsx +0 -54
  105. package/src/contexts/com/components/NotificationRenderer.tsx +0 -42
  106. package/src/contexts/com/components/NotificationsWidget.tsx +0 -182
  107. package/src/contexts/com/components/notificationFormats.tsx +0 -50
  108. package/src/contexts/com/useLaravelEcho.tsx +0 -432
  109. package/src/contexts/dictionary/DictionaryContext.tsx +0 -94
  110. package/src/declarations.d.ts +0 -17
  111. package/src/default-theme/DASHAppProviders.tsx +0 -117
  112. package/src/default-theme/DashThemeContext.tsx +0 -209
  113. package/src/default-theme/DashThemeContext.tsx.fast +0 -143
  114. package/src/default-theme/DashThemeContext.tsx.old +0 -306
  115. package/src/default-theme/DashThemeHelperProvider.tsx +0 -98
  116. package/src/default-theme/DomainAppLayout.tsx +0 -166
  117. package/src/default-theme/DomainHeader.tsx +0 -162
  118. package/src/default-theme/DomainTheme.tsx +0 -59
  119. package/src/default-theme/FullLayoutMarkup.tsx +0 -231
  120. package/src/default-theme/StaticLayout.tsx +0 -47
  121. package/src/default-theme/index.tsx +0 -11
  122. package/src/default-theme/menu/AppDashboardGrid.tsx +0 -279
  123. package/src/default-theme/menu/AppMaterialMenu.tsx +0 -546
  124. package/src/default-theme/menu/AppMenuComponents/SubmenuPortal.tsx +0 -61
  125. package/src/default-theme/menu/AppMenuComponents/collapsed/CollapsedSidebarItem.tsx +0 -264
  126. package/src/default-theme/menu/AppMenuComponents/collapsed/CollapsedSidebarItems.tsx +0 -31
  127. package/src/default-theme/menu/AppMenuComponents/expanded/CollapsableSidebarMenu.tsx +0 -293
  128. package/src/default-theme/menu/AppMenuComponents/expanded/SidebarItem.tsx +0 -92
  129. package/src/default-theme/menu/AppMenuComponents/getItem.tsx +0 -17
  130. package/src/default-theme/menu/AppMenuComponents/interfaces.tsx +0 -41
  131. package/src/default-theme/menu/AppMenuComponents/submenuConstants.ts +0 -90
  132. package/src/default-theme/menu/AppSidebarMaterial.tsx +0 -339
  133. package/src/default-theme/menu/SidebarActions.tsx +0 -84
  134. package/src/default-theme/updateDomCssVariables.tsx +0 -176
  135. package/src/helpers/checkRole.tsx +0 -66
  136. package/src/helpers/parseAxiosError.tsx +0 -41
  137. package/src/hooks/audio/useAudio.tsx +0 -39
  138. package/src/hooks/axios.tsx +0 -165
  139. package/src/hooks/data/useDashboardStats.tsx +0 -65
  140. package/src/hooks/data/usePackageByClientsStats.tsx +0 -44
  141. package/src/hooks/data/usePackageByCommunesStats.tsx +0 -44
  142. package/src/hooks/data/usePackageStats.tsx +0 -69
  143. package/src/hooks/data/usePackageWithdrawDetails.tsx +0 -61
  144. package/src/hooks/data/useStats.tsx +0 -86
  145. package/src/hooks/isCurrentPath.tsx +0 -22
  146. package/src/hooks/notifications/WSMessagesManager.tsx +0 -152
  147. package/src/hooks/notifications/WSPusherManager.tsx +0 -92
  148. package/src/hooks/useBreadcrumbs.tsx +0 -329
  149. package/src/hooks/useClickOutside.tsx +0 -57
  150. package/src/hooks/useFormPersistance.tsx +0 -150
  151. package/src/hooks/useGlobalErrorMediator.tsx +0 -43
  152. package/src/hooks/useGlobalLoaderMgr.tsx +0 -21
  153. package/src/hooks/useHash.tsx +0 -27
  154. package/src/hooks/useLocalStorage.tsx +0 -196
  155. package/src/hooks/usePolyglotTranslation.tsx +0 -62
  156. package/src/hooks/usePrevious.tsx +0 -9
  157. package/src/hooks/usePrintSelected.tsx +0 -37
  158. package/src/hooks/useVirtualHash.tsx +0 -33
  159. package/src/hooks/window/useWindowSize.tsx +0 -36
  160. package/src/index.tsx +0 -134
  161. package/src/interfaces/IAppResourceConfig.tsx +0 -20
  162. package/src/interfaces/Log.tsx +0 -16
  163. package/src/interfaces/Tenant.tsx +0 -25
  164. package/src/interfaces/communication/IActions.tsx +0 -5
  165. package/src/interfaces/communication/INotification.tsx +0 -21
  166. package/src/interfaces/communication/IPayload.tsx +0 -3
  167. package/src/interfaces/communication/IRequestAction.tsx +0 -10
  168. package/src/interfaces/communication/IRequestPayload.tsx +0 -7
  169. package/src/interfaces/communication/IResponseAction.tsx +0 -7
  170. package/src/interfaces/misc/IAny.tsx +0 -3
  171. package/src/interfaces/misc/IFlashMessage.tsx +0 -10
  172. package/src/interfaces/navigation/IAppMenu.ts +0 -14
  173. package/src/interfaces/navigation/ICollapsableSidebarMenu.ts +0 -12
  174. package/src/interfaces/navigation/IMenuItem.ts +0 -16
  175. package/src/interfaces/notifications/IModel.tsx +0 -6
  176. package/src/interfaces/notifications/IModelField.tsx +0 -8
  177. package/src/interfaces/notifications/IUserNotification.tsx +0 -12
  178. package/src/interfaces/notifications/IUserNotificationData.tsx +0 -13
  179. package/src/interfaces/notifications/IUserNotificationPayload.tsx +0 -8
  180. package/src/interfaces/user/IGetAuth.tsx +0 -92
  181. package/src/interfaces/user/ITenantSettings.tsx +0 -3
  182. package/src/interfaces/user/IUser.tsx +0 -60
  183. package/src/interfaces/user/IUserSettings.tsx +0 -43
  184. package/src/interfaces.tsx +0 -6
  185. package/src/layout/AppLayout.tsx +0 -112
  186. package/src/layout/ApplicationLayout.tsx +0 -197
  187. package/src/layout/MotionWrapper.original.tsx +0 -236
  188. package/src/layout/MotionWrapper.tsx +0 -236
  189. package/src/layout/ResourceMenu.tsx +0 -164
  190. package/src/layout/ResoureLayout.tsx +0 -105
  191. package/src/layout/TransitionWrapper.tsx +0 -125
  192. package/src/pages/ChangePassword.tsx +0 -179
  193. package/src/pages/DASHLanding.tsx +0 -22
  194. package/src/pages/DASHLightWeightLogin.tsx +0 -611
  195. package/src/pages/DASHSimpleLogin.tsx +0 -260
  196. package/src/pages/Login.tsx +0 -111
  197. package/src/pages/Profile.tsx +0 -357
  198. package/src/pages/RecoverPassword.tsx +0 -175
  199. package/src/pages/SingleImageUploader.tsx +0 -55
  200. package/src/pages/VerifyAccount.tsx +0 -128
  201. package/src/providers/authProvider.tsx +0 -217
  202. package/src/providers/dataProvider.tsx +0 -672
  203. package/src/providers/i18n/en.ts +0 -646
  204. package/src/providers/i18n/es.ts +0 -652
  205. package/src/providers/i18n/languages.tsx +0 -8
  206. package/src/providers/i18n/mergeTranslations.ts +0 -53
  207. package/src/providers/i18nProvider.tsx +0 -23
  208. package/src/react-admin-dash/RADashComponent.tsx +0 -240
  209. package/src/react-admin-dash/Resource.tsx +0 -77
  210. package/src/resources/Brand/BrandResource.tsx +0 -130
  211. package/src/resources/DASHResourceLoader.ts +0 -180
  212. package/src/resources/Log/LogResource.tsx +0 -73
  213. package/src/resources/Tenant/ImpersonateTenantResource.tsx +0 -113
  214. package/src/resources/Trash/TrashTemplate.tsx +0 -180
  215. package/src/resources/User/components/AvatarUploadField.tsx +0 -57
  216. package/src/resources/User/components/PasswordFields.tsx +0 -73
  217. package/src/resources/User/getProfileMenu.ts +0 -57
  218. package/src/resources/User/profileResource.tsx +0 -51
  219. package/src/resources/User/userLayout.tsx +0 -62
  220. package/src/resources/User/userResource.tsx +0 -111
  221. package/src/resources/User/userSchema.tsx +0 -213
  222. package/src/resources/User/usersFilters.tsx +0 -21
  223. package/src/resources.tsx +0 -280
  224. package/src/schemas/log.tsx +0 -45
  225. package/src/schemas/notification.tsx +0 -42
  226. package/src/schemas/permissions.tsx +0 -44
  227. package/src/schemas/roles.tsx +0 -48
  228. package/src/schemas/rolesDataGrid.tsx +0 -48
  229. package/src/schemas/subscription/components/SubscriptionActions.tsx +0 -153
  230. package/src/schemas/subscription/components/SubscriptionPaymentHistory.tsx +0 -127
  231. package/src/schemas/subscription/components/SubscriptionPlanFeatures.tsx +0 -162
  232. package/src/schemas/subscription/components/SubscriptionPlanPreview.tsx +0 -141
  233. package/src/schemas/subscription/components/SubscriptionPlanStats.tsx +0 -318
  234. package/src/schemas/subscription/components/SubscriptionStatusIndicator.tsx +0 -72
  235. package/src/schemas/subscription/subscriptionPlanSchema.tsx +0 -185
  236. package/src/schemas/subscription/subscriptionSchema.tsx +0 -152
  237. package/src/schemas/subscriptionPlan.ts +0 -422
  238. package/src/schemas/tenant.tsx +0 -129
  239. package/src/schemas/tenantUser.tsx +0 -96
  240. package/src/schemas/tenant_superadmin.tsx +0 -119
  241. package/src/schemas/user.tsx +0 -26
  242. package/src/systemResources.old.tsx +0 -928
  243. package/src/systemResources.tsx +0 -1369
  244. package/src/templates/ResourceTemplate.tsx +0 -240
  245. package/src/templates/ResourceTemplate.tsx.memoized_experiment +0 -350
  246. package/src/templates/ResourceTemplate.tsx.original +0 -396
  247. package/src/templates/ResourceTemplateCreate.tsx +0 -182
  248. package/src/templates/ResourceTemplateEdit.tsx +0 -176
  249. package/src/templates/ResourceTemplateFull.tsx +0 -581
  250. package/src/templates/ResourceTemplateList.tsx +0 -340
  251. package/src/templates/ResourceTemplateOld.tsx.bkup +0 -567
  252. package/src/templates/ResourceTemplateShow.tsx +0 -88
  253. package/src/templates/TrashTemplate.tsx +0 -179
  254. package/src/tenantResources.tsx +0 -223
  255. package/src/test_portal_bubbles.tsx +0 -40
  256. package/src/theme/AppHeader.tsx +0 -52
  257. package/src/theme/AppLayoutSetting.tsx +0 -33
  258. package/src/theme/AppLogo.tsx +0 -13
  259. package/src/theme/AppSidebar.tsx +0 -12
  260. package/src/theme/AppSidebarContent.tsx +0 -105
  261. package/src/theme/AppSidebarLogo.tsx +0 -48
  262. package/src/theme/components/PageTitle.tsx +0 -37
  263. package/src/utils/cache/CacheInvalidatorContext.tsx +0 -125
  264. package/src/utils/cache/CacheInvalidatorListenerComponent.tsx +0 -10
  265. package/src/utils/cache/useCacheInvalidatorListener.tsx +0 -27
  266. package/src/utils/convertFileToBase64.tsx +0 -9
  267. package/src/utils/convertToFile.tsx +0 -14
  268. package/src/utils/cookies.tsx +0 -33
  269. package/src/utils/dashDefaultQueryClient.tsx +0 -34
  270. package/src/utils/dataUrlToBlob.tsx +0 -30
  271. package/src/utils/deepReplace.tsx +0 -19
  272. package/src/utils/getProfileMenu.tsx +0 -41
  273. package/src/utils/getTenantSettings.tsx +0 -9
  274. package/src/utils/getType.tsx +0 -8
  275. package/src/utils/getUserSettings.tsx +0 -8
  276. package/src/utils/hasCode.tsx +0 -14
  277. package/src/utils/index.ts +0 -19
  278. package/src/utils/injectTenantStyles.ts +0 -28
  279. package/src/utils/isComponent.tsx +0 -45
  280. package/src/utils/navEvents.tsx +0 -91
  281. package/src/utils/prototypes.tsx +0 -5
  282. package/src/utils/regexp.tsx +0 -4
  283. package/src/utils/resolveObjectPath.tsx +0 -4
  284. package/src/utils/setNativeValue.tsx +0 -24
  285. package/src/utils/slugify.tsx +0 -11
  286. package/src/utils/validators/emailValidator.tsx +0 -6
  287. package/src/utils/validators/requiredValidator.tsx +0 -5
  288. package/src/utils/validators/rutValidator.tsx +0 -31
  289. 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;