Skip to content

Commit

Permalink
Merge branch 'master' into kevin/phantom_funding
Browse files Browse the repository at this point in the history
  • Loading branch information
octavioamu authored Sep 11, 2019
2 parents 2f51e7f + 787ebbd commit 0833579
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 132 deletions.
59 changes: 24 additions & 35 deletions app/assets/v2/css/bounty.css
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,30 @@ body {
margin-bottom: 5px;
}

.stat-card {
background: #ecf0fa;
border-radius: 4px;
}

.stat-card h2,
.stat-card p,
.related-bounties li .bounty-org,
.popover-bounty__content .summary {
color: #717171;
}

.related-bounties {
list-style-type: none;
}

.related-bounties .bounty-title {
color: #3E00FF;
}

.related-bounties .static-stars .far {
font-size: 0.8rem;
}

.box {
padding: 14px;
border: 1px solid #DBDBDB;
Expand Down Expand Up @@ -153,10 +177,6 @@ body {
color: #000000;
}

/* #issue_description pre, code {
padding: 1em 0;
} */

#bounty-info-row {
margin-left: 1px;
}
Expand Down Expand Up @@ -490,35 +510,6 @@ a.btn {
margin-bottom: 2em;
}

.earned {
color: #8E2ABE;
font-size: 14px;
line-height: 13px;
font-weight: 600;
}

.contributor-position,
.username,
.current_status,
.in-progress {
color: #0D0764;
}

.specialty {
font-weight: 600;
font-size: 10px;
line-height: 11px;
}

.completed-bounties {
color: #05B66A;
}

.abandoned-bounties,
.removed-bounties {
color: #F5A623;
}

#funder_notif_info:empty {
display: none;
}
Expand All @@ -540,7 +531,6 @@ a.btn {
top: -2px;
}


#bounty_details #issue_description img {
max-height: 30rem;
max-width: 30rem;
Expand Down Expand Up @@ -860,7 +850,6 @@ a.btn {
display: none;
}

#title,
#funder_notif_info {
text-align: center;
}
Expand Down
163 changes: 84 additions & 79 deletions app/assets/v2/js/user_popover.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,90 @@
let popoverData = [];

