Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
130182f
feat(student): implement StudentService for API integration and updat…
constantine0621 Jun 22, 2026
9348a9f
Changes in Student interface
constantine0621 Jun 22, 2026
6155251
feat(student): update StudentElm interface and related components to …
constantine0621 Jun 23, 2026
55b1c68
feat(student): update StudentElm interface and related components to …
constantine0621 Jun 23, 2026
7a5e3bf
feat(course): add CourseElm interface and CourseService for course da…
constantine0621 Jun 24, 2026
ac9ec74
adding shared warning messages for Add and Edit forms
constantine0621 Jun 24, 2026
f1f7a02
added majorId to student element interface and refactored getStudents…
constantine0621 Jun 24, 2026
07200ac
feat(i18n): add Bulgarian and English localization files for student …
constantine0621 Jun 25, 2026
29237f3
feat(i18n): restructure student add/edit warnings in Bulgarian and En…
constantine0621 Jun 25, 2026
f945835
Merge branch 'main' of https://github.com/uni-dev-lab/uniplan-web int…
constantine0621 Jun 25, 2026
bc92eeb
style(student-table): student-table i18n
constantine0621 Jun 25, 2026
aa1c25e
Merge branch main into Student-db-connection
constantine0621 Jun 26, 2026
c15562c
feat(student-table): emit subtypesLoaded event and clean up unused code
constantine0621 Jun 26, 2026
828b0b0
Merge branch 'main' of https://github.com/uni-dev-lab/uniplan-web int…
constantine0621 Jun 30, 2026
001c74b
refactor: update CourseService to use API_ENDPOINTS for URL management
constantine0621 Jun 30, 2026
2b5f90b
refactor: remove unused apiUrl variable from CourseService
constantine0621 Jun 30, 2026
d5d2583
refactor: update StudentService to use API_ENDPOINTS for student API …
constantine0621 Jul 1, 2026
64a5213
Merge branch 'main' into Feature--Student-db-connection
constantine0621 Jul 1, 2026
ce408b2
Merge branch 'main' into Feature--Student-db-connection
constantine0621 Jul 1, 2026
1966f80
Merge branch 'main' into Feature--Student-db-connection
constantine0621 Jul 4, 2026
94819f9
Merge branch 'main' into Feature--Student-db-connection
constantine0621 Jul 4, 2026
23e236f
Merge branch 'Feature--Student-db-connection' of https://github.com/u…
constantine0621 Jul 4, 2026
ccc0fe5
update comment
constantine0621 Jul 6, 2026
5292fbd
Refactor StudentElm interface to use CourseSubtype type and update st…
constantine0621 Jul 9, 2026
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
19 changes: 19 additions & 0 deletions uniplanWeb/public/i18n/bg.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,27 @@
"faculty-number-label": "Факултетен номер",
"course-label": "Курс",
"qualification-level-label": "Квалификационна степен",
"first-name-label": "Първо име",
"last-name-label": "Фамилия",
"major-label": "Специалност",
"study-mode-label": "Форма на обучение",
"add": {
"title": "Добави студент"
},
"edit": {
"title": "Редактирай студент"
},
"delete": {
"title": "Изтрий студент"
},
"warnings": {
"first-name": "Моля въведете първо име на студента.",
"last-name": "Моля въведете фамилия на студента.",
"faculty-number": "Моля въведете факултетен номер.",
"major": "Моля изберете специалност.",
"study-mode": "Моля изберете форма на обучение.",
"qualification": "Моля изберете квалификационна степен.",
"course": "Моля изберете курс."
}
},
"settings": {
Expand Down
19 changes: 19 additions & 0 deletions uniplanWeb/public/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,27 @@
"faculty-number-label": "Student ID",
"course-label": "Course",
"qualification-level-label": "Qualification level",
"first-name-label": "First name",
"last-name-label": "Last name",
"major-label": "Major",
"study-mode-label": "Study mode",
"add": {
"title": "Add student"
},
"edit": {
"title": "Edit student"
},
"delete":{
"title": "Delete student"
},
"warnings": {
"first-name": "Please enter the student's first name.",
"last-name": "Please enter the student's last name.",
"faculty-number": "Please enter the faculty number.",
"major": "Please select a major.",
"study-mode": "Please select a study mode.",
"qualification": "Please select a qualification level.",
"course": "Please select a course."
}
},
"settings": {
Expand Down
1 change: 1 addition & 0 deletions uniplanWeb/src/app/config/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export const API_ENDPOINTS = {
courses: `${environment.baseUrl}/courses`,
faculties: `${environment.baseUrl}/faculties`,
majors: `${environment.baseUrl}/majors`,
students: `${environment.baseUrl}/students`,
};
7 changes: 7 additions & 0 deletions uniplanWeb/src/app/core/interfaces/course-elm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface CourseElm {
id: string;
majorId: string;
courseYear: number;
courseType: string;
courseSubtype: string;
}
12 changes: 8 additions & 4 deletions uniplanWeb/src/app/core/interfaces/student-elm.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { CourseSubtype } from "../../features/course/course-subtype";

export interface StudentElm {
id: string;
position: number;
name: string;
facultyNumber: string;
major: string;
majorType: string;
course: string;
subtype: 'редовно' | 'задочно';
majorId: string;
majorName: string;
courseType: string;
courseSubtype: CourseSubtype;
courseYear: number;
}
18 changes: 18 additions & 0 deletions uniplanWeb/src/app/features/course/course-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { HttpClient } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { CourseElm } from '../../core/interfaces/course-elm';
import { API_ENDPOINTS } from '../../config/endpoints';

@Injectable({
providedIn: 'root'
})
export class CourseService {
private http = inject(HttpClient);

getCoursesByMajorId(majorId: string): Observable<CourseElm[]> {
return this.http.get<CourseElm[]>(`${API_ENDPOINTS.courses}/major/${majorId}`);
}
}
//placeholder course service to make student form dropdowns work,
//when replacing this please provide a getCoursesByMajorId-like method
6 changes: 6 additions & 0 deletions uniplanWeb/src/app/features/course/course-subtype.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const CourseSubtypeLabels = {
FullTime: 'редовно',
PartTime: 'задочно',
} as const;

export type CourseSubtype = typeof CourseSubtypeLabels[keyof typeof CourseSubtypeLabels];
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
[searchFacNum]="searchFacNum"
[searchMajor]="searchMajor"
[subtype]="selectedStudentSubtype"
[subtypes]="studentSubtypes">
[subtypes]="studentSubtypes"
(subtypesLoaded)="studentSubtypes=$event">
</app-student-table>
</div>
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Component, OnInit } from '@angular/core';

