diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.html b/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.html
deleted file mode 100644
index 26221dc..0000000
--- a/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.html
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
- {{ isNew() ? 'New Benchmark' : 'Benchmark Detail' }}
-
-
-
-@if (errorMessage()) {
-{{ errorMessage() }}
-}
-
-@if (loaded()) {
-
-
- Goal: {{ goalCategory }}
-
-
-
-
-
-
-
-
-
- @if (!isNew()) {
-
- @if (createdByName) {
- Created by: {{ createdByName }}
- }
- Created: {{ createdAt | date:'medium' }}
- @if (updatedAt) {
- Updated: {{ updatedAt | date:'medium' }}
- }
-
- }
-
-
-
-
-
-}
-
-@if (successMessage()) {
-{{ successMessage() }}
-}
\ No newline at end of file
diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.scss b/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.scss
deleted file mode 100644
index f1c488f..0000000
--- a/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.scss
+++ /dev/null
@@ -1,120 +0,0 @@
-:host {
- display: flex;
- flex-direction: column;
- height: 100%;
- padding: 24px 28px;
-}
-
-.toolbar {
- display: flex;
- align-items: center;
- gap: 0.75rem;
- margin-bottom: 20px;
- flex-shrink: 0;
-}
-
-.toolbar-btn {
- padding: 6px 14px;
- background: transparent;
- color: var(--accent-indigo);
- border: 1px solid var(--accent-indigo);
- border-radius: var(--radius-md);
- font-size: 13px;
- font-weight: 500;
- cursor: pointer;
- font-family: inherit;
-
- &:hover {
- background: #EEF2FF;
- }
-
- &:disabled {
- opacity: 0.5;
- cursor: not-allowed;
- }
-}
-
-.toolbar-title {
- font-weight: 600;
- font-size: 18px;
- color: var(--text-primary);
-}
-
-.spacer {
- flex: 1;
-}
-
-.error {
- font-size: 13px;
- color: #dc2626;
- margin: 0 0 12px;
-}
-
-.success {
- font-size: 13px;
- color: #16a34a;
- margin: 12px 0 0;
-}
-
-.detail-card {
- background: var(--bg-surface);
- border: 1px solid var(--border-color);
- border-radius: var(--radius-xl);
- padding: 22px;
- max-width: 600px;
-}
-
-.field {
- display: flex;
- flex-direction: column;
- margin-bottom: 14px;
-}
-
-.field-label {
- font-size: 12px;
- font-weight: 600;
- color: #666;
- margin-bottom: 4px;
-}
-
-.field-input {
- padding: 8px 10px;
- border: 1px solid var(--border-muted);
- border-radius: var(--radius-md);
- font-size: 13px;
- font-family: inherit;
- outline: none;
-}
-
-.field-textarea {
- resize: vertical;
- min-height: 70px;
-}
-
-.metadata {
- display: flex;
- gap: 1.5rem;
- margin-bottom: 14px;
-}
-
-.meta-item {
- font-size: 12px;
- color: var(--text-muted);
-}
-
-.actions {
- display: flex;
- justify-content: flex-end;
- gap: 8px;
- margin-top: 8px;
-}
-
-.save-btn {
- background: var(--accent-indigo) !important;
- color: #fff !important;
- border-color: var(--accent-indigo) !important;
-
- &:hover {
- background: #3730A3 !important;
- }
-}
\ No newline at end of file
diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.spec.ts b/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.spec.ts
deleted file mode 100644
index 30710b6..0000000
--- a/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.spec.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { BenchmarkCardFull } from './benchmark-card-full';
-
-describe('BenchmarkCardFull', () => {
- let component: BenchmarkCardFull;
- let fixture: ComponentFixture;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- imports: [BenchmarkCardFull]
- })
- .compileComponents();
-
- fixture = TestBed.createComponent(BenchmarkCardFull);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.ts b/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.ts
deleted file mode 100644
index 51f96dd..0000000
--- a/ui/winstudentgoaltracker/src/app/desktop/components/benchmark-card-full/benchmark-card-full.ts
+++ /dev/null
@@ -1,181 +0,0 @@
-import { Component, inject, signal, OnDestroy } from '@angular/core';
-import { ActivatedRoute, Router } from '@angular/router';
-import { FormsModule } from '@angular/forms';
-import { DatePipe } from '@angular/common';
-import { Subscription } from 'rxjs';
-import { StudentService } from '../../../shared/services/student.service';
-import { BenchmarkDto } from '../../../shared/classes/benchmark.dto';
-
-@Component({
- selector: 'app-benchmark-card-full',
- imports: [FormsModule, DatePipe],
- templateUrl: './benchmark-card-full.html',
- styleUrl: './benchmark-card-full.scss',
-})
-export class BenchmarkCardFull implements OnDestroy {
-
- // ************************** Constructor **************************
-
- constructor() {
- this.paramSub = this.route.paramMap.subscribe(params => {
- this.studentId = params.get('studentId')!;
- this.goalId = params.get('goalId')!;
- this.benchmarkId = params.get('benchmarkId') ?? null;
- this.loadBenchmark();
- });
- }
-
- // ************************** 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;
- private benchmarkId: string | null = null;
-
- protected readonly loaded = signal(false);
- protected readonly isNew = signal(false);
- protected readonly errorMessage = signal(null);
- protected readonly successMessage = signal(null);
- protected readonly saving = signal(false);
-
- // Form fields
- protected benchmarkText = '';
- protected shortName = '';
- private savedBenchmarkText = '';
- private savedShortName = '';
-
- // Read-only metadata
- protected goalCategory = '';
- protected createdByName = '';
- protected createdAt: Date | null = null;
- protected updatedAt: Date | null = null;
-
- // ************************** Properties ***************************
-
- // *****************************************************************
- // Returns true if the benchmark text has unsaved changes.
- // *****************************************************************
- hasChanges(): boolean {
- return this.benchmarkText !== this.savedBenchmarkText
- || this.shortName !== this.savedShortName;
- }
-
- // ************************ Public Methods *************************
-
- // ************************ Event Handlers *************************
-
- // *****************************************************************
- // Saves changes or creates a new benchmark.
- // *****************************************************************
- async onSave() {
- this.saving.set(true);
- this.errorMessage.set(null);
- this.successMessage.set(null);
-
- if (this.isNew()) {
- const result = await this.studentService.createBenchmark(this.studentId, {
- goalId: this.goalId,
- benchmark: this.benchmarkText,
- shortName: this.shortName || undefined,
- });
- this.saving.set(false);
- if (result.success) {
- this.successMessage.set('Benchmark created.');
- this.savedBenchmarkText = this.benchmarkText;
- this.savedShortName = this.shortName;
- this.studentService.notifyDataChanged();
- if (result.payload?.benchmarkId) {
- this.router.navigate(['/students', this.studentId, 'goals', this.goalId, 'benchmarks', result.payload.benchmarkId]);
- }
- } else {
- this.errorMessage.set(result.message);
- }
- } else {
- const result = await this.studentService.updateBenchmark(this.studentId, this.benchmarkId!, this.benchmarkText, this.shortName || undefined);
- this.saving.set(false);
- if (result.success) {
- this.savedBenchmarkText = this.benchmarkText;
- this.savedShortName = this.shortName;
- this.successMessage.set('Changes saved.');
- } else {
- this.errorMessage.set(result.message);
- }
- }
- }
-
- // *****************************************************************
- // Reverts the benchmark text to the last-saved value.
- // *****************************************************************
- onCancel() {
- this.benchmarkText = this.savedBenchmarkText;
- this.shortName = this.savedShortName;
- this.errorMessage.set(null);
- this.successMessage.set(null);
- }
-
- onBack() {
- this.router.navigate(['/students', this.studentId, 'goals', this.goalId]);
- }
-
- ngOnDestroy() {
- this.paramSub.unsubscribe();
- }
-
- // ********************** Support Procedures ***********************
-
- // *****************************************************************
- // Loads existing benchmark data or sets up new-benchmark state.
- // *****************************************************************
- private loadBenchmark() {
- if (!this.benchmarkId) {
- this.isNew.set(true);
- this.benchmarkText = '';
- this.shortName = '';
- this.savedBenchmarkText = '';
- this.savedShortName = '';
- this.loadGoalCategory();
- this.loaded.set(true);
- return;
- }
-
- this.isNew.set(false);
- this.studentService.getBenchmarksForStudent(this.studentId).then(result => {
- if (!result.success || !result.payload) {
- this.errorMessage.set(result.message);
- return;
- }
-
- const bm = result.payload.benchmarks.find(b => b.benchmarkId === this.benchmarkId);
- if (!bm) {
- this.errorMessage.set('Benchmark not found.');
- return;
- }
-
- this.benchmarkText = bm.benchmark;
- this.shortName = bm.shortName ?? '';
- this.savedBenchmarkText = bm.benchmark;
- this.savedShortName = bm.shortName ?? '';
- this.goalCategory = bm.goalCategory;
- this.createdByName = bm.createdByName;
- this.createdAt = bm.createdAt;
- this.updatedAt = bm.updatedAt;
- this.loaded.set(true);
- });
- }
-
- // *****************************************************************
- // Loads the goal category for a new benchmark.
- // *****************************************************************
- private loadGoalCategory() {
- this.studentService.getGoalsForStudent(this.studentId).then(result => {
- if (result.success && result.payload) {
- const goal = result.payload.goals.find(g => g.goalId === this.goalId);
- this.goalCategory = goal?.category ?? '';
- }
- });
- }
-}
diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/edit-benchmark-modal/edit-benchmark-modal.html b/ui/winstudentgoaltracker/src/app/desktop/components/edit-benchmark-modal/edit-benchmark-modal.html
index 3ed6bc8..8838b30 100644
--- a/ui/winstudentgoaltracker/src/app/desktop/components/edit-benchmark-modal/edit-benchmark-modal.html
+++ b/ui/winstudentgoaltracker/src/app/desktop/components/edit-benchmark-modal/edit-benchmark-modal.html
@@ -1,11 +1,13 @@
-
+
-
-
+
+
-
-
+
+
@if (errorMessage()) {
@@ -14,8 +16,8 @@
-
diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/edit-benchmark-modal/edit-benchmark-modal.ts b/ui/winstudentgoaltracker/src/app/desktop/components/edit-benchmark-modal/edit-benchmark-modal.ts
index cb924d6..83416e3 100644
--- a/ui/winstudentgoaltracker/src/app/desktop/components/edit-benchmark-modal/edit-benchmark-modal.ts
+++ b/ui/winstudentgoaltracker/src/app/desktop/components/edit-benchmark-modal/edit-benchmark-modal.ts
@@ -14,7 +14,10 @@ export class EditBenchmarkModal {
private readonly studentService = inject(StudentService);
readonly studentId = input.required();
- readonly benchmark = input.required();
+ readonly goalId = input.required();
+
+ /** null for new benchmark, populated for edit */
+ readonly benchmark = input(null);
readonly saved = output();
readonly closed = output();
@@ -24,31 +27,60 @@ export class EditBenchmarkModal {
protected shortName = '';
protected benchmarkText = '';
+ protected get isEditMode(): boolean {
+ return !!this.benchmark();
+ }
+
+ protected get modalTitle(): string {
+ return this.isEditMode ? 'Edit Benchmark' : 'Add Benchmark';
+ }
+
+ protected get submitLabel(): string {
+ return this.isEditMode ? 'Save' : 'Add Benchmark';
+ }
+
ngOnInit() {
const b = this.benchmark();
- this.shortName = b.shortName ?? '';
- this.benchmarkText = b.benchmark;
+ if (b) {
+ this.shortName = b.shortName ?? '';
+ this.benchmarkText = b.benchmark;
+ }
}
async onSave() {
- if (!this.shortName.trim()) return;
+ if (!this.benchmarkText.trim()) return;
this.saving.set(true);
this.errorMessage.set(null);
- const result = await this.studentService.updateBenchmark(
- this.studentId(),
- this.benchmark().benchmarkId,
- this.benchmarkText,
- this.shortName,
- );
+ if (this.isEditMode) {
+ const result = await this.studentService.updateBenchmark(
+ this.studentId(),
+ this.benchmark()!.benchmarkId,
+ this.benchmarkText,
+ this.shortName || undefined,
+ );
+ this.saving.set(false);
- this.saving.set(false);
-
- if (result.success) {
- this.studentService.notifyDataChanged();
- this.saved.emit();
+ if (result.success) {
+ this.studentService.notifyDataChanged();
+ this.saved.emit();
+ } else {
+ this.errorMessage.set(result.message);
+ }
} else {
- this.errorMessage.set(result.message);
+ const result = await this.studentService.createBenchmark(this.studentId(), {
+ goalId: this.goalId(),
+ benchmark: this.benchmarkText,
+ shortName: this.shortName || undefined,
+ });
+ this.saving.set(false);
+
+ if (result.success) {
+ this.studentService.notifyDataChanged();
+ this.saved.emit();
+ } else {
+ this.errorMessage.set(result.message);
+ }
}
}
}
diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/workspace/workspace.html b/ui/winstudentgoaltracker/src/app/desktop/components/workspace/workspace.html
index 0915d49..4eeb9d1 100644
--- a/ui/winstudentgoaltracker/src/app/desktop/components/workspace/workspace.html
+++ b/ui/winstudentgoaltracker/src/app/desktop/components/workspace/workspace.html
@@ -12,7 +12,8 @@
(closed)="showGoalModal.set(null)" />
}
@if (showEditBenchmarkModal()) {
-
}
@if (showEditEventModal()) {
diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/workspace/workspace.ts b/ui/winstudentgoaltracker/src/app/desktop/components/workspace/workspace.ts
index fa886e8..d3037ce 100644
--- a/ui/winstudentgoaltracker/src/app/desktop/components/workspace/workspace.ts
+++ b/ui/winstudentgoaltracker/src/app/desktop/components/workspace/workspace.ts
@@ -73,7 +73,7 @@ export class Workspace {
// Modal states
protected readonly showGoalModal = signal(null);
- protected readonly showEditBenchmarkModal = signal(null);
+ protected readonly showEditBenchmarkModal = signal(null);
protected readonly showEditEventModal = signal(null);
// ************************** Properties ***************************
@@ -148,8 +148,7 @@ export class Workspace {
}
onAddBenchmark() {
- // Navigate to the new benchmark route (still uses the old page for creation)
- this.router.navigate(['/students', this.studentId(), 'goals', this.selectedGoal()!.goalId, 'benchmarks', 'new']);
+ this.showEditBenchmarkModal.set('new');
}
onNewEvent() {
diff --git a/ui/winstudentgoaltracker/src/app/desktop/desktop.routes.ts b/ui/winstudentgoaltracker/src/app/desktop/desktop.routes.ts
index 8f6197e..0e97869 100644
--- a/ui/winstudentgoaltracker/src/app/desktop/desktop.routes.ts
+++ b/ui/winstudentgoaltracker/src/app/desktop/desktop.routes.ts
@@ -3,8 +3,6 @@ import { Home } from './pages/home/home';
import { Workspace } from './components/workspace/workspace';
import { Reports } from './components/reports/reports';
import { StudentProgressReport } from './components/student-progress-report/student-progress-report';
-import { BenchmarkCardFull } from './components/benchmark-card-full/benchmark-card-full';
-
export default [
{
path: '',
@@ -14,8 +12,6 @@ export default [
{ path: 'students', component: Workspace },
{ path: 'students/:studentId', component: Workspace },
{ path: 'students/:studentId/goals/:goalId', component: Workspace },
- // Benchmark creation still uses the dedicated page (no create-benchmark modal yet)
- { path: 'students/:studentId/goals/:goalId/benchmarks/new', component: BenchmarkCardFull },
{ path: 'reports', component: Reports },
{ path: 'reports/student-progress', component: StudentProgressReport },
],