@@ -4,6 +4,7 @@ import { withStyles } from '@material-ui/core';
4
4
import { useTranslation } from 'react-i18next' ;
5
5
import PropTypes from 'prop-types' ;
6
6
import { forwardRef } from 'react' ;
7
+ import moment from 'moment' ;
7
8
8
9
import AddBox from '@material-ui/icons/AddBox' ;
9
10
import ArrowDownward from '@material-ui/icons/ArrowDownward' ;
@@ -12,6 +13,7 @@ import ChevronLeft from '@material-ui/icons/ChevronLeft';
12
13
import ChevronRight from '@material-ui/icons/ChevronRight' ;
13
14
import Clear from '@material-ui/icons/Clear' ;
14
15
import Delete from '@material-ui/icons/Delete' ;
16
+ import CloudDownloadIcon from '@material-ui/icons/CloudDownload' ;
15
17
import Edit from '@material-ui/icons/Edit' ;
16
18
import FilterList from '@material-ui/icons/FilterList' ;
17
19
import FirstPage from '@material-ui/icons/FirstPage' ;
@@ -76,6 +78,135 @@ const CustomMaterialTable = ({
76
78
77
79
const mergedOptions = { ...defaultOptions , ...options } ;
78
80
81
+ const downloaddataAsCsv = async ( pageSize = 100 ) => {
82
+ let allData = [ ] ;
83
+ let currentPage = 0 ;
84
+ let hasMoreData = true ;
85
+
86
+ try {
87
+ // Handle case where data is already an array
88
+ if ( typeof data !== 'function' ) {
89
+ if ( ! Array . isArray ( data ) ) {
90
+ throw new Error (
91
+ 'Data must be either a function or an array'
92
+ ) ;
93
+ }
94
+
95
+ allData = data ;
96
+ if ( ! allData . length ) {
97
+ return ;
98
+ }
99
+
100
+ const headers = Object . keys ( allData [ 0 ] || { } ) . sort ( ) ;
101
+ return generateAndDownloadCsv ( allData , headers ) ;
102
+ }
103
+
104
+ // Handle case where data is a function
105
+ const firstPageQuery = {
106
+ page : currentPage ,
107
+ pageSize : pageSize ,
108
+ search : '' ,
109
+ } ;
110
+
111
+ const firstPageResponse = await data ( firstPageQuery ) ;
112
+ if ( ! firstPageResponse . data . length ) {
113
+ return ;
114
+ }
115
+
116
+ // Get headers from first item and sort alphabetically
117
+ const headers = Object . keys ( firstPageResponse . data [ 0 ] ) . sort ( ) ;
118
+ allData = [ ...firstPageResponse . data ] ;
119
+
120
+ // Continue fetching if there's more data
121
+ hasMoreData =
122
+ firstPageResponse . data . length === pageSize &&
123
+ allData . length < firstPageResponse . totalCount ;
124
+ currentPage ++ ;
125
+
126
+ // Fetch remaining pages
127
+ while ( hasMoreData ) {
128
+ const query = {
129
+ page : currentPage ,
130
+ pageSize : pageSize ,
131
+ search : '' ,
132
+ } ;
133
+
134
+ const response = await data ( query ) ;
135
+ allData = [ ...allData , ...response . data ] ;
136
+
137
+ hasMoreData =
138
+ response . data . length === pageSize &&
139
+ allData . length < response . totalCount ;
140
+ currentPage ++ ;
141
+ }
142
+
143
+ return generateAndDownloadCsv ( allData , headers ) ;
144
+ } catch ( error ) {
145
+ console . error ( 'Error downloading data:' , error ) ;
146
+ throw error ;
147
+ }
148
+ } ;
149
+
150
+ // Helper function to generate and download CSV
151
+ const generateAndDownloadCsv = ( allData , headers ) => {
152
+ // Convert data to CSV format
153
+ const csvContent = [
154
+ // Add headers
155
+ headers . join ( ',' ) ,
156
+ // Add data rows, handling missing fields
157
+ ...allData . map ( ( item ) =>
158
+ headers
159
+ . map ( ( header ) => {
160
+ const value = item [ header ] ?? '' ;
161
+ // Handle special cases like arrays and objects
162
+ const processedValue =
163
+ typeof value === 'object'
164
+ ? JSON . stringify ( value )
165
+ : String ( value ) ;
166
+ // Escape commas, quotes, and newlines
167
+ const escapedValue = processedValue
168
+ . replace ( / " / g, '""' )
169
+ . replace ( / \n / g, ' ' ) ;
170
+ return `"${ escapedValue } "` ;
171
+ } )
172
+ . join ( ',' )
173
+ ) ,
174
+ ] . join ( '\n' ) ;
175
+
176
+ // Create and download the CSV file
177
+ const blob = new Blob ( [ csvContent ] , {
178
+ type : 'text/csv;charset=utf-8;' ,
179
+ } ) ;
180
+ const link = document . createElement ( 'a' ) ;
181
+ const url = URL . createObjectURL ( blob ) ;
182
+
183
+ link . setAttribute ( 'href' , url ) ;
184
+ link . setAttribute (
185
+ 'download' ,
186
+ `download_${ moment ( ) . format ( 'YYYY-MM-DD_HH-mm-ss' ) } .csv`
187
+ ) ;
188
+ document . body . appendChild ( link ) ;
189
+ link . click ( ) ;
190
+ document . body . removeChild ( link ) ;
191
+ URL . revokeObjectURL ( url ) ;
192
+
193
+ return {
194
+ totalItems : allData . length ,
195
+ columns : headers ,
196
+ } ;
197
+ } ;
198
+
199
+ if ( ! actions ) {
200
+ actions = [ ] ;
201
+ }
202
+
203
+ actions . push ( {
204
+ tooltip : t ( 'DOWNLOAD' ) ,
205
+ icon : CloudDownloadIcon ,
206
+ isFreeAction : true ,
207
+ onClick : ( evt ) => downloaddataAsCsv ( ) ,
208
+ } ) ;
209
+
79
210
return (
80
211
< MaterialTable
81
212
onChangeRowsPerPage = { setPageSize }
0 commit comments