Changeset 7c3e6a8
- Timestamp:
- 10/31/21 13:26:57 (3 years ago)
- Branches:
- dev
- Children:
- 728eb31
- Parents:
- ad079e5
- Location:
- src
- Files:
-
- 2 added
- 12 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
src/Clients/Angular/finki-chattery/src/app/core/state/question-facade.service.ts
rad079e5 r7c3e6a8 2 2 import { Injectable } from '@angular/core'; 3 3 import { Action, Store } from '@ngrx/store'; 4 import { Observable, Subject , throwError} from 'rxjs';5 import { catchError, filter, map} from 'rxjs/operators';4 import { Observable, Subject } from 'rxjs'; 5 import { filter } from 'rxjs/operators'; 6 6 7 7 import { … … 9 9 PreviewQuestionViewModel, 10 10 QuestionStateViewModel, 11 SearchQuestionsQueryViewModel 11 SearchQuestionsQueryViewModel, 12 VoteType 12 13 } from 'src/app/shared-app/models'; 13 14 import { … … 16 17 GetPreviewQuestionsPopular, 17 18 GetQuestionState, 18 GetSearchQuestions 19 GetSearchQuestions, 20 VoteAnswer 19 21 } from './question-state/question.actions'; 20 22 import { questionStateQuery } from './question-state/question.selectors'; … … 30 32 31 33 constructor(private store: Store<QuestionState>) { 32 this.effectWorking$ = this.store.select(questionStateQuery.effectWorking).pipe( 33 filter((effect) => effect !== null), 34 map((effect) => { 35 if (effect instanceof HttpErrorResponse) { 36 throw effect; 37 } else { 38 return effect; 39 } 40 }), 41 catchError((err) => { 42 return throwError(err); 43 }) 44 ); 34 this.effectWorking$ = this.store.select(questionStateQuery.effectWorking).pipe(filter((effect) => effect !== null)); 45 35 } 46 36 … … 81 71 } 82 72 73 public voteAnswer(answerUid: string, questionUid: string, voteType: VoteType): void { 74 this.dispatchEffect(new VoteAnswer(questionUid, answerUid, voteType)); 75 } 76 83 77 public fetchQuestion(questionUid: string): void { 84 78 this.dispatchEffect(new GetQuestionState(questionUid)); -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question-state-response.models.ts
rad079e5 r7c3e6a8 1 import { VoteType } from 'src/app/shared-app/models'; 2 1 3 export class QuestionStateResponse { 2 4 public uid!: string; … … 73 75 public text!: string; 74 76 } 77 78 export class VoteAnswerResponse { 79 public answerUid!: string; 80 public voteUid!: string; 81 public voteType!: VoteType; 82 } -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.actions.ts
rad079e5 r7c3e6a8 2 2 import { Action } from '@ngrx/store'; 3 3 4 import { PreviewQuestionViewModel, QuestionStateViewModel, SearchQuestionsQueryViewModel } from 'src/app/shared-app/models'; 4 import { 5 PreviewQuestionViewModel, 6 QuestionStateViewModel, 7 SearchQuestionsQueryViewModel, 8 VoteAnswerViewModel, 9 VoteType 10 } from 'src/app/shared-app/models'; 5 11 6 12 export enum QuestionActionTypes { … … 13 19 GetSearchQuestions = '[Question] Get search questions', 14 20 GetSearchQuestionsSuccess = '[Question] Get search questions Success', 21 VoteAnswer = '[Question] Vote answer', 22 VoteAnswerSuccess = '[Question] Vote answer Success', 15 23 EffectStartedWorking = '[Question] Effect Started Working', 16 24 EffectFinishedWorking = '[Question] Effect Finished Working', … … 66 74 } 67 75 76 export class VoteAnswer implements Action { 77 readonly type = QuestionActionTypes.VoteAnswer; 78 79 constructor(public questionUid: string, public answerUid: string, public voteType: VoteType) {} 80 } 81 82 export class VoteAnswerSuccess implements Action { 83 readonly type = QuestionActionTypes.VoteAnswerSuccess; 84 85 constructor(public payload: VoteAnswerViewModel) {} 86 } 87 68 88 export class EffectStartedWorking implements Action { 69 89 readonly type = QuestionActionTypes.EffectStartedWorking; … … 89 109 | GetPreviewQuestionsPopularSuccess 90 110 | GetSearchQuestionsSuccess 111 | VoteAnswerSuccess 91 112 | EffectStartedWorking 92 113 | EffectFinishedWorking -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.effects.ts
rad079e5 r7c3e6a8 7 7 import { BaseApiService } from 'src/app/shared-app/services/base-api.service'; 8 8 import { QuestionFacadeService } from '../question-facade.service'; 9 import { PreviewQuestionResponse, QuestionStateResponse } from './question-state.models'; 9 import { VoteAnswerRequest } from './question-state-request.models'; 10 import { PreviewQuestionResponse, QuestionStateResponse, VoteAnswerResponse } from './question-state-response.models'; 10 11 import { 11 12 EffectFinishedWorking, … … 19 20 GetSearchQuestions, 20 21 GetSearchQuestionsSuccess, 21 QuestionActionTypes 22 QuestionActionTypes, 23 VoteAnswer, 24 VoteAnswerSuccess 22 25 } from './question.actions'; 23 26 import { QuestionMapper } from './question.mapper'; … … 103 106 ); 104 107 }); 108 109 voteAnswer$ = createEffect(() => { 110 return this.actions$.pipe( 111 ofType<VoteAnswer>(QuestionActionTypes.VoteAnswer), 112 mergeMap((action) => { 113 const body = new VoteAnswerRequest(action.voteType); 114 return this.api.post<VoteAnswerResponse>(`v1/questions/${action.questionUid}/answers/${action.answerUid}/votes`, body).pipe( 115 switchMap((state) => [new VoteAnswerSuccess(QuestionMapper.ToVoteAnswerViewModel(state)), new EffectFinishedWorking()]), 116 catchError((err) => [new EffectFinishedWorkingError(err)]) 117 ); 118 }) 119 ); 120 }); 105 121 } -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.mapper.ts
rad079e5 r7c3e6a8 10 10 QuestionStateViewModel, 11 11 StudentQuestionStateViewModel, 12 TeamQuestionStateViewModel 12 TeamQuestionStateViewModel, 13 VoteAnswerViewModel 13 14 } from 'src/app/shared-app/models'; 14 15 import { TranslateFromJsonService } from 'src/app/shared-app/services'; 15 import { PreviewQuestionResponse, QuestionStateResponse } from './question-state.models';16 import { PreviewQuestionResponse, QuestionStateResponse, VoteAnswerResponse } from './question-state-response.models'; 16 17 17 18 export class QuestionMapper { … … 113 114 return questions; 114 115 } 116 117 public static ToVoteAnswerViewModel(response: VoteAnswerResponse): VoteAnswerViewModel { 118 return new VoteAnswerViewModel(response.answerUid, response.voteUid, response.voteType); 119 } 115 120 } -
src/Clients/Angular/finki-chattery/src/app/core/state/question-state/question.reducers.ts
rad079e5 r7c3e6a8 1 import { VoteType } from 'src/app/shared-app/models'; 1 2 import { QuestionAction, QuestionActionTypes } from './question.actions'; 2 3 import { initialState, QuestionState } from './question.state'; … … 25 26 searchQuestionsQuery: action.query 26 27 }; 28 case QuestionActionTypes.VoteAnswerSuccess: { 29 if (state.question) { 30 return { 31 ...state, 32 question: { 33 ...state.question, 34 answers: state.question.answers.map((x) => { 35 if (x.uid === action.payload.answerUid) { 36 let votesCountNew = x.votesCount; 37 38 switch (action.payload.voteType) { 39 case VoteType.Upvote: 40 votesCountNew++; 41 break; 42 case VoteType.Downvote: 43 votesCountNew--; 44 break; 45 } 46 47 return { 48 ...x, 49 votesCount: votesCountNew 50 }; 51 } 52 53 return x; 54 }) 55 } 56 }; 57 } 58 59 return { 60 ...state 61 }; 62 } 27 63 case QuestionActionTypes.EffectStartedWorking: { 28 64 return { -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/vote/vote.component.ts
rad079e5 r7c3e6a8 1 1 import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; 2 import { VoteType } from 'src/app/shared-app/models'; 2 3 import { ButtonType } from '../button/button.models'; 3 4 export enum VoteType {5 Upvote,6 Downvote7 }8 4 9 5 @Component({ -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.html
rad079e5 r7c3e6a8 14 14 <mat-card-content> 15 15 <div fxLayout="row wrap" fxLayoutAlign="space-around none"> 16 <app-vote [voteCount]="answer.votesCount" [correct]="answer.correctAnswer" fxFlex="6%"></app-vote> 16 <app-vote 17 [voteCount]="answer.votesCount" 18 [correct]="answer.correctAnswer" 19 (voteClicked)="answerVoted($event, answer.uid, question.uid)" 20 fxFlex="6%" 21 ></app-vote> 17 22 <div fxFlex="92%"> 18 23 <app-text-editor -
src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.ts
rad079e5 r7c3e6a8 1 import { HttpErrorResponse } from '@angular/common/http'; 1 2 import { Component, OnInit } from '@angular/core'; 3 import { NotificationService } from 'src/app/core/services/notification.service'; 2 4 import { QuestionFacadeService } from 'src/app/core/state/question-facade.service'; 3 5 4 import { QuestionStateViewModel } from 'src/app/shared-app/models';6 import { QuestionStateViewModel, VoteType } from 'src/app/shared-app/models'; 5 7 import { ButtonType } from '../../generic/button/button.models'; 6 8 … … 14 16 working = true; 15 17 ButtonType = ButtonType; 16 constructor(private questionFacade: QuestionFacadeService ) {}18 constructor(private questionFacade: QuestionFacadeService, private notification: NotificationService) {} 17 19 18 20 ngOnInit(): void { … … 21 23 this.working = false; 22 24 }); 25 26 this.questionFacade.effectWorking$.subscribe((effect) => { 27 if (effect instanceof HttpErrorResponse) { 28 this.notification.handleErrorsNotification(effect.error); 29 } 30 }); 31 } 32 33 answerVoted(voteType: VoteType, answerUid: string, questionUid: string): void { 34 this.questionFacade.voteAnswer(answerUid, questionUid, voteType); 23 35 } 24 36 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/models/question-state-enums.models.ts
rad079e5 r7c3e6a8 3 3 Popular 4 4 } 5 6 export enum VoteType { 7 Upvote, 8 Downvote 9 } -
src/Clients/Angular/finki-chattery/src/app/shared-app/models/question-state-view-models.models.ts
rad079e5 r7c3e6a8 1 import { VoteType } from '.'; 2 1 3 export class QuestionStateViewModel { 2 4 constructor( … … 73 75 constructor(public text: string) {} 74 76 } 77 78 export class VoteAnswerViewModel { 79 constructor(public answerUid: string, public voteUid: string, public voteType: VoteType) {} 80 } -
src/Clients/Angular/finki-chattery/src/assets/translations/en.json
rad079e5 r7c3e6a8 53 53 "ask-question-stepper-ask": "Ask question", 54 54 "ask-question-ask-button-back": "Edit question", 55 "ask-question-ask-button": "Ask question" 55 "ask-question-ask-button": "Ask question", 56 "AnswerAlreadyUpvoted": "You have already upvoted this answer", 57 "AnswerAlreadyDownvoted": "You have already downvoted this answer", 58 "StudentHasBadReputation": "You have bad reputation and can not vote" 56 59 } -
src/FinkiChattery/FinkiChattery.Api/Controllers/v1/VotesController.cs
rad079e5 r7c3e6a8 30 30 VoteType voteType = request.VoteType == VoteTypeRequest.Upvote ? VoteType.Upvote : VoteType.Downvote; 31 31 var voteUid = await MediatorService.SendAsync(new VoteAnswerCommand(voteType, answerUid, questionUid)); 32 return Ok( voteUid);32 return Ok(new VoteAnswerResponse(answerUid, voteUid, request.VoteType)); 33 33 } 34 34 }
Note:
See TracChangeset
for help on using the changeset viewer.