@@ -8,7 +8,7 @@ import {useTranslation} from 'react-i18next';
88import Typography from '@mui/material/Typography' ;
99import Button from '@mui/material/Button' ;
1010import { useExportingRegistry } from 'context/ExportContext' ;
11- import type { Content , TDocumentDefinitions , ContentImage , Column , ContentTable } from 'pdfmake/interfaces' ;
11+ import type { Content , TDocumentDefinitions , ContentImage , ContentTable , TableLayout } from 'pdfmake/interfaces' ;
1212import { DataContext } from 'context/SelectedDataContext' ;
1313import { useAppSelector } from 'store/hooks' ;
1414
@@ -84,6 +84,8 @@ export default function ExportDialog(): JSX.Element {
8484 return result ;
8585 } , [ compartmentNames , scenarioCardData , scenariosState ] ) ;
8686
87+ //TODO: add a error handler in case the card values doesn't have any data for the selected scenario
88+
8789 const handleExport = useCallback ( ( ) => {
8890 void ( async ( ) => {
8991 const lineExp = get ( 'lineChart' ) ;
@@ -103,109 +105,133 @@ export default function ExportDialog(): JSX.Element {
103105 /**
104106 * More information how to work with pdfmake to create a pdf: https://pdfmake.github.io/docs/0.1/document-definition-object/
105107 */
108+ const nowStr = new Date ( ) . toLocaleString ( ) ;
106109 const doc : TDocumentDefinitions = {
107110 pageSize : 'A4' ,
108111 pageOrientation : 'portrait' ,
109- pageMargins : [ 10 , 10 , 10 , 10 ] ,
112+ pageMargins : [ 30 , 30 , 30 , 40 ] ,
110113 content : [ ] ,
111- styles : { header : { fontSize : 18 , bold : true , margin : [ 0 , 0 , 0 , 10 ] } } ,
114+ styles : {
115+ header : { fontSize : 20 , bold : true , margin : [ 0 , 0 , 0 , 8 ] } ,
116+ subheader : { fontSize : 12 , color : '#666' , margin : [ 0 , 0 , 0 , 12 ] } ,
117+ tableHeader : { bold : true , fontSize : 10 , color : '#333' } ,
118+ tableCell : { fontSize : 10 , color : '#333' } ,
119+ small : { fontSize : 8 , color : '#666' } ,
120+ } ,
121+ footer : ( currentPage : number , pageCount : number ) => ( {
122+ text : `${ currentPage } / ${ pageCount } ` ,
123+ alignment : 'right' ,
124+ margin : [ 30 , 0 , 30 , 20 ] ,
125+ fontSize : 8 ,
126+ color : '#666' ,
127+ } ) ,
128+ defaultStyle : { fontSize : 11 } ,
129+ info : { title : 'ESID Export' , subject : 'Exported report' , creator : 'ESID' } ,
112130 } ;
113131
114132 ( doc . content as Content [ ] ) . push ( { text : t ( 'export.header' ) , style : 'header' } ) ;
115-
116- const columns : Column [ ] = [
117- [
118- {
119- text : 'Selected District' ,
120- fontSize : 14 ,
121- } ,
122- {
123- text : selectedDistrictName ,
124- fontSize : 10 ,
125- } ,
126- ] ,
127- [
128- {
129- text : 'Selected Scenario' ,
130- fontSize : 14 ,
131- } ,
132- {
133- text : selectedScenarioName ?? '' ,
134- fontSize : 10 ,
135- } ,
136- ] ,
137- ] ;
138-
139133 ( doc . content as Content [ ] ) . push ( {
140- columns : columns ,
141- columnGap : 10 ,
142- margin : [ 0 , 0 , 0 , 10 ] ,
134+ text : `${ selectedDistrictName } — ${ selectedScenarioName ?? '' } • ${ nowStr } ` ,
135+ style : 'subheader' ,
143136 } ) ;
144137
138+ const infoTable : ContentTable = {
139+ table : {
140+ widths : [ '*' , '*' , '*' , '*' ] ,
141+ body : [
142+ [
143+ { text : 'Selected District' , style : 'tableHeader' } ,
144+ { text : selectedDistrictName , style : 'tableCell' } ,
145+ { text : 'Selected Scenario' , style : 'tableHeader' } ,
146+ { text : selectedScenarioName ?? '' , style : 'tableCell' } ,
147+ ] ,
148+ [
149+ { text : 'Reference Date' , style : 'tableHeader' } ,
150+ { text : referenceDay ?? '' , style : 'tableCell' } ,
151+ { text : 'Selected Date' , style : 'tableHeader' } ,
152+ { text : selectedDate ?? '' , style : 'tableCell' } ,
153+ ] ,
154+ ] ,
155+ } ,
156+ layout : {
157+ fillColor : ( rowIndex : number ) => ( rowIndex === 0 ? '#f5f5f5' : null ) ,
158+ hLineColor : '#e0e0e0' ,
159+ vLineColor : '#e0e0e0' ,
160+ } as TableLayout ,
161+ margin : [ 0 , 0 , 0 , 12 ] ,
162+ } ;
163+
164+ ( doc . content as Content [ ] ) . push ( infoTable ) ;
165+
145166 if ( lineDataUrl ) {
146167 ( doc . content as ContentImage [ ] ) . push ( {
147168 image : lineDataUrl ,
148- width : 500 ,
169+ fit : [ 540 , 320 ] ,
170+ alignment : 'center' ,
171+ margin : [ 0 , 0 , 0 , 8 ] ,
172+ } ) ;
173+ ( doc . content as Content [ ] ) . push ( {
174+ text : 'Line chart' ,
175+ style : 'small' ,
176+ alignment : 'center' ,
177+ margin : [ 0 , 0 , 0 , 12 ] ,
149178 } ) ;
150179 }
151180
152181 if ( mapDataUrl ) {
153182 ( doc . content as ContentImage [ ] ) . push ( {
154183 image : mapDataUrl ,
155- fit : [ 300 , 300 ] ,
184+ fit : [ 540 , 320 ] ,
185+ alignment : 'center' ,
186+ margin : [ 0 , 0 , 0 , 8 ] ,
187+ } ) ;
188+ ( doc . content as Content [ ] ) . push ( {
189+ text : 'Map' ,
190+ style : 'small' ,
191+ alignment : 'center' ,
192+ margin : [ 0 , 0 , 0 , 12 ] ,
156193 } ) ;
157194 }
158195
159196 // add each compartment name to the table
160197 const tableBody = [
161198 [
162- {
163- text : ' ' ,
164- fontSize : 14 ,
165- } ,
166- {
167- text : 'Reference Date' ,
168- fontSize : 12 ,
169- } ,
170- {
171- text : 'Selected Date' ,
172- fontSize : 12 ,
173- } ,
174- ] ,
175- [
176- {
177- text : ' ' ,
178- fontSize : 10 ,
179- } ,
180- {
181- text : referenceDay ?? '' ,
182- fontSize : 10 ,
183- } ,
184- {
185- text : selectedDate ?? '' ,
186- fontSize : 10 ,
187- } ,
188- ] ,
189- [
190- { text : 'Compartment' , bold : true , fontSize : 10 } ,
191- { text : 'Value' , bold : true , fontSize : 10 , colSpan : 2 } ,
199+ { text : 'Compartment' , style : 'tableHeader' } ,
200+ { text : 'Reference Value' , style : 'tableHeader' , alignment : 'right' } ,
201+ { text : 'Selected Value' , style : 'tableHeader' , alignment : 'right' } ,
192202 ] ,
193203 ] ;
194204
195205 for ( const compartment of compartmentNames ) {
196206 tableBody . push ( [
197- { text : compartment . name , fontSize : 10 } ,
198- { text : compartmentValues [ compartment . id ] . toString ( ) , fontSize : 10 } ,
199- { text : cardValues [ selectedScenario ?? '' ] ?. [ compartment . id ] ?. toString ( ) ?? '' , fontSize : 10 } ,
207+ { text : compartment . name , style : 'tableCell' } ,
208+ {
209+ text : ( compartmentValues [ compartment . id ] ?? '' ) . toString ( ) ,
210+ style : 'tableCell' ,
211+ alignment : 'right' ,
212+ } ,
213+ {
214+ text : ( cardValues [ selectedScenario ?? '' ] ?. [ compartment . id ] ?? '' ) . toString ( ) ,
215+ style : 'tableCell' ,
216+ alignment : 'right' ,
217+ } ,
200218 ] ) ;
201219 }
202220
221+ const zebraLayout : TableLayout = {
222+ fillColor : ( rowIndex : number ) => ( rowIndex === 0 ? '#f5f5f5' : rowIndex % 2 === 0 ? '#fafafa' : null ) ,
223+ hLineColor : '#e0e0e0' ,
224+ vLineColor : '#e0e0e0' ,
225+ } ;
226+
203227 ( doc . content as ContentTable [ ] ) . push ( {
204- layout : 'lightHorizontalLines' , // optional
228+ layout : zebraLayout ,
205229 table : {
206- headerRows : 3 ,
230+ headerRows : 1 ,
231+ widths : [ '*' , 'auto' , 'auto' ] ,
207232 body : tableBody ,
208233 } ,
234+ margin : [ 0 , 0 , 0 , 4 ] ,
209235 } ) ;
210236
211237 const pdfmake = pdfMake as { createPdf ?: ( doc : unknown ) => { download : ( name : string ) => void } } ;
0 commit comments