Reputation: 79
I am on working on a simple react web app that adds and retrieves files to/from IPFS.
When a file is added to IPFS, the name of the added file (i.e Medical file) as well as a "View file " button will appear on the page.
When the button is clicked, the file should be viewed using the "Document" component in react-pdf [https://www.npmjs.com/package/react-pdf | (Document file="..." . the file can be a URL, base64 content, Uint8Array, and more.)
Adding and retrieving files from IPFS work successfully. The retrieved file from IPFS in the form of Uint8Array is passed to the Document component inside the Main.js component to view the pdf file. However, the page failed to load PDF file. Also, I got an error:
Error: "Setting up fake worker failed: "window.pdfjsWorker is undefined"."
Please note that I have the following in the Main.js:
<Document file={{ data: pdfFile.content }}></Document>
App.js
import React, { Component } from "react";
import Web3 from "web3";
import "./App.css";
import Meme from "../abis/Meme";
import Addressbar from "./Addressbar";
import Main from "./Main";
class App extends Component {
async componentDidMount() {
await this.getWeb3Provider();
this.loadBlockchainData();
}
async getWeb3Provider() {
if (window.ethereum) {
window.web3 = new Web3(window.ethereum);
await window.ethereum.enable();
} else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider);
} else {
window.alert(
"Non-Ethereum browser detected. You should consider trying MetaMask!"
);
}
}
async loadBlockchainData() {
const web3 = window.web3;
// Load the account
const accounts = await web3.eth.getAccounts();
this.setState({ account: accounts[0] });
/*Get an instance of the deployed smart contract in Javascript to allow us to
call the functions of the smart contract*/
const networkId = await web3.eth.net.getId();
const networkData = Meme.networks[networkId];
if (networkData) {
const contract = new web3.eth.Contract(Meme.abi, networkData.address);
this.setState({ contract: contract });
// Fetching the file hashes from the smart contract
const count = await contract.methods.getfileHashesCount().call();
for (var i = 0; i < count; i++) {
const fileHash = await contract.methods.fileHashes(i).call();
this.setState({
fileHashes: [...this.state.fileHashes, fileHash]
});
}
} else {
window.alert("The contract is not found in your blockchain.");
}
}
constructor(props) {
super(props);
// Setting the account (1)
this.state = {
account: null,
fileHashes: [],
contract: null,
buffer: null
};
}
// Setting the buffer
setBuffer = data => {
this.setState({ buffer: data });
console.log("buffer data", this.state.buffer);
};
// Storing/adding the file hash on the blockchain
storeFileHash = hash => {
this.state.contract.methods
.addFileHash(hash)
.send({ from: this.state.account })
.then(r => {
return this.setState({ fileHashes: [...this.state.fileHashes, hash] });
});
//console.log("fileHashes", this.state.fileHashes);
};
render() {
return (
<div className="container">
<div>
<Addressbar account={this.state.account} />
</div>
<div>
<Main
fileHashes={this.state.fileHashes}
setBuffer={this.setBuffer}
buffer={this.state.buffer}
storeFileHash={this.storeFileHash}
/>
</div>
</div>
);
}
}
export default App;
Main.Js
import React, { Component } from "react";
import { Document, Page } from "react-pdf";
//import { Document } from "react-pdf/dist/entry.webpack";
//import { pdfjs } from "react-pdf";
//pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
//Required module(s)
const ipfsAPI = require("ipfs-api");
/*** Connceting to the ipfs network via infura gateway ***/
const ipfs = ipfsAPI("ipfs.infura.io", "5001", { protocol: "https" });
export class Main extends Component {
/*
state = {
pdfFiles: []
};
*/
state = {
pdfFiles: [],
text: "Hi World"
};
captureFile = event => {
event.preventDefault();
// Fetch the file chosen
const file = event.target.files[0];
console.log("The original file : ", file);
// Convert the file to a buffer
const reader = new window.FileReader();
reader.readAsArrayBuffer(file);
reader.onloadend = () => {
const arr = new Uint8Array(reader.result);
console.log("Uint8Array ouptut", arr);
console.log("reader.result output : ", reader.result);
console.log("Buffer(reader.result) output : ", Buffer(reader.result));
this.props.setBuffer(Buffer(reader.result));
};
};
onSubmit = event => {
event.preventDefault();
console.log("Submitting file to IPFS......");
console.log(this.props.buffer);
// Adding the file to IPFS
ipfs.files.add(this.props.buffer, (error, result) => {
if (error) {
console.log(error);
return;
}
console.log("File added succesfully");
console.log("IPFS result", result);
// Storing the file hash on the blockchain
this.props.storeFileHash(result[0].hash);
});
}; // end of sumbit event
onClick = event => {
event.preventDefault();
console.log("Button clicked......");
console.log(this.state.text);
/*** Getting the uploaded file via hash code ***/
const that = this; // NECESSARY
ipfs.files.cat(event.target.name, function(err, file) {
console.log("Getting files from IPFS ....... ");
//console.log("File path ", file.path);
//console.log("File hash", file.hash);
console.log("The Unit8Array file content: ", file);
const unit8Array_ = {
content: file
};
console.log("Printing (1)......", unit8Array_.content);
that.setState({ text: "Hi America" });
console.log(that.state.text);
that.setState({ pdfFiles: [...that.state.pdfFiles, unit8Array_] });
});
}; // end of sumbit event
render() {
return (
<div className="container-fluid mt-5">
<div className="row">
<main>
<div>
<h3>Medical Files-Upload: </h3>
<form onSubmit={this.onSubmit}>
<div>
<label className="mr-2">Upload your medical document:</label>
<input type="file" onChange={this.captureFile} />
<input type="submit" />
</div>
</form>
</div>
<hr></hr>
<div>
<h5>PDF Document: {this.state.text} </h5>
{this.state.pdfFiles.map((pdfFile, key) => {
return (
<div>
<p>{console.log("Printing (2)....", pdfFile.content)}</p>
<Document file={{ data: pdfFile.content }}></Document>
</div>
);
})}
</div>
<hr></hr>
<div>
<h3>Medical Files-View: </h3>
{this.props.fileHashes.map((fileHash, key) => {
return (
<p>
{" "}
Medical File{" "}
<button name={fileHash} onClick={this.onClick}>
View File
</button>{" "}
</p>
);
})}
</div>
</main>
</div>
</div>
);
}
}
export default Main;
Addresbar.js
import React, { Component } from "react";
class Addressbar extends Component {
render() {
return (
<nav className="navbar navbar-dark fixed-top bg-dark flex-md-nowrap p-0 shadow">
<ul className="navbar-nav px-3">
<li className="nav-item text-nowrap d-none d-sm-none d-sm-block">
<small className="text-white">
<span id="account">
{"Your account address: " + this.props.account}
</span>
</small>
</li>
</ul>
</nav>
);
}
}
export default Addressbar;
Upvotes: 5
Views: 17530
Reputation: 900
If you are using create-react-app biolerplate:
change your code to:
import { Document, Page, pdfjs } from "react-pdf";
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
It will work.
Thanks @frankenapps for suggesting a good practice.
Also, Refer to this for create-react-app
Upvotes: 9