ui-soxo-bootstrap-core 2.4.25-dev.28 → 2.4.25-dev.30

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.
@@ -158,7 +158,6 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
158
158
 
159
159
  // callback();
160
160
  // };
161
-
162
161
 
163
162
  const onMenuClick = (menu, index) => {
164
163
  const key = menu.path || `menu-${menu.id || index}`;
@@ -176,19 +175,52 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
176
175
  setMenu(menu);
177
176
  if (callback) callback();
178
177
  };
179
-
180
178
 
179
+ /**
180
+ * Controls submenu open/close behavior.
181
+ *
182
+ * - Detects the most recently opened menu key.
183
+ * - When opening a submenu, keeps only its full parent path expanded
184
+ * (accordion behavior).
185
+ * - When closing a submenu, updates state without recalculating paths.
186
+ *
187
+ * @param {string[]} keys - Currently open menu keys from the Menu component.
188
+ *
189
+ * Assumptions:
190
+ * - Menu keys are stable and unique.
191
+ * - Only one menu branch should be open at a time.
192
+ */
181
193
  const onOpenChange = (keys) => {
182
194
  const latestOpenKey = keys.find((k) => !openKeys.includes(k));
183
195
 
184
- // If opening a ROOT menu → close other roots
185
- if (rootSubmenuKeys.includes(latestOpenKey)) {
186
- setOpenKeys([latestOpenKey]);
196
+ if (!latestOpenKey) {
197
+ setOpenKeys(keys);
187
198
  return;
188
199
  }
189
200
 
190
- // Otherwise (2nd / 3rd level) keep ALL parents open
191
- setOpenKeys(keys);
201
+ const findPath = (items) => {
202
+ const sortedItems = Menus.screenMenus(items, 'order');
203
+ for (const item of sortedItems) {
204
+ const key = String(item.id || item.path || item.caption);
205
+ if (key === latestOpenKey) {
206
+ return [key];
207
+ }
208
+ if (item.sub_menus) {
209
+ const childPath = findPath(item.sub_menus);
210
+ if (childPath) {
211
+ return [key, ...childPath];
212
+ }
213
+ }
214
+ }
215
+ return null;
216
+ };
217
+
218
+ const path = findPath(modules);
219
+ if (path) {
220
+ setOpenKeys(path);
221
+ } else {
222
+ setOpenKeys(keys);
223
+ }
192
224
  };
193
225
 
194
226
  /**
@@ -3,7 +3,7 @@ import themes from './themes.json';
3
3
  export const THEME_GROUPS = {
4
4
  nura: ['nura', 'default'],
5
5
  purple: ['purple'],
6
- default: ['default'],
6
+ default: ['nura'],
7
7
  };
8
8
 
9
9
  const currentEnvTheme = process.env.REACT_APP_THEME?.toLowerCase() || 'default';
@@ -3,9 +3,10 @@
3
3
  * Handles navigation and action controls for a multi-step process,
4
4
  * including dynamic content rendering and process completion actions.
5
5
  */
6
- import React from 'react';
6
+ import React, { useState } from 'react';
7
7
  import { Skeleton } from 'antd';
8
8
  import { Button } from '../../lib';
9
+ import './action-buttons.scss';
9
10
 
10
11
  export default function ActionButtons({
11
12
  loading,
@@ -21,63 +22,50 @@ export default function ActionButtons({
21
22
  nextProcessId,
22
23
  timelineCollapsed,
23
24
  }) {
25
+ const [showNextProcess, setShowNextProcess] = useState(false);
26
+
24
27
  return (
25
28
  <>
26
29
  <div style={{ minHeight: 300 }}>{loading ? <Skeleton active /> : renderDynamicComponent()}</div>
27
30
  <>
28
- <div style={{ marginTop: 20, display: 'flex', justifyContent: 'flex-start', gap: '10px' }}>
31
+ <div className="action-buttons-container">
29
32
  {/* Back button */}
30
- <Button disabled={activeStep === 0} onClick={handlePrevious} style={{ marginRight: 8, borderRadius: 4 }}>
33
+ <Button disabled={activeStep === 0} onClick={handlePrevious}>
31
34
  Back
32
35
  </Button>
33
36
 
34
37
  {/* Skip button */}
35
38
  {steps.length > 0 && steps[activeStep]?.allow_skip === 'Y' && (
36
- <Button
37
- type="default"
38
- onClick={handleSkip}
39
- style={{
40
- borderRadius: 4,
41
- }}
42
- disabled={activeStep === steps.length - 1}
43
- >
39
+ <Button type="default" onClick={handleSkip} disabled={activeStep === steps.length - 1}>
44
40
  Skip
45
41
  </Button>
46
42
  )}
47
43
 
48
44
  {/* Next / Finish / Start Next */}
49
45
  {steps[activeStep]?.order_seqtype === 'E' ? (
50
- nextProcessId?.next_process_id ? (
51
- <Button
52
- type="primary"
53
- style={{
54
- borderRadius: 4,
55
- }}
56
- onClick={handleStartNextProcess}
57
- >
58
- Start Next {nextProcessId.next_process_name}
59
- </Button>
60
- ) : (
61
- <Button
62
- type="primary"
63
- style={{
64
- borderRadius: 4,
65
- }}
66
- onClick={handleFinish}
67
- >
68
- Finish
69
- </Button>
70
- )
46
+ <>
47
+ {!showNextProcess && (
48
+ <Button
49
+ type="primary"
50
+ onClick={async () => {
51
+ const success = await handleFinish();
52
+ if (success && nextProcessId?.next_process_id) {
53
+ setShowNextProcess(true);
54
+ }
55
+ }}
56
+ >
57
+ Finish
58
+ </Button>
59
+ )}
60
+
61
+ {showNextProcess && nextProcessId?.next_process_id && (
62
+ <Button type="primary" onClick={handleStartNextProcess}>
63
+ Start {nextProcessId.next_process_name}
64
+ </Button>
65
+ )}
66
+ </>
71
67
  ) : (
72
- <Button
73
- type="primary"
74
- // shape="round"
75
- style={{
76
- borderRadius: 4,
77
- }}
78
- disabled={activeStep === steps.length - 1 || !isStepCompleted}
79
- onClick={handleNext}
80
- >
68
+ <Button type="primary" disabled={activeStep === steps.length - 1 || !isStepCompleted} onClick={handleNext}>
81
69
  Next →
82
70
  </Button>
83
71
  )}
@@ -0,0 +1,16 @@
1
+ .action-buttons-container {
2
+ margin-top: 38px;
3
+ display: flex;
4
+ justify-content: flex-start;
5
+ gap: 10px;
6
+ position: sticky;
7
+ bottom: 0;
8
+ z-index: 1000;
9
+ background: #fff;
10
+ padding: 10px 0;
11
+ border-top: 1px solid #f0f0f0;
12
+
13
+ .ant-btn {
14
+ border-radius: 4px;
15
+ }
16
+ }
@@ -204,7 +204,9 @@ export default function ProcessStepsPage({ processId, match, CustomComponents =
204
204
  */
205
205
  const handleFinish = async () => {
206
206
  const final = recordStepTime();
207
- if (await handleProcessSubmit(final)) props.history?.goBack();
207
+ const success = await handleProcessSubmit(final);
208
+ if (success && !nextProcessId) props.history?.goBack();
209
+ return success;
208
210
  };
209
211
  /**
210
212
  * Start Next Process
@@ -268,6 +270,7 @@ export default function ProcessStepsPage({ processId, match, CustomComponents =
268
270
  * and external window view.
269
271
  */
270
272
  const renderContent = () => (
273
+ <div>
271
274
  <Card>
272
275
  <Row gutter={20}>
273
276
  <Col xs={24} sm={24} lg={timelineCollapsed ? 2 : 6}>
@@ -303,6 +306,7 @@ export default function ProcessStepsPage({ processId, match, CustomComponents =
303
306
  </Col>
304
307
  </Row>
305
308
  </Card>
309
+ </div>
306
310
  );
307
311
  /**
308
312
  * Renders content in both the main window and an external window
@@ -1,7 +1,8 @@
1
1
  .timeline-card .ant-card-body {
2
- padding: 20px;
2
+ // padding: 20px;
3
+ border: none;
3
4
  min-height: 400px;
4
- position: fixed; /* For positioning the arrow */
5
+ // position: fixed; /* For positioning the arrow */
5
6
  }
6
7
 
7
8
  .timeline-sidebar {
@@ -46,7 +47,7 @@
46
47
 
47
48
  .vertical-line {
48
49
  width: 2px;
49
- height: 40px;
50
+ height: 20px;
50
51
  background: #d9d9d9;
51
52
  }
52
53
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ui-soxo-bootstrap-core",
3
- "version": "2.4.25-dev.28",
3
+ "version": "2.4.25-dev.30",
4
4
  "description": "All the Core Components for you to start",
5
5
  "keywords": [
6
6
  "all in one"