ui-soxo-bootstrap-core 2.6.1-dev.3 → 2.6.1-dev.31

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 (68) hide show
  1. package/core/components/extra-info/extra-info-details.js +2 -2
  2. package/core/components/index.js +2 -11
  3. package/core/components/landing-api/landing-api.js +216 -18
  4. package/core/components/landing-api/landing-api.scss +22 -0
  5. package/core/components/license-management/license-alert.js +97 -0
  6. package/core/lib/Store.js +8 -4
  7. package/core/lib/components/global-header/global-header.js +217 -242
  8. package/core/lib/components/index.js +2 -2
  9. package/core/lib/components/sidemenu/sidemenu.js +19 -13
  10. package/core/lib/components/sidemenu/sidemenu.scss +1 -1
  11. package/core/lib/elements/basic/country-phone-input/country-phone-input.js +14 -9
  12. package/core/lib/elements/basic/dragabble-wrapper/draggable-wrapper.js +1 -1
  13. package/core/lib/elements/basic/menu-tree/menu-tree.js +26 -13
  14. package/core/lib/models/forms/components/form-creator/form-creator.js +525 -468
  15. package/core/lib/models/forms/components/form-creator/form-creator.scss +30 -26
  16. package/core/lib/models/menus/components/menu-list/menu-list.js +424 -467
  17. package/core/lib/models/process/components/process-dashboard/process-dashboard.js +469 -3
  18. package/core/lib/models/process/components/process-dashboard/process-dashboard.scss +4 -0
  19. package/core/lib/modules/generic/generic-list/ExportReactCSV.js +28 -2
  20. package/core/lib/pages/change-password/change-password.js +17 -24
  21. package/core/lib/pages/change-password/change-password.scss +45 -48
  22. package/core/lib/pages/login/commnication-mode-selection.js +2 -2
  23. package/core/lib/pages/login/login.js +53 -64
  24. package/core/lib/pages/login/login.scss +9 -0
  25. package/core/lib/pages/login/reset-password.js +17 -17
  26. package/core/lib/pages/login/reset-password.scss +10 -1
  27. package/core/lib/pages/profile/themes.json +4 -4
  28. package/core/lib/utils/api/api.utils.js +53 -45
  29. package/core/lib/utils/common/common.utils.js +49 -35
  30. package/core/lib/utils/generic/generic.utils.js +2 -1
  31. package/core/lib/utils/http/http.utils.js +33 -4
  32. package/core/lib/utils/index.js +4 -1
  33. package/core/models/base/base.js +7 -3
  34. package/core/models/core-scripts/core-scripts.js +147 -126
  35. package/core/models/doctor/components/doctor-add/doctor-add.js +9 -4
  36. package/core/models/menus/components/menu-add/menu-add.js +1 -1
  37. package/core/models/menus/components/menu-lists/menu-lists.js +53 -54
  38. package/core/models/menus/menus.js +49 -2
  39. package/core/models/roles/components/role-add/role-add.js +92 -59
  40. package/core/models/roles/components/role-list/role-list.js +1 -1
  41. package/core/models/staff/components/staff-add/staff-add.js +20 -32
  42. package/core/models/users/components/assign-role/assign-role.js +145 -50
  43. package/core/models/users/components/assign-role/assign-role.scss +209 -45
  44. package/core/models/users/components/assign-role/avatar-props.js +45 -0
  45. package/core/models/users/components/user-add/user-add.js +46 -55
  46. package/core/models/users/components/user-add/user-edit.js +25 -4
  47. package/core/models/users/users.js +9 -1
  48. package/core/modules/dashboard/components/dashboard-card/menu-dashboard-card.js +1 -1
  49. package/core/modules/reporting/components/reporting-dashboard/README.md +316 -0
  50. package/core/modules/reporting/components/reporting-dashboard/adavance-search/advance-search.js +174 -0
  51. package/core/modules/reporting/components/reporting-dashboard/adavance-search/advance-search.scss +76 -0
  52. package/core/modules/reporting/components/reporting-dashboard/display-columns/build-display-columns.js +90 -0
  53. package/core/modules/reporting/components/reporting-dashboard/display-columns/build-display-columns.test.js +74 -0
  54. package/core/modules/reporting/components/reporting-dashboard/display-columns/display-cell-renderer.js +448 -0
  55. package/core/modules/reporting/components/reporting-dashboard/display-columns/display-cell-renderer.test.js +199 -0
  56. package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +195 -822
  57. package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.scss +43 -0
  58. package/core/modules/reporting/components/reporting-dashboard/reporting-table.js +517 -0
  59. package/core/modules/steps/action-buttons.js +30 -16
  60. package/core/modules/steps/action-buttons.scss +55 -9
  61. package/core/modules/steps/chat-assistant.js +141 -0
  62. package/core/modules/steps/openai-realtime.js +275 -0
  63. package/core/modules/steps/readme.md +167 -0
  64. package/core/modules/steps/steps.js +1286 -60
  65. package/core/modules/steps/steps.scss +703 -86
  66. package/core/modules/steps/timeline.js +21 -19
  67. package/core/modules/steps/voice-navigation.js +709 -0
  68. package/package.json +2 -1
