Ignore:
Timestamp:
11/03/21 16:42:35 (3 years ago)
Author:
Стојков Марко <mst@…>
Branches:
dev
Children:
b9d7ae5
Parents:
80e2fe0
Message:

Set correct answer for question by question owner

Location:
src/Clients/Angular/finki-chattery/src
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • src/Clients/Angular/finki-chattery/src/app/core/services/auth.service.ts

    r80e2fe0 r2a9d9d1  
    2424  public user: ApplicationUser | null = null;
    2525  public oidcUser: User | null = null;
     26  public selfUser: SelfUserResponse | null = null;
    2627
    2728  constructor(private baseApi: BaseApiService) {
     
    3536        user?.profile.isVerified
    3637      );
     38
     39      this.selfUserDto().subscribe((selfUser) => {
     40        if (selfUser) {
     41          this.selfUser = selfUser;
     42        }
     43      });
    3744    });
    3845  }
     
    8693        user.profile.isVerified
    8794      );
     95
     96      if (!this.selfUser) {
     97        this.selfUserDto().subscribe((selfUser) => {
     98          if (selfUser) {
     99            this.selfUser = selfUser;
     100          }
     101        });
     102      }
    88103    });
    89104  }
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-facade.service.ts

    r80e2fe0 r2a9d9d1  
    33import { Action, Store } from '@ngrx/store';
    44import { Observable, Subject } from 'rxjs';
    5 import { filter } from 'rxjs/operators';
     5import { filter, map } from 'rxjs/operators';
    66
    77import {
     
    1212  VoteType
    1313} from 'src/app/shared-app/models';
     14import { AuthService } from '../services';
    1415import {
    1516  EffectStartedWorking,
     
    1819  GetQuestionState,
    1920  GetSearchQuestions,
     21  SetCorrectAnswer,
    2022  VoteAnswer
    2123} from './question-state/question.actions';
     
    3133  effectWorking$: Observable<boolean | HttpErrorResponse>;
    3234
    33   constructor(private store: Store<QuestionState>) {
     35  constructor(private store: Store<QuestionState>, private auth: AuthService) {
    3436    this.effectWorking$ = this.store.select(questionStateQuery.effectWorking).pipe(filter((effect) => effect !== null));
     37  }
     38
     39  public currentQuestionOwnedByCurrentUser(): Observable<boolean> {
     40    return this.getQuestion().pipe(map((question) => this.auth.selfUser?.student?.uid === question.student.uid));
    3541  }
    3642
     
    7177  }
    7278
     79  public setCorrectAnswer(questionUid: string, answerUid: string): void {
     80    this.dispatchEffect(new SetCorrectAnswer(questionUid, answerUid));
     81  }
     82
    7383  public voteAnswer(answerUid: string, questionUid: string, voteType: VoteType): void {
    7484    this.dispatchEffect(new VoteAnswer(questionUid, answerUid, voteType));
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.actions.ts

    r80e2fe0 r2a9d9d1  
    1313  GetQuestionState = '[Question] Get state',
    1414  GetQuestionStateSuccess = '[Question] Get state success',
     15  SetCorrectAnswer = '[Question] Set Correct Answer',
     16  SetCorrectAnswerSuccess = '[Question] Set Correct Answer success',
    1517  GetPreviewQuestionsLatest = '[Question] Get preview questions Latest',
    1618  GetPreviewQuestionsLatestSuccess = '[Question] Get preview questions Latest Success',
     
    3638
    3739  constructor(public payload: QuestionStateViewModel) {}
     40}
     41
     42export class SetCorrectAnswer implements Action {
     43  readonly type = QuestionActionTypes.SetCorrectAnswer;
     44
     45  constructor(public questionUid: string, public answerUid: string) {}
     46}
     47
     48export class SetCorrectAnswerSuccess implements Action {
     49  readonly type = QuestionActionTypes.SetCorrectAnswerSuccess;
     50
     51  constructor(public payload: string) {}
    3852}
    3953
     
    110124  | GetSearchQuestionsSuccess
    111125  | VoteAnswerSuccess
     126  | SetCorrectAnswerSuccess
    112127  | EffectStartedWorking
    113128  | EffectFinishedWorking
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.effects.ts

    r80e2fe0 r2a9d9d1  
    11import { Injectable } from '@angular/core';
    22import { act, Actions, createEffect, ofType } from '@ngrx/effects';
    3 import { catchError, filter, mergeMap, switchMap, withLatestFrom } from 'rxjs/operators';
     3import { catchError, filter, mergeMap, switchMap, tap, withLatestFrom } from 'rxjs/operators';
    44import { PreviewQuestionsOrderEnum, SearchQuestionsQueryViewModel } from 'src/app/shared-app/models';
    55import { TranslateFromJsonService } from 'src/app/shared-app/services';
    66
    77import { BaseApiService } from 'src/app/shared-app/services/base-api.service';
     8import { NotificationService } from '../../services/notification.service';
    89import { QuestionFacadeService } from '../question-facade.service';
    910import { VoteAnswerRequest } from './question-state-request.models';
     
    2122  GetSearchQuestionsSuccess,
    2223  QuestionActionTypes,
     24  SetCorrectAnswer,
     25  SetCorrectAnswerSuccess,
    2326  VoteAnswer,
    2427  VoteAnswerSuccess
     
    3437    private api: BaseApiService,
    3538    private translate: TranslateFromJsonService,
    36     private facade: QuestionFacadeService
     39    private facade: QuestionFacadeService,
     40    private notification: NotificationService
    3741  ) {}
    3842
     
    113117        const body = new VoteAnswerRequest(action.voteType);
    114118        return this.api.post<VoteAnswerResponse>(`v1/questions/${action.questionUid}/answers/${action.answerUid}/votes`, body).pipe(
     119          tap((state) => this.notification.successNotification('sucess-vote')),
    115120          switchMap((state) => [new VoteAnswerSuccess(QuestionMapper.ToVoteAnswerViewModel(state)), new EffectFinishedWorking()]),
    116121          catchError((err) => [new EffectFinishedWorkingError(err)])
     
    119124    );
    120125  });
     126
     127  setCorrectAnswer$ = createEffect(() => {
     128    return this.actions$.pipe(
     129      ofType<SetCorrectAnswer>(QuestionActionTypes.SetCorrectAnswer),
     130      mergeMap((action) => {
     131        return this.api.put<string>(`v1/questions/${action.questionUid}/answers/${action.answerUid}/correct`).pipe(
     132          tap((state) => this.notification.successNotification('success-correct-answer')),
     133          switchMap((state) => [new SetCorrectAnswerSuccess(state), new EffectFinishedWorking()]),
     134          catchError((err) => [new EffectFinishedWorkingError(err)])
     135        );
     136      })
     137    );
     138  });
    121139}
  • src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.reducers.ts

    r80e2fe0 r2a9d9d1  
    1 import { VoteType } from 'src/app/shared-app/models';
     1import { AnswerQuestionStateViewModel, VoteType } from 'src/app/shared-app/models';
    22import { QuestionAction, QuestionActionTypes } from './question.actions';
    33import { initialState, QuestionState } from './question.state';
     
    6161      };
    6262    }
     63    case QuestionActionTypes.SetCorrectAnswerSuccess: {
     64      if (state.question) {
     65        return {
     66          ...state,
     67          question: {
     68            ...state.question,
     69            answers: state.question.answers.map((x) => {
     70              if (x.correctAnswer) {
     71                return {
     72                  ...x,
     73                  correctAnswer: false
     74                };
     75              }
     76              if (x.uid === action.payload) {
     77                return {
     78                  ...x,
     79                  correctAnswer: true
     80                };
     81              }
     82              return x;
     83            })
     84          }
     85        };
     86      }
     87
     88      return {
     89        ...state
     90      };
     91    }
    6392    case QuestionActionTypes.EffectStartedWorking: {
    6493      return {
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/vote/vote.component.html

    r80e2fe0 r2a9d9d1  
    1 <div>
     1<div class="main-div">
    22  <div class="vote-icons" fxLayout="column" fxLayoutAlign="center center">
    33    <mat-icon class="vote-icon" (click)="voted(VoteType.Upvote)" [inline]="true">arrow_drop_up</mat-icon>
     
    77      >check</mat-icon
    88    >
     9    <mat-icon
     10      *ngIf="canSetCorrectAnswer && !correct"
     11      [inline]="true"
     12      class="text-center text-bold green set-correct-answer"
     13      (click)="setCorrectAnswer.emit()"
     14      >check</mat-icon
     15    >
    916  </div>
    1017</div>
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/vote/vote.component.scss

    r80e2fe0 r2a9d9d1  
    1414  cursor: pointer;
    1515}
     16
     17.show-on-hover {
     18  display: none;
     19}
     20
     21.set-correct-answer {
     22  opacity: 0.3;
     23  visibility: hidden;
     24}
     25
     26.main-div:hover > .vote-icons > .set-correct-answer {
     27  visibility: visible;
     28}
     29
     30.main-div {
     31  height: 100%;
     32}
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/vote/vote.component.ts

    r80e2fe0 r2a9d9d1  
    1010export class VoteComponent implements OnInit {
    1111  @Input() voteCount: number | undefined;
     12  @Input() canSetCorrectAnswer: boolean | null = false;
    1213  @Input() correct = false;
    1314  @Output() voteClicked = new EventEmitter<VoteType>();
     15  @Output() setCorrectAnswer = new EventEmitter<void>();
    1416
    1517  VoteType = VoteType;
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.html

    r80e2fe0 r2a9d9d1  
    1515        <div fxLayout="row wrap" fxLayoutAlign="space-around none">
    1616          <app-vote
     17            [canSetCorrectAnswer]="canSetCorrectAnswer | async"
    1718            [voteCount]="answer.votesCount"
    1819            [correct]="answer.correctAnswer"
    1920            (voteClicked)="answerVoted($event, answer.uid, question.uid)"
     21            (setCorrectAnswer)="setCorrectAnswer(question.uid, answer.uid)"
    2022            fxFlex="6%"
    2123          ></app-vote>
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.ts

    r80e2fe0 r2a9d9d1  
    1313})
    1414export class QuestionPreviewComponent implements OnInit {
     15  canSetCorrectAnswer = this.questionFacade.currentQuestionOwnedByCurrentUser();
    1516  question!: QuestionStateViewModel;
    1617  working = true;
     
    3435    this.questionFacade.voteAnswer(answerUid, questionUid, voteType);
    3536  }
     37
     38  setCorrectAnswer(questionUid: string, answerUid: string): void {
     39    this.questionFacade.setCorrectAnswer(questionUid, answerUid);
     40  }
    3641}
  • src/Clients/Angular/finki-chattery/src/app/shared-app/models/user.models.ts

    r80e2fe0 r2a9d9d1  
    99}
    1010
    11 export class SelfUserResponse {
    12   uid!: string;
    13 }
    14 
    1511export enum ApplicationUserType {
    1612  Student = 'Student',
     
    1915  Guest = 'Guest'
    2016}
     17
     18export class SelfUserResponse {
     19  public student?: StudentSelfResponse | null;
     20  public teacher?: TeacherSelfResponse | null;
     21  public moderator?: ModeratorSelfResponse | null;
     22}
     23
     24export class StudentSelfResponse {
     25  public uid!: string;
     26  public applicationUserId!: number;
     27  public index!: string;
     28  public reputation!: number;
     29  public imageUrl!: string;
     30  public questions!: StudentQuestionResponse[];
     31  public teams!: StudentTeamResponse[];
     32}
     33
     34export class StudentQuestionResponse {
     35  public questionUid!: string;
     36  public title!: string;
     37}
     38
     39export class StudentTeamResponse {
     40  public teamUid!: string;
     41  public name!: string;
     42}
     43
     44export class ModeratorSelfResponse {
     45  public uid!: string;
     46  public applicationUserId!: number;
     47}
     48
     49export class TeacherSelfResponse {
     50  public uid!: string;
     51  public applicationUserId!: number;
     52  public teams!: TeacherTeamResponse[];
     53}
     54
     55export class TeacherTeamResponse {
     56  public teamUid!: string;
     57  public name!: string;
     58}
  • src/Clients/Angular/finki-chattery/src/app/shared-app/services/base-api.service.ts

    r80e2fe0 r2a9d9d1  
    1919
    2020  public getSelfUser(): Observable<SelfUserResponse> {
    21     return this.get<SelfUserResponse>('self');
     21    return this.get<SelfUserResponse>('v1/self');
    2222  }
    2323
  • src/Clients/Angular/finki-chattery/src/assets/translations/en.json

    r80e2fe0 r2a9d9d1  
    5353  "ask-question-stepper-ask": "Ask question",
    5454  "ask-question-ask-button-back": "Edit question",
     55  "sucess-vote": "Successfully voted answer",
     56  "success-correct-answer": "Successfully set correct answer",
    5557  "ask-question-ask-button": "Ask question",
    5658  "AnswerAlreadyUpvoted": "You have already upvoted this answer",
Note: See TracChangeset for help on using the changeset viewer.