From 0fcd22d989a57929f7638c9b88a687de6e0b02c9 Mon Sep 17 00:00:00 2001
From: Max <133934232+Kleostro@users.noreply.github.com>
Date: Sat, 17 Aug 2024 18:26:12 +0300
Subject: [PATCH 1/5] feat: implement create station form
---
.../create-station-form.component.html | 68 +++++++++++
.../create-station-form.component.scss | 27 +++++
.../create-station-form.component.ts | 108 ++++++++++++++++++
src/app/shared/constants/message-status.ts | 9 ++
4 files changed, 212 insertions(+)
create mode 100644 src/app/admin/components/create-station-form/create-station-form.component.html
create mode 100644 src/app/admin/components/create-station-form/create-station-form.component.scss
create mode 100644 src/app/admin/components/create-station-form/create-station-form.component.ts
create mode 100644 src/app/shared/constants/message-status.ts
diff --git a/src/app/admin/components/create-station-form/create-station-form.component.html b/src/app/admin/components/create-station-form/create-station-form.component.html
new file mode 100644
index 0000000..0251781
--- /dev/null
+++ b/src/app/admin/components/create-station-form/create-station-form.component.html
@@ -0,0 +1,68 @@
+
diff --git a/src/app/admin/components/create-station-form/create-station-form.component.scss b/src/app/admin/components/create-station-form/create-station-form.component.scss
new file mode 100644
index 0000000..d15a6de
--- /dev/null
+++ b/src/app/admin/components/create-station-form/create-station-form.component.scss
@@ -0,0 +1,27 @@
+.form {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ margin-top: 4.813rem;
+}
+
+.controls {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.control {
+ width: 100%;
+
+ &-label {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+}
+
+.submit {
+ gap: 0.5rem;
+ justify-content: center;
+}
diff --git a/src/app/admin/components/create-station-form/create-station-form.component.ts b/src/app/admin/components/create-station-form/create-station-form.component.ts
new file mode 100644
index 0000000..a6d5069
--- /dev/null
+++ b/src/app/admin/components/create-station-form/create-station-form.component.ts
@@ -0,0 +1,108 @@
+import { NgIf } from '@angular/common';
+import { ChangeDetectionStrategy, Component, inject, OnDestroy, OnInit, signal } from '@angular/core';
+import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
+
+import { MessageService } from 'primeng/api';
+import { ButtonModule } from 'primeng/button';
+import { FloatLabelModule } from 'primeng/floatlabel';
+import { InputNumberModule } from 'primeng/inputnumber';
+import { RippleModule } from 'primeng/ripple';
+import { ToastModule } from 'primeng/toast';
+import { map, Observable, of, Subscription, switchMap } from 'rxjs';
+
+import { StationsService } from '@/app/api/stationsService/stations.service';
+import MESSAGE_STATUS from '@/app/shared/constants/message-status';
+
+import { MapService } from '../../services/map/map.service';
+
+@Component({
+ selector: 'app-create-station-form',
+ standalone: true,
+ imports: [FloatLabelModule, InputNumberModule, ReactiveFormsModule, RippleModule, ButtonModule, NgIf, ToastModule],
+ providers: [MessageService],
+ templateUrl: './create-station-form.component.html',
+ styleUrl: './create-station-form.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class CreateStationFormComponent implements OnInit, OnDestroy {
+ private fb = inject(FormBuilder);
+ private mapService = inject(MapService);
+ private stationsService = inject(StationsService);
+ private messageService = inject(MessageService);
+ private subscription = new Subscription();
+
+ public isStationCreated = signal(false);
+
+ private createStation(city: string, latitude: number, longitude: number): Observable<{ id: number }> {
+ return this.stationsService.createNewStation({
+ city,
+ latitude,
+ longitude,
+ relations: [],
+ });
+ }
+
+ private createMarker(city: string, latitude: number, longitude: number): void {
+ this.mapService.createNewMarker({
+ city,
+ lat: latitude,
+ lng: longitude,
+ });
+ }
+
+ public createStationForm = this.fb.nonNullable.group({
+ city: ['', [Validators.required.bind(this)]],
+ latitude: [0, [Validators.required.bind(this)]],
+ longitude: [0, [Validators.required.bind(this)]],
+ });
+
+ public submitForm(): void {
+ this.createStationForm.markAllAsTouched();
+ this.createStationForm.updateValueAndValidity();
+
+ if (this.createStationForm.valid) {
+ this.isStationCreated.set(true);
+ const { city, latitude, longitude } = this.createStationForm.getRawValue();
+ this.subscription.add(
+ this.stationsService
+ .isStationInCity(city)
+ .pipe(
+ switchMap((exists) =>
+ exists
+ ? of(null)
+ : this.createStation(city, latitude, longitude).pipe(
+ map((id) => {
+ this.isStationCreated.set(false);
+ this.createStationForm.reset();
+ this.messageService.add({
+ severity: MESSAGE_STATUS.SUCCESS,
+ summary: 'Success!',
+ detail: `Station created with id: ${id.id}`,
+ });
+ }),
+ ),
+ ),
+ map((exists) => (exists ? of(null) : this.createMarker(city, latitude, longitude))),
+ )
+ .subscribe({
+ error: (error: Error) => {
+ this.isStationCreated.set(false);
+ this.messageService.add({ severity: MESSAGE_STATUS.ERROR, summary: error.name, detail: error.message });
+ },
+ }),
+ );
+ }
+ }
+
+ public ngOnInit(): void {
+ this.subscription.add(
+ this.mapService.getLngLat().subscribe((lngLat) => {
+ this.createStationForm.patchValue({ longitude: lngLat.lng, latitude: lngLat.lat });
+ }),
+ );
+ }
+
+ public ngOnDestroy(): void {
+ this.subscription.unsubscribe();
+ }
+}
diff --git a/src/app/shared/constants/message-status.ts b/src/app/shared/constants/message-status.ts
new file mode 100644
index 0000000..29ffc06
--- /dev/null
+++ b/src/app/shared/constants/message-status.ts
@@ -0,0 +1,9 @@
+const MESSAGE_STATUS = {
+ SUCCESS: 'success',
+ ERROR: 'error',
+ INFO: 'info',
+ WARNING: 'warning',
+ DEFAULT: 'default',
+} as const;
+
+export default MESSAGE_STATUS;
From f35d9520c458cc95456131c59f30658da53680d5 Mon Sep 17 00:00:00 2001
From: Max <133934232+Kleostro@users.noreply.github.com>
Date: Sat, 17 Aug 2024 18:27:12 +0300
Subject: [PATCH 2/5] feat: implement map
---
.../admin/components/map/map.component.html | 5 ++
.../admin/components/map/map.component.scss | 16 ++++
src/app/admin/components/map/map.component.ts | 83 +++++++++++++++++++
src/app/admin/services/.gitkeep | 0
src/app/admin/services/map/map.service.ts | 43 ++++++++++
5 files changed, 147 insertions(+)
create mode 100644 src/app/admin/components/map/map.component.html
create mode 100644 src/app/admin/components/map/map.component.scss
create mode 100644 src/app/admin/components/map/map.component.ts
delete mode 100644 src/app/admin/services/.gitkeep
create mode 100644 src/app/admin/services/map/map.service.ts
diff --git a/src/app/admin/components/map/map.component.html b/src/app/admin/components/map/map.component.html
new file mode 100644
index 0000000..7af8fac
--- /dev/null
+++ b/src/app/admin/components/map/map.component.html
@@ -0,0 +1,5 @@
+
diff --git a/src/app/admin/components/map/map.component.scss b/src/app/admin/components/map/map.component.scss
new file mode 100644
index 0000000..a8820d6
--- /dev/null
+++ b/src/app/admin/components/map/map.component.scss
@@ -0,0 +1,16 @@
+:host {
+ display: flex;
+}
+
+.map-wrap {
+ position: relative;
+ width: 100%;
+ height: calc(100vh - 4.813rem);
+ margin-top: 4.813rem;
+}
+
+.map {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
diff --git a/src/app/admin/components/map/map.component.ts b/src/app/admin/components/map/map.component.ts
new file mode 100644
index 0000000..167f069
--- /dev/null
+++ b/src/app/admin/components/map/map.component.ts
@@ -0,0 +1,83 @@
+import {
+ AfterViewInit,
+ ChangeDetectionStrategy,
+ Component,
+ ElementRef,
+ inject,
+ OnDestroy,
+ OnInit,
+ signal,
+ ViewChild,
+} from '@angular/core';
+
+import { Map, NavigationControl } from 'maplibre-gl';
+import { SkeletonModule } from 'primeng/skeleton';
+import { Subscription } from 'rxjs';
+
+import ENVIRONMENTS from '@/environment/environment';
+
+import { INITIAL_MAP_STATE } from '../../constants/initial-map-state';
+import { MapService } from '../../services/map/map.service';
+
+@Component({
+ selector: 'app-map',
+ standalone: true,
+ imports: [SkeletonModule],
+ templateUrl: './map.component.html',
+ styleUrl: './map.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class MapComponent implements OnInit, AfterViewInit, OnDestroy {
+ private mapService = inject(MapService);
+ private subscription = new Subscription();
+ private map!: Map;
+
+ @ViewChild('map')
+ private mapContainer!: ElementRef;
+
+ public isMapLoaded = signal(false);
+
+ private initMap(): void {
+ this.map = new Map({
+ container: this.mapContainer.nativeElement,
+ style: `https://api.maptiler.com/maps/streets-v2/style.json?key=${ENVIRONMENTS.MAP_KEY}`,
+ center: [INITIAL_MAP_STATE.lng, INITIAL_MAP_STATE.lat],
+ zoom: INITIAL_MAP_STATE.zoom,
+ });
+
+ this.map.addControl(new NavigationControl({}));
+ }
+
+ private initMapClickHandler(): void {
+ this.map.on('click', ({ lngLat }) => {
+ this.mapService.setLngLat({ lng: lngLat.lng, lat: lngLat.lat });
+ });
+
+ this.map.on('load', () => {
+ this.isMapLoaded.set(true);
+ });
+ }
+
+ public ngOnInit(): void {
+ this.subscription.add(
+ this.mapService.getNewMarker().subscribe((marker) => {
+ marker.addTo(this.map);
+ marker.togglePopup();
+ this.map.flyTo({
+ center: [marker.getLngLat().lng, marker.getLngLat().lat],
+ zoom: INITIAL_MAP_STATE.zoom,
+ });
+ }),
+ );
+ }
+
+ public ngAfterViewInit(): void {
+ this.initMap();
+ this.initMapClickHandler();
+ }
+
+ public ngOnDestroy(): void {
+ this.map.remove();
+ this.subscription.unsubscribe();
+ }
+}
diff --git a/src/app/admin/services/.gitkeep b/src/app/admin/services/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/app/admin/services/map/map.service.ts b/src/app/admin/services/map/map.service.ts
new file mode 100644
index 0000000..ea014e2
--- /dev/null
+++ b/src/app/admin/services/map/map.service.ts
@@ -0,0 +1,43 @@
+import { Injectable } from '@angular/core';
+
+import { Marker, Popup } from 'maplibre-gl';
+import { BehaviorSubject, Subject } from 'rxjs';
+
+import makeFirstLetterToUppercase from '@/app/shared/utils/makeFirstLetterToUppercase';
+
+import { MARKER_PARAMS } from '../../constants/initial-map-state';
+import createNewPopupOffsets from '../../utils/createNewPopupOffsets';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class MapService {
+ private lngLat = new BehaviorSubject({ lng: 0, lat: 0 });
+ private newMarker = new Subject();
+
+ public createNewMarker({ city, lng, lat }: { city: string; lng: number; lat: number }): void {
+ this.newMarker.next(
+ new Marker({ color: MARKER_PARAMS.color })
+ .setLngLat([lng, lat])
+ .setPopup(
+ new Popup({ className: 'map-popup' })
+ .setLngLat({ lng, lat })
+ .setText(makeFirstLetterToUppercase(city))
+ .setOffset(createNewPopupOffsets())
+ .setMaxWidth(MARKER_PARAMS.max_width),
+ ),
+ );
+ }
+
+ public getLngLat(): BehaviorSubject<{ lng: number; lat: number }> {
+ return this.lngLat;
+ }
+
+ public setLngLat({ lng, lat }: { lng: number; lat: number }): void {
+ this.lngLat.next({ lng, lat });
+ }
+
+ public getNewMarker(): Subject {
+ return this.newMarker;
+ }
+}
From 92bd4225700f3b8894e689ba0596fab9e66913fa Mon Sep 17 00:00:00 2001
From: Max <133934232+Kleostro@users.noreply.github.com>
Date: Sat, 17 Aug 2024 18:28:01 +0300
Subject: [PATCH 3/5] feat: api key for map
---
src/environment/environment.ts | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 src/environment/environment.ts
diff --git a/src/environment/environment.ts b/src/environment/environment.ts
new file mode 100644
index 0000000..14f31f1
--- /dev/null
+++ b/src/environment/environment.ts
@@ -0,0 +1,5 @@
+const ENVIRONMENTS = {
+ MAP_KEY: '1bdk2M9O2x8FBX6D1NjO',
+} as const;
+
+export default ENVIRONMENTS;
From 2899081faa79884986f3d7c17b014699b442484a Mon Sep 17 00:00:00 2001
From: Max <133934232+Kleostro@users.noreply.github.com>
Date: Sat, 17 Aug 2024 18:28:43 +0300
Subject: [PATCH 4/5] feat: inital map state
---
angular.json | 1 +
package.json | 3 ++
public/styles/common.scss | 8 +++++
.../components/sidebar/sidebar.component.scss | 35 +++++++++----------
src/app/admin/constants/initial-map-state.ts | 8 +++++
.../admin-layout/admin-layout.component.scss | 4 +++
.../pages/stations/stations.component.html | 5 ++-
.../pages/stations/stations.component.scss | 7 ++++
.../pages/stations/stations.component.spec.ts | 22 ------------
.../pages/stations/stations.component.ts | 5 ++-
src/app/admin/utils/createNewPopupOffsets.ts | 23 ++++++++++++
.../api/stationsService/stations.service.ts | 10 +++++-
.../utils/makeFirstLetterToUppercase.ts | 3 ++
tsconfig.json | 2 ++
14 files changed, 93 insertions(+), 43 deletions(-)
create mode 100644 src/app/admin/constants/initial-map-state.ts
delete mode 100644 src/app/admin/pages/stations/stations.component.spec.ts
create mode 100644 src/app/admin/utils/createNewPopupOffsets.ts
create mode 100644 src/app/shared/utils/makeFirstLetterToUppercase.ts
diff --git a/angular.json b/angular.json
index 93dbf3b..dc611de 100644
--- a/angular.json
+++ b/angular.json
@@ -33,6 +33,7 @@
"styles": [
"node_modules/primeng/resources/themes/lara-light-blue/theme.css",
"node_modules/primeng/resources/primeng.min.css",
+ "node_modules/maplibre-gl/dist/maplibre-gl.css",
"src/styles.scss"
],
"stylePreprocessorOptions": {
diff --git a/package.json b/package.json
index b7ad44b..b1e8a88 100644
--- a/package.json
+++ b/package.json
@@ -35,11 +35,14 @@
"@ngrx/store": "^18.0.2",
"@ngrx/store-devtools": "^18.0.1",
"@planess/train-a-backend": "^0.0.3",
+ "@types/geojson": "^7946.0.14",
"@types/jest": "^29.5.12",
+ "@types/maplibre-gl": "^1.14.0",
"eslint-plugin-unused-imports": "^4.1.3",
"express": "^4.18.2",
"jest": "^29.7.0",
"jest-preset-angular": "^14.2.2",
+ "maplibre-gl": "^4.5.2",
"modern-normalize": "^3.0.0",
"primeicons": "^7.0.0",
"primeng": "^17.18.9",
diff --git a/public/styles/common.scss b/public/styles/common.scss
index cea2d00..6565ad2 100644
--- a/public/styles/common.scss
+++ b/public/styles/common.scss
@@ -23,6 +23,14 @@ body {
body {
margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans',
+ 'Droid Sans', 'Helvetica Neue', sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}
.hidden {
diff --git a/src/app/admin/components/sidebar/sidebar.component.scss b/src/app/admin/components/sidebar/sidebar.component.scss
index 71acb3d..9c2f644 100644
--- a/src/app/admin/components/sidebar/sidebar.component.scss
+++ b/src/app/admin/components/sidebar/sidebar.component.scss
@@ -5,12 +5,28 @@
height: 100%;
background-color: $gray-200;
border-right: $one solid $gray-100;
+
+ ::ng-deep .p-element {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ width: $offset-ms;
+ height: $offset-ms;
+ padding: 0;
+
+ font-size: $font-size-xs;
+
+ &.link-back {
+ margin: $offset-xxs;
+ margin-right: 0;
+ }
+ }
}
.links {
display: flex;
flex-direction: column;
- height: 100%;
}
.link {
@@ -38,20 +54,3 @@
background-color: $gray-100;
}
}
-
-::ng-deep .p-element {
- display: flex;
- align-items: center;
- justify-content: center;
-
- width: $offset-ms;
- height: $offset-ms;
- padding: 0;
-
- font-size: $font-size-xs;
-
- &.link-back {
- margin: $offset-xxs;
- margin-right: 0;
- }
-}
diff --git a/src/app/admin/constants/initial-map-state.ts b/src/app/admin/constants/initial-map-state.ts
new file mode 100644
index 0000000..52fe797
--- /dev/null
+++ b/src/app/admin/constants/initial-map-state.ts
@@ -0,0 +1,8 @@
+export const INITIAL_MAP_STATE = { lng: 2.349014, lat: 48.864716, zoom: 10 };
+export const MARKER_PARAMS = {
+ height: 40,
+ radius: 40,
+ offset: 20,
+ max_width: '5rem',
+ color: '#3B82F6',
+};
diff --git a/src/app/admin/layout/admin-layout/admin-layout.component.scss b/src/app/admin/layout/admin-layout/admin-layout.component.scss
index 82c0881..6d11024 100644
--- a/src/app/admin/layout/admin-layout/admin-layout.component.scss
+++ b/src/app/admin/layout/admin-layout/admin-layout.component.scss
@@ -5,3 +5,7 @@
grid-template-columns: calc($offset-xxxl * 2.6) 1fr;
height: 100vh;
}
+
+.content {
+ padding: 0 $offset-s;
+}
diff --git a/src/app/admin/pages/stations/stations.component.html b/src/app/admin/pages/stations/stations.component.html
index 4fded1c..303cf8b 100644
--- a/src/app/admin/pages/stations/stations.component.html
+++ b/src/app/admin/pages/stations/stations.component.html
@@ -1 +1,4 @@
-stations works!
+
diff --git a/src/app/admin/pages/stations/stations.component.scss b/src/app/admin/pages/stations/stations.component.scss
index e69de29..19857da 100644
--- a/src/app/admin/pages/stations/stations.component.scss
+++ b/src/app/admin/pages/stations/stations.component.scss
@@ -0,0 +1,7 @@
+@import 'variables';
+
+.wrapper {
+ display: grid;
+ grid-template-columns: 1fr 25rem;
+ gap: $offset-s;
+}
diff --git a/src/app/admin/pages/stations/stations.component.spec.ts b/src/app/admin/pages/stations/stations.component.spec.ts
deleted file mode 100644
index c4c2ab4..0000000
--- a/src/app/admin/pages/stations/stations.component.spec.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { StationsComponent } from './stations.component';
-
-describe('StationsComponent', () => {
- let component: StationsComponent;
- let fixture: ComponentFixture;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- imports: [StationsComponent],
- }).compileComponents();
-
- fixture = TestBed.createComponent(StationsComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/src/app/admin/pages/stations/stations.component.ts b/src/app/admin/pages/stations/stations.component.ts
index dbfbcbe..1fe9baa 100644
--- a/src/app/admin/pages/stations/stations.component.ts
+++ b/src/app/admin/pages/stations/stations.component.ts
@@ -1,9 +1,12 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { CreateStationFormComponent } from '../../components/create-station-form/create-station-form.component';
+import { MapComponent } from '../../components/map/map.component';
+
@Component({
selector: 'app-stations',
standalone: true,
- imports: [],
+ imports: [MapComponent, CreateStationFormComponent],
templateUrl: './stations.component.html',
styleUrl: './stations.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
diff --git a/src/app/admin/utils/createNewPopupOffsets.ts b/src/app/admin/utils/createNewPopupOffsets.ts
new file mode 100644
index 0000000..6788d66
--- /dev/null
+++ b/src/app/admin/utils/createNewPopupOffsets.ts
@@ -0,0 +1,23 @@
+import { Offset, Point } from 'maplibre-gl';
+
+import { MARKER_PARAMS } from '../constants/initial-map-state';
+
+const createNewPopupOffsets = (): Offset => ({
+ top: new Point(0, 0),
+ left: new Point(MARKER_PARAMS.radius, (MARKER_PARAMS.height - MARKER_PARAMS.radius) * -1),
+ right: new Point(-MARKER_PARAMS.radius, (MARKER_PARAMS.height - MARKER_PARAMS.radius) * -1),
+ bottom: new Point(0, -MARKER_PARAMS.height),
+ center: new Point(0, MARKER_PARAMS.height),
+ 'top-left': new Point(0, 0),
+ 'top-right': new Point(0, 0),
+ 'bottom-left': new Point(
+ MARKER_PARAMS.offset,
+ (MARKER_PARAMS.height - MARKER_PARAMS.radius + MARKER_PARAMS.offset) * -1,
+ ),
+ 'bottom-right': new Point(
+ -MARKER_PARAMS.offset,
+ (MARKER_PARAMS.height - MARKER_PARAMS.radius + MARKER_PARAMS.offset) * -1,
+ ),
+});
+
+export default createNewPopupOffsets;
diff --git a/src/app/api/stationsService/stations.service.ts b/src/app/api/stationsService/stations.service.ts
index 6ed2c49..3f8ec43 100644
--- a/src/app/api/stationsService/stations.service.ts
+++ b/src/app/api/stationsService/stations.service.ts
@@ -1,7 +1,7 @@
import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
-import { Observable } from 'rxjs';
+import { map, Observable } from 'rxjs';
import { NewStation, Station } from '../models/stations';
@@ -23,4 +23,12 @@ export class StationsService {
public deleteStation(id: number): Observable {
return this.httpClient.delete(`${this.STATION_ENDPOINT}/${id}`);
}
+
+ public isStationInCity(station: string): Observable {
+ return this.getStations().pipe(
+ map((stations) =>
+ stations.some((stationFromList) => stationFromList.city.toLowerCase() === station.toLowerCase()),
+ ),
+ );
+ }
}
diff --git a/src/app/shared/utils/makeFirstLetterToUppercase.ts b/src/app/shared/utils/makeFirstLetterToUppercase.ts
new file mode 100644
index 0000000..55d500e
--- /dev/null
+++ b/src/app/shared/utils/makeFirstLetterToUppercase.ts
@@ -0,0 +1,3 @@
+const makeFirstLetterToUppercase = (text: string): string => text.charAt(0).toUpperCase() + text.slice(1);
+
+export default makeFirstLetterToUppercase;
diff --git a/tsconfig.json b/tsconfig.json
index 41de90c..da35bd4 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,6 +4,8 @@
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
+ "forceConsistentCasingInFileNames": true,
+ "downlevelIteration": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
From b4105443332ba085b2649d908027911d4128d942 Mon Sep 17 00:00:00 2001
From: Max <133934232+Kleostro@users.noreply.github.com>
Date: Sat, 17 Aug 2024 18:40:12 +0300
Subject: [PATCH 5/5] refactor: replace ngIf with if
---
.../create-station-form.component.html | 30 +++++++++++++------
.../create-station-form.component.ts | 3 +-
2 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/src/app/admin/components/create-station-form/create-station-form.component.html b/src/app/admin/components/create-station-form/create-station-form.component.html
index 0251781..2aeaccf 100644
--- a/src/app/admin/components/create-station-form/create-station-form.component.html
+++ b/src/app/admin/components/create-station-form/create-station-form.component.html
@@ -13,9 +13,13 @@ Create Station
autocomplete="off"
/>
@if (createStationForm.controls.city; as city) {
-
- Please enter a city!
-
+ @if (city.invalid && city.dirty) {
+
+ @if (city.hasError('required')) {
+ Please enter a city!
+ }
+
+ }
}
@@ -30,9 +34,13 @@ Create Station
class="p-inputtext control"
/>
@if (createStationForm.controls.latitude; as latitude) {
-
- Please enter a latitude!
-
+ @if (latitude.invalid && latitude.dirty) {
+
+ @if (latitude.hasError('required')) {
+ Please enter a latitude!
+ }
+
+ }
}
@@ -47,9 +55,13 @@ Create Station
class="p-inputtext control"
/>
@if (createStationForm.controls.longitude; as longitude) {
-
- Please enter a longitude!
-
+ @if (longitude.invalid && longitude.dirty) {
+
+ @if (longitude.hasError('required')) {
+ Please enter a longitude!
+ }
+
+ }
}
diff --git a/src/app/admin/components/create-station-form/create-station-form.component.ts b/src/app/admin/components/create-station-form/create-station-form.component.ts
index a6d5069..b75a4ad 100644
--- a/src/app/admin/components/create-station-form/create-station-form.component.ts
+++ b/src/app/admin/components/create-station-form/create-station-form.component.ts
@@ -1,4 +1,3 @@
-import { NgIf } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject, OnDestroy, OnInit, signal } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
@@ -18,7 +17,7 @@ import { MapService } from '../../services/map/map.service';
@Component({
selector: 'app-create-station-form',
standalone: true,
- imports: [FloatLabelModule, InputNumberModule, ReactiveFormsModule, RippleModule, ButtonModule, NgIf, ToastModule],
+ imports: [FloatLabelModule, InputNumberModule, ReactiveFormsModule, RippleModule, ButtonModule, ToastModule],
providers: [MessageService],
templateUrl: './create-station-form.component.html',
styleUrl: './create-station-form.component.scss',