ui-soxo-bootstrap-core 2.6.43 → 2.6.45

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.
@@ -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 };
@@ -59,11 +59,29 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
59
59
 
60
60
  const [meta, setMeta] = useState({});
61
61
  const [loadingMessage, setLoadingMessage] = useState('');
62
+ const [licenseData, setLicenseData] = useState(null);
63
+ const [licAlert, setLicAlert] = useState(false);
62
64
 
63
65
  // const [reports, setReports] = useState([]);
64
66
 
65
67
  var config = {};
66
68
 
69
+ //fetch license summary
70
+ const fetchSummary = async () => {
71
+ try {
72
+ const res = await MenusAPI.getSummary();
73
+ if (res?.data) {
74
+ setLicenseData(res?.data);
75
+ setLicAlert(true);
76
+ } else {
77
+ setLicenseData(null);
78
+ setLicAlert(false);
79
+ }
80
+ } catch (err) {
81
+ console.error(err);
82
+ }
83
+ };
84
+
67
85
  // Variable decides the control of homepage
68
86
  // #TODO This is a temporary fix - Homemage
69
87
 
@@ -138,9 +156,12 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
138
156
  */
139
157
  async function initializeUserMenus() {
140
158
  // need to find what implement, with a login who has the respective value ("wug_custreportids")
159
+
141
160
  const report = await loadScripts(user);
142
161
 
143
162
  await loadMenus(report);
163
+ // fetch license summary
164
+ fetchSummary();
144
165
  }
145
166
 
146
167
  // const keyMap = {
