You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mvfront-react/components/CSVLink.tsx

124 lines
4.0 KiB

import React from 'react';
// import dynamic from 'next/dynamic'
// import {buildURI} from 'react-csv';
// /**
// * See https://github.com/react-csv/react-csv/issues/87
// */
export const isSafari = () => /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
export const isJsons = ((array) => Array.isArray(array) && array.every(
row => (typeof row === 'object' && !(row instanceof Array))
));
export const isArrays = ((array) => Array.isArray(array) && array.every(
row => Array.isArray(row)
));
export const jsonsHeaders = ((array) => Array.from(
array.map(json => Object.keys(json))
.reduce((a, b) => new Set([...a, ...b]), [])
));
export const jsons2arrays = (jsons, headers) => {
headers = headers || jsonsHeaders(jsons);
// allow headers to have custom labels, defaulting to having the header data key be the label
let headerLabels = headers;
let headerKeys = headers;
if (isJsons(headers)) {
headerLabels = headers.map((header) => header.label);
headerKeys = headers.map((header) => header.key);
}
const data = jsons.map((object) => headerKeys.map((header) => getHeaderValue(header, object)));
return [headerLabels, ...data];
};
export const getHeaderValue = (property, obj) => {
const foundValue = property
.replace(/\[([^\]]+)]/g, ".$1")
.split(".")
.reduce(function (o, p, i, arr) {
// if at any point the nested keys passed do not exist, splice the array so it doesnt keep reducing
const value = o[p];
if (value === undefined || value === null) {
arr.splice(1);
} else {
return value;
}
}, obj);
// if at any point the nested keys passed do not exist then looks for key `property` in object obj
return (foundValue === undefined) ? ((property in obj) ? obj[property] : '') : foundValue;
}
export const elementOrEmpty = (element) =>
(typeof element === 'undefined' || element === null) ? '' : element;
export const joiner = ((data, separator = ',', enclosingCharacter = '"') => {
return data
.filter(e => e)
.map(
row => row
.map((element) => elementOrEmpty(element))
.map(column => `${enclosingCharacter}${column}${enclosingCharacter}`)
.join(separator)
)
.join(`\n`);
});
export const arrays2csv = ((data, headers, separator, enclosingCharacter) =>
joiner(headers ? [headers, ...data] : data, separator, enclosingCharacter)
);
export const jsons2csv = ((data, headers, separator, enclosingCharacter) =>
joiner(jsons2arrays(data, headers), separator, enclosingCharacter)
);
export const string2csv = ((data, headers, separator) =>
(headers) ? `${headers.join(separator)}\n${data}` : data.replace(/"/g, '""')
);
export const toCSV = (data, headers, separator, enclosingCharacter) => {
if (isJsons(data)) return jsons2csv(data, headers, separator, enclosingCharacter);
if (isArrays(data)) return arrays2csv(data, headers, separator, enclosingCharacter);
if (typeof data === 'string') return string2csv(data, headers, separator);
throw new TypeError(`Data should be a "String", "Array of arrays" OR "Array of objects" `);
};
const CSVLink = ({filename, data, children, ...rest}) => {
const buildURI = ((data, uFEFF, headers, separator, enclosingCharacter) => {
const csv = toCSV(data, headers, separator, enclosingCharacter);
const type = isSafari() ? 'application/csv' : 'text/csv';
const blob = new Blob([uFEFF ? '\uFEFF' : '', csv], {type});
const dataURI = `data:${type};charset=utf-8,${uFEFF ? '\uFEFF' : ''}${csv}`;
const URL = window.URL || window.webkitURL;
return (typeof URL.createObjectURL === 'undefined')
? dataURI
: URL.createObjectURL(blob);
});
const isNodeEnvironment = typeof window === 'undefined';
const uFEFF = true;
const headers = undefined;
const separator = ",";
const enclosingCharacter = '"';
const href = isNodeEnvironment ? '' : buildURI(data, uFEFF, headers, separator, enclosingCharacter)
return (
<a
download={filename}
target="_blank"
{...rest}
href={href}
>
{children}
</a>
);
}
export default CSVLink;