Moralis react: saveFile() on IPFS

Hi Guys,

I am trying to use saveFile to save a file (uploaded from the react front end) into IPFS.

I am getting the below messages from the console based on my console.log calls, but I can not get the IPFS hash so there must be an issue somewhere.

File {name: "image.png", lastModified: 1627135297645, lastModifiedDate: Sun Jul 25 2021 00:01:37..., webkitRelativePath: "", size: 160822, …}

Promise {<fulfilled>: undefined}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined

Could you please advise what I am doing incorrectly. See below the code of my react component which imports Moralis:

import React, { useState } from 'react'
import './style.css'
import { Button, Form, Modal } from 'react-bootstrap'
import { useMoralis, useMoralisFile } from 'react-moralis'
import { Moralis } from 'moralis'

const UploadDataModal = () => {
  const [file, setFile] = useState('')
  const [showModal, setShowModal] = useState(false)
  const handleClose = () => setShowModal(false)
  const handleShow = () => setShowModal(true)

  const {saveFile, moralisFile} = useMoralisFile()

  const saveFileIPFS = (f) => {
    console.log(f)
    const fileIpfs = saveFile(f.name, file, {saveIPFS: true})
    console.log(fileIpfs)
  }

  const handleFinal = () => {
    saveFileIPFS(file[0])
    handleClose()
  }

  return (
    <>
      <Button variant="warning" onClick={handleShow}>
        Upload File
      </Button>
      <Modal show={showModal} onHide={handleClose}>
        <Modal.Header closeButton>
          <Modal.Title>
            Upload file
          </Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <Form>
            <Form.Group className="mb-3" controlId="formBasicEmail">
              <Form.Label>Upload the file</Form.Label>
              <Form.Control
                type="file"
                placeholder="Upload the file"
                onChange={(e) => setFile(e.target.files)}
              />
             </Form.Group>
          </Form>
        </Modal.Body>
        <Modal.Footer>
          <Button variant="secondary" onClick={handleClose}>
            Close
          </Button>
          <Button variant="primary" onClick={handleFinal}>
            Add
          </Button>
        </Modal.Footer>
      </Modal>
    </>
  )
  
}

export default UploadDataModal
1 Like

Hi @Tristan3000,

You should make the save call a async await call. So your function would look like this –

const saveFileIPFS = async (f) => {
    console.log(f)
    const fileIpfs = await saveFile(f.name, file, {saveIPFS: true})
    console.log(fileIpfs)
  }

This should solve the issue.

Happy building ! :man_mechanic:

2 Likes

I used this code and it worked perfectly –

import React, { useState } from 'react'
import './style.css'
import { Button, Form, Modal } from 'react-bootstrap'
import { useMoralis, useMoralisFile } from 'react-moralis'
import { Moralis } from 'moralis'

const UploadDataModal = () => {
  const [file, setFile] = useState('')
  const [showModal, setShowModal] = useState(false)
  const handleClose = () => setShowModal(false)
  const handleShow = () => setShowModal(true)

  const {saveFile, moralisFile} = useMoralisFile()

  const saveFileIPFS = async (f) => {
    console.log("FILE",f)
    const fileIpfs = await saveFile(f.name, file, {saveIPFS: true})
    console.log(fileIpfs)
  }

  const handleFinal = () => {
    saveFileIPFS(file)
    handleClose()
  }

  return (
    <>
      <Button variant="warning" onClick={handleShow}>
        Upload File
      </Button>
      <Modal show={showModal} onHide={handleClose}>
        <Modal.Header closeButton>
          <Modal.Title>
            Upload file
          </Modal.Title>
        </Modal.Header>
        <Modal.Body>
          <Form>
            <Form.Group className="mb-3" controlId="formBasicEmail">
              <Form.Label>Upload the file</Form.Label>
              <Form.Control
                type="file"
                placeholder="Upload the file"
                onChange={(e) => setFile(e.target.files[0])}
              />
             </Form.Group>
          </Form>
        </Modal.Body>
        <Modal.Footer>
          <Button variant="secondary" onClick={handleClose}>
            Close
          </Button>
          <Button variant="primary" onClick={handleFinal}>
            Add
          </Button>
        </Modal.Footer>
      </Modal>
    </>
  )
  
}

export default UploadDataModal
2 Likes

Thank you @malik that works perfectly :slight_smile:

1 Like

