Skip to content
Snippets Groups Projects
DownloadDataButton.tsx 3.38 KiB
import React from 'react';
import * as XLSX from "xlsx";
import { ExportType } from "../../helpers/constants";
import { FaDownload } from 'react-icons/fa';
import { NrenAndYearDatapoint } from '../../Schema';


interface DownloadProps {
    data: NrenAndYearDatapoint[];
    filename: string;
    exportType: ExportType;
}


function createCSVRows(jsonData: NrenAndYearDatapoint[], header: string[]): string[] {
    return jsonData.map(obj => {
        return header.map(fieldName => {
            const value = obj[fieldName];

            if (value === null) {
                return "";
            }

            // Always wrap strings in double quotes and escape internal double quotes
            if (typeof value === 'string') {
                return `"${value.replace(/"/g, '""')}"`;
            }

            return value;
        }).join(',');
    });
}


function convertToCSV(jsonData: NrenAndYearDatapoint[]): string {
    if (!jsonData.length) return "";

    const header = Object.keys(jsonData[0]);
    const rows = createCSVRows(jsonData, header);

    // Combine header and rows with newline characters
    return [header.join(','), ...rows].join('\r\n');
}

function convertToExcel(jsonData: NrenAndYearDatapoint[], sheetName = "Sheet1"): Blob {
    const ws = XLSX.utils.json_to_sheet(jsonData);
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, ws, sheetName);
    const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });

    const buffer = new ArrayBuffer(wbout.length);
    const view = new Uint8Array(buffer);
    for (let i = 0; i < wbout.length; i++) {
        // Convert each character of the binary workbook string to an 8-bit integer and store in the Uint8Array 'view' for blob creation.
        view[i] = wbout.charCodeAt(i) & 0xFF;
    }

    return new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' });
}

const DownloadDataButton: React.FC<DownloadProps> = ({ data, filename, exportType }) => {

    const downloadData = () => {
        let convertedData;
        let fileType;
        let contentType;

        switch (exportType) {
            case ExportType.EXCEL: {
                convertedData = convertToExcel(data);
                fileType = 'xlsx';
                contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8';
                break;
            }
            case ExportType.CSV:
            default: {
                convertedData = convertToCSV(data);
                fileType = 'csv';
                contentType = 'text/csv;charset=UTF-8';
                break;
            }
        }

        const blob = new Blob([convertedData], { type: contentType });
        filename = filename.endsWith(fileType) ? filename : `${filename}.${fileType}`;

        const link = document.createElement('a');
        link.href = URL.createObjectURL(blob);
        link.download = filename;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }

    let classname = 'downloadbutton';
    if (exportType === ExportType.CSV) {
        classname += ' downloadcsv';
    }
    else if (exportType === ExportType.EXCEL) {
        classname += ' downloadexcel';
    }

    return (
        <button className={classname} onClick={downloadData}>{exportType} <FaDownload /></button>
    );
}

export default DownloadDataButton;