From 5eea08c23313443b1c4e5e60c18a0563d25a795c Mon Sep 17 00:00:00 2001 From: Ben Stein Date: Tue, 28 Nov 2023 12:33:43 -0500 Subject: [PATCH] Add challenge feedback in practice mode. Addresses GBAPI#242. Also light refactor of some tools into the core module. --- .../gameboard-ui/src/app/api/board.service.ts | 2 +- .../src/app/api/challenges.service.ts | 2 +- .../src/app/api/feedback.service.ts | 10 +- .../error-div/error-div.component.html | 0 .../error-div/error-div.component.scss | 0 .../error-div/error-div.component.ts | 0 .../feedback-form.component.html | 114 +++++++++++++++++ .../feedback-form.component.scss | 0 .../feedback-form/feedback-form.component.ts | 121 ++++++++++-------- .../gameboard-ui/src/app/core/core.module.ts | 6 + .../pipes/camelspace.pipe.ts | 0 .../game/components/play/play.component.html | 6 - .../feedback-form.component.html | 110 ---------------- .../gameboard-ui/src/app/game/game.module.ts | 3 - ...tice-challenge-solved-modal.component.html | 7 + ...actice-challenge-solved-modal.component.ts | 44 ++++++- .../practice-session.component.html | 2 +- .../practice-session.component.ts | 4 +- .../src/app/services/modal-confirm.service.ts | 1 - .../src/app/stores/active-challenges.store.ts | 10 +- .../src/app/unity/unity.module.ts | 7 +- .../src/app/utility/utility.module.ts | 4 - 22 files changed, 252 insertions(+), 201 deletions(-) rename projects/gameboard-ui/src/app/{utility => core}/components/error-div/error-div.component.html (100%) rename projects/gameboard-ui/src/app/{utility => core}/components/error-div/error-div.component.scss (100%) rename projects/gameboard-ui/src/app/{utility => core}/components/error-div/error-div.component.ts (100%) create mode 100644 projects/gameboard-ui/src/app/core/components/feedback-form/feedback-form.component.html rename projects/gameboard-ui/src/app/{game => core/components}/feedback-form/feedback-form.component.scss (100%) rename projects/gameboard-ui/src/app/{game => core/components}/feedback-form/feedback-form.component.ts (74%) rename projects/gameboard-ui/src/app/{utility => core}/pipes/camelspace.pipe.ts (100%) delete mode 100644 projects/gameboard-ui/src/app/game/feedback-form/feedback-form.component.html diff --git a/projects/gameboard-ui/src/app/api/board.service.ts b/projects/gameboard-ui/src/app/api/board.service.ts index f41564e0..bb12bc9e 100644 --- a/projects/gameboard-ui/src/app/api/board.service.ts +++ b/projects/gameboard-ui/src/app/api/board.service.ts @@ -7,7 +7,7 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { GameSessionService } from '../services/game-session.service'; import { ConfigService } from '../utility/config.service'; -import { BoardPlayer, BoardSpec, Challenge, ChallengeResult, ChallengeSummary, ChangedChallenge, ConsoleActor, NewChallenge, ObserveChallenge, SectionSubmission, VmConsole } from './board-models'; +import { BoardPlayer, BoardSpec, Challenge, ChallengeSummary, ChangedChallenge, ConsoleActor, NewChallenge, ObserveChallenge, SectionSubmission, VmConsole } from './board-models'; @Injectable({ providedIn: 'root' }) export class BoardService { diff --git a/projects/gameboard-ui/src/app/api/challenges.service.ts b/projects/gameboard-ui/src/app/api/challenges.service.ts index 58b625be..00346469 100644 --- a/projects/gameboard-ui/src/app/api/challenges.service.ts +++ b/projects/gameboard-ui/src/app/api/challenges.service.ts @@ -75,7 +75,7 @@ export class ChallengesService { public grade(model: SectionSubmission): Observable { return this.http.put(this.apiUrl.build("challenge/grade"), model).pipe( - tap(challenge => this._challengeGraded$.next(challenge)) + tap(challenge => this._challengeGraded$.next(challenge)), ); } diff --git a/projects/gameboard-ui/src/app/api/feedback.service.ts b/projects/gameboard-ui/src/app/api/feedback.service.ts index 0b06d71d..ca8d2e5f 100644 --- a/projects/gameboard-ui/src/app/api/feedback.service.ts +++ b/projects/gameboard-ui/src/app/api/feedback.service.ts @@ -7,9 +7,7 @@ import { Observable } from 'rxjs'; import { ConfigService } from '../utility/config.service'; import { Feedback, FeedbackReportDetails, FeedbackSubmission } from './feedback-models'; -@Injectable({ - providedIn: 'root' -}) +@Injectable({ providedIn: 'root' }) export class FeedbackService { url = ''; @@ -21,16 +19,14 @@ export class FeedbackService { } public list(search: any): Observable { - return this.http.get(`${this.url}/feedback/list`, {params: search}); + return this.http.get(`${this.url}/feedback/list`, { params: search }); } public retrieve(search: any): Observable { - return this.http.get(`${this.url}/feedback`, {params: search}); + return this.http.get(`${this.url}/feedback`, { params: search }); } public submit(model: FeedbackSubmission): Observable { return this.http.put(`${this.url}/feedback/submit`, model); } - - } diff --git a/projects/gameboard-ui/src/app/utility/components/error-div/error-div.component.html b/projects/gameboard-ui/src/app/core/components/error-div/error-div.component.html similarity index 100% rename from projects/gameboard-ui/src/app/utility/components/error-div/error-div.component.html rename to projects/gameboard-ui/src/app/core/components/error-div/error-div.component.html diff --git a/projects/gameboard-ui/src/app/utility/components/error-div/error-div.component.scss b/projects/gameboard-ui/src/app/core/components/error-div/error-div.component.scss similarity index 100% rename from projects/gameboard-ui/src/app/utility/components/error-div/error-div.component.scss rename to projects/gameboard-ui/src/app/core/components/error-div/error-div.component.scss diff --git a/projects/gameboard-ui/src/app/utility/components/error-div/error-div.component.ts b/projects/gameboard-ui/src/app/core/components/error-div/error-div.component.ts similarity index 100% rename from projects/gameboard-ui/src/app/utility/components/error-div/error-div.component.ts rename to projects/gameboard-ui/src/app/core/components/error-div/error-div.component.ts diff --git a/projects/gameboard-ui/src/app/core/components/feedback-form/feedback-form.component.html b/projects/gameboard-ui/src/app/core/components/feedback-form/feedback-form.component.html new file mode 100644 index 00000000..44c6b786 --- /dev/null +++ b/projects/gameboard-ui/src/app/core/components/feedback-form/feedback-form.component.html @@ -0,0 +1,114 @@ + +
+ + +

