From 8391cf6df63f79ad406b6e0ddb61bd5682142326 Mon Sep 17 00:00:00 2001 From: silasakash Date: Mon, 9 Mar 2026 15:55:48 +0100 Subject: [PATCH] create dashboard template --- frontend/src/app/app.routes.ts | 5 +- frontend/src/app/auth/auth.service.ts | 13 ++++- .../src/app/auth/login/login.component.ts | 6 +- .../app/dashboard/dashboard.component.html | 15 +++++ .../app/dashboard/dashboard.component.scss | 50 ++++++++++++++++ .../src/app/dashboard/dashboard.component.ts | 13 +++++ .../event-create-form.component.html | 15 +++++ .../event-create-form.component.ts | 52 +++++++++++++++++ .../report-progress.component.html | 14 +++++ .../report-progress.component.scss | 15 +++++ .../report-progress.component.ts | 57 +++++++++++++++++++ frontend/src/app/services/event.service.ts | 34 +++++++++++ frontend/src/app/services/report.service.ts | 14 +++++ 13 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 frontend/src/app/dashboard/dashboard.component.html create mode 100644 frontend/src/app/dashboard/dashboard.component.scss create mode 100644 frontend/src/app/dashboard/dashboard.component.ts create mode 100644 frontend/src/app/dashboard/event-create-form/event-create-form.component.html create mode 100644 frontend/src/app/dashboard/event-create-form/event-create-form.component.ts create mode 100644 frontend/src/app/dashboard/report-progress/report-progress.component.html create mode 100644 frontend/src/app/dashboard/report-progress/report-progress.component.scss create mode 100644 frontend/src/app/dashboard/report-progress/report-progress.component.ts create mode 100644 frontend/src/app/services/event.service.ts create mode 100644 frontend/src/app/services/report.service.ts diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts index b4e3a25..d5756fd 100644 --- a/frontend/src/app/app.routes.ts +++ b/frontend/src/app/app.routes.ts @@ -1,9 +1,12 @@ import { Routes } from '@angular/router'; import { RegisterComponent } from './auth/register/register.component'; import { LoginComponent } from './auth/login/login.component'; +import { DashboardComponent } from './dashboard/dashboard.component'; export const routes: Routes = [ { path: 'register', component: RegisterComponent }, { path: 'login', component: LoginComponent }, - { path: '', redirectTo: 'register', pathMatch: 'full' } + { path: 'dashboard', component: DashboardComponent }, + { path: '', redirectTo: 'login', pathMatch: 'full' }, // default to login + { path: '**', redirectTo: 'login' } // fallback route ]; \ No newline at end of file diff --git a/frontend/src/app/auth/auth.service.ts b/frontend/src/app/auth/auth.service.ts index 076eccb..8ca5f78 100644 --- a/frontend/src/app/auth/auth.service.ts +++ b/frontend/src/app/auth/auth.service.ts @@ -16,6 +16,7 @@ interface LoginDto { interface LoginResponse { access_token: string; + user: { id: number; username: string; role: string }; } @Injectable({ @@ -23,6 +24,7 @@ interface LoginResponse { }) export class AuthService { private apiUrl = 'http://localhost:3000/api/auth'; + private _currentUser: { id: number; username: string; role: string } | null = null; constructor(private http: HttpClient) {} @@ -33,14 +35,15 @@ export class AuthService { login(dto: LoginDto): Observable { return this.http.post(`${this.apiUrl}/login`, dto).pipe( tap((res) => { - // Save JWT in localStorage localStorage.setItem('token', res.access_token); + this._currentUser = res.user; }) ); } logout(): void { localStorage.removeItem('token'); + this._currentUser = null; } getToken(): string | null { @@ -50,4 +53,12 @@ export class AuthService { isLoggedIn(): boolean { return !!this.getToken(); } + + getCurrentUserId(): number | null { + return this._currentUser?.id ?? null; + } + + getCurrentUser(): { id: number; username: string; role: string } | null { + return this._currentUser; + } } \ No newline at end of file diff --git a/frontend/src/app/auth/login/login.component.ts b/frontend/src/app/auth/login/login.component.ts index c1e91f9..cf084ec 100644 --- a/frontend/src/app/auth/login/login.component.ts +++ b/frontend/src/app/auth/login/login.component.ts @@ -34,7 +34,11 @@ export class LoginComponent { this.auth.login(this.loginForm.value).subscribe({ next: () => { this.error = ''; - this.router.navigate(['/events']); + this.message = 'Login successful!'; + this.cd.detectChanges(); + + // Navigate to dashboard instead of /events + this.router.navigate(['/dashboard']); }, error: (err) => { this.error = err.error?.message ?? 'Invalid email or password'; diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html new file mode 100644 index 0000000..51d1652 --- /dev/null +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -0,0 +1,15 @@ +
+
+ + +
+ +
+ + +
+
\ No newline at end of file diff --git a/frontend/src/app/dashboard/dashboard.component.scss b/frontend/src/app/dashboard/dashboard.component.scss new file mode 100644 index 0000000..fda7ceb --- /dev/null +++ b/frontend/src/app/dashboard/dashboard.component.scss @@ -0,0 +1,50 @@ +.dashboard-container { + padding: 20px; + font-family: Arial, sans-serif; + + header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + + .logo { + font-weight: bold; + font-size: 24px; + } + + nav a { + margin-left: 15px; + text-decoration: none; + color: #333; + } + } + + section { + margin-bottom: 30px; + + h3 { + margin-bottom: 10px; + } + + .status { + margin-top: 10px; + + .progress-bar { + width: 100%; + height: 10px; + background-color: #eee; + border-radius: 5px; + overflow: hidden; + margin-top: 5px; + + .progress-fill { + height: 100%; + background-color: #4caf50; + width: 0%; + transition: width 0.3s ease; + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts new file mode 100644 index 0000000..98706d0 --- /dev/null +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { EventCreateFormComponent } from './event-create-form/event-create-form.component'; +import { ReportProgressComponent } from './report-progress/report-progress.component'; + +@Component({ + selector: 'app-dashboard', + standalone: true, + imports: [RouterModule, EventCreateFormComponent, ReportProgressComponent], + templateUrl: './dashboard.component.html', + styleUrls: ['./dashboard.component.scss'], // <-- add this +}) +export class DashboardComponent {} \ No newline at end of file diff --git a/frontend/src/app/dashboard/event-create-form/event-create-form.component.html b/frontend/src/app/dashboard/event-create-form/event-create-form.component.html new file mode 100644 index 0000000..149bb6b --- /dev/null +++ b/frontend/src/app/dashboard/event-create-form/event-create-form.component.html @@ -0,0 +1,15 @@ +
+

Create New Event

+
+ + + + + + + +
+ +

{{ message }}

+

{{ error }}

+
\ No newline at end of file diff --git a/frontend/src/app/dashboard/event-create-form/event-create-form.component.ts b/frontend/src/app/dashboard/event-create-form/event-create-form.component.ts new file mode 100644 index 0000000..8b2281e --- /dev/null +++ b/frontend/src/app/dashboard/event-create-form/event-create-form.component.ts @@ -0,0 +1,52 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { EventService, CreateEventPayload } from '../../services/event.service'; + +@Component({ + selector: 'app-event-create-form', + standalone: true, + imports: [CommonModule, ReactiveFormsModule], + templateUrl: './event-create-form.component.html', +}) +export class EventCreateFormComponent { + eventForm: FormGroup; + message: string = ''; + error: string = ''; + + constructor(private fb: FormBuilder, private eventService: EventService) { + this.eventForm = this.fb.group({ + title: ['', Validators.required], + location: ['', Validators.required], + event_date: ['', Validators.required], + description: [''], + capacity: [1, [Validators.required, Validators.min(1)]], + }); + } + + onSubmit() { + if (this.eventForm.valid) { + const payload: CreateEventPayload = { + title: this.eventForm.value.title!, + location: this.eventForm.value.location!, + event_date: this.eventForm.value.event_date!, + description: this.eventForm.value.description || '', + capacity: this.eventForm.value.capacity!, + }; + + this.eventService.createEvent(payload).subscribe({ + next: () => { + this.message = 'Event created successfully!'; + this.error = ''; + this.eventForm.reset(); + }, + error: (err) => { + this.error = err.error?.message ?? 'Event creation failed'; + this.message = ''; + }, + }); + } else { + this.error = 'Please fill in all required fields correctly.'; + } + } +} \ No newline at end of file diff --git a/frontend/src/app/dashboard/report-progress/report-progress.component.html b/frontend/src/app/dashboard/report-progress/report-progress.component.html new file mode 100644 index 0000000..33413a6 --- /dev/null +++ b/frontend/src/app/dashboard/report-progress/report-progress.component.html @@ -0,0 +1,14 @@ +
+

Participation Reports

+ + + + + +
+

Status: {{ status() }}

+ +
+
\ No newline at end of file diff --git a/frontend/src/app/dashboard/report-progress/report-progress.component.scss b/frontend/src/app/dashboard/report-progress/report-progress.component.scss new file mode 100644 index 0000000..ae98b04 --- /dev/null +++ b/frontend/src/app/dashboard/report-progress/report-progress.component.scss @@ -0,0 +1,15 @@ +
+

Participation Reports

+ + + + + + +
+

Status: {{ statusMessage }}

+ +
+
\ No newline at end of file diff --git a/frontend/src/app/dashboard/report-progress/report-progress.component.ts b/frontend/src/app/dashboard/report-progress/report-progress.component.ts new file mode 100644 index 0000000..4d263cf --- /dev/null +++ b/frontend/src/app/dashboard/report-progress/report-progress.component.ts @@ -0,0 +1,57 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { EventService, EventItem } from '../../services/event.service'; +import { AuthService } from '../../auth/auth.service'; + +@Component({ + selector: 'app-report-progress', + standalone: true, + imports: [CommonModule, FormsModule], + templateUrl: './report-progress.component.html', +}) +export class ReportProgressComponent { + events: EventItem[] = []; + selectedEventId: number | null = null; + statusMessage = ''; + progressValue = 0; + + constructor( + private eventService: EventService, + private authService: AuthService + ) { + this.loadEvents(); + } + + loadEvents() { + const userId = this.authService.getCurrentUserId(); + if (userId) { + this.eventService.getEventsByUser(userId).subscribe((e: EventItem[]) => { + this.events = e; + }); + } + } + + generateReport() { + if (!this.selectedEventId) return; + + this.statusMessage = 'Generating... (do not close)'; + this.progressValue = 0; + + const interval = setInterval(() => { + this.progressValue += 10; + if (this.progressValue >= 100) { + clearInterval(interval); + this.statusMessage = 'Report generation completed!'; + } + }, 200); + } + + status() { + return this.statusMessage; + } + + progress() { + return this.progressValue; + } +} \ No newline at end of file diff --git a/frontend/src/app/services/event.service.ts b/frontend/src/app/services/event.service.ts new file mode 100644 index 0000000..d7134ca --- /dev/null +++ b/frontend/src/app/services/event.service.ts @@ -0,0 +1,34 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +export interface CreateEventPayload { + title: string; + location: string; + event_date: string; + description?: string; + capacity: number; +} + +export interface EventItem { + event_id: number; + title: string; + [key: string]: any; +} + +@Injectable({ + providedIn: 'root', +}) +export class EventService { + private apiUrl = 'http://localhost:3000/api/events'; + + constructor(private http: HttpClient) {} + + createEvent(payload: CreateEventPayload): Observable { + return this.http.post(`${this.apiUrl}`, payload); + } + + getEventsByUser(userId?: number): Observable { + return this.http.get(`${this.apiUrl}/my/events`); + } +} \ No newline at end of file diff --git a/frontend/src/app/services/report.service.ts b/frontend/src/app/services/report.service.ts new file mode 100644 index 0000000..3f38ff6 --- /dev/null +++ b/frontend/src/app/services/report.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class ReportService { + constructor(private http: HttpClient) {} + + generateReport(eventId: number): Observable { + return this.http.get(`/api/reports/${eventId}`); + } +} \ No newline at end of file