@@ -292,6 +313,8 @@ export default function LandingApi({ history, CustomComponents, CustomModels, ap
292
313
  modules={allModules}
293
314
  user={user}
294
315
  history={history}
316
+ licenseData={licenseData}
317
+ licAlert={licAlert}
295
318
  >
296
319
  {loader ? (
297
320
  <Card className="skeleton-card">
@@ -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
+ }
@@ -2,136 +2,93 @@
2
2
  *
3
3
  * Global header component
4
4
  */
5
-
6
5
  import { useContext, useEffect, useRef, useState } from 'react';
7
-
8
6
  import { motion, useAnimation } from 'framer-motion';
9
-
10
7
  import { boxVariants } from './animations';
11
-
12
8
  import { GlobalContext, GlobalProvider } from './../../Store';
13
-
14
9
  import { Link, useLocation } from 'react-router-dom';
15
-
16
10
  import { Avatar, Input, Tooltip, Typography } from 'antd';
17
-
18
11
  import ProgressBar from '../progress-bar/progress-bar'; // Adjust the path as needed
19
-
20
12
  import { Button } from '../../elements';
21
-
22
13
  import GenericHeader from '../header/generic-header';
23
-
24
-
25
14
  import { CustomerServiceOutlined, MenuOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
26
-
27
15
  import { Drawer } from 'antd';
28
-
29
16
  import { ReloadOutlined, SearchOutlined } from '@ant-design/icons';
30
-
31
17
  import SideMenu from './../sidemenu/sidemenu';
32
-
33
18
  import './global-header.scss';
34
-
35
19
  import LanguageSwitcher from '../language-switcher/language-switcher';
36
-
37
20
  import { useTranslation } from 'react-i18next';
38
-
39
21
  import SettingsUtil from '../../../utils/settings.utils';
40
22
  import SpotlightSearch from '../spotlight-search/spotlight-search.component';
23
+ import LicenseAlert from '../../../components/license-management/license-alert';
41
24
 
42
25
  const { Title } = Typography;
43
-
44
- function GlobalHeaderContent({ loading, appSettings, children, isConnected, history, modules = [], sidemenu = [], reload, meta = {}, ...props }) {
26
+ function GlobalHeaderContent({ loading, appSettings, children, isConnected, history, modules = [], sidemenu = [], reload, meta = {}, licAlert,
27
+ licenseData,...props }) {
45
28
  let location = useLocation();
46
29
  // let location = {};
47
-
48
30
  const { isMobile, user = { locations: [] }, kiosk, state, settings } = useContext(GlobalContext);
49
-
50
31
  const [visible, setVisible] = useState(false);
51
32
  const helpDeskSetting = settings?.HELPATR || {};
52
-
53
33
  // Variable to handle toggling of menu
54
34
  const [collapsed, setCollapsed] = useState(false);
55
35
  // varibale handle branch switcher
56
-
57
36
  // const [searchModalVisible, setSearchModalVisible] = useState(false);
58
-
59
37
  const { globalCustomerHeader = () => {} } = appSettings;
60
-
61
38
  const { t, i18n } = useTranslation();
62
-
63
39
  const spotlightRef = useRef();
64
-
65
40
  useEffect(() => {
66
41
  setTimeout(() => {
67
42
  i18n.changeLanguage(localStorage.selectedLanguage);
68
43
  }, 0);
69
44
  }, []);
70
-
71
45
  /**
72
46
  * Function to handle toggling of menu
73
47
  */
74
-
75
48
  const toggleCollapsed = () => {
76
49
  setVisible(true);
77
-
78
50
  collapsed === true ? setCollapsed(false) : setCollapsed(true);
79
51
  };
80
-
81
52
  const openSearchModal = () => {
82
53
  // input to avoid typing
83
54
  SettingsUtil.openSpotlightModal();
84
55
  };
85
-
86
56
  /**
87
57
  * Function to remove toggling on mobile view
88
58
  */
89
59
  const hideToggle = () => {
90
60
  setVisible(true);
91
-
92
61
  setCollapsed(false);
93
62
  };
94
-
95
63
  /**
96
64
  * onClose Function
97
65
  */
98
-
99
66
  const onClose = () => {
100
67
  setVisible(false);
101
68
  };
102
-
103
69
  // const { model = {} } = menu;
104
-
105
70
  const { model: BaseModel = {}, menu = {} } = meta;
106
-
107
71
  const { model = {} } = menu;
108
-
109
72
  //Animations//
110
73
  const boxControls = useAnimation();
111
-
112
74
  async function animate() {
113
75
  await boxControls.start('entered');
114
-
115
76
  //await boxControls.start("show");
116
77
  }
117
-
118
78
  useEffect(() => {
119
79
  animate();
120
80
  }, []);
121
-
122
81
  useEffect(() => {}, [state.theme]);
123
-
124
82
  return (
83
+ <>
125
84
  <div
126
85
  className={`global-header ${process.env.REACT_APP_THEME} ${isConnected && !kiosk ? 'connected' : ''}`}
127
86
  style={{
128
87
  // background: state.theme.colors.bodyBackground,
129
-
130
- height: 10,
88
+ height: 'auto',
131
89
  }}
132
90
  >
133
91
  {/* <MenuOutlined style={{left:'1%',top:'1%', fontSize:18, position:'absolute', zIndex:999}} onClick={showSidebar}/> */}
134
-
135
92
  <div className="layout-content">
136
93
  <div
137
94
  //whileHover="hover"
@@ -174,7 +131,6 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
174
131
  </Drawer>
175
132
  )}
176
133
  </div>
177
-
178
134
  {/* Right Section of the Component Loader */}
179
135
  <div
180
136
  className={`right-section ${!collapsed ? 'open' : 'close'} ${kiosk ? 'kioskon' : ''}`}
@@ -189,11 +145,9 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
189
145
  {/* */}
190
146
  <div className="page-header-name">
191
147
  <ProgressBar isLoading={loading} />
192
-
193
148
  <span type onClick={!isMobile ? toggleCollapsed : hideToggle} className="toggle-box toggle-menu">
194
149
  <MenuOutlined />
195
150
  </span>
196
-
197
151
  {/* Back Button */}
198
152
  {location.pathname !== '/' ? (
199
153
  <span
@@ -206,39 +160,30 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
206
160
  </span>
207
161
  ) : null}
208
162
  {/* Back Button Ends */}
209
-
210
163
  {location.pathname !== '/' ? (
211
164
  <h4 className="menu-caption header-caption" style={{ color: state.theme.colors.headerColor }}>
212
165
  {menu.caption}
213
166
  </h4>
214
167
  ) : null}
215
168
  </div>
216
-
217
169
  {/* Page Menu Actions */}
218
-
219
170
  {user.role || user.id ? (
220
171
  <div className="page-menu">
221
172
  {/* Search Input in header start */}
222
173
  {!isMobile && (
223
174
  <div>
224
175
  <Input placeholder="Search (Shift + F)" prefix={<SearchOutlined />} onClick={openSearchModal} readOnly style={{ width: 250 }} />
225
-
226
176
  <SpotlightSearch ref={(elem) => SettingsUtil.registerModal(elem)} props={props} />
227
177
  </div>
228
178
  )}
229
179
  {/* Search Input in header start */}
230
-
231
180
  {/** branchswitcher Option */}
232
181
  {/* branch switcher controlled with env for matria and nura */}
233
182
  {!process.env.REACT_APP_SHOW_BRANCH_SWITCHER ? <div className="branch-switcher">{globalCustomerHeader()}</div> : null}
234
183
  {/* <div className="branch-switcher">{globalCustomerHeader()}</div> */}
235
-
236
184
  {/* Search Option */}
237
-
238
185
  {/* <ModalSearch /> */}
239
-
240
186
  {/* Search Option Ends */}
241
-
242
187
  {/* Configurator Actions */}
243
188
  {user.isAdmin ? (
244
189
  <>
@@ -252,13 +197,9 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
252
197
  </>
253
198
  ) : null}
254
199
  {/* Configurator Actions Ends */}
255
-
256
200
  {/* Reload Button */}
257
-
258
201
  <Button onClick={reload} icon={<ReloadOutlined />} type="default" size={'small'}></Button>
259
-
260
202
  {/* Reload Button Ends */}
261
-
262
203
  {/* Help-desk-btn */}
263
204
  {helpDeskSetting?.showSupportBtn
264
205
  ? (() => {
@@ -277,11 +218,9 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
277
218
  );
278
219
  })()
279
220
  : null}
280
-
281
221
  {/** Switch Languages starts */}
282
222
  {process.env.REACT_APP_ENABLE_LANGUAGE_SWITCHER ? <LanguageSwitcher /> : null}
283
223
  {/** Switch Languages ends */}
284
-
285
224
  {/* User Profile */}
286
225
  <div style={{ padding: '10px' }}>
287
226
  <ProfileAvatar />
@@ -290,11 +229,9 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
290
229
  {/* User Profile Ends */}
291
230
  </div>
292
231
  ) : null}
293
-
294
232
  {/* Page Menu Actions Ends */}
295
233
  </div>
296
234
  ) : null}
297
-
298
235
  {/* The children is rendered */}
299
236
  {children}
300
237
  {/* The children is rendered */}
@@ -302,32 +239,40 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
302
239
  {/* Right Section of the Component Loader Ends */}
303
240
  </div>
304
241
  </div>
242
+ {licAlert && licenseData && (
243
+ <div
244
+ style={{
245
+ top: 0,
246
+ marginTop: '3rem',
247
+ right: '2%',
248
+ position: 'absolute',
249
+ zIndex: 1008,
250
+ }}
251
+ >
252
+ <LicenseAlert data={licenseData} />
253
+ </div>
254
+ )}
255
+ </>
305
256
  );
306
257
  }
