Skip to content

Commit

Permalink
Merge pull request #21 from piuswalter/development
Browse files Browse the repository at this point in the history
implemented multiple choice questions
  • Loading branch information
piuswalter authored May 3, 2021
2 parents 56e6734 + e620331 commit 0cbbd5c
Show file tree
Hide file tree
Showing 15 changed files with 331 additions and 109 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:14.14-alpine
FROM node:16.0.0-alpine
ENV NODE_ENV=development

WORKDIR /tmp
Expand All @@ -18,6 +18,6 @@ RUN rm -r /tmp/backend /tmp/frontend

ENV NODE_ENV=production
COPY backend/package*.json ./
RUN npm ci
RUN npm ci && npm cache clean --force

CMD ["node", "./src/app.js"]
8 changes: 8 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@angular/common": "^11.0.9",
"@angular/compiler": "^11.0.9",
"@angular/core": "^11.0.9",
"@angular/flex-layout": "^11.0.0-beta.33",
"@angular/forms": "^11.0.9",
"@angular/material": "^11.2.7",
"@angular/platform-browser": "^11.0.9",
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/app/_services/db.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ export class DbService extends Dexie {
return from(this.subjects.add(new StudySmarterSubject(subject)));
}

async getSubjectIds(): Promise<number[]> {
const raw = await this.subjects.toArray();
return raw.map(
(subject) => (subject as StudySmarterSubject).studySmarter.id
);
}

