Skip to content

Commit

Permalink
Merge pull request #120 from Clean-CaDET/development
Browse files Browse the repository at this point in the history
feat: Instructors can view group-wide semaphores to analyze weekly progress of whole group
  • Loading branch information
Luburic authored Oct 14, 2024
2 parents 25a13e0 + f0079df commit 44e3a68
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
<small style="font-size: 12px;">{{learner.index}}</small><br>
<span>{{learner.name}} {{learner.surname}}</span>
</div>
<div *ngIf="learners?.length > 0 && mode === 'grading'" class="theme-warn">
<div *ngIf="mode === 'grading'" class="theme-warn">
<span *ngIf="learner.completedTaskCount" matTooltip="Broj urađenih i neocenjenih zadataka">{{learner.completedTaskCount}}</span><br>
<small *ngIf="learner.completedStepCount" matTooltip="Broj urađenih i neocenjenih koraka">{{learner.completedStepCount}}</small>
</div>
<div *ngIf="mode === 'progress'">
<mat-icon *ngIf="learner.semaphore" [matTooltip]="learner.semaphoreJustification" [color]="learner.semaphore == 1 ? 'warn' : learner.semaphore == 2 ? 'accent' : 'primary'">circle</mat-icon>
<mat-icon *ngIf="!learner.semaphore" matTooltip="Nema povratne informacije o studentu za nedelju">radio_button_off</mat-icon>
</div>
</div>
<mat-divider></mat-divider>
</div>
Expand All @@ -36,7 +40,7 @@
<cc-grading [courseId]="courseId" [selectedLearnerId]="selectedLearner.id" [learners]="learners" (learnerChanged)="changeLearner($event)" (unitsChanged)="getTaskSummaries($event)"></cc-grading>
</div>
<div *ngIf="selectedLearner && mode === 'progress'">
<cc-weekly-progress [courseId]="courseId" [selectedLearnerId]="selectedLearner.id" [learners]="learners" (learnerChanged)="changeLearner($event)"></cc-weekly-progress>
<cc-weekly-progress [courseId]="courseId" [selectedLearnerId]="selectedLearner.id" [learners]="learners" (learnerChanged)="changeLearner($event)" (dateChanged)="getGroupFeedback($event)"></cc-weekly-progress>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Group } from '../model/group.model';
import { GroupMonitoringService } from './group-monitoring.service';
import { Learner } from '../model/learner.model';
import { TaskProgress } from '../grading/model/task-progress';
import { WeeklyFeedbackService } from '../weekly-feedback/weekly-feedback.service';

