Updates to encompass benchmarks

This commit is contained in:
ivan-pelly
2026-03-07 16:10:55 -08:00
parent 69e96403f4
commit 3d531298e2
65 changed files with 2505 additions and 86 deletions
@@ -0,0 +1,154 @@
import { Component, inject, signal, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { Subscription } from 'rxjs';
import { StudentService } from '../../../shared/services/student.service';
import { StudentGoalItem } from '../../../shared/classes/student-goal';
@Component({
selector: 'app-goal-card-full',
imports: [FormsModule],
templateUrl: './goal-card-full.html',
styleUrl: './goal-card-full.scss',
})
export class GoalCardFull implements OnDestroy {
// ************************** Constructor **************************
constructor() {
this.paramSub = this.route.paramMap.subscribe(params => {
this.studentId = params.get('studentId')!;
this.goalId = params.get('goalId')!;
this.loadGoal();
});
}
// ************************** Declarations *************************
private readonly studentService = inject(StudentService);
private readonly route = inject(ActivatedRoute);
private readonly router = inject(Router);
private readonly paramSub: Subscription;
private studentId!: string;
private goalId!: string;
protected readonly loaded = signal(false);
protected readonly errorMessage = signal<string | null>(null);
protected readonly successMessage = signal<string | null>(null);
protected readonly saving = signal(false);
// Form fields
protected title = '';
protected description = '';
protected category = '';
// Read-only metadata
protected progressEventCount = 0;
protected benchmarkCount = 0;
// Snapshot
private savedTitle = '';
private savedDescription = '';
private savedCategory = '';
// ************************** Properties ***************************
// *****************************************************************
// Returns true if form values differ from the saved snapshot.
// *****************************************************************
hasChanges(): boolean {
return this.title !== this.savedTitle
|| this.description !== this.savedDescription
|| this.category !== this.savedCategory;
}
// ************************ Public Methods *************************
// ************************ Event Handlers *************************
// *****************************************************************
// Saves changes to the goal via the API.
// *****************************************************************
async onSave() {
this.saving.set(true);
this.errorMessage.set(null);
this.successMessage.set(null);
const result = await this.studentService.updateGoal(this.studentId, this.goalId, {
title: this.title,
description: this.description,
category: this.category,
});
this.saving.set(false);
if (result.success) {
this.savedTitle = this.title;
this.savedDescription = this.description;
this.savedCategory = this.category;
this.successMessage.set('Changes saved.');
} else {
this.errorMessage.set(result.message);
}
}
// *****************************************************************
// Reverts form fields to the last-saved snapshot.
// *****************************************************************
onCancel() {
this.title = this.savedTitle;
this.description = this.savedDescription;
this.category = this.savedCategory;
this.errorMessage.set(null);
this.successMessage.set(null);
}
onBack() {
this.router.navigate(['/students', this.studentId]);
}
onProgressEvents() {
this.router.navigate(['/students', this.studentId, 'goals', this.goalId, 'progress']);
}
onBenchmarks() {
this.router.navigate(['/students', this.studentId, 'benchmarks']);
}
ngOnDestroy() {
this.paramSub.unsubscribe();
}
// ********************** Support Procedures ***********************
// *****************************************************************
// Loads the goal by finding it in the student's goal list.
// *****************************************************************
private loadGoal() {
this.loaded.set(false);
this.studentService.getGoalsForStudent(this.studentId).then(result => {
if (!result.success || !result.payload) {
this.errorMessage.set(result.message);
return;
}
const goal = result.payload.goals.find(g => g.goalId === this.goalId);
if (!goal) {
this.errorMessage.set('Goal not found.');
return;
}
this.title = goal.title;
this.description = goal.description;
this.category = goal.category;
this.progressEventCount = goal.progressEventCount;
this.benchmarkCount = goal.benchmarkCount;
this.savedTitle = goal.title;
this.savedDescription = goal.description;
this.savedCategory = goal.category;
this.loaded.set(true);
});
}
}