Skip to content

Commit

Permalink
Feature/42 create fe header (#51)
Browse files Browse the repository at this point in the history
* add weather graph and test.
  • Loading branch information
MocStepan authored Apr 21, 2024
1 parent 0764c96 commit f85577e
Show file tree
Hide file tree
Showing 17 changed files with 189 additions and 64 deletions.
26 changes: 26 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
"@angular/platform-browser": "^17.3.0",
"@angular/platform-browser-dynamic": "^17.3.0",
"@angular/router": "^17.3.0",
"chart.js": "^4.4.2",
"moment": "^2.30.1",
"rxjs": "~7.8.0",
"sweetalert2": "^11.10.7",
"ts-node": "^10.9.2",
Expand Down
13 changes: 6 additions & 7 deletions frontend/src/app/auth/login/login.component.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import {ChangeDetectionStrategy, Component, inject, OnInit} from '@angular/core';
import {AuthService} from "../service/auth.service";
import {FormBuilder, FormGroup, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule, Validators} from "@angular/forms";
import {FormBuilder, FormGroup, NG_VALUE_ACCESSOR, ReactiveFormsModule, Validators} from "@angular/forms";
import {LoginForm} from "../model/LoginForm";
import {MatFormField, MatFormFieldModule, MatPrefix} from "@angular/material/form-field";
import {MatFormField, MatPrefix} from "@angular/material/form-field";
import {MatCard} from "@angular/material/card";
import {MatToolbar} from "@angular/material/toolbar";
import {MatIcon, MatIconModule} from "@angular/material/icon";
import {MatInput, MatInputModule} from "@angular/material/input";
import {MatButton, MatButtonModule} from "@angular/material/button";
import {MatIcon} from "@angular/material/icon";
import {MatInput} from "@angular/material/input";
import {MatButton} from "@angular/material/button";
import {NgIf} from "@angular/common";
import {FrontendNotificationService} from "../../shared/frontend-notification/service/frontend-notification.service";
import {Router} from "@angular/router";
import {AppModule} from "../../app.module";

@Component({
selector: 'app-login',
Expand Down Expand Up @@ -40,7 +39,7 @@ import {AppModule} from "../../app.module";
]
})
export class LoginComponent implements OnInit {
formGroup!: FormGroup
protected formGroup!: FormGroup
private formBuilder = inject(FormBuilder)
private authService = inject(AuthService)
private notificationService = inject(FrontendNotificationService)
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/auth/register/register.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import {RegistrationForm} from "../model/RegistrationForm";
]
})
export class RegisterComponent implements OnInit {
formGroup!: FormGroup
protected formGroup!: FormGroup
private formBuilder = inject(FormBuilder)
private authService = inject(AuthService)
private notificationService = inject(FrontendNotificationService)
Expand Down
11 changes: 6 additions & 5 deletions frontend/src/app/shared/navigation/navigation.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ import {filter, Subscription} from "rxjs";
styleUrl: './navigation.component.css'
})
export class NavigationComponent implements OnInit, OnDestroy {
currentUrl: string = ''
isUserSignedIn: WritableSignal<boolean> = signal(false)
private readonly onChangeSubs: Subscription[] = []
protected isUserSignedIn: WritableSignal<boolean> = signal(false)
private readonly subscriptions: Subscription[] = []
private currentUrl: string = ''


private router = inject(Router)
private authService = inject(AuthService)
Expand All @@ -53,11 +54,11 @@ export class NavigationComponent implements OnInit, OnDestroy {
this.currentUrl = (event as NavigationEnd).url
this.changeDetectorRef.detectChanges()
});
this.onChangeSubs.push(routerSubscription)
this.subscriptions.push(routerSubscription)
}

ngOnDestroy(): void {
this.onChangeSubs.forEach((subscription) => subscription.unsubscribe())
this.subscriptions.forEach((subscription) => subscription.unsubscribe())
}

