Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overdue bounties correct status info #1829

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/projects/app/assets/IconDoubleCheck.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'

const IconDoubleCheck = () => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
const IconDoubleCheck = props => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" {...props}>
<path d="M20.8462 8.1494C20.6411 7.9502 20.3086 7.9502 20.1036 8.1494L12.2594 15.7686L8.89644 12.502C8.69138 12.3028 8.35886 12.3028 8.15381 12.502C7.94873 12.7012 7.94873 13.0242 8.15381 13.2234L11.8881 16.8506C11.9906 16.9502 12.1251 17 12.2594 17C12.3938 17 12.5283 16.9502 12.6308 16.8506L20.8462 8.87075C21.0513 8.67158 21.0513 8.34862 20.8462 8.1494Z" fill="#2CC68F" stroke="#2CC68F" strokeWidth="0.5"/>
<path d="M15.8462 8.1494C15.6411 7.9502 15.3086 7.9502 15.1036 8.1494L7.2594 15.7686L3.89644 12.502C3.69138 12.3028 3.35886 12.3028 3.15381 12.502C2.94873 12.7012 2.94873 13.0242 3.15381 13.2234L6.88811 16.8506C6.99064 16.9502 7.12506 17 7.25945 17C7.39384 17 7.52826 16.9502 7.63079 16.8506L15.8462 8.87075C16.0513 8.67158 16.0513 8.34862 15.8462 8.1494Z" fill="#2CC68F" stroke="#2CC68F" strokeWidth="0.5"/>
</svg>
Expand Down
12 changes: 12 additions & 0 deletions apps/projects/app/assets/IconUserError.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 14 additions & 1 deletion apps/projects/app/assets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,18 @@ import IconCollapse from './IconCollapse'
import IconDropArrow from './IconDropArrow'
import IconDoubleCheck from './IconDoubleCheck'
import IconUserCheck from './IconUserCheck'
import IconUserError from './IconUserError'

export { IconMore, IconSort, IconGrid, IconCoins, IconFilter, IconOpen, IconCollapse, IconDropArrow, IconDoubleCheck, IconUserCheck }
export {
IconDoubleCheck,
IconDropArrow,
IconCoins,
IconCollapse,
IconFilter,
IconGrid,
IconMore,
IconOpen,
IconSort,
IconUserCheck,
IconUserError,
}
90 changes: 58 additions & 32 deletions apps/projects/app/components/Card/Issue.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ContextMenu,
IconAddUser,
IconClock,
IconCoin,
IconGraph2,
IconInfo,
Tag,
Expand All @@ -19,11 +20,12 @@ import { formatDistance } from 'date-fns'
import { BountyContextMenu } from '../Shared'
import { BOUNTY_STATUS, BOUNTY_BADGE_COLOR } from '../../utils/bounty-status'
import { issueShape } from '../../utils/shapes'
import { IconUserError, IconDoubleCheck } from '../../assets'

const DeadlineDistance = date =>
const deadlineDistance = date =>
formatDistance(new Date(date), new Date(), { addSuffix: true })

const dot = <span css="margin: 0px 10px">&middot;</span>
const Dot = () => <span css="margin: 0px 10px">&middot;</span>

