Merge remote-tracking branch 'origin/dev' into dev
# Conflicts: # src/app/component/detail/detail.component.html
This commit is contained in:
1
src/app/component/detail/detail.component.css
Normal file
1
src/app/component/detail/detail.component.css
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
60
src/app/component/detail/detail.component.html
Normal file
60
src/app/component/detail/detail.component.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<div>
|
||||
<div class="flex flex-col md:flex-row gap-0 m-5 h-full">
|
||||
<div class="card w-full h-full bg-base-100 shadow-2xl">
|
||||
<figure><img src="assets/testDetail/igm.png" [alt]="test.name"/></figure>
|
||||
<div class="card-body">
|
||||
<div class="flex justify-between items-center">
|
||||
<h1 class="card-title font-extrabold">{{ test.name }}</h1>
|
||||
<div class="font-extrabold text-end text-blue-500 flex items-center">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="19.9219" height="19.9316" *ngIf="!distance" class="mx-1">
|
||||
<g>
|
||||
<rect height="19.9316" opacity="0" width="19.9219" x="0" y="0"/>
|
||||
<path
|
||||
d="M4.85352 11.0156L9.95117 11.0156C10.332 11.0156 10.6348 10.7227 10.6348 10.332L10.6348 3.75C10.6348 3.36914 10.332 3.07617 9.95117 3.07617C9.57031 3.07617 9.27734 3.36914 9.27734 3.75L9.27734 9.6582L4.85352 9.6582C4.46289 9.6582 4.16992 9.95117 4.16992 10.332C4.16992 10.7227 4.46289 11.0156 4.85352 11.0156ZM9.96094 19.9219C15.4102 19.9219 19.9219 15.4004 19.9219 9.96094C19.9219 4.51172 15.4004 0 9.95117 0C4.51172 0 0 4.51172 0 9.96094C0 15.4004 4.52148 19.9219 9.96094 19.9219ZM9.96094 18.2617C5.35156 18.2617 1.66992 14.5703 1.66992 9.96094C1.66992 5.35156 5.3418 1.66016 9.95117 1.66016C14.5605 1.66016 18.2617 5.35156 18.2617 9.96094C18.2617 14.5703 14.5703 18.2617 9.96094 18.2617Z"
|
||||
fill="currentcolor" fill-opacity="0.85"/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.44 18.4" width="18" height="18" fill="currentColor"
|
||||
class="mx-2" *ngIf="distance">
|
||||
<path
|
||||
d="M1.29,9.83l7.12,0c0.15,0,0.27,0.12,0.27,0.27v6.06c0,1.46,1.76,2.15,2.42,0.81l7.22-15.54c0.66-1.34-0.49-2.52-1.85-2.08L1.08,7.49C-0.14,8.06,0.1,9.82,1.29,9.83z"/>
|
||||
</svg>
|
||||
{{distance === undefined ? '' : distance}} Km
|
||||
</div>
|
||||
</div>
|
||||
<p>{{ test.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md:relative w-full flex items-center justify-center md:justify-start">
|
||||
<iframe *ngIf="distance" class="md:absolute sm:w-full md:h-3/4 md:w-3/4 rounded-b-lg md:rounded-r-lg shadow-2xl border-2 items-center" height="300" frameborder=""
|
||||
style=""
|
||||
referrerpolicy="no-referrer-when-downgrade"
|
||||
[src]='embed | safe' allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Put this part before </body> tag -->
|
||||
<input type="checkbox" id="my-modal-6" class="modal-toggle" #myModal/>
|
||||
|
||||
<div class="modal modal-bottom sm:modal-middle" *ngIf="img">
|
||||
<div class="modal-box">
|
||||
<h3 class="font-bold text-lg">Congratulations you have discovred {{ test.name }}!</h3>
|
||||
<img class="xl:max-w-md max-h-screen py-4 m-auto" [src]="img" *ngIf="img">
|
||||
<div class="modal-action">
|
||||
<label for="my-modal-6" class="btn bg-white hover:bg-blue-400" (click)="downloadImage()">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="17.334" height="23.4863">
|
||||
<g>
|
||||
<rect height="23.4863" opacity="0" width="17.334" x="0" y="0"/>
|
||||
<path
|
||||
d="M3.06641 22.041L14.2676 22.041C16.3086 22.041 17.334 21.0254 17.334 19.0137L17.334 9.26758C17.334 7.25586 16.3086 6.24023 14.2676 6.24023L11.543 6.24023L11.543 7.8125L14.2383 7.8125C15.2051 7.8125 15.7617 8.33984 15.7617 9.35547L15.7617 18.9258C15.7617 19.9414 15.2051 20.4688 14.2383 20.4688L3.08594 20.4688C2.10938 20.4688 1.57227 19.9414 1.57227 18.9258L1.57227 9.35547C1.57227 8.33984 2.10938 7.8125 3.08594 7.8125L5.79102 7.8125L5.79102 6.24023L3.06641 6.24023C1.02539 6.24023 0 7.25586 0 9.26758L0 19.0137C0 21.0254 1.02539 22.041 3.06641 22.041ZM8.66211 14.3945C9.08203 14.3945 9.44336 14.043 9.44336 13.6328L9.44336 3.60352L9.38477 2.13867L10.0391 2.83203L11.5234 4.41406C11.6602 4.57031 11.8555 4.64844 12.0508 4.64844C12.4512 4.64844 12.7637 4.35547 12.7637 3.95508C12.7637 3.75 12.6758 3.59375 12.5293 3.44727L9.22852 0.263672C9.0332 0.0683594 8.86719 0 8.66211 0C8.4668 0 8.30078 0.0683594 8.0957 0.263672L4.79492 3.44727C4.64844 3.59375 4.57031 3.75 4.57031 3.95508C4.57031 4.35547 4.86328 4.64844 5.27344 4.64844C5.45898 4.64844 5.67383 4.57031 5.81055 4.41406L7.28516 2.83203L7.94922 2.13867L7.89062 3.60352L7.89062 13.6328C7.89062 14.043 8.24219 14.3945 8.66211 14.3945Z"
|
||||
fill="#000000"/>
|
||||
</g>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
195
src/app/component/detail/detail.component.ts
Executable file
195
src/app/component/detail/detail.component.ts
Executable file
@@ -0,0 +1,195 @@
|
||||
import {Component, OnInit, ViewChild, ElementRef} from '@angular/core';
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
import {positionService} from "../../service/position.service";
|
||||
import * as qrcode from 'qrcode';
|
||||
|
||||
@Component({
|
||||
selector: 'app-detail',
|
||||
templateUrl: './detail.component.html',
|
||||
styleUrls: ['./detail.component.css']
|
||||
})
|
||||
export class DetailComponent implements OnInit {
|
||||
@ViewChild('myModal', { static: true }) myModal!: ElementRef<HTMLInputElement>;
|
||||
private location: string | undefined;
|
||||
private id: number | undefined;
|
||||
|
||||
private URLParams: any;
|
||||
|
||||
test = {
|
||||
name: 'SPAI',
|
||||
cordinates: '46.2295425892837, 8.74425883677592',
|
||||
lat: 46.2295425892837,
|
||||
lng: 8.74425883677592,
|
||||
description: "Lorem ipsum"
|
||||
}
|
||||
|
||||
embed: any;
|
||||
|
||||
cord: any;
|
||||
|
||||
showNav = true;
|
||||
distance: number | undefined;
|
||||
displayedDistance = 0;
|
||||
|
||||
img: any;
|
||||
|
||||
constructor(private route: ActivatedRoute , private positionService: positionService) {}
|
||||
|
||||
async ngOnInit(){
|
||||
this.URLParams = this.route.params
|
||||
|
||||
console.log(this.URLParams.location); // {location: "lugano", id: "1"}
|
||||
|
||||
//this.URLParams = this.route.snapshot.url.slice(-2).map(segment => segment.path);
|
||||
console.log("getting your location: wait...");
|
||||
this.cord = await this.positionService.getLocation();
|
||||
console.log("location: ", this.cord);
|
||||
this.checkDistanceTimer();
|
||||
}
|
||||
|
||||
async checkDistanceTimer() {
|
||||
//set interval
|
||||
let intervalID = setInterval(() => {
|
||||
this.cord = this.positionService.getLocationWithoutPromise();
|
||||
this.embed = `https://www.google.com/maps/embed/v1/directions?key=AIzaSyBJL4FWmG032BG6KXxTb4faxpO_ccyaP3o&origin=${this.cord.lat},${this.cord.lon}&destination=${this.test.lat},${this.test.lng}`;
|
||||
if (this.showNav) {
|
||||
this.myModal.nativeElement.checked = false;
|
||||
if (this.cord?.lat && this.cord?.lon) {
|
||||
this.distance = this.positionService.getDistanceBetweenCoordinates(this.cord?.lat, this.cord?.lon, this.test.lat, this.test.lng);
|
||||
if (this.distance < 0.05) {
|
||||
//this.showNav = false;
|
||||
this.generateQR()
|
||||
// implement this nex line in angular ts
|
||||
this.myModal.nativeElement.checked = true;
|
||||
}
|
||||
} else {
|
||||
this.distance = undefined;
|
||||
}
|
||||
|
||||
} else {
|
||||
clearInterval(intervalID);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
async generateQRCode(url: string) {
|
||||
try {
|
||||
const string = await qrcode.toString(url, { errorCorrectionLevel: 'H', margin: 1, color: { dark: '#000000FF', light: '#FFFFFFFF' } });
|
||||
return string;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw new Error('Error generating QR code');
|
||||
}
|
||||
}
|
||||
|
||||
addSvgToImage(imageUrl: string, svgString: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = new Image();
|
||||
image.src = imageUrl;
|
||||
|
||||
const svgBlob = new Blob([svgString], { type: 'image/svg+xml' });
|
||||
const svgUrl = URL.createObjectURL(svgBlob);
|
||||
|
||||
image.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (ctx) {
|
||||
ctx.drawImage(image, 0, 0);
|
||||
const svgImage = new Image();
|
||||
svgImage.src = svgUrl;
|
||||
|
||||
svgImage.onload = () => {
|
||||
if (ctx && svgImage) {
|
||||
const x = image.width - (image.width * 0.2 + 5);
|
||||
const y = image.height - (image.width * 0.2 + 5);
|
||||
ctx.drawImage(svgImage, x, y, image.width * 0.2, image.width * 0.2);
|
||||
const outputImageUrl = canvas.toDataURL('image/png');
|
||||
resolve(outputImageUrl);
|
||||
} else {
|
||||
reject('Error loading SVG');
|
||||
}
|
||||
};
|
||||
|
||||
svgImage.onerror = () => {
|
||||
reject('Error loading SVG');
|
||||
};
|
||||
} else {
|
||||
reject('Error creating canvas context');
|
||||
}
|
||||
};
|
||||
|
||||
image.onerror = () => {
|
||||
reject('Error loading image');
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
async generateQR() {
|
||||
console.log("generating QR code");
|
||||
console.log(this.URLParams.value);
|
||||
let url = `http://localhost:4200/location/${this.URLParams.value.location}/${this.URLParams.value.id}`;
|
||||
|
||||
let qrCode = await this.generateQRCode(url);
|
||||
|
||||
console.log(qrCode);
|
||||
|
||||
const imageUrl = 'assets/testDetail/img.jpg';
|
||||
|
||||
this.addSvgToImage(imageUrl, qrCode).then((outputImageUrl) => {
|
||||
this.img = outputImageUrl // Output the URL of the output image
|
||||
console.log(outputImageUrl);
|
||||
}).catch((error) => {
|
||||
console.error(error); // Handle any errors that occur
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public downloadImage(): void {
|
||||
const link = document.createElement('a');
|
||||
link.download = this.test.name;
|
||||
link.href = this.img;
|
||||
link.click();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*async addQRCodeToImage(url: string, imagePath: string, outputPath: string): Promise<void> {
|
||||
// Generate QR code
|
||||
const qrCode = await qrcode.toBuffer(url);
|
||||
|
||||
// Load input image using Sharp
|
||||
const image = sharp(imagePath);
|
||||
|
||||
// Get input image dimensions
|
||||
const { width, height } = await image.metadata();
|
||||
|
||||
// Resize QR code to 25% of input image height
|
||||
const qrCodeHeight = Math.round(height * 0.25);
|
||||
const qrCodeBuffer = await sharp(qrCode)
|
||||
.resize(qrCodeHeight, qrCodeHeight)
|
||||
.toBuffer();
|
||||
|
||||
// Composite QR code onto input image at bottom-right corner
|
||||
await image.composite([
|
||||
{
|
||||
input: qrCodeBuffer,
|
||||
gravity: 'southeast',
|
||||
top: height - qrCodeHeight,
|
||||
left: width - qrCodeHeight,
|
||||
},
|
||||
]);
|
||||
|
||||
// Save output image to file
|
||||
await image.toFile(outputPath);
|
||||
}*/
|
||||
|
||||
}
|
||||
39
src/app/component/list/list.component.css
Normal file
39
src/app/component/list/list.component.css
Normal file
@@ -0,0 +1,39 @@
|
||||
h1 {
|
||||
font-size: 75px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 25px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
color: dimgray;
|
||||
}
|
||||
|
||||
.distance {
|
||||
font-size: 20px;
|
||||
border-bottom: 2px solid #E9E92D;
|
||||
width: 35%;
|
||||
padding-bottom: 20px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.row {
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-left: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#translate{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
#translateUl{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
41
src/app/component/list/list.component.html
Normal file
41
src/app/component/list/list.component.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<div class="dropdown dropdown-hover" id="translate">
|
||||
<label tabindex="0" class="btn m-1 bg-black border-neutral text-base-100"
|
||||
id="translateLabel">{{translations.translate}}</label>
|
||||
<ul tabindex="0" class="dropdown-content menu p-2 shadow rounded-box w-52" id="translateUl">
|
||||
<li (click)="switchLanguage('DE')"><a>DE</a></li>
|
||||
<li (click)="switchLanguage('FR')"><a>FR</a></li>
|
||||
<li (click)="switchLanguage('IT')"><a>IT</a></li>
|
||||
<li (click)="switchLanguage('EN')"><a>EN</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div *ngIf="isNear" class="container">
|
||||
<h1>
|
||||
{{translations.locationName}}{{locationParams}}
|
||||
</h1>
|
||||
<div *ngFor="let locations of locations, let i = index" class="row">
|
||||
<h3>
|
||||
<a class="link link-primary" href="location/{{locations.location}}">{{locations.location}}</a>
|
||||
</h3>
|
||||
<div>
|
||||
<h4 *ngIf="locations.distance && !positionNotFound">{{translations.distance}}{{locations.distance}} km</h4>
|
||||
<h4 *ngIf="positionNotFound">{{translations.positionNotFoundErrorMessage}}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!isNear && location && waypoints" class="container">
|
||||
<h1>
|
||||
{{location.location}}
|
||||
</h1>
|
||||
<div *ngFor="let waypoint of waypoints, let i = index" class="row">
|
||||
<h3>
|
||||
<a class="link link-primary" href="location/{{location.location}}/{{waypoint.id}}"> {{waypoint.name}}</a>
|
||||
</h3>
|
||||
<div class="distance">
|
||||
<h4 *ngIf="waypoint.distance && !positionNotFound">{{translations.distance}}{{waypoint.distance}} km</h4>
|
||||
<h4 *ngIf="positionNotFound">{{translations.positionNotFoundErrorMessage}}</h4>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
145
src/app/component/list/list.component.ts
Normal file
145
src/app/component/list/list.component.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
import {Component, OnChanges, OnInit, SimpleChanges} from '@angular/core';
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
import {positionService} from "../../service/position.service";
|
||||
import {listTranslations} from "../../interface/translations";
|
||||
import {TranslateService} from "../../service/language/translate.service";
|
||||
import {ReadTranslateJsonService} from "../../service/language/readTranslateJson.service";
|
||||
import {LocationService} from "../../service/http/location.service";
|
||||
import {LocationEntity} from "../../interface/LocationEntity";
|
||||
import {WaypointsEntity} from "../../interface/WaypointsEntity";
|
||||
import {WaypointService} from "../../service/http/waypoint.service"
|
||||
|
||||
@Component({
|
||||
selector: 'app-list',
|
||||
templateUrl: './list.component.html',
|
||||
styleUrls: ['./list.component.css']
|
||||
})
|
||||
export class ListComponent implements OnInit, OnChanges {
|
||||
locationParams: string | undefined
|
||||
locations: LocationEntity[] | undefined;
|
||||
location: LocationEntity | undefined;
|
||||
|
||||
waypoints: WaypointsEntity[] | undefined;
|
||||
|
||||
positionCord: any;
|
||||
|
||||
isNear: boolean = true;
|
||||
|
||||
|
||||
translations: listTranslations = {} as listTranslations
|
||||
|
||||
positionNotFound: boolean = false;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private positionService: positionService,
|
||||
private translateService: TranslateService,
|
||||
private readTranslationJsonService: ReadTranslateJsonService,
|
||||
private locationService: LocationService,
|
||||
private waypointService: WaypointService,
|
||||
) {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.translations = this.readTranslationJsonService.getListTransaltions();
|
||||
this.route.params.subscribe(params => {
|
||||
this.locationParams = params['location'];
|
||||
});
|
||||
this.locationService.getLocation(this.locationParams ?? "").subscribe(location => {
|
||||
this.location = location;
|
||||
if (this.location.location != null || this.location.location != undefined) {
|
||||
this.isNear = false;
|
||||
this.waypointService.getWaypoints(this.location.location).subscribe(waypoints => {
|
||||
this.waypoints = waypoints;
|
||||
console.log("waypoints", this.waypoints)
|
||||
this.setDistance()
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
this.locationService.getLocations().subscribe(locations => {
|
||||
this.locations = locations;
|
||||
console.log("locations", this.locations)
|
||||
this.setDistance()
|
||||
});
|
||||
|
||||
this.getPosition();
|
||||
this.positionNotFoundFunction();
|
||||
}
|
||||
|
||||
|
||||
positionNotFoundFunction() {
|
||||
if (!this.positionNotFound) {
|
||||
setTimeout(() => {
|
||||
if (!this.positionCord) {
|
||||
this.positionNotFound = true;
|
||||
} else {
|
||||
if (this.waypoints) {
|
||||
if (!this.waypoints[0].distance) {
|
||||
this.positionNotFound = true;
|
||||
} else {
|
||||
this.positionNotFound = false;
|
||||
}
|
||||
}
|
||||
if (this.locations) {
|
||||
if (!this.locations[0].distance) {
|
||||
this.positionNotFound = true;
|
||||
} else {
|
||||
this.positionNotFound = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['positionCord'] && (changes['positionCord'])) {
|
||||
console.log("onChanges")
|
||||
this.setDistance();
|
||||
}
|
||||
}
|
||||
|
||||
getPosition(): any {
|
||||
setInterval(async () => {
|
||||
this.positionCord = await this.positionService.getLocation();
|
||||
this.setDistance();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
async switchLanguage(lang: string) {
|
||||
this.translations.translate = await this.translateService.getData(this.translations.translate, lang);
|
||||
this.translations.distance = await this.translateService.getData(this.translations.distance, lang);
|
||||
this.translations.locationName = await this.translateService.getData(this.translations.locationName, lang);
|
||||
this.translations.positionNotFoundErrorMessage = await this.translateService.getData(this.translations.positionNotFoundErrorMessage, lang);
|
||||
}
|
||||
|
||||
private checkDataPopulated(): void {
|
||||
if (this.locations && this.location) {
|
||||
console.log("Dati popolati correttamente:", this.locations, this.location);
|
||||
for (let i = 0; i < this.locations.length; i++) {
|
||||
if (this.locations[i].location === this.locationParams) {
|
||||
this.location = this.locations[i];
|
||||
console.log("Location trovata:", this.location);
|
||||
this.isNear = false;
|
||||
this.setDistance();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private setDistance(): void {
|
||||
if (this.waypoints) {
|
||||
for (let i = 0; i < this.waypoints.length; i++) {
|
||||
this.waypoints[i].distance = this.positionService.getDistanceBetweenCoordinates(this.waypoints[i].lat, this.waypoints[i].lon, this.positionCord.lat, this.positionCord.lon);
|
||||
}
|
||||
} else {
|
||||
if (this.locations) {
|
||||
for (let i = 0; i < this.locations.length; i++) {
|
||||
this.locations[i].distance = this.positionService.getDistanceBetweenCoordinates(this.locations[i].lat, this.locations[i].lon, this.positionCord.lat, this.positionCord.lon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
141
src/app/component/management/management.component.css
Normal file
141
src/app/component/management/management.component.css
Normal file
@@ -0,0 +1,141 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin:2% 0 1% 10%;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
/* Tabella degli utenti */
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 80%;
|
||||
margin: 0 10% 0 10%;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
/* Form di aggiunta utente */
|
||||
.overlay {
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
background-color: #fefefe;
|
||||
border-radius: 5px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
width: 400px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.form-container h2 {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.form-container div {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.form-container label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-container input {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-container select{
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-container button {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-container button[type="submit"] {
|
||||
background-color: #008CBA;
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.form-container button[type="submit"]:hover {
|
||||
background-color: #0d8bf2;
|
||||
}
|
||||
|
||||
.form-container button[type="submit"]:active {
|
||||
background-color: #0a5a8d;
|
||||
}
|
||||
|
||||
.form-container button[type="submit"]:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.form-container button[type="submit"]:disabled {
|
||||
background-color: #cccccc;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.form-container button[type="submit"]:disabled:hover {
|
||||
background-color: #cccccc;
|
||||
}
|
||||
|
||||
.form-container button:not([type="submit"]) {
|
||||
background-color: #f44336;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.form-container button:not([type="submit"]):hover {
|
||||
background-color: #d30f0f;
|
||||
}
|
||||
|
||||
.form-container button:not([type="submit"]):active {
|
||||
background-color: #8b0c0c;
|
||||
}
|
||||
|
||||
.form-container button:not([type="submit"]):focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button-container{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
184
src/app/component/management/management.component.html
Normal file
184
src/app/component/management/management.component.html
Normal file
@@ -0,0 +1,184 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Management</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Users</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Username</th>
|
||||
<th>Password</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let user of users">
|
||||
<td>{{ user.name }}</td>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.password }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="button-container">
|
||||
<button (click)="openUserForm()"
|
||||
class="btn gap-2 border-primary bg-primary text-secondary hover:bg-secondary hover:text-primary hover:border-primary"
|
||||
style="margin: 10px 10% 0 0;">Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="overlay" [style.display]="showUserForm ? 'block' : 'none'">
|
||||
<div class="form-container">
|
||||
<h2>Add User</h2>
|
||||
<form (submit)="addUser(newUser.name, newUser.username, newUser.password)">
|
||||
<div>
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="name" [(ngModel)]="newUser.name">
|
||||
</div>
|
||||
<div>
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" id="username" name="username" [(ngModel)]="newUser.username">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password" [(ngModel)]="newUser.password">
|
||||
</div>
|
||||
<button type="submit">Add User</button>
|
||||
</form>
|
||||
<button (click)="closeUserForm()">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Locations</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Location</th>
|
||||
<th>Region</th>
|
||||
<th>Latitude</th>
|
||||
<th>Longitude</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let location of locations">
|
||||
<td>{{ location.location }}</td>
|
||||
<td>{{ location.region }}</td>
|
||||
<td>{{ location.lat }}</td>
|
||||
<td>{{ location.lon }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="button-container">
|
||||
<button (click)="openLocationForm()"
|
||||
class="btn gap-2 border-primary bg-primary text-secondary hover:bg-secondary hover:text-primary hover:border-primary"
|
||||
style="margin: 10px 10% 0 0;">Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="overlay" [style.display]="showLocationForm ? 'block' : 'none'">
|
||||
<div class="form-container">
|
||||
<h2>Add Location</h2>
|
||||
<form (submit)="addLocation(newLocation.location, newLocation.region, newLocation.lat ,newLocation.lon)">
|
||||
<div>
|
||||
<label for="location">Location:</label>
|
||||
<input type="text" id="location" name="location" [(ngModel)]="newLocation.location">
|
||||
</div>
|
||||
<div>
|
||||
<label for="region">Region:</label>
|
||||
<input type="text" id="region" name="region" [(ngModel)]="newLocation.region">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="lat">Latitude:</label>
|
||||
<input type="number" id="lat" name="lat" [(ngModel)]="newLocation.lat">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="lon">Longitude:</label>
|
||||
<input type="number" id="lon" name="lon" [(ngModel)]="newLocation.lon">
|
||||
</div>
|
||||
|
||||
|
||||
<button type="submit">Add Location</button>
|
||||
</form>
|
||||
<button (click)="closeLocationForm()">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Waypoints</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Latitude</th>
|
||||
<th>Longitude</th>
|
||||
<th>Description</th>
|
||||
<th>Location Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let waypoint of waypoints">
|
||||
<td>{{ waypoint.name }}</td>
|
||||
<td>{{ waypoint.lat }}</td>
|
||||
<td>{{ waypoint.lon }}</td>
|
||||
<td>{{ waypoint.description }}</td>
|
||||
<td>{{ waypoint.locationName }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="button-container">
|
||||
<button (click)="openWaypointForm()"
|
||||
class="btn gap-2 border-primary bg-primary text-secondary hover:bg-secondary hover:text-primary hover:border-primary"
|
||||
style="margin: 10px 10% 0 0;">Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="overlay" [style.display]="showWaypointForm ? 'block' : 'none'">
|
||||
<div class="form-container">
|
||||
<h2>Add Location</h2>
|
||||
<form
|
||||
(submit)="addWaypoint(newWaypoint.name, newWaypoint.lat, newWaypoint.lon, newWaypoint.description, newWaypoint.image, newWaypoint.locationName)">
|
||||
<div>
|
||||
<label for="waypointName">Waypoint:</label>
|
||||
<input type="text" id="waypointName" name="waypointName" [(ngModel)]="newWaypoint.name">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="waypointLat">Latitude:</label>
|
||||
<input type="number" id="waypointLat" name="waypointLat" [(ngModel)]="newWaypoint.lat">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="waypointLon">Longitude:</label>
|
||||
<input type="number" id="waypointLon" name="waypointLon" [(ngModel)]="newWaypoint.lon">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="description">Description:</label>
|
||||
<input type="text" id="description" name="description" [(ngModel)]="newWaypoint.description">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="image">Image (Base64):</label>
|
||||
<input type="text" id="image" name="image" [(ngModel)]="newWaypoint.img">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="locationName">Location Name:</label>
|
||||
<select [(ngModel)]="newWaypoint.locationName" id="locationName" name="locationName">
|
||||
<option *ngFor="let location of locations" [value]="location.location">{{ location.location }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit">Add Waypoint</button>
|
||||
</form>
|
||||
<button (click)="closeWaypointForm()">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
97
src/app/component/management/management.component.ts
Normal file
97
src/app/component/management/management.component.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {UserEntity} from "../../interface/UserEntity";
|
||||
import {LocationEntity} from "../../interface/LocationEntity";
|
||||
import {WaypointsEntity} from "../../interface/WaypointsEntity";
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
import {LocationService} from "../../service/http/location.service";
|
||||
import {UserService} from "../../service/http/user.service";
|
||||
import {WaypointService} from "../../service/http/waypoint.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './management.component.html',
|
||||
styleUrls: ['./management.component.css']
|
||||
})
|
||||
|
||||
export class ManagementComponent implements OnInit {
|
||||
showUserForm: boolean = false;
|
||||
showLocationForm: boolean = false;
|
||||
showWaypointForm: boolean = false;
|
||||
|
||||
newUser: UserEntity;
|
||||
newLocation: LocationEntity;
|
||||
newWaypoint: WaypointsEntity;
|
||||
|
||||
locations: LocationEntity[] | undefined;
|
||||
waypoints: WaypointsEntity[] | undefined;
|
||||
users: UserEntity[] | undefined;
|
||||
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private locationService: LocationService,
|
||||
private waypointService: WaypointService,
|
||||
private userService: UserService,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.locationService.getLocations().subscribe(locations => {
|
||||
this.locations = locations;
|
||||
});
|
||||
this.waypointService.getAllWaypoints().subscribe(waypoints => {
|
||||
this.waypoints = waypoints;
|
||||
});
|
||||
this.userService.getUsers().subscribe(users => {
|
||||
this.users = users;
|
||||
});
|
||||
}
|
||||
|
||||
addUser(name: string, username: string, password: string) {
|
||||
this.newUser = { name: name, username: username, password: password};
|
||||
this.userService.createUser(this.newUser).subscribe(user => {
|
||||
this.users?.push(user);
|
||||
});
|
||||
this.showUserForm = false;
|
||||
}
|
||||
|
||||
addLocation(name: string, region: string, lat: number, lon: number) {
|
||||
this.newLocation = {name: name, region: region, lat: lat, lon: lon};
|
||||
this.locationService.createLocation(this.newLocation).subscribe(location => {
|
||||
this.locations?.push(location);
|
||||
});
|
||||
this.showLocationForm = false;
|
||||
}
|
||||
|
||||
addWaypoint(name: string, lat: string, lon: string, description: string, image: string, locationName: string) {
|
||||
this.newWaypoint = {name: name, lat: lat, lon: lon, description: description, img: image, locationName: locationName};
|
||||
this.waypointService.createWaypoint(this.newWaypoint).subscribe(waypoint => {
|
||||
this.waypoints?.push(waypoint);
|
||||
});
|
||||
this.showWaypointForm = false;
|
||||
}
|
||||
|
||||
openUserForm() {
|
||||
this.showUserForm = true;
|
||||
}
|
||||
|
||||
closeUserForm() {
|
||||
this.showUserForm = false;
|
||||
}
|
||||
|
||||
openLocationForm() {
|
||||
this.showLocationForm = true;
|
||||
}
|
||||
|
||||
closeLocationForm() {
|
||||
this.showLocationForm = false;
|
||||
}
|
||||
|
||||
openWaypointForm() {
|
||||
this.showWaypointForm = true;
|
||||
}
|
||||
|
||||
closeWaypointForm() {
|
||||
this.showWaypointForm = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user