show amount pledged and goal on project cards

This commit is contained in:
Barry Gitarts 2019-05-06 15:30:47 -04:00 committed by Barry G
parent 0331f53c18
commit 81795436d7
5 changed files with 96 additions and 75 deletions

View File

@ -172,9 +172,9 @@ const SubmissionSection = ({ classes, profiles, delegatePledges, projectId, open
)
}
function BackProject({classes, match, profile, delegates: _delegates, projectAddedEvents, delegateAddedEvents: _delegateAddedEvents}) {
function BackProject({classes, match, delegates: _delegates, projectAddedEvents, delegateAddedEvents: _delegateAddedEvents}) {
const projectId = match.params.id
const { manifest, delegateProfiles, openSnackBar } = useProjectData(projectId, profile, projectAddedEvents)
const { manifest, delegateProfiles, openSnackBar } = useProjectData(projectId, projectAddedEvents)
const delegatePledges = useProfileData(delegateProfiles)
return (
<div className={classes.root}>

View File

@ -15,8 +15,8 @@ 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 { getAmountsPledged } from '../../utils/pledges'
import { getFiles } from '../../utils/ipfs'
import { getImageType } from '../../utils/images'
import { useProjectData } from './hooks'
@ -111,18 +111,6 @@ function _getWithdrawnAmount(id, transfers){
}, 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))
}
@ -195,7 +183,7 @@ const getAvatarSrc = assets => {
function Project({ classes, match, profile, transfers, pledges, projectAddedEvents }) {
const projectId = match.params.id
const { projectAge, projectAssets, manifest } = useProjectData(projectId, profile, projectAddedEvents)
const { projectAge, projectAssets, manifest } = useProjectData(projectId, projectAddedEvents)
const amountsPledged = useMemo(() => getAmountsPledged(pledges), [pledges, projectId])
const numberOfBackers = useMemo(() => getNumberOfBackers(pledges), [pledges, projectId])

View File

@ -1,4 +1,4 @@
import React, {Fragment, useState} from 'react'
import React, {Fragment, useState, useMemo} from 'react'
import {withStyles} from '@material-ui/core/styles'
import {withDatabase} from "@nozbe/watermelondb/DatabaseProvider";
import withObservables from "@nozbe/with-observables";
@ -28,6 +28,7 @@ import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import classnames from 'classnames';
import { getAmountsPledged } from '../../utils/pledges'
import defaultProjectImage from '../../images/default-project-img.png';
import newProjectImage from '../../images/new-project.png';
@ -138,43 +139,61 @@ function sortByDate(a, b) {
}
function Favorite({classes, setFavorites, favorites, projectId, className}) {
return (<span className={classnames(className, classes.favorite, {isFavorite: favorites[projectId]})}
onClick={() => setFavorites({...favorites, [projectId]: !favorites[projectId]})}/>);
return (
<span
className={classnames(className, classes.favorite, {isFavorite: favorites[projectId]})}
onClick={() => setFavorites({...favorites, [projectId]: !favorites[projectId]})} />
);
}
function ProjectCard({classes, project, favorites, setFavorites}) {
return (<Card className={classes.card}>
<CardActionArea href={`/#/project/${project.projectId}`} onClick={e => { if (e.target.className.indexOf(classes.favorite) > -1) { e.preventDefault() } }}>
<CardMedia
className={classes.media}
image={defaultProjectImage}
title="Project image"
/>
<LinearProgress className={classes.progress} variant="determinate" value={75} /> {/*TODO get actual percentage*/}
<CardContent>
<Typography align="right" className={classes['card-content']}>75% of 2.055 ETH</Typography> {/*TODO get actual percentage*/}
<Typography align="right" className={classes['card-content']}>3 funders</Typography> {/*TODO get actual funders*/}
<Typography gutterBottom variant="h5" component="h2" className={classes['card-title']} noWrap>
{project.manifest.title}
</Typography>
<Typography component="p" className={classes['card-content']} noWrap gutterBottom>
{project.manifest.description}&nbsp;
</Typography>
<Typography component="p" className={classes['card-content']} color="textSecondary">
Delegate: {project.manifest.creator} {/*TODO check if that really is the delegate*/}
</Typography>
{project.manifest.avatar && <img className={classes.avatarGrid} alt="avatar" src={project.manifest.avatar} width={40} height={40}/>}
<Favorite className={classes.cardFavorite} classes={classes} favorites={favorites} projectId={project.projectId} setFavorites={setFavorites}/>
</CardContent>
</CardActionArea>
<CardActions className={classes['card-actions']}>
<Button size="small" color="primary" href={`/#/project/${project.projectId}`}>
Read more
</Button>
</CardActions>
</Card>)
function RawProjectCard({classes, project, pledges, favorites, setFavorites}) {
const { manifest } = project
const amountsPledged = useMemo(() => getAmountsPledged(pledges), [pledges])
const totalPledged = amountsPledged[0] ? amountsPledged[0][1] : 0
const pledgeCurrency = amountsPledged[0] ? amountsPledged[0][0] : 'ETH'
const percentToGoal = manifest ? Math.min(
(Number(totalPledged) / Number(manifest.goal)) * 100,
100
) : 0
return (
<Card className={classes.card}>
<CardActionArea href={`/#/project/${project.projectId}`} onClick={e => { if (e.target.className.indexOf(classes.favorite) > -1) { e.preventDefault() } }}>
<CardMedia
className={classes.media}
image={defaultProjectImage}
title="Project image"
/>
<LinearProgress className={classes.progress} variant="determinate" value={percentToGoal} />
<CardContent>
<Typography align="right" className={classes['card-content']}>{Math.round(totalPledged)} pledged of {manifest.goal} {pledgeCurrency}</Typography>
<Typography align="right" className={classes['card-content']}>3 funders</Typography> {/*TODO get actual funders*/}
<Typography gutterBottom variant="h5" component="h2" className={classes['card-title']} noWrap>
{project.manifest.title}
</Typography>
<Typography component="p" className={classes['card-content']} noWrap gutterBottom>
{project.manifest.description}&nbsp;
</Typography>
<Typography component="p" className={classes['card-content']} color="textSecondary">
Delegate: {project.manifest.creator} {/*TODO check if that really is the delegate*/}
</Typography>
{project.manifest.avatar && <img className={classes.avatarGrid} alt="avatar" src={project.manifest.avatar} width={40} height={40}/>}
<Favorite className={classes.cardFavorite} classes={classes} favorites={favorites} projectId={project.projectId} setFavorites={setFavorites}/>
</CardContent>
</CardActionArea>
<CardActions className={classes['card-actions']}>
<Button size="small" color="primary" href={`/#/project/${project.projectId}`}>
Read more
</Button>
</CardActions>
</Card>)
}
const ProjectCard = withDatabase(withObservables(['project'], ({ database, project }) => ({
pledges: database.collections.get('pledges').query(
Q.where('intended_project', project.projectId)
).observe()
}))(RawProjectCard))
function GridView({classes, projects, favorites, setFavorites}) {
return (<Grid container spacing={40}>
{projects.map((project, index) => {
@ -233,7 +252,7 @@ function ListView({classes, projects, history, favorites, setFavorites}) {
<TableRow className={classnames(classes.row, {[classes.darkRow]: rowCounter%2})} key={'project-' + index}>
<CustomTableCell>
{project.manifest.avatar &&
<img className={classes.avatar} alt="avatar" src={project.manifest.avatar} width={40} height={40}/>}
<img className={classes.avatar} alt="avatar" src={project.manifest.avatar} width={40} height={40}/>}
</CustomTableCell>
<CustomTableCell className={classes.nameCell}>{project.manifest.title}</CustomTableCell>
<CustomTableCell>{project.manifest.description}</CustomTableCell>
@ -269,7 +288,7 @@ function Projects({projectAddedEvents, classes, history}) {
const [isGridView, setIsGridView] = useState(true);
const projects = projectAddedEvents.map(event => {
return Object.assign({projectId: event.returnValues.idProject}, useProjectData(event.returnValues.idProject, '', projectAddedEvents));
return Object.assign({projectId: event.returnValues.idProject}, useProjectData(event.returnValues.idProject, projectAddedEvents));
})
let sortFunction = (sortType === SORT_TYPES.name) ? sortByTitle : sortByDate;
@ -281,26 +300,26 @@ function Projects({projectAddedEvents, classes, history}) {
{projects.length === 0 && <Loading/>}
{projects.length > 0 &&
<Fragment>
<div className={classes.filters}>
<FormControl>
<TextField
variant="outlined"
placeholder="Filter by tags"
InputProps={{
className: classes.search,
startAdornment: <InputAdornment position="start"><SearchIcon/></InputAdornment>,
}}
/>
</FormControl>
<Fragment>
<div className={classes.filters}>
<FormControl>
<TextField
variant="outlined"
placeholder="Filter by tags"
InputProps={{
className: classes.search,
startAdornment: <InputAdornment position="start"><SearchIcon/></InputAdornment>,
}}
/>
</FormControl>
<DashboardIcon className={classnames(classes.formatBtn, {'active': isGridView})} color="disabled" fontSize="large" onClick={() => setIsGridView(true)}/>
<ListIcon className={classnames(classes.formatBtn, {'active': !isGridView})} color="disabled" fontSize="large" onClick={() => setIsGridView(false)}/>
</div>
<DashboardIcon className={classnames(classes.formatBtn, {'active': isGridView})} color="disabled" fontSize="large" onClick={() => setIsGridView(true)}/>
<ListIcon className={classnames(classes.formatBtn, {'active': !isGridView})} color="disabled" fontSize="large" onClick={() => setIsGridView(false)}/>
</div>
{!isGridView && ListView({classes, projects, history, favorites, setFavorites})}
{isGridView && GridView({classes, projects, favorites, setFavorites})}
</Fragment>
{!isGridView && ListView({classes, projects, history, favorites, setFavorites})}
{isGridView && GridView({classes, projects, favorites, setFavorites})}
</Fragment>
}
</div>)
}

View File

@ -20,16 +20,16 @@ async function getProjectAge(id, events, setState){
}
}
async function getProjectAssets(projectId, setState){
async function getProjectAssets(projectId, setState, debug=false){
EmbarkJS.onReady(async (_err) => {
const projectInfo = await LiquidPledging.methods.getPledgeAdmin(projectId).call()
const CID = projectInfo.url.split('/').slice(-1)[0]
console.log({CID, projectInfo, ipfs})
if (debug) console.log({CID, projectInfo, ipfs})
getFiles(CID)
.then((files) => {
setState(files)
const manifest = files[2]
console.log({files}, JSON.parse(manifest.content))
if (debug) console.log({files}, JSON.parse(manifest.content))
})
.catch(async (err) => {
console.log('IPFS getFiles error: ', err)
@ -40,7 +40,7 @@ async function getProjectAssets(projectId, setState){
.then((files) => {
setState(files)
const manifest = files[2]
console.log({files}, JSON.parse(manifest.content))
if (debug) console.log({files}, JSON.parse(manifest.content))
})
.catch((err) => {
console.log('IPFS FAILED ON READY', err)
@ -99,7 +99,7 @@ const getProjectManifest = assets => {
}
}
export function useProjectData(projectId, profile, projectAddedEvents) {
export function useProjectData(projectId, projectAddedEvents) {
const [projectAge, setAge] = useState(null)
const [projectAssets, setAssets] = useState(null)
const [ipfsReady, setIpfsState] = useState(null)

View File

@ -1,5 +1,7 @@
/*global web3, BigInt*/
import LiquidPledging from '../embarkArtifacts/contracts/LiquidPledging'
import { getTokenLabel } from './currencies'
import { toEther } from './conversions'
const { getPledgeDelegate, numberOfPledges, getPledge } = LiquidPledging.methods
const getPledgeDelegates = (idPledge, numDelegates) => {
@ -78,3 +80,15 @@ export const transferBetweenPledges = (setState, tx) => {
}
})
}
export 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]]))
}