From 75e8c6faddf77cfb7476adc483fd27c39fe057e6 Mon Sep 17 00:00:00 2001 From: Sanjeev Singh Date: Wed, 3 Jul 2019 17:33:03 +0530 Subject: [PATCH] Modify challenge overview page according to current theme(#142) --- .../challenge/challenge.component.html | 186 ++++++++++++++---- .../challenge/challenge.component.scss | 160 +++++---------- .../challenge/challenge.component.ts | 171 +++++++++++++++- .../challengeoverview.component.html | 27 ++- .../challengeoverview.component.scss | 23 +-- .../challengeoverview.component.ts | 51 ++++- .../challengesubmissions.component.ts | 9 +- .../components/profile/profile.component.ts | 13 +- .../teamlist/teamlist.component.ts | 17 +- .../utility/confirm/confirm.component.html | 15 +- .../utility/confirm/confirm.component.scss | 11 +- .../utility/input/input.component.html | 2 +- .../utility/input/input.component.ts | 5 + .../utility/modal/modal.component.html | 11 +- .../utility/modal/modal.component.spec.ts | 6 +- .../utility/modal/modal.component.ts | 31 ++- src/app/services/challenge.service.ts | 39 ++++ src/app/services/endpoints.service.ts | 17 ++ src/index.html | 3 +- src/styles/base.scss | 181 +++++++++++++++-- src/styles/variables.scss | 17 +- 21 files changed, 785 insertions(+), 210 deletions(-) diff --git a/src/app/components/challenge/challenge.component.html b/src/app/components/challenge/challenge.component.html index 2a003e651..918d3b82a 100644 --- a/src/app/components/challenge/challenge.component.html +++ b/src/app/components/challenge/challenge.component.html @@ -1,42 +1,156 @@ -
-
-
- -
-
-
-
-
- +
+
+
+
+
+
+
+ +
+
+
+
+

+ + + {{challenge['title']}} + + +   + + + + + + + + +
+ + Organized by: + + {{challenge['creator']['team_name']}} + + + + Organized by: + {{challenge['creator']['team_name']}} + +
+ + + {{publishChallenge.state}} + + + + +

+
+
+
+ +
+
+ +
-
-
- - {{challenge['title']}} - - - - {{stars['count']}} - - -
-
- Organized by: {{challenge['creator']['team_name']}} -
-
- - -
-
diff --git a/src/app/components/challenge/challenge.component.scss b/src/app/components/challenge/challenge.component.scss index c65d0804c..af71015aa 100644 --- a/src/app/components/challenge/challenge.component.scss +++ b/src/app/components/challenge/challenge.component.scss @@ -2,123 +2,63 @@ @import './mixins.scss'; .challenge-container { - - width:90%; + width: 83.5%; margin: 0 auto; - margin-top:50px; margin-bottom:50px; - .challenge-image-container { - z-index:5; - margin: 0 auto; - width:100%; - height:300px; - border-radius:10px; - background:rgba(0,0,0,0.5); - position:relative; - @include box-shadow(0px, 0px, 5px, 0px, $overlay-light); - .challenge-cover-image { - border-radius:10px; - width:100%; - height:300px; - } - } - .challenge-content-container { - position:relative; - z-index:10; - @include box-shadow(0px, 0px, 15px, 5px, $overlay-light); - border-radius:10px; - width:80%; - margin:0 auto; - margin-top:-200px; - color:$gray-darker; - background:white; - .challenge-header { - text-align:center; - .challenge-img-parent { - position: relative; - display:inline-table; - width: 150px; - height: 100px; - position: relative; - @include box-shadow(0px, 0px, 5px, 0px, $overlay-light); - margin:20px; - text-align:center; - .challenge-img-wrap { - display: table-cell; - position: relative; - vertical-align:middle; - margin:0 auto; - .challenge-img { - max-width: 150px; - max-height: 100px; - display: inline-block; - position: relative; - } - } - - } - - .challenge-title { - text-align: center; - margin:10px; - .stars { - font-size:$fs-12; - color:white; - background:$red-light; - border-radius:5px; - padding:5px; - position: absolute; - right: 50px; - margin-top:5px; - padding: 3px 10px 3px 10px; - &.is-starred { - color: $yellow-light; - } - i { - margin-right: 10px; - } - &.is-clickable { - cursor:pointer; - } - } - .title { - font-size: $fs-24; - color:$gray-darker; - } - } - .challenge-host { - display: inline-block; - margin: 10px; - font-weight: $fw-light; - font-size: $fs-18; - color: $gray-dark; - span { - color: $gray-darker; - } - } - } - } + padding-top: 70px; } + @include screen-medium { .challenge-container { - .challenge-content-container { - width:90%; - } + width: 90%; } } @include screen-small { - .challenge-container { - .challenge-content-container { - width:90%; - .challenge-header { - .challenge-title { - .stars { - right: 5px; - margin-top: -25px; - } - } - } - } - } + .challenge-container { + width: 95%; + } +} + +.mid-container { + background-color: #fafafa; +} + +.card-content p { + padding-bottom: 10px; +} + +.top-card-container { + padding: 40px 40px 0 40px; +} + +.toggle-participation-text { + display: inline-block; + padding-left: 10px; +} + +.top-card-container { + .stars { + cursor: default; + &.is-clickable { + cursor:pointer; + } + } + + .card-img-row { + margin-bottom: 20px; + padding: 0 15px 0 15px; + } + + .card-tab-row { + padding: 0 12px 0 12px; + } +} + +.top-card-container ul.inline-list { + margin: 0px; +} +.top-card-container ul.inline-list li { + margin: 0 40px 1.5% 0; + min-height: 40px; } diff --git a/src/app/components/challenge/challenge.component.ts b/src/app/components/challenge/challenge.component.ts index 1c7e0ff9d..1f35c85db 100644 --- a/src/app/components/challenge/challenge.component.ts +++ b/src/app/components/challenge/challenge.component.ts @@ -4,6 +4,7 @@ import { AuthService } from '../../services/auth.service'; import { ApiService } from '../../services/api.service'; import { GlobalService } from '../../services/global.service'; import { ChallengeService } from '../../services/challenge.service'; +import { EndpointsService } from '../../services/endpoints.service'; /** * Component Class @@ -30,6 +31,19 @@ export class ChallengeComponent implements OnInit { */ isStarred = false; + /** + * Is challenge host + */ + isChallengeHost = false; + + /** + * publish challenge state and it's icon + */ + publishChallenge = { + 'state': 'Not Published', + 'icon': 'fa fa-eye-slash red-text' + }; + /** * Is participated in Challenge */ @@ -50,6 +64,11 @@ export class ChallengeComponent implements OnInit { */ isLoggedIn: any = false; + /** + * To call the API inside modal for editing the challenge details + */ + apiCall: any; + /** * Constructor. * @param route ActivatedRoute Injection. @@ -57,11 +76,13 @@ export class ChallengeComponent implements OnInit { * @param authService AuthService Injection. * @param globalService GlobalService Injection. * @param apiService Router Injection. + * @param endpointsService EndpointsService Injection. * @param challengeService ChallengeService Injection. */ constructor(private router: Router, private route: ActivatedRoute, private apiService: ApiService, private globalService: GlobalService, - private challengeService: ChallengeService, private authService: AuthService) { } + private challengeService: ChallengeService, private authService: AuthService, + private endpointsService: EndpointsService) { } /** * Component on initialized @@ -85,6 +106,13 @@ export class ChallengeComponent implements OnInit { this.challengeService.currentParticipationStatus.subscribe(status => { this.isParticipated = status; }); + this.challengeService.isChallengeHost.subscribe(status => { + this.isChallengeHost = status; + }); + this.challengeService.currentChallengePublishState.subscribe(publishChallenge => { + this.publishChallenge.state = publishChallenge.state; + this.publishChallenge.icon = publishChallenge.icon; + }); } /** @@ -93,6 +121,147 @@ export class ChallengeComponent implements OnInit { starToggle(challengeId) { if (this.isLoggedIn) { this.challengeService.starToggle(challengeId); + } else { + this.globalService.showToast('error', 'Please login to star the challenge!', 5); + } + } + + /** + * Publish challenge click function + */ + togglePublishChallengeState() { + const SELF = this; + let toggleChallengePublishState, isPublished; + if (this.publishChallenge.state === 'Published') { + toggleChallengePublishState = 'private'; + isPublished = false; + } else { + toggleChallengePublishState = 'public'; + isPublished = true; } + + SELF.apiCall = () => { + const BODY = JSON.stringify({ + 'published': isPublished + }); + SELF.apiService.patchUrl( + SELF.endpointsService.editChallengeDetailsURL(SELF.challenge.creator.id, SELF.challenge.id), + BODY + ).subscribe( + data => { + if (isPublished) { + this.publishChallenge.state = 'Published'; + this.publishChallenge.icon = 'fa fa-eye green-text'; + } else { + this.publishChallenge.state = 'Not Published'; + this.publishChallenge.icon = 'fa fa-eye-slash red-text'; + } + SELF.globalService.showToast('success', 'The challenge was successfully made ' + toggleChallengePublishState, 5); + }, + err => { + SELF.globalService.handleApiError(err, true); + SELF.globalService.showToast('error', err); + }, + () => console.log('PUBLISH-CHALLENGE-UPDATE-FINISHED') + ); + }; + + const PARAMS = { + title: 'Make this challenge ' + toggleChallengePublishState + '?', + content: '', + confirm: 'Yes, I\'m sure', + deny: 'No', + confirmCallback: SELF.apiCall + }; + SELF.globalService.showConfirm(PARAMS); + } + + /** + * Edit challenge title function + */ + editChallengeTitle() { + const SELF = this; + + SELF.apiCall = (params) => { + const BODY = JSON.stringify(params); + SELF.apiService.patchUrl( + SELF.endpointsService.editChallengeDetailsURL(SELF.challenge.creator.id, SELF.challenge.id), + BODY + ).subscribe( + data => { + SELF.challenge.title = data.title; + SELF.globalService.showToast('success', 'The challenge title is successfully updated!', 5); + }, + err => { + SELF.globalService.handleApiError(err, true); + SELF.globalService.showToast('error', err); + }, + () => console.log('EDIT-CHALLENGE-TITLE-FINISHED') + ); + }; + + const PARAMS = { + title: 'Edit Challenge Title', + content: '', + confirm: 'Submit', + deny: 'Cancel', + form: [ + { + name: 'editChallengeTitle', + isRequired: true, + label: 'title', + placeholder: 'Challenge Title', + type: 'text', + value: this.challenge.title + }, + ], + confirmCallback: SELF.apiCall + }; + SELF.globalService.showModal(PARAMS); + } + + /** + * Delete challenge + */ + deleteChallenge() { + const SELF = this; + const redirectTo = '/dashboard'; + + SELF.apiCall = () => { + const BODY = JSON.stringify({}); + SELF.apiService.postUrl( + SELF.endpointsService.deleteChallengeURL(SELF.challenge.id), + BODY + ).subscribe( + data => { + SELF.router.navigate([redirectTo]); + SELF.globalService.showToast('success', 'The Challenge is successfully deleted!', 5); + }, + err => { + SELF.globalService.handleApiError(err, true); + SELF.globalService.showToast('error', err); + }, + () => console.log('DELETE-CHALLENGE-FINISHED') + ); + }; + + const PARAMS = { + title: 'Delete Challenge', + content: '', + confirm: 'I understand consequences, delete the challenge', + deny: 'Cancel', + form: [ + { + name: 'challegenDeleteInput', + isRequired: true, + label: '', + placeholder: 'Please type in the name of the challenge to confirm', + type: 'text', + value: '' + }, + ], + confirmCallback: SELF.apiCall + }; + SELF.globalService.showModal(PARAMS); } } diff --git a/src/app/components/challenge/challengeoverview/challengeoverview.component.html b/src/app/components/challenge/challengeoverview/challengeoverview.component.html index 9d9a01617..b06803574 100644 --- a/src/app/components/challenge/challengeoverview/challengeoverview.component.html +++ b/src/app/components/challenge/challengeoverview/challengeoverview.component.html @@ -1,7 +1,22 @@ -
-
- -
-
-
+
+
+
+
+ + {{challenge['title']}} + +
+ +
+
+
+
+
+
+
diff --git a/src/app/components/challenge/challengeoverview/challengeoverview.component.scss b/src/app/components/challenge/challengeoverview/challengeoverview.component.scss index ae2df1fd8..9bd00ed5d 100644 --- a/src/app/components/challenge/challengeoverview/challengeoverview.component.scss +++ b/src/app/components/challenge/challengeoverview/challengeoverview.component.scss @@ -1,21 +1,10 @@ @import './variables.scss'; @import './mixins.scss'; -.challenge-overview-container { - padding:40px; - overflow:auto; - .content { - text-align:center; - font-weight:$fw-light; - font-size:$fs-16; - color:$gray-darker; - line-height: 20px; - letter-spacing: 0.5px; - a { - color:$red-light; - } - i { - color: $gray-darker; - } +.bottom-card-container { + padding: 40px; + + .row { + margin-bottom: 20px; } -} \ No newline at end of file +} diff --git a/src/app/components/challenge/challengeoverview/challengeoverview.component.ts b/src/app/components/challenge/challengeoverview/challengeoverview.component.ts index fe1a2de9d..5d7d55baa 100644 --- a/src/app/components/challenge/challengeoverview/challengeoverview.component.ts +++ b/src/app/components/challenge/challengeoverview/challengeoverview.component.ts @@ -1,6 +1,9 @@ import { Component, OnInit, Inject } from '@angular/core'; import { DOCUMENT } from '@angular/common'; +import { GlobalService } from '../../../services/global.service'; import { ChallengeService } from '../../../services/challenge.service'; +import { ApiService } from '../../../services/api.service'; +import { EndpointsService } from '../../../services/endpoints.service'; /** * Component Class @@ -17,12 +20,24 @@ export class ChallengeoverviewComponent implements OnInit { */ challenge: any = null; + /** + * Is challenge host + */ + isChallengeHost = false; + + /** + * To call the API inside modal for editing the challenge description + */ + apiCall: any; + /** * Constructor. * @param document Window document Injection. * @param challengeService ChallengeService Injection. */ - constructor(private challengeService: ChallengeService, @Inject(DOCUMENT) private document: Document) { } + constructor(private challengeService: ChallengeService, @Inject(DOCUMENT) private document: Document, + private globalService: GlobalService, private apiService: ApiService, + private endpointsService: EndpointsService) { } /** * Component on initialized. @@ -32,5 +47,39 @@ export class ChallengeoverviewComponent implements OnInit { challenge => { this.challenge = challenge; }); + this.challengeService.isChallengeHost.subscribe(status => { + this.isChallengeHost = status; + }); + } + + editChallengeOverview() { + const SELF = this; + + SELF.apiCall = (params) => { + const BODY = JSON.stringify(params); + SELF.apiService.postUrl( + SELF.endpointsService.editChallengeDetailsURL(SELF.challenge.creator.id, SELF.challenge.id), + BODY + ).subscribe( + data => { + SELF.globalService.showToast('success', 'The challenge title is successfully updated!', 5); + + }, + err => { + SELF.globalService.handleApiError(err, true); + SELF.globalService.showToast('error', err); + }, + () => console.log('EDIT-CHALLENGE-DESCRIPTION-FINISHED') + ); + }; + + const PARAMS = { + title: 'Edit Challenge Description', + content: 'asdasdasd \n\nasdasdasdasd', + confirm: 'Submit', + deny: 'Cancel', + confirmCallback: SELF.apiCall + }; + SELF.globalService.showModal(PARAMS); } } diff --git a/src/app/components/challenge/challengesubmissions/challengesubmissions.component.ts b/src/app/components/challenge/challengesubmissions/challengesubmissions.component.ts index 3ca323ca6..77f932e5a 100644 --- a/src/app/components/challenge/challengesubmissions/challengesubmissions.component.ts +++ b/src/app/components/challenge/challengesubmissions/challengesubmissions.component.ts @@ -87,6 +87,11 @@ export class ChallengesubmissionsComponent implements OnInit, AfterViewInit { */ submissionHighlighted: any = null; + /** + * To call the API inside modal for editing the submission + */ + apiCall: any; + /** * Constructor. * @param route ActivatedRoute Injection. @@ -324,7 +329,7 @@ export class ChallengesubmissionsComponent implements OnInit, AfterViewInit { */ editSubmission(submission) { const SELF = this; - const apiCall = (params) => { + SELF.apiCall = (params) => { const BODY = JSON.stringify(params); SELF.apiService.patchUrl( SELF.endpointsService.challengeSubmissionUpdateURL(SELF.challenge.id, submission.challenge_phase, submission.id), @@ -376,7 +381,7 @@ export class ChallengesubmissionsComponent implements OnInit, AfterViewInit { value: submission['publication_url'] } ], - confirmCallback: apiCall + confirmCallback: SELF.apiCall }; SELF.globalService.showModal(PARAMS); } diff --git a/src/app/components/profile/profile.component.ts b/src/app/components/profile/profile.component.ts index 785402a5f..8cba4d73b 100644 --- a/src/app/components/profile/profile.component.ts +++ b/src/app/components/profile/profile.component.ts @@ -48,6 +48,11 @@ export class ProfileComponent implements OnInit { */ isTokenModalVisible = false; + /** + * To call the API inside modal for updating the user details and password + */ + apiCall: any; + /** * Form components from 'formtoken' */ @@ -121,7 +126,7 @@ export class ProfileComponent implements OnInit { */ updateUserDetails() { const SELF = this; - const apiCall = (params) => { + SELF.apiCall = (params) => { const BODY = JSON.stringify(params); console.log(params); SELF.apiService.putUrl(SELF.endpointsService.userDetailsURL(), @@ -165,7 +170,7 @@ export class ProfileComponent implements OnInit { value: this.user['affiliation'] } ], - confirmCallback: apiCall + confirmCallback: SELF.apiCall }; SELF.globalService.showModal(PARAMS); @@ -194,7 +199,7 @@ export class ProfileComponent implements OnInit { */ updatePassword() { const SELF = this; - const apiCall = (params) => { + SELF.apiCall = (params) => { const BODY = JSON.stringify(params); console.log(params); SELF.apiService.postUrl(SELF.endpointsService.changePasswordURL(), @@ -241,7 +246,7 @@ export class ProfileComponent implements OnInit { type: 'password' } ], - confirmCallback: apiCall + confirmCallback: SELF.apiCall }; SELF.globalService.showModal(PARAMS); } diff --git a/src/app/components/publiclists/teamlist/teamlist.component.ts b/src/app/components/publiclists/teamlist/teamlist.component.ts index c29d2f940..1d1ce81d7 100644 --- a/src/app/components/publiclists/teamlist/teamlist.component.ts +++ b/src/app/components/publiclists/teamlist/teamlist.component.ts @@ -107,6 +107,11 @@ export class TeamlistComponent implements OnInit { */ challenge: any; + /** + * To call the API inside the modal + */ + apiCall: any; + /** * Form components */ @@ -265,7 +270,7 @@ export class TeamlistComponent implements OnInit { deleteTeamWrapper() { const SELF = this; const deleteTeam = (e) => { - const apiCall = () => { + SELF.apiCall = () => { SELF.apiService.deleteUrl(SELF.deleteTeamsPath + '/' + e).subscribe( data => { // Success Message in data.message @@ -284,7 +289,7 @@ export class TeamlistComponent implements OnInit { content: 'Note: This action will remove you from the team.', confirm: 'Yes', deny: 'Cancel', - confirmCallback: apiCall + confirmCallback: SELF.apiCall }; SELF.globalService.showConfirm(PARAMS); return false; @@ -298,7 +303,7 @@ export class TeamlistComponent implements OnInit { editTeamWrapper() { const SELF = this; const editTeam = (team) => { - const apiCall = (params) => { + SELF.apiCall = (params) => { const BODY = JSON.stringify(params); SELF.apiService.patchUrl(SELF.endpointsService.participantTeamURL(team), BODY).subscribe( data => { @@ -333,7 +338,7 @@ export class TeamlistComponent implements OnInit { type: 'text' } ], - confirmCallback: apiCall + confirmCallback: SELF.apiCall }; SELF.globalService.showModal(PARAMS); }; @@ -346,7 +351,7 @@ export class TeamlistComponent implements OnInit { addMembersToTeamWrapper() { const SELF = this; const addMembersToTeam = (team) => { - const apiCall = (params) => { + SELF.apiCall = (params) => { const BODY = JSON.stringify(params); let apiPath = SELF.endpointsService.participantTeamInviteURL(team); if (SELF.isHost) { @@ -379,7 +384,7 @@ export class TeamlistComponent implements OnInit { type: 'email' } ], - confirmCallback: apiCall + confirmCallback: SELF.apiCall }; SELF.globalService.showModal(PARAMS); }; diff --git a/src/app/components/utility/confirm/confirm.component.html b/src/app/components/utility/confirm/confirm.component.html index 8913e94c9..f723f96c7 100644 --- a/src/app/components/utility/confirm/confirm.component.html +++ b/src/app/components/utility/confirm/confirm.component.html @@ -6,8 +6,19 @@
{{content}}
-
- {{deny}} {{confirm}} +
+
+
+ +
+
diff --git a/src/app/components/utility/confirm/confirm.component.scss b/src/app/components/utility/confirm/confirm.component.scss index 9e76c9533..55f047470 100644 --- a/src/app/components/utility/confirm/confirm.component.scss +++ b/src/app/components/utility/confirm/confirm.component.scss @@ -6,4 +6,13 @@ .confirm-card { z-index: 111; } -} \ No newline at end of file + + .btn-inline { + display: -webkit-inline-box; + } +} + +.row ul.confirm-buttons li { + display: inline-block; + margin: 9px 9px; +} diff --git a/src/app/components/utility/input/input.component.html b/src/app/components/utility/input/input.component.html index 9279859ea..e6fce63c5 100644 --- a/src/app/components/utility/input/input.component.html +++ b/src/app/components/utility/input/input.component.html @@ -1,6 +1,6 @@
- + diff --git a/src/app/components/utility/input/input.component.ts b/src/app/components/utility/input/input.component.ts index 1296dbd9d..3840ea435 100644 --- a/src/app/components/utility/input/input.component.ts +++ b/src/app/components/utility/input/input.component.ts @@ -27,6 +27,11 @@ export class InputComponent implements OnInit { */ @Input() type: string; + /** + * Name of input + */ + @Input() name: string; + /** * Is it a required field */ diff --git a/src/app/components/utility/modal/modal.component.html b/src/app/components/utility/modal/modal.component.html index f9aba7662..fb98f6126 100644 --- a/src/app/components/utility/modal/modal.component.html +++ b/src/app/components/utility/modal/modal.component.html @@ -8,11 +8,18 @@
- +
- {{deny}} {{confirm}} +
diff --git a/src/app/components/utility/modal/modal.component.spec.ts b/src/app/components/utility/modal/modal.component.spec.ts index 6b74d250a..70fe954d5 100644 --- a/src/app/components/utility/modal/modal.component.spec.ts +++ b/src/app/components/utility/modal/modal.component.spec.ts @@ -5,6 +5,10 @@ import { InputComponent } from '../input/input.component'; import { GlobalService } from '../../../services/global.service'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; +import { ChallengeService } from '../../../services/challenge.service'; +import { ApiService } from '../../../services/api.service'; +import { AuthService } from '../../../services/auth.service'; +import { EndpointsService } from '../../../services/endpoints.service'; describe('ModalComponent', () => { let component: ModalComponent; @@ -14,7 +18,7 @@ describe('ModalComponent', () => { TestBed.configureTestingModule({ declarations: [ ModalComponent, InputComponent ], imports: [ HttpClientModule ], - providers: [ GlobalService ], + providers: [ GlobalService, ChallengeService, EndpointsService, AuthService, ApiService ], schemas: [ NO_ERRORS_SCHEMA ] }) .compileComponents(); diff --git a/src/app/components/utility/modal/modal.component.ts b/src/app/components/utility/modal/modal.component.ts index e07fdc9ae..36d851191 100644 --- a/src/app/components/utility/modal/modal.component.ts +++ b/src/app/components/utility/modal/modal.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit, Input } from '@angular/core'; import { ViewChildren, QueryList, AfterViewInit } from '@angular/core'; import { GlobalService } from '../../../services/global.service'; import { InputComponent } from '../input/input.component'; +import { ChallengeService } from '../../../services/challenge.service'; /** * Component Class @@ -43,6 +44,16 @@ export class ModalComponent implements OnInit { */ form = []; + /** + * challenge object + */ + challenge: any; + + /** + * delete challenge button disable + */ + isDisabled = true; + /** * Modal form items */ @@ -63,7 +74,7 @@ export class ModalComponent implements OnInit { * Constructor. * @param globalService GlobalService Injection. */ - constructor(private globalService: GlobalService) { } + constructor(private globalService: GlobalService, private challengeService: ChallengeService) { } /** * Component on intialized. @@ -92,6 +103,8 @@ export class ModalComponent implements OnInit { this.form = this.params['form']; } } + + this.challengeService.currentChallenge.subscribe(challenge => this.challenge = challenge); } /** @@ -122,4 +135,20 @@ export class ModalComponent implements OnInit { this.denyCallback(); } + validateModalInput(e) { + if (e.target.name === 'challegenDeleteInput') { + if (e.target.value === this.challenge.title) { + this.isDisabled = false; + } else { + this.isDisabled = true; + } + } else if (e.target.name === 'editChallengeTitle') { + if (e.target.value !== this.challenge.title && e.target.value.length > 1) { + this.isDisabled = false; + } else { + this.isDisabled = true; + } + } + } + } diff --git a/src/app/services/challenge.service.ts b/src/app/services/challenge.service.ts index e6e51235e..d3eb238a9 100644 --- a/src/app/services/challenge.service.ts +++ b/src/app/services/challenge.service.ts @@ -9,6 +9,10 @@ import { EndpointsService } from './endpoints.service'; export class ChallengeService { private defaultChallenge: any = { 'creator': {}}; private defaultStars: any = { 'count': 0, 'is_starred': false}; + private defaultPublishChallenge: any = { + 'state': 'Not Published', + 'icon': 'fa fa-eye-slash red-text' + }; private isLoggedIn = false; private challengeSource = new BehaviorSubject(this.defaultChallenge); currentChallenge = this.challengeSource.asObservable(); @@ -24,6 +28,10 @@ export class ChallengeService { currentParticipationStatus = this.challengeParticipationSource.asObservable(); private hostTeamSource = new BehaviorSubject(null); currentHostTeam = this.hostTeamSource.asObservable(); + private challengeHostSource = new BehaviorSubject(false); + isChallengeHost = this.challengeHostSource.asObservable(); + private challengePublishSource = new BehaviorSubject(this.defaultPublishChallenge); + currentChallengePublishState = this.challengePublishSource.asObservable(); /** * Constructor. @@ -42,6 +50,22 @@ export class ChallengeService { this.challengeSource.next(challenge); } + /** + * Update user's challenge host status for current challenge. + * @param isChallengeHost new challenge host status. + */ + changeChallengeHostStatus(isChallengeHost: any) { + this.challengeHostSource.next(isChallengeHost); + } + + /** + * Update challenge publish state and icon for current challenge. + * @param publishChallenge new challenge publish status and icon. + */ + changeChallengePublish(publishChallenge: any) { + this.challengePublishSource.next(publishChallenge); + } + /** * Update stars for current challenge. * @param stars new stars. @@ -116,6 +140,18 @@ export class ChallengeService { if (data['id'] === parseInt(id, 10)) { SELF.changeCurrentChallenge(data); } + const challengePublish = { + state: '', + icon: '' + }; + if (data['published']) { + challengePublish.state = 'Published'; + challengePublish.icon = 'fa fa-eye green-text'; + } else { + challengePublish.state = 'Not Published'; + challengePublish.icon = 'fa fa-eye-slash red-text'; + } + this.changeChallengePublish(challengePublish); }, err => { SELF.globalService.handleApiError(err); @@ -190,6 +226,9 @@ export class ChallengeService { data => { let teams = []; let participated = false; + if (data['is_challenge_host']) { + SELF.changeChallengeHostStatus(true); + } if (data['challenge_participant_team_list']) { teams = data['challenge_participant_team_list']; this.changeCurrentParticipantTeams(teams); diff --git a/src/app/services/endpoints.service.ts b/src/app/services/endpoints.service.ts index 99076ad13..8cae44a23 100644 --- a/src/app/services/endpoints.service.ts +++ b/src/app/services/endpoints.service.ts @@ -220,4 +220,21 @@ export class EndpointsService { challengeSubmissionsRemainingURL(challenge, phase) { return `${this.jobs}${challenge}/phases/${phase}/remaining_submissions`; } + + /** + * Edit challenge details + * @param hostTeam challenge host team id + * @param challenge challenge id + */ + editChallengeDetailsURL(hostTeam, challenge) { + return `${this.challenges}challenge_host_team/${hostTeam}/${this.challenge}${challenge}`; + } + + /** + * Delete challenge + * @param challenge challenge id + */ + deleteChallengeURL(challenge) { + return `${this.challenges}${this.challenge}${challenge}/disable`; + } } diff --git a/src/index.html b/src/index.html index 3d3df37ff..a99178992 100644 --- a/src/index.html +++ b/src/index.html @@ -4,8 +4,7 @@ EvalAI - - + diff --git a/src/styles/base.scss b/src/styles/base.scss index be1493c5b..cb7bde32c 100644 --- a/src/styles/base.scss +++ b/src/styles/base.scss @@ -22,6 +22,8 @@ body { .content { line-height: 24px; letter-spacing: 0.1px; + font-size: 15px; + color: rgba(0, 0, 0, 0.87); } .go { @@ -118,6 +120,10 @@ body { font-size: $fs-14; } +.fs-15 { + font-size: $fs-15; +} + .fs-16 { font-size: $fs-16; } @@ -148,16 +154,81 @@ body { +/*card styles*/ + +.ev-card-panel { + position: relative; + display: block; + background-color: #fff; + width: 100%; + height: auto; + border-radius: 10px; + overflow: hidden; + box-shadow: 0px 0px 12px $shadow-black; +} + + +/*grad button style*/ + +.grad-btn { + border-radius: 20px; +} + +.grad-btn-dark { + background: $med-gray; + font-weight: $fw-regular; + color: #fff; + box-shadow: 0px 4px 8px #9d9d9d; + &:hover { + box-shadow: 0px 0px 8px #9d9d9d; + } +} + +.grad-btn-light { + background: $highlight; + font-weight: $fw-regular; + color: #fff; + box-shadow: 0px 4px 8px #9d9d9d; + &:hover { + box-shadow: 0px 0px 8px #9d9d9d; + background: $highlight; + } +} + +.grad-btn-transparent { + background-color: rgba(0,0,0,0); + font-weight: $fw-regular; + color: $med-gray; + border: 1px solid $med-gray; + box-shadow: 0px 4px 8px transparent; + &:hover { + box-shadow: 0px 0px 8px #9d9d9d; + background: $med-gray; + color: #fff; + } +} + + +/*icon colors*/ + +.red-text { + color: #F44336; +} + +.green-text { + color: #4CAF50; +} + /*anchors*/ a { - color: $red-light; + color: #3c3e49; transition: all 0.2s ease-in-out; text-decoration: none; cursor: pointer; &:hover { - color: $red-dark; + // color: $red-dark; } &:focus, &:active { @@ -165,6 +236,10 @@ a { } } +a:active, a:hover { + outline: 0; +} + a.light-link { color: $red-light; transition: all 0.2s ease-in-out; @@ -173,6 +248,22 @@ a.light-link { } } +a.dark-link:hover { + color: #ffaf4b; +} + +a.text-light-black:hover { + color: #ffaf4b; +} + +a.active-challenge { + color: #4d4d4d; + display: block; + height: 40px; + box-sizing: border-box; + border-bottom: 2px solid #ffaf4b; +} + .pointer { cursor: pointer; outline: none; @@ -432,7 +523,7 @@ ul { border-radius: 20px; margin-right: 10px; margin-top: 5px; - margin-bottom: 0 !important; + margin-bottom: 5px !important; text-align: center; cursor: pointer; display: inline-block; @@ -440,6 +531,13 @@ ul { font-size: $fs-14; } +.btn:disabled { + background-color: #DFDFDF !important; + box-shadow: none; + color: #9F9F9F !important; + cursor: default; +} + .btn-nofill { padding: 10px 30px 10px 30px; border: 1px solid white; @@ -542,24 +640,19 @@ ul { } .btn-filter { - padding: 10px 30px 10px 30px; - border: 1px solid $red-light; color: $gray-darker; &.selected { - color: white; - background: $red-light; + background-color: rgba(0,0,0,0); + font-weight: $fw-regular; + color: $med-gray; + border: 1px solid $med-gray; + box-shadow: 0px 4px 8px transparent; &:hover { - color: white; + box-shadow: 0px 0px 8px #9d9d9d; + background: $med-gray; + color: #fff; } } - &:hover { - @include box-shadow(0px, - 0px, - 5px, - 0px, - $overlay-light); - color: $red-light; - } } @@ -644,6 +737,7 @@ ul { color: $gray-darker; padding: 30px; .title { + color: $med-black; padding: 10px; font-size: $fs-18; font-weight: $fw-bold; @@ -793,3 +887,58 @@ ul { .cbx:disabled~.cbx-label:after { background: $gray-lighter; } + +.text-light-black { + color: #9d9d9d; +} + +.orange-text { + color: $orange; +} + +.btn-waves-effect { + position: relative; + cursor: pointer; + display: inline-block; + overflow: hidden; + user-select: none; + height: 36px; + -webkit-tap-highlight-color: transparent; + vertical-align: middle; + z-index: 1; + will-change: opacity, transform; + transition: .3s ease-out; +} + + .grad-rec-btn { + border-radius: 2px; +} + + .grad-btn-dark { + background: #3c3e49; + font-weight: 400; + color: #fff; + box-shadow: 0 4px 8px #9d9d9d; +} + + .ev-btn-dark { + padding: 0 32px; + border: none; + background: #252833; +} + + .ev-btn-dark:hover { + background: #3c3e49; +} + +.challenge-card { + margin: 0 10px -30px 10px; + padding: 20px; +} + +.selected { + height: 30px; + border-bottom: 2px solid #ffaf4b; + display: block; + color: #4d4d4d; +} diff --git a/src/styles/variables.scss b/src/styles/variables.scss index b78a66a3a..a7c0162f7 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -3,6 +3,9 @@ /* Blue Shades */ +$light-gray: #adb4d0; +$med-gray: #3c3e49; +$dark-gray: #252833; $blue-dark: #33526e; $blue-darker: #273e54; $blue-light: #adb4d0; @@ -25,12 +28,24 @@ $red-dark: #252833; $red-light: #eb8474; +/*black shades*/ -/* Orange Shades */ +$shadow-black: #dedede; +$light-black: #9d9d9d; +$med-black: #4d4d4d; +$dark-black: #4d4d4d; + + /*orange shades*/ $yellow: #ffaf4b; $yellow-light: #ffecc8; +$orange: #ff9800; $orange-light: #ffd99a; +$highlight: #ffaf4b; +$highlight-dark: #ff7b2e; +$med-orange: #DF9C3E; +$hover-orange: #DA8F27; + /* Pink Shades */ $pink-dark: #d7387f;