@dashadmin/dash-admin 1.3.45 → 1.3.47

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 (43) hide show
  1. package/dist/components/i18n/BridgedLocalesMenuButton.js +1 -2
  2. package/dist/components/menu/DarkToggleMode.js +1 -1
  3. package/dist/components/subscription/PlanPricesSettings.js +4 -2
  4. package/dist/components/tenancy/GlobalTenantWrapper.js +64 -0
  5. package/dist/components/tenancy/TenantSwitcher.js +389 -0
  6. package/dist/contexts/com/components/EchoNotificationsCenter.js +40 -0
  7. package/dist/default-theme/menu/AppMenuComponents/expanded/SidebarItem.js +1 -0
  8. package/dist/index.js +60 -40
  9. package/dist/pages/Profile.js +32 -38
  10. package/dist/providers/i18n/en.js +33 -0
  11. package/dist/providers/i18n/es.js +33 -0
  12. package/dist/resources/User/components/AvatarUploadField.js +61 -0
  13. package/dist/resources/User/components/PasswordFields.js +67 -0
  14. package/dist/resources/User/getProfileMenu.js +36 -0
  15. package/dist/resources/User/profileResource.js +33 -0
  16. package/dist/resources/User/userLayout.js +58 -0
  17. package/dist/resources/User/userResource.js +90 -0
  18. package/dist/resources/User/userSchema.js +206 -0
  19. package/dist/resources/User/usersFilters.js +22 -0
  20. package/dist/systemResources.js +30 -19
  21. package/package.json +1 -1
  22. package/src/components/i18n/BridgedLocalesMenuButton.tsx +1 -2
  23. package/src/components/menu/DarkToggleMode.tsx +1 -1
  24. package/src/components/subscription/PlanPricesSettings.tsx +2 -2
  25. package/src/components/tenancy/GlobalTenantWrapper.tsx +84 -0
  26. package/src/components/tenancy/TenantSwitcher.tsx +485 -0
  27. package/src/contexts/com/components/EchoNotificationsCenter.tsx +65 -0
  28. package/src/default-theme/menu/AppMaterialMenu.tsx +1 -1
  29. package/src/default-theme/menu/AppMenuComponents/expanded/SidebarItem.tsx +1 -0
  30. package/src/default-theme/menu/SidebarActions.tsx +1 -1
  31. package/src/index.tsx +15 -0
  32. package/src/pages/Profile.tsx +69 -107
  33. package/src/providers/i18n/en.ts +33 -0
  34. package/src/providers/i18n/es.ts +33 -0
  35. package/src/resources/User/components/AvatarUploadField.tsx +57 -0
  36. package/src/resources/User/components/PasswordFields.tsx +73 -0
  37. package/src/resources/User/getProfileMenu.ts +57 -0
  38. package/src/resources/User/profileResource.tsx +51 -0
  39. package/src/resources/User/userLayout.tsx +62 -0
  40. package/src/resources/User/userResource.tsx +111 -0
  41. package/src/resources/User/userSchema.tsx +213 -0
  42. package/src/resources/User/usersFilters.tsx +21 -0
  43. package/src/systemResources.tsx +31 -20
