Skip to content

Commit 1c29e57

Browse files
committed
gamification/: Redesign the webpage
The redesigned webpages provides a enhanced UI/UX design to web-page with additional functionality of searching the contributors. Closes coala#260
1 parent c2f5c96 commit 1c29e57

File tree

7 files changed

+579
-56
lines changed

7 files changed

+579
-56
lines changed

community/urls.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from gci.feeds import LatestTasksFeed as gci_tasks_rss
1212
from ci_build.view_log import BuildLogsView
1313
from data.views import ContributorsListView
14-
from gamification.views import index as gamification_index
14+
from gamification.views import GamificationResults
1515
from meta_review.views import ContributorsMetaReview
1616
from inactive_issues.inactive_issues_scraper import inactive_issues_json
1717
from openhub.views import index as openhub_index
@@ -193,7 +193,7 @@ def get_organization():
193193
distill_file='static/unassigned-issues.json',
194194
),
195195
distill_url(
196-
r'gamification/$', gamification_index,
196+
r'gamification/$', GamificationResults.as_view(),
197197
name='community-gamification',
198198
distill_func=get_index,
199199
distill_file='gamification/index.html',

gamification/tests/test_views.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ def test_view_uses_correct_template(self):
2525
def test_all_contributors_on_template(self):
2626
resp = self.client.get(reverse('community-gamification'))
2727
self.assertEqual(resp.status_code, 200)
28-
self.assertTrue(len(resp.context['participants']) == 10)
28+
self.assertTrue(len(resp.context['gamification_results']) == 10)

gamification/views.py

+75-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,79 @@
1-
from django.shortcuts import render
1+
import json
22

3-
from gamification.models import Participant
3+
from django.views.generic import TemplateView
44

5+
from community.views import get_header_and_footer
6+
from gamification.models import Participant, Level, Badge
57

6-
def index(request):
7-
Participant.objects.filter(username__startswith='testuser').delete()
8+
9+
class GamificationResults(TemplateView):
10+
template_name = 'gamification.html'
811
participants = Participant.objects.all()
9-
args = {'participants': participants}
10-
return render(request, 'gamification.html', args)
12+
13+
def get_users_username(self, users):
14+
"""
15+
:param users: A Queryset, with a field username
16+
:return: A list of usernames
17+
"""
18+
usernames = list()
19+
for user in users:
20+
usernames.append(user.username)
21+
return usernames
22+
23+
def group_participants_by_score(self):
24+
"""
25+
Divide the participants according to their scores. For example, if
26+
there are 10 contributors who have different scores and there are
27+
possibly 4 ranges i.e. score_gt 80, score_between (70,80),
28+
score_between (60,70) and score_lt 60. So, divide them and put them
29+
in their respective lists.
30+
:return: A Dict, with key as score_range and value a list of
31+
contributors username
32+
"""
33+
scores = set()
34+
for contrib in self.participants:
35+
scores.add(contrib.score)
36+
37+
scores = list(scores)
38+
scores.sort()
39+
40+
try:
41+
min_score, max_score = scores[0], scores[-1]
42+
except IndexError:
43+
return dict()
44+
45+
difference_bw_groups_score = int(max_score/5)
46+
score_ranges = [
47+
min_score + i * difference_bw_groups_score for i in range(6)
48+
]
49+
score_ranges[-1] += max_score % 5
50+
51+
grouped_participants = dict()
52+
for index, score in enumerate(score_ranges[1:]):
53+
begin_score, end_score = score_ranges[index], score
54+
55+
filtered_participants = self.participants.filter(
56+
score__range=[begin_score, end_score]
57+
)
58+
59+
if begin_score == min_score:
60+
grp_lvl = f'<{end_score}'
61+
elif end_score < max_score:
62+
grp_lvl = f'>={begin_score} and <{end_score}'
63+
else:
64+
grp_lvl = f'>={begin_score}'
65+
66+
grouped_participants[grp_lvl] = json.dumps(
67+
self.get_users_username(filtered_participants)
68+
)
69+
return grouped_participants
70+
71+
def get_context_data(self, **kwargs):
72+
context = super().get_context_data(**kwargs)
73+
context = get_header_and_footer(context)
74+
context['gamification_results'] = self.participants
75+
context['levels'] = Level.objects.all()
76+
context['badges'] = Badge.objects.all()
77+
context['grouped_participants'] = self.group_participants_by_score()
78+
79+
return context

static/css/gamification.css

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
.badge-filter {
2+
width: 150px;
3+
}
4+
5+
.bottom-center {
6+
position: absolute;
7+
width: 100px;
8+
bottom: 2%;
9+
left: 50%;
10+
transform: translate(-50%, -50%);
11+
}
12+
13+
.clear-filters {
14+
cursor: pointer;
15+
}
16+
17+
.gamifier-details {
18+
max-width: 79%;
19+
display: flex;
20+
}
21+
22+
.gamifier-details-part-1,
23+
.gamifier-details-part-2,
24+
.gamifier-details-part-3 {
25+
max-width: 44%;
26+
max-height: 80%;
27+
padding: 10px 5px;
28+
}
29+
30+
.gamifier-card {
31+
width: 100%;
32+
min-height: 380px;
33+
}
34+
35+
.gamifier-image {
36+
width: 20%;
37+
}
38+
39+
.gamifier-image img{
40+
width: 90%;
41+
margin-right: 0;
42+
margin-left: 1%;
43+
min-width: 100px;
44+
45+
}
46+
47+
.github-icon {
48+
color: white;
49+
background-color: black;
50+
border-radius: 100px;
51+
}
52+
53+
.gitlab-icon {
54+
color: #e33834;
55+
border-radius: 100px;
56+
}
57+
58+
.filter-btn {
59+
width: 250px;
60+
margin-top: 3%;
61+
margin-left: 3%;
62+
z-index: 0;
63+
}
64+
65+
.filter-btn .btn-large {
66+
border-radius: 100px;
67+
}
68+
69+
.filter-btn .btn {
70+
text-transform: none;
71+
border-radius: 100px;
72+
box-shadow: 0 0 25px 2px black;
73+
}
74+
75+
.filters-option {
76+
margin: 3% auto auto;
77+
display: none;
78+
-webkit-animation-duration: 1s;
79+
animation-duration: 1s;
80+
-webkit-animation-fill-mode: both;
81+
animation-fill-mode: both;
82+
}
83+
84+
.filter-select-fields {
85+
width: 50%;
86+
min-width: 350px;
87+
box-shadow: 0 0 15px 2px black;
88+
border-radius: 20px;
89+
}
90+
91+
.level-filter {
92+
width: 145px;
93+
}
94+
95+
.no-contribs-found {
96+
display: none;
97+
justify-content: center;
98+
}
99+
100+
.no-contribs-found h5 {
101+
margin: 0;
102+
}
103+
104+
.score-filter {
105+
width: 175px;
106+
}
107+
108+
.social-icons {
109+
font-size: 1.5em;
110+
}
111+
112+
@media only screen and (max-width: 890px){
113+
114+
.gamifier-card {
115+
max-width: 100%;
116+
width: auto;
117+
margin: 10px;
118+
}
119+
120+
.gamifier-details {
121+
max-width: 100%;
122+
padding: 0 10px;
123+
}
124+
125+
.gamifier-image {
126+
margin: auto;
127+
width: 35%;
128+
}
129+
130+
.bottom-center {
131+
bottom: 2%;
132+
}
133+
134+
@media only screen and (max-width: 526px){
135+
136+
.gamifier-details-part-3 {
137+
display: none;
138+
}
139+
140+
.gamifier-details-part-1,
141+
.gamifier-details-part-2 {
142+
max-width: 50%;
143+
}
144+
145+
.gamifier-image {
146+
width: 50%;
147+
}
148+
149+
}
150+
}
151+
152+
@-webkit-keyframes fade-in {
153+
0% {opacity: 0;}
154+
100% {opacity: 1;}
155+
}
156+
157+
@keyframes fade-in {
158+
0% {opacity: 0;}
159+
100% {opacity: 1;}
160+
}
161+
162+
.fade-in {
163+
-webkit-animation-name: fade-in;
164+
animation-name: fade-in;
165+
}

static/js/contributors.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ $(document).ready(function(){
3535
else {
3636
$('.search-results').css('display', 'block');
3737
close_icon.css('display', 'block');
38-
var search_by_login = $('[login^=' + searched_keyword +']');
39-
var search_by_name = $('[name^=' + searched_keyword +']');
38+
var search_by_login = $(
39+
'.contributor-card[login^=' + searched_keyword +']'
40+
);
41+
var search_by_name = $(
42+
'.contributor-card[name^=' + searched_keyword +']'
43+
);
4044
var results_tbody_tr = $('.search-results-tbody tr');
4145
results_tbody_tr.remove();
4246
if(search_by_login.length + search_by_name.length === 0 ){

0 commit comments

Comments
 (0)