ReactJS xlsx-js-style read local xls file - reactjs

I have an imported file: import ExportReportCardTemplate from "asset/files/excel/report_card_template.xls";
How can I use it with library import * as xlsx from "xlsx-js-style";
I've searching but all I get is reading xls file with input, how can I read a local file and then use it with xlsx?
After following tpliakas' answer, I got this error:

First you should read file as a binary string, so you have to do something like this
function readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
resolve(e.target.result);
};
reader.onerror = (e) => {
reject(e);
};
reader.readAsBinaryString(file);
});
}
Then you should parse this binary string to a workbook:
async function readExcel() {
// Wait for the binary string first
const binaryString = await readFile(ExportReportCardTemplate);
const wb = xlsx.read(binaryString, { type: 'binary' });
// use the wb here
}

After following tpliakas answer, I had a bit adjustment and finally I can read the local file to workbook data, here is the code:
import ExportReportCardTemplate from "asset/files/excel/report_card_template.xls";
import * as xlsx from "xlsx-js-style";
const readFile = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
resolve(e.target.result);
};
reader.onerror = (e) => {
reject(e);
};
fetch(file)
.then((response) => response.blob())
.then((file) => reader.readAsBinaryString(file));
});
};
export const exportReportCardExcel = async (data) => {
try {
const binaryString = await readFile(ExportReportCardTemplate);
const workbook = xlsx.read(binaryString, { type: "binary" });
console.log("workbook:::", workbook);
} catch (error) {
console.log("error:::", error);
}
};

Related

All files in an array not converting to base64 in react js

I have a custom hook called useBase64 where I convert my image to Base64. This hook accepts an initial value and returns handleCreateBase64 function and logo (piece of state). handleCreateBase64 converts the file to base64 and stores it in logo. I am sending an array of images as File and then mapping through that array and I want to store it in logo and then send it to that component. right now the problem is that in the logo I can only see 1 base64 even if I select multiple files.
useBase64 hook: -
import { useCallback, useState } from "react";
export const useBase64 = (initialValue) => {
const [logo, setLogo] = useState(initialValue)
const handleCreateBase64 = useCallback(async (receivedFile) => {
let file = receivedFile;
if(initialValue instanceof Array) {
file = Object.values(receivedFile)
file.map(async el => {
const base64 = await convertToBase64(el)
setLogo([...logo, base64])
})
}
});
const convertToBase64 = (file) => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
if (!file) {
console.log("no image");
} else {
fileReader.readAsDataURL(file);
fileReader.onload = () => {
resolve(fileReader.result);
};
}
fileReader.onerror = (error) => {
reject(error);
};
});
};
return { handleCreateBase64, logo }
}
The result: -
As you can see above that I have 3 images selected but I see only 1 base64. I am quiet new to this so it will be great if full explanation is provided.
Wrong use of map and setState
Try:
const items = await Promise.all(file.map(el => convertToBase64(el)))
setLogo([...logo, ...items])

trouble with async reucrsion of directories , with file system access api in react js