const labelsTags = (labels, theme) =>
labels.edges.map(label => (
Expand All @@ -45,7 +47,7 @@ const FlexibleDiv = ({ compact, children }) => {
</div>
) : (
<React.Fragment>
{dot}
<Dot />
{children}
</React.Fragment>
)
Expand All @@ -56,46 +58,66 @@ FlexibleDiv.propTypes = {
children: PropTypes.node.isRequired,
}

const Bounty = ({ issue }) => {
const BountyDetail = ({ Icon, iconColor, text }) => {
const theme = useTheme()
return (
<span css="white-space: nowrap">
<Icon
style={{ marginBottom: '-8px', marginRight: '4px' }}
color={iconColor ? iconColor : `${theme.surfaceIcon}`}
/>
{text}
</span>
)
}
BountyDetail.propTypes = {
Icon: PropTypes.func.isRequired,
iconColor: PropTypes.string,
text: PropTypes.string.isRequired,
}

const Bounty = ({ issue }) => {
const { layoutName } = useLayout()
const { workStatus, deadline, expLevel, openSubmission } = issue
const theme = useTheme()

let status = BOUNTY_STATUS[workStatus]
if (openSubmission && workStatus === 'funded')
status = BOUNTY_STATUS['open-submission-funded']

const pastDueDate = new Date() > new Date(issue.deadline)

if (issue.workStatus === 'fulfilled') return (
<FlexibleDiv compact={layoutName !== 'large'}>
<BountyDetail Icon={IconCoin} text="1 bounty" />
<Dot />
<BountyDetail Icon={IconDoubleCheck} text="Completed" />
</FlexibleDiv>
)

if (pastDueDate) return (
<FlexibleDiv compact={layoutName !== 'large'}>
<BountyDetail Icon={IconCoin} text="1 bounty" />
<Dot />
<BountyDetail Icon={IconUserError} iconColor={`${theme.positiveSurfaceContent}`} text="Not Completed" />
</FlexibleDiv>
)

return (
<React.Fragment>
<>
<FlexibleDiv compact={layoutName !== 'large'}>
<span css="white-space: nowrap">
<IconAddUser
color={`${theme.surfaceIcon}`}
css="margin-bottom: -8px; margin-right: 4px"
/>
{status}
</span>
{dot}
<span css="white-space: nowrap">
<IconClock color={`${theme.surfaceIcon}`}
css="margin-bottom: -8px; margin-right: 4px"
/>
Due {DeadlineDistance(deadline)}
</span>
<BountyDetail Icon={IconCoin} text="1 bounty" />
<Dot />
<BountyDetail Icon={IconAddUser} text={status} />
</FlexibleDiv>
<FlexibleDiv compact={layoutName !== 'large'}>
<span css="white-space: nowrap">
<IconGraph2
css="margin-bottom: -8px; margin-right: 4px"
color={`${theme.surfaceIcon}`}
/>
{expLevel}
</span>
<BountyDetail Icon={IconClock} text={'Due ' + deadlineDistance(deadline)} />
<Dot />
<BountyDetail Icon={IconGraph2} text={expLevel} />
</FlexibleDiv>
</React.Fragment>
</>
)
}

Bounty.propTypes = issueShape

const Issue = ({ isSelected, onClick, onSelect, ...issue }) => {
Expand Down Expand Up @@ -161,15 +183,19 @@ const Issue = ({ isSelected, onClick, onSelect, ...issue }) => {
<IssueDetails>
<Text.Block color={`${theme.surfaceContentSecondary}`} size="small">
<span css="font-weight: 600; white-space: nowrap">{repo} #{number}</span>

<FlexibleDiv compact={layoutName === 'small'}>
<span css="white-space: nowrap">
<IconInfo color={`${theme.positiveSurfaceContent}`} css="margin-bottom: -8px; margin-right: 4px" />
opened {DeadlineDistance(createdAt)}
</span>
<BountyDetail
Icon={IconInfo}
iconColor={`${theme.positiveSurfaceContent}`}
text={'opened ' + deadlineDistance(createdAt)}
/>
</FlexibleDiv>

{issue.hasBounty && (
<Bounty issue={issue} />
)}

</Text.Block>
</IssueDetails>
</IssueData>
Expand Down
103 changes: 68 additions & 35 deletions apps/projects/app/components/Content/IssueDetail/BountyCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
GU,
IconAddUser,
IconClock,
IconCoin,
IconFile,
IconGraph2,
IdentityBadge,
Expand All @@ -18,7 +19,7 @@ import { issueShape } from '../../../utils/shapes.js'
import { usePanelManagement } from '../../Panel'
import { useAragonApi } from '../../../api-react'
import { formatDistance } from 'date-fns'
import { IconDoubleCheck, IconUserCheck } from '../../../assets'
import { IconDoubleCheck, IconUserCheck, IconUserError } from '../../../assets'

const ActionButton = ({ panel, caption, issue }) => (
<EventButton
Expand Down Expand Up @@ -56,13 +57,24 @@ const DeadlineDistance = ({ date }) =>

const pluralize = (word, number) => `${number} ${word}${number > 1 ? 's' : ''}`

const pastDueDate = deadline => new Date() > new Date(deadline)

const Status = ({ issue }) => {
const theme = useTheme()
const workStatus = (issue.openSubmission && issue.workStatus !== 'fulfilled') ?
'openSubmission'
:
issue.workStatus

if (pastDueDate(issue.deadline) && workStatus !== 'fulfilled') return (
<>
<IconUserError color={`${theme.surfaceIcon}`} />
<BountyText>
Not completed
</BountyText>
</>
)

switch(workStatus) {
case 'openSubmission': return (
<>
Expand Down Expand Up @@ -113,15 +125,15 @@ const Submissions = ({ issue }) => {
'No applications'
)
case 'review-applicants': return (
<Link onClick={() => reviewApplication({ issue, requestIndex: 0 })}>
<Link onClick={() => reviewApplication({ issue, requestIndex: 0, readOnly: pastDueDate(issue.deadline) })}>
{pluralize('application', issue.requestsData.length)}

</Link>
)
case 'openSubmission':
case 'in-progress':
if ('workSubmissions' in issue) return (
<Link onClick={() => reviewWork({ issue, index: 0 })}>
<Link onClick={() => reviewWork({ issue, index: 0, readOnly: pastDueDate(issue.deadline) })}>
{pluralize('work submission', issue.workSubmissions.length)}
</Link>
)
Expand All @@ -130,7 +142,7 @@ const Submissions = ({ issue }) => {
)
case 'review-work':
case 'fulfilled': return (
<Link onClick={() => reviewWork({ issue, index: 0 })}>
<Link onClick={() => reviewWork({ issue, index: 0, readOnly: pastDueDate(issue.deadline) })}>
{pluralize('work submission', issue.workSubmissions.length)}
</Link>)
default: return null
Expand All @@ -150,10 +162,12 @@ const Dot = ({ color }) => (
)
Dot.propTypes = PropTypes.string.isRequired

const BountyDot = ({ workStatus }) => {
const BountyDot = ({ issue }) => {
const theme = useTheme()

switch(workStatus) {
if (pastDueDate(issue.deadline)) return null

switch(issueShape.workStatus) {
case 'funded':
case 'review-applicants':
return (
Expand All @@ -167,7 +181,7 @@ const BountyDot = ({ workStatus }) => {
default: return null
}
}
BountyDot.propTypes = PropTypes.string.isRequired
BountyDot.propTypes = issueShape

const Action = ({ issue }) => {
const { requestAssignment, submitWork } = usePanelManagement()
Expand All @@ -177,6 +191,8 @@ const Action = ({ issue }) => {
:
issue.workStatus

if (pastDueDate(issue.deadline)) return null

switch(workStatus) {
case 'funded':
case 'review-applicants': return (
Expand All @@ -196,12 +212,12 @@ Action.propTypes = issueShape

const BountyCard = ({ issue }) => {
const theme = useTheme()
const { appState: { bountySettings } } = useAragonApi()
const { appState: { bountySettings }, connectedAccount } = useAragonApi()
const expLevels = bountySettings.expLvls

return (
<Box
heading="Bounty"
heading="Bounty info"
padding={3 * GU}
css={`
flex: 0 1 auto;
Expand All @@ -212,38 +228,56 @@ const BountyCard = ({ issue }) => {
padding: 0;
`}
>
<div css={`display: flex; margin-bottom: ${2 * GU}px`}>
<BountyDot workStatus={issue.workStatus} />
<div css="display: flex; align-items: baseline">
<Text size="xxlarge">{issue.balance}</Text>
<Text color={`${theme.surfaceContentSecondary}`} css="margin-left: 2px">{issue.symbol}</Text>
</div>
</div>
<div css={`
> :not(:last-child) {
rkzel marked this conversation as resolved.
Show resolved Hide resolved
margin-bottom: ${GU}px;
}
`}>

{!(pastDueDate(issue.deadline) && issue.workStatus !== 'fulfilled') && (
rkzel marked this conversation as resolved.
Show resolved Hide resolved
<div css={`display: flex; margin-bottom: ${2 * GU}px`}>
rkzel marked this conversation as resolved.
Show resolved Hide resolved
<BountyDot issue={issue} />
<div css="display: flex; align-items: baseline">
<Text size="xxlarge">{issue.balance}</Text>
<Text color={`${theme.surfaceContentSecondary}`} css="margin-left: 2px">{issue.symbol}</Text>
</div>
</div>
)}

<Row>
<Status issue={issue} />
</Row>
{connectedAccount !== issue.assignee && (
<Row>
<IconCoin color={`${theme.surfaceIcon}`} />
<BountyText>1 bounty</BountyText>
</Row>
)}

{issue.workStatus !== 'fulfilled' && (
<Row>
<IconClock color={`${theme.surfaceIcon}`} />
<BountyText>Due <DeadlineDistance date={issue.deadline} /></BountyText>
<Status issue={issue} />
</Row>
)}

<Row>
<IconGraph2 color={`${theme.surfaceIcon}`} />
<BountyText>{expLevels[issue.exp].name}</BountyText>
</Row>
{issue.workStatus !== 'fulfilled' && (
<Row>
<IconClock color={`${theme.surfaceIcon}`} />
<BountyText>Due <DeadlineDistance date={issue.deadline} /></BountyText>
</Row>
)}

<Row>
<IconFile color={`${theme.surfaceIcon}`} />
<BountyText>
<Submissions issue={issue} />
</BountyText>
</Row>
{!(pastDueDate(issue.deadline) && issue.workStatus !== 'fulfilled') && (
rkzel marked this conversation as resolved.
Show resolved Hide resolved
<Row>
<IconGraph2 color={`${theme.surfaceIcon}`} />
<BountyText>{expLevels[issue.exp].name}</BountyText>
</Row>
)}

<Action issue={issue} />
<Row>
<IconFile color={`${theme.surfaceIcon}`} />
<BountyText>
<Submissions issue={issue} />
</BountyText>
</Row>

<Action issue={issue} />
</div>
</Box>
)
}
Expand All @@ -258,7 +292,6 @@ const EventButton = styled(Button)`
`
const Row = styled.div`
display: flex;
margin-bottom: ${GU}px;
`
const BountyText = styled.div`
margin-left: ${GU}px;
Expand Down
Loading