Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/app/api/models/unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export class Unit extends Entity {
extensionWeeksOnResubmitRequest: number;
allowStudentChangeTutorial: boolean;

credit_points: number;
prerequisites: string;
corequisites: string;

public readonly learningOutcomesCache: EntityCache<LearningOutcome> =
new EntityCache<LearningOutcome>();
public readonly tutorialStreamsCache: EntityCache<TutorialStream> =
Expand Down Expand Up @@ -231,8 +235,12 @@ export class Unit extends Entity {
return Math.round((startToNow / totalDuration) * 100);
}

public rolloverTo(body: {new_unit_code?: string, start_date: Date; end_date: Date}): Observable<Unit>;
public rolloverTo(body: {new_unit_code?: string, teaching_period_id: number}): Observable<Unit>;
public rolloverTo(body: {
new_unit_code?: string;
start_date: Date;
end_date: Date;
}): Observable<Unit>;
public rolloverTo(body: {new_unit_code?: string; teaching_period_id: number}): Observable<Unit>;
public rolloverTo(body: any): Observable<Unit> {
const unitService = AppInjector.get(UnitService);

Expand Down
103 changes: 62 additions & 41 deletions src/app/api/services/unit.service.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { GroupSetService, LearningOutcomeService, TaskOutcomeAlignmentService, TeachingPeriodService, TutorialService, TutorialStreamService, Unit, UserService } from 'src/app/api/models/doubtfire-model';
import { CachedEntityService, Entity, EntityMapping } from 'ngx-entity-service';
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {
GroupSetService,
LearningOutcomeService,
TaskOutcomeAlignmentService,
TeachingPeriodService,
TutorialService,
TutorialStreamService,
Unit,
UserService,
} from 'src/app/api/models/doubtfire-model';
import {CachedEntityService, Entity, EntityMapping} from 'ngx-entity-service';
import API_URL from 'src/app/config/constants/apiURL';
import { UnitRoleService } from './unit-role.service';
import { AppInjector } from 'src/app/app-injector';
import { TaskDefinitionService } from './task-definition.service';
import { GroupService } from './group.service';
import { Observable } from 'rxjs';
import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants';
import {UnitRoleService} from './unit-role.service';
import {AppInjector} from 'src/app/app-injector';
import {TaskDefinitionService} from './task-definition.service';
import {GroupService} from './group.service';
import {Observable} from 'rxjs';
import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants';

export type IloStats = {
median: number;
Expand All @@ -32,7 +41,7 @@ export class UnitService extends CachedEntityService<Unit> {
private taskDefinitionService: TaskDefinitionService,
private taskOutcomeAlignmentService: TaskOutcomeAlignmentService,
private groupSetService: GroupSetService,
private groupService: GroupService
private groupService: GroupService,
) {
super(http, API_URL);

Expand All @@ -50,18 +59,18 @@ export class UnitService extends CachedEntityService<Unit> {
toEntityFn: (data: object, jsonKey: string, entity: Unit) => {
const unitRoleService = AppInjector.get(UnitRoleService);
unitRoleService.cache.get(data[jsonKey]);
}
},
},
{
keys: 'staff',
toEntityOp: (data, key, entity) => {
const unitRoleService = AppInjector.get(UnitRoleService);
// Add staff
entity.staffCache.clear();
data[key]?.forEach(staff => {
data[key]?.forEach((staff) => {
entity.staffCache.add(unitRoleService.buildInstance(staff));
});
}
},
},
{
keys: ['mainConvenor', 'main_convenor_id'],
Expand All @@ -72,7 +81,7 @@ export class UnitService extends CachedEntityService<Unit> {
},
toJsonFn: (unit: Unit, key: string) => {
return unit.mainConvenor?.id;
}
},
},
{
keys: ['mainConvenorUser', 'main_convenor_user_id'],
Expand All @@ -81,20 +90,22 @@ export class UnitService extends CachedEntityService<Unit> {
},
toJsonFn: (unit: Unit, key: string) => {
return unit.mainConvenor?.user.id;
}
},
},
{
keys: ['teachingPeriod', 'teaching_period_id'],
toEntityFn: (data, key, entity) => {
if ( data['teaching_period_id'] ) {
if (data['teaching_period_id']) {
const teachingPeriod = this.teachingPeriodService.cache.get(data['teaching_period_id']);
teachingPeriod?.unitsCache.add(entity);
return teachingPeriod;
} else { return undefined; }
} else {
return undefined;
}
},
toJsonFn: (entity: Unit, key: string) => {
return entity.teachingPeriod ? entity.teachingPeriod.id : undefined;
}
},
},
{
keys: 'startDate',
Expand All @@ -103,7 +114,7 @@ export class UnitService extends CachedEntityService<Unit> {
},
toJsonFn: (entity, key) => {
return entity.startDate.toISOString().slice(0, 10);
}
},
},
{
keys: 'endDate',
Expand All @@ -112,7 +123,7 @@ export class UnitService extends CachedEntityService<Unit> {
},
toJsonFn: (entity, key) => {
return entity.endDate.toISOString().slice(0, 10);
}
},
},
{
keys: 'portfolioAutoGenerationDate',
Expand All @@ -121,7 +132,7 @@ export class UnitService extends CachedEntityService<Unit> {
},
toJsonFn: (entity, key) => {
return entity.portfolioAutoGenerationDate?.toISOString().slice(0, 10);
}
},
},
'assessmentEnabled',
'overseerImageId',
Expand All @@ -135,37 +146,43 @@ export class UnitService extends CachedEntityService<Unit> {
{
keys: 'ilos',
toEntityOp: (data: object, key: string, unit: Unit) => {
data[key]?.forEach(ilo => {
data[key]?.forEach((ilo) => {
unit.learningOutcomesCache.getOrCreate(ilo['id'], this.learningOutcomeService, ilo);
});
}
},
},
{
keys: 'tutorialStreams',
toEntityOp: (data, key, entity) => {
data['tutorial_streams'].forEach((streamJson: object) => {
entity.tutorialStreamsCache.add(this.tutorialStreamService.buildInstance(streamJson, {constructorParams: entity}));
entity.tutorialStreamsCache.add(
this.tutorialStreamService.buildInstance(streamJson, {constructorParams: entity}),
);
});
}
},
},
{
keys: 'tutorials',
toEntityOp: (data, key, entity) => {
data['tutorials'].forEach((tutorialJson: object) => {
if (tutorialJson) {
entity.tutorialsCache.add(this.tutorialService.buildInstance(tutorialJson, {constructorParams: entity}));
entity.tutorialsCache.add(
this.tutorialService.buildInstance(tutorialJson, {constructorParams: entity}),
);
}
});
}
},
},
// 'tutorialEnrolments', - map to tutorial enrolments
{
keys: 'groupSets',
toEntityOp: (data, key, unit) => {
data[key]?.forEach((groupSetJson: object) => {
unit.groupSetsCache.add(this.groupSetService.buildInstance(groupSetJson, {constructorParams: unit}));
unit.groupSetsCache.add(
this.groupSetService.buildInstance(groupSetJson, {constructorParams: unit}),
);
});
}
},
},
{
keys: 'groups',
Expand All @@ -174,17 +191,22 @@ export class UnitService extends CachedEntityService<Unit> {
const group = this.groupService.buildInstance(groupJson, {constructorParams: unit});
group.groupSet.groupsCache.add(group);
});
}
},
},
{
keys: 'taskDefinitions',
toEntityOp: (data, key, unit) => {
var seq: number = 0;
data['task_definitions'].forEach((taskDefinitionJson: object) => {
const td = unit.taskDefinitionCache.getOrCreate(taskDefinitionJson['id'], this.taskDefinitionService, taskDefinitionJson, {constructorParams: unit});
const td = unit.taskDefinitionCache.getOrCreate(
taskDefinitionJson['id'],
this.taskDefinitionService,
taskDefinitionJson,
{constructorParams: unit},
);
td.seq = seq++;
});
}
},
},
{
keys: ['draftTaskDefinition', 'draft_task_definition_id'],
Expand All @@ -193,22 +215,22 @@ export class UnitService extends CachedEntityService<Unit> {
},
toJsonFn: (unit: Unit, key: string) => {
return unit.draftTaskDefinition?.id;
}
},
},
{
keys: 'taskOutcomeAlignments',
toEntityOp: (data: object, jsonKey: string, unit: Unit) => {
data[jsonKey].forEach( (alignment) => {
data[jsonKey].forEach((alignment) => {
unit.taskOutcomeAlignmentsCache.getOrCreate(
alignment['id'],
this.taskOutcomeAlignmentService,
alignment,
{
constructorParams: unit
}
constructorParams: unit,
},
);
});
}
},
},
// 'groupMemberships', - map to group memberships
);
Expand Down Expand Up @@ -237,7 +259,7 @@ export class UnitService extends CachedEntityService<Unit> {
'draftTaskDefinition',
'allowStudentExtensionRequests',
'extensionWeeksOnResubmitRequest',
'allowStudentChangeTutorial'
'allowStudentChangeTutorial',
);
}