@@ -0,0 +1,58 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Box, Card, Grid } from "@mui/material";
3
+ const userLayout = (render) => {
4
+ return /* @__PURE__ */ jsxs(Grid, { container: true, spacing: 1, children: [
5
+ /* @__PURE__ */ jsx(Grid, { size: { xs: 12, md: 4 }, children: /* @__PURE__ */ jsxs(Grid, { container: true, children: [
6
+ /* @__PURE__ */ jsx(Grid, { size: 12, children: /* @__PURE__ */ jsxs(Card, { sx: { mb: 1 }, className: "dash-widget", children: [
7
+ /* @__PURE__ */ jsx(
8
+ Box,
9
+ {
10
+ sx: { p: 1 },
11
+ style: { display: "flex", alignItems: "center" },
12
+ children: /* @__PURE__ */ jsx("span", { className: "card-title", children: "Avatar" })
13
+ }
14
+ ),
15
+ /* @__PURE__ */ jsx(Box, { sx: { p: 1 }, children: render("Avatar") })
16
+ ] }) }),
17
+ /* @__PURE__ */ jsx(Grid, { size: 12, children: /* @__PURE__ */ jsxs(Card, { sx: { mb: 1 }, className: "dash-widget", children: [
18
+ /* @__PURE__ */ jsx(
19
+ Box,
20
+ {
21
+ sx: { p: 1 },
22
+ style: { display: "flex", alignItems: "center" },
23
+ children: /* @__PURE__ */ jsx("span", { className: "card-title", children: "Credenciales" })
24
+ }
25
+ ),
26
+ /* @__PURE__ */ jsx(Box, { sx: { p: 1 }, children: render("Credenciales") })
27
+ ] }) })
28
+ ] }) }),
29
+ /* @__PURE__ */ jsx(Grid, { size: { xs: 12, md: 8 }, children: /* @__PURE__ */ jsxs(Grid, { container: true, children: [
30
+ /* @__PURE__ */ jsx(Grid, { size: 12, children: /* @__PURE__ */ jsxs(Card, { sx: { mb: 1 }, className: "dash-widget", children: [
31
+ /* @__PURE__ */ jsx(
32
+ Box,
33
+ {
34
+ sx: { p: 1 },
35
+ style: { display: "flex", alignItems: "center" },
36
+ children: /* @__PURE__ */ jsx("span", { className: "card-title", children: "Datos del usuario" })
37
+ }
38
+ ),
39
+ /* @__PURE__ */ jsx(Box, { sx: { p: 1 }, children: render("Datos del usuario") })
40
+ ] }) }),
41
+ /* @__PURE__ */ jsx(Grid, { size: 12, children: /* @__PURE__ */ jsxs(Card, { sx: { mb: 1 }, className: "dash-widget", children: [
42
+ /* @__PURE__ */ jsx(
43
+ Box,
44
+ {
45
+ sx: { p: 1 },
46
+ style: { display: "flex", alignItems: "center" },
47
+ children: /* @__PURE__ */ jsx("span", { className: "card-title", children: "Configuraci\xF3n" })
48
+ }
49
+ ),
50
+ /* @__PURE__ */ jsx(Box, { sx: { p: 1 }, children: render("Configuraci\xF3n") })
51
+ ] }) })
52
+ ] }) })
53
+ ] });
54
+ };
55
+ var userLayout_default = userLayout;
56
+ export {
57
+ userLayout_default as default
58
+ };
@@ -0,0 +1,90 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import ResourceTemplate from "../../templates/ResourceTemplate";
3
+ import Settings from "@mui/icons-material/Settings";
4
+ import { PaginationComponent } from "dash-components";
5
+ import { DASHAppConstants } from "dash-constants";
6
+ import { DASHAdminSystemConstants } from "dash-constants";
7
+ import userLayout from "./userLayout";
8
+ import userSchema from "./userSchema";
9
+ import { NoResults } from "../../components/misc/NoResults";
10
+ import usersFilters from "./usersFilters";
11
+ const userResource = {
12
+ filterWithSubmit: true,
13
+ roles: [
14
+ DASHAdminSystemConstants.system.DASH_SYSTEM_ROLE,
15
+ DASHAppConstants.system.TENANT_ROLE
16
+ ],
17
+ component: ResourceTemplate,
18
+ trash: true,
19
+ model: "tenant/user",
20
+ schema: userSchema,
21
+ icon: /* @__PURE__ */ jsx(Settings, {}),
22
+ group: "resource.groups.configuration",
23
+ label: "resource.ecommerce.users.label",
24
+ menu: [
25
+ {
26
+ title: "Usuarios",
27
+ redirect: "/tenant/user"
28
+ },
29
+ {
30
+ title: "\u{1F5D1}",
31
+ redirect: "/tenant/user/trash"
32
+ }
33
+ ],
34
+ resourceMenuDisabled: false,
35
+ refreshAfter: true,
36
+ /*customListActions: (props) => {
37
+ const { children } = props;
38
+ return <Card sx={{ mb: 2 }} className='dash-card-content dash-module top-toolbar'>{children}</Card>;
39
+ },*/
40
+ isFormData: true,
41
+ /** @deprecated TODO: side effects? seems is not implemented anywhere */
42
+ listEditButton: { enabled: true },
43
+ postFormatter: (params, _method) => {
44
+ if (!params.avatar) {
45
+ delete params.avatar;
46
+ }
47
+ return params;
48
+ },
49
+ dataGridProps: { stickyHeader: true, empty: /* @__PURE__ */ jsx(NoResults, {}), bulkActionButtons: false },
50
+ listProps: { perPage: DASHAdminSystemConstants.system.DEFAULT_PER_PAGE || 50, empty: false },
51
+ dataGridWrapper: (props) => {
52
+ const { children } = props;
53
+ return /* @__PURE__ */ jsx("div", { className: "sticky-header-wrapper", children });
54
+ },
55
+ redirectAfterUpdate: false,
56
+ createLayout: userLayout,
57
+ editLayout: userLayout,
58
+ formGroupMode: "layout",
59
+ /*exporter: (clients) => {
60
+ const clientsForExport = clients.map((client) => {
61
+ return client;
62
+ });
63
+ jsonExport(
64
+ clientsForExport,
65
+ {
66
+ //headers: ['id', 'title', 'author_name', 'body'] // order fields in the export
67
+ },
68
+ (err, csv) => {
69
+ downloadCSV(csv, 'clientes');
70
+ },
71
+ );
72
+ },*/
73
+ create: true,
74
+ edit: true,
75
+ view: false,
76
+ listViewButton: { enabled: false },
77
+ toolbarCreateButton: { enabled: true },
78
+ toolbarEditButton: { enabled: false },
79
+ toolbarExportButton: { enabled: false },
80
+ toolbarListButton: { enabled: true },
81
+ listDeleteButton: { enabled: true, props: { confirm: true } },
82
+ Pagination: PaginationComponent,
83
+ drawer: false,
84
+ mutationMode: "pessimistic",
85
+ referenceFilters: usersFilters
86
+ };
87
+ var userResource_default = userResource;
88
+ export {
89
+ userResource_default as default
90
+ };
@@ -0,0 +1,206 @@
1
+ import { SelectArrayInput } from "react-admin";
2
+ import { RutValidator } from "../../utils/validators";
3
+ import AvatarUploadField from "./components/AvatarUploadField";
4
+ import PasswordFields from "./components/PasswordFields";
5
+ const userSchema = [
6
+ {
7
+ tab: "Datos del usuario",
8
+ attribute: "id",
9
+ label: "Id",
10
+ type: String,
11
+ sortable: true,
12
+ inEdit: false,
13
+ inCreate: false
14
+ },
15
+ {
16
+ tab: "Datos del usuario",
17
+ attribute: "public_id",
18
+ label: "Rut",
19
+ type: String,
20
+ fieldOptions: { required: true, showDiv: true, fullWidth: true },
21
+ sortable: true,
22
+ inEdit: true,
23
+ inCreate: true,
24
+ inShow: true,
25
+ inList: false,
26
+ validate: (value) => {
27
+ if (!value) throw Error("El campo es requerido");
28
+ if (!RutValidator(value)) {
29
+ throw Error("El Rut es inv\xE1lido");
30
+ }
31
+ }
32
+ },
33
+ {
34
+ tab: "Datos del usuario",
35
+ attribute: "name",
36
+ label: "Nombre",
37
+ type: String,
38
+ sortable: true,
39
+ inEdit: true,
40
+ inCreate: true,
41
+ inShow: false,
42
+ inList: false,
43
+ fieldOptions: { required: true }
44
+ },
45
+ {
46
+ tab: "Datos del usuario",
47
+ attribute: "lastname",
48
+ label: "Apellido",
49
+ type: String,
50
+ sortable: true,
51
+ inEdit: true,
52
+ inCreate: true,
53
+ inShow: true,
54
+ inList: false,
55
+ fieldOptions: { required: true }
56
+ },
57
+ {
58
+ tab: "Datos del usuario",
59
+ attribute: "full_name",
60
+ label: "Nombre",
61
+ type: String,
62
+ sortable: true,
63
+ inEdit: false,
64
+ inShow: true,
65
+ inCreate: false,
66
+ fieldOptions: { required: true }
67
+ },
68
+ {
69
+ tab: "Datos del usuario",
70
+ attribute: "email",
71
+ label: "Email",
72
+ type: String,
73
+ sortable: true,
74
+ inEdit: true,
75
+ inShow: true,
76
+ inCreate: true,
77
+ fieldOptions: { required: true }
78
+ },
79
+ {
80
+ tab: "Datos del usuario",
81
+ attribute: "phone",
82
+ label: "Telefono",
83
+ type: String,
84
+ sortable: true,
85
+ inEdit: true,
86
+ inCreate: true,
87
+ inShow: true,
88
+ inList: false
89
+ },
90
+ /*{
91
+ tab: 'Configuración',
92
+ attribute: 'active',
93
+ type: Boolean,
94
+ inList: true,
95
+ inCreate: false,
96
+ label: 'Activo',
97
+ showLabel: false,
98
+ processor: 'Boolean',
99
+ },*/
100
+ {
101
+ tab: "Credenciales",
102
+ attribute: "password",
103
+ label: "Contrase\xF1a",
104
+ type: String,
105
+ sortable: true,
106
+ inEdit: false,
107
+ inCreate: false,
108
+ inShow: false,
109
+ inList: false
110
+ },
111
+ {
112
+ tab: "Credenciales",
113
+ attribute: "password_confirmation",
114
+ label: "Confirma Contrase\xF1a",
115
+ type: String,
116
+ sortable: true,
117
+ inEdit: false,
118
+ inCreate: false,
119
+ inShow: false,
120
+ inList: false
121
+ },
122
+ /*{
123
+ tab: 'Credenciales',
124
+ attribute: 'role_id',
125
+ type: 'system/role/forSelect.name',
126
+ label: 'Rol de usuario',
127
+ componentProps: {
128
+ filter: { substitutable: true } // Shows only substituable roles for current user, backend logic.
129
+ },
130
+ sortable: true,
131
+ inEdit: true,
132
+ inCreate: true,
133
+ inShow: true,
134
+ inList: false,
135
+ multiple: false,
136
+ },*/
137
+ {
138
+ tab: "Credenciales",
139
+ label: "Roles",
140
+ attribute: "role_ids",
141
+ //listAttribute: 'name',
142
+ // system/role is core-owned and works for every domain (kitchntabs-*, vanexa-*),
143
+ // unlike tenant/role which only exists in kitchntabs-backend-domain
144
+ // (Domain\App\Http\Controllers\API\ECommerce\RoleController — an empty
145
+ // Domain\App\Models\ECommerce\Role subclass of the same core Role/roles table,
146
+ // with equivalent privilege-level-based visibility filtering).
147
+ type: "system/role/forSelect.name",
148
+ //type: Object,
149
+ // TODO Agregar un filtro, solo para traer los roles de cliente.
150
+ pagination: false,
151
+ multiple: true,
152
+ //custom: true,
153
+ //componentProps:{ options: {fullwidth: true} },
154
+ component: SelectArrayInput
155
+ //searchField: "subdomain"
156
+ },
157
+ {
158
+ // @TODO Solo mostrar cuando se está creando:
159
+ label: "Genear Contrase\xF1a Aleatorea Autom\xE1ticamente",
160
+ attribute: "generate_password",
161
+ type: Boolean,
162
+ inList: false,
163
+ inEdit: false,
164
+ tab: "Configuraci\xF3n"
165
+ },
166
+ {
167
+ attribute: "active",
168
+ type: Boolean,
169
+ inList: true,
170
+ label: "Activo",
171
+ tab: "Configuraci\xF3n",
172
+ processor: "Boolean"
173
+ },
174
+ {
175
+ tab: "Avatar",
176
+ attribute: "avatar",
177
+ listAttribute: "image_url",
178
+ label: "Foto Usuario",
179
+ type: String,
180
+ sortable: true,
181
+ inEdit: true,
182
+ inCreate: true,
183
+ inShow: true,
184
+ inList: false,
185
+ custom: true,
186
+ component: AvatarUploadField,
187
+ processor: "File"
188
+ },
189
+ {
190
+ tab: "Credenciales",
191
+ attribute: "password",
192
+ label: "Contrase\xF1a",
193
+ type: String,
194
+ sortable: true,
195
+ inList: false,
196
+ inEdit: true,
197
+ inCreate: true,
198
+ custom: true,
199
+ inShow: false,
200
+ component: PasswordFields
201
+ }
202
+ ];
203
+ var userSchema_default = userSchema;
204
+ export {
205
+ userSchema_default as default
206
+ };
@@ -0,0 +1,22 @@
1
+ const usersReferenceFilters = [
2
+ {
3
+ id: "q",
4
+ label: "Nombres/Email/Busqueda General",
5
+ source: "q",
6
+ alwaysOn: true,
7
+ reference: null,
8
+ optionText: null
9
+ },
10
+ {
11
+ id: "email",
12
+ label: "Email",
13
+ source: "email",
14
+ alwaysOn: true,
15
+ reference: null,
16
+ optionText: null
17
+ }
18
+ ];
19
+ var usersFilters_default = usersReferenceFilters;
20
+ export {
21
+ usersFilters_default as default
22
+ };
@@ -29,6 +29,8 @@ import Avatar from "./components/avatar/Avatar";
29
29
  import SystemUpdateAlt from "@mui/icons-material/SystemUpdateAlt";
