organized types into one place

This commit is contained in:
2026-03-02 14:08:01 -08:00
parent 15b82360bf
commit 328a44043f
15 changed files with 67 additions and 40 deletions
@@ -1,7 +1,7 @@
import { Component, inject, signal } from '@angular/core'; import { Component, inject, signal } from '@angular/core';
import { StudentCard } from '../student-card/student-card'; import { StudentCard } from '../student-card/student-card';
import { StudentService } from '../../../../shared/services/student.service'; import { StudentService } from '../../../../shared/services/dummy-student.service';
import { StudentCardDto } from '../../../../shared/models/dto/student-card.dto'; import { StudentCardDto } from '../../../../shared/classes/student-card.dto';
export type DisplayMode = 'card' | 'list'; export type DisplayMode = 'card' | 'list';
@@ -25,6 +25,8 @@ export class StudentCardList {
protected readonly students = signal<StudentCardDto[]>([]); protected readonly students = signal<StudentCardDto[]>([]);
protected readonly displayMode = signal<DisplayMode>('card'); protected readonly displayMode = signal<DisplayMode>('card');
public errorMessage = signal<String | null>(null);
// ************************** Properties *************************** // ************************** Properties ***************************
// ************************ Public Methods ************************* // ************************ Public Methods *************************
@@ -41,8 +43,17 @@ export class StudentCardList {
// Loads students from the service and populates the students signal. // Loads students from the service and populates the students signal.
// ***************************************************************** // *****************************************************************
private loadStudents() { private loadStudents() {
this.studentService.getStudentCards().subscribe(data => { this.studentService.getStudentCards().then(data => {
this.students.set(data);
if(!data.success)
{
this.errorMessage.set(data.message);
}
else
{
this.students.set(data.payload || [])
}
}); });
} }
} }
@@ -1,6 +1,6 @@
import { Component, input } from '@angular/core'; import { Component, input } from '@angular/core';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { StudentCardDto } from '../../../../shared/models/dto/student-card.dto'; import { StudentCardDto } from '../../../../shared/classes/student-card.dto';
@Component({ @Component({
selector: 'app-student-card', selector: 'app-student-card',
@@ -1,6 +1,6 @@
import { Component, inject, input } from '@angular/core'; import { Component, inject, input } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { StudentCardDto } from '../../../shared/models/dto/student-card.dto'; import { StudentCardDto } from '../../../shared/classes/student-card.dto';
@Component({ @Component({
selector: 'app-student-card', selector: 'app-student-card',
@@ -1,6 +1,7 @@
import { Component, inject, signal } from '@angular/core'; import { Component, inject, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router'; import { RouterOutlet } from '@angular/router';
import { DummyMobileHomeMeta, MobileHomeMeta } from '../../../shared/services/dummy-mobile-home-meta.service'; import { DummyMobileHomeMeta } from '../../../shared/services/dummy-mobile-home-meta.service';
import { MobileHomeMeta } from '../../../shared/classes/mobile-home-meta';
import { Auth } from '../../../shared/services/auth'; import { Auth } from '../../../shared/services/auth';
@Component({ @Component({
@@ -1,6 +1,7 @@
import { Component, inject, signal } from '@angular/core'; import { Component, inject, signal } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { DummyStudentGoalService, StudentGoalSummary } from '../../../shared/services/dummy-student-goal.service'; import { DummyStudentGoalService } from '../../../shared/services/dummy-student-goal.service';
import { StudentGoalSummary } from '../../../shared/classes/student-goal';
@Component({ @Component({
selector: 'app-student-goals', selector: 'app-student-goals',
@@ -1,7 +1,7 @@
import { Component, inject, signal } from '@angular/core'; import { Component, inject, signal } from '@angular/core';
import { StudentCard } from '../../components/student-card/student-card'; import { StudentCard } from '../../components/student-card/student-card';
import { StudentService } from '../../../shared/services/student.service'; import { StudentService } from '../../../shared/services/dummy-student.service';
import { StudentCardDto } from '../../../shared/models/dto/student-card.dto'; import { StudentCardDto } from '../../../shared/classes/student-card.dto';
@Component({ @Component({
selector: 'app-students', selector: 'app-students',
@@ -22,6 +22,8 @@ export class Students {
private readonly studentService = inject(StudentService); private readonly studentService = inject(StudentService);
protected readonly students = signal<StudentCardDto[]>([]); protected readonly students = signal<StudentCardDto[]>([]);
public errorMessage = signal<String | null>(null);
// ************************** Properties *************************** // ************************** Properties ***************************
// ************************ Public Methods ************************* // ************************ Public Methods *************************
@@ -34,8 +36,16 @@ export class Students {
// Loads the list of students assigned to the current user. // Loads the list of students assigned to the current user.
// ***************************************************************** // *****************************************************************
private loadStudents() { private loadStudents() {
this.studentService.getDummyStudentsForUser().subscribe(data => { this.studentService.getDummyStudentsForUser().then(data => {
this.students.set(data);
if (!data.success)
{
this.errorMessage.set(data.message);
}
else
{
this.students.set(data.payload || []);
}
}); });
} }
} }
@@ -0,0 +1,4 @@
export interface MobileHomeMeta {
programName: string; // program.name — varchar(255)
userName: string; // user.name — varchar(255)
}
@@ -0,0 +1,12 @@
export interface StudentGoalSummary {
studentIdentifier: string; // student.identifier — varchar(50)
goals: StudentGoalItem[];
}
export interface StudentGoalItem {
goalId: string; // goal.id_goal — char(36)
title: string; // goal.title — varchar(255)
description: string; // goal.description — text
category: string; // goal.category — varchar(100)
progressEventCount: number; // count of progress_event rows for this goal
}
@@ -10,7 +10,7 @@ import {
SelectProgramRequest, SelectProgramRequest,
SelectProgramResponse, SelectProgramResponse,
TokenRefreshResponse, TokenRefreshResponse,
} from '../models/auth.models'; } from '../classes/auth.models';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
@@ -8,7 +8,7 @@ import {
SelectProgramResponse, SelectProgramResponse,
TokenRefreshResponse, TokenRefreshResponse,
UserProgramSummary, UserProgramSummary,
} from '../models/auth.models'; } from '../classes/auth.models';
import { Api } from './api'; import { Api } from './api';
const STORAGE_KEYS = { const STORAGE_KEYS = {
@@ -1,17 +1,12 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { ApiResult } from '../classes/api-result'; import { ApiResult } from '../classes/api-result';
import { MobileHomeMeta } from '../classes/mobile-home-meta';
// ***************************************************************** // *****************************************************************
// TODO: This dummy service should be replaced by MobileHomeMeta, // TODO: This dummy service should be replaced by MobileHomeMeta,
// which will fetch real data from the API. // which will fetch real data from the API.
// ***************************************************************** // *****************************************************************
export interface MobileHomeMeta {
programName: string; // program.name — varchar(255)
userName: string; // user.name — varchar(255)
}
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
@@ -1,24 +1,12 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ApiResult } from '../classes/api-result'; import { ApiResult } from '../classes/api-result';
import { StudentGoalSummary } from '../classes/student-goal';
// ***************************************************************** // *****************************************************************
// TODO: This dummy service should be replaced by StudentGoalService, // TODO: This dummy service should be replaced by StudentGoalService,
// which will fetch real data from the API. // which will fetch real data from the API.
// ***************************************************************** // *****************************************************************
export interface StudentGoalSummary {
studentIdentifier: string; // student.identifier — varchar(50)
goals: StudentGoalItem[];
}
export interface StudentGoalItem {
goalId: string; // goal.id_goal — char(36)
title: string; // goal.title — varchar(255)
description: string; // goal.description — text
category: string; // goal.category — varchar(100)
progressEventCount: number; // count of progress_event rows for this goal
}
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
@@ -1,6 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { StudentCardDto } from '../models/dto/student-card.dto'; import { StudentCardDto } from '../classes/student-card.dto';
import { ApiResult } from '../classes/api-result';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
@@ -19,8 +20,8 @@ export class StudentService {
// Returns student card summaries. Currently returns dummy data // Returns student card summaries. Currently returns dummy data
// until the API endpoint is available. // until the API endpoint is available.
// ***************************************************************** // *****************************************************************
getStudentCards(): Observable<StudentCardDto[]> { async getStudentCards(): Promise<ApiResult<StudentCardDto[]>> {
return of([ var payload = [
{ {
studentId: '1', studentId: '1',
identifier: 'J.B', identifier: 'J.B',
@@ -45,7 +46,9 @@ export class StudentService {
goalCount: 2, goalCount: 2,
progressEventCount: 0, progressEventCount: 0,
}, },
]); ];
return ApiResult.ok(payload);
} }
// ***************************************************************** // *****************************************************************
@@ -54,14 +57,16 @@ export class StudentService {
// Returns students assigned to the current user with their // Returns students assigned to the current user with their
// identifier, age, goal count, and progress event count. // identifier, age, goal count, and progress event count.
// ***************************************************************** // *****************************************************************
getDummyStudentsForUser(): Observable<StudentCardDto[]> { async getDummyStudentsForUser(): Promise<ApiResult<StudentCardDto[]>> {
return of([ var payload = [
{ studentId: '1', identifier: 'J.B', age: 21, lastEntryDate: '2026-02-21', goalCount: 3, progressEventCount: 5 }, { studentId: '1', identifier: 'J.B', age: 21, lastEntryDate: '2026-02-21', goalCount: 3, progressEventCount: 5 },
{ studentId: '2', identifier: 'M.K', age: 19, lastEntryDate: '2026-02-25', goalCount: 4, progressEventCount: 8 }, { studentId: '2', identifier: 'M.K', age: 19, lastEntryDate: '2026-02-25', goalCount: 4, progressEventCount: 8 },
{ studentId: '3', identifier: 'A.R', age: 22, lastEntryDate: null, goalCount: 2, progressEventCount: 0 }, { studentId: '3', identifier: 'A.R', age: 22, lastEntryDate: null, goalCount: 2, progressEventCount: 0 },
{ studentId: '4', identifier: 'T.W', age: 20, lastEntryDate: '2026-02-18', goalCount: 5, progressEventCount: 12 }, { studentId: '4', identifier: 'T.W', age: 20, lastEntryDate: '2026-02-18', goalCount: 5, progressEventCount: 12 },
{ studentId: '5', identifier: 'L.C', age: 18, lastEntryDate: '2026-02-27', goalCount: 1, progressEventCount: 2 }, { studentId: '5', identifier: 'L.C', age: 18, lastEntryDate: '2026-02-27', goalCount: 1, progressEventCount: 2 },
]); ];
return ApiResult.ok(payload);
} }
// ************************ Event Handlers ************************* // ************************ Event Handlers *************************