Expand Down Expand Up @@ -281,13 +303,12 @@ export class UnitService extends CachedEntityService<Unit> {
}

getUnitByCode(unitCode: string): Observable<Unit> {
const url = `${API_URL}/units/${unitCode}`;
const url = `${API_URL}/units/code/${unitCode}`;
return this.http.get<Unit>(url);
}

getUnits(): Observable<Unit[]> {
const url = `${API_URL}/units/`;
return this.http.get<Unit[]>(url);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<div
class="credit-points-summary"
[ngClass]="[variant, statusClass]"
[matTooltip]="tooltipText"
matTooltipPosition="below"
>
<!-- Default variant -->
<div *ngIf="variant === 'default'" class="default-display">
<div class="points-header">
<mat-icon *ngIf="showIcon" class="credit-icon">school</mat-icon>
<span class="points-label">Credit Points</span>
</div>
<div class="points-value">
<span class="current">{{ currentPoints }}</span>
<span class="separator">/</span>
<span class="total">{{ totalPoints }}</span>
<span class="unit">CP</span>
</div>
<div class="progress-bar">
<div class="progress-fill" [style.width.%]="Math.min(progressPercentage, 100)"></div>
</div>
</div>

<!-- Compact variant -->
<div *ngIf="variant === 'compact'" class="compact-display">
<mat-icon *ngIf="showIcon" class="credit-icon">school</mat-icon>
<span class="points-text"> {{ currentPoints }}/{{ totalPoints }} CP</span>
</div>

<!-- Header variant -->
<div *ngIf="variant === 'header'" class="header-display">
<div class="header-content">
<mat-icon *ngIf="showIcon" class="credit-icon">school</mat-icon>
<div class="header-text">
<span class="points-main">{{ currentPoints }}/{{ totalPoints }}</span>
<span class="points-unit">Credit Points</span>
</div>
</div>
<div class="header-progress">
<div class="progress-fill" [style.width.%]="Math.min(progressPercentage, 100)"></div>
</div>
</div>
</div>
Loading