Skip to content

Commit

Permalink
feat: refactoring popover on bounty details
Browse files Browse the repository at this point in the history
  • Loading branch information
thelostone-mc committed Sep 5, 2019
1 parent ec23f01 commit 6ddff59
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 135 deletions.
6 changes: 0 additions & 6 deletions app/assets/v2/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -1528,12 +1528,6 @@ div.busyOverlay {
border-top-color: #F8F8F8;
}

.popover-bounty__footer {
padding: 1.3em 1.3em 1.2em;
background-color: #F8F8F8;
border-radius: 0 0 .3rem .3rem;
}

.popover-bounty__content {
padding: 1.4em 1.3em 1.3em;
}
Expand Down
31 changes: 0 additions & 31 deletions app/assets/v2/css/bounty.css
Original file line number Diff line number Diff line change
Expand Up @@ -490,35 +490,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 +511,6 @@ a.btn {
top: -2px;
}


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

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

const renderPopOverData = json => {
let orgs = Object.keys(json.profile.organizations).map((org, index) => {
const renderPopOverData = profile => {
let contributed_to = Object.keys(profile.contributed_to).map((_organization, index) => {
if (index < 3) {
return `<img src="/dynamic/avatar/${org}" alt="${org}" class="rounded-circle" width="24" height="24">`;
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">+${Object.keys(profile.contributed_to).length - 3}</span>`;
}).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="${profile.avatar_url}" width="35" class="rounded-circle">
<p class="ml-3 d-inline font-body my-auto font-weight-semibold">${profile.handle}</p>
${contributed_to.length ? '<span class="my-auto">Contributes to: </span>' + contributed_to : ''}
</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">
<div class="stat-card d-inline">
<h2>${profile.stats.position}</h2>
<p>contributor</p>
</div>
<div class="stat-card d-inline">
<h2>${profile.stats.success_rate}</h2>
<p>success rate</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 d-inline">
<h2>${profile.stats.earnings ? Number(profile.stats.earnings).toFixed(4) : 0} ETH</h2>
<p>collected from ${profile.stats.completed_bounties} 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>
<p>Bounties completed related to ${profile.keywords.slice(0, 3).toString()}</p>
${profile.related_bounties ?
'<ul><li>// TODO: LOOP THROUGH TITLE</li></ul>'
:
'<p>None</p>'
}
</div>
`;
};

const openContributorPopOver = (contributor, element) => {
let contributorURL = `/api/v0.1/profile/${contributor}`;
function openContributorPopOver(contributor, element) {
const contributorURL = `/api/v0.1/profile/${contributor}`;

if (popoverData.filter(index => index[contributor]).length === 0) {
fetch(contributorURL, { method: 'GET' })
Expand All @@ -65,8 +53,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 +72,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
54 changes: 34 additions & 20 deletions app/dashboard/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1785,29 +1785,43 @@ def profile_details(request, handle):
"""
try:
profile = profile_helper(handle, True)
activity = Activity.objects.filter(profile=profile).order_by('-created_on').first()
count_work_completed = Activity.objects.filter(profile=profile, activity_type='work_done').count()
count_work_in_progress = Activity.objects.filter(profile=profile, activity_type='start_work').count()
count_work_abandoned = Activity.objects.filter(profile=profile, activity_type='stop_work').count()
count_work_removed = Activity.objects.filter(profile=profile, activity_type='bounty_removed_by_funder').count()
except (ProfileNotFoundException, ProfileHiddenException):
raise Http404

bounties = profile.bounties
for word in profile.keywords:
bounties = bounties.keyword(word) # TODO: Is this right

_bounties = []
if bounties :
for bounty in bounties:
_bounty = {
'title': bounty.title,
'url': bounty.get_absolute_url()
}
try:
# feedback = FeedbackEntry.objects.get(bounty=bounty.pk, receiver_profile=profile)
feedback = FeedbackEntry.objects.get() # TODO: remove after testing
if feedback:
_bounty['contibutor_rating'] = feedback.rating
except FeedbackEntry.DoesNotExist:
_bounty['contibutor_rating'] = None
_bounties.append(_bounty)

response = {
'profile': ProfileSerializer(profile).data,
'success_rate': profile.success_rate,
'recent_activity': {
'activity_metadata': activity.metadata,
'activity_type': activity.activity_type,
'created': activity.created
},
'statistics': {
'work_completed': count_work_completed,
'work_in_progress': count_work_in_progress,
'work_abandoned': count_work_abandoned,
'work_removed': count_work_removed
'avatar': profile.avatar_url,
'handle': profile.handle,
# 'contributed_to' : dic(profile.get_who_works_with()) # TODO: make into array
'keywords': profile.keywords,
'related_bounties' : _bounties,
'stats': {
'position': profile.get_contributor_leaderboard_index(),
'completed_bounties': profile.completed_bounties,
'success_rate': profile.success_rate,
'earnings': profile.get_eth_sum()
}
}

return JsonResponse(response, safe=False)


Expand Down Expand Up @@ -2003,15 +2017,15 @@ def profile(request, handle):
currently_working_bounties_count = currently_working_bounties.count()
if currently_working_bounties_count > 0:
paginator = Paginator(currently_working_bounties, 10)

if page > paginator.num_pages:
return HttpResponse(status=204)

context = {}
context['bounties'] = [bounty for bounty in paginator.get_page(page)]
context['bounties'] = [bounty for bounty in paginator.get_page(page)]

return TemplateResponse(request, 'profiles/profile_bounties.html', context, status=status)

else:

all_activities = profile.get_various_activities()
Expand Down

0 comments on commit 6ddff59

Please sign in to comment.