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

Feat/badges and leaderboard #849

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fc3305f
feat: users & badges admin page UI design
May 20, 2021
70c2c86
feat: leaderboard UI design
May 21, 2021
88735d6
feat: leaderboard pagination base functions
May 21, 2021
1223314
fix: valid alt text required lint errors
May 21, 2021
0a4be59
fix: user-survey model relation points 2 wrong column
Sep 18, 2021
33426d9
chore: number badge seeder file
Sep 18, 2021
da892c1
feat: add user badges migration, seed, & model
Sep 18, 2021
e35c8c6
feat: define relationship between badge and user badges
Sep 18, 2021
41e5332
feat: add events listeners for triggers to award badge to users
Sep 18, 2021
2bcd3f5
feat: add badge awarding tests
Sep 18, 2021
6f39793
feat(frontend): add logic to resolve badge unlocked notification
Sep 18, 2021
dba4e83
add linter for css
brianmarete Sep 23, 2021
8241dd8
css lint fixes
brianmarete Sep 23, 2021
b5c73d9
add badge unlocked component
brianmarete Sep 25, 2021
7751307
Emit socket event when user unlocks a badge
brianmarete Sep 27, 2021
4dccf87
listen to badge unlocked event in frontend
brianmarete Sep 27, 2021
c60109a
fix copy for when user earns a badge
brianmarete Sep 27, 2021
7385fca
Merge branch 'master' into feat/leaderboard-and-awarding-frontend
brianmarete Sep 27, 2021
0e2d4eb
Merge branch 'feat/leaderboard-and-awarding-frontend' into feat/badge…
brianmarete Oct 1, 2021
4f0c601
leaderboard api
brianmarete Oct 1, 2021
f21d626
fix: column reference "metadata" is ambiguous on joined query
Oct 1, 2021
42686c3
feat: use right join to only return users with badges
Oct 1, 2021
5dd4fc2
feat: reduce the amount of user info returned
Oct 1, 2021
fafa37a
Add link to leaderboard in main header
brianmarete Oct 3, 2021
bf7bbae
fix: add missing assets
brianmarete Feb 25, 2022
5799098
feat: top leader component
brianmarete Feb 25, 2022
10da18e
Merge branch 'leaderboard-components' into feat/badges-and-leaderboard
brianmarete Feb 25, 2022
168512e
Merge branch 'master' into feat/badges-and-leaderboard
brianmarete Feb 25, 2022
765cbfa
refactor: create top leader component
brianmarete Mar 16, 2022
9b7c25d
Merge branch 'master' into feat/badges-and-leaderboard
brianmarete Jun 21, 2022
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
5 changes: 5 additions & 0 deletions frontend/app/components/admin/sidenav.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
{{t 'admin.sidenav.manage_badges'}}
</LinkTo>
</li>
<li class="nav-item">
<LinkTo @route="admin.badges.users" class="nav-link">
{{t "admin.sidenav.badge_users"}}
</LinkTo>
</li>
</ul>
</BsCollapse>
</li>
Expand Down
48 changes: 48 additions & 0 deletions frontend/app/components/badge/badge-unlocked.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<BsModal
@open={{this.showBadgeUnlockedModal}}
@closeButton={{true}}
class="badge-unlocked"
@position="center"
@onHide={{this.hideSurveyFillPrompt}} as |Modal|
>
<Modal.body class="text-center">
<div class="title mb-5">
{{t 'badge.unlocked.title'}}
</div>
<div class="points">
{{t 'badge.unlocked.points' numOfPoints=this.badge.points}}
</div>
<div class="badge-icon-container">
{{#if this.badge.iconUrl}}
<img
src="{{this.badge.iconUrl}}"
class="badge-icon"
role="presentation"
alt=""
/>
{{else}}
{{svg-jar 'badge' width='100' height='100'}}
{{/if}}
</div>
<div class="name">
{{this.badge.name}}
</div>
<div class="description">
{{this.badge.description}}
</div>
<div class="actions d-flex justify-content-around">
<BsButton @type="default" class="btn">
{{t 'badge.unlocked.publish'}}
</BsButton>
<BsButton @type="default" class="btn">
{{t 'badge.unlocked.share'}}
</BsButton>
</div>
</Modal.body>
<Modal.footer>
<BsButton @onClick={{Modal.close}} @type="default" class="btn">
{{t 'badge_popup.ok'}}
</BsButton>
</Modal.footer>
</BsModal>
<span {{did-insert this.notificationEventIntercept}}></span>
31 changes: 31 additions & 0 deletions frontend/app/components/badge/badge-unlocked.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import { events } from '../../utils/socket-events';

export default class BadgeUnlockedComponent extends Component {
@service socket;
@service store;
@service router;

@tracked showBadgeUnlockedModal = false;
@tracked badge;

@action
hideBadgeUnlockedModal() {
this.showBadgeUnlockedModal = false;
}

@action
notificationEventIntercept() {
this.socket.socket.on(events.user.badge.unlocked, (notification) => {
setTimeout(async () => {
if (!this.showBadgeUnlockedModal) {
this.badge = await this.store.find('badge', notification.badgeId);
this.showBadgeUnlockedModal = true;
}
}, 3000);
});
}
}
67 changes: 67 additions & 0 deletions frontend/app/components/leaderboard/top-leader.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<div class="d-flex flex-column" local-class="leader-card {{@position}}">
<div class="d-flex justify-content-between">
<div class="d-flex">
<div local-class="image-container">
<img
src="/images/profile-placeholder.gif"
local-class="user-profile-image"
alt=""
/>
</div>
<div class="d-flex flex-column" local-class="details">
<span local-class="name">
Jane Doe
</span>
<span local-class="location">
Nairobi
</span>
</div>
</div>
<div class="d-flex flex-column">
<span local-class="points">
3,000
</span>
<span local-class="points-title">
{{t 'leaderboard.earnedPoints'}}
</span>
</div>
</div>
<hr class="w-100" />
<div class="d-flex justify-content-between">
<div local-class="badges-list">
<div local-class="badge-icon-container">
<img
src="/images/badges/badge1.png"
local-class="badge-icon"
alt=""
role="presentation"
/>
</div>
<div local-class="badge-icon-container">
<img
src="/images/badges/badge1.png"
local-class="badge-icon"
alt=""
role="presentation"
/>
</div>
<div local-class="badge-icon-container">
<img
src="/images/badges/badge1.png"
local-class="badge-icon"
alt=""
role="presentation"
/>
</div>
<div local-class="badge-icon-container">
+5
</div>
</div>
{{!-- <LinkTo @route="profile" class="btn-sm btn btn-primary view-profile-btn">
{{t 'admin.users_and_badges.buttons.view_user'}}
</LinkTo> --}}
</div>
{{#if (eq @position 'first')}}
<div local-class="confetti-one"></div><div local-class="confetti-two"></div>
{{/if}}
</div>
175 changes: 175 additions & 0 deletions frontend/app/components/leaderboard/top-leader.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
$palette: (
primary: #f57010,
white: #ffff,
darkCharcoal: rgba(87, 92, 88, 1),
teach: #32a583,
eucalyptus: #28a745,
);

.leader-card {
width: 422px;
height: 155px;
box-shadow: 0px 3px 30px rgba(0, 0, 0, 0.29);
border-radius: 5px;
margin-left: 8px;
padding: 15px;

.image-container {
max-height: 52px;
max-width: 52px;

img {
box-shadow: 0px 3px 6px rgb(0 0 0 / 7%);
border: 3px solid rgba(255, 255, 255, 1);
}
}

.details {
padding-left: 8px;

.name {
font-size: 19px;
color: map-get($palette, darkCharcoal);
font-weight: 500;
}

.location {
font-size: 15px;
color: map-get($palette, darkCharcoal);
}
}

.points {
color: map-get($palette, eucalyptus);
font-weight: 700;
font-size: 19px;
}

.points-title {
font-size: 15px;
color: map-get($palette, darkCharcoal);
}
}

.leader-card {
.badges-list {
display: flex;
position: relative;

.badge-icon-container {
width: 30px;
height: 30px;
position: absolute;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: white;
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.05);
border: 3px solid rgba(255, 255, 255, 1);
font-size: 11px;
font-weight: 700;

.badge-icon {
width: 100%;
height: 100%;
}

&:nth-child(2) {
margin-left: 20px;
}

&:nth-child(3) {
margin-left: 40px;
}

&:nth-child(4) {
margin-left: 60px;
}
}
}
}

.leader-card.first {
height: 180px;
background-repeat: no-repeat;
background-position: 0% 0%;
background-origin: padding-box;
background-image: linear-gradient(
119deg,
rgba(126, 87, 194, 1) 0%,
rgba(171, 71, 188, 1) 100%
);
background-color: transparent;
background-clip: padding-box;

.image-container {
max-height: 62px;
max-width: 62px;
}

.name,
.location,
.points,
.points-title {
color: map-get($palette, white);
}

.bottom {
padding-bottom: 10px;
padding-top: 10px;
}

.view-profile-btn {
background-color: map-get($palette, white);
border-color: map-get($palette, white);
color: map-get($palette, darkCharcoal);
}
}

.first {
position: relative;

.confetti-one {
position: absolute;
background-image: url('/images/confetti.svg');
width: 70%;
height: 55px;
background-size: cover;
top: -40px;
left: -30px;
background-repeat: no-repeat;
z-index: -1;
}

.confetti-two {
position: absolute;
background-image: url('/images/confetti-1.svg');
width: 70%;
height: 55px;
background-size: cover;
top: -40px;
right: -60px;
background-repeat: no-repeat;
z-index: -1;
}
}

.image-container {
max-width: 40px;
max-height: 40px;

.user-profile-image {
width: 100%;
height: 100%;
border-radius: 50%;
}
}

.view-profile-btn {
font-size: 13px;
padding-bottom: 4px;
padding-top: 4px;
}
5 changes: 5 additions & 0 deletions frontend/app/components/main-header.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
{{t "buttons.teach"}}
</LinkTo>
</li>
<li class="nav-item text-{{this.config.content.APP.header_text}}">
<LinkTo @route="leaderboard" class="nav-link" data-toggle="collapse" data-target="#mainTopNav.show">
{{t "buttons.leaderboard"}}
</LinkTo>
</li>
<li class="nav-item text-{{this.config.content.APP.header_text}}">
<a href="https://discord.gg/tT9Ug6D" class="nav-link forum-link-item" rel="noopener">
{{t "buttons.community"}}
Expand Down
16 changes: 8 additions & 8 deletions frontend/app/components/survey/prompt-popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ export default class SurveyPromptPopupComponent extends Component {

@action
notificationEventIntercept() {
this.socket.socket.on(events.user.notification.created, (notification) => {
setTimeout(async () => {
if (!this.showSurveyFillPrompt) {
this.survey = await this.store.find('survey', notification.itemId);
this.showSurveyFillPrompt = true;
}
}, 3000);
});
// this.socket.socket.on(events.user.notification.created, (notification) => {
// setTimeout(async () => {
// if (!this.showSurveyFillPrompt) {
// this.survey = await this.store.find('survey', notification.itemId);
// this.showSurveyFillPrompt = true;
// }
// }, 3000);
// });
}

@action
Expand Down
Loading