import { StudentElm } from '../../../core/interfaces/student-elm';
import { StudentOptions } from '../student-options/student-options';
import { StudentFilters } from '../student-filters/student-filters';
import { StudentTable, ELEMENT_STUDENT_DATA } from '../student-table/student-table';
import { StudentTable } from '../student-table/student-table';

@Component({
selector: 'app-student-panel',
Expand All @@ -19,7 +18,6 @@ export class StudentPanel implements OnInit {
studentSubtypes: string[] = [];

ngOnInit(): void {
const students: StudentElm[] = ELEMENT_STUDENT_DATA;
this.studentSubtypes = StudentTable.getFilterOptions(students).subtypes;

}
}
61 changes: 61 additions & 0 deletions uniplanWeb/src/app/features/student/student-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { inject, Injectable } from '@angular/core';
import { map, Observable, Subject } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { StudentElm } from '../../core/interfaces/student-elm';
import { API_ENDPOINTS } from '../../config/endpoints';

@Injectable({
providedIn: 'root'
})
export class StudentService {
private apiUrl = API_ENDPOINTS.students;

refreshNeeded = new Subject<void>();

private http = inject(HttpClient);

getStudents(): Observable<StudentElm[]> {
return this.http.get<StudentElm[]>(this.apiUrl).pipe(
map((students) =>
students.map((student, index) => ({
id: student.id,
position: index + 1,
name: student.name,
facultyNumber: student.facultyNumber,
majorId: student.majorId,
majorName: student.majorName,
courseType: student.courseType,
courseSubtype: student.courseSubtype,
courseYear: student.courseYear,
}))
)
);
}
createStudent(student: Omit<StudentElm, 'position' | 'id'>): Observable<void> {
return this.http.post<void>(`${this.apiUrl}`, student).pipe(
map((res) => {
this.refreshNeeded.next();
return res;
})
);
}

editStudent(id: string,
updatedStudent: Omit<StudentElm, 'position' | 'id'>): Observable<void> {
return this.http.put<void>(`${this.apiUrl}/${id}`, updatedStudent).pipe(
map((res) => {
this.refreshNeeded.next();
return res;
})
);
}

deleteStudent(id: string): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`).pipe(
map((res) => {
this.refreshNeeded.next();
return res;
})
);
}
}
Original file line number Diff line number Diff line change
@@ -1,104 +1,66 @@
<div class="table-wrapper">
<table mat-table [dataSource]="dataSourceFilter"
class="mat-elevation-z8 table-header">
<table mat-table [dataSource]="dataSourceFilter" class="mat-elevation-z8 table-header">
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef class="col-position"> {{ 'features.number-label' | translate }}
</th>
</ng-container>

<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef class="col-name">{{ 'features.name-label' | translate }}
</th>
<th mat-header-cell *matHeaderCellDef class="col-name"> {{ 'features.name-label' | translate }} </th>
</ng-container>

<ng-container matColumnDef="facultyNumber">
<th mat-header-cell *matHeaderCellDef class="col-fac-number">
{{ 'student.faculty-number-label' | translate }}
</th>
<th mat-header-cell *matHeaderCellDef class="col-fac-number"> {{ 'student.faculty-number-label' | translate }} </th>
</ng-container>

<ng-container matColumnDef="major">
<th mat-header-cell *matHeaderCellDef class="col-major">
{{ 'features.major-label' | translate }}
</th>
<ng-container matColumnDef="majorName">
<th mat-header-cell *matHeaderCellDef class="col-major"> {{ 'features.major-label' | translate }} </th>
</ng-container>

<ng-container matColumnDef="majorType">
<th mat-header-cell *matHeaderCellDef class="col-major-type">
{{'student.qualification-level-label' | translate}}
</th>
<ng-container matColumnDef="courseType">
<th mat-header-cell *matHeaderCellDef class="col-course-type"> {{ 'student.qualification-level-label' | translate }} </th>
</ng-container>

<ng-container matColumnDef="course">
<th mat-header-cell *matHeaderCellDef class="col-course"> {{ 'student.course-label' | translate }}
</th>
<ng-container matColumnDef="courseSubtype">
<th mat-header-cell *matHeaderCellDef class="col-subtype"> {{ 'features.study-mode-label' | translate }} </th>
</ng-container>

<ng-container matColumnDef="subtype">
<th mat-header-cell *matHeaderCellDef class="col-subtype">{{ 'features.study-mode-label' | translate }}
</th>
<ng-container matColumnDef="courseYear">
<th mat-header-cell *matHeaderCellDef class="col-year"> {{ 'student.course-label' | translate }} </th>
</ng-container>

<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="col-actions"> {{ 'features.actions-label' | translate }}
</th>
<th mat-header-cell *matHeaderCellDef class="col-actions"> {{ 'features.actions-label' | translate }} </th>
</ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
</table>

<div class="scrollable-body">
<table mat-table [dataSource]="dataSourceFilter"
class="mat-elevation-z8 table-body">
<table mat-table [dataSource]="dataSourceFilter" class="mat-elevation-z8 table-body">
<ng-container matColumnDef="position">
<td mat-cell *matCellDef="let element" class="col-position">
{{element.position}} </td>
<td mat-cell *matCellDef="let element" class="col-position"> {{element.position}} </td>
</ng-container>

<ng-container matColumnDef="name">
<td mat-cell *matCellDef="let element" class="col-name">
{{element.name}} </td>
<td mat-cell *matCellDef="let element" class="col-name"> {{element.name}} </td>
</ng-container>

<ng-container matColumnDef="facultyNumber">
<td mat-cell *matCellDef="let element" class="col-fac-number">
{{element.facultyNumber}} </td>
<td mat-cell *matCellDef="let element" class="col-fac-number"> {{element.facultyNumber}} </td>
</ng-container>

<ng-container matColumnDef="major">
<td mat-cell *matCellDef="let element" class="col-major">
{{element.major}} </td>
<ng-container matColumnDef="majorName">
<td mat-cell *matCellDef="let element" class="col-major"> {{element.majorName}} </td>
</ng-container>

<ng-container matColumnDef="majorType">
<td mat-cell *matCellDef="let element" class="col-major-type">
{{element.majorType}} </td>
<ng-container matColumnDef="courseType">
<td mat-cell *matCellDef="let element" class="col-course-type"> {{element.courseType}} </td>
</ng-container>

<ng-container matColumnDef="course">
<td mat-cell *matCellDef="let element" class="col-course">
{{element.course}} </td>
<ng-container matColumnDef="courseSubtype">
<td mat-cell *matCellDef="let element" class="col-subtype"> {{element.courseSubtype}} </td>
</ng-container>

<ng-container matColumnDef="subtype">
<td mat-cell *matCellDef="let element" class="col-subtype">
{{element.subtype}} </td>
<ng-container matColumnDef="courseYear">
<td mat-cell *matCellDef="let element" class="col-year"> {{element.courseYear}} </td>
</ng-container>

<ng-container matColumnDef="actions">
<td mat-cell *matCellDef="let element" class="col-actions">
<button mat-icon-button color="primary"
(click)="onEdit(element)">
<button mat-icon-button color="primary" (click)="onEdit(element)">
<mat-icon>edit</mat-icon>
</button>
<button mat-icon-button color="warn"
(click)="onDelete(element)">
<button mat-icon-button color="warn" (click)="onDelete(element)">
<mat-icon>delete</mat-icon>
</button>
</td>
</ng-container>

<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
</div>
Loading