307
-
308
258
  export default function GlobalHeader(props) {
309
259
  const context = useContext(GlobalContext);
310
-
311
260
  if (context.dispatch) {
312
261
  return <GlobalHeaderContent {...props} />;
313
262
  }
314
-
315
263
  return (
316
264
  <GlobalProvider {...props} appSettings={props.appSettings}>
317
265
  <GlobalHeaderContent {...props} />
318
266
  </GlobalProvider>
319
267
  );
320
268
  }
321
-
322
269
  /**
323
270
  *
324
271
  * @returns
325
272
  */
326
273
  function ProfileAvatar() {
327
274
  const { user = { locations: [] } } = useContext(GlobalContext);
328
-
329
275
  useEffect(() => {}, []);
330
-
331
276
  return (
332
277
  <Link className="profile-avatar" to="/profile">
333
278
  {user.photograph ? (
@@ -337,7 +282,6 @@ function ProfileAvatar() {
337
282
  ) : (
338
283
  <Avatar shape="square" size="small" icon={<UserOutlined />} />
339
284
  )}
340
-
341
285
  {/* {user.name} */}
342
286
  </Link>
343
287
  );
@@ -305,6 +305,12 @@ class MenusAPI extends Base {
305
305
  // }
306
306
  ];
307
307
  };
308
+ // license summary api call
309
+ getSummary = () => {
310
+ return ApiUtils.get({
311
+ url: 'license/summary',
312
+ });
313
+ };
308
314
  }
309
315
 
310
316
  export default MenusAPI;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ui-soxo-bootstrap-core",
3
- "version": "2.6.43",
3
+ "version": "2.6.45",
4
4
  "description": "All the Core Components for you to start",
5
5
  "keywords": [
6
6
  "all in one"