Skip to content

Commit d879c2f

Browse files
authored
Merge pull request #228 from royshouvik/fix-tc-1186
Fix bug 1186
2 parents e7e7467 + edba966 commit d879c2f

File tree

2 files changed

+74
-112
lines changed

2 files changed

+74
-112
lines changed

components/ChallengeStatus/ChallengeStatus.jsx

+42-102
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import React, { Component, PropTypes } from 'react';
2-
import fetch from 'isomorphic-fetch';
32
import moment from 'moment';
4-
import _ from 'lodash';
53
import LeaderboardAvatar from '../LeaderboardAvatar/LeaderboardAvatar';
64
import ChallengeProgressBar from '../ChallengeProgressBar/ChallengeProgressBar';
75
import ProgressBarTooltip from '../ChallengeCard/Tooltips/ProgressBarTooltip';
@@ -15,7 +13,6 @@ import './ChallengeStatus.scss';
1513
// Constants
1614
const ID_LENGTH = 6;
1715
const MAX_VISIBLE_WINNERS = 3;
18-
const MOCK_PHOTO = 'https://acrobatusers.com/assets/images/template/author_generic.jpg';
1916
const STALLED_MSG = 'Stalled';
2017
const DRAFT_MSG = 'In Draft';
2118
const STALLED_TIME_LEFT_MSG = 'Challenge is currently on hold';
@@ -149,13 +146,15 @@ const getTimeToGo = (start, end) => {
149146
* Returns an user profile object as expected by the UserAvatarTooltip
150147
* @param {String} handle
151148
*/
152-
function getSampleProfile(user) {
153-
const { handle } = user;
149+
function getProfile(user) {
150+
const { handle, placement } = user;
151+
const photoLink = user.photoURL || `i/m/${handle}.jpeg`;
154152
return {
155153
handle,
154+
placement,
156155
country: '',
157156
memberSince: '',
158-
photoLink: `i/m/${handle}.jpeg`,
157+
photoLink,
159158
ratingSummary: [],
160159
};
161160
}
@@ -173,28 +172,48 @@ class ChallengeStatus extends Component {
173172
DS_CHALLENGE_URL,
174173
FORUM_URL,
175174
};
176-
this.handleHover = this.handleHover.bind(this);
177-
this.getDevelopmentWinners = this.getDevelopmentWinners.bind(this);
178-
this.getDesignWinners = this.getDesignWinners.bind(this);
175+
179176
this.registrantsLink = this.registrantsLink.bind(this);
180177
}
181178

182179
renderLeaderboard() {
183180
const { challenge } = this.props;
184181
const { DS_CHALLENGE_URL, CHALLENGE_URL } = this.state;
185182
const { id, track } = challenge;
183+
186184
const challengeURL = track === 'DATA_SCIENCE' ? DS_CHALLENGE_URL : CHALLENGE_URL;
187-
const leaderboard = this.state.winners && this.state.winners.map(winner => (
188-
<div className="avatar-container" key={winner.handle}>
189-
<UserAvatarTooltip user={getSampleProfile(winner)}>
190-
<LeaderboardAvatar member={winner} />
191-
</UserAvatarTooltip>
192-
</div>
193-
));
185+
let winners = challenge.winners && challenge.winners.filter(winner => winner.type === 'final')
186+
.map(winner => ({
187+
handle: winner.handle,
188+
position: winner.placement,
189+
photoURL: winner.photoURL || `${this.props.MAIN_URL}/i/m/${winner.handle}.jpeg`,
190+
}));
191+
192+
if (winners && winners.length > MAX_VISIBLE_WINNERS) {
193+
const lastItem = {
194+
handle: `+${winners.length - MAX_VISIBLE_WINNERS}`,
195+
isLastItem: true,
196+
};
197+
winners = winners.slice(0, MAX_VISIBLE_WINNERS);
198+
winners.push(lastItem);
199+
}
200+
201+
const leaderboard = winners && winners.map((winner) => {
202+
if (winner.isLastItem) {
203+
return <LeaderboardAvatar key={winner.handle} member={winner} url={`${this.props.detailLink}#winner`} />;
204+
}
205+
const userProfile = getProfile(winner);
206+
return (
207+
<div className="avatar-container" key={winner.handle}>
208+
<UserAvatarTooltip user={userProfile}>
209+
<LeaderboardAvatar member={winner} />
210+
</UserAvatarTooltip>
211+
</div>);
212+
});
194213
return leaderboard || (
195-
<span className="winners" onMouseEnter={this.handleHover}>
196-
<a href={`${challengeURL}${id}`}>Winners</a>
197-
</span>);
214+
<span className="winners">
215+
<a href={`${challengeURL}${id}#winner`}>Results</a>
216+
</span>);
198217
}
199218

