ipfs/src/components/Add.tsx

106 lines
2.8 KiB
TypeScript

import React, { useState, useEffect } from 'react'
import { ipfsNodeUri, ipfsGateway } from '../../site.config'
import Dropzone from './Dropzone'
import styles from './Add.module.css'
import Spinner from './Spinner'
import useIpfsApi, { IpfsConfig } from '../hooks/use-ipfs-api'
export function formatBytes(a: number, b: number) {
if (a === 0) return '0 Bytes'
const c = 1024
const d = b || 2
const e = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const f = Math.floor(Math.log(a) / Math.log(c))
return parseFloat((a / Math.pow(c, f)).toFixed(d)) + ' ' + e[f]
}
const { hostname, port, protocol } = new URL(ipfsNodeUri)
const ipfsConfig: IpfsConfig = {
protocol: protocol.replace(':', ''),
host: hostname,
port: port || '443'
}
async function addToIpfs(
files: File[],
setFileSizeReceived: (size: string) => void
) {
const { ipfs } = useIpfsApi(ipfsConfig)
const file = [...files][0]
const fileDetails = { path: file.name, content: file }
const response = await ipfs.add(fileDetails, {
wrapWithDirectory: true,
progress: (length: number) => setFileSizeReceived(formatBytes(length, 0))
})
// CID of wrapping directory is returned last
const cid = response[response.length - 1].hash
return cid
}
export default function Add() {
const { isIpfsReady, ipfsError } = useIpfsApi(ipfsConfig)
const [fileHash, setFileHash] = useState()
const [loading, setLoading] = useState(false)
const [message, setMessage] = useState()
const [error, setError] = useState()
const [fileSize, setFileSize] = useState()
const [fileSizeReceived, setFileSizeReceived] = useState('')
useEffect(() => {
setMessage(
`Adding to IPFS<br />
<small>${fileSizeReceived || 0}/${fileSize}</small><br />`
)
}, [fileSize, fileSizeReceived])
async function handleOnDrop(acceptedFiles: File[]) {
if (!acceptedFiles[0]) return
setLoading(true)
setError(null)
const totalSize = formatBytes(acceptedFiles[0].size, 0)
setFileSize(totalSize)
try {
const cid = await addToIpfs(acceptedFiles, setFileSizeReceived)
if (!cid) return
setFileHash(cid)
setLoading(false)
} catch (error) {
setError(`Adding to IPFS failed: ${error.message}`)
return null
}
}
return (
<div className={styles.add}>
{loading ? (
<Spinner message={message} />
) : fileHash ? (
<a
target="_blank"
rel="noopener noreferrer"
href={`${ipfsGateway}/ipfs/${fileHash}`}
>
ipfs://{fileHash}
</a>
) : (
<>
<Dropzone
multiple={false}
handleOnDrop={handleOnDrop}
disabled={!isIpfsReady}
/>
{(error || ipfsError) && (
<div className={styles.error}>{error || ipfsError}</div>
)}
</>
)}
</div>
)
}