Skip to content

Commit c7dbc75

Browse files
authored
Merge pull request #2219 from codalab/profile-page
Add competitions organized in profile page
2 parents dd45024 + 4a38e06 commit c7dbc75

8 files changed

Lines changed: 170 additions & 27 deletions

File tree

src/apps/profiles/views.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from api.serializers.profiles import UserSerializer, OrganizationDetailSerializer, OrganizationEditSerializer, \
2121
UserNotificationSerializer
22+
from api.serializers.competitions import CompetitionSerializerSimple
2223
from .forms import SignUpForm, LoginForm, ActivationForm
2324
from .models import User, DeletedUser, Organization, Membership
2425
from oidc_configurations.models import Auth_Organization
@@ -67,7 +68,23 @@ class UserDetailView(LoginRequiredMixin, DetailView):
6768

6869
def get_context_data(self, **kwargs):
6970
context = super().get_context_data(**kwargs)
70-
context['serialized_user'] = json.dumps(UserSerializer(self.get_object()).data)
71+
user = self.get_object()
72+
user_data = UserSerializer(user).data
73+
# Fetch competitions organized by this user (as owner or collaborator)
74+
organized_qs = (
75+
Competition.objects
76+
.filter(
77+
Q(created_by=user) | Q(collaborators=user),
78+
published=True,
79+
)
80+
.distinct()
81+
.order_by("-created_when")
82+
)
83+
# Serialize into the same shape your public-list cards expect
84+
user_data["competitions_organized"] = CompetitionSerializerSimple(
85+
organized_qs, many=True, context={"request": self.request}
86+
).data
87+
context["serialized_user"] = json.dumps(user_data).replace("</", "<\\/")
7188
return context
7289

7390

src/static/riot/competitions/public-list.tag

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@
182182
self.update_competitions_list(1)
183183
}
184184