I use this code and have a problem with “error” variable and moralisFile seems to be empty so I use the return data of the saveFile() function…

Also: using chakra-ui (inspired by the “React & Moralis” videos of @Erno) but for “input type=“file”” I had to use the react-bootstrap (as above) (reason here)

As Fileupload.js:

import { Box, Input, Text, Stack, Button, Checkbox, Img, Link } from "@chakra-ui/react";
import { ExternalLinkIcon } from '@chakra-ui/icons';
import { Form } from 'react-bootstrap';
import { useState } from "react";
import { useMoralis, useMoralisFile } from "react-moralis";
import { MessageBox } from "./Message";

export const FileUpload = () => {
    const { isAuthenticated } = useMoralis();
    const { error, isUploading, moralisFile, saveFile} = useMoralisFile();

    const [fileData, setFileData] = useState(); // name, size, type, lastModified, webkitRelativePath
    const [filename, setFilename] = useState(''); // string
    const [SaveAsIPFS, setSaveAsIPFS] = useState(true); // boolean
    const [uploadResultMessage, setUploadResultMessage] = useState(''); // string
    const [uploadError, setUploadError] = useState(false); // string
    const [fileUrl, setFileUrl] = useState(''); // string

    const doSaveFile = async (fdata, fname, asIPFS) => {
        if (isAuthenticated && fdata.size > 0) {
            console.log('fdata', fdata);
            const name = (fname !== "") ? fname : fdata.name;
            setFilename(name);
            console.log('filename='+name);
            const fileResult = await saveFile(name, fdata, {saveIPFS: asIPFS});
            console.log('fileResult', fileResult);
            console.log('moralisFile=', moralisFile);
            // => moralisFile: ipfs, hash, metadata, name, tags, url
            setFileUrl(fileResult._url);
            setUploadError(fileResult._url === "");
            console.log('error', error);
            setUploadResultMessage(error ? error.message : `Succesful upload of ${name}`);
        } else {
            setFileUrl("");
            setUploadError(true);
            setUploadResultMessage(isAuthenticated ? "Not authenticated!" : "No file to save!");
        }
    }

    const handleFile = () => {
        doSaveFile(fileData, filename, SaveAsIPFS);
    }

    const FileUrlText = () => {
        return fileUrl;
    }

    const FileList = () => {
        return "ToDo";
    }

    return <Box>
        <Stack spacing={3}>
            {uploadResultMessage && <MessageBox title="File handling" message={uploadResultMessage} error={uploadError} />}
            <Box><Form><Form.Group className="mb-3" controlId="formFile">
                <Form.Label>Select a file * </Form.Label>
                <Form.Control type="file" placeholder="Select a file" onChange={event => setFileData(event.target.files[0])} />
            </Form.Group></Form></Box>
            <Box><Text>Filename:</Text> <Input value={filename} onChange={event => setFilename(event.currentTarget.value)}/></Box>
            <Box><Text>IPFS:</Text> <Checkbox onChange={event => setSaveAsIPFS(event.target.checked)}>Save as IPFS</Checkbox></Box>
            <Button onClick={handleFile} isLoading={isUploading}>Save file</Button>
            {fileUrl !== "" && <Box>
                <Link to={fileUrl} isExternal >File URL <ExternalLinkIcon mx="2px" /></Link>: <FileUrlText />
                <Img src={fileUrl} alt={filename} />
            </Box>}
        </Stack>
        <Stack spacing={6}>
            <Heading>Available files</Heading>
            <FileList />
        </Stack>
    </Box>
}

with Message.js:

import { Alert, AlertIcon, Box, AlertTitle, AlertDescription, CloseButton } from "@chakra-ui/react";

export const MessageBox = ({title, message, error}) => {

    return (<Alert status={error ? "error" : "message"}>
        <AlertIcon />
        <Box flex="1">
            <AlertTitle>{title}</AlertTitle>
            <AlertDescription display="block">{message}</AlertDescription>
        </Box>
        <CloseButton position="absolute" right="8px" top="8px" />
    </Alert>
    );
}

After submit I get:

How to use ‘error’ of useMoralisFile() ?

Why is moralisFile null ?

Is there a method to list all urls (etc) of saved files? Or do I need to save it seperately into a table?
Or: the only method to remember / get a file is to record myself the fileHash and name as reference?

Hey @CasNWK

Take a look at:

If it will not solve your problem please share your github repo :man_mechanic: