Skip to content

Commit 5c1eb67

Browse files
Merge pull request #6571 from topcoder-platform/reskin-tco-badge
TCO badges in member profile
2 parents bb8fd8b + 2e8b7b1 commit 5c1eb67

File tree

23 files changed

+513
-18
lines changed

23 files changed

+513
-18
lines changed

.circleci/config.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,21 +356,21 @@ workflows:
356356
filters:
357357
branches:
358358
only:
359-
- gig-share
359+
- free
360360
# This is alternate dev env for parallel testing
361361
- "build-qa":
362362
context : org-global
363363
filters:
364364
branches:
365365
only:
366-
- reskin-profile-settings
366+
- free
367367
# This is beta env for production soft releases
368368
- "build-prod-beta":
369369
context : org-global
370370
filters:
371371
branches:
372372
only:
373-
- tco23-leaderboards
373+
- free
374374
# This is stage env for production QA releases
375375
- "build-prod-staging":
376376
context : org-global

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ ENV GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY=$GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY
143143
# Optimizely
144144
ENV OPTIMIZELY_SDK_KEY=$OPTIMIZELY_SDK_KEY
145145

146+
ENV GAMIFICATION_ORG_ID=$GAMIFICATION_ORG_ID
147+
146148
################################################################################
147149
# Testing and build of the application inside the container.
148150

