import web3 from 'Embark/web3' import React, { useMemo } from 'react' import { Link } from 'react-router-dom' import Typography from '@material-ui/core/Typography' import Button from '@material-ui/core/Button' import withObservables from '@nozbe/with-observables' import { Q } from '@nozbe/watermelondb' import { withDatabase } from '@nozbe/watermelondb/DatabaseProvider' import CardMedia from '@material-ui/core/CardMedia' import LinearProgress from '@material-ui/core/LinearProgress' import Loading from '../base/Loading' import Avatar from '@material-ui/core/Avatar' import ReactPlayer from 'react-player' import { uniqBy, length } from 'ramda' import { withStyles } from '@material-ui/core/styles' import PropTypes from 'prop-types' import { toEther } from '../../utils/conversions' import { getTokenLabel } from '../../utils/currencies' import { timeSinceBlock } from '../../utils/dates' import { getFiles } from '../../utils/ipfs' import { useProjectData } from './hooks' const styles = theme => ({ root: { display: 'grid', gridTemplateColumns: '1fr 5fr', gridTemplateRows: '1fr 4fr', gridColumnGap: '1em', gridRowGap: '36px', margin: '1.75rem 4.5rem', fontFamily: theme.typography.fontFamily }, paper: { padding: theme.spacing.unit * 2, textAlign: 'center', color: theme.palette.text.secondary, }, title: { fontSize: '2.5rem' }, subTitle: { fontSize: '1.5rem', fontWeight: 200 }, creator:{ display: 'flex', flexDirection: 'column', justifyContent: 'space-around', alignItems: 'end' }, creatorName: { fontSize: '1rem' }, media: { objectFit: 'cover' }, secondRow: { gridColumnStart: '1', gridColumnEnd: '3', display: 'grid', gridTemplateColumns: '2fr 1fr', gridColumnGap: '3em' }, infoBox: { display: 'grid', gridTemplateRows: '0rem 2.5rem 2.5rem 2.5rem', gridRowGap: '2rem' }, infoBoxSection: { display: 'flex', flexDirection: 'column' }, infoText: { fontSize: '2rem' }, raisedAmount: { fontSize: '2em', color: theme.palette.primary.main }, subtext: { ...theme.typography.caption, fontSize: '1rem' }, linearColorPrimary: { backgroundColor: '#00000014', }, linearBarColorPrimary: { backgroundColor: theme.palette.primary.main }, link: { textDecoration: 'none' } }) function getReceivedAmount(id, transfers){ return transfers .filter(t => t.returnValues.to === id) .reduce((pv, cv) => { const amount = Number(toEther(cv.returnValues.amount)) return pv + amount }, 0) } function getWithdrawnAmount(id, transfers){ return transfers .filter(t => t.returnValues.from === id) .reduce((pv, cv) => { const amount = Number(toEther(cv.returnValues.amount)) return pv + amount }, 0) } function getAmountsPledged(pledges){ const amounts = {} pledges.forEach(pledge => { const { token, amount } = pledge if (amounts[token]) amounts[token] += Number(toEther(amount)) else amounts[token] = Number(toEther(amount)) }) return Object .entries(amounts) .map(entry => ([getTokenLabel(entry[0]), entry[1]])) } function getNumberOfBackers(pledges){ return length(uniqBy(p => p.owner, pledges)) } async function getProjectAge(id, events, setState){ const event = events.find(e => e.returnValues.idProject === id) const { timestamp } = await web3.eth.getBlock(event.blockNumber) setState(timeSinceBlock(timestamp, 'days')) } async function getProjectAssets(hash, setState){ console.log({hash}) const CID = hash.split('/').slice(-1)[0] getFiles(CID) .then((files) => { setState(files) const manifest = files[2] console.log({files}, JSON.parse(manifest.content)) }) .catch(console.log) } const getProjectManifest = assets => assets ? JSON.parse(assets.find(a => a.name.toLowerCase() === 'manifest.json').content) : null const formatMedia = content => { const blob = new Blob([content], {type : 'video/mp4'}) return URL.createObjectURL(blob) } const getMediaType = assets => { if (!assets) return false const { media } = getProjectManifest(assets) if (media.type.toLowerCase().includes('video')) return true } const getMediaSrc = assets => { if (!assets) return null const { media } = getProjectManifest(assets) if (media.type.includes('video')) { if (media.url) return media.url if (media.file) { return formatMedia( assets.find(a => a.name === media.file).content ) } } } function Project({ classes, match, profile, transfers, pledges, projectAddedEvents }) { const projectId = match.params.id const { projectAge, projectAssets, manifest } = useProjectData(projectId, profile, projectAddedEvents) const amountsPledged = useMemo(() => getAmountsPledged(pledges), [pledges]) const numberOfBackers = useMemo(() => getNumberOfBackers(pledges), [pledges]) const mediaType = useMemo(() => getMediaType(projectAssets), [projectAssets]) const mediaUrl = useMemo(() => getMediaSrc(projectAssets), [projectAssets]) const totalPledged = amountsPledged[0] ? amountsPledged[0][1] : 0 const percentToGoal = manifest ? Math.min( (Number(totalPledged) / Number(manifest.goal)) * 100, 100 ) : 0 console.log({profile, projectAssets, mediaUrl, mediaType, amountsPledged, pledges, transfers}) return ( !projectAssets ? :
{manifest && `By ${manifest.creator}`}
{manifest && manifest.title} {manifest && manifest.subtitle}
{mediaType ? : }
{amountsPledged[0] ? : }
{`${totalPledged.toLocaleString()} ${amountsPledged[0] ? amountsPledged[0][0] : ''}`} {manifest && `pledged of ${Number(manifest.goal).toLocaleString()} goal`}
{numberOfBackers} backers
{projectAge} days active
) } Project.propTypes = { classes: PropTypes.object.isRequired, match: PropTypes.object, profile: PropTypes.array.isRequired, } const StyledProject = withStyles(styles)(Project) export default withDatabase(withObservables([], ({ database, match }) => ({ profile: database.collections.get('profiles').query( Q.where('id_profile', match.params.id) ).observe(), transfers: database.collections.get('lp_events').query( Q.where('event', 'Transfer') ).observe(), projectAddedEvents: database.collections.get('lp_events').query( Q.where('event', 'ProjectAdded') ).observe(), pledges: database.collections.get('pledges').query( Q.where('intended_project', match.params.id) ).observe() }))(StyledProject))