@@ -21,7 +21,7 @@ import ExtraInfo from './extra-info';
21
21
 
22
22
  const { TabPane } = Tabs;
23
23
 
24
- export default function ExtraInfoDetail({ modeValue, icon, title, tabPosition = 'left', showDrawerData, dbPtr, callback, ...record }) {
24
+ export default function ExtraInfoDetail({ modeValue, icon, title, tabPosition = 'left', showDrawerData, dbPtr, callback, drawerWidth = '35%', ...record }) {
25
25
  // State to control drawer
26
26
  const [open, setOpen] = useState(false);
27
27
 
@@ -121,7 +121,7 @@ export default function ExtraInfoDetail({ modeValue, icon, title, tabPosition =
121
121
  {/* */}
122
122
 
123
123
  {/* */}
124
- <Drawer width={'35%'} title={title} onClose={onClose} open={open}>
124
+ <Drawer width={drawerWidth} title={title} onClose={onClose} open={open}>
125
125
  <div className="main-drawer-content">
126
126
  <div className="drawer-container">
127
127
  <div className="drawer-click">
@@ -1,7 +1,3 @@
1
-
2
-
3
-
4
-
5
1
  import LandingAPI from './landing-api/landing-api';
6
2
 
7
3
  import ExtraInfoDetail from './extra-info/extra-info-details';
@@ -11,11 +7,6 @@ import RootApplicationAPI from './root-application-api/root-application-api';
11
7
  import { HomePageAPI } from '../modules';
12
8
 
13
9
  import { ExternalWindow } from './external-window/external-window';
10
+ import LicenseAlert from './license-management/license-alert';
14
11
 
15
- export {
16
- LandingAPI,
17
- RootApplicationAPI,
18
- ExtraInfoDetail,
19
- HomePageAPI,
20
- ExternalWindow
21
- }
12
+ export { LandingAPI, RootApplicationAPI, ExtraInfoDetail, HomePageAPI, ExternalWindow, LicenseAlert };
@@ -1,10 +1,21 @@
1
- import React, { useState, useEffect, useContext } from 'react';
1
+ import React, { useState, useEffect, useContext, useRef } from 'react';
2
2
 
3
3
  import { Route, Switch } from 'react-router-dom';
4
4
 
5
- import { Skeleton } from 'antd';
6
-
7
- import { GlobalHeader, ChangePassword, useTranslation, GlobalContext, ModuleRoutes, SpotlightSearch, SettingsUtil, Profile, Card } from '../../lib';
5
+ import { Skeleton, message, Modal } from 'antd';
6
+
7
+ import {
8
+ GlobalHeader,
9
+ ChangePassword,
10
+ useTranslation,
11
+ GlobalContext,
12
+ ModuleRoutes,
13
+ SpotlightSearch,
14
+ SettingsUtil,
15
+ Profile,
16
+ Card,
17
+ safeJSON,
18
+ } from '../../lib';
8
19
 
9
20
  import './landing-api.scss';
10
21
 
@@ -18,15 +29,34 @@ import PropTypes from 'prop-types';
18
29
 
19
30
  import { MenusAPI, CoreScripts } from '../../models';
20
31
 
32
+ const motivatingMessages = [
33
+ 'Setting things up for a great start...',
34
+ 'Good things are loading. Stay with us.',
35
+ 'Almost there. Preparing your workspace.',
36
+ 'You are one moment away from your dashboard.',
37
+ 'Getting everything ready for you.',
38
+ 'Great care takes a second. Loading now.',
39
+ ];
40
+
41
+ function getRandomMessage(previousMessage = '') {
42
+ const options = motivatingMessages.filter((message) => message !== previousMessage);
43
+
44
+ if (!options.length) {
45
+ return motivatingMessages[0];
46
+ }
47
+
48
+ const randomIndex = Math.floor(Math.random() * options.length);
49
+ return options[randomIndex];
50
+ }
51
+
21
52
  /**
22
53
  * Landing API
23
54
  *
24
55
  * @param {*} param0
25
56
  * @returns
26
57
  */
27
- export default function LandingApi({ history, CustomComponents, CustomModels, appSettings, ...props }) {
58
+ export default function LandingApi({ history, CustomComponents, CustomModels, appSettings, transitionPending = false, onHomeReady, ...props }) {
28
59
  const [loader, setLoader] = useState(false);
29
-
30
60
  // const [modules, setModules] = useState([]);
31
61
 
32
62
  const [connected] = useState();
@@ -34,13 +64,22 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
34
64
  const { dispatch, user = {} } = useContext(GlobalContext);
35
65
 
36
66
  const [allModules, setAllModules] = useState();
67
+ const homeReadyNotifiedRef = useRef(false);
68
+ const messageIntervalRef = useRef(null);
37
69
 
38
70
  const [meta, setMeta] = useState({});
71
+ const [loadingMessage, setLoadingMessage] = useState('');
72
+ const [licenseData, setLicenseData] = useState(null);
73
+
74
+ const [licAlert, setLicAlert] = useState(false);
75
+ // License data state
39
76
 
40
77
  // const [reports, setReports] = useState([]);
41
78
 
42
79
  var config = {};
43
80
 
81
+ //fetch license summary
82
+
44
83
  // Variable decides the control of homepage
45
84
  // #TODO This is a temporary fix - Homemage
46
85
 
@@ -50,6 +89,70 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
50
89
  disableHomepage = JSON.parse(process.env.REACT_APP_DISABLEHOMEPAGE);
51
90
  }
52
91
 
92
+ /**
93
+ * Normalizes the user's branch access list from `organization_details`.
94
+ *
95
+ * The API can return `organization_details` as a JSON string, so we always
96
+ * parse it through `safeJSON` before reading the branch collection.
97
+ *
98
+ * @returns {Array} List of branches the current user can access.
99
+ */
100
+ const getAccessibleBranches = () => {
101
+ const orgDetails = safeJSON(user?.organization_details);
102
+ return Array.isArray(orgDetails?.branch) ? orgDetails.branch : [];
103
+ };
104
+
105
+ /**
106
+ * Resolves the currently selected branch record using the persisted db pointer.
107
+ *
108
+ * @param {Array} branches
109
+ * @returns {Object|null}
110
+ */
111
+ const getCurrentBranchRecord = (branches) => {
112
+ const currentDbPtr = localStorage.getItem('db_ptr');
113
+ return branches.find((branch) => String(branch.dbPtr) === String(currentDbPtr)) || null;
114
+ };
115
+
116
+ /**
117
+ * Resolves the target branch from the URL `index` query parameter.
118
+ *
119
+ * @param {Array} branches
120
+ * @param {string|null} branchId
121
+ * @returns {Object|null}
122
+ */
123
+ const getBranchRecordById = (branches, branchId) => {
124
+ return branches.find((branch) => String(branch.branch_id) === String(branchId)) || null;
125
+ };
126
+
127
+ /**
128
+ * Persists branch-specific auth data after a successful switch.
129
+ *
130
+ * @param {Object} tokenBundle
131
+ * @param {string} dbPtr
132
+ */
133
+ const persistBranchSession = (tokenBundle, dbPtr) => {
134
+ const accessToken = tokenBundle?.access_token;
135
+ const refreshToken = tokenBundle?.refresh_token;
136
+
137
+ if (accessToken) localStorage.setItem('access_token', accessToken);
138
+ if (refreshToken) localStorage.setItem('refresh_token', refreshToken);
139
+ if (dbPtr) localStorage.setItem('db_ptr', dbPtr);
140
+ };
141
+
142
+ const fetchSummary = async () => {
143
+ try {
144
+ const res = await MenusAPI.getSummary();
145
+ if (res?.data) {
146
+ setLicenseData(res?.data);
147
+ setLicAlert(true);
148
+ } else {
149
+ setLicenseData(null);
150
+ setLicAlert(false);
151
+ }
152
+ } catch (err) {
153
+ console.error(err);
154
+ }
155
+ };
53
156
  // useEffect(() => {
54
157
 
55
158
  // // Initialize the menus for the logged in user
@@ -65,19 +168,122 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
65
168
  // }
66
169
  // }, [loader]);
67
170
 
171
+ /**
172
+ * Synchronizes the active branch with the `index` query parameter.
173
+ *
174
+ * Flow:
175
+ * 1. Read the target branch id from the URL.
176
+ * 2. Compare it against the branch represented by the current `db_ptr`.
177
+ * 3. Switch branch only when the user has access and the branch actually differs.
178
+ * 4. Refresh auth/profile state and reload menus for the new branch context.
179
+ */
180
+ useEffect(() => {
181
+ const handleUrlBranchSwitch = async () => {
182
+ const searchParams = new URLSearchParams(history.location.search);
183
+ const urlDbPtr = searchParams.get('index');
184
+ if (!urlDbPtr) return;
185
+
186
+ const accessibleBranches = getAccessibleBranches();
187
+ const currentBranch = getCurrentBranchRecord(accessibleBranches);
188
+ const targetBranch = getBranchRecordById(accessibleBranches, urlDbPtr);
189
+
190
+ if (!targetBranch || String(currentBranch?.branch_id) === String(urlDbPtr)) return;
191
+
192
+ setLoader(true);
193
+
194
+ try {
195
+ const switchResult = await MenusAPI.switchBranch(
196
+ {
197
+ firm_id: targetBranch.firm_ptr,
198
+ branch_id: targetBranch.branch_id,
199
+ },
200
+ targetBranch.dbPtr
201
+ );
202
+
203
+ if (!switchResult?.success) {
204
+ Modal.error({
205
+ title: 'Branch Switch Failed',
206
+ content: switchResult?.message || 'An error occurred while attempting to switch branches.',
207
+ });
208
+ return;
209
+ }
210
+
211
+ persistBranchSession(switchResult?.token, targetBranch.dbPtr);
212
+ window.dispatchEvent(new CustomEvent('branchChanged', { detail: targetBranch.dbPtr }));
213
+
214
+ const accessToken = switchResult?.token?.access_token;
215
+ const profileResult = await MenusAPI.getProfile(accessToken);
216
+ const updatedUser = { ...profileResult, loggedCheckDone: true };
217
+
218
+ dispatch({ type: 'user', payload: updatedUser });
219
+ localStorage.setItem('userInfo', JSON.stringify(updatedUser));
220
+
221
+ await initializeUserMenus();
222
+ } catch (error) {
223
+ console.error('Auto branch switch failed:', error);
224
+ } finally {
225
+ setLoader(false);
226
+ }
227
+ };
228
+
229
+ if (user?.id && history?.location) handleUrlBranchSwitch();
230
+ }, [history?.location?.search, user?.id]);
231
+
68
232
  useEffect(() => {
69
233
  // Initialize the menus for the logged in user
70
234
  initializeUserMenus();
71
235
  }, []);
72
236
 
237
+ useEffect(() => {
238
+ if (!transitionPending) {
239
+ homeReadyNotifiedRef.current = false;
240
+ return;
241
+ }
242
+
243
+ if (!loader && allModules && !homeReadyNotifiedRef.current) {
244
+ homeReadyNotifiedRef.current = true;
245
+ if (typeof onHomeReady === 'function') {
246
+ onHomeReady();
247
+ }
248
+ }
249
+ }, [transitionPending, loader, allModules, onHomeReady]);
250
+
251
+ useEffect(() => {
252
+ if (!loader) {
253
+ setLoadingMessage('');
254
+
255
+ if (messageIntervalRef.current) {
256
+ clearInterval(messageIntervalRef.current);
257
+ messageIntervalRef.current = null;
258
+ }
259
+
260
+ return;
261
+ }
262
+
263
+ setLoadingMessage((previousMessage) => getRandomMessage(previousMessage));
264
+
265
+ messageIntervalRef.current = setInterval(() => {
266
+ setLoadingMessage((previousMessage) => getRandomMessage(previousMessage));
267
+ }, 2200);
268
+
269
+ return () => {
270
+ if (messageIntervalRef.current) {
271
+ clearInterval(messageIntervalRef.current);
272
+ messageIntervalRef.current = null;
273
+ }
274
+ };
275
+ }, [loader]);
276
+
73
277
  /**
74
278
  * Initialize the user menus
75
279
  */
76
280
  async function initializeUserMenus() {
77
281
  // need to find what implement, with a login who has the respective value ("wug_custreportids")
282
+
78
283
  const report = await loadScripts(user);
79
284
 
80
285
  await loadMenus(report);
286
+ // fetch license summary
81
287
  }
82
288
 
83
289
  // const keyMap = {
@@ -96,26 +302,21 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
96
302
  * @param reports
97
303
  */
98
304
  async function loadMenus(reports) {
99
-
100
305
  setLoader(true);
101
306
 
102
307
  // setReports(report)
103
-
308
+ fetchSummary();
104
309
  const result = await MenusAPI.getMenus(user);
105
310
 
106
311
  // console.log(result);
107
312
 
108
313
  if (result && Array.isArray(result.result) && result.result.length) {
109
-
110
314
  // setModules(result.result);
111
-
112
315
  // result.result.map((ele) => {
113
316
  // let languageString = JSON.parse(ele.attributes)
114
317
  // console.log('language_string', languageString);
115
318
  // if (languageString && languageString.languages) {
116
-
117
319
  // const language = i18n.language;
118
-
119
320
  // i18n.addResourceBundle(language, 'translation', languageString.languages[i18n.language]);
120
321
  // }
121
322
  // })
@@ -126,7 +327,6 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
126
327
  dispatch({ type: 'settings', payload: result.result.settings });
127
328
  }
128
329
 
129
-
130
330
  // Reports length
131
331
  if (reports.length) {
132
332
  reportMenus = [
@@ -161,7 +361,6 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
161
361
  //If there is no roles assigned to the user
162
362
  setAllModules([...coreModules]);
163
363
  }
164
-
165
364
  } else {
166
365
  // for nura
167
366
  if (result && result.result.menus && reportMenus) {
@@ -170,14 +369,10 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
170
369
  //If there is no roles assigned to the user
171
370
  setAllModules([...coreModules]);
172
371
  }
173
-
174
-
175
372
  }
176
373
  setLoader(false);
177
-
178
374
  }
179
375
 
180
-
181
376
  /**
182
377
  * Load the scripts
183
378
  *
@@ -240,11 +435,14 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
240
435
  modules={allModules}
241
436
  user={user}
242
437
  history={history}
438
+ licenseData={licenseData}
439
+ licAlert={licAlert}
243
440
  >
244
441
  {loader ? (
245
442
  <Card className="skeleton-card">
246
443
  <div className="skeleton-wrapper">
247
444
  <Skeleton paragraph={{ rows: 4 }} />
445
+ <p className="motivating-text">{loadingMessage}</p>
248
446
  </div>
249
447
  </Card>
250
448
  ) : (
@@ -11,9 +11,31 @@
11
11
  }
12
12
 
13
13
  .skeleton-wrapper {
14
+ .motivating-text {
15
+ margin-top: 14px;
16
+ margin-bottom: 4px;
17
+ font-size: 14px;
18
+ line-height: 20px;
19
+ text-align: center;
20
+ color: #5e6d86;
21
+ font-weight: 500;
22
+ animation: skeletonTextFade 0.4s ease-in-out;
23
+ }
14
24
  }
15
25
 
16
26
  .wrapper-loader {
17
27
  margin: 20px;
18
28
  }
19
29
  }
30
+
31
+ @keyframes skeletonTextFade {
32
+ from {
33
+ opacity: 0;
34
+ transform: translateY(2px);
35
+ }
36
+
37
+ to {
38
+ opacity: 1;
39
+ transform: translateY(0);
40
+ }
41
+ }
@@ -0,0 +1,97 @@
1
+ import { Alert } from 'antd';
2
+ import React, { useState, useEffect } from 'react';
3
+
4
+ export default function LicenseAlert({ data }) {
5
+ // setting visibility of alert based on license status
6
+ const [visible, setVisible] = useState(true);
7
+ // resolve alert configuration based on license data
8
+ const alertConfig = resolveLicenseAlert(data);
9
+ // auto-hide alert after 10 seconds or when data changes
10
+ useEffect(() => {
11
+ if (alertConfig) {
12
+ setVisible(true);
13
+
14
+ const timer = setTimeout(() => {
15
+ setVisible(false);
16
+ }, 10000); // 10 seconds
17
+
18
+ return () => {
19
+ clearTimeout(timer);
20
+ };
21
+ }
22
+ }, [data]);
23
+ // if no alert configuration or not visible, render nothing
24
+ if (!alertConfig || !visible) return null;
25
+
26
+ return (
27
+ // render the alert with appropriate type, message, and description
28
+ <Alert
29
+ type={alertConfig.type}
30
+ message={alertConfig.message}
31
+ description={alertConfig.description}
32
+ showIcon
33
+ closable
34
+ onClose={() => setVisible(false)}
35
+ />
36
+ );
37
+ }
38
+ // function to determine alert configuration based on license data
39
+ function resolveLicenseAlert(data) {
40
+ if (!data) return null;
41
+ // destructure relevant fields from license data
42
+ const { status, expiresInDays, isExpiringSoon, gracePeriod } = data;
43
+
44
+ // ===== NOT INSTALLED =====
45
+ if (status === 'NOT_INSTALLED') {
46
+ return {
47
+ type: 'error',
48
+ message: 'License not found',
49
+ description: 'Please install a valid license to continue.',
50
+ };
51
+ }
52
+
53
+ // ===== GRACE PERIOD =====
54
+ if (gracePeriod) {
55
+ return {
56
+ type: 'warning',
57
+ message: 'Grace period mode',
58
+ description: 'License expired. Running in read-only mode.',
59
+ };
60
+ }
61
+
62
+ // ===== EXPIRING SOON =====
63
+ if (status === 'ACTIVE' && isExpiringSoon) {
64
+ let descriptionText = '';
65
+ // customize message based on how soon the license is expiring
66
+ if (expiresInDays === 0) {
67
+ descriptionText = 'Your license will expire today. Please renew immediately.';
68
+ } else {
69
+ descriptionText = `Your license will expire in ${expiresInDays} days. Please plan for renewal.`;
70
+ }
71
+
72
+ return {
73
+ type: 'warning',
74
+ message: 'License expiring soon',
75
+ description: descriptionText,
76
+ };
77
+ }
78
+
79
+ // ===== NOT INSTALLED =====
80
+ if (status === 'NOT_INSTALLED') {
81
+ return {
82
+ type: 'error',
83
+ message: 'License not found',
84
+ description: 'Please install a valid license to continue.',
85
+ };
86
+ }
87
+ // =====EXPIRED=====
88
+ if (status === 'EXPIRED') {
89
+ return {
90
+ type: 'error',
91
+ message: 'License expired',
92
+ description: 'Your license has expired. Please renew or install a new license.',
93
+ };
94
+ }
95
+
96
+ return null;
97
+ }
package/core/lib/Store.js CHANGED
@@ -50,7 +50,7 @@ const initialTheme = () => {
50
50
  // manage theme with env
51
51
  const isEnvThemeTrue = process.env.REACT_APP_THEME;
52
52
 
53
- console.log('REACT_APP_THEME:', isEnvThemeTrue);
53
+ // console.log('REACT_APP_THEME:', isEnvThemeTrue);
54
54
  const matchedTheme = themes.find((t) => t.name === isEnvThemeTrue);
55
55
 
56
56
  if (matchedTheme) return matchedTheme;
@@ -64,7 +64,7 @@ const initialTheme = () => {
64
64
  // Fallback to default
65
65
  return themes[0];
66
66
  } catch (e) {
67
- console.error('Error loading theme:', e);
67
+ // console.error('Error loading theme:', e);
68
68
  return themes[0];
69
69
  }
70
70
  };
@@ -72,12 +72,16 @@ const initialTheme = () => {
72
72
  const initialState = {
73
73
  defaultBranch: {},
74
74
  theme: initialTheme(), // Set the initial theme from themes.json
75
+ settings: {},
75
76
  };
76
77
 
77
78
  /**
78
79
  * Context for sharing state accross app
79
80
  */
80
- export const GlobalContext = createContext(initialState);
81
+ export const GlobalContext = createContext({
82
+ ...initialState,
83
+ state: initialState,
84
+ });
81
85
 
82
86
  let app = {};
83
87
 
@@ -94,7 +98,7 @@ export const GlobalProvider = ({ children, CustomModels,CustomComponents, appSet
94
98
 
95
99
  const [state, dispatch] = useReducer(AppReducer, initialState);
96
100
 
97
- console.log(state);
101
+ // console.log(state);
98
102
 
99
103
  const { isMobile } = useDeviceDetect();
100
104