isSelected(navigationUrl: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ form {
}

.mat-mdc-card {
background: #2c3338;
background: white;
}

.data-content {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
<mat-card>
<mat-form-field>
<mat-icon matPrefix>cloud</mat-icon>
<input [formControl]="cityForm" matInput placeholder="Vyberte počasí" type="text">
<input [formControl]="cityFormControl" matInput placeholder="Vyberte počasí" type="text">
</mat-form-field>

<button (click)="getCurrentWeather()" color="primary" mat-raised-button>Hledat</button>
<button (click)="getWeather()" color="primary" mat-raised-button>Hledat</button>
</mat-card>
</div>
</div>
Expand All @@ -31,11 +31,7 @@
<mat-card class="col">
<mat-card-title>Forecast Weather</mat-card-title>
<mat-card-content>
<div *ngIf="currentSignal()">
<p>Čas: {{ currentSignal().time }}</p>
<p>Teplota: {{ currentSignal().temperature }}°C</p>
<p>Oblačnost: {{ currentSignal().cloudCover }}</p>
</div>
<app-weather-graph></app-weather-graph>
</mat-card-content>
</mat-card>
</div>
Expand Down
45 changes: 30 additions & 15 deletions frontend/src/app/weather/weather-detail/weather-detail.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import {ChangeDetectionStrategy, Component, inject, OnInit, signal, WritableSignal} from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
inject,
OnDestroy,
OnInit,
signal,
ViewChild,
WritableSignal
} from '@angular/core';
import {MatFormField, MatPrefix} from "@angular/material/form-field";
import {MatInput} from "@angular/material/input";
import {MatButton} from "@angular/material/button";
Expand All @@ -9,8 +18,9 @@ import {NgIf} from "@angular/common";
import {FormControl, ReactiveFormsModule} from "@angular/forms";
import {WeatherService} from "../service/weather.service";
import {CurrentWeatherDetail} from "../model/CurrentWeatherDetail";
import {ForecastWeatherDetail} from "../model/ForecastWeatherDetal";
import {FrontendNotificationService} from "../../shared/frontend-notification/service/frontend-notification.service";
import {WeatherGraphComponent} from "../weather-graph/weather-graph.component";
import {Subscription} from "rxjs";

@Component({
selector: 'app-weather-detail',
Expand All @@ -27,41 +37,46 @@ import {FrontendNotificationService} from "../../shared/frontend-notification/se
ReactiveFormsModule,
MatPrefix,
MatCardContent,
MatCardTitle
MatCardTitle,
WeatherGraphComponent
],
providers: [WeatherService],
templateUrl: './weather-detail.component.html',
styleUrl: './weather-detail.component.css'
})
export class WeatherDetailComponent implements OnInit {
public cityForm = new FormControl();
public currentSignal: WritableSignal<CurrentWeatherDetail> = signal(CurrentWeatherDetail.createDefault())
public forecastSignal: WritableSignal<ForecastWeatherDetail> = signal(ForecastWeatherDetail.createDefault())
export class WeatherDetailComponent implements OnInit, OnDestroy {
@ViewChild(WeatherGraphComponent) weatherGraphComponent!: WeatherGraphComponent;

protected cityFormControl = new FormControl();
protected currentSignal: WritableSignal<CurrentWeatherDetail> = signal(CurrentWeatherDetail.createDefault())
private weatherService = inject(WeatherService);
private notificationService = inject(FrontendNotificationService);
private subscriptions: Subscription[] = [];

ngOnInit(): void {
}

getCurrentWeather() {
this.weatherService.getCurrentWeather(this.cityForm.value).subscribe({
ngOnDestroy(): void {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
}

getWeather() {
this.subscriptions.push(this.weatherService.getCurrentWeather(this.cityFormControl.value).subscribe({
next: (response) => {
this.currentSignal.set(response)
},
error: (error) => {
this.notificationService.errorNotification('Město nenalezeno')
}
})
}
}))

getForecastWeather() {
this.weatherService.getForecastWeather(this.cityForm.value).subscribe({
this.subscriptions.push(this.weatherService.getForecastWeather(this.cityFormControl.value).subscribe({
next: (response) => {
this.forecastSignal.set(response)
this.weatherGraphComponent.createChart(response)
},
error: (error) => {
this.notificationService.errorNotification('Město nenalezeno')
}
})
}))
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="chart-container">
<canvas id="MyChart">{{ chart }}</canvas>
</div>
62 changes: 62 additions & 0 deletions frontend/src/app/weather/weather-graph/weather-graph.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {ForecastWeatherDetail} from "../model/ForecastWeatherDetal";
import {Chart, registerables} from 'chart.js';
import moment from "moment";

@Component({
selector: 'app-weather-graph',
standalone: true,
imports: [],
templateUrl: './weather-graph.component.html',
styleUrl: './weather-graph.component.css'
})
export class WeatherGraphComponent implements OnInit, OnDestroy {
protected chart: any;

ngOnInit() {
Chart.register(...registerables);
this.createChart(ForecastWeatherDetail.createDefault());
}

ngOnDestroy(): void {
}

createChart(data: ForecastWeatherDetail) {
if (this.chart != undefined) {
this.chart.destroy();
}
this.chart = new Chart("MyChart", {
type: "line", //this denotes tha type of chart

data: {// values on X-Axis
labels: data.time.map(time => moment(time).format("DD/MM")),
datasets: [
{
label: "Min Temp",
data: data.minTemperature,
backgroundColor: 'blue'
},
{
label: "Max Temp",
data: data.maxTemperature,
backgroundColor: 'red'
},
{
label: "Max wind",
data: data.maxWindSpeed,
backgroundColor: 'grey'
}
]
},
options: {
scales: {
y: {
beginAtZero: true
}
},
responsive: true,
aspectRatio: 1
}
});
}
}
5 changes: 2 additions & 3 deletions frontend/src/test/app.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import {TestBed} from '@angular/core/testing';
import {AppComponent} from "../app/app.component";
import {HttpClientModule} from "@angular/common/http";
import {RouterTestingModule} from "@angular/router/testing";
import {HttpClientTestingModule} from "@angular/common/http/testing";

describe('AppComponent', () => {
beforeEach(() => TestBed.configureTestingModule({
declarations: [AppComponent],
imports: [RouterTestingModule, HttpClientModule],
imports: [HttpClientTestingModule],
}));

it('should create the app', () => {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/test/auth/login.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('LoginComponent', () => {
describe('login', () => {
it('should login', () => {
const validFormValue = {email: "[email protected]", password: "password"} as LoginForm
component.formGroup = formBuilder.group(validFormValue)
component['formGroup'] = formBuilder.group(validFormValue)
fixture.detectChanges()

authService.login = jest.fn().mockReturnValue(of({}));
Expand All @@ -62,7 +62,7 @@ describe('LoginComponent', () => {

it('invalid password', () => {
const validFormValue = {email: "[email protected]", password: "password"} as LoginForm
component.formGroup = formBuilder.group(validFormValue)
component['formGroup'] = formBuilder.group(validFormValue)
fixture.detectChanges()

const notificationSpy = jest.spyOn(notificationService, 'errorNotification');
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/test/auth/register.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe('RegisterComponent', () => {
password: "password",
passwordConfirmation: "password"
} as RegistrationForm
component.formGroup = formBuilder.group(validFormValue)
component['formGroup'] = formBuilder.group(validFormValue)
fixture.detectChanges()

authService.register = jest.fn().mockReturnValue(of({}));
Expand All @@ -68,7 +68,7 @@ describe('RegisterComponent', () => {

it('should throw error', () => {
const validFormValue = {email: "[email protected]", password: "password"} as LoginForm
component.formGroup = formBuilder.group(validFormValue)
component['formGroup'] = formBuilder.group(validFormValue)
fixture.detectChanges()

const notificationSpy = jest.spyOn(notificationService, 'errorNotification');
Expand Down
Loading

0 comments on commit f85577e

Please sign in to comment.