Changeset c205cc4


Ignore:
Timestamp:
10/27/21 21:29:11 (3 years ago)
Author:
Стојков Марко <mst@…>
Branches:
dev
Children:
32cd040
Parents:
d2b1fa6
Message:

Ask question finishing touches

Location:
src
Files:
2 deleted
16 edited

Legend:

Unmodified
Added
Removed
  • src/Clients/Angular/finki-chattery/src/app/app-routing.module.ts

    rd2b1fa6 rc205cc4  
    66const routes: Routes = [
    77  {
     8    path: 'questioning',
     9    canActivate: [AuthorizedGuard],
     10    loadChildren: () => import('./modules/questioning/questioning.module').then((x) => x.QuestioningModule)
     11  },
     12  {
    813    path: 'auth-callback',
     14    pathMatch: 'full',
    915    component: AuthCallbackComponent
    1016  },
    1117  {
    12     path: 'questioning',
    13     canActivate: [AuthorizedGuard],
    14     loadChildren: () => import('./modules/questioning/questioning.module').then((x) => x.QuestioningModule)
     18    path: '',
     19    pathMatch: 'full',
     20    redirectTo: 'questioning/preview'
    1521  },
    1622  {
  • src/Clients/Angular/finki-chattery/src/app/core/core.module.ts

    rd2b1fa6 rc205cc4  
    99import { SharedMaterialModule } from '../shared-material/shared-material.module';
    1010import { COMPONENTS } from './components/components';
    11 import { GUARDS } from './guards/guards';
    1211import { LoaderInterceptor } from './interceptors/loader.interceptor';
    1312import { reducers } from './state';
     
    2019  declarations: [COMPONENTS],
    2120  providers: [
    22     GUARDS,
    2321    { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptor, multi: true },
    2422    { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true }
  • src/Clients/Angular/finki-chattery/src/app/core/services/auth.service.ts

    rd2b1fa6 rc205cc4  
    11import { Injectable } from '@angular/core';
    2 import { User, UserManager } from 'oidc-client';
     2import { User, UserManager, WebStorageStateStore } from 'oidc-client';
    33import { Observable, of } from 'rxjs';
    44
    55import { environment } from '@env/environment';
    6 import { ApplicationUser, SelfUserResponse } from 'src/app/shared-app/models';
     6import { ApplicationUser, ApplicationUserType, SelfUserResponse } from 'src/app/shared-app/models';
    77import { BaseApiService } from 'src/app/shared-app/services/base-api.service';
    88
     
    1717    response_type: 'id_token token',
    1818    scope: 'openid app.api.finki-chattery profile',
    19     post_logout_redirect_uri: window.location.origin
     19    post_logout_redirect_uri: window.location.origin,
     20    filterProtocolClaims: true,
     21    loadUserInfo: true,
     22    userStore: new WebStorageStateStore({ store: window.localStorage })
    2023  });
    2124
     
    2326  public oidcUser: User | null = null;
    2427
    25   constructor(private baseApi: BaseApiService) {}
     28  constructor(private baseApi: BaseApiService) {
     29    this.userManager.getUser().then((user) => {
     30      this.oidcUser = user;
     31      this.user = new ApplicationUser(
     32        user?.profile.id,
     33        user?.profile.userType,
     34        user?.profile.emailAddress,
     35        user?.profile.username,
     36        user?.profile.isVerified
     37      );
     38    });
     39  }
    2640
    2741  public login(): void {
     
    3852    }
    3953    return false;
     54  }
     55
     56  public isStudent(): boolean {
     57    return this.user?.userType === ApplicationUserType.Student;
    4058  }
    4159
  • src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/ask-question/ask-question.component.html

    rd2b1fa6 rc205cc4  
    11<form class="example-container" [formGroup]="questionFormGroup">
    2   <mat-form-field class="full-width" appearance="standard" appHandleInputFormErrors>
    3     <mat-label>STAVI TRANSLATE</mat-label>
     2  <mat-form-field class="full-width margin-bottom-sm" appearance="fill" appHandleInputFormErrors>
     3    <mat-label>{{ 'ask-question-question-title' | translate }}</mat-label>
    44    <input matInput [formControl]="titleForm" />
    55  </mat-form-field>
     
    77  <editor
    88    matInput
     9    class="margin-bottom-sm"
    910    [formControl]="textForm"
    1011    [init]="{
     12      apiKey: 'fx28x0d64jeufa35u7mcd80fgveayg5c4ap9gnr6posehzny',
    1113      menubar: false,
    1214      plugins: [
     
    1618      ],
    1719      toolbar:
    18         'undo redo | formatselect | bold italic backcolor | \
     20        'undo redo | formatselect | bold italic backcolor | code | \
    1921        alignleft aligncenter alignright alignjustify | \
    2022        bullist numlist outdent indent | removeformat | help'
     
    2224  ></editor>
    2325  <mat-error *ngIf="textForm?.touched && textForm?.errors?.required">{{ 'not-found' | translate }}</mat-error>
    24   <mat-error *ngIf="textForm?.touched && textForm?.errors?.maxlength">STAVI TRANSL ATE MAX LENGTH</mat-error>
     26  <mat-error *ngIf="textForm?.touched && textForm?.errors?.maxlength">{{
     27    'error-message-max-length' | translate: { maxlength: textForm?.errors?.maxlength?.requiredLength }
     28  }}</mat-error>
    2529
    26   <mat-form-field class="full-width" appearance="standard" appHandleInputFormErrors>
    27     <mat-label>STAVI TRANSLATE</mat-label>
     30  <mat-form-field class="full-width margin-bottom-sm" appearance="fill" appHandleInputFormErrors>
     31    <mat-label>{{ 'ask-question-categories' | translate }}</mat-label>
    2832    <mat-select [formControl]="categoriesForm" multiple>
    29       <mat-option *ngFor="let category of categoriesList" [value]="category.uid">{{ category.name }}</mat-option>
     33      <mat-option *ngFor="let category of categoriesList$ | async" [value]="category.uid">{{ category.translatedName }}</mat-option>
    3034    </mat-select>
    3135  </mat-form-field>
    3236
    3337  <app-button [disabled]="questionFormGroup.invalid" [buttonType]="ButtonType.CallToAction" (action)="askQuestion()">
    34     {{ 'not-found' | translate }}
     38    {{ 'ask-question-ask-button' | translate }}
    3539  </app-button>
    3640</form>
  • src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/ask-question/ask-question.component.scss

    rd2b1fa6 rc205cc4  
    1 .full-width {
    2   width: 100%;
    3 }
  • src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/ask-question/ask-question.component.ts

    rd2b1fa6 rc205cc4  
    11import { Component, OnInit } from '@angular/core';
    22import { FormControl, FormGroup, Validators } from '@angular/forms';
     3import { Router } from '@angular/router';
    34
     5import { CategoryFacadeService } from 'src/app/core/state/category-facade.service';
    46import { ButtonType } from 'src/app/shared-app/components/generic/button/button.models';
    5 import { CategoryViewModel } from 'src/app/shared-app/models';
    67import { AskQuestionRequest } from '../../models/questioning-request.models';
    78import { QuestioningApiService } from '../../services/questioning-api.service';
     
    1617  public textForm = new FormControl('', [Validators.required, Validators.maxLength(4000)]);
    1718  public categoriesForm = new FormControl([]);
    18 
    1919  public questionFormGroup: FormGroup;
    2020  public ButtonType = ButtonType;
     21  public categoriesList$ = this.categoriesFacade.getCategories();
    2122
    22   // TODO: PULL FROM ENDPOINT OR FROM STORE (BETTER FROM STORE)
    23   public categoriesList: CategoryViewModel[] = [
    24     new CategoryViewModel('123', 'test'),
    25     new CategoryViewModel('345', 'test 2'),
    26     new CategoryViewModel('345', 'test 3'),
    27     new CategoryViewModel('345', 'test 4'),
    28     new CategoryViewModel('345', 'test 5')
    29   ];
    30 
    31   constructor(private api: QuestioningApiService) {
     23  constructor(private api: QuestioningApiService, private categoriesFacade: CategoryFacadeService, private router: Router) {
    3224    this.questionFormGroup = new FormGroup({
    3325      title: this.titleForm,
     
    4133  public askQuestion(): void {
    4234    const body = new AskQuestionRequest(this.titleForm.value, this.textForm.value, this.categoriesForm.value);
    43     this.api.askQuestion(body).subscribe(() => {});
     35    this.api.askQuestion(body).subscribe((questionUid) => {
     36      this.router.navigateByUrl(`questioning/${questionUid}`);
     37    });
    4438  }
    4539}
  • src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/questioning-general/questioning-general.component.ts

    rd2b1fa6 rc205cc4  
    11import { Component, OnInit } from '@angular/core';
     2import { CategoryFacadeService } from 'src/app/core/state/category-facade.service';
    23
    34@Component({
     
    78})
    89export class QuestioningGeneralComponent implements OnInit {
    9   constructor() {}
     10  constructor(private categoriesFacade: CategoryFacadeService) {}
    1011
    11   ngOnInit(): void {}
     12  ngOnInit(): void {
     13    this.categoriesFacade.fetchCategories();
     14  }
    1215}
  • src/Clients/Angular/finki-chattery/src/app/modules/questioning/components/questions-preview-general/questions-preview-general.component.ts

    rd2b1fa6 rc205cc4  
    1717  questionsSortByForm = new FormControl(PreviewQuestionsOrderEnum.Latest);
    1818
    19   constructor(private categoriesFacade: CategoryFacadeService, private questionFacade: QuestionFacadeService, private router: Router) {}
     19  constructor(private questionFacade: QuestionFacadeService, private router: Router) {}
    2020
    2121  ngOnInit(): void {
    22     this.categoriesFacade.fetchCategories();
    2322    this.questionFacade.fetchPreviewQuestions(PreviewQuestionsOrderEnum.Latest);
    2423    this.questionsSortByForm.valueChanges.subscribe((value: PreviewQuestionsOrderEnum) => {
  • src/Clients/Angular/finki-chattery/src/app/modules/questioning/services/questioning-api.service.ts

    rd2b1fa6 rc205cc4  
    1313  }
    1414
    15   askQuestion(body: AskQuestionRequest): Observable<void> {
     15  askQuestion(body: AskQuestionRequest): Observable<string> {
    1616    return this.post('v1/questions', body);
    1717  }
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/header/header.component.html

    rd2b1fa6 rc205cc4  
    22  <span>FinkiChattery</span>
    33  <span class="right"></span>
    4   <app-button *ngIf="auth.isLoggedIn()" (action)="logout()" [buttonType]="ButtonType.CallToAction">Logout</app-button>
     4  <app-button class="margin-y-xs" *ngIf="auth.isStudent()" (action)="askQuestion()" [buttonType]="ButtonType.CallToAction">{{
     5    'header-ask-question' | translate
     6  }}</app-button>
     7  <app-button class="margin-y-xs" *ngIf="auth.isLoggedIn()" (action)="logout()" [buttonType]="ButtonType.Basic">{{
     8    'header-logout' | translate
     9  }}</app-button>
    510</mat-toolbar>
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/generic/header/header.component.ts

    rd2b1fa6 rc205cc4  
    11import { Component, OnInit } from '@angular/core';
     2import { Router } from '@angular/router';
    23import { AuthService } from 'src/app/core/services';
    34import { ButtonType } from '../button/button.models';
     
    1112  ButtonType = ButtonType;
    1213
    13   constructor(public auth: AuthService) {}
     14  constructor(public auth: AuthService, private router: Router) {}
    1415
    1516  ngOnInit(): void {}
     
    1819    this.auth.logout();
    1920  }
     21
     22  askQuestion(): void {
     23    this.router.navigateByUrl('questioning/ask');
     24  }
    2025}
  • src/Clients/Angular/finki-chattery/src/app/shared-app/components/question/question-preview/question-preview.component.html

    rd2b1fa6 rc205cc4  
    2020      </mat-chip-list>
    2121
    22       <div class="margin-top-lg" [innerHTML]="question.text"></div>
     22      <editor
     23        class="margin-x-sm"
     24        [init]="{
     25          apiKey: 'fx28x0d64jeufa35u7mcd80fgveayg5c4ap9gnr6posehzny',
     26          menubar: false,
     27          plugins: ['autoresize'],
     28          toolbar: ''
     29        }"
     30        [disabled]="true"
     31        [initialValue]="question.text"
     32      ></editor>
    2333      <div class="align-right">
    2434        <app-student-card
     
    4858          <app-vote [voteCount]="answer.upvotesCount" [correct]="answer.correctAnswer" fxFlex="6%"></app-vote>
    4959          <div fxFlex="92%">
    50             <div [innerHTML]="answer.text"></div>
     60            <editor
     61              class="margin-x-sm"
     62              [init]="{
     63                apiKey: 'fx28x0d64jeufa35u7mcd80fgveayg5c4ap9gnr6posehzny',
     64                menubar: false,
     65                plugins: ['autoresize'],
     66                toolbar: ''
     67              }"
     68              [disabled]="true"
     69              [initialValue]="answer.text"
     70            ></editor>
    5171            <div class="align-right">
    5272              <app-student-card
  • src/Clients/Angular/finki-chattery/src/assets/translations/en.json

    rd2b1fa6 rc205cc4  
    4444  "questions-preview-question-answers": "Answers",
    4545  "questions-preview-question-views": "Views",
    46   "questions-search-title": "Search results for: {{searchQuery}}"
     46  "questions-search-title": "Search results for: {{searchQuery}}",
     47  "ask-question-question-title": "Question title",
     48  "ask-question-categories": "Add categories to question",
     49  "ask-question-ask-button": "Ask question",
     50  "header-logout": "Logout",
     51  "header-ask-question": "Ask question"
    4752}
  • src/FinkiChattery/FinkiChattery.Api/Controllers/v1/QuestionsController.cs

    rd2b1fa6 rc205cc4  
    2929        public async Task<IActionResult> AskQuestion([FromBody] AskQuestionRequest request)
    3030        {
    31             await MediatorService.SendAsync(new AskQuestionCommand(request.Title, request.Text, request.Categories));
    32             return Ok();
     31            var questionUid = await MediatorService.SendAsync(new AskQuestionCommand(request.Title, request.Text, request.Categories));
     32            return Ok(questionUid);
    3333        }
    3434
  • src/FinkiChattery/FinkiChattery.Persistence/Configurations/QuestionConfig.cs

    rd2b1fa6 rc205cc4  
    2424            builder.Property(x => x.Views).HasColumnName(@"Views").HasColumnType("bigint").IsRequired().HasDefaultValue(0);
    2525            builder.Property(x => x.LastActiveOn).HasColumnName(@"LastActiveOn").HasColumnType("smalldatetime").IsRequired();
    26             builder.Property(x => x.Search).HasColumnType(@"Search").HasColumnType("nvarchar").HasMaxLength(4000).IsRequired();
     26            builder.Property(x => x.Search).HasComputedColumnSql(@"Search").HasColumnType("nvarchar").ValueGeneratedOnAddOrUpdate().HasMaxLength(4000).IsRequired();
    2727            builder.Property(x => x.AnswersCount).HasColumnType(@"AnswersCount").HasColumnType("bigint").IsRequired().HasDefaultValue(0);
    2828
  • src/FinkiChattery/FinkiChattery.Persistence/Models/Question.cs

    rd2b1fa6 rc205cc4  
    11using System;
    22using System.Collections.Generic;
     3using System.ComponentModel.DataAnnotations.Schema;
    34
    45namespace FinkiChattery.Persistence.Models
     
    3233        public DateTime LastActiveOn { get; set; }
    3334
     35        [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    3436        public string Search { get; set; }
    3537
Note: See TracChangeset for help on using the changeset viewer.