ui-soxo-bootstrap-core 2.6.1-dev.11 → 2.6.1-dev.13

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.
@@ -344,144 +344,6 @@ export default function ReportingDashboard({
344
344
  }
345
345
  };
346
346
 
347
- /**
348
- *
349
- * @param {*} searchValues
350
- * @param {*} searchParameters
351
- * @returns
352
- */
353
- const buildSearchCondition = (searchValues, searchParameters) => {
354
- let searchCondition = '';
355
-
356
- Object.keys(searchValues).forEach((key) => {
357
- const arr = searchValues[key];
358
- if (!Array.isArray(arr) || arr.length === 0) return;
359
-
360
- const param = searchParameters.find((p) => p.field === key);
361
- if (!param) return;
362
-
363
- const operator = (param.search_operator || '').trim().toUpperCase();
364
- const column = param.db_column || key;
365
-
366
- if (operator === 'LIKE') {
367
- const likeConditions = arr.map((v) => `${column} LIKE '${v}'`).join(' OR ');
368
- searchCondition += ` AND (${likeConditions})`;
369
- } else if (operator === 'IN') {
370
- const valueList = arr.map((v) => `'${v}'`).join(',');
371
- searchCondition += ` AND ${column} IN (${valueList})`;
372
- } else if (operator === '=') {
373
- const eqConditions = arr.map((v) => `${column} = '${v}'`).join(' OR ');
374
- searchCondition += ` AND (${eqConditions})`;
375
- } else if (operator === '!=') {
376
- const neqConditions = arr.map((v) => `${column} != '${v}'`).join(' AND ');
377
- searchCondition += ` AND (${neqConditions})`;
378
- } else {
379
- // fallback for other operators like > < >= <=
380
- const conditions = arr.map((v) => `${column} ${operator} '${v}'`).join(' OR ');
381
- searchCondition += ` AND (${conditions})`;
382
- }
383
- });
384
-
385
- return searchCondition;
386
- };
387
- // const handleSubmit = (values) => {
388
- // const hasSearchValues = Object.values(searchValues).some((v) => Array.isArray(v) && v.length > 0);
389
-
390
- // // Check if regular form values have changed since the last submission.
391
- // const regularValuesChanged = (() => {
392
- // const newKeys = Object.keys(values);
393
- // const oldKeys = Object.keys(formContents);
394
-
395
- // if (newKeys.length !== oldKeys.length) return true;
396
-
397
- // for (const key of newKeys) {
398
- // const newValue = values[key];
399
- // const oldValue = formContents[key];
400
-
401
- // if (moment.isMoment(newValue) && moment.isMoment(oldValue)) {
402
- // if (!newValue.isSame(oldValue)) {
403
- // return true;
404
- // }
405
- // } else if (newValue !== oldValue) {
406
- // // This is a shallow comparison, but should work for primitives and new array/object references.
407
- // return true;
408
- // }
409
- // }
410
- // return false;
411
- // })();
412
-
413
- // if (hasSearchValues && regularValuesChanged) {
414
- // Modal.confirm({
415
- // title: 'Combine Filters',
416
- // content: 'You have applied both standard and advanced filters. Do you want to combine them?',
417
- // okText: 'Yes, Apply Both',
418
- // cancelText: 'No, Use Advanced Only',
419
- // onOk: () => {
420
- // // User chose to combine filters.
421
- // const searchCondition = buildSearchCondition(searchValues, searchParameters);
422
- // const finalValues = {
423
- // ...values,
424
- // search_condition: searchCondition,
425
- // };
426
- // onFinish(finalValues, 1);
427
- // },
428
- // onCancel: () => {
429
- // // User chose to use only advanced search.
430
- // const searchCondition = buildSearchCondition(searchValues, searchParameters);
431
- // const resetValues = {};
432
- // Object.keys(values).forEach((key) => {
433
- // resetValues[key] = null;
434
- // });
435
- // const finalValues = {
436
- // ...resetValues,
437
- // search_condition: searchCondition,
438
- // };
439
- // onFinish(finalValues, 1);
440
- // },
441
- // });
442
- // return; // Stop further execution, wait for modal response.
443
- // }
444
-
445
- // // --- Default behavior if the condition for the modal is not met ---
446
-
447
- // let finalValues = values;
448
- // if (hasSearchValues) {
449
- // // If only advanced search has values (or regular filters haven't changed), reset regular filters.
450
- // const searchCondition = buildSearchCondition(searchValues, searchParameters);
451
- // const resetValues = {};
452
- // Object.keys(values).forEach((key) => {
453
- // resetValues[key] = null;
454
- // });
455
- // finalValues = {
456
- // ...resetValues,
457
- // search_condition: searchCondition,
458
- // };
459
- // }
460
-
461
- // const { pageSize } = pagination;
462
- // const resetPage = 1;
463
-
464
- // scriptId.current = null;
465
-
466
- // // Update URL only when NOT using advanced search
467
- // if (!hasSearchValues) {
468
- // const currentUrlParams = Location.search();
469
- // const { script_id, selected_card, ...cleanParams } = currentUrlParams;
470
-
471
- // const newParams = new URLSearchParams({
472
- // ...cleanParams,
473
- // current: resetPage,
474
- // pageSize,
475
- // });
476
-
477
- // const newUrl = `${window.location.pathname}?${newParams.toString()}`;
478
- // window.history.replaceState({}, '', newUrl);
479
- // }
480
-
481
- // // Call report API
482
- // onFinish(finalValues, resetPage);
483
- // };
484
-
485
347
  const handleSubmit = (values) => {
486
348
  const hasSearchValues = Object.values(searchValues).some((v) => Array.isArray(v) && v.length > 0);
487
349
 
@@ -511,11 +373,9 @@ export default function ReportingDashboard({
511
373
 
512
374
  onOk() {
513
375
  // YES → send form values + search condition
514
- const searchCondition = buildSearchCondition(searchValues, searchParameters);
515
-
516
376
  const finalValues = {
517
377
  ...values,
518
- search_condition: searchCondition,
378
+ search_values: searchValues,
519
379
  };
520
380
 
521
381
  runSubmit(finalValues);
@@ -523,8 +383,6 @@ export default function ReportingDashboard({
523
383
 
524
384
  onCancel() {
525
385
  // NO → reset form values
526
- const searchCondition = buildSearchCondition(searchValues, searchParameters);
527
-
528
386
  const resetValues = {};
529
387
  Object.keys(values).forEach((key) => {
530
388
  resetValues[key] = null;
@@ -532,7 +390,7 @@ export default function ReportingDashboard({
532
390
 
533
391
  const finalValues = {
534
392
  ...resetValues,
535
- search_condition: searchCondition,
393
+ search_values: searchValues,
536
394
  };
537
395
 
538
396
  runSubmit(finalValues);
@@ -540,8 +398,6 @@ export default function ReportingDashboard({
540
398
  });
541
399
  } else {
542
400
  // no form change
543
- const searchCondition = buildSearchCondition(searchValues, searchParameters);
544
-
545
401
  const resetValues = {};
546
402
  Object.keys(values).forEach((key) => {
547
403
  resetValues[key] = null;
@@ -549,7 +405,7 @@ export default function ReportingDashboard({
549
405
 
550
406
  const finalValues = {
551
407
  ...resetValues,
552
- search_condition: searchCondition,
408
+ search_values: searchValues,
553
409
  };
554
410
 
555
411
  runSubmit(finalValues);
@@ -562,7 +418,7 @@ export default function ReportingDashboard({
562
418
 
563
419
  scriptId.current = null;
564
420
 
565
- const hasSearchValues = finalValues.search_condition;
421
+ const hasSearchValues = finalValues.search_values && Object.values(finalValues.search_values).some((v) => Array.isArray(v) && v.length > 0);
566
422
 
567
423
  if (!hasSearchValues) {
568
424
  const currentUrlParams = Location.search();
@@ -746,6 +602,7 @@ export default function ReportingDashboard({
746
602
  key={param.field}
747
603
  parameter={param}
748
604
  field={param}
605
+ reportId={reportId}
749
606
  value={searchValues[param.field] || []}
750
607
  onChange={(value) => {
751
608
  setSearchValues((prev) => ({
@@ -753,6 +610,32 @@ export default function ReportingDashboard({
753
610
  [param.field]: value,
754
611
  }));
755
612
  }}
613
+ onReset={() => {
614
+ setSearchValues((prev) => {
615
+ const updated = {
616
+ ...prev,
617
+ [param.field]: [],
618
+ };
619
+
620
+ // const finalValues = {
621
+ // ...formContents,
622
+ // search_values: updated,
623
+ // };
624
+ // console.log(finalValues);
625
+ // runSubmit(finalValues); // 🔥 refresh report correctly
626
+ getPatientDetails();
627
+
628
+ return updated;
629
+ });
630
+ }}
631
+ // onReset={() => {
632
+ // setSearchValues((prev) => ({
633
+ // ...prev,
634
+ // [param.field]: [],
635
+ // }));
636
+
637
+ // handleSubmit(formContents); // 🔥 refresh report
638
+ // }}
756
639
  />
757
640
  ))
758
641
  : null}
@@ -978,6 +861,40 @@ function GuestList({
978
861
  const handleCloseEdit = () => {
979
862
  setShowEdit(false);
980
863
  };
864
+ /**
865
+ *
866
+ */
867
+ function calculateSummaryValues(summaryCols, pageData) {
868
+ const summaryValues = {};
869
+
870
+ summaryCols.forEach((col) => {
871
+ const field = col.field;
872
+
873
+ if (col.function === 'sum') {
874
+ summaryValues[field] = pageData.reduce((total, row) => total + Number(row[field] || 0), 0);
875
+ }
876
+
877
+ if (col.function === 'count') {
878
+ summaryValues[field] = pageData.length;
879
+ }
880
+
881
+ if (col.function === 'avg') {
882
+ const total = pageData.reduce((sum, row) => sum + Number(row[field] || 0), 0);
883
+ summaryValues[field] = pageData.length ? total / pageData.length : 0;
884
+ }
885
+ if (col.function === 'min') {
886
+ const values = pageData.map((row) => Number(row[field] || 0));
887
+ summaryValues[field] = values.length ? Math.min(...values) : 0;
888
+ }
889
+
890
+ if (col.function === 'max') {
891
+ const values = pageData.map((row) => Number(row[field] || 0));
892
+ summaryValues[field] = values.length ? Math.max(...values) : 0;
893
+ }
894
+ });
895
+
896
+ return summaryValues;
897
+ }
981
898
  return (
982
899
  <>
983
900
  <div className="table-header">
@@ -1053,46 +970,131 @@ function GuestList({
1053
970
  sticky
1054
971
  pagination={false}
1055
972
  // title={config.caption}
973
+ // summary={(pageData) => {
974
+ // // Variable to save the summary data
975
+ // let summary = {};
976
+
977
+ // let summaryColumns = [
978
+ // { field: 'opb_amt', title: 'Amount' },
979
+ // { field: 'opb_netamt', title: 'Net Amount' },
980
+ // ];
981
+
982
+ // let tableColumns = cols;
983
+
984
+ // // Creating a copy of columns to append the summary configuration that is needed to set
985
+ // tableColumns.forEach((record, index) => {
986
+ // summaryColumns.forEach((inner) => {
987
+ // if (record.field === inner.field) {
988
+ // tableColumns[index].summary = inner;
989
+ // }
990
+ // });
991
+ // });
992
+
993
+ // // Initialize
994
+ // summaryColumns.map((item) => {
995
+ // return (summary[item.field] = 0);
996
+ // });
997
+
998
+ // // Find the total
999
+ // summaryColumns.map((item) => {
1000
+ // pageData.forEach((entry) => {
1001
+ // return (summary[item.field] = summary[item.field] + entry[item.field]);
1002
+ // });
1003
+ // });
1004
+
1005
+ // return (
1006
+ // <>
1007
+ // <Table.Summary.Row>
1008
+ // {tableColumns.map((column, key) => {
1009
+ // return <Table.Summary.Cell key={key}>{column.summary ? <>{summary[column.summary.field]}</> : null}</Table.Summary.Cell>;
1010
+ // })}
1011
+ // </Table.Summary.Row>
1012
+ // </>
1013
+ // );
1014
+ // }}
1015
+ // summary={(pageData) => {
1016
+ // const summaryCols = columns.filter((col) => col.enable_summary);
1017
+ // if (!summaryCols.length) return null;
1018
+
1019
+ // const summaryValues = {};
1020
+
1021
+ // summaryCols.forEach((col) => {
1022
+ // const field = col.field;
1023
+
1024
+ // if (col.function === 'sum') {
1025
+ // summaryValues[field] = pageData.reduce((total, row) => total + Number(row[field] || 0), 0);
1026
+ // }
1027
+
1028
+ // if (col.function === 'count') {
1029
+ // summaryValues[field] = pageData.length;
1030
+ // }
1031
+
1032
+ // if (col.function === 'avg') {
1033
+ // const total = pageData.reduce((sum, row) => sum + Number(row[field] || 0), 0);
1034
+ // summaryValues[field] = pageData.length ? total / pageData.length : 0;
1035
+ // }
1036
+ // });
1037
+
1038
+ // return (
1039
+ // <Table.Summary.Row className="report-summary-row">
1040
+ // {cols.map((col, index) => {
1041
+ // // show summary value
1042
+ // if (summaryValues[col.field] !== undefined) {
1043
+ // return (
1044
+ // <Table.Summary.Cell key={index}>
1045
+ // <strong>{summaryValues[col.field]}</strong>
1046
+ // </Table.Summary.Cell>
1047
+ // );
1048
+ // }
1049
+
1050
+ // // caption before summary column
1051
+ // const nextCol = cols[index + 1];
1052
+ // if (nextCol && summaryValues[nextCol.field] !== undefined) {
1053
+ // const configCol = columns.find((c) => c.field === nextCol.field);
1054
+ // return (
1055
+ // <Table.Summary.Cell key={index}>
1056
+ // <strong>{configCol?.summary_caption || 'Total'}</strong>
1057
+ // </Table.Summary.Cell>
1058
+ // );
1059
+ // }
1060
+
1061
+ // return <Table.Summary.Cell key={index} />;
1062
+ // })}
1063
+ // </Table.Summary.Row>
1064
+ // );
1065
+ // }}
1066
+
1056
1067
  summary={(pageData) => {
1057
- // Variable to save the summary data
1058
- let summary = {};
1059
-
1060
- let summaryColumns = [
1061
- { field: 'opb_amt', title: 'Amount' },
1062
- { field: 'opb_netamt', title: 'Net Amount' },
1063
- ];
1064
-
1065
- let tableColumns = cols;
1066
-
1067
- // Creating a copy of columns to append the summary configuration that is needed to set
1068
- tableColumns.forEach((record, index) => {
1069
- summaryColumns.forEach((inner) => {
1070
- if (record.field === inner.field) {
1071
- tableColumns[index].summary = inner;
1072
- }
1073
- });
1074
- });
1075
-
1076
- // Initialize
1077
- summaryColumns.map((item) => {
1078
- return (summary[item.field] = 0);
1079
- });
1080
-
1081
- // Find the total
1082
- summaryColumns.map((item) => {
1083
- pageData.forEach((entry) => {
1084
- return (summary[item.field] = summary[item.field] + entry[item.field]);
1085
- });
1086
- });
1068
+ const summaryCols = columns.filter((col) => col.enable_summary);
1069
+ if (!summaryCols.length) return null;
1070
+
1071
+ const summaryValues = calculateSummaryValues(summaryCols, pageData);
1087
1072
 
1088
1073
  return (
1089
- <>
1090
- <Table.Summary.Row>
1091
- {tableColumns.map((column, key) => {
1092
- return <Table.Summary.Cell key={key}>{column.summary ? <>{summary[column.summary.field]}</> : null}</Table.Summary.Cell>;
1093
- })}
1094
- </Table.Summary.Row>
1095
- </>
1074
+ <Table.Summary.Row>
1075
+ {cols.map((col, index) => {
1076
+ if (summaryValues[col.field] !== undefined) {
1077
+ return (
1078
+ <Table.Summary.Cell key={index}>
1079
+ <strong>{summaryValues[col.field]}</strong>
1080
+ </Table.Summary.Cell>
1081
+ );
1082
+ }
1083
+
1084
+ const nextCol = cols[index + 1];
1085
+ if (nextCol && summaryValues[nextCol.field] !== undefined) {
1086
+ const configCol = columns.find((c) => c.field === nextCol.field);
1087
+
1088
+ return (
1089
+ <Table.Summary.Cell key={index}>
1090
+ <strong>{configCol?.summary_caption || 'Total'}</strong>
1091
+ </Table.Summary.Cell>
1092
+ );
1093
+ }
1094
+
1095
+ return <Table.Summary.Cell key={index} />;
1096
+ })}
1097
+ </Table.Summary.Row>
1096
1098
  );
1097
1099
  }}
1098
1100
  />
@@ -5,6 +5,13 @@
5
5
  justify-content: space-between;
6
6
  }
7
7
 
8
+ .report-summary-row {
9
+ position: sticky;
10
+ bottom: 0;
11
+ background: #fff;
12
+ z-index: 10;
13
+ }
14
+
8
15
  .table-header {
9
16
  display: flex;
10
17
  justify-content: space-between;
@@ -13,6 +13,8 @@ export default function ActionButtons({
13
13
  steps,
14
14
  activeStep,
15
15
  isStepCompleted,
16
+ isFullscreen,
17
+ onToggleFullscreen,
16
18
  renderDynamicComponent,
17
19
  handlePrevious,
18
20
  handleNext,
@@ -37,6 +39,10 @@ export default function ActionButtons({
37
39
  Back
38
40
  </Button>
39
41
 
42
+ <Button type="default" onClick={onToggleFullscreen}>
43
+ {isFullscreen ? 'Exit Full Screen' : 'Switch to Full Screen'}
44
+ </Button>
45
+
40
46
  {/* Skip button */}
41
47
  {steps.length > 0 && steps[activeStep]?.allow_skip === 'Y' && (
42
48
  <Button type="default" onClick={handleSkip} disabled={activeStep === steps.length - 1}>
@@ -11,6 +11,7 @@
11
11
  overflow-y: auto;
12
12
  overflow-x: hidden;
13
13
  overscroll-behavior: contain;
14
+
14
15
  padding-bottom: 8px;
15
16
  }
16
17
 
@@ -27,7 +28,6 @@
27
28
  border-top: 1px solid #f0f0f0;
28
29
  box-shadow: 0 -2px 10px rgba(15, 23, 42, 0.04);
29
30
 
30
-
31
31
  width: 61%;
32
32
  padding: 10px;
33
33
  position: fixed;
@@ -37,9 +37,15 @@
37
37
  display: flex;
38
38
  border-radius: 4px;
39
39
  box-shadow: -1px -4px 10px 2px #f7f7f76e;
40
-
40
+ flex-wrap: wrap;
41
41
 
42
42
  .ant-btn {
43
43
  border-radius: 4px;
44
44
  }
45
- }
45
+ }
46
+
47
+ .process-steps-page.is-fullscreen .action-buttons-container {
48
+ width: calc(100% - 24px);
49
+ left: 12px;
50
+ right: 12px;
51
+ }
@@ -8,7 +8,7 @@
8
8
  * - Handles process submission and optional chaining to the next process.
9
9
  * - Provides a collapsible timeline view and action controls.
10
10
  */
11
- import React, { useEffect, useState } from 'react';
11
+ import React, { useEffect, useRef, useState } from 'react';
12
12
  import { Row, Col, Empty } from 'antd';
13
13
  import { Card } from './../../lib';
14
14
  import * as genericComponents from './../../lib';
@@ -36,8 +36,11 @@ export default function ProcessStepsPage({ match, CustomComponents = {}, ...prop
36
36
  const [timelineCollapsed, setTimelineCollapsed] = useState(false);
37
37
  const [showExternalWindow, setShowExternalWindow] = useState(false);
38
38
  const [externalWin, setExternalWin] = useState(null);
39
+ const [isFullscreen, setIsFullscreen] = useState(false);
40
+ const processStepsRef = useRef(null);
39
41
 
40
42
  const urlParams = Location.search();
43
+ const isConsultationMode = String(urlParams?.consultation).toLowerCase() === 'true';
41
44
  let processId = urlParams.processId;
42
45
  const [currentProcessId, setCurrentProcessId] = useState(processId);
43
46
  // Load process details based on the current process ID
@@ -271,13 +274,49 @@ export default function ProcessStepsPage({ match, CustomComponents = {}, ...prop
271
274
  };
272
275
  }, [activeStep, steps, externalWin]);
273
276
 
277
+ useEffect(() => {
278
+ const syncFullscreenState = () => {
279
+ setIsFullscreen(document.fullscreenElement === processStepsRef.current);
280
+ };
281
+
282
+ document.addEventListener('fullscreenchange', syncFullscreenState);
283
+ syncFullscreenState();
284
+
285
+ return () => {
286
+ document.removeEventListener('fullscreenchange', syncFullscreenState);
287
+ };
288
+ }, []);
289
+
290
+ const handleToggleFullscreen = async () => {
291
+ const element = processStepsRef.current;
292
+ if (!element) return;
293
+
294
+ try {
295
+ if (document.fullscreenElement === element) {
296
+ if (document.exitFullscreen) {
297
+ await document.exitFullscreen();
298
+ }
299
+ return;
300
+ }
301
+
302
+ if (element.requestFullscreen) {
303
+ await element.requestFullscreen();
304
+ }
305
+ } catch (error) {
306
+ console.error('Unable to toggle full screen for steps page:', error);
307
+ }
308
+ };
309
+
274
310
  /**
275
311
  * Renders the main process UI including timeline, step details,
276
312
  * and action buttons. This content is reused in both normal view
277
313
  * and external window view.
278
314
  */
279
- const renderContent = () => (
280
- <div className="process-steps-page">
315
+ const renderContent = (attachRef = true) => (
316
+ <div
317
+ ref={attachRef ? processStepsRef : null}
318
+ className={`process-steps-page ${isConsultationMode ? 'consultation-mode' : ''} ${isFullscreen ? 'is-fullscreen' : ''}`}
319
+ >
281
320
  <Card className="process-steps-card">
282
321
  <Row gutter={20} className="process-steps-row" align="stretch">
283
322
  <Col xs={24} sm={24} lg={timelineCollapsed ? 2 : 6} className="process-steps-timeline-col">
@@ -302,6 +341,8 @@ export default function ProcessStepsPage({ match, CustomComponents = {}, ...prop
302
341
  steps={steps}
303
342
  activeStep={activeStep}
304
343
  isStepCompleted={isStepCompleted}
344
+ isFullscreen={isFullscreen}
345
+ onToggleFullscreen={handleToggleFullscreen}
305
346
  renderDynamicComponent={DynamicComponent}
306
347
  handlePrevious={handlePrevious}
307
348
  handleNext={handleNext}
@@ -335,9 +376,9 @@ export default function ProcessStepsPage({ match, CustomComponents = {}, ...prop
335
376
  width={props.ExternalWindowWidth || 1000}
336
377
  height={props.ExternalWindowHeight || 1000}
337
378
  >
338
- {renderContent()}
379
+ {renderContent(false)}
339
380
  </ExternalWindow>
340
- {renderContent()}
381
+ {renderContent(true)}
341
382
  </>
342
383
  );
343
384
  }