ui-soxo-bootstrap-core 2.6.30 → 2.6.32-dev.0

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.
@@ -2,35 +2,30 @@ import React, { useState, useEffect, useContext, useRef } from 'react';
2
2
 
3
3
  import { Table, Skeleton, Input, Modal, message, Pagination, 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
15
 
25
- // import { isPdfFile } from 'pdfjs-dist';
16
+ import ReportingTable from './reporting-table';
17
+ // import * as ReportingDashboardComp from '../index';
18
+ // import buildDisplayColumns from './display-columns/build-display-columns';
19
+ // import AdvancedSearchSelect from './adavance-search/advance-search';
20
+
21
+ // // import { isPdfFile } from 'pdfjs-dist';
26
22
 
27
- var genericComponents = require('./../../../../lib');
23
+ // var genericComponents = require('./../../../../lib');
28
24
 
29
25
  const { Search } = Input;
30
26
 
31
27
  /**
32
28
  * ReportingDashboard component renders the dashboard and handles patient details,
33
- * configuration, and form layout for generating reports.
34
29
  *
35
30
  * @param {Object} props - The component's props.
36
31
  * @param {Object} props.match - The match object containing the URL parameters.
@@ -56,7 +51,7 @@ export default function ReportingDashboard({
56
51
  const [config, setConfig] = useState({});
57
52
 
58
53
  // State to manage the layout of the form
59
- const [formLayout, setFormLayout] = useState('vertical');
54
+ const [formLayout] = useState('vertical');
60
55
 
61
56
  const [loading, setLoading] = useState(true);
62
57
 
@@ -83,9 +78,9 @@ export default function ReportingDashboard({
83
78
 
84
79
  const [columns, setColumns] = useState([]); // To set columns
85
80
 
86
- const [summaryColumns, setSummaryColumns] = useState([]);
81
+ const [, setSummaryColumns] = useState([]);
87
82
 
88
- const [patients, setPatients] = useState([]); //Patients list array
83
+ const [reportRequestPayload, setReportRequestPayload] = useState(null);
89
84
 
90
85
  const urlParams = Location.search();
91
86
 
@@ -106,7 +101,6 @@ export default function ReportingDashboard({
106
101
  * @returns {Promise<void>} A promise that resolves when the patient details have been fetched and the state has been updated.
107
102
  */
108
103
  async function getPatientDetails(idOverride) {
109
- setPatients([]);
110
104
  const fetchId = idOverride || id;
111
105
  await CoreScripts.getRecord({ id: fetchId, dbPtr }).then(async ({ result }) => {
112
106
  // Check if display columns are provided from backend
@@ -266,85 +260,40 @@ export default function ReportingDashboard({
266
260
  // Refresh patient details.
267
261
 
268
262
  function refresh() {
269
- getPatientDetails();
263
+ getPatientDetails(scriptId.current || id);
270
264
  }
271
265
 
272
- const fetchReportData = async (id, values, dbPtr, pagination, parsedColumns) => {
273
- const { current, pageSize } = pagination || {};
274
- // If card script id is exist load that id otherwise load id
275
- const coreScriptId = scriptId.current ? scriptId.current : id;
276
- const normalizedColumns = Array.isArray(parsedColumns) ? parsedColumns : Array.isArray(columns) ? columns : [];
266
+ const buildReportRequestPayload = (values = {}, paginationOverride) => {
267
+ const pager = paginationOverride || pagination;
268
+ const formattedValues = {};
277
269
 
278
- setLoading(true);
279
- try {
280
- // Prepare payload for backend: format only here
281
- const formattedValues = {};
282
- Object.keys(values).forEach((key) => {
283
- const val = values[key];
284
- formattedValues[key] = moment.isMoment(val) ? val.format('YYYY-MM-DD') : val;
285
- });
286
- // Pagination Data
287
- const paginationData = {
288
- page: pagination.current || 1,
289
- limit: pagination.pageSize || 10,
290
- };
291
- // Combine form data + pagination
292
- let formBody = {
270
+ Object.keys(values || {}).forEach((key) => {
271
+ const val = values[key];
272
+ formattedValues[key] = moment.isMoment(val) ? val.format('YYYY-MM-DD') : val;
273
+ });
274
+
275
+ const paginationData = {
276
+ page: pager.current || 1,
277
+ limit: pager.pageSize || 10,
278
+ };
279
+
280
+ if (scope) {
281
+ return {
293
282
  body: {
294
- ...formattedValues,
283
+ ...scope,
295
284
  ...paginationData,
296
285
  },
297
286
  };
298
- // Optional override if `scope` exists
299
- if (scope) {
300
- formBody = { body: { ...scope, ...paginationData } };
301
- }
302
-
303
- // Fetch result
304
- const result = await CoreScripts.getReportingLisitng(coreScriptId, formBody, dbPtr);
305
-
306
- const apiData = Array.isArray(result) ? result : Array.isArray(result?.result) ? result.result : [];
307
-
308
- // Handle both result formats
309
- let resultDetails = apiData[0] || [];
310
- if (result?.result && result?.result[0]) {
311
- resultDetails = result.result[0];
312
- }
313
- // Update patients
314
- setPatients(resultDetails || []);
315
-
316
- // When display_columns is missing, build columns from the response keys.
317
- if (normalizedColumns.length === 0 && resultDetails.length > 0) {
318
- // Create columns dynamically from resultDetails keys
319
- setColumns((prev) => {
320
- if (prev.length > 0) return prev;
321
- return Object.keys(resultDetails[0]).map((key) => ({
322
- title: key,
323
- field: key,
324
- }));
325
- });
326
- }
327
-
328
- if (result.length) {
329
- // Set Pgination data into URL
330
- Location.search({ ...Location.search(), current, pageSize });
331
-
332
- setPagination((prev) => ({
333
- ...prev,
334
- current: pagination.current,
335
- pageSize: pagination.pageSize,
336
- total: resultDetails?.[0]?.TotalCount ?? pagination?.total,
337
- }));
338
- }
339
- } catch (error) {
340
- console.error('Error fetching report data:', error);
341
- } finally {
342
- // Always runs, success or error
343
- setLoading(false);
344
287
  }
345
- };
346
288
 
347
- const handleSubmit = (values) => {
289
+ return {
290
+ body: {
291
+ ...formattedValues,
292
+ ...paginationData,
293
+ },
294
+ };
295
+ };
296
+ const handleSubmit = (values) => {
348
297
  // Extract search fields from the form values
349
298
  const searchKeys = searchParameters.map((p) => p.field);
350
299
  const currentSearchValues = {};
@@ -424,6 +373,86 @@ export default function ReportingDashboard({
424
373
  runSubmit(finalValues);
425
374
  }
426
375
  };
376
+ // const handleSubmit = (values) => {
377
+ // // Extract search fields from the form values
378
+ // const searchKeys = searchParameters.map((p) => p.field);
379
+ // const currentSearchValues = {};
380
+ // const formValues = {};
381
+
382
+ // Object.keys(values).forEach((key) => {
383
+ // if (searchKeys.includes(key)) {
384
+ // currentSearchValues[key] = values[key];
385
+ // } else {
386
+ // formValues[key] = values[key];
387
+ // }
388
+ // });
389
+
390
+ // const hasSearchValues = Object.values(currentSearchValues).some((v) => Array.isArray(v) && v.length > 0);
391
+
392
+ // if (!hasSearchValues) {
393
+ // runSubmit(formValues);
394
+ // return;
395
+ // }
396
+
397
+ // // Check if main form values (non-search) changed
398
+ // const formChanged = Object.keys(formValues).some((key) => {
399
+ // const newVal = formValues[key];
400
+ // const oldVal = formContents[key];
401
+
402
+ // if (moment.isMoment(newVal) && moment.isMoment(oldVal)) {
403
+ // return !newVal.isSame(oldVal, 'day');
404
+ // }
405
+
406
+ // return newVal !== oldVal;
407
+ // });
408
+
409
+ // if (formChanged) {
410
+ // Modal.confirm({
411
+ // title: 'Filters changed',
412
+ // content: 'You changed some filters. Do you want to search using these filters also?',
413
+ // okText: 'Yes',
414
+ // cancelText: 'No',
415
+
416
+ // onOk() {
417
+ // // YES → send form values + search condition
418
+ // const finalValues = {
419
+ // ...formValues,
420
+ // search_values: currentSearchValues,
421
+ // };
422
+
423
+ // runSubmit(finalValues);
424
+ // },
425
+
426
+ // onCancel() {
427
+ // // NO → reset form values
428
+ // const resetValues = {};
429
+ // Object.keys(formValues).forEach((key) => {
430
+ // resetValues[key] = null;
431
+ // });
432
+
433
+ // const finalValues = {
434
+ // ...resetValues,
435
+ // search_values: currentSearchValues,
436
+ // };
437
+
438
+ // runSubmit(finalValues);
439
+ // },
440
+ // });
441
+ // } else {
442
+ // // no form change
443
+ // const resetValues = {};
444
+ // Object.keys(formValues).forEach((key) => {
445
+ // resetValues[key] = null;
446
+ // });
447
+
448
+ // const finalValues = {
449
+ // ...resetValues,
450
+ // search_values: currentSearchValues,
451
+ // };
452
+
453
+ // runSubmit(finalValues);
454
+ // }
455
+ // };
427
456
 
428
457
  const runSubmit = (finalValues) => {
429
458
  const { pageSize } = pagination;
@@ -435,7 +464,12 @@ export default function ReportingDashboard({
435
464
 
436
465
  if (!hasSearchValues) {
437
466
  const currentUrlParams = Location.search();
438
- const { script_id, selected_card, ...cleanParams } = currentUrlParams;
467
+ const searchKeys = new Set(searchParameters.map((parameter) => parameter.field));
468
+ const cleanParams = Object.fromEntries(
469
+ Object.entries(currentUrlParams).filter(
470
+ ([key]) => key !== 'script_id' && key !== 'selected_card' && !searchKeys.has(key)
471
+ )
472
+ );
439
473
 
440
474
  const newParams = new URLSearchParams({
441
475
  ...cleanParams,
@@ -520,14 +554,22 @@ export default function ReportingDashboard({
520
554
  return parameter;
521
555
  });
522
556
 
523
- // Remove keys with undefined, null, or empty string values
557
+ const currentParams = Location.search();
558
+ // Mark existing empty values as null so Location.search removes stale query params.
524
559
  const filteredParams = Object.fromEntries(
525
- Object.entries(urlsToUpdate).filter(([_, value]) => value !== undefined && value !== null && value !== '')
560
+ Object.entries(urlsToUpdate).flatMap(([key, value]) => {
561
+ const shouldRemove = value === undefined || value === null || value === '' || (Array.isArray(value) && value.length === 0);
562
+ if (shouldRemove && !Object.prototype.hasOwnProperty.call(currentParams, key)) {
563
+ return [];
564
+ }
565
+
566
+ return [[key, shouldRemove ? null : value]];
567
+ })
526
568
  );
527
569
 
528
570
  setformContents(formContent);
529
571
  setLiveFormContents(formContent);
530
- Location.search({ ...Location.search(), ...filteredParams });
572
+ Location.search({ ...currentParams, ...filteredParams });
531
573
  }
532
574
 
533
575
  // Reset Pagination Data
@@ -539,17 +581,12 @@ export default function ReportingDashboard({
539
581
 
540
582
  // Call API
541
583
  try {
542
- await fetchReportData(id, values, dbPtr, paginationData, parsedColumns);
543
- } finally {
544
- setLoading(false);
545
- setCardLoading(false);
546
- }
547
- };
548
-
549
- // Pagination Handler
550
- const handlePagination = async (newPagination) => {
551
- try {
552
- await fetchReportData(id, formContents, dbPtr, newPagination);
584
+ setPagination((prev) => ({
585
+ ...prev,
586
+ current: paginationData.current,
587
+ pageSize: paginationData.pageSize,
588
+ }));
589
+ setReportRequestPayload(buildReportRequestPayload(values, paginationData));
553
590
  } finally {
554
591
  setLoading(false);
555
592
  setCardLoading(false);
@@ -568,6 +605,7 @@ export default function ReportingDashboard({
568
605
  <MenuDashBoardComponent
569
606
  dashBoardIds={dashBoardIds} //Pass the available dashboard IDs to the componen
570
607
  activeId={Number(urlParams?.selected_card || 0)}
608
+ dbPtr={dbPtr}
571
609
  callback={(record) => {
572
610
  const selectedCard = record?.id;
573
611
  if (record.other_details) {
@@ -636,447 +674,39 @@ export default function ReportingDashboard({
636
674
  ) : null}
637
675
  </div>
638
676
 
639
- {/** GuestList component start*/}
640
- <GuestList
641
- patients={patients}
677
+ <ReportingTable
642
678
  columns={columns}
643
- summaryColumns={summaryColumns}
644
679
  isFixedIndex={isFixedIndex}
645
680
  showScanner={showScanner}
681
+ reportId={reportId}
682
+ requestId={scriptId.current ? scriptId.current : id}
683
+ requestPayload={reportRequestPayload}
684
+ dbPtr={dbPtr}
646
685
  barcodeFilterKey={barcodeFilterKey}
647
- CustomComponents={{ ...CustomComponents, ...genericComponents, ...ReportingDashboardComp }}
686
+ CustomComponents={CustomComponents}
648
687
  refresh={refresh}
649
688
  config={config}
689
+
650
690
  loading={cardLoading}
651
691
  pagination={pagination}
652
- handlePagination={handlePagination}
692
+ onPaginationChange={(nextPagination) => {
693
+ Location.search({
694
+ ...Location.search(),
695
+ current: nextPagination.current,
696
+ pageSize: nextPagination.pageSize,
697
+ });
698
+ setPagination((prev) => ({
699
+ ...prev,
700
+ ...nextPagination,
701
+ }));
702
+ }}
653
703
  attributes={attributes}
654
- selectedSearchFields={selectedSearchFields}
655
- handleRemoveSearchField={handleRemoveSearchField}
656
- fetchReportData={(paginationUpdate) => fetchReportData(id, formContents, dbPtr, paginationUpdate || pagination)}
704
+ // selectedSearchFields={selectedSearchFields}
705
+ // handleRemoveSearchField={handleRemoveSearchField}
706
+ // fetchReportData={(paginationUpdate) => fetchReportData(id, formContents, dbPtr, paginationUpdate || pagination)}
657
707
  />
658
- {/** GuestList component end*/}
659
708
  </>
660
709
  )}
661
710
  </Card>
662
711
  );
663
712
  }
664
-
665
- /**
666
- *
667
- * @param root0
668
- * @param root0.patients
669
- * @param root0.CustomComponents
670
- * @param root0.summaryColumns
671
- * @param root0.refresh
672
- * @param root0.isFixedIndex
673
- * @returns {*}
674
- */
675
- //Renders a table displaying a list of patients with dynamic columns
676
- function GuestList({
677
- patients,
678
- columns,
679
- loading,
680
- CustomComponents,
681
- refresh,
682
- isFixedIndex,
683
- barcodeFilterKey,
684
- showScanner,
685
- config,
686
- pagination,
687
- handlePagination,
688
- attributes,
689
- selectedSearchFields,
690
- handleRemoveSearchField,
691
- fetchReportData,
692
- }) {
693
- /**
694
- * @param {*} propValues
695
- */
696
- const propValues = (attributes && JSON.parse(attributes)) || {};
697
-
698
- const { buttonAttributes = [] } = propValues;
699
-
700
- var [query, setQuery] = useState('');
701
-
702
- const [exportData, setExportData] = useState({});
703
-
704
- // const [data, setData] = useState([]);
705
-
706
- //visibility of the QR scanner modal.
707
- const [isScannerVisible, setScannerVisible] = useState(false);
708
-
709
- // Stores the patients filtered specifically by QR scan match.
710
- const [filteredPatients, setFilteredPatients] = useState([]); // Show all initially
711
-
712
- // patient object to redirect to upon successful QR scan.
713
- const [redirectPatient, setRedirectPatient] = useState(null);
714
-
715
- const [visible, setVisible] = useState(false);
716
-
717
- const [ActiveComponent, setActiveComponent] = useState(null);
718
-
719
- let history = useHistory();
720
-
721
- const { isMobile, dispatch } = useContext(GlobalContext);
722
- const [single, setSingle] = useState({});
723
- const otherDetails = config.other_details1 ? JSON.parse(config.other_details1) : {};
724
-
725
- // const otherDetails = config.other_details1 ? JSON.parse(config.other_details1) : {};
726
- // const [view, setView] = useState(isMobile ? true : false); //Need to check this condition
727
- const cols = buildDisplayColumns({
728
- columns,
729
- patients,
730
- isFixedIndex,
731
- CustomComponents,
732
- refresh,
733
- otherDetails,
734
- });
735
-
736
- /**
737
- *
738
- * @param {*} result
739
- */
740
-
741
- // function changeView(result) {
742
- // setView(result);
743
- // }
744
-
745
- /**
746
- *
747
- * @param {*} event
748
- */
749
-
750
- function onSearch(event) {
751
- setQuery(event.target.value);
752
- }
753
-
754
- /**
755
- *
756
- */
757
-
758
- useEffect(() => {
759
- //Cheaking if there is patient data exists
760
- if (patients) {
761
- // let data = patients?.map((entry) => {
762
- // entry.rowIndex = entry.opb_id;
763
-
764
- // entry.dispatch = dispatch;
765
-
766
- // return entry;
767
- // });
768
-
769
- // setData(data);
770
-
771
- // Define export data
772
- // Sanitize cols for export to ensure titles are strings
773
- const exportCols = cols.map((col) => {
774
- if (col.title && typeof col.title === 'object' && col.title.props) {
775
- return { ...col, title: col.title.props.title };
776
- }
777
- return col;
778
- });
779
- const summaryCols = columns.filter((col) => col.enable_summary);
780
- let dataToExport = [...patients];
781
-
782
- if (summaryCols.length > 0) {
783
- // Build one synthetic row for CSV export that mirrors the table layout:
784
- // numeric summary cells are populated from `calculateSummaryValues`, while
785
- // non-summary columns stay blank unless a configured caption should be shown.
786
- const summaryValues = calculateSummaryValues(summaryCols, patients);
787
- const summaryRow = { isSummaryRow: true };
788
-
789
- cols.forEach((col, index) => {
790
- // Start each export column empty so the appended row keeps the same shape
791
- // as the data rows and does not leak index/helper values into the export.
792
- const colKey = col.field || col.key || col.dataIndex;
793
- if (colKey && !summaryRow[colKey]) {
794
- summaryRow[colKey] = '';
795
- }
796
-
797
- if (summaryValues[col.field] !== undefined) {
798
- // Fill columns that have an aggregate configured (sum, count, avg, etc.).
799
- summaryRow[col.field] = summaryValues[col.field];
800
- } else {
801
- // If this column is marked as the caption target for a summary column,
802
- // place the configured label (for example "Total") into that cell.
803
- const captionConfig = columns.find((c) => col.field && c.caption_field === col.field);
804
- if (captionConfig) {
805
- summaryRow[col.field] = captionConfig.summary_caption || '';
806
- }
807
- }
808
- });
809
- dataToExport.push(summaryRow);
810
- }
811
- let exportDatas = getExportData(dataToExport, exportCols);
812
-
813
- if (exportDatas.exportDataColumns.length && exportDatas.exportDataHeaders.length) {
814
- setExportData({ exportDatas });
815
- }
816
- }
817
- }, [patients, columns]);
818
-
819
- let filtered;
820
-
821
- if (patients) {
822
- filtered = patients.filter((record) => {
823
- if (query) {
824
- // Keys
825
- let keys = Object.keys(record);
826
-
827
- let flag = false;
828
-
829
- keys.forEach((key) => {
830
- let ele = record[key];
831
-
832
- if (ele && typeof ele === 'string' && ele.toLowerCase().indexOf(query.toLowerCase()) !== -1) {
833
- flag = true;
834
- }
835
- });
836
-
837
- /**Will return flag */
838
- return flag;
839
- } else {
840
- return true;
841
- }
842
- });
843
- }
844
-
845
- /**
846
- * Checks for a match in the filtered patient list based on a scanned code,
847
- * updates the relevant state if a match is found, and redirects to the
848
- * patient's detail page. Displays a warning if no match is found.
849
- *
850
- * @param {string} code - The scanned code to match against a specific field of each patient.
851
- */
852
-
853
- const handleScanSuccess = (code) => {
854
- // Filters patients based on the scanned code and the selected barcode key(using attributes 'barcodeFilterKey')
855
- const matched = filtered.filter((patient) => patient[barcodeFilterKey] === code);
856
-
857
- if (matched.length) {
858
- const patient = matched[0];
859
- setFilteredPatients(matched);
860
- setRedirectPatient(matched);
861
- message.success(`Match found for ${code}, redirecting...`);
862
-
863
- const actionColumn = columns.find((col) => col.field === 'action') || columns.find((col) => col.type === 'action');
864
- if (actionColumn) {
865
- const redirectLink = getRedirectLink(actionColumn, patient);
866
- // history.push(redirectLink);
867
- window.location.href = redirectLink;
868
- }
869
- } else {
870
- Modal.warning({
871
- title: 'No matching records.',
872
- content: `No match for scanned code: ${code}`,
873
- });
874
- }
875
- };
876
-
877
- //open the edit modal
878
- const handleOpenEdit = (button) => {
879
- const componentName = button.component;
880
- const ComponentToRender = ReportingDashboardComp[componentName];
881
-
882
- if (!ComponentToRender) {
883
- console.error(`Component ${componentName} not found!`);
884
- return;
885
- }
886
-
887
- setSingle({});
888
- setActiveComponent(() => ComponentToRender);
889
- setVisible(true);
890
- };
891
-
892
- // close the edit modal
893
- const handleCloseEdit = () => {
894
- setShowEdit(false);
895
- };
896
- /**
897
- * Calculates aggregate values for the configured summary columns.
898
- *
899
- * Each summary definition contributes one value keyed by its `field`. Missing
900
- * row values are treated as `0` for numeric operations so the table summary and
901
- * export summary row can be built from the same result object.
902
- *
903
- * Supported functions:
904
- * `sum` - totals all numeric values in the field.
905
- * `count` - returns the number of rows in the current dataset.
906
- * `avg` - returns the arithmetic mean of the field values.
907
- * `min` - returns the smallest numeric value in the field.
908
- * `max` - returns the largest numeric value in the field.
909
- *
910
- * @param {Array<Object>} summaryCols - Column configs with `field` and `function`.
911
- * @param {Array<Object>} pageData - Rows currently being summarized.
912
- * @returns {Object} Aggregate values keyed by field name.
913
- */
914
- function calculateSummaryValues(summaryCols, pageData) {
915
- const summaryValues = {};
916
-
917
- summaryCols.forEach((col) => {
918
- const field = col.field;
919
-
920
- if (col.function === 'sum') {
921
- summaryValues[field] = pageData.reduce((total, row) => total + Number(row[field] || 0), 0);
922
- }
923
-
924
- if (col.function === 'count') {
925
- summaryValues[field] = pageData.length;
926
- }
927
-
928
- if (col.function === 'avg') {
929
- const total = pageData.reduce((sum, row) => sum + Number(row[field] || 0), 0);
930
- summaryValues[field] = pageData.length ? total / pageData.length : 0;
931
- }
932
- if (col.function === 'min') {
933
- const values = pageData.map((row) => Number(row[field] || 0));
934
- summaryValues[field] = values.length ? Math.min(...values) : 0;
935
- }
936
-
937
- if (col.function === 'max') {
938
- const values = pageData.map((row) => Number(row[field] || 0));
939
- summaryValues[field] = values.length ? Math.max(...values) : 0;
940
- }
941
- });
942
-
943
- return summaryValues;
944
- }
945
- return (
946
- <>
947
- <div className="table-header">
948
- <div className="table-left">
949
- {/* {selectedSearchFields?.length > 0 ? (
950
- <div className="search-tags-container">
951
- {selectedSearchFields.map((field) => (
952
- <Tag key={field.field} closable color="blue" onClose={() => handleRemoveSearchField(field.field)}>
953
- {field.caption}
954
- </Tag>
955
- ))}
956
- </div>
957
- ) : null} */}
958
- </div>
959
-
960
- <div className="table-right">
961
- {/* shwoing caption is not correct so this commented */}
962
- {/* <span className="menu-caption">{config.caption}</span> */}
963
- <Search className="table-search-input" placeholder="Enter Search Value" allowClear onChange={onSearch} />
964
- <div className="table-export-button">
965
- {exportData.exportDatas && (
966
- <ExportReactCSV
967
- title={config.caption}
968
- headers={exportData.exportDatas.exportDataHeaders}
969
- csvData={exportData.exportDatas.exportDataColumns}
970
- />
971
- )}
972
- </div>
973
-
974
- {/* QR Scan start */}
975
- {showScanner ? (
976
- <Button size="small" type="primary" icon={<QrcodeOutlined />} onClick={() => setScannerVisible(true)}>
977
- Scan QR
978
- </Button>
979
- ) : null}
980
- {/** Add User button */}
981
- {Array.isArray(buttonAttributes) &&
982
- buttonAttributes.map((btn, index) => (
983
- <Button key={index} size="small" type="primary" style={{ marginLeft: 8 }} onClick={() => handleOpenEdit(btn)}>
984
- {btn.title}
985
- </Button>
986
- ))}
987
-
988
- <Modal open={visible} onCancel={() => setVisible(false)} footer={null} destroyOnClose width={950} style={{ top: 10 }}>
989
- {ActiveComponent && (
990
- <ActiveComponent
991
- formContent={single}
992
- callback={() => {
993
- setVisible(false);
994
- refresh();
995
- setVisible(false);
996
- fetchReportData();
997
- }}
998
- // {...dynamicProps}
999
- />
1000
- )}
1001
- </Modal>
1002
-
1003
- <Modal open={isScannerVisible} title="Scan QR Code" footer={null} onCancel={() => setScannerVisible(false)} destroyOnClose>
1004
- <QrScanner onScanSuccess={handleScanSuccess} onClose={() => setScannerVisible(false)} />
1005
- </Modal>
1006
- {/* QR Scan End */}
1007
- </div>
1008
- </div>
1009
-
1010
- <div>
1011
- <Card>
1012
- {loading ? (
1013
- <>
1014
- <Skeleton active paragraph={{ rows: 6 }} />
1015
- </>
1016
- ) : (
1017
- <TableComponent
1018
- size="small"
1019
- // scroll={{ x: 'max-content' }}
1020
- scroll={{ x: 'max-content', y: '60vh' }}
1021
- rowKey={(record) => record.OpNo}
1022
- dataSource={filtered ? filtered : patients} // In case if there is no filtered values we can use patient data
1023
- columns={cols}
1024
- sticky
1025
- pagination={false}
1026
- summary={(pageData) => {
1027
- const summaryCols = columns.filter((col) => col.enable_summary);
1028
- if (!summaryCols.length) return null;
1029
- /** calculate summary*/
1030
-
1031
- const summaryValues = calculateSummaryValues(summaryCols, pageData);
1032
-
1033
-
1034
- return (
1035
- <Table.Summary.Row className="report-summary-row">
1036
- {cols.map((col, index) => {
1037
- if (summaryValues[col.field] !== undefined) {
1038
- return (
1039
- <Table.Summary.Cell key={index}>
1040
- <strong style={{ fontWeight: 900 }}>{summaryValues[col.field]}</strong>
1041
- </Table.Summary.Cell>
1042
- );
1043
- }
1044
-
1045
- const captionConfig = columns.find((c) => col.field && c.caption_field === col.field);
1046
- if (captionConfig) {
1047
- return (
1048
- <Table.Summary.Cell key={index}>
1049
- <strong style={{ fontWeight: 900 }}>{captionConfig.summary_caption || ''}</strong>
1050
- </Table.Summary.Cell>
1051
- );
1052
- }
1053
-
1054
- return <Table.Summary.Cell key={index} />;
1055
- })}
1056
- </Table.Summary.Row>
1057
- );
1058
- }}
1059
- />
1060
- )}
1061
-
1062
- {/* Pagination aligned to the right */}
1063
- <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 8 }}>
1064
- <Pagination
1065
- showSizeChanger
1066
- current={pagination.current}
1067
- pageSize={pagination.pageSize}
1068
- total={pagination.total}
1069
- pageSizeOptions={[20, 30, 50, 100]}
1070
- onChange={(page, pageSize) => handlePagination({ current: page, pageSize })}
1071
- />
1072
- </div>
1073
-
1074
- {/*If patient data exists show the number else to 0 */}
1075
- <p className="size-hint">{patients ? patients.length : 0} records. </p>
1076
- </Card>
1077
- {/* </> */}
1078
- {/* )} */}
1079
- </div>
1080
- </>
1081
- );
1082
- }