async getSubjects(): Promise<Subject[]> {
const raw = await this.subjects.toArray();
return raw.map(
Expand All @@ -40,6 +47,15 @@ export class DbService extends Dexie {
);
}

async deleteSubject(subjectId: number): Promise<void> {
await this.subjects.delete(subjectId);
await this.flashcards.where('subjectId').equals(subjectId).delete();
}

async deleteSubjects(subjectIds: number[]): Promise<void> {
await Promise.all(subjectIds.map((id) => this.deleteSubject(id)));
}

addFlashcards(
flashcards: IStudySmarterFlashcard[],
subjectId: number
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { environment } from '../environments/environment';
import { HomeComponent } from './home/home.component';
import { SettingsComponent } from './settings/settings.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FlexLayoutModule } from '@angular/flex-layout';

import { MatBadgeModule } from '@angular/material/badge';
import { MatButtonModule } from '@angular/material/button';
Expand All @@ -30,6 +31,7 @@ import { StudySmarterService } from './_services/study-smarter.service';
import { SubjectSelectorComponent } from './download/subject-selector/subject-selector.component';
import { ProgressSpinnerDialogComponent } from './download/progress-spinner-dialog/progress-spinner-dialog.component';
import { LogoutDialogComponent } from './logout-dialog/logout-dialog.component';
import { FlashcardComponent } from './home/flashcard/flashcard.component';

const initLocalStorage = (studySmarter: StudySmarterService) => {
return (): void => studySmarter.loadCredentials();
Expand All @@ -45,7 +47,8 @@ const initLocalStorage = (studySmarter: StudySmarterService) => {
StudySmarterLoginComponent,
SubjectSelectorComponent,
ProgressSpinnerDialogComponent,
LogoutDialogComponent
LogoutDialogComponent,
FlashcardComponent
],
imports: [
BrowserModule,
Expand All @@ -54,6 +57,7 @@ const initLocalStorage = (studySmarter: StudySmarterService) => {
enabled: environment.production
}),
BrowserAnimationsModule,
FlexLayoutModule,
FormsModule,
HttpClientModule,
MatBadgeModule,
Expand Down
58 changes: 42 additions & 16 deletions frontend/src/app/download/download.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,32 @@
<h1 class="mat-headline">Select subjects for download!</h1>
<div class="spacer-2x"></div>
<section class="subject-selection">
<mat-list *ngIf="syncedSubjectIds.length">
<div mat-subheader>Synced Subjects</div>
<mat-list-item *ngFor="let subject of syncedSubjects">
<div mat-line>
<p class="subject-selection-item">
<span [matBadge]="subject.flashcards" matBadgeOverlap="false">
{{ subject.name }}
</span>
</p>
</div>
<div mat-line>Last used: {{ subject.last_used | date }}</div>
</mat-list-item>

<div class="spacer"></div>
<button
mat-raised-button
class="full-width"
color="primary"
(click)="downloadSubjects(syncedSubjectIds)"
>
Update
</button>
<div class="spacer"></div>
<mat-divider></mat-divider>
</mat-list>

<mat-selection-list #subjectList>
<div mat-subheader>Active Subjects</div>
<app-subject-selector
Expand All @@ -18,24 +44,24 @@ <h1 class="mat-headline">Select subjects for download!</h1>
*ngFor="let subject of archivedSubjects"
[subject]="subject"
></app-subject-selector>
<p class="download-information">
You've selected
{{ subjectList.selectedOptions.selected.length }} Subjects
containing {{ getFlashcardCount(selectedSubjectIds) }} Flashcards
</p>
<div class="spacer"></div>
<button
mat-raised-button
(click)="downloadSubjects(selectedSubjectIds)"
class="full-width"
color="primary"
[disabled]="!selectedSubjectIds.length"
>
Download
</button>
<div class="spacer"></div>
</mat-selection-list>

<p>
You've selected
{{ subjectList.selectedOptions.selected.length }} Subjects containing
{{ getFlashcardCount(selectedSubjectIds) }} Flashcards
</p>
</section>
<div class="spacer"></div>
<button
mat-raised-button
(click)="downloadSubjects()"
class="full-width"
color="primary"
[disabled]="!selectedSubjectIds.length"
>
Download
</button>
</mat-card>
</div>
</div>
6 changes: 6 additions & 0 deletions frontend/src/app/download/download.component.sass
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
text-align: center
justify-content: center

.content
margin-bottom: 15px

.spacer
margin-top: 20px

Expand All @@ -18,3 +21,6 @@

.subject-selection-item
margin-top: 15px

.download-information
margin-top: 15px
27 changes: 20 additions & 7 deletions frontend/src/app/download/download.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ import { ProgressSpinnerDialogComponent } from './progress-spinner-dialog/progre
export class DownloadComponent implements OnInit {
@ViewChild('subjectList') subjectList: MatSelectionList | undefined;
private subjects: IStudySmarterSubject[] = [];
public syncedSubjectIds: number[] = [];

constructor(
private apiService: ApiService,
private dialog: MatDialog,
private dbService: DbService
) {}

ngOnInit(): void {
async ngOnInit(): Promise<void> {
this.syncedSubjectIds = await this.dbService.getSubjectIds();
this.fetchSubjects();
}

Expand All @@ -34,10 +36,20 @@ export class DownloadComponent implements OnInit {

private filteredSubjects(active: boolean): IStudySmarterSubject[] {
return this.subjects
.filter((subject) => subject.archived !== active)
.filter(
(subject) =>
subject.archived !== active &&
!this.syncedSubjectIds.includes(subject.id)
)
.sort(this.cmpSubjectLastUsed.bind(this));
}

get syncedSubjects(): IStudySmarterSubject[] {
return this.subjects.filter((sub) =>
this.syncedSubjectIds.includes(sub.id)
);
}

get activeSubjects(): IStudySmarterSubject[] {
return this.filteredSubjects(true);
}
Expand Down Expand Up @@ -74,15 +86,15 @@ export class DownloadComponent implements OnInit {
});
}

downloadSubjects(): void {
async downloadSubjects(subjectIds: number[]): Promise<void> {
const dialogRef = this.showProgressSpinnerUntilExecuted();
const toFetch =
this.getFlashcardCount(this.selectedSubjectIds) +
this.selectedSubjectIds.length;
const toFetch = this.getFlashcardCount(subjectIds) + subjectIds.length;
let fetched = 0;

await this.dbService.deleteSubjects(subjectIds);

const subscriptions: Subscription[] = [];
for (const subjectId of this.selectedSubjectIds) {
for (const subjectId of subjectIds) {
let subjectFetched = 0;
const subscription = this.apiService
.getFlashcards(subjectId)
Expand Down Expand Up @@ -116,6 +128,7 @@ export class DownloadComponent implements OnInit {
dialogRef.componentInstance.progress = (100 / toFetch) * ++fetched;
if (fetched === toFetch) {
dialogRef.close();
void this.ngOnInit();
}
});
subscriptions.push(subscription);
Expand Down
62 changes: 62 additions & 0 deletions frontend/src/app/home/flashcard/flashcard.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<mat-card class="flashcard">
<mat-card-header class="title">
<mat-card-title>Frage</mat-card-title>
</mat-card-header>
<mat-card-actions class="controls">
<button (click)="switchCard.emit(-1)" mat-mini-fab color="primary">
<mat-icon aria-hidden="false">chevron_left</mat-icon>
</button>
<button
(click)="hideAnswer = !hideAnswer"
mat-raised-button
color="primary"
>
{{ hideAnswer ? "Show" : "Hide" }} answer
</button>
<button (click)="switchCard.emit(1)" mat-mini-fab color="primary">
<mat-icon aria-hidden="false" aria-label="Chevron right icon"
>chevron_right</mat-icon
>
</button>
</mat-card-actions>
<mat-card-content class="center">
<div [innerHTML]="question" class="flashcard-text"></div>
<hr class="halfwidth" />
<div
*ngIf="!isMultipleChoice"
[innerHTML]="answer"
[hidden]="hideAnswer"
class="flashcard-text"
></div>
<div
*ngIf="isMultipleChoice && !hideAnswer"
class="multiple-choice-feedback"
>
<span *ngIf="isAnswerCorrect">Correct 🥳</span>
<span *ngIf="!isAnswerCorrect"
>That was probably not quite tivial 😨</span
>
</div>
<div
*ngIf="isMultipleChoice"
fxLayout="row wrap"
fxLayout.lt-sm="column"
fxLayoutAlign="center center"
>
<div
fxFlex="calc(50% - 10px)"
fxFill
*ngFor="let answer of answers; let idx = index"
>
<div
class="multiple-choice-button"
(click)="onCardClicked(idx)"
[class.show-solution]="!hideAnswer"
[class.correct]="answer.isCorrect"
[class.selected]="answer.isSelected"
[innerHTML]="answer.safeHtml"
></div>
</div>
</div>
</mat-card-content>
</mat-card>
Loading

0 comments on commit 0cbbd5c

Please sign in to comment.