From e2834c1d5b3c04e5fee59e15eef96b428f6173b4 Mon Sep 17 00:00:00 2001 From: Oliver Pelly Date: Wed, 8 Apr 2026 15:48:28 -0700 Subject: [PATCH] modal consolidation --- .../add-goal-modal/add-goal-modal.ts | 56 --------- .../edit-goal-modal/edit-goal-modal.html | 29 ----- .../edit-goal-modal/edit-goal-modal.scss | 1 - .../edit-goal-modal/edit-goal-modal.ts | 58 --------- .../goal-modal.html} | 6 +- .../goal-modal.scss} | 0 .../components/goal-modal/goal-modal.ts | 113 ++++++++++++++++++ .../components/workspace/workspace.html | 13 +- .../desktop/components/workspace/workspace.ts | 18 ++- 9 files changed, 130 insertions(+), 164 deletions(-) delete mode 100644 ui/winstudentgoaltracker/src/app/desktop/components/add-goal-modal/add-goal-modal.ts delete mode 100644 ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.html delete mode 100644 ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.scss delete mode 100644 ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.ts rename ui/winstudentgoaltracker/src/app/desktop/components/{add-goal-modal/add-goal-modal.html => goal-modal/goal-modal.html} (84%) rename ui/winstudentgoaltracker/src/app/desktop/components/{add-goal-modal/add-goal-modal.scss => goal-modal/goal-modal.scss} (100%) create mode 100644 ui/winstudentgoaltracker/src/app/desktop/components/goal-modal/goal-modal.ts diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/add-goal-modal/add-goal-modal.ts b/ui/winstudentgoaltracker/src/app/desktop/components/add-goal-modal/add-goal-modal.ts deleted file mode 100644 index ac775f3..0000000 --- a/ui/winstudentgoaltracker/src/app/desktop/components/add-goal-modal/add-goal-modal.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Component, inject, input, output, signal } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { ModalShell } from '../modal-shell/modal-shell'; -import { CreateGoalDto } from '../../../shared/classes/create-goal.dto'; -import { StudentGoalItem } from '../../../shared/classes/student-goal'; -import { StudentService } from '../../../shared/services/student.service'; - -@Component({ - selector: 'app-add-goal-modal', - imports: [FormsModule, ModalShell], - templateUrl: './add-goal-modal.html', - styleUrl: './add-goal-modal.scss', -}) -export class AddGoalModal { - private readonly studentService = inject(StudentService); - - readonly studentId = input.required(); - readonly existingGoals = input.required(); - readonly nextIepDate = input(); - readonly goalCreated = output(); - readonly cancelled = output(); - - protected readonly isSubmitting = signal(false); - protected readonly errorMessage = signal(null); - - protected form: CreateGoalDto = { - description: '', - category: '', - baseline: '', - goalParentId: null, - targetCompletionDate: null, - }; - - ngOnInit() { - const iepDate = this.nextIepDate?.(); - if (iepDate) { - this.form.targetCompletionDate = iepDate; - } - } - - async onSubmit() { - if (!this.form.category.trim()) return; - this.errorMessage.set(null); - this.isSubmitting.set(true); - - const result = await this.studentService.createGoal(this.studentId(), this.form); - this.isSubmitting.set(false); - - if (!result.success) { - this.errorMessage.set(result.message); - return; - } - - this.goalCreated.emit(result.payload!); - } -} diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.html b/ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.html deleted file mode 100644 index 426cf00..0000000 --- a/ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.html +++ /dev/null @@ -1,29 +0,0 @@ - -
- - -
-
- - -
-
- - -
-
- - -
- - @if (errorMessage()) { -

{{ errorMessage() }}

- } - - -
diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.scss b/ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.scss deleted file mode 100644 index 2918c96..0000000 --- a/ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.scss +++ /dev/null @@ -1 +0,0 @@ -/* Inherits all styles from modal-shell via ::ng-deep */ diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.ts b/ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.ts deleted file mode 100644 index 35ad92f..0000000 --- a/ui/winstudentgoaltracker/src/app/desktop/components/edit-goal-modal/edit-goal-modal.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Component, inject, input, output, signal } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { ModalShell } from '../modal-shell/modal-shell'; -import { StudentService } from '../../../shared/services/student.service'; -import { StudentGoalItem } from '../../../shared/classes/student-goal'; - -@Component({ - selector: 'app-edit-goal-modal', - imports: [FormsModule, ModalShell], - templateUrl: './edit-goal-modal.html', - styleUrl: './edit-goal-modal.scss', -}) -export class EditGoalModal { - private readonly studentService = inject(StudentService); - - readonly studentId = input.required(); - readonly goal = input.required(); - readonly saved = output(); - readonly closed = output(); - - protected readonly saving = signal(false); - protected readonly errorMessage = signal(null); - - protected category = ''; - protected description = ''; - protected baseline = ''; - protected targetCompletionDate: string | null = null; - - ngOnInit() { - const g = this.goal(); - this.category = g.category; - this.description = g.description; - this.baseline = g.baseline; - this.targetCompletionDate = g.targetCompletionDate ? g.targetCompletionDate.substring(0, 10) : null; - } - - async onSave() { - if (!this.category.trim() || !this.description.trim()) return; - this.saving.set(true); - this.errorMessage.set(null); - - const result = await this.studentService.updateGoal(this.studentId(), this.goal().goalId, { - category: this.category, - description: this.description, - baseline: this.baseline, - targetCompletionDate: this.targetCompletionDate, - }); - - 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/add-goal-modal/add-goal-modal.html b/ui/winstudentgoaltracker/src/app/desktop/components/goal-modal/goal-modal.html similarity index 84% rename from ui/winstudentgoaltracker/src/app/desktop/components/add-goal-modal/add-goal-modal.html rename to ui/winstudentgoaltracker/src/app/desktop/components/goal-modal/goal-modal.html index a5d4b23..48dee84 100644 --- a/ui/winstudentgoaltracker/src/app/desktop/components/add-goal-modal/add-goal-modal.html +++ b/ui/winstudentgoaltracker/src/app/desktop/components/goal-modal/goal-modal.html @@ -1,4 +1,4 @@ - +
- +
diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/add-goal-modal/add-goal-modal.scss b/ui/winstudentgoaltracker/src/app/desktop/components/goal-modal/goal-modal.scss similarity index 100% rename from ui/winstudentgoaltracker/src/app/desktop/components/add-goal-modal/add-goal-modal.scss rename to ui/winstudentgoaltracker/src/app/desktop/components/goal-modal/goal-modal.scss diff --git a/ui/winstudentgoaltracker/src/app/desktop/components/goal-modal/goal-modal.ts b/ui/winstudentgoaltracker/src/app/desktop/components/goal-modal/goal-modal.ts new file mode 100644 index 0000000..37cd2be --- /dev/null +++ b/ui/winstudentgoaltracker/src/app/desktop/components/goal-modal/goal-modal.ts @@ -0,0 +1,113 @@ +import { Component, inject, input, output, signal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { ModalShell } from '../modal-shell/modal-shell'; +import { CreateGoalDto } from '../../../shared/classes/create-goal.dto'; +import { StudentGoalItem } from '../../../shared/classes/student-goal'; +import { StudentService } from '../../../shared/services/student.service'; + +@Component({ + selector: 'app-goal-modal', + imports: [FormsModule, ModalShell], + templateUrl: './goal-modal.html', + styleUrl: './goal-modal.scss', +}) +export class GoalModal { + private readonly studentService = inject(StudentService); + + /** Required: the student this goal belongs to. */ + readonly studentId = input.required(); + + /** Optional: when provided the modal operates in edit mode. */ + readonly goal = input(null); + + /** Optional: used to pre-fill the target completion date in add mode. */ + readonly nextIepDate = input(null); + + /** Emits the newly created goal (add mode). */ + readonly goalCreated = output(); + + /** Emits when an existing goal has been saved (edit mode). */ + readonly saved = output(); + + /** Emits when the modal is dismissed without saving. */ + readonly closed = output(); + + protected readonly isSubmitting = signal(false); + protected readonly errorMessage = signal(null); + + protected form: CreateGoalDto = { + description: '', + category: '', + baseline: '', + goalParentId: null, + targetCompletionDate: null, + }; + + protected get isEditMode(): boolean { + return !!this.goal(); + } + + protected get modalTitle(): string { + return this.isEditMode ? 'Edit Goal' : 'Add Goal'; + } + + protected get submitLabel(): string { + return this.isEditMode ? 'Save' : 'Add Goal'; + } + + ngOnInit() { + const existing = this.goal(); + if (existing) { + // Edit mode — populate form from the existing goal + this.form.category = existing.category; + this.form.description = existing.description; + this.form.baseline = existing.baseline; + this.form.goalParentId = existing.goalParentId; + this.form.targetCompletionDate = existing.targetCompletionDate + ? existing.targetCompletionDate.substring(0, 10) + : null; + } else { + // Add mode — pre-fill target date from IEP if available + const iepDate = this.nextIepDate?.(); + if (iepDate) { + this.form.targetCompletionDate = iepDate; + } + } + } + + async onSubmit() { + if (!this.form.category.trim()) return; + this.errorMessage.set(null); + this.isSubmitting.set(true); + + if (this.isEditMode) { + const result = await this.studentService.updateGoal( + this.studentId(), + this.goal()!.goalId, + { + category: this.form.category, + description: this.form.description, + baseline: this.form.baseline, + targetCompletionDate: this.form.targetCompletionDate, + }, + ); + this.isSubmitting.set(false); + + if (result.success) { + this.studentService.notifyDataChanged(); + this.saved.emit(); + } else { + this.errorMessage.set(result.message); + } + } else { + const result = await this.studentService.createGoal(this.studentId(), this.form); + this.isSubmitting.set(false); + + if (result.success) { + this.goalCreated.emit(result.payload!); + } 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 00d5240..4df120a 100644 --- a/ui/winstudentgoaltracker/src/app/desktop/components/workspace/workspace.html +++ b/ui/winstudentgoaltracker/src/app/desktop/components/workspace/workspace.html @@ -4,13 +4,12 @@ } @else { -@if (showAddGoalModal()) { - -} -@if (showEditGoalModal() && selectedGoal()) { - +@if (showGoalModal()) { + } @if (showEditBenchmarkModal()) { ('benchmarks'); // Modal states - protected readonly showAddGoalModal = signal(false); - protected readonly showEditGoalModal = signal(false); + protected readonly showGoalModal = signal(null); protected readonly showEditBenchmarkModal = signal(null); protected readonly showEditEventModal = signal(null); @@ -113,20 +111,20 @@ export class Workspace { // Modal handlers onEditGoal() { - this.showEditGoalModal.set(true); + this.showGoalModal.set(this.selectedGoal()!); } - onEditGoalSaved() { - this.showEditGoalModal.set(false); + onGoalSaved() { + this.showGoalModal.set(null); this.loadStudentData(this.studentId()!); } onAddGoal() { - this.showAddGoalModal.set(true); + this.showGoalModal.set('add'); } onGoalCreated(goal: StudentGoalItem) { - this.showAddGoalModal.set(false); + this.showGoalModal.set(null); this.studentService.notifyDataChanged(); this.loadStudentData(this.studentId()!).then(() => { this.selectedGoalId.set(goal.goalId);