diff --git a/src/app/services/workgroup.service.ts b/src/app/services/workgroup.service.ts index d8181f23c51..3edccefe95d 100644 --- a/src/app/services/workgroup.service.ts +++ b/src/app/services/workgroup.service.ts @@ -5,11 +5,14 @@ import { ConfigService } from '../../assets/wise5/services/configService'; @Injectable() export class WorkgroupService { - constructor(private ConfigService: ConfigService, private http: HttpClient) {} + constructor( + private ConfigService: ConfigService, + private http: HttpClient + ) {} getWorkgroupsInPeriod(periodId: number): Map { const workgroups = new Map(); for (const workgroup of this.getWorkgroupsSortedById()) { - if (workgroup.periodId === periodId && workgroup.workgroupId != null) { + if (periodId === -1 || (workgroup.periodId === periodId && workgroup.workgroupId != null)) { workgroup.displayNames = this.ConfigService.getDisplayUsernamesByWorkgroupId( workgroup.workgroupId ); diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-completion/component-completion.component.spec.ts b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-completion/component-completion.component.spec.ts new file mode 100644 index 00000000000..f9514d07767 --- /dev/null +++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-completion/component-completion.component.spec.ts @@ -0,0 +1,73 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { Node } from '../../../common/Node'; +import { MockProviders } from 'ng-mocks'; +import { WorkgroupService } from '../../../../../app/services/workgroup.service'; +import { ComponentServiceLookupService } from '../../../services/componentServiceLookupService'; +import { TeacherDataService } from '../../../services/teacherDataService'; +import { MultipleChoiceService } from '../../../components/multipleChoice/multipleChoiceService'; +import { ComponentCompletionComponent } from './component-completion.component'; + +let component: ComponentCompletionComponent; +let fixture: ComponentFixture; +describe('ComponentProgressComponent', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComponentCompletionComponent], + providers: [ + MockProviders( + ComponentServiceLookupService, + MultipleChoiceService, + TeacherDataService, + WorkgroupService + ) + ] + }).compileComponents(); + + fixture = TestBed.createComponent(ComponentCompletionComponent); + component = fixture.componentInstance; + component.component = { id: 'component1', maxScore: 10 }; + component.node = { id: 'node1' } as Node; + component.periodId = 1; + }); + ngOnChanges(); +}); + +function ngOnChanges() { + describe('ngOnChanges()', () => { + beforeEach(() => { + const workgroups = new Map(); + workgroups.set(1, {}); + workgroups.set(2, {}); + spyOn(TestBed.inject(WorkgroupService), 'getWorkgroupsInPeriod').and.returnValue(workgroups); + spyOn(TestBed.inject(ComponentServiceLookupService), 'getService').and.returnValue( + new MultipleChoiceService() + ); + }); + describe('no student completed this work', () => { + beforeEach(() => + spyOn( + TestBed.inject(TeacherDataService), + 'getComponentStatesByWorkgroupIdAndComponentId' + ).and.returnValue([]) + ); + it('shows "0%"', () => { + component.ngOnChanges(); + fixture.detectChanges(); + expect(fixture.nativeElement.textContent.trim()).toEqual('0%'); + }); + }); + describe('half of the students completed this work', () => { + beforeEach(() => + spyOn( + TestBed.inject(TeacherDataService), + 'getComponentStatesByWorkgroupIdAndComponentId' + ).and.returnValues([], [{ studentData: { studentChoices: [{ id: 'choice1' }] } }]) + ); + it('shows "50%"', () => { + component.ngOnChanges(); + fixture.detectChanges(); + expect(fixture.nativeElement.textContent.trim()).toEqual('50%'); + }); + }); + }); +} diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-completion/component-completion.component.ts b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-completion/component-completion.component.ts new file mode 100644 index 00000000000..f8b55522c06 --- /dev/null +++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-completion/component-completion.component.ts @@ -0,0 +1,52 @@ +import { Component, Input } from '@angular/core'; +import { Node } from '../../../common/Node'; +import { WorkgroupService } from '../../../../../app/services/workgroup.service'; +import { TeacherDataService } from '../../../services/teacherDataService'; +import { ComponentServiceLookupService } from '../../../services/componentServiceLookupService'; +import { DecimalPipe } from '@angular/common'; + +@Component({ + imports: [DecimalPipe], + selector: 'component-completion', + template: `{{ completion | number: '1.0-0' }}%` +}) +export class ComponentCompletionComponent { + protected completion: number; + @Input() component: any; + @Input() node: Node; + @Input() periodId: number; + + constructor( + private componentServiceLookupService: ComponentServiceLookupService, + private dataService: TeacherDataService, + private workgroupService: WorkgroupService + ) {} + + ngOnChanges(): void { + if (this.component && this.node) { + const workgroups = this.workgroupService.getWorkgroupsInPeriod(this.periodId); + const numWorkgroupsCompleted = Array.from(workgroups.keys()).filter((workgroupId) => + this.isCompleted(workgroupId) + ).length; + this.completion = (numWorkgroupsCompleted / workgroups.size) * 100; + } + } + + private isCompleted(workgroupId: number): boolean { + const service = this.componentServiceLookupService.getService(this.component.type); + const componentStates = this.dataService.getComponentStatesByWorkgroupIdAndComponentId( + workgroupId, + this.component.id + ); + return ['OpenResponse', 'Discussion'].includes(this.component.type) + ? service.isCompletedV2(this.node, this.component, { + componentStates: componentStates + }) + : service.isCompleted( + this.component, + componentStates, + this.dataService.getEventsByNodeId(this.node.id), + this.node + ); + } +} diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-grading-view/component-grading-view.component.html b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-grading-view/component-grading-view.component.html index 50660c3674a..3f3bad8805d 100644 --- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-grading-view/component-grading-view.component.html +++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-grading-view/component-grading-view.component.html @@ -1,5 +1,7 @@ +Component Completion / {{ component?.maxScore ?? 0 }} Mean Score diff --git a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-grading-view/component-grading-view.component.ts b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-grading-view/component-grading-view.component.ts index 5e507771ea0..6772709ffd1 100644 --- a/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-grading-view/component-grading-view.component.ts +++ b/src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-grading-view/component-grading-view.component.ts @@ -12,18 +12,19 @@ import { ComponentClassResponsesComponent } from '../component-class-responses/c import { ActivatedRoute } from '@angular/router'; import { MilestoneReportButtonComponent } from '../milestone-report-button/milestone-report-button.component'; import { PeerGroupButtonComponent } from '../peer-group-button/peer-group-button.component'; +import { ComponentCompletionComponent } from '../component-completion/component-completion.component'; import { ComponentAverageScoreComponent } from '../component-average-score/component-average-score.component'; @Component({ imports: [ ComponentAverageScoreComponent, ComponentClassResponsesComponent, + ComponentCompletionComponent, MilestoneReportButtonComponent, PeerGroupButtonComponent, TeacherSummaryDisplayComponent ], selector: 'component-grading-view', - standalone: true, templateUrl: './component-grading-view.component.html' }) export class ComponentGradingViewComponent { diff --git a/src/messages.xlf b/src/messages.xlf index b495640b9e6..4aec5b1412c 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -13357,11 +13357,18 @@ The branches will be removed but the steps will remain in the unit. 97,100 + + Component Completion + + src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-grading-view/component-grading-view.component.html + 4,5 + + Mean Score src/assets/wise5/classroomMonitor/classroomMonitorComponents/component-grading-view/component-grading-view.component.html - 5,7 + 7,9