@Component({
selector: 'cc-group-monitoring',
Expand All @@ -19,7 +20,9 @@ export class GroupMonitoringComponent implements OnInit {
learners: Learner[] = [];
selectedLearner: Learner;

constructor(private route: ActivatedRoute, private groupMonitoringService: GroupMonitoringService) { }
feedbackDate: Date;

constructor(private route: ActivatedRoute, private groupMonitoringService: GroupMonitoringService, private feedbackService: WeeklyFeedbackService) { }

ngOnInit(): void {
this.route.params.subscribe((params: Params) => {
Expand All @@ -46,6 +49,7 @@ export class GroupMonitoringComponent implements OnInit {
this.selectedLearner = null;
this.learners = data.results.sort((l1, l2) => l1.name > l2.name ? 1 : -1);
this.selectedLearner = this.learners[0];
if(this.feedbackDate && this.mode === 'progress') this.getGroupFeedback(this.feedbackDate);
});
}

Expand All @@ -59,4 +63,19 @@ export class GroupMonitoringComponent implements OnInit {
l.completedStepCount = taskProgress.filter(p => p.learnerId === l.id).flatMap(p => p.stepProgresses).filter(p => p.status === 'Answered').length;
});
}

public getGroupFeedback(date: Date) {
this.feedbackDate = date;
this.feedbackService.getByGroup(this.courseId, this.learners.map(l => l.id), date)
.subscribe(feedback => this.learners.forEach(l => {
const relatedFeedback = feedback.find(f => f.learnerId === l.id);
if(!relatedFeedback) {
l.semaphore = 0;
l.semaphoreJustification = '';
return;
}
l.semaphore = relatedFeedback.semaphore;
l.semaphoreJustification = relatedFeedback.semaphoreJustification;
}));
}
}
4 changes: 4 additions & 0 deletions src/app/modules/monitoring/model/learner.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ export interface Learner {
// Grading summaries
completedTaskCount: number;
completedStepCount: number;

// Feedback summaries
semaphore: number;
semaphoreJustification: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,33 @@ import { WeeklyFeedback } from './weekly-feedback.model';

@Injectable({providedIn: "root"})
export class WeeklyFeedbackService {
private baseUrl(courseId: number, learnerId: number): string {
private baseLearnerUrl(courseId: number, learnerId: number): string {
return `${environment.apiHost}monitoring/${courseId}/feedback/${learnerId}/`;
}

constructor(private http: HttpClient) { }

getByCourseAndLearner(courseId: number, learnerId: number): Observable<WeeklyFeedback[]> {
return this.http.get<WeeklyFeedback[]>(this.baseUrl(courseId, learnerId))
return this.http.get<WeeklyFeedback[]>(this.baseLearnerUrl(courseId, learnerId))
.pipe(map(results => {
results.forEach(r => r.weekEnd = new Date(r.weekEnd));
return results;
}));
}

getByGroup(courseId: number, learnerIds: number[], weekEnd: Date): Observable<WeeklyFeedback[]> {
return this.http.post<WeeklyFeedback[]>(`${environment.apiHost}monitoring/${courseId}/feedback`, {learnerIds, weekEnd});
}

create(courseId: number, learnerId: number, item: WeeklyFeedback): Observable<WeeklyFeedback> {
return this.http.post<WeeklyFeedback>(this.baseUrl(courseId, learnerId), item);
return this.http.post<WeeklyFeedback>(this.baseLearnerUrl(courseId, learnerId), item);
}

update(courseId: number, learnerId: number, item: WeeklyFeedback): Observable<WeeklyFeedback> {
return this.http.put<WeeklyFeedback>(this.baseUrl(courseId, learnerId)+item.id, item);
return this.http.put<WeeklyFeedback>(this.baseLearnerUrl(courseId, learnerId)+item.id, item);
}

delete(courseId: number, learnerId: number, itemId: number): Observable<WeeklyFeedback> {
return this.http.delete<WeeklyFeedback>(this.baseUrl(courseId, learnerId)+itemId);
return this.http.delete<WeeklyFeedback>(this.baseLearnerUrl(courseId, learnerId)+itemId);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<div class="flex-row" style="height: 100vh;">
<div class="flex-col" style="height: 100vh; width: 60%;">
<div>
<mat-form-field appearance="fill" style="padding: 10px; margin-bottom: -1.25em; width: 250px;">
<mat-label>Dan pred sastanak sa mentorom</mat-label>
<input matInput [matDatepicker]="picker" [value]="selectedDate" (dateChange)="onDateChange($event)">
<mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<button mat-icon-button matTooltip="Osveži semafore grupe" (click)="loadGroupSemaphores()"><mat-icon>traffic</mat-icon></button>
</div>
<div *ngIf="!units?.length" style="padding: 10px;">
Student nije imao nove lekcije u protekloj nedelji.
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { Learner } from '../model/learner.model';
import { MatDatepickerInputEvent } from '@angular/material/datepicker';
import { WeeklyActivityService } from './weekly-activity.service';
Expand All @@ -12,15 +12,16 @@ import { WeeklyRatingStatistics, WeeklyProgressStatistics, calculateWeeklySatisf
templateUrl: './weekly-progress.component.html',
styleUrls: ['./weekly-progress.component.scss']
})
export class WeeklyProgressComponent implements OnChanges {
export class WeeklyProgressComponent implements OnInit, OnChanges {
@Input() courseId: number;
@Input() selectedLearnerId: number;
@Input() learners: Learner[];
@Output() learnerChanged = new EventEmitter<number>();
groupMemberIds: Set<number>;
allRatings: UnitProgressRating[];

selectedDate: Date;
@Output() dateChanged = new EventEmitter<Date>();

units: UnitHeader[] = [];
weeklyRatings: WeeklyRatingStatistics;
Expand All @@ -30,6 +31,15 @@ export class WeeklyProgressComponent implements OnChanges {
this.selectedDate = new Date();
}

ngOnInit() {
if(!this.learners?.length) return;
this.loadGroupSemaphores();
}

public loadGroupSemaphores() {
this.dateChanged.emit(this.selectedDate);
}

ngOnChanges(changes: SimpleChanges): void {
if(!changes) return;

Expand All @@ -50,6 +60,7 @@ export class WeeklyProgressComponent implements OnChanges {
public onDateChange(event: MatDatepickerInputEvent<Date>) {
if(!event?.value) return;
this.selectedDate = event.value;
this.loadGroupSemaphores();
this.getUnits();
}

Expand Down

0 comments on commit 44e3a68

Please sign in to comment.