185-
186185
self.one("mount", function () {
187186
const urlParams = new URLSearchParams(window.location.search)
188187

src/static/riot/profiles/organization_create.tag

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
</div>
5959

6060
<script>
61-
self = this
61+
var self = this
6262
self.org_photo = null
6363

6464
self.one("mount", function () {

src/static/riot/profiles/organization_edit.tag

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
</form>
6464
</div>
6565
<script>
66-
self = this
66+
var self = this
6767
self.organization = organization
6868
self.original_org_photo_name = typeof self.organization.photo !== 'undefined' ? null : self.organization.photo.replace(/\\/g, '/').replace(/.*\//, '')
6969
self.original_org_photo = self.organization.photo

src/static/riot/profiles/organization_invite.tag

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103
</div>
104104
</div>
105105
<script>
106-
self = this
106+
var self = this
107107
self.state = 'loading'
108108
self.queryString = window.location.search
109109
self.urlParams = new URLSearchParams(self.queryString)

src/static/riot/profiles/profile_account.tag

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
</div>
5252

5353
<script>
54-
self = this;
54+
var self = this;
5555
self.user = user;
5656

5757
self.isDeleteAccountSubmitButtonDisabled = true;

src/static/riot/profiles/profile_detail.tag

Lines changed: 147 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,64 @@
22
<!-- HTML -->
33
<div class="background">
44
<div id="profile_wrapper" class="ui two column doubling stackable grid container">
5+
6+
<!-- First Column -->
57
<div class="column">
68
<div if="{!selected_user.photo}"><img id="avatar" class="ui centered small rounded image" src="/static/img/user-avatar.png"></div>
79
<div if="{selected_user.photo}"><img id="avatar" class="ui centered small rounded image" src="{selected_user.photo}"></div>
810

9-
<!-- Competition Divider -->
10-
<div class="ui horizontal divider">Organizations</div>
11-
12-
<!-- Competition Cards -->
13-
<div each="{org in selected_user.organizations}" class="ui fluid card">
14-
<div class="comp_card center aligned image">
15-
<div class="comp_header center aligned header content">
16-
<div class="comp_name">{org.name}</div>
17-
<img class="ui centered mini circular image"
18-
src="{org.photo}">
11+
<!-- Organizations -->
12+
<div if="{selected_user.organizations && selected_user.organizations.length}">
13+
<div class="ui horizontal divider">Organizations</div>
14+
15+
<div each="{org in selected_user.organizations}" class="ui fluid card">
16+
<div class="comp_card center aligned image">
17+
<div class="comp_header center aligned header content">
18+
<div class="comp_name">{org.name}</div>
19+
<img class="ui centered mini circular image"
20+
src="{org.photo}">
21+
</div>
1922
</div>
20-
</div>
21-
<div class="content">
22-
<div class="description">
23-
<p>{ org.description.length > 225 ? org.description.substring(0, 222) + "..." : org.description}</p>
23+
<div class="content">
24+
<div class="description">
25+
<p>{ org.description.length > 225 ? org.description.substring(0, 222) + "..." : org.description}</p>
26+
</div>
27+
</div>
28+
<div class="right aligned extra content">
29+
<a class="status" href="/profiles/organization/{org.id}/">
30+
View Organization
31+
<i class="angle right icon"></i>
32+
</a>
2433
</div>
2534
</div>
26-
<div class="right aligned extra content">
27-
<a class="status" href="/profiles/organization/{org.id}/">
28-
View Organization
29-
<i class="angle right icon"></i>
30-
</a>
35+
</div>
36+
37+
<!-- Competitions Organized -->
38+
<div if="{selected_user.competitions_organized && selected_user.competitions_organized.length}">
39+
<div class="ui horizontal divider">Competitions Organized</div>
40+
41+
<div each="{competition in selected_user.competitions_organized}">
42+
<!-- tile-wrapper from public-list.tag -->
43+
<div class="tile-wrapper">
44+
<div class="ui square tiny bordered image img-wrapper">
45+
<img src="{competition.logo_icon ? competition.logo_icon : competition.logo}" loading="lazy">
46+
</div>
47+
<a class="link-no-deco" href="/competitions/{competition.id}">
48+
<div class="comp-info">
49+
<h4 class="heading">{competition.title}</h4>
50+
<p class="comp-description">{ pretty_description(competition.description) }</p>
51+
</div>
52+
</a>
53+
<div class="comp-stats">
54+
{pretty_date(competition.created_when)}
55+
<div if="{!competition.reward && ! competition.report}" class="ui divider"></div>
56+
<div>
57+
<span if="{competition.reward}"><img width="30" height="30" src="/static/img/trophy.png"></span>
58+
<span if="{competition.report}"><a href="{competition.report}" target="_blank"><img width="30" height="30" src="/static/img/paper.png"></a></span>
59+
</div>
60+
<strong>{competition.participants_count}</strong> Participants
61+
</div>
62+
</div>
3163
</div>
3264
</div>
3365
</div>
@@ -95,7 +127,6 @@
95127
<!-- Empty About Message -->
96128
<span if="{!selected_user.location && !selected_user.title}" class="text-placeholder">Update your profile to show your job title and location here.</span>
97129

98-
99130

100131
<!-- Section Bio -->
101132
<div id="horiz-margin" class="ui horizontal divider">Bio</div>
@@ -156,8 +187,19 @@
156187
</div>
157188
</div>
158189
</div>
190+
191+
<!-- Script -->
159192
<script>
193+
var self = this
160194
self.selected_user = selected_user
195+
196+
self.pretty_date = function (date_string) {
197+
return !!date_string ? luxon.DateTime.fromISO(date_string).toLocaleString(luxon.DateTime.DATE_FULL) : ''
198+
}
199+
200+
self.pretty_description = function (description) {
201+
return description.substring(0, 120) + (description.length > 120 ? '...' : '') || ''
202+
}
161203
</script>
162204

163205
<!-- CSS Styling -->
@@ -253,5 +295,90 @@
253295
.value
254296
font-size 15px
255297
margin-left 10px
298+
299+
/* Competition cards (from public-list.tag) */
300+
.link-no-deco
301+
all unset
302+
text-decoration none
303+
cursor pointer
304+
width 100%
305+
306+
.tile-wrapper
307+
border solid 1px gainsboro
308+
display inline-flex
309+
background-color #fff
310+
transition all 75ms ease-in-out
311+
color #909090
312+
width 100%
313+
margin-bottom 6px
314+
315+
.tile-wrapper:hover
316+
box-shadow 0 3px 4px -1px #cac9c9ff
317+
transition all 75ms ease-in-out
318+
background-color #e6edf2
319+
border solid 1px #a5b7c5
320+
321+
.comp-stats
322+
background-color #344d5e
323+
transition background-color 75ms ease-in-out
324+
325+
.img-wrapper
326+
padding 5px
327+
align-self center
328+
329+
.img-wrapper img
330+
max-height 60px !important
331+
max-width 60px !important
332+
margin 0 auto
333+
334+
.comp-info
335+
flex 1
336+
padding 0 10px
337+
338+
.comp-info .heading
339+
text-align left
340+
padding 5px
341+
color #1b1b1b
342+
margin-bottom 0
343+
344+
.comp-info .comp-description
345+
text-align left
346+
font-size 13px
347+
line-height 1.15em
348+
margin 0.35em
349+
350+
.organizer
351+
font-size 13px
352+
text-align left
353+
margin 0.35em
354+
355+
.comp-stats
356+
background #405e73
357+
color #e8e8e8
358+
padding 10px
359+
text-align center
360+
font-size 12px
361+
width 140px
362+
363+
.loading-indicator
364+
display flex
365+
align-items center
366+
padding 10px 0
367+
width 100%
368+
margin 0 auto
369+
370+
.spinner
371+
border 4px solid rgba(0,0,0,.1)
372+
width 28px
373+
height 28px
374+
border-radius 50%
375+
border-top-color #3498db
376+
animation spin 1s ease-in-out infinite
377+
378+
@keyframes spin
379+
0%
380+
transform rotate(0deg)
381+
100%
382+
transform rotate(360deg)
256383
</style>
257384
</profile-detail>

src/static/riot/profiles/profile_edit.tag

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
</div>
7474

7575
<script>
76-
self = this
76+
var self = this
7777
self.selected_user = selected_user
7878
self.photo = self.selected_user.photo
7979
delete self.selected_user.photo

0 commit comments

Comments
 (0)