diff --git a/src/app/app.component.html b/src/app/app.component.html index 978a25397357c5e833c60e894e6fee5fdfb38879..fa706e9738d4d010ca64d79ccac3a52ee3cdf6a2 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,2 +1,4 @@ <app-header *ngIf="!playQuiz"></app-header> -<router-outlet></router-outlet> \ No newline at end of file +<main> + <router-outlet></router-outlet> +</main> \ No newline at end of file diff --git a/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.css b/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.css index 5e95b5d8a42a517882a9e81a1220fab385a1ac07..ba34fb003d6edbaca0b8f5864289cd842833941c 100644 --- a/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.css +++ b/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.css @@ -1,48 +1,212 @@ -.question-table { +.header { + display: flex; + flex-direction: row; + align-items: center; + align-items: center; + justify-content: space-between; + width: 100%; + height: 10vh; } -.w-fit { - width: fit-content !important; +.header mat-icon { + width: auto; + height: auto; + margin: 0; + font-size: 8vmin; + padding-right: 5vw; + /* Your profile */ + font-style: normal; + font-weight: 500; + color: #00B3F4; } -.question-table tbody td:nth-child(2) { - flex: 0 0 auto; - justify-content: center; +.header h1 { + width: auto; + height: auto; + margin: 0; + font-size: 8vmin; + padding-left: 5vw; + /* Your profile */ + font-style: normal; + font-weight: 500; + color: #00B3F4; } -.question-table tbody td:nth-child(3), -.question-table tbody td:nth-child(4) { - flex: 1; +.header mat-icon:hover { + cursor: pointer; + color: #2B73FE; } -.m-10 { - margin: 10px; +.container { + display: flex; + flex-direction: column; + + width: 90vw; + margin-left: 5%; + height: 70vh; + + background-color: #F3F3F3; + + border-radius: 10px; + border: 0.5vmin solid #DBDBDB; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; } -.cell { - border: 1px solid #ccc; +/* form { + height: 100%; +} */ + +input { + height: 3vmin; + width: calc(90vw/2); + margin-top: 0.5vmin; + margin-bottom: 0.5vmin; + /*padding-left: 1vmin; + padding-right: 1vmin; */ + + border-radius: 5px; + border: 0.25vmin solid #DBDBDB; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; } -.row { - max-width: 100%; +select { + height: 3vmin; + width: auto; + margin-top: 0.5vmin; + margin-bottom: 0.5vmin; + /*padding-left: 1vmin; + padding-right: 1vmin; */ + + border-radius: 5px; + border: 0.25vmin solid #DBDBDB; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; } -.add-cell { - max-width: 100%; +.quiz-info-wrapper { + display: flex; + flex-direction: row; + justify-content: left; + align-items: center; + + width: 100%; + /*margin-top: 1vmin;*/ +} + +.label-wrapper { + width: 30%; + text-align: right; + font-size: 3vmin; + margin: 0; + margin-right: 5%; + flex-shrink: 0; +} + +.quiz-info { + display: flex; + flex-direction: column; + + width: 100%; + height: 8vh; +} + +.quiz-info-wrapper select { + width: 30%; +} + +hr { + width: 100%; + height: 0.5vmin; + background-color: #DBDBDB; + border: none; +} + +/*****************************************/ +/* questions Info */ +/*****************************************/ +.question-info { + height: 58vh; + overflow: auto; +} + +/* .question-table { + height: 100%; + overflow: scroll; +} */ + +.question-cell { + display: flex; + flex-direction: row; + align-items: center; + + width: 100%; + margin-top: 1vmin; +} + +.answers-cell { display: flex; - justify-content: center; - border: 2px solid black; - flex-wrap: nowrap; + flex-direction: row; + padding-top: 2vmin; } -.add-cell-question { +.answers-list { + display: flex; + flex-direction: column; width: 100%; - display: table-row; - text-align: center; - border: 2px solid rgba(0, 0, 0, 0.808); } -.bigger-icon { - transform: scale(1.2); +.answer-wrapper { + width: 70%; } + +.answer-cell { + display: flex; + flex-direction: row; + align-items: center; + + width: 100%; +} + +mat-icon { + height: 100%; +} + + +.answer-cell input { + width: calc(45vw - 2.5vmin); +} + +span { + flex-shrink: 0; +} + +.add-cell { + display: flex; + flex-direction: row; + align-items: center; + + width: 100%; + /* margin-top: 1vmin; */ +} + +.add-cell p { + margin: 0; + margin-left: 1%; + font-size: 1.5vmin; + color: #C9C9C9; +} + +.btn-group { + display: flex; + flex-direction: row; + justify-content: space-evenly; + width: 96%; + margin-left: 2%; + margin-top: 0.5%; +} \ No newline at end of file diff --git a/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.html b/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.html index edcc0de521e3df920df7f33df43df9cfe1732c00..0c6238e408f5387c005fd2e960f704e4f1e59f07 100644 --- a/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.html +++ b/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.html @@ -1,74 +1,85 @@ -<div class="col-md-12"> - <div class="card"> - <div class="row"> - <div class="col-md-12"> - <form class="m-10" (ngSubmit)="createQuiz()" [formGroup]="quizForm"> - <label class="m-10">Quiz title : </label> - <input class="m-10" type="text" formControlName="title" /> - <label class="m-10">Difficulty : </label> +<div class="question-marks"> + <div class="header"> + <h1>Create your own quiz</h1> + <mat-icon (click)="createQuiz()">save</mat-icon> + </div> + <div class="container"> + <form [formGroup]="quizForm"> + <div class="quiz-info"> + <div class="quiz-info-wrapper"> + <div class="label-wrapper"> + <label for="title">QUIZ TITLE </label> + </div> + <input type="text" formControlName="title" placeholder="Write the quiz title..." /> + </div> + <div class="quiz-info-wrapper"> + <div class="label-wrapper"> + <label for="difficulty">QUIZ DIFFICULTY </label> + </div> <select formControlName="difficulty"> <option value="easy">Easy</option> <option value="medium">Medium</option> <option value="hard">Hard</option> </select> - <table class="question-table"> - <thead> - <tr> - <th class="photo-cell">Question</th> - <th class="task-type-cell">Answers</th> - </tr> - </thead> - <tbody formArrayName="questions"> - <tr *ngFor="let question of questions.controls; let i = index" [formGroupName]="i"> - <td class="cell question-cell"> - <label>Question : </label> - <input type="text" formControlName="question" /> - </td> - <td class="cell answers-cell" formArrayName="answers"> - <table class="answers-table"> - <tr - *ngFor="let answer of getAnswers(i).controls; let j = index" - [formGroupName]="j" - > - <td> - <input type="text" formControlName="answer" /> - </td> - <td> - <input type="checkbox" [formControlName]="'right_answer'" /> - </td> - - <td (click)="removeAnswer(i, j)"> - <mat-icon style="color: red">delete</mat-icon> - </td> - </tr> - <span *ngIf="getAnswers(i).errors?.['duplicateAnswer']" style="color: red" - >All answers need to be unique.</span - > - <tr class="add-cell" (click)="addAnswer(i)"> - <td> - <mat-icon style="color: brown">add</mat-icon> - </td> - </tr> - </table> - </td> - <td (click)="removeQuestion(i)"> - <mat-icon style="color: red">delete</mat-icon> - </td> - </tr> - <tr class="add-cell-question" (click)="addQuestion()"> - <td colspan="5"> - <mat-icon [style.color]="'brown'">add</mat-icon> - </td> - </tr> - </tbody> - </table> - </form> - <div class="center-button"> - <button (click)="createQuiz()" class="btn btn-secondary btn-success" [disabled]="quizForm.invalid"> - Add - </button> </div> </div> - </div> + <hr> + <div class="question-info"> + <div class="question-table"> + <div formArrayName="questions"> + <div class="question-row" *ngFor="let question of questions.controls; let i = index" + [formGroupName]="i"> + <div class="cell question-cell"> + <div class="label-wrapper"> + <label>QUESTION {{i + 1}} </label> + </div> + <input type="text" formControlName="question" placeholder="Write a question..." /> + <!-- the button bellow is temporary --> + <mat-icon style="color: red" (click)="removeQuestion(i)">delete</mat-icon> + </div> + <div class="cell answers-cell" formArrayName="answers"> + <div class="label-wrapper"> + <label>ANSWERS </label> + </div> + <div class="answer-wrapper"> + <div class="answers-list" + *ngFor="let answer of getAnswers(i).controls; let j = index" + [formGroupName]="j"> + <div class="answer-cell"> + <!-- answer index 0 is always the correct anwser --> + <div *ngIf="j == 0" class="answer-cell"> + <mat-icon style="color: green">check</mat-icon> + <input type="text" formControlName="answer" + placeholder="Write true answer..." /> + </div> + <div *ngIf="j>0" class="answer-cell"> + <mat-icon style="color: red">clear</mat-icon> + <input type="text" formControlName="answer" + placeholder="Write wrong answer..." /> + <mat-icon *ngIf="j > 1" (click)="removeAnswer(i, j)" + style="color: red">delete</mat-icon> + </div> + </div> + </div> + <span *ngIf="getAnswers(i).errors?.['duplicateAnswer']" style="color: red">All + answers need to be unique. + </span> + <div class="add-cell" (click)="addAnswer(i)" *ngIf="getAnswers(i).length<4"> + <!-- <mat-icon style="color: brown">add</mat-icon> --> + <button class="questionsButton">+ ADD AN ANSWER</button> + <p>up to 4</p> + </div> + </div> + </div> + <hr> + </div> + <div class="btn-group"> + <button (click)="addQuestion()" class="questionsButton">+ ADD A QUESTION</button> + <button class="questionsButton">ADD FROM DATABASE</button> + </div> + </div> + </div> + </div> + </form> </div> -</div> +</div> \ No newline at end of file diff --git a/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.ts b/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.ts index 94785c40a42b0b58a36b0977339eff36dcc9bc25..6c6a3dce3dc571020dd1ee71fef6542dd7ae9e52 100644 --- a/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.ts +++ b/src/app/modules/profile/create-custom-quiz/create-custom-quiz.component.ts @@ -1,5 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { AbstractControl, FormArray, FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import Swal from 'sweetalert2'; @Component({ templateUrl: './create-custom-quiz.component.html', @@ -7,14 +9,18 @@ import { AbstractControl, FormArray, FormBuilder, FormGroup, ValidationErrors, V }) export class CreateCustomQuizComponent implements OnInit { quizForm: FormGroup; - constructor(private fb: FormBuilder) { + router: any; + constructor( + private fb: FormBuilder, + router: Router + ) { this.quizForm = this.fb.group({ title: this.fb.control('', [Validators.required, Validators.maxLength(255)]), - difficulty: this.fb.control('', [Validators.required]), + difficulty: this.fb.control('medium', [Validators.required]), questions: this.fb.array([this.createQuestion()], [Validators.required]), }); } - ngOnInit(): void {} + ngOnInit(): void { } get questions(): FormArray { return this.quizForm.get('questions') as FormArray; @@ -37,7 +43,7 @@ export class CreateCustomQuizComponent implements OnInit { createAnswer() { return this.fb.group({ answer: this.fb.control('', [Validators.required, Validators.maxLength(255)]), - right_answer: this.fb.control(false, [Validators.required]), + right_answer: this.fb.control(true, [Validators.required]), }); } addAnswer(i: number) { @@ -53,14 +59,41 @@ export class CreateCustomQuizComponent implements OnInit { } removeQuestion(i: number) { - this.questions.removeAt(i); + Swal.fire({ + title: "Are you sure you want to delete this question?", + text: "You won't be able to revert this!", + icon: "warning", + showCancelButton: true, + confirmButtonColor: "#3085d6", + cancelButtonColor: "#d33", + confirmButtonText: "Yes, delete it!" + }).then((result) => { + if (result.isConfirmed) { + this.questions.removeAt(i); + } + }); } answersValidators(formArray: AbstractControl): ValidationErrors | null { - const names = formArray.value.map((answer: any) => answer.answer.toLowerCase()); - const hasDuplicates = names.some((name: string, index: number) => names.indexOf(name.toLowerCase()) !== index); - return hasDuplicates ? { duplicateAnswer: true } : null; + const answersValues = formArray.value.map((answer: any) => answer.answer.toLowerCase()).filter((answer: string) => answer.trim() !== ''); + // check if the text already exist in another answer + const hasDuplicates = answersValues.some((name: string, index: number) => answersValues.indexOf(name.toLowerCase()) !== index); + // check if the text is empty + const hasEmpty = answersValues.some((name: string) => name.trim() === ''); + return { duplicateAnswer: hasDuplicates, emptyAnswer: hasEmpty }; } - createQuiz() {} + createQuiz() { + if (this.quizForm.valid) { + console.log(this.quizForm.value); + this.router.navigate(['profile/']); + } else { + Swal.fire({ + icon: 'error', + title: 'Oops...', + text: 'Please fill all the required fields!', + }); + console.log(this.quizForm.value); + } + } } diff --git a/src/app/modules/profile/profile-info/profile-info.component.ts b/src/app/modules/profile/profile-info/profile-info.component.ts index f443113177ba49a194236954958fddb5f8585db0..c7d2854bf84c194cfe8b723813ba6fbdfee82f09 100644 --- a/src/app/modules/profile/profile-info/profile-info.component.ts +++ b/src/app/modules/profile/profile-info/profile-info.component.ts @@ -35,7 +35,8 @@ export class ProfileInfoComponent { } newQuiz() { - this.router.navigate(['/']); + console.log('Create new quiz'); + this.router.navigate(['profile/create-custom-quiz']); } } diff --git a/src/styles.css b/src/styles.css index 28d774ee6212e6f990ce31546f05427e462a32e7..1512f9a739bd63678b5e70258ea0622c34eac7a7 100644 --- a/src/styles.css +++ b/src/styles.css @@ -18,6 +18,7 @@ h1, h2, h3, h4, +label, p { font-family: 'Roboto'; } @@ -29,7 +30,7 @@ p { h1 { height: 10vh; margin: 0; - margin-left: 7vw; + margin-left: 5vw; font-size: 8vmin; /* Your profile */ font-style: normal; @@ -89,11 +90,12 @@ h1 { } .questionsButton { - width: 11vw; + width: 20vw; + height: 2.5vh; font-size: 1.25vmin; background-color: #FEFEFE; - border-radius: 5px; + border-radius: 20px; border: 0.25vmin solid #DBDBDB; box-sizing: border-box; -moz-box-sizing: border-box;