This code is designed to recursively iterate through a selected directory using the file system access api , and sent it via axios post request.
I have an encountered 2 problems :
I am struggling to find the right way to to enter subdirectories (now it only works for a directory with only files and no subDirs)
as you can see , i set a timeout before the post request , for some reason I cant identify , the promise in savedOCS function , probably resolves before it should.
I have the following code :
async uploadDirectory () {
const directoryHandle = await window.showDirectoryPicker();
const t0 = performance.now();
console.log(`t0 ${t0}`);
this.setState({chosenDirectory: directoryHandle.name} , ()=> {
console.log(this.state.chosenDirectory);
});
await this.handleDirectoryEntry(directoryHandle);
const t4 = performance.now();
console.log(`t4 ${t4}`);
setTimeout(() => {
this.axios.post(
'/DirectoryTransfer', {
directory: this.state.chosenDirectory,
directoryFiles: this.state.directoryFiles
}
).then((resData) => {
// this.fetchRemoteFileSystem();
const t5 = performance.now();
console.log(`t5 ${t5}`);
}).catch((error) => {
console.log(error)
})
}, 5000);
}
async handleDirectoryEntry(directoryHandle,subdir) {
let fileEntries = [];
console.log(directoryHandle);
for await (const entry of directoryHandle.values()) {
console.log(entry);
if(entry.kind === "file" && subdir === '') {
fileEntries.push(await entry.getFile());
}
}
console.log(fileEntries);
await this.saveDocs(fileEntries);
}
saveDocs = async (files) => {
const filePromises = files.map((file) => {
return new Promise ((resolve ,reject)=> {
const fileReader = new FileReader();
fileReader.onload = async ()=> {
try {
let directoryFiles = this.state.directoryFiles || [];
console.log('before setState: ', directoryFiles)
let response = false;
const t2 = performance.now();
console.log(`t2 ${t2}`)
await this.setState(
(prevState) => ({
directoryFiles: [...prevState.directoryFiles, { name: file.name, data: fileReader.result }]
}),
() => {
response = true;
console.log("after setState: ", this.state.directoryFiles);
const t3 = performance.now();
console.log(`t3 ${t3}`)
}
);
resolve(response);
} catch(err) {
reject(err)
}
}
fileReader.onerror = (err) => {
reject(err);
}
fileReader.readAsText(file);
})
})
const fileInfos = await Promise.all(filePromises);
return fileInfos;
}
i tried to find a way to iterate subDirs using recursion , and to async read files inside a directory.
current results :
the code reads the files fine.
without the timeout it sends a post request with an empty array of files.
doesn't have an implementation for subDirs.

How to convert blob into base64 in nextJs

I am getting the Image from an API response. I am trying to the get the image and display in the UI.
import FileReader from 'filereader';
export default async (req, res) => {
const { method } = req;
switch (method) {
case 'GET':
try {
const response = await fetch("imagepathurl", Constants.config);
const imageBlob = await response.blob()
console.log("imageBlob", imageBlob)
return new Promise((resolve, _) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(imageBlob);
});
} catch (error) {
console.log("error", error);
}
break
default:
res.setHeader('Allow', ['GET', 'PUT', 'PATCH'])
res.status(405).end(`Method ${method} Not Allowed`)
}
}
I can able to capture imageBlob but from the fileReader() i am unable to capture and convert to base64.
In File Reader i am facing Error: cannot read as File: {}.
Please let me know the way i am doing is correct or can soneone guide me in fixing it.

React-Dropzone how convert each file to base64

I am using react-dropzone plugin for file uploads. I worried how i can convert each file to base64:
eg:
Here is my function where i get files:
I am creating here for example thumb for each file and attach to object. But how add to item here prop like base64string: and it will keep base64 data for each file?
this.onDrop = files => {
files.map(file =>
Object.assign(file, {
preview: URL.createObjectURL(file),
})
);
};
check this out,you can get files and then you can store them into images array of state instance.
onDropHandler = (files) => {
files.map(file => {
const reader = new FileReader();
reader.onload = (event) => {
//store result into your state array.
this.setState(prevState => {
const updatedImages = [...prevState.images, event.target.result];
return {
images: updatedImages,
}
})
console.log(event.target.result);
};
reader.readAsDataURL(file);
});
}
With this code you get an array with the base64 data and blob url for the preview.
const [data, setData] = useState([])
const onDrop = (files) => {
files.map((file) => {
const reader = new FileReader()
reader.onload = (e) => {
setdata(
files.map((file) =>
Object.assign(file, {
preview: URL.createObjectURL(file),
base64Image: e.target.result,
})
)
)
}
reader.readAsDataURL(file)
})
}

how to upload file like pdf or doc in firestore

