mirror of
https://github.com/oceanprotocol/commons.git
synced 2023-03-15 18:03:00 +01:00
more user feedback, refactoring
This commit is contained in:
parent
1c59d49d5d
commit
3b889725f1
@ -4,13 +4,15 @@ import Ipfs from 'ipfs'
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
let ipfs: any = null
|
let ipfs: any = null
|
||||||
let ipfsMessage: string | null = null
|
let ipfsMessage = ''
|
||||||
|
|
||||||
export default function useIpfs() {
|
export default function useIpfs() {
|
||||||
const [isIpfsReady, setIpfsReady] = useState(Boolean(ipfs))
|
const [isIpfsReady, setIpfsReady] = useState(Boolean(ipfs))
|
||||||
const [ipfsInitError, setIpfsInitError] = useState(null)
|
const [ipfsInitError, setIpfsInitError] = useState(null)
|
||||||
|
|
||||||
async function startIpfs() {
|
async function startIpfs() {
|
||||||
|
ipfsMessage = 'Starting IPFS...'
|
||||||
|
|
||||||
if (ipfs) {
|
if (ipfs) {
|
||||||
console.log('IPFS already started')
|
console.log('IPFS already started')
|
||||||
// } else if (window.ipfs && window.ipfs.enable) {
|
// } else if (window.ipfs && window.ipfs.enable) {
|
||||||
@ -18,7 +20,7 @@ export default function useIpfs() {
|
|||||||
// ipfs = await window.ipfs.enable()
|
// ipfs = await window.ipfs.enable()
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const message = 'IPFS Started'
|
const message = 'IPFS started'
|
||||||
console.time(message)
|
console.time(message)
|
||||||
ipfs = await Ipfs.create()
|
ipfs = await Ipfs.create()
|
||||||
console.timeEnd(message)
|
console.timeEnd(message)
|
||||||
@ -40,12 +42,13 @@ export default function useIpfs() {
|
|||||||
// just like componentDidUnmount()
|
// just like componentDidUnmount()
|
||||||
return function cleanup() {
|
return function cleanup() {
|
||||||
if (ipfs && ipfs.stop) {
|
if (ipfs && ipfs.stop) {
|
||||||
console.time('IPFS Stopped')
|
console.time('IPFS stopped')
|
||||||
ipfs.stop()
|
ipfs.stop()
|
||||||
setIpfsReady(false)
|
setIpfsReady(false)
|
||||||
ipfs = null
|
ipfs = null
|
||||||
ipfsMessage = null
|
ipfsMessage = ''
|
||||||
console.timeEnd('IPFS Stopped')
|
setIpfsInitError(null)
|
||||||
|
console.timeEnd('IPFS stopped')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
@ -1,5 +1,52 @@
|
|||||||
@import '../../../styles/variables';
|
@import '../../../styles/variables';
|
||||||
|
|
||||||
.ipfsForm {
|
.ipfsForm {
|
||||||
margin-top: $spacer;
|
margin-top: $spacer / 2;
|
||||||
|
border: 1px solid $brand-grey-lighter;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
padding: $spacer / 2;
|
||||||
|
background: $body-background;
|
||||||
|
|
||||||
|
input {
|
||||||
|
display: block;
|
||||||
|
width: fit-content;
|
||||||
|
cursor: pointer;
|
||||||
|
border: .1rem solid $brand-grey-lighter;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
padding: $spacer / 2 $spacer / 2;
|
||||||
|
margin-top: $spacer / 2;
|
||||||
|
background: $brand-white;
|
||||||
|
transition: border .2s ease-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: $brand-grey-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
font-size: $font-size-small;
|
||||||
|
margin-top: $spacer / 2;
|
||||||
|
color: $brand-grey-light;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
width: .5rem;
|
||||||
|
height: .5rem;
|
||||||
|
display: inline-block;
|
||||||
|
background: $green;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: $spacer / 4;
|
||||||
|
margin-bottom: .05rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
composes: message;
|
||||||
|
color: $red;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
border-radius: 0;
|
||||||
|
background: $red;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,66 @@
|
|||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
import React from 'react'
|
import React, { useState } from 'react'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import useIpfs from '../../../hooks/use-ipfs'
|
import useIpfs from '../../../hooks/use-ipfs'
|
||||||
|
import Label from '../../../components/atoms/Form/Label'
|
||||||
|
import Spinner from '../../../components/atoms/Spinner'
|
||||||
import styles from './Ipfs.module.scss'
|
import styles from './Ipfs.module.scss'
|
||||||
|
|
||||||
async function pingUrl(url: string) {
|
async function pingUrl(url: string) {
|
||||||
try {
|
try {
|
||||||
const response = await axios(url)
|
const response = await axios(url)
|
||||||
if (response.status !== 200) console.error(`Could not find ${url}`)
|
if (response.status !== 200) console.error(`Not found: ${url}`)
|
||||||
|
|
||||||
console.log(`File found under ${url}`)
|
console.log(`File found: ${url}`)
|
||||||
return
|
return
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error.message)
|
console.error(error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Ipfs({ addItem }: { addItem(url: string): void }) {
|
function formatBytes(a: number, b: number) {
|
||||||
const { ipfs, ipfsInitError, ipfsMessage } = useIpfs()
|
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]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Ipfs({ addFile }: { addFile(url: string): void }) {
|
||||||
|
const { ipfs, isIpfsReady, ipfsInitError, ipfsMessage } = useIpfs()
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [message, setMessage] = useState('')
|
||||||
|
|
||||||
async function saveToIpfs(buffer: Buffer) {
|
async function saveToIpfs(buffer: Buffer) {
|
||||||
|
setLoading(true)
|
||||||
|
setMessage('Adding to local IPFS node<br />')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await ipfs.add(buffer)
|
const response = await ipfs.add(buffer, {
|
||||||
|
progress: (length: number) => {
|
||||||
|
setMessage(
|
||||||
|
`Adding to local IPFS node<br />
|
||||||
|
${formatBytes(length, 0)}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const cid = response[0].hash
|
const cid = response[0].hash
|
||||||
console.log(`File added: ${cid}`)
|
console.log(`File added: ${cid}`)
|
||||||
|
|
||||||
// ping url to make it globally available
|
// ping url to make it globally available
|
||||||
const url = `https://ipfs.io/ipfs/${cid}`
|
const url = `https://ipfs.io/ipfs/${cid}`
|
||||||
|
setMessage('Checking global IPFS URL')
|
||||||
await pingUrl(url)
|
await pingUrl(url)
|
||||||
|
|
||||||
// add IPFS url to file.url
|
// add IPFS url to file.url
|
||||||
addItem(url)
|
addFile(url)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error.message)
|
console.error(error.message)
|
||||||
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,12 +77,26 @@ export default function Ipfs({ addItem }: { addItem(url: string): void }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.ipfsForm}>
|
<div className={styles.ipfsForm}>
|
||||||
|
<Label htmlFor="fileUpload" required>
|
||||||
|
Add File To IPFS
|
||||||
|
</Label>
|
||||||
|
{loading ? (
|
||||||
|
<Spinner message={message} />
|
||||||
|
) : (
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
|
name="fileUpload"
|
||||||
|
id="fileUpload"
|
||||||
onChange={e => handleCaptureFile(e.target.files)}
|
onChange={e => handleCaptureFile(e.target.files)}
|
||||||
|
disabled={!isIpfsReady}
|
||||||
/>
|
/>
|
||||||
{ipfsMessage && <div>{ipfsMessage}</div>}
|
)}
|
||||||
{ipfsInitError && <div>{ipfsInitError}</div>}
|
{ipfsMessage !== '' && (
|
||||||
|
<div className={styles.message}>{ipfsMessage}</div>
|
||||||
|
)}
|
||||||
|
{ipfsInitError && (
|
||||||
|
<div className={styles.error}>{ipfsInitError}</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
.itemForm {
|
.itemForm {
|
||||||
margin-top: $spacer / 2;
|
margin-top: $spacer / 2;
|
||||||
padding-left: $spacer / 2;
|
border: 1px solid $brand-grey-lighter;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
padding: $spacer / 2;
|
||||||
|
background: $body-background;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
margin-top: -($spacer * 2);
|
margin-top: -($spacer * 2);
|
||||||
|
@ -2,10 +2,10 @@ import React from 'react'
|
|||||||
import { render, fireEvent } from '@testing-library/react'
|
import { render, fireEvent } from '@testing-library/react'
|
||||||
import ItemForm from './ItemForm'
|
import ItemForm from './ItemForm'
|
||||||
|
|
||||||
const addItem = jest.fn()
|
const addFile = jest.fn()
|
||||||
|
|
||||||
const setup = () => {
|
const setup = () => {
|
||||||
const utils = render(<ItemForm placeholder="Hello" addItem={addItem} />)
|
const utils = render(<ItemForm placeholder="Hello" addFile={addFile} />)
|
||||||
const input = utils.getByPlaceholderText('Hello')
|
const input = utils.getByPlaceholderText('Hello')
|
||||||
const button = utils.getByText('Add File')
|
const button = utils.getByText('Add File')
|
||||||
const { container } = utils
|
const { container } = utils
|
||||||
@ -23,17 +23,17 @@ describe('ItemForm', () => {
|
|||||||
expect(container.firstChild).toBeInTheDocument()
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('fires addItem', async () => {
|
it('fires addFile', async () => {
|
||||||
const { input, button } = setup()
|
const { input, button } = setup()
|
||||||
|
|
||||||
fireEvent.change(input, {
|
fireEvent.change(input, {
|
||||||
target: { value: 'https://hello.com' }
|
target: { value: 'https://hello.com' }
|
||||||
})
|
})
|
||||||
fireEvent.click(button)
|
fireEvent.click(button)
|
||||||
expect(addItem).toHaveBeenCalled()
|
expect(addFile).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not fire addItem when no url present', () => {
|
it('does not fire addFile when no url present', () => {
|
||||||
const { input, button, container } = setup()
|
const { input, button, container } = setup()
|
||||||
|
|
||||||
// empty url
|
// empty url
|
||||||
|
@ -5,7 +5,7 @@ import Button from '../../../components/atoms/Button'
|
|||||||
import styles from './ItemForm.module.scss'
|
import styles from './ItemForm.module.scss'
|
||||||
|
|
||||||
interface ItemFormProps {
|
interface ItemFormProps {
|
||||||
addItem(url: string): void
|
addFile(url: string): void
|
||||||
placeholder: string
|
placeholder: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ export default class ItemForm extends PureComponent<
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.addItem(url)
|
this.props.addFile(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
private onChangeUrl = (e: React.FormEvent<HTMLInputElement>) => {
|
private onChangeUrl = (e: React.FormEvent<HTMLInputElement>) => {
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
.newItems {
|
.newItems {
|
||||||
margin-top: $spacer / 2;
|
margin-top: $spacer / 2;
|
||||||
|
|
||||||
|
> button {
|
||||||
|
margin-right: $spacer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.itemsList {
|
.itemsList {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { render, fireEvent, waitForElement, act } from '@testing-library/react'
|
import { render, fireEvent, waitForElement } from '@testing-library/react'
|
||||||
import mockAxios from 'jest-mock-axios'
|
import mockAxios from 'jest-mock-axios'
|
||||||
import Files from '.'
|
import Files from '.'
|
||||||
|
|
||||||
@ -56,21 +56,20 @@ describe('Files', () => {
|
|||||||
const { container, getByText } = renderComponent()
|
const { container, getByText } = renderComponent()
|
||||||
|
|
||||||
// open
|
// open
|
||||||
fireEvent.click(getByText('+ Add a file URL'))
|
fireEvent.click(getByText('+ From public URL'))
|
||||||
await waitForElement(() => getByText('- Cancel'))
|
await waitForElement(() => getByText('- Cancel'))
|
||||||
expect(container.querySelector('.itemForm')).toBeInTheDocument()
|
expect(container.querySelector('.itemForm')).toBeInTheDocument()
|
||||||
|
|
||||||
// close
|
// close
|
||||||
fireEvent.click(getByText('- Cancel'))
|
fireEvent.click(getByText('- Cancel'))
|
||||||
await waitForElement(() => getByText('+ Add a file URL'))
|
await waitForElement(() => getByText('+ From public URL'))
|
||||||
expect(container.querySelector('.grow-exit')).toBeInTheDocument()
|
expect(container.querySelector('.itemForm')).not.toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('new IPFS file form can be opened and closed', async () => {
|
it('new IPFS file form can be opened and closed', async () => {
|
||||||
const { container, getByText } = renderComponent()
|
const { container, getByText } = renderComponent()
|
||||||
|
|
||||||
// open
|
// open
|
||||||
act(async () => {
|
|
||||||
fireEvent.click(getByText('+ Add to IPFS'))
|
fireEvent.click(getByText('+ Add to IPFS'))
|
||||||
await waitForElement(() => getByText('- Cancel'))
|
await waitForElement(() => getByText('- Cancel'))
|
||||||
expect(container.querySelector('.ipfsForm')).toBeInTheDocument()
|
expect(container.querySelector('.ipfsForm')).toBeInTheDocument()
|
||||||
@ -78,8 +77,7 @@ describe('Files', () => {
|
|||||||
// close
|
// close
|
||||||
fireEvent.click(getByText('- Cancel'))
|
fireEvent.click(getByText('- Cancel'))
|
||||||
await waitForElement(() => getByText('+ Add to IPFS'))
|
await waitForElement(() => getByText('+ Add to IPFS'))
|
||||||
expect(container.querySelector('.grow-exit')).toBeInTheDocument()
|
expect(container.querySelector('.ipfsForm')).not.toBeInTheDocument()
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('item can be removed', async () => {
|
it('item can be removed', async () => {
|
||||||
@ -92,7 +90,7 @@ describe('Files', () => {
|
|||||||
it('item can be added', async () => {
|
it('item can be added', async () => {
|
||||||
const { getByText, getByPlaceholderText } = renderComponent()
|
const { getByText, getByPlaceholderText } = renderComponent()
|
||||||
|
|
||||||
fireEvent.click(getByText('+ Add a file URL'))
|
fireEvent.click(getByText('+ From public URL'))
|
||||||
await waitForElement(() => getByText('- Cancel'))
|
await waitForElement(() => getByText('- Cancel'))
|
||||||
fireEvent.change(getByPlaceholderText('Hello'), {
|
fireEvent.change(getByPlaceholderText('Hello'), {
|
||||||
target: { value: 'https://hello.com' }
|
target: { value: 'https://hello.com' }
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { FormEvent, PureComponent, ChangeEvent } from 'react'
|
import React, { FormEvent, PureComponent, ChangeEvent } from 'react'
|
||||||
import { CSSTransition, TransitionGroup } from 'react-transition-group'
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { Logger } from '@oceanprotocol/squid'
|
import { Logger } from '@oceanprotocol/squid'
|
||||||
import Button from '../../../components/atoms/Button'
|
import Button from '../../../components/atoms/Button'
|
||||||
@ -58,15 +57,21 @@ export default class Files extends PureComponent<FilesProps, FilesStates> {
|
|||||||
|
|
||||||
private toggleForm = (e: Event) => {
|
private toggleForm = (e: Event) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.setState({ isFormShown: !this.state.isFormShown })
|
this.setState({
|
||||||
|
isFormShown: !this.state.isFormShown,
|
||||||
|
isIpfsFormShown: false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private toggleIpfsForm = (e: Event) => {
|
private toggleIpfsForm = (e: Event) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.setState({ isIpfsFormShown: !this.state.isIpfsFormShown })
|
this.setState({
|
||||||
|
isIpfsFormShown: !this.state.isIpfsFormShown,
|
||||||
|
isFormShown: false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private addItem = async (url: string) => {
|
private async getFile(url: string) {
|
||||||
const file: File = {
|
const file: File = {
|
||||||
url,
|
url,
|
||||||
contentType: '',
|
contentType: '',
|
||||||
@ -83,15 +88,34 @@ export default class Files extends PureComponent<FilesProps, FilesStates> {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const { contentLength, contentType, found } = response.data.result
|
const { contentLength, contentType, found } = response.data.result
|
||||||
|
|
||||||
file.contentLength = contentLength
|
file.contentLength = contentLength
|
||||||
file.contentType = contentType
|
file.contentType = contentType
|
||||||
file.compression = cleanupContentType(contentType)
|
file.compression = cleanupContentType(contentType)
|
||||||
file.found = found
|
file.found = found
|
||||||
|
|
||||||
|
return file
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
!axios.isCancel(error) && Logger.error(error.message)
|
!axios.isCancel(error) && Logger.error(error.message)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private addFile = async (url: string) => {
|
||||||
|
// check for duplicate urls
|
||||||
|
const duplicateFiles = this.props.files.filter(props =>
|
||||||
|
url.includes(props.url)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (duplicateFiles.length > 0) {
|
||||||
|
return this.setState({
|
||||||
|
isFormShown: false,
|
||||||
|
isIpfsFormShown: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const file: File | undefined = await this.getFile(url)
|
||||||
|
file && this.props.files.push(file)
|
||||||
|
|
||||||
this.props.files.push(file)
|
|
||||||
const event = {
|
const event = {
|
||||||
currentTarget: {
|
currentTarget: {
|
||||||
name: 'files',
|
name: 'files',
|
||||||
@ -99,13 +123,14 @@ export default class Files extends PureComponent<FilesProps, FilesStates> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.props.onChange(event as any)
|
this.props.onChange(event as any)
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isFormShown: !this.state.isFormShown,
|
isFormShown: false,
|
||||||
isIpfsFormShown: !this.state.isIpfsFormShown
|
isIpfsFormShown: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeItem = (index: number) => {
|
private removeFile = (index: number) => {
|
||||||
this.props.files.splice(index, 1)
|
this.props.files.splice(index, 1)
|
||||||
const event = {
|
const event = {
|
||||||
currentTarget: {
|
currentTarget: {
|
||||||
@ -136,57 +161,33 @@ export default class Files extends PureComponent<FilesProps, FilesStates> {
|
|||||||
|
|
||||||
<div className={styles.newItems}>
|
<div className={styles.newItems}>
|
||||||
{files.length > 0 && (
|
{files.length > 0 && (
|
||||||
<TransitionGroup
|
<ul className={styles.itemsList}>
|
||||||
component="ul"
|
|
||||||
className={styles.itemsList}
|
|
||||||
>
|
|
||||||
{files.map((item: any, index: number) => (
|
{files.map((item: any, index: number) => (
|
||||||
<CSSTransition
|
|
||||||
key={index}
|
|
||||||
timeout={400}
|
|
||||||
classNames="fade"
|
|
||||||
>
|
|
||||||
<Item
|
<Item
|
||||||
|
key={item.url}
|
||||||
item={item}
|
item={item}
|
||||||
removeItem={() =>
|
removeItem={() => this.removeFile(index)}
|
||||||
this.removeItem(index)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</CSSTransition>
|
|
||||||
))}
|
))}
|
||||||
</TransitionGroup>
|
</ul>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button link onClick={this.toggleForm}>
|
<Button link onClick={this.toggleForm}>
|
||||||
{isFormShown ? '- Cancel' : '+ Add a file URL'}
|
{isFormShown ? '- Cancel' : '+ From public URL'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button link onClick={this.toggleIpfsForm}>
|
<Button link onClick={this.toggleIpfsForm}>
|
||||||
{isIpfsFormShown ? '- Cancel' : '+ Add to IPFS'}
|
{isIpfsFormShown ? '- Cancel' : '+ Add to IPFS'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<CSSTransition
|
{isFormShown && (
|
||||||
classNames="grow"
|
|
||||||
in={isFormShown}
|
|
||||||
timeout={200}
|
|
||||||
unmountOnExit
|
|
||||||
onExit={() => this.setState({ isFormShown: false })}
|
|
||||||
>
|
|
||||||
<ItemForm
|
<ItemForm
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
addItem={this.addItem}
|
addFile={this.addFile}
|
||||||
/>
|
/>
|
||||||
</CSSTransition>
|
)}
|
||||||
|
|
||||||
<CSSTransition
|
{isIpfsFormShown && <Ipfs addFile={this.addFile} />}
|
||||||
classNames="grow"
|
|
||||||
in={isIpfsFormShown}
|
|
||||||
timeout={200}
|
|
||||||
unmountOnExit
|
|
||||||
onExit={() => this.setState({ isIpfsFormShown: false })}
|
|
||||||
>
|
|
||||||
<Ipfs addItem={this.addItem} />
|
|
||||||
</CSSTransition>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user