{{title}}

+

{{title}}

+
+
+ +
+ + + +
+ + {{message}} +
+ +
+ + + + + + + {{characterLimit - (q.answer?.length ?? 0)}} + + + + +
+ {{q.minLabel}} +
+ +
+ {{q.maxLabel}} +
+ + + + +
+ +
+ +
+ +
+ + +
+ +
+
+
+
+ + + +
+ +
+ + +
+ +
+
+
+
+
+ + + + {{feedbackForm.submitted ? "Submitted" : "Submit"}} + +
+ Responses cannot be changed after clicking submit. + {{status}} +
+
+ +

+ Thank you for submitting feedback! +

+ +
diff --git a/projects/gameboard-ui/src/app/game/feedback-form/feedback-form.component.scss b/projects/gameboard-ui/src/app/core/components/feedback-form/feedback-form.component.scss similarity index 100% rename from projects/gameboard-ui/src/app/game/feedback-form/feedback-form.component.scss rename to projects/gameboard-ui/src/app/core/components/feedback-form/feedback-form.component.scss diff --git a/projects/gameboard-ui/src/app/game/feedback-form/feedback-form.component.ts b/projects/gameboard-ui/src/app/core/components/feedback-form/feedback-form.component.ts similarity index 74% rename from projects/gameboard-ui/src/app/game/feedback-form/feedback-form.component.ts rename to projects/gameboard-ui/src/app/core/components/feedback-form/feedback-form.component.ts index 98fc18d8..1da76661 100644 --- a/projects/gameboard-ui/src/app/game/feedback-form/feedback-form.component.ts +++ b/projects/gameboard-ui/src/app/core/components/feedback-form/feedback-form.component.ts @@ -1,21 +1,29 @@ -import { Component, OnInit, ViewChild, Input, AfterViewInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core'; +import { Component, ViewChild, Input, AfterViewInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core'; import { FormGroup, NgForm } from '@angular/forms'; -import { BoardPlayer, BoardSpec } from '../../api/board-models'; +import { firstValueFrom, Observable, of, Subject, Subscription } from 'rxjs'; +import { catchError, debounceTime, delay, filter, first, tap } from 'rxjs/operators'; import { faCaretDown, faCaretRight, faCloudUploadAlt, faExclamationCircle } from '@fortawesome/free-solid-svg-icons'; -import { Observable, of, Subject, Subscription } from 'rxjs'; -import { FeedbackService } from '../../api/feedback.service'; -import { Feedback, FeedbackSubmission, FeedbackQuestion } from '../../api/feedback-models'; -import { BoardGame } from '../../api/board-models'; -import { catchError, combineAll, debounceTime, delay, filter, first, map, mergeAll, switchMap, takeUntil, takeWhile, tap } from 'rxjs/operators'; +import { BoardGame, BoardPlayer, BoardSpec } from '@/api/board-models'; +import { FeedbackService } from '@/api/feedback.service'; +import { Feedback, FeedbackSubmission, FeedbackQuestion } from '@/api/feedback-models'; + +export type MiniBoardSpec = { + id: string, + instance?: { + id: string, + state: { isActive: boolean } + }, +} @Component({ selector: 'app-feedback-form', templateUrl: './feedback-form.component.html', styleUrls: ['./feedback-form.component.scss'] }) -export class FeedbackFormComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { +export class FeedbackFormComponent implements AfterViewInit, OnChanges, OnDestroy { @Input() boardPlayer?: BoardPlayer; - @Input() spec?: BoardSpec; + @Input() hideIfFeedbackProvidedPreviously = false; + @Input() spec?: MiniBoardSpec; @Input() title!: string; @Input() type!: 'challenge' | 'game'; @ViewChild(NgForm) form!: FormGroup; @@ -30,8 +38,9 @@ export class FeedbackFormComponent implements OnInit, AfterViewInit, OnChanges, errors: any[] = []; game?: BoardGame; + isForceHidden = false; + show = false; submitPending: boolean = false; - show: boolean = false; refreshSpec$ = new Subject(); status: string = ""; @@ -48,16 +57,13 @@ export class FeedbackFormComponent implements OnInit, AfterViewInit, OnChanges, }; } - ngOnInit(): void { - this.load(this.boardPlayer, this.spec, this.type); - } - ngAfterViewInit(): void { this.autosaveInit(); } - ngOnChanges(changes: SimpleChanges): void { - this.load(this.boardPlayer, this.spec, this.type); + async ngOnChanges(changes: SimpleChanges): Promise { + await this.load(this.boardPlayer, this.spec, this.type); + this.isForceHidden = (this.feedbackForm?.submitted || false) && this.hideIfFeedbackProvidedPreviously; } ngOnDestroy(): void { @@ -70,7 +76,7 @@ export class FeedbackFormComponent implements OnInit, AfterViewInit, OnChanges, // swap in the answers from user submitted response object, but only answers feedback.questions.forEach((question) => { // templateMap holds references to feedback form question objects, mapped by id - let questionTemplate = this.templateMap.get(question.id); + const questionTemplate = this.templateMap.get(question.id); if (questionTemplate) questionTemplate.answer = question.answer; }); @@ -205,70 +211,75 @@ export class FeedbackFormComponent implements OnInit, AfterViewInit, OnChanges, return Array.from(new Array(max), (x, i) => i + min); } - private load(boardPlayer?: BoardPlayer, spec?: BoardSpec, type?: "challenge" | "game") { + private async load(boardPlayer?: BoardPlayer, spec?: MiniBoardSpec, type?: "challenge" | "game") { // clear form this.form?.reset(); this.status = ""; this.errors = []; - if (!boardPlayer || !spec || !type) + if (!boardPlayer || !type) return; - this.game = boardPlayer.game; + if (type == "challenge") { + if (!spec) { + throw new Error("Can't load challenge-level feedback without a spec."); + } - if (type === "challenge") { - this.loadChallenge(boardPlayer, spec); + await this.loadChallenge(boardPlayer, spec); return; } - this.loadGame(boardPlayer, spec); + await this.loadGame(boardPlayer); } - private loadChallenge(boardPlayer: BoardPlayer, spec: BoardSpec) { + private async loadChallenge(boardPlayer: BoardPlayer, spec: MiniBoardSpec) { this.setTemplate(boardPlayer.game.feedbackTemplate.challenge); if (!spec) { return; } - this.api.retrieve({ - challengeSpecId: spec.id, - challengeId: spec.instance?.id, - gameId: boardPlayer.gameId - }).pipe( - first(), - tap(feedback => { - if (feedback) - this.updateFeedback(feedback); - - // behavior for whether to hide form on load based on challenge status or already submitted - this.show = !this.spec?.instance?.state.isActive; - - if (feedback?.submitted) { - this.show = false; - } - }) - ).subscribe(); + try { + const feedback = await firstValueFrom( + this.api.retrieve({ + challengeSpecId: spec.id, + challengeId: spec.instance?.id, + gameId: boardPlayer.gameId + }) + ); + + if (feedback) + this.updateFeedback(feedback); + + // behavior for whether to hide form on load based on challenge status or already submitted + this.show = !this.spec?.instance?.state.isActive; + + if (feedback?.submitted) { + this.show = false; + } + } + catch (err: any) { + this.errors.push(err); + } } - private loadGame(boardPlayer: BoardPlayer, spec: BoardSpec) { + private async loadGame(boardPlayer: BoardPlayer) { this.setTemplate(boardPlayer.game.feedbackTemplate.game); if (!boardPlayer) { return; } - this.api.retrieve({ gameId: boardPlayer.gameId }) - .pipe(first()).subscribe( - feedback => { - this.updateFeedback(feedback); - - if (boardPlayer.session.isAfter) - this.show = true; - if (feedback?.submitted) - this.show = false; - }, - (err: any) => { } - ); + try { + const feedback = await firstValueFrom(this.api.retrieve({ gameId: boardPlayer.gameId })); + + if (boardPlayer.session.isAfter) + this.show = true; + if (feedback?.submitted) + this.show = false; + } + catch (err: any) { + this.errors.push(err); + } } } diff --git a/projects/gameboard-ui/src/app/core/core.module.ts b/projects/gameboard-ui/src/app/core/core.module.ts index 83f6c103..da06a42e 100644 --- a/projects/gameboard-ui/src/app/core/core.module.ts +++ b/projects/gameboard-ui/src/app/core/core.module.ts @@ -40,6 +40,8 @@ import { CountdownPipe } from './pipes/countdown.pipe'; import { CumulativeTimeClockComponent } from './components/cumulative-time-clock/cumulative-time-clock.component'; import { DoughnutChartComponent } from './components/doughnut-chart/doughnut-chart.component'; import { DropzoneComponent } from './components/dropzone/dropzone.component'; +import { ErrorDivComponent } from './components/error-div/error-div.component'; +import { FeedbackFormComponent } from './components/feedback-form/feedback-form.component'; import { FriendlyDateAndTimePipe } from './pipes/friendly-date-and-time.pipe'; import { FriendlyTimePipe } from './pipes/friendly-time.pipe'; import { GameboardPerformanceSummaryComponent } from './components/gameboard-performance-summary/gameboard-performance-summary.component'; @@ -86,11 +88,13 @@ import { UrlRewritePipe } from './pipes/url-rewrite.pipe'; import { WhitespacePipe } from './pipes/whitespace.pipe'; import { YamlBlockComponent } from './components/yaml-block/yaml-block.component'; import { YamlPipe } from './pipes/yaml.pipe'; +import { CamelspacePipe } from './pipes/camelspace.pipe'; const PUBLIC_DECLARATIONS = [ GbProgressBarComponent, ApiUrlPipe, AssetPathPipe, + CamelspacePipe, ChallengeResultColorPipe, ChallengeResultPrettyPipe, ChallengeSolutionGuideComponent, @@ -99,6 +103,8 @@ const PUBLIC_DECLARATIONS = [ CumulativeTimeClockComponent, DoughnutChartComponent, DropzoneComponent, + ErrorDivComponent, + FeedbackFormComponent, FriendlyDateAndTimePipe, GameboardPerformanceSummaryComponent, GameCardImageComponent, diff --git a/projects/gameboard-ui/src/app/utility/pipes/camelspace.pipe.ts b/projects/gameboard-ui/src/app/core/pipes/camelspace.pipe.ts similarity index 100% rename from projects/gameboard-ui/src/app/utility/pipes/camelspace.pipe.ts rename to projects/gameboard-ui/src/app/core/pipes/camelspace.pipe.ts diff --git a/projects/gameboard-ui/src/app/game/components/play/play.component.html b/projects/gameboard-ui/src/app/game/components/play/play.component.html index df145608..9c6b2285 100644 --- a/projects/gameboard-ui/src/app/game/components/play/play.component.html +++ b/projects/gameboard-ui/src/app/game/components/play/play.component.html @@ -70,11 +70,5 @@

Challenge Questions

- -
- -
diff --git a/projects/gameboard-ui/src/app/game/feedback-form/feedback-form.component.html b/projects/gameboard-ui/src/app/game/feedback-form/feedback-form.component.html deleted file mode 100644 index 92477b17..00000000 --- a/projects/gameboard-ui/src/app/game/feedback-form/feedback-form.component.html +++ /dev/null @@ -1,110 +0,0 @@ -
- - -

{{title}}

-

{{title}}

-
-
- -
- - - -
- - {{message}} -
- -
- - - - - - - {{characterLimit - (q.answer?.length ?? 0)}} - - - - -
- {{q.minLabel}} -
- -
- {{q.maxLabel}} -
- - - - -
- -
- -
- -
- - -
- -
-
-
-
- - - -
- -
- - -
- -
-
-
-
-
- - - - {{feedbackForm.submitted ? "Submitted" : "Submit"}} - -
- Responses cannot be changed after clicking submit. - {{status}} -
-
- -

- Thank you for submitting feedback! -

diff --git a/projects/gameboard-ui/src/app/game/game.module.ts b/projects/gameboard-ui/src/app/game/game.module.ts index 387fb0e1..3e2ada61 100644 --- a/projects/gameboard-ui/src/app/game/game.module.ts +++ b/projects/gameboard-ui/src/app/game/game.module.ts @@ -18,7 +18,6 @@ import { ExternalGameLinkBannerComponent } from './components/external-game-link import { ExternalGameLoadingPageComponent } from './pages/external-game-loading-page/external-game-loading-page.component'; import { ExternalGamePageComponent } from './pages/external-game-page/external-game-page.component'; import { ExternalSyncGameGuard } from '@/guards/external-sync-game.guard'; -import { FeedbackFormComponent } from './feedback-form/feedback-form.component'; import { GameboardPageComponent } from './pages/gameboard-page/gameboard-page.component'; import { GameInfoComponent } from './game-info/game-info.component'; import { GameIsStarted } from '@/guards/game-is-started.guard'; @@ -45,7 +44,6 @@ const MODULE_DECLARATIONS = [ ChallengeDeployCountdownComponent, ExternalGameLoadingPageComponent, ExternalGamePageComponent, - FeedbackFormComponent, GameInfoComponent, GamePageComponent, GameboardPageComponent, @@ -60,7 +58,6 @@ const MODULE_DECLARATIONS = [ ScoreboardPageComponent, ScoreboardTableComponent, PlayerPresenceComponent, - FeedbackFormComponent, CertificateComponent, HubStateToPlayerStatusPipe, SessionStartControlsComponent, diff --git a/projects/gameboard-ui/src/app/prac/components/practice-challenge-solved-modal/practice-challenge-solved-modal.component.html b/projects/gameboard-ui/src/app/prac/components/practice-challenge-solved-modal/practice-challenge-solved-modal.component.html index b8e0eb3d..8c78633f 100644 --- a/projects/gameboard-ui/src/app/prac/components/practice-challenge-solved-modal/practice-challenge-solved-modal.component.html +++ b/projects/gameboard-ui/src/app/prac/components/practice-challenge-solved-modal/practice-challenge-solved-modal.component.html @@ -9,12 +9,19 @@

Congratulations!

You've successfully solved the challenge {{ context.challenge.spec.name }}! Congratulations! + Click here to view a printable certificate commemorating your achievement.

+ +

We'll take you back to the Practice Area so you can find a new challenge to conquer.

diff --git a/projects/gameboard-ui/src/app/prac/components/practice-challenge-solved-modal/practice-challenge-solved-modal.component.ts b/projects/gameboard-ui/src/app/prac/components/practice-challenge-solved-modal/practice-challenge-solved-modal.component.ts index 12571dd2..43d64e15 100644 --- a/projects/gameboard-ui/src/app/prac/components/practice-challenge-solved-modal/practice-challenge-solved-modal.component.ts +++ b/projects/gameboard-ui/src/app/prac/components/practice-challenge-solved-modal/practice-challenge-solved-modal.component.ts @@ -1,15 +1,24 @@ +import { Component, OnInit } from '@angular/core'; +import { firstValueFrom } from 'rxjs'; +import { BoardPlayer } from '@/api/board-models'; +import { BoardService } from '@/api/board.service'; import { LocalActiveChallenge } from '@/api/challenges.models'; import { PlayerMode } from '@/api/player-models'; +import { MiniBoardSpec } from '@/core/components/feedback-form/feedback-form.component'; import { PracticeService } from '@/services/practice.service'; import { RouterService } from '@/services/router.service'; -import { Component, OnInit } from '@angular/core'; +import { UnsubscriberService } from '@/services/unsubscriber.service'; import { BsModalRef } from 'ngx-bootstrap/modal'; -import { firstValueFrom } from 'rxjs'; export interface PracticeChallengeSolvedModalContext { challenge: LocalActiveChallenge; } +interface LegacyFeedbackFormContext { + boardPlayer?: BoardPlayer; + boardSpec?: MiniBoardSpec; +} + @Component({ selector: 'app-practice-challenge-solved-modal', templateUrl: './practice-challenge-solved-modal.component.html', @@ -19,10 +28,13 @@ export class PracticeChallengeSolvedModalComponent implements OnInit { protected context?: PracticeChallengeSolvedModalContext; protected certificateUrl?: string; protected isCertificateConfigured = false; + protected feedbackFormContext?: LegacyFeedbackFormContext = undefined; constructor( + private boardService: BoardService, private practiceService: PracticeService, private routerService: RouterService, + private unsub: UnsubscriberService, private modalRef: BsModalRef) { } async ngOnInit(): Promise { @@ -33,10 +45,38 @@ export class PracticeChallengeSolvedModalComponent implements OnInit { const practiceSettings = await firstValueFrom(this.practiceService.getSettings()); this.isCertificateConfigured = !!practiceSettings.certificateHtmlTemplate; this.certificateUrl = this.routerService.getCertificatePrintableUrl(PlayerMode.practice, this.context.challenge.spec.id); + + // load feedback form data + this.feedbackFormContext = await this.loadFeedbackFormContext(this.context.challenge); + + // wire up event handler for background-click dismiss + if (this.modalRef.onHidden) { + this.unsub.add( + this.modalRef.onHidden.subscribe(() => this.routerService.toPracticeArea()) + ); + } } handleModalClose() { this.modalRef.hide(); this.routerService.toPracticeArea(); } + + private async loadFeedbackFormContext(challenge: LocalActiveChallenge): Promise { + const player = await firstValueFrom(this.boardService.load(challenge.player.id)); + + if (!player.game.feedbackTemplate?.challenge?.length) + return undefined; + + return { + boardPlayer: player, + boardSpec: { + id: challenge.spec.id, + instance: { + id: challenge.challengeDeployment.challengeId, + state: { isActive: challenge.challengeDeployment.isDeployed }, + } + } + }; + } } diff --git a/projects/gameboard-ui/src/app/prac/components/practice-session/practice-session.component.html b/projects/gameboard-ui/src/app/prac/components/practice-session/practice-session.component.html index 73589c6b..08b57412 100644 --- a/projects/gameboard-ui/src/app/prac/components/practice-session/practice-session.component.html +++ b/projects/gameboard-ui/src/app/prac/components/practice-session/practice-session.component.html @@ -19,7 +19,7 @@
+ btnClass="btn btn-lg btn-info px-4 mb-4" (confirm)="play(spec.gameId)" class="d-block"> Start Practice Session diff --git a/projects/gameboard-ui/src/app/prac/components/practice-session/practice-session.component.ts b/projects/gameboard-ui/src/app/prac/components/practice-session/practice-session.component.ts index 8b6a188a..e684cf1b 100644 --- a/projects/gameboard-ui/src/app/prac/components/practice-session/practice-session.component.ts +++ b/projects/gameboard-ui/src/app/prac/components/practice-session/practice-session.component.ts @@ -35,11 +35,11 @@ export class PracticeSessionComponent { protected showSpecMarkdown = true; constructor( + practiceService: PracticeService, private activeChallengesRepo: ActiveChallengesRepo, private modalService: ModalConfirmService, private localUser: LocalUserService, private playerService: PlayerService, - private practiceService: PracticeService, private route: ActivatedRoute, private routerService: RouterService, private teamService: TeamService, @@ -156,7 +156,7 @@ export class PracticeSessionComponent { content: PracticeChallengeSolvedModalComponent, context: { challenge - } + }, }); } diff --git a/projects/gameboard-ui/src/app/services/modal-confirm.service.ts b/projects/gameboard-ui/src/app/services/modal-confirm.service.ts index 1fdb832e..49cb7cff 100644 --- a/projects/gameboard-ui/src/app/services/modal-confirm.service.ts +++ b/projects/gameboard-ui/src/app/services/modal-confirm.service.ts @@ -44,7 +44,6 @@ export class ModalConfirmService implements OnDestroy { return this.bsModalService.show(config.content, { initialState: { context: { ...config.context } } as unknown as Partial, class: config.modalClasses?.join(" ") || "modal-dialog-centered", - // backdrop: config.isBackdropStatic ? "static" : false, ignoreBackdropClick: config.ignoreBackdropClick || false, scrollable: true } as ModalOptions); diff --git a/projects/gameboard-ui/src/app/stores/active-challenges.store.ts b/projects/gameboard-ui/src/app/stores/active-challenges.store.ts index 85ec71ee..a603b03b 100644 --- a/projects/gameboard-ui/src/app/stores/active-challenges.store.ts +++ b/projects/gameboard-ui/src/app/stores/active-challenges.store.ts @@ -90,13 +90,6 @@ export class ActiveChallengesRepo implements OnDestroy { return this.resolveActivePracticeChallenge(activeChallengesStore.value); } - search(predicate: ActiveChallengesPredicate): LocalActiveChallenge[] { - return [ - ...(activeChallengesStore.state.practice.filter(predicate) || []), - ...(activeChallengesStore.state.competition.filter(predicate) || []) - ]; - } - private checkActiveChallengesForEnd() { const challenges = [...activeChallengesStore.state.practice]; @@ -117,6 +110,9 @@ export class ActiveChallengesRepo implements OnDestroy { // and grading attempts, and notify appropriate subjects const activePracticeChallenge = this.resolveActivePracticeChallenge(activeChallengesStore.state); if (activePracticeChallenge?.challengeDeployment.challengeId === challenge.id) { + // no matter what, update the activeChallenge thing in state with the deploy state of the + // challenge's gamespace + activePracticeChallenge.challengeDeployment.isDeployed = challenge.state.isActive; let removeChallengeFromState = false; if (challenge.score >= challenge.points) { diff --git a/projects/gameboard-ui/src/app/unity/unity.module.ts b/projects/gameboard-ui/src/app/unity/unity.module.ts index 62d0865c..f7ef5f32 100644 --- a/projects/gameboard-ui/src/app/unity/unity.module.ts +++ b/projects/gameboard-ui/src/app/unity/unity.module.ts @@ -2,12 +2,17 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { UnityBoardComponent } from './unity-board/unity-board.component'; import { UtilityModule } from '../utility/utility.module'; +import { CoreModule } from '@/core/core.module'; @NgModule({ declarations: [ UnityBoardComponent ], - imports: [CommonModule, UtilityModule], + imports: [ + CommonModule, + CoreModule, + UtilityModule + ], exports: [UnityBoardComponent] }) export class UnityModule { } diff --git a/projects/gameboard-ui/src/app/utility/utility.module.ts b/projects/gameboard-ui/src/app/utility/utility.module.ts index 01f75f06..47610a20 100644 --- a/projects/gameboard-ui/src/app/utility/utility.module.ts +++ b/projects/gameboard-ui/src/app/utility/utility.module.ts @@ -18,7 +18,6 @@ import { TooltipModule } from 'ngx-bootstrap/tooltip'; // internal components/services import { AgedDatePipe } from './pipes/aged-date.pipe'; import { ClipspanComponent } from './components/clipspan/clipspan.component'; -import { ErrorDivComponent } from './components/error-div/error-div.component'; import { GameCardComponent } from './components/game-card/game-card.component'; import { ImageManagerComponent } from './components/image-manager/image-manager.component'; import { ImagestackComponent } from './components/imagestack/imagestack.component'; @@ -28,7 +27,6 @@ import { LoginComponent } from './components/login/login.component'; import { MessageBoardComponent } from './components/message-board/message-board.component'; import { MorphingTextComponent } from './components/morphing-text/morphing-text.component'; -import { CamelspacePipe } from './pipes/camelspace.pipe'; import { FormsModule } from '@angular/forms'; import { MatchesTermPipe } from './pipes/matches-term.pipe'; import { ObserveOrderPipe } from './pipes/observe-order.pipe'; @@ -41,7 +39,6 @@ import { ProgressbarModule } from 'ngx-bootstrap/progressbar'; const components = [ ClipspanComponent, - ErrorDivComponent, ImageManagerComponent, GameCardComponent, LoginComponent, @@ -49,7 +46,6 @@ const components = [ InplaceEditorComponent, AgedDatePipe, UntilPipe, - CamelspacePipe, ShortTimePipe, UntagPipe, SafeUrlPipe,