200219
renderRegisterButton() {
@@ -334,16 +353,15 @@ class ChallengeStatus extends Component {
334353
<div>
335354
{this.renderLeaderboard()}
336355
<span className="challenge-stats">
337-
<span>
356+
<span className="num-reg">
338357
<Tooltip content={numRegistrantsTipText(challenge.numRegistrants)}>
339358
<a className="num-reg past" href={this.registrantsLink(challenge, MM_REG)}>
340359
<RegistrantsIcon /> <span className="number">{challenge.numRegistrants}</span>
341360
</a>
342361
</Tooltip>
343362
</span>
344-
<span>
363+
<span className="num-sub">
345364
<Tooltip content={numSubmissionsTipText(challenge.numSubmissions)}>
346-
347365
<a className="num-sub past" href={this.registrantsLink(challenge, MM_SUB)}>
348366
<SubmissionsIcon /> <span className="number">{challenge.numSubmissions}</span>
349367
</a>
@@ -360,86 +378,6 @@ class ChallengeStatus extends Component {
360378
);
361379
}
362380

363-
getDevelopmentWinners(challengeId) {
364-
return new Promise((resolve, reject) => {
365-
fetch(`${this.props.config.API_URL_V2}/develop/challenges/${challengeId}`)
366-
.then(res => res.json())
367-
.then((data) => {
368-
let winners = data.submissions.filter(sub => sub.placement)
369-
.map(winner => ({
370-
handle: winner.handle,
371-
position: winner.placement,
372-
photoURL: MOCK_PHOTO,
373-
}));
374-
winners = _.uniqWith(winners, _.isEqual);
375-
if (winners.length > MAX_VISIBLE_WINNERS) {
376-
const lastItem = {
377-
handle: `+${winners.length - MAX_VISIBLE_WINNERS}`,
378-
};
379-
winners = winners.slice(0, MAX_VISIBLE_WINNERS);
380-
winners.push(lastItem);
381-
}
382-
resolve(winners);
383-
})
384-
.catch(err => reject(err));
385-
});
386-
}
387-
388-
getDesignWinners(challengeId) {
389-
return new Promise((resolve, reject) => {
390-
fetch(`${this.props.config.API_URL_V2}/design/challenges/result/${challengeId}`)
391-
.then(res => res.json())
392-
.then((data) => {
393-
let winners = data.results.filter(sub => sub.placement)
394-
.map(winner => ({
395-
handle: winner.handle,
396-
position: winner.placement,
397-
photoURL: MOCK_PHOTO,
398-
}));
399-
winners = _.uniqWith(winners, _.isEqual);
400-
if (winners.length > MAX_VISIBLE_WINNERS) {
401-
const lastItem = {
402-
handle: `+${winners.length - MAX_VISIBLE_WINNERS}`,
403-
};
404-
winners = winners.slice(0, MAX_VISIBLE_WINNERS);
405-
winners.push(lastItem);
406-
}
407-
resolve(winners);
408-
})
409-
.catch(err => reject(err));
410-
});
411-
}
412-
413-
414-
getWinners(challengeType, challengeId) {
415-
switch (challengeType) {
416-
case 'develop':
417-
return this.getDevelopmentWinners(challengeId);
418-
case 'design':
419-
return this.getDesignWinners(challengeId);
420-
default:
421-
return this.getDevelopmentWinners(challengeId);
422-
}
423-
}
424-
425-
/**
426-
* Get the list of winners when the user hovers
427-
* over the status
428-
*/
429-
handleHover() {
430-
if (!this.state.winners) {
431-
const { challenge } = this.props;
432-
const { id, track } = challenge;
433-
434-
// We don't have the API for data science challenge
435-
if (track === 'DATA_SCIENCE') {
436-
return;
437-
}
438-
const results = this.getWinners(track.toLowerCase(), id);
439-
results.then(winners => this.setState({ winners }));
440-
}
441-
}
442-
443381
render() {
444382
const { challenge } = this.props;
445383
const status = challenge.status === 'COMPLETED' ? 'completed' : '';
@@ -456,12 +394,14 @@ ChallengeStatus.defaultProps = {
456394
config: {},
457395
detailLink: '',
458396
sampleWinnerProfile: undefined,
397+
MAIN_URL: process.env.MAIN_URL,
459398
};
460399

461400
ChallengeStatus.propTypes = {
462401
challenge: PropTypes.object,
463402
config: PropTypes.object,
464403
detailLink: PropTypes.string,
404+
MAIN_URL: PropTypes.string,
465405
};
466406

467407
export default ChallengeStatus;
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,50 @@
1-
import React from 'react'
1+
import React, { Component } from 'react'
22
import './LeaderboardAvatar.scss'
33

44
// Constants
55
const VISIBLE_CHARACTERS = 3
6+
const MOCK_PHOTO = 'https://acrobatusers.com/assets/images/template/author_generic.jpg'
67

7-
function LeaderboardAvatar ({member, domain}) {
8-
return (
9-
<a href={`//${domain}/members/${member.handle}`} className={`leaderboard-avatar ${member.position || member.isSmr ? 'dark-gray' : 'light-gray'}`}>
10-
{member.photoURL ? <img src={member.photoURL} className="member-icon"/> : member.handle.slice(0, VISIBLE_CHARACTERS)}
11-
<span className={member.position ? `placement placement-${member.position}` : 'hidden'}>
12-
{member.position}
13-
</span>
14-
</a>
15-
)
8+
class LeaderboardAvatar extends Component {
9+
constructor(props) {
10+
super(props)
11+
this.state = {
12+
member: props.member,
13+
}
14+
this.handleError = this.handleError.bind(this)
15+
}
16+
17+
handleError() {
18+
const { member } = this.state
19+
member.photoURL = MOCK_PHOTO
20+
this.setState({ member })
21+
}
22+
23+
render() {
24+
const { domain, url } = this.props
25+
const { member } = this.state
26+
const targetURL = url ? url : `//${domain}/members/${member.handle}`
27+
return (
28+
<a href={targetURL} className={`leaderboard-avatar ${member.position || member.isSmr ? 'dark-gray' : 'light-gray'}`}>
29+
{member.photoURL ? <img src={member.photoURL} className="member-icon" onError={this.handleError} /> : member.handle.slice(0, VISIBLE_CHARACTERS)}
30+
<span className={member.position ? `placement placement-${member.position}` : 'hidden'}>
31+
{member.position}
32+
</span>
33+
</a>
34+
)
35+
}
1636
}
1737

1838
LeaderboardAvatar.propTypes = {
1939
member: React.PropTypes.object,
2040
domain: React.PropTypes.string,
41+
url: React.PropTypes.string,
2142
}
2243

2344
LeaderboardAvatar.defaultProps = {
2445
member: {},
2546
domain: process.env.domain,
47+
url: ''
2648
}
2749

2850
export default LeaderboardAvatar

0 commit comments

Comments
 (0)