__tests__/shared/components/ProfilePage/__snapshots__/index.jsx.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ exports[`renders a full Profile correctly 1`] = `
5858
},
5959
]
6060
}
61+
badges={Object {}}
6162
challenges={null}
6263
clearSubtrackChallenges={[Function]}
6364
copilot={true}
@@ -720,6 +721,7 @@ exports[`renders a full Profile correctly 1`] = `
720721
exports[`renders an empty Profile correctly 1`] = `
721722
<ProfilePage
722723
achievements={Array []}
724+
badges={Object {}}
723725
challenges={null}
724726
clearSubtrackChallenges={[Function]}
725727
copilot={false}

build.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ docker build -t $TAG \
5353
--build-arg OPTIMIZELY_SDK_KEY=$OPTIMIZELY_SDK_KEY \
5454
--build-arg COMMUNITY_APP_URL=$COMMUNITY_APP_URL \
5555
--build-arg GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY=$GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY \
56+
--build-arg GAMIFICATION_ORG_ID=$GAMIFICATION_ORG_ID \
5657
--build-arg VALID_ISSUERS=$VALID_ISSUERS .
5758

5859
# Copies "node_modules" from the created image, if necessary for caching.

config/custom-environment-variables.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,8 @@ module.exports = {
114114
SDK_KEY: 'OPTIMIZELY_SDK_KEY',
115115
},
116116
GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY: 'GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY',
117+
GAMIFICATION: {
118+
ORG_ID: 'GAMIFICATION_ORG_ID',
119+
ENABLE_BADGE_UI: 'GAMIFICATION_ENABLE_BADGE_UI',
120+
},
117121
};

config/default.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,9 @@ module.exports = {
452452
OPTIMIZELY: {
453453
SDK_KEY: '7V4CJhurXT3Y3bnzv1hv1',
454454
},
455-
PLATFORM_SITE_URL: 'https://platform.topcoder-dev.com',
455+
GAMIFICATION: {
456+
ORG_ID: '6052dd9b-ea80-494b-b258-edd1331e27a3',
457+
ENABLE_BADGE_UI: true,
458+
},
456459
PLATFORMUI_SITE_URL: 'https://platform-ui.topcoder-dev.com',
457460
};

src/assets/images/default-award.svg

Lines changed: 17 additions & 0 deletions
Loading
11.9 KB
Loading

src/assets/images/profile/header-overlay.svg

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/shared/actions/page/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import _ from 'lodash';
22
import challengeDetails from './challenge-details';
3+
import memberProfile from './profile';
34

4-
export default _.merge({}, challengeDetails);
5+
export default _.merge({}, challengeDetails, memberProfile);

src/shared/actions/page/profile.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Actions for member profile page.
3+
*/
4+
/* global fetch */
5+
import { redux, config } from 'topcoder-react-utils';
6+
7+
/**
8+
* @static
9+
* @desc Initiates an action that fetch member's badges
10+
* @param {String} handle Member handle.
11+
* @return {Action}
12+
*/
13+
async function getGamificationBadgesInit(handle) {
14+
return { handle };
15+
}
16+
17+
/**
18+
* @static
19+
* @desc Creates an action that gets member's badges
20+
*
21+
* @param {String} handle Topcoder member handle.
22+
* @return {Action}
23+
*/
24+
async function getGamificationBadgesDone(handle) {
25+
try {
26+
const memberInfo = await fetch(`${config.API.V5}/members/${handle}`)
27+
.then(response => response.json());
28+
const badges = await fetch(`${config.API.V5}/gamification/badges/assigned/${memberInfo.userId}?organization_id=${config.GAMIFICATION.ORG_ID}`)
29+
.then(response => response.json());
30+
31+
return {
32+
handle,
33+
badges,
34+
};
35+
} catch (error) {
36+
return {
37+
handle,
38+
error,
39+
};
40+
}
41+
}
42+
43+
export default redux.createActions({
44+
PAGE: {
45+
PROFILE: {
46+
GET_GAMIFICATION_BADGES_INIT: getGamificationBadgesInit,
47+
GET_GAMIFICATION_BADGES_DONE: getGamificationBadgesDone,
48+
},
49+
},
50+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from 'react';
2+
import PT from 'prop-types';
3+
import FallBackAwardIcon from 'assets/images/default-award.svg';
4+
5+
import './styles.scss';
6+
7+
const AwardBadge = ({
8+
title, imageUrl, mimeType, onSelectBadge,
9+
}) => (
10+
<div role="presentation" styleName="awardBadge" onClick={onSelectBadge}>
11+
{
12+
imageUrl ? (
13+
<img src={imageUrl} type={mimeType} alt="award-badge" styleName="image" />
14+
) : (
15+
<FallBackAwardIcon styleName="image" />
16+
)
17+
}
18+
<div styleName="title">
19+
<span>
20+
<div dangerouslySetInnerHTML={{ __html: title }} />
21+
</span>
22+
</div>
23+
</div>
24+
);
25+
26+
AwardBadge.defaultProps = {
27+
title: '',
28+
imageUrl: null,
29+
mimeType: 'image/svg+xml',
30+
};
31+
32+
AwardBadge.propTypes = {
33+
title: PT.string,
34+
imageUrl: PT.string,
35+
mimeType: PT.string,
36+
onSelectBadge: PT.func.isRequired,
37+
};
38+
39+
export default AwardBadge;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
@import "~styles/mixins";
2+
3+
.awardBadge {
4+
background-color: $tc-white;
5+
padding: 16px;
6+
border-radius: 8px;
7+
display: flex;
8+
cursor: pointer;
9+
10+
.image {
11+
width: 48px;
12+
height: 48px;
13+
}
14+
15+
.title {
16+
@include roboto-bold;
17+
$color: $tco-black;
18+
19+
font-size: 14px;
20+
font-weight: 700;
21+
line-height: 16px;
22+
display: flex;
23+
flex-direction: column;
24+
justify-content: center;
25+
margin-left: 8px;
26+
max-width: 130px;
27+
28+
@include xs-to-sm {
29+
max-width: unset;
30+
}
31+
}
32+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from 'react';
2+
import PT from 'prop-types';
3+
import FallBackAwardIcon from 'assets/images/default-award.svg';
4+
5+
import './styles.scss';
6+
7+
const AwatarModal = ({
8+
modalData,
9+
}) => {
10+
const {
11+
title, description, imageUrl,
12+
} = modalData;
13+
14+
return (
15+
<div styleName="awardModal">
16+
{
17+
imageUrl ? (
18+
<img src={imageUrl} alt="award-badge" styleName="image" />
19+
) : (
20+
<FallBackAwardIcon styleName="image" />
21+
)
22+
}
23+
24+
<div styleName="rightContent">
25+
<div styleName="title">
26+
<span>{title}</span>
27+
</div>
28+
29+
<div styleName="description">{description}</div>
30+
31+
</div>
32+
</div>
33+
);
34+
};
35+
36+
AwatarModal.defaultProps = {
37+
modalData: {},
38+
};
39+
40+
AwatarModal.propTypes = {
41+
modalData: PT.shape(
42+
{
43+
title: PT.string,
44+
description: PT.string,
45+
imageUrl: PT.string,
46+
},
47+
),
48+
};
49+
50+
export default AwatarModal;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
@import "~styles/mixins";
2+
@import "~components/Contentful/brackets";
3+
4+
.awardModal {
5+
display: flex;
6+
margin-top: 48px;
7+
8+
@include xs-to-md {
9+
flex-direction: column;
10+
margin-top: 24px;
11+
}
12+
13+
.image {
14+
width: 100px;
15+
height: 100px;
16+
17+
@include xs-to-md {
18+
display: block;
19+
margin: 0 auto;
20+
}
21+
}
22+
23+
.rightContent {
24+
margin-left: 16px;
25+
display: flex;
26+
align-items: flex-start;
27+
justify-content: center;
28+
flex-direction: column;
29+
30+
.title {
31+
@include roboto-bold;
32+
33+
color: $tco-black;
34+
font-size: 20px;
35+
font-weight: 700;
36+
line-height: 26px;
37+
38+
@include xs-to-md {
39+
text-align: center;
40+
}
41+
}
42+
43+
.description {
44+
@include brackets-content;
45+
46+
font-weight: 400;
47+
color: $tco-black;
48+
font-size: 16px;
49+
line-height: 24px;
50+
margin-top: 10px;
51+
}
52+
53+
@include xs-to-md {
54+
margin-top: 24px;
55+
text-align: center;
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)