const renderPopOverData = json => {
let orgs = Object.keys(json.profile.organizations).map((org, index) => {
if (index < 3) {
return `<img src="/dynamic/avatar/${org}" alt="${org}" class="rounded-circle" width="24" height="24">`;
const renderPopOverData = data => {
const unique_contributed_to = data.contributed_to ? Array.from(new Set(data.contributed_to)) : [];
let contributed_to = unique_contributed_to && unique_contributed_to.map((_organization, index) => {
if (index < 5) {
return `<img src="/dynamic/avatar/${_organization}" alt="${_organization}"
class="rounded-circle" width="24" height="24">`;
}
return `<span class="m-1">+${Object.keys(json.profile.organizations).length - 3}</span>`;
return `<span class="m-1">+${data.contributed_to.length - 5}</span>`;
}).join(' ');

const bounties = data.related_bounties && data.related_bounties.map(bounty => {
const title = bounty.title <= 30 ? bounty.title : bounty.title.slice(0, 27) + '...';

let ratings = [];

if (bounty.rating && bounty.rating[0] > 0) {
for (let i = 0; i < 5; i++) {
ratings.push(`<i class="far fa-star ${ i <= bounty.rating[0] ? 'fas' : ''} "></i>`);
}
}

return `<li>
<span class="font-weight-semibold bounty-title">${title}</span>
<span class="bounty-org">by ${bounty.org}</span>
${ratings.length > 0 ?
`<span class="static-stars float-right">
${ratings.join(' ')}
</span>` : ''}
</li>`;
}).join(' ');

return `
<div class="popover-bounty__content">
<div class="d-flex justify-content-between mb-2">
<img src="${json.profile.avatar_url}" width="30" class="rounded-circle">
<h2 class="title font-subheader font-weight-bold username">${json.profile.handle}</h2>
<span class="text-muted specialty pt-2">Specialty: ${json.profile.keywords.slice(0, 3).toString()}</span>
${orgs.length ? '<span>Contributes to: </span>' + orgs : ''}
<div class="mb-2">
<img src="${data.avatar}" width="35" class="rounded-circle">
<p class="ml-3 d-inline font-body my-auto font-weight-semibold">${data.handle}</p>
<div class="float-right">
${contributed_to.length ? '<span class="my-auto">Contributes to: </span>' + contributed_to : ''}
</div>
</div>
<span class="earned">~ ${Number(json.profile.total_earned).toFixed(4)} ETH earned</span>
<div class="statistics d-flex justify-content-between mt-2">
<div class="popover_card text-center mr-4 pt-2">
<span class="contributor-position font-weight-semibold">#${json.profile.position}</span>
<p class="mt-2">Gitcoin Contributor</p>
<div class="stats text-center mt-4">
<div class="stat-card mx-1 mb-2 py-2 px-5 px-sm-3 d-inline-block text-center">
<h2 class="font-title font-weight-bold mb-0">
${data.stats.position == 0 ? '-' : '#' + data.stats.position}
</h2>
<p class="font-body mb-0">contributor</p>
</div>
<div class="contributions d-flex justify-content-between">
<div class="popover_card text-center mr-2 pt-2">
<span class="completed-bounties font-weight-semibold">${json.statistics.work_completed}</span>
<p class="mt-2">Bounties Completed</p>
</div>
<div class="popover_card text-center mr-2 pt-2">
<span class="in-progress text-center font-weight-semibold">${json.statistics.work_in_progress}</span>
<p class="mt-2">Bounties In Progress</p>
</div>
<div class="popover_card text-center mr-2 pt-2">
<span class="abandoned-bounties font-weight-semibold">${json.statistics.work_abandoned}</span>
<p class="mt-2">Bounties Abandoned</p>
</div>
<div class="popover_card text-center mr-2 pt-2">
<span class="removed-bounties font-weight-semibold">${json.statistics.work_removed}</span>
<p class="mt-2">Bounties Removed</p>
</div>
<div class="stat-card mx-1 mb-2 py-2 px-5 px-sm-3 d-inline-block text-center">
<h2 class="font-title font-weight-bold mb-0">
${data.stats.success_rate ? Math.round(data.stats.success_rate * 100) : 0} %
</h2>
<p class="font-body mb-0">success rate</p>
</div>
<div class="stat-card mx-1 mb-2 py-2 px-5 px-sm-3 d-inline-block text-center">
<h2 class="font-title font-weight-bold mb-0">
${data.stats.earnings ? Number(data.stats.earnings).toFixed(4) : 0} ETH
</h2>
<p class="font-body mb-0">
collected from
<span class="font-weight-bold">${data.stats.completed_bounties}</span> bounties
</p>
</div>
</div>
</div>
<div class="popover-bounty__footer">
<div class="d-flex justify-content-between">
<span class="title text-muted">Latest Activity
<span class="current_status font-weight-semibold">${currentStatus(json.recent_activity.activity_type)}</span>
</span>
<span class="text-muted time-ago">${moment(json.recent_activity.created, 'YYYYMMDD').fromNow()}</span>
</div>
<p class="text-muted pt-2 activity-title">${json.recent_activity.activity_metadata.title}</p>
${data.related_bounties.length == 0 ?
`<p class="font-body mt-3 summary">
No bounties completed related to <span class="font-italic">${data.keywords || 'bounty'}</span>
</p>`
:
`<p class="font-body mt-3 summary">
Bounties completed related to <span class="font-italic">${data.keywords || 'bounty'}:</span>
</p>
<ul class="related-bounties font-body pl-0">
${bounties}
</ul>`
}
</div>
`;
};

const openContributorPopOver = (contributor, element) => {
let contributorURL = `/api/v0.1/profile/${contributor}`;
function openContributorPopOver(contributor, element) {
const keywords = document.result.keywords || '';
const contributorURL = `/api/v0.1/profile/${contributor}?keywords=${keywords}`;

if (popoverData.filter(index => index[contributor]).length === 0) {
fetch(contributorURL, { method: 'GET' })
Expand All @@ -65,8 +93,12 @@ const openContributorPopOver = (contributor, element) => {
element.popover({
placement: 'auto',
trigger: 'hover',
template:
'<div class="popover popover-bounty" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',
template: `
<div class="popover popover-bounty" role="tooltip">
<div class="arrow"></div>
<h3 class="popover-header"></h3>
<div class="popover-body"></div>
</div>`,
content: renderPopOverData(response),
html: true
});
Expand All @@ -80,44 +112,17 @@ const openContributorPopOver = (contributor, element) => {
element.popover({
placement: 'auto',
trigger: 'hover',
template:
'<div class="popover popover-bounty" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',
template: `
<div class="popover popover-bounty" role="tooltip">
<div class="arrow"></div>
<h3 class="popover-header"></h3>
<div class="popover-body"></div>
</div>`,
content: renderPopOverData(
popoverData.filter(item => item[contributor])[0][contributor]
),
html: true
});
$(element).popover('show');
}
};

const currentStatus = status => {
const activity_names = {
new_bounty: gettext('New Bounty'),
start_work: gettext('Work Started'),
stop_work: gettext('Work Stopped'),
work_submitted: gettext('Work Submitted'),
work_done: gettext('Work Done'),
worker_approved: gettext('Worker Approved'),
worker_rejected: gettext('Worker Rejected'),
worker_applied: gettext('Worker Applied'),
increased_bounty: gettext('Increased Funding'),
killed_bounty: gettext('Canceled Bounty'),
new_crowdfund: gettext('New Crowdfund Contribution'),
new_tip: gettext('New Tip'),
receive_tip: gettext('Tip Received'),
bounty_abandonment_escalation_to_mods: gettext(
'Escalated for Abandonment of Bounty'
),
bounty_abandonment_warning: gettext('Warned for Abandonment of Bounty'),
bounty_removed_slashed_by_staff: gettext(
'Dinged and Removed from Bounty by Staff'
),
bounty_removed_by_staff: gettext('Removed from Bounty by Staff'),
bounty_removed_by_funder: gettext('Removed from Bounty by Funder'),
bounty_changed: gettext('Bounty Details Changed'),
extend_expiration: gettext('Extended Bounty Expiration')
};

return activity_names[status] || 'Unknown activity ';
};
}
20 changes: 20 additions & 0 deletions app/dashboard/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2364,8 +2364,28 @@ def is_staff(self):
"""
return self.user.is_staff if self.user else False


@property
def completed_bounties(self):
"""Returns bounties completed by user
Returns:
number: number of bounties completed
"""
network = self.get_network()
return self.bounties.filter(
idx_status__in=['done'], network=network).count()


@property
def success_rate(self):
"""Returns success rate of user on the platform
Returns:
number: sucess rate of user
"""
network = self.get_network()
num_completed_bounties = self.bounties.filter(
idx_status__in=['done'], network=network).count()
Expand Down
4 changes: 4 additions & 0 deletions app/dashboard/templates/bounty/details.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<link rel="stylesheet" href="{% static "v2/css/bounty.css" %}">
<link rel="stylesheet" href="{% static "v2/css/user_popover.css" %}">
<link rel="stylesheet" href="{% static "v2/css/tag.css" %}">
<link rel="stylesheet" href={% static "v2/css/rating.css" %} />
</head>

<body class="interior {{active}} g-font-muli">
Expand Down Expand Up @@ -488,6 +489,9 @@ <h3>{{ noscript.keywords }}</h3>
$("body").on("mouseover", "[data-username]", function(e) {
openContributorPopOver($(this).data("username"), $(this));
});
$("body").on("mouseout", "[data-username]", function(e) {
$(this).popover('dispose');
});
</script>
<script src="{% static "v2/js/lib/daterangepicker.min.js" %}"></script>
<script src="{% static "v2/js/pages/bounty_funder_payout_reminder.js" %}"></script>
Expand Down
Loading

0 comments on commit 0833579

Please sign in to comment.