ui-soxo-bootstrap-core 2.6.40-dev.20 → 2.6.40-dev.21

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.
@@ -211,7 +211,9 @@ function FormCreator({
211
211
  // Keep the same value preparation path for normal submit and search reset.
212
212
  fields.forEach((field) => {
213
213
 
214
- if (field.field && field.field.includes('date')) {
214
+ // Only actual date inputs are converted , a field can be named with date
215
+ // and still hold a plain value ( eg : date_filter_type select )
216
+ if (field.field && field.field.includes('date') && ['date', 'datetime'].indexOf(field.type) !== -1) {
215
217
 
216
218
  nextValues[field.field] = moment(nextValues[field.field]).valueOf();
217
219
 
@@ -530,7 +532,7 @@ function UserInput({ field, onUpload, selectedInformation, onChange, onSearchRes
530
532
  return (
531
533
  <Select defaultValue={defaultValue}
532
534
  required={field.required}
533
- style={{ width: '120' }}
535
+ style={{ minWidth: '160px' }}
534
536
  onChange={(value) => onChange(field, value)}
535
537
  >
536
538
  {field.options.map((option, key) => (
@@ -1,32 +1,22 @@
1
1
  import React, { useState, useEffect, useContext, useRef } from 'react';
2
2
 
3
- import { Table, Skeleton, Input, Modal, message, Pagination, Tag } from 'antd';
3
+ import { Table, Skeleton, Input, Modal, message, Tag } from 'antd';
4
4
 
5
- import { QrcodeOutlined } from '@ant-design/icons';
6
-
7
- import { Location, FormCreator, GlobalContext, ExportReactCSV, getExportData, Card, TableComponent, QrScanner } from './../../../../lib/';
5
+ import { Location, FormCreator, GlobalContext, Card } from './../../../../lib/';
8
6
 
9
7
  import { CoreScripts } from './../../../../models/';
10
8
 
11
9
  import moment from 'moment-timezone';
12
10
 
13
- import Button from '../../../../lib/elements/basic/button/button';
14
-
15
11
  import './reporting-dashboard.scss';
16
12
 
17
13
  // import MenuDashBoard from '../../../../pages/homepage-api/menu-dashboard';
18
14
  import MenuDashBoardComponent from '../../../../lib/elements/basic/menu-dashboard/menu-dashboard';
19
- import { useHistory } from 'react-router-dom';
20
- import * as ReportingDashboardComp from '../index';
21
- import buildDisplayColumns from './display-columns/build-display-columns';
22
- import { getRedirectLink } from './display-columns/display-cell-renderer';
23
- import AdvancedSearchSelect from './adavance-search/advance-search';
24
-
25
- // import { isPdfFile } from 'pdfjs-dist';
26
15
 
27
- var genericComponents = require('./../../../../lib');
16
+ import ReportingTable from './reporting-table';
28
17
 
29
- const { Search } = Input;
18
+ // Input parameter that decides which date column the report is filtered by
19
+ const DATE_FILTER_FIELD = 'date_filter_type';
30
20
 
31
21
  /**
32
22
  * ReportingDashboard component renders the dashboard and handles patient details,
@@ -56,7 +46,7 @@ export default function ReportingDashboard({
56
46
  const [config, setConfig] = useState({});
57
47
 
58
48
  // State to manage the layout of the form
59
- const [formLayout, setFormLayout] = useState('vertical');
49
+ const [formLayout] = useState('inline');
60
50
 
61
51
  const [loading, setLoading] = useState(true);
62
52
 
@@ -79,7 +69,7 @@ export default function ReportingDashboard({
79
69
 
80
70
  //In case of reports from core_script , there will be id from params
81
71
  // In case of normal menu we need to take id from props
82
- let id = reportId ? reportId : match.params.id;
72
+ let id = reportId ? reportId : match?.params?.id;
83
73
 
84
74
  const { CustomModels = {} } = useContext(GlobalContext);
85
75
 
@@ -87,9 +77,9 @@ export default function ReportingDashboard({
87
77
 
88
78
  const [columns, setColumns] = useState([]); // To set columns
89
79
 
90
- const [summaryColumns, setSummaryColumns] = useState([]);
80
+ const [, setSummaryColumns] = useState([]);
91
81
 
92
- const [patients, setPatients] = useState([]); //Patients list array
82
+ const [reportRequestPayload, setReportRequestPayload] = useState(null);
93
83
 
94
84
  const urlParams = Location.search();
95
85
 
@@ -110,7 +100,6 @@ export default function ReportingDashboard({
110
100
  * @returns {Promise<void>} A promise that resolves when the patient details have been fetched and the state has been updated.
111
101
  */
112
102
  async function getPatientDetails(idOverride) {
113
- setPatients([]);
114
103
  const fetchId = idOverride || id;
115
104
  await CoreScripts.getRecord({ id: fetchId, dbPtr }).then(async ({ result }) => {
116
105
  // Check if display columns are provided from backend
@@ -188,6 +177,9 @@ export default function ReportingDashboard({
188
177
  if (urlParams[record.field]) {
189
178
  if (record.type === 'date') {
190
179
  formContent[record.field] = moment.utc(urlParams[record.field]);
180
+ } else if (record.type !== 'search') {
181
+ // Restore plain values ( eg : select filters ) back from the url
182
+ formContent[record.field] = urlParams[record.field];
191
183
  }
192
184
 
193
185
  // return formContent;
@@ -215,6 +207,10 @@ export default function ReportingDashboard({
215
207
  break;
216
208
 
217
209
  default:
210
+ // Any other default is taken as the value itself ( eg : select filters )
211
+ if (record.default !== undefined && record.default !== null && record.type !== 'date') {
212
+ formContent[record.field] = record.default;
213
+ }
218
214
  break;
219
215
  }
220
216
  }
@@ -223,6 +219,11 @@ export default function ReportingDashboard({
223
219
  if (record.type === 'date' && !formContent[record.field]) {
224
220
  formContent[record.field] = moment().tz(process.env.REACT_APP_TIMEZONE);
225
221
  }
222
+
223
+ // For a static select with no value yet , preselect the first option
224
+ if (record.type === 'select' && Array.isArray(record.options) && formContent[record.field] === undefined) {
225
+ formContent[record.field] = record.options[0]?.valueMember;
226
+ }
226
227
  if (record.type === 'search') {
227
228
  if (!formContent[record.field]) formContent[record.field] = [];
228
229
  return {
@@ -262,95 +263,57 @@ export default function ReportingDashboard({
262
263
  // If enabled, clear the details array
263
264
  setDetails([]);
264
265
  } else {
266
+ // The date filter input is shown only when the filter is enabled in otherDetails .
267
+ // Otherwise it stays hidden holding its default value , so the report keeps filtering
268
+ // on the default date
269
+ const filterKey = otherDetails ? Object.keys(otherDetails).find((key) => key.toLowerCase().trim() === 'enableuserfilter') : null;
270
+
271
+ const isFilterEnabled = filterKey ? otherDetails[filterKey] === true || otherDetails[filterKey] === 'true' : false;
272
+
265
273
  // Keep all parameters with a type (including search) to render in FormCreator
266
- setDetails([...parameters.filter((ele) => ele.type)]);
274
+ setDetails([
275
+ ...parameters
276
+ .filter((ele) => ele.type)
277
+ .map((ele) => (ele.field === DATE_FILTER_FIELD ? { ...ele, visible: isFilterEnabled } : ele)),
278
+ ]);
267
279
  }
268
280
  }
269
281
 
270
282
  // Refresh patient details.
271
283
 
272
284
  function refresh() {
273
- getPatientDetails();
285
+ getPatientDetails(scriptId.current || id);
274
286
  }
275
287
 
276
- const fetchReportData = async (id, values, dbPtr, pagination, parsedColumns) => {
277
- const { current, pageSize } = pagination || {};
278
- // If card script id is exist load that id otherwise load id
279
- const coreScriptId = scriptId.current ? scriptId.current : id;
280
- const normalizedColumns = Array.isArray(parsedColumns) ? parsedColumns : Array.isArray(columns) ? columns : [];
288
+ const buildReportRequestPayload = (values = {}, paginationOverride) => {
289
+ const pager = paginationOverride || pagination;
290
+ const formattedValues = {};
281
291
 
282
- setLoading(true);
283
- try {
284
- // Prepare payload for backend: format only here
285
- const formattedValues = {};
286
- Object.keys(values).forEach((key) => {
287
- const val = values[key];
288
- formattedValues[key] = moment.isMoment(val) ? val.format('YYYY-MM-DD') : val;
289
- });
290
- // Pagination Data
291
- const paginationData = {
292
- page: pagination.current || 1,
293
- limit: pagination.pageSize || 10,
294
- };
295
- // Combine form data + pagination
296
- let formBody = {
292
+ Object.keys(values || {}).forEach((key) => {
293
+ const val = values[key];
294
+ formattedValues[key] = moment.isMoment(val) ? val.format('YYYY-MM-DD') : val;
295
+ });
296
+
297
+ const paginationData = {
298
+ page: pager.current || 1,
299
+ limit: pager.pageSize || 10,
300
+ };
301
+
302
+ if (scope) {
303
+ return {
297
304
  body: {
298
- ...formattedValues,
305
+ ...scope,
299
306
  ...paginationData,
300
307
  },
301
308
  };
302
- // Optional override if `scope` exists
303
- if (scope) {
304
- formBody = { body: { ...scope, ...paginationData } };
305
- }
306
-
307
- setReportMailRequest({
308
- scriptId: coreScriptId,
309
- inputParameters: formBody,
310
- });
311
-
312
- // Fetch result
313
- const result = await CoreScripts.getReportingLisitng(coreScriptId, formBody, dbPtr);
314
-
315
- const apiData = Array.isArray(result) ? result : Array.isArray(result?.result) ? result.result : [];
316
-
317
- // Handle both result formats
318
- let resultDetails = apiData[0] || [];
319
- if (result?.result && result?.result[0]) {
320
- resultDetails = result.result[0];
321
- }
322
- // Update patients
323
- setPatients(resultDetails || []);
324
-
325
- // When display_columns is missing, build columns from the response keys.
326
- if (normalizedColumns.length === 0 && resultDetails.length > 0) {
327
- // Create columns dynamically from resultDetails keys
328
- setColumns((prev) => {
329
- if (prev.length > 0) return prev;
330
- return Object.keys(resultDetails[0]).map((key) => ({
331
- title: key,
332
- field: key,
333
- }));
334
- });
335
- }
336
-
337
- if (result.length) {
338
- // Set Pgination data into URL
339
- Location.search({ ...Location.search(), current, pageSize });
340
-
341
- setPagination((prev) => ({
342
- ...prev,
343
- current: pagination.current,
344
- pageSize: pagination.pageSize,
345
- total: resultDetails?.[0]?.TotalCount ?? pagination?.total,
346
- }));
347
- }
348
- } catch (error) {
349
- console.error('Error fetching report data:', error);
350
- } finally {
351
- // Always runs, success or error
352
- setLoading(false);
353
309
  }
310
+
311
+ return {
312
+ body: {
313
+ ...formattedValues,
314
+ ...paginationData,
315
+ },
316
+ };
354
317
  };
355
318
 
356
319
  const handleSubmit = (values) => {
@@ -561,17 +524,12 @@ export default function ReportingDashboard({
561
524
 
562
525
  // Call API
563
526
  try {
564
- await fetchReportData(id, values, dbPtr, paginationData, parsedColumns);
565
- } finally {
566
- setLoading(false);
567
- setCardLoading(false);
568
- }
569
- };
570
-
571
- // Pagination Handler
572
- const handlePagination = async (newPagination) => {
573
- try {
574
- await fetchReportData(id, formContents, dbPtr, newPagination);
527
+ setPagination((prev) => ({
528
+ ...prev,
529
+ current: paginationData.current,
530
+ pageSize: paginationData.pageSize,
531
+ }));
532
+ setReportRequestPayload(buildReportRequestPayload(values, paginationData));
575
533
  } finally {
576
534
  setLoading(false);
577
535
  setCardLoading(false);
@@ -659,459 +617,36 @@ export default function ReportingDashboard({
659
617
  ) : null}
660
618
  </div>
661
619
 
662
- {/** GuestList component start*/}
663
- <GuestList
664
- patients={patients}
620
+ <ReportingTable
665
621
  columns={columns}
666
- summaryColumns={summaryColumns}
667
622
  isFixedIndex={isFixedIndex}
668
623
  showScanner={showScanner}
624
+ reportId={reportId}
625
+ requestId={scriptId.current ? scriptId.current : id}
626
+ requestPayload={reportRequestPayload}
627
+ dbPtr={dbPtr}
669
628
  barcodeFilterKey={barcodeFilterKey}
670
- CustomComponents={{ ...CustomComponents, ...genericComponents, ...ReportingDashboardComp }}
629
+ CustomComponents={CustomComponents}
671
630
  refresh={refresh}
672
631
  config={config}
632
+
673
633
  loading={cardLoading}
674
634
  pagination={pagination}
675
- handlePagination={handlePagination}
635
+ onPaginationChange={(nextPagination) => {
636
+ Location.search({
637
+ ...Location.search(),
638
+ current: nextPagination.current,
639
+ pageSize: nextPagination.pageSize,
640
+ });
641
+ setPagination((prev) => ({
642
+ ...prev,
643
+ ...nextPagination,
644
+ }));
645
+ }}
676
646
  attributes={attributes}
677
- selectedSearchFields={selectedSearchFields}
678
- handleRemoveSearchField={handleRemoveSearchField}
679
- fetchReportData={(paginationUpdate) => fetchReportData(id, formContents, dbPtr, paginationUpdate || pagination)}
680
- reportScriptId={reportMailRequest.scriptId}
681
- reportInputParameters={reportMailRequest.inputParameters}
682
647
  />
683
- {/** GuestList component end*/}
684
648
  </>
685
649
  )}
686
650
  </Card>
687
651
  );
688
652
  }
689
-
690
- /**
691
- * Filters report records using the same search text that drives the table.
692
- *
693
- * @param {Array<Object>} records - Report rows.
694
- * @param {string} searchText - Current table search text.
695
- * @returns {Array<Object>} Rows matching the search text.
696
- */
697
- function filterReportRecords(records, searchText) {
698
- if (!Array.isArray(records)) return [];
699
-
700
- const query = String(searchText || '').trim().toLowerCase();
701
-
702
- if (!query) return records;
703
-
704
- return records.filter((record) =>
705
- Object.values(record).some((value) => {
706
- if (value === undefined || value === null || typeof value === 'object') return false;
707
-
708
- return String(value).toLowerCase().indexOf(query) !== -1;
709
- })
710
- );
711
- }
712
-
713
- /**
714
- *
715
- * @param root0
716
- * @param root0.patients
717
- * @param root0.CustomComponents
718
- * @param root0.summaryColumns
719
- * @param root0.refresh
720
- * @param root0.isFixedIndex
721
- * @returns {*}
722
- */
723
- //Renders a table displaying a list of patients with dynamic columns
724
- function GuestList({
725
- patients,
726
- columns,
727
- loading,
728
- CustomComponents,
729
- refresh,
730
- isFixedIndex,
731
- barcodeFilterKey,
732
- showScanner,
733
- config,
734
- pagination,
735
- handlePagination,
736
- attributes,
737
- selectedSearchFields,
738
- handleRemoveSearchField,
739
- fetchReportData,
740
- reportScriptId,
741
- reportInputParameters,
742
- }) {
743
- /**
744
- * @param {*} propValues
745
- */
746
- const propValues = (attributes && JSON.parse(attributes)) || {};
747
-
748
- const { buttonAttributes = [] } = propValues;
749
-
750
- var [query, setQuery] = useState('');
751
-
752
- const [exportData, setExportData] = useState({});
753
-
754
- // const [data, setData] = useState([]);
755
-
756
- //visibility of the QR scanner modal.
757
- const [isScannerVisible, setScannerVisible] = useState(false);
758
-
759
- // Stores the patients filtered specifically by QR scan match.
760
- const [filteredPatients, setFilteredPatients] = useState([]); // Show all initially
761
-
762
- // patient object to redirect to upon successful QR scan.
763
- const [redirectPatient, setRedirectPatient] = useState(null);
764
-
765
- const [visible, setVisible] = useState(false);
766
-
767
- const [ActiveComponent, setActiveComponent] = useState(null);
768
-
769
- let history = useHistory();
770
-
771
- const { isMobile, dispatch } = useContext(GlobalContext);
772
- const [single, setSingle] = useState({});
773
- const otherDetails = config.other_details1 ? JSON.parse(config.other_details1) : {};
774
-
775
- // const otherDetails = config.other_details1 ? JSON.parse(config.other_details1) : {};
776
- // const [view, setView] = useState(isMobile ? true : false); //Need to check this condition
777
- const cols = buildDisplayColumns({
778
- columns,
779
- patients,
780
- isFixedIndex,
781
- CustomComponents,
782
- refresh,
783
- otherDetails,
784
- });
785
-
786
- /**
787
- *
788
- * @param {*} result
789
- */
790
-
791
- // function changeView(result) {
792
- // setView(result);
793
- // }
794
-
795
- /**
796
- *
797
- * @param {*} event
798
- */
799
-
800
- function onSearch(event) {
801
- setQuery(event.target.value);
802
- }
803
-
804
- /**
805
- *
806
- */
807
-
808
- useEffect(() => {
809
- //Cheaking if there is patient data exists
810
- if (patients) {
811
- // let data = patients?.map((entry) => {
812
- // entry.rowIndex = entry.opb_id;
813
-
814
- // entry.dispatch = dispatch;
815
-
816
- // return entry;
817
- // });
818
-
819
- // setData(data);
820
-
821
- // Define export data
822
- // Sanitize cols for export to ensure titles are strings
823
- const exportCols = cols.map((col) => {
824
- if (col.title && typeof col.title === 'object' && col.title.props) {
825
- return { ...col, title: col.title.props.title };
826
- }
827
- return col;
828
- });
829
- const summaryCols = columns.filter((col) => col.enable_summary);
830
- let dataToExport = [...filterReportRecords(patients, query)];
831
-
832
- if (summaryCols.length > 0) {
833
- // Build one synthetic row for CSV export that mirrors the table layout:
834
- // numeric summary cells are populated from `calculateSummaryValues`, while
835
- // non-summary columns stay blank unless a configured caption should be shown.
836
- const summaryValues = calculateSummaryValues(summaryCols, dataToExport);
837
- const summaryRow = { isSummaryRow: true };
838
-
839
- cols.forEach((col, index) => {
840
- // Start each export column empty so the appended row keeps the same shape
841
- // as the data rows and does not leak index/helper values into the export.
842
- const colKey = col.field || col.key || col.dataIndex;
843
- if (colKey && !summaryRow[colKey]) {
844
- summaryRow[colKey] = '';
845
- }
846
-
847
- if (summaryValues[col.field] !== undefined) {
848
- // Fill columns that have an aggregate configured (sum, count, avg, etc.).
849
- summaryRow[col.field] = summaryValues[col.field];
850
- } else {
851
- // If this column is marked as the caption target for a summary column,
852
- // place the configured label (for example "Total") into that cell.
853
- const captionConfig = columns.find((c) => col.field && c.caption_field === col.field);
854
- if (captionConfig) {
855
- summaryRow[col.field] = captionConfig.summary_caption || '';
856
- }
857
- }
858
- });
859
- dataToExport.push(summaryRow);
860
- }
861
- let exportDatas = getExportData(dataToExport, exportCols);
862
-
863
- if (exportDatas.exportDataHeaders.length) {
864
- setExportData({ exportDatas });
865
- } else {
866
- setExportData({});
867
- }
868
- }
869
- }, [patients, columns, query]);
870
-
871
- let filtered = filterReportRecords(patients, query);
872
-
873
- /**
874
- * Checks for a match in the filtered patient list based on a scanned code,
875
- * updates the relevant state if a match is found, and redirects to the
876
- * patient's detail page. Displays a warning if no match is found.
877
- *
878
- * @param {string} code - The scanned code to match against a specific field of each patient.
879
- */
880
-
881
- const handleScanSuccess = (code) => {
882
- // Filters patients based on the scanned code and the selected barcode key(using attributes 'barcodeFilterKey')
883
- const matched = filtered.filter((patient) => patient[barcodeFilterKey] === code);
884
-
885
- if (matched.length) {
886
- const patient = matched[0];
887
- setFilteredPatients(matched);
888
- setRedirectPatient(matched);
889
- message.success(`Match found for ${code}, redirecting...`);
890
-
891
- const actionColumn = columns.find((col) => col.field === 'action') || columns.find((col) => col.type === 'action');
892
- if (actionColumn) {
893
- const redirectLink = getRedirectLink(actionColumn, patient);
894
- // history.push(redirectLink);
895
- window.location.href = redirectLink;
896
- }
897
- } else {
898
- Modal.warning({
899
- title: 'No matching records.',
900
- content: `No match for scanned code: ${code}`,
901
- });
902
- }
903
- };
904
-
905
- //open the edit modal
906
- const handleOpenEdit = (button) => {
907
- const componentName = button.component;
908
- const ComponentToRender = ReportingDashboardComp[componentName];
909
-
910
- if (!ComponentToRender) {
911
- console.error(`Component ${componentName} not found!`);
912
- return;
913
- }
914
-
915
- setSingle({});
916
- setActiveComponent(() => ComponentToRender);
917
- setVisible(true);
918
- };
919
-
920
- // close the edit modal
921
- const handleCloseEdit = () => {
922
- setShowEdit(false);
923
- };
924
- /**
925
- * Calculates aggregate values for the configured summary columns.
926
- *
927
- * Each summary definition contributes one value keyed by its `field`. Missing
928
- * row values are treated as `0` for numeric operations so the table summary and
929
- * export summary row can be built from the same result object.
930
- *
931
- * Supported functions:
932
- * `sum` - totals all numeric values in the field.
933
- * `count` - returns the number of rows in the current dataset.
934
- * `avg` - returns the arithmetic mean of the field values.
935
- * `min` - returns the smallest numeric value in the field.
936
- * `max` - returns the largest numeric value in the field.
937
- *
938
- * @param {Array<Object>} summaryCols - Column configs with `field` and `function`.
939
- * @param {Array<Object>} pageData - Rows currently being summarized.
940
- * @returns {Object} Aggregate values keyed by field name.
941
- */
942
- function calculateSummaryValues(summaryCols, pageData) {
943
- const summaryValues = {};
944
-
945
- summaryCols.forEach((col) => {
946
- const field = col.field;
947
-
948
- if (col.function === 'sum') {
949
- summaryValues[field] = pageData.reduce((total, row) => total + Number(row[field] || 0), 0);
950
- }
951
-
952
- if (col.function === 'count') {
953
- summaryValues[field] = pageData.length;
954
- }
955
-
956
- if (col.function === 'avg') {
957
- const total = pageData.reduce((sum, row) => sum + Number(row[field] || 0), 0);
958
- summaryValues[field] = pageData.length ? total / pageData.length : 0;
959
- }
960
- if (col.function === 'min') {
961
- const values = pageData.map((row) => Number(row[field] || 0));
962
- summaryValues[field] = values.length ? Math.min(...values) : 0;
963
- }
964
-
965
- if (col.function === 'max') {
966
- const values = pageData.map((row) => Number(row[field] || 0));
967
- summaryValues[field] = values.length ? Math.max(...values) : 0;
968
- }
969
- });
970
-
971
- return summaryValues;
972
- }
973
- return (
974
- <>
975
- <div className="table-header">
976
- <div className="table-left">
977
- {/* {selectedSearchFields?.length > 0 ? (
978
- <div className="search-tags-container">
979
- {selectedSearchFields.map((field) => (
980
- <Tag key={field.field} closable color="blue" onClose={() => handleRemoveSearchField(field.field)}>
981
- {field.caption}
982
- </Tag>
983
- ))}
984
- </div>
985
- ) : null} */}
986
- </div>
987
-
988
- <div className="table-right">
989
- {/* shwoing caption is not correct so this commented */}
990
- {/* <span className="menu-caption">{config.caption}</span> */}
991
- <Search className="table-search-input" placeholder="Enter Search Value" allowClear onChange={onSearch} />
992
- <div className="table-export-button">
993
- {exportData.exportDatas && (
994
- <>
995
- <ExportReactCSV
996
- title={config.caption}
997
- headers={exportData.exportDatas.exportDataHeaders}
998
- csvData={exportData.exportDatas.exportDataColumns}
999
- fileName={`${config.caption || 'Report'}.xlsx`}
1000
- pdfFileName={`${config.caption || 'Report'}.pdf`}
1001
- scriptId={reportScriptId}
1002
- inputParameters={reportInputParameters}
1003
- dropdown
1004
- />
1005
- </>
1006
- )}
1007
- </div>
1008
-
1009
- {/* QR Scan start */}
1010
- {showScanner ? (
1011
- <Button size="small" type="primary" icon={<QrcodeOutlined />} onClick={() => setScannerVisible(true)}>
1012
- Scan QR
1013
- </Button>
1014
- ) : null}
1015
- {/** Add User button */}
1016
- {Array.isArray(buttonAttributes) &&
1017
- buttonAttributes.map((btn, index) => (
1018
- <Button key={index} size="small" type="primary" style={{ marginLeft: 8 }} onClick={() => handleOpenEdit(btn)}>
1019
- {btn.title}
1020
- </Button>
1021
- ))}
1022
-
1023
- <Modal open={visible} onCancel={() => setVisible(false)} footer={null} destroyOnClose width={950} style={{ top: 10 }}>
1024
- {ActiveComponent && (
1025
- <ActiveComponent
1026
- formContent={single}
1027
- callback={() => {
1028
- setVisible(false);
1029
- refresh();
1030
- setVisible(false);
1031
- fetchReportData();
1032
- }}
1033
- // {...dynamicProps}
1034
- />
1035
- )}
1036
- </Modal>
1037
-
1038
- <Modal open={isScannerVisible} title="Scan QR Code" footer={null} onCancel={() => setScannerVisible(false)} destroyOnClose>
1039
- <QrScanner onScanSuccess={handleScanSuccess} onClose={() => setScannerVisible(false)} />
1040
- </Modal>
1041
- {/* QR Scan End */}
1042
- </div>
1043
- </div>
1044
-
1045
- <div>
1046
- <Card>
1047
- {loading ? (
1048
- <>
1049
- <Skeleton active paragraph={{ rows: 6 }} />
1050
- </>
1051
- ) : (
1052
- <TableComponent
1053
- size="small"
1054
- // scroll={{ x: 'max-content' }}
1055
- scroll={{ x: 'max-content', y: '60vh' }}
1056
- rowKey={(record) => record.OpNo}
1057
- dataSource={filtered ? filtered : patients} // In case if there is no filtered values we can use patient data
1058
- columns={cols}
1059
- sticky
1060
- pagination={true}
1061
- summary={(pageData) => {
1062
- const summaryCols = columns.filter((col) => col.enable_summary);
1063
- if (!summaryCols.length) return null;
1064
- /** calculate summary*/
1065
-
1066
- const summaryValues = calculateSummaryValues(summaryCols, pageData);
1067
-
1068
-
1069
- return (
1070
- <Table.Summary.Row className="report-summary-row">
1071
- {cols.map((col, index) => {
1072
- if (summaryValues[col.field] !== undefined) {
1073
- return (
1074
- <Table.Summary.Cell key={index}>
1075
- <strong style={{ fontWeight: 900 }}>{summaryValues[col.field]}</strong>
1076
- </Table.Summary.Cell>
1077
- );
1078
- }
1079
-
1080
- const captionConfig = columns.find((c) => col.field && c.caption_field === col.field);
1081
- if (captionConfig) {
1082
- return (
1083
- <Table.Summary.Cell key={index}>
1084
- <strong style={{ fontWeight: 900 }}>{captionConfig.summary_caption || ''}</strong>
1085
- </Table.Summary.Cell>
1086
- );
1087
- }
1088
-
1089
- return <Table.Summary.Cell key={index} />;
1090
- })}
1091
- </Table.Summary.Row>
1092
- );
1093
- }}
1094
- />
1095
- )}
1096
-
1097
- {/* Pagination aligned to the right */}
1098
- <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 8 }}>
1099
- <Pagination
1100
- showSizeChanger
1101
- current={pagination.current}
1102
- pageSize={pagination.pageSize}
1103
- total={pagination.total}
1104
- pageSizeOptions={[20, 30, 50, 100]}
1105
- onChange={(page, pageSize) => handlePagination({ current: page, pageSize })}
1106
- />
1107
- </div>
1108
-
1109
- {/*If patient data exists show the number else to 0 */}
1110
- <p className="size-hint">{patients ? patients.length : 0} records. </p>
1111
- </Card>
1112
- {/* </> */}
1113
- {/* )} */}
1114
- </div>
1115
- </>
1116
- );
1117
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ui-soxo-bootstrap-core",
3
- "version": "2.6.40-dev.20",
3
+ "version": "2.6.40-dev.21",
4
4
  "description": "All the Core Components for you to start",
5
5
  "keywords": [
6
6
  "all in one"