30
30
  import Person from "@mui/icons-material/Person";
31
31
  import CardMembershipIcon from "@mui/icons-material/CardMembership";
32
+ import PaidIcon from "@mui/icons-material/Paid";
33
+ import TranslateIcon from "@mui/icons-material/Translate";
32
34
  import { lazy } from "react";
33
35
  import BusinessIcon from "@mui/icons-material/Business";
34
36
  import Chip from "@mui/material/Chip";
@@ -878,12 +880,19 @@ const systemResources = [
878
880
  redirectAfterUpdate: false,
879
881
  redirectAfterCreate: true
880
882
  }, drawerSettings),
883
+ // ============ Currency Management (core shared master data) ============
884
+ // Backed by dash-backend core's system/currency route (App\Http\Controllers\
885
+ // API\System\CurrencyController). Previously pointed at the domain's
886
+ // ecommerce/currency route — currencies moved to core as "shared master
887
+ // data" (see CLAUDE.md's core/domain split), so every app using this
888
+ // shared systemResources manifest (kitchntabs-*, vanexa-*) now gets a
889
+ // working Currencies page with no domain layer required.
881
890
  {
882
891
  roles: [DASHAppConstants.system.SYSTEM_ROLE],
883
892
  component: ResourceTemplate,
884
893
  trash: true,
885
- model: "ecommerce/currency",
886
- label: "resource.ecommerce.currencies.label",
894
+ model: "system/currency",
895
+ label: "resource.system.currencies.label",
887
896
  schema: [
888
897
  {
889
898
  label: "C\xF3digo",
@@ -920,23 +929,20 @@ const systemResources = [
920
929
  component: FormatCurrency
921
930
  }
922
931
  ],
923
- //references: [{ reference: 'roles', target: 'role', schema: rolesSchema }]
924
- //references: [{ reference: 'roles', target: 'id', schema: roleSchema }],
925
- icon: /* @__PURE__ */ jsx(Person, {}),
926
- // group: "resource.groups.system_resources",
932
+ icon: /* @__PURE__ */ jsx(PaidIcon, {}),
927
933
  group: "System",
928
934
  menu: [
929
935
  {
930
- title: "resource.ecommerce.currencies.menu_list",
931
- redirect: "/ecommerce/currency"
936
+ title: "resource.system.currencies.menu_list",
937
+ redirect: "/system/currency"
932
938
  },
933
939
  {
934
940
  title: "\u{1F5D1}",
935
- redirect: "/ecommerce/currency/trash"
941
+ redirect: "/system/currency/trash"
936
942
  }
937
943
  ],
938
944
  mainAction: {
939
- title: "resource.ecommerce.currencies.main_action",
945
+ title: "resource.system.currencies.main_action",
940
946
  mode: "create",
941
947
  fn: "virtualhash",
942
948
  redirect: "inline/create"
@@ -950,16 +956,21 @@ const systemResources = [
950
956
  mutationMode: "pessimistic",
951
957
  saveButtonAlwaysEnabled: true,
952
958
  listProps: { storeKey: false, filterDefaultValues: { show_disabled: true } },
953
- // deshabilita persistencia deel estado, cache de los valores seleccionados sort, page, etc.
954
959
  resetSelectedIdsOnLoad: true
955
960
  },
956
- // ============ Language Management ============
961
+ // ============ Language Management (core shared master data) ============
962
+ // Backed by dash-backend core's system/language route (App\Http\Controllers\
963
+ // API\System\LanguageController). Previously pointed at the domain's
964
+ // common/language route — languages moved to core as "shared master data"
965
+ // (see CLAUDE.md's core/domain split), so every app using this shared
966
+ // systemResources manifest (kitchntabs-*, vanexa-*) now gets a working
967
+ // Languages page with no domain layer required.
957
968
  {
958
969
  roles: [DASHAppConstants.system.SYSTEM_ROLE],
959
970
  component: ResourceTemplate,
960
971
  trash: true,
961
- model: "common/language",
962
- label: "resource.common.languages.label",
972
+ model: "system/language",
973
+ label: "resource.system.languages.label",
963
974
  schema: [
964
975
  {
965
976
  label: "Code",
@@ -1003,20 +1014,20 @@ const systemResources = [
1003
1014
  }
1004
1015
  }
1005
1016
  ],
1006
- icon: /* @__PURE__ */ jsx(Person, {}),
1017
+ icon: /* @__PURE__ */ jsx(TranslateIcon, {}),
1007
1018
  group: "System",
1008
1019
  menu: [
1009
1020
  {
1010
- title: "resource.common.languages.menu_list",
1011
- redirect: "/common/language"
1021
+ title: "resource.system.languages.menu_list",
1022
+ redirect: "/system/language"
1012
1023
  },
1013
1024
  {
1014
1025
  title: "\u{1F5D1}",
1015
- redirect: "/common/language/trash"
1026
+ redirect: "/system/language/trash"
1016
1027
  }
1017
1028
  ],
1018
1029
  mainAction: {
1019
- title: "resource.common.languages.main_action",
1030
+ title: "resource.system.languages.main_action",
1020
1031
  mode: "create",
1021
1032
  fn: "virtualhash",
1022
1033
  redirect: "inline/create"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dashadmin/dash-admin",
3
- "version": "1.3.45",
3
+ "version": "1.3.47",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -111,8 +111,7 @@ const BridgedLocalesMenuButton: React.FC<BridgedLocalesMenuButtonProps> = ({
111
111
  <Tooltip title={`Language: ${currentLocaleName}`}>
112
112
  <IconButton
113
113
  onClick={handleClick}
114
- color="inherit"
115
- size="small"
114
+ className="dash-icon-button-color dash-icon-button-bg"
116
115
  aria-label="change language"
117
116
  aria-controls={open ? 'locale-menu' : undefined}
118
117
  aria-haspopup="true"
@@ -38,7 +38,7 @@ const DarkToggleMode = () => {
38
38
 
39
39
  return (
40
40
  <>
41
- <div onClick={onClick}>
41
+ <div className='dash-theme-mode-switcher' onClick={onClick}>
42
42
 
43
43
  <DashThemeHelperProvider>
44
44
  <Avatar
@@ -53,7 +53,7 @@ const PlanPricesView: React.FC<IDashAutoAdminCustomFieldComponent> = () => {
53
53
  const prices = plan?.prices;
54
54
 
55
55
  const { data: currencies, isLoading } = useGetList<Currency>(
56
- 'ecommerce/currency',
56
+ 'system/currency', // core "shared master data" — works for every domain, unlike ecommerce/currency (kitchntabs-backend-domain only)
57
57
  {
58
58
  pagination: { page: 1, perPage: 100 },
59
59
  sort: { field: 'code', order: 'ASC' },
@@ -161,7 +161,7 @@ const PlanPricesEdit: React.FC<IDashAutoAdminCustomFieldComponent> = ({ method }
161
161
 
162
162
  // Fetch available currencies
163
163
  const { data: currencies, isLoading, error } = useGetList<Currency>(
164
- 'ecommerce/currency',
164
+ 'system/currency', // core "shared master data" — works for every domain, unlike ecommerce/currency (kitchntabs-backend-domain only)
165
165
  {
166
166
  pagination: { page: 1, perPage: 100 },
167
167
  sort: { field: 'code', order: 'ASC' },
@@ -0,0 +1,84 @@
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;