I want to upload document files in firestore using redux. i get the file in and passed it as a state to the action file with other datas. following is my code in action file.
const createJob = (project) => {
return (dispatch, getState, {getFirebase, getFirestore}) => {
const firestore = getFirestore();
firestore.collection('Jobs').add({
...project,
postedby:'Employer1',
Documents:project.Documents.name
}).then(()=>{
dispatch({type:'CREATE_JOB', project});
}).catch((err)=>{
dispatch({type:'CREATE_JOB_ERROR', err});
})
}
};
but the data is saved as C:\fakepath\doc1.doc
how to upload the actual file in firestore
Technically you can upload an image to firestore. You need to convert it to base64 text first. Just spent some time figuring it out. I take the selected file from an upload file from browser then I upload it in the callback of the file reader. Hopefully this helps someone out.
function getBase64(file){
var n = document.getElementById('nameU').value;
//name of uploaded file from textbox
var d = document.getElementById('dateU').value;
//date of uploaded file from textbox
var reader = new FileReader();
reader.onerror = function (error) {
console.log('Error: ', error);
};
reader.readAsDataURL(file);
reader.onload = function () {
let encoded = reader.result.split(',');
//you split this to get mimetype out of your base64
addForSale(Date.now().toString(10), {uDesc: n, date: d, uFile: encoded[1]});
// I just used a timestamp as the ID
}
};
function addForSale(id, data) {
var collection = firebase.firestore().collection('forsale');
return collection.doc(id).set(data);}
Hi You cannot directly store the image in firestore.What you have to do is first store the document in firebase storage and get the url as reponse.Once the response is received add the url in documents.
First create an Storage Action in reduce:
import { storage } from '../../../firebase/firebase';
import {
ADD_DOCUMENT_STARTED,
ADD_DOCUMENT_COMPLETED,
ADD_DOCUMENT_ERROR
} from '../../actionTypes/storageActionTypes';
import { toast } from 'react-toastify';
import constants from '../../../config/constants';
export const addDocumentStart = () => ({
type: ADD_DOCUMENT_STARTED
});
export const addDocumentSuccess = () => ({
type: ADD_DOCUMENT_COMPLETED
});
export const addDocumentFailure = () => ({
type: ADD_DOCUMENT_ERROR
});
export const addDocument = (values, pathName) => {
const toastId = toast('Uploading Attachment, Please wait..', {
autoClose: false
});
return (dispatch) =>
new Promise(function(resolve, reject) {
dispatch(addDocumentStart());
const timeStamp = new Date().getTime();
const image = values.document[0];
var name;
if (values && values.documentName) {
name = timeStamp.toString().concat(values.documentName);
} else {
name = timeStamp.toString().concat(image.name);
}
const imageUpload = storage.ref(`${pathName}/${name}`).put(image);
imageUpload.on(
'state_changed',
(snapshot) => {
switch (snapshot.state) {
case 'paused':
reject('Upload is paused');
dispatch(addDocumentFailure('Upload is paused'));
break;
}
},
(error) => {
switch (error.code) {
case 'storage/unauthorized':
reject('Permission Denied');
dispatch(addDocumentFailure('Permission Denied'));
break;
case 'storage/canceled':
reject('Upload Cancelled');
dispatch(addDocumentFailure('Upload Cancelled'));
break;
case 'storage/unknown':
reject('Server Response Error');
dispatch(addDocumentFailure('Server Response Error'));
break;
}
},
() => {
toast.update(toastId, {
render: 'Attachment Uploaded successfully',
type: toast.TYPE.SUCCESS,
autoClose: constants.toastTimer
});
storage
.ref(pathName)
.child(name)
.getDownloadURL()
.then((url) => {
dispatch(addDocumentSuccess());
resolve(url);
});
}
);
});
};
Then in your onsubmit:
this.props.dispatch(addDocument(values, 'Jobs')).then((resp) => {
let documentUrl = resp;
firestore.collection('Jobs').add({
...project,
postedby:'Employer1',
Documents:documentUrl
}).then(()=>{
});

Resources