Add drag & drop functionality and fix suggestions

home
Alexis Feron 5 months ago
parent ec66934ce3
commit 14cf8a7eac

@ -15,7 +15,7 @@
aria-hidden="true" aria-hidden="true"
class="hidden absolute top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full" class="hidden absolute top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"
> >
<div class="relative p-4 w-full max-w-md max-h-full"> <div class="relative p-4 w-full max-w-xl max-h-full">
<!-- Modal content --> <!-- Modal content -->
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700"> <div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
<!-- Modal header --> <!-- Modal header -->
@ -50,7 +50,7 @@
</div> </div>
<!-- Modal body --> <!-- Modal body -->
<div class="p-4 md:p-5"> <div class="p-4 md:p-5">
<form class="space-y-4" [formGroup]="form"> <form class="grid gap-6 mb-1 md:grid-cols-2" [formGroup]="form">
<div> <div>
<label <label
for="title" for="title"
@ -67,54 +67,6 @@
/> />
</div> </div>
<div class="flex items-center justify-center w-full">
<label
for="dropzone-file"
class="flex flex-col items-center justify-center w-full h-36 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-gray-800 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500"
>
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<svg
class="w-8 h-8 mb-4 text-gray-500 dark:text-gray-400"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 20 16"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"
/>
</svg>
<p class="mb-2 text-sm text-gray-500 dark:text-gray-400">
<span class="font-semibold">Click to upload</span> or drag and
drop
</p>
<p class="text-xs text-gray-500 dark:text-gray-400">
PNG, JPG or GIF
</p>
</div>
<input id="dropzone-file" type="file" class="hidden" />
</label>
</div>
<div>
<label
for="description"
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>Description</label
>
<input
type="description"
name="description"
id="description"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
placeholder="Describe your memory"
required
/>
</div>
<div> <div>
<label <label
for="localisation" for="localisation"
@ -127,22 +79,48 @@
formControlName="location" formControlName="location"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
placeholder="Enter location" placeholder="Enter location"
(input)="onLocationInput($event)" (focus)="onFocus()"
(blur)="onBlur()"
/> />
<ul <ul
*ngIf="suggestions.length > 0" *ngIf="suggestions.length > 0 && inputFocused"
class="bg-white border border-gray-300 mt-2 rounded shadow" class="bg-white dark:bg-gray-700 border border-gray-300 mt-2 rounded shadow absolute z-10 mr-5 max-h-60 overflow-auto"
> >
<li <li
*ngFor="let suggestion of suggestions" *ngFor="let suggestion of suggestions"
(click)="selectSuggestion(suggestion)" (click)="selectSuggestion(suggestion)"
class="p-2 hover:bg-gray-100 cursor-pointer" class="p-2 block mb-2 text-sm font-medium text-gray-900 dark:text-white hover:bg-gray-500 cursor-pointer"
> >
{{ suggestion.display_name }} {{ suggestion.display_name }}
</li> </li>
</ul> </ul>
</div> </div>
<div>
<app-drag-drop></app-drag-drop>
</div>
<div>
<label
for="description"
class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>Description</label
>
<textarea
id="description"
rows="4"
class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
placeholder="Describe your memory"
></textarea>
</div>
<div class="flex justify-between">
<button
type="reset"
class="w-full text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-800"
>
Annuler
</button>
</div>
<div class="flex justify-between"> <div class="flex justify-between">
<button <button
type="submit" type="submit"

@ -1,22 +1,31 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Component } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { import {
FormBuilder, FormBuilder,
FormControl, FormControl,
FormGroup, FormGroup,
ReactiveFormsModule, ReactiveFormsModule,
} from '@angular/forms'; } from '@angular/forms';
import { of } from 'rxjs';
import {
catchError,
debounceTime,
distinctUntilChanged,
switchMap,
} from 'rxjs/operators';
import { AutocompleteService } from '../../services/auto-complete.service'; import { AutocompleteService } from '../../services/auto-complete.service';
import { DragDropComponent } from '../drag-drop/drag-drop.component';
@Component({ @Component({
selector: 'app-add-pin-popup', selector: 'app-add-pin-popup',
standalone: true, standalone: true,
imports: [ReactiveFormsModule, CommonModule], imports: [ReactiveFormsModule, CommonModule, DragDropComponent],
templateUrl: './add-pin-popup.component.html', templateUrl: './add-pin-popup.component.html',
}) })
export class AddPinPopupComponent { export class AddPinPopupComponent implements OnInit {
form: FormGroup; form: FormGroup;
suggestions: any[] = []; suggestions: any[] = [];
inputFocused: boolean = false;
constructor( constructor(
private fb: FormBuilder, private fb: FormBuilder,
@ -30,22 +39,39 @@ export class AddPinPopupComponent {
}); });
} }
// Handles location input onFocus(): void {
onLocationInput(event: any): void { this.inputFocused = true; // Activer le focus
const query = event.target.value.trim(); }
if (query.length > 2) {
this.autocompleteService.getAddressSuggestions(query).subscribe({ onBlur(): void {
next: (data) => { setTimeout(() => {
this.suggestions = data; this.inputFocused = false; // Désactiver le focus après un petit délai pour permettre un clic sur la liste
}, }, 200);
error: (err) => { }
console.error('Error fetching suggestions:', err);
this.suggestions = []; ngOnInit(): void {
}, // Use debounce on the location field
this.form
.get('location')
?.valueChanges.pipe(
debounceTime(300), // Wait for 300ms after the last keystroke
distinctUntilChanged(), // Ignore if the new value is the same as the previous one
switchMap((query) => {
const trimmedQuery = query.trim();
if (trimmedQuery.length > 2) {
return this.autocompleteService.getAddressSuggestions(trimmedQuery);
}
// Return an empty observable if query length <= 2
return of([]);
}),
catchError((error) => {
console.error('Error fetching suggestions:', error);
return of([]); // Return an empty list in case of error
})
)
.subscribe((data) => {
this.suggestions = data;
}); });
} else {
this.suggestions = [];
}
} }
// Handles suggestion selection // Handles suggestion selection

@ -0,0 +1,72 @@
<div
class="flex flex-col items-center justify-center w-full h-36 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-gray-800 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500"
(click)="fileInput.click()"
(drop)="onDrop($event)"
(dragover)="onDragOver($event)"
(dragleave)="onDragLeave($event)"
>
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<svg
class="w-8 h-8 mb-4 text-gray-500 dark:text-gray-400"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 20 16"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"
/>
</svg>
<p class="mb-2 text-sm text-gray-500 dark:text-gray-400">
<span class="font-semibold">Click to upload</span> or drag and drop
</p>
<p class="text-xs text-gray-500 dark:text-gray-400">PNG, JPG or GIF</p>
</div>
<!-- Input masqué -->
<input
#fileInput
class="hidden"
type="file"
multiple
(change)="onFilesSelected($event)"
/>
</div>
<!-- Zone pour afficher les fichiers sélectionnés -->
<div
*ngIf="fileNames.length > 0"
class="mt-2 text-sm text-gray-500 dark:text-gray-400"
>
<ul>
<li *ngFor="let fileName of fileNames">
{{ fileName }}
<button
type="button"
class="end-2.5 text-gray-400 bg-transparent hover:text-gray-900 rounded-lg text-sm w-6 h-6 ms-auto inline-flex justify-center items-center dark:hover:text-white"
(click)="removeFile(fileName)"
>
<svg
class="w-2 h-2"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 14 14"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"
/>
</svg>
<span class="sr-only">Delete</span>
</button>
</li>
</ul>
</div>

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DragDropComponent } from './drag-drop.component';
describe('DragDropComponent', () => {
let component: DragDropComponent;
let fixture: ComponentFixture<DragDropComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DragDropComponent]
})
.compileComponents();
fixture = TestBed.createComponent(DragDropComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

@ -0,0 +1,45 @@
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
@Component({
selector: 'app-drag-drop',
imports: [CommonModule],
templateUrl: './drag-drop.component.html',
})
export class DragDropComponent {
fileNames: string[] = [];
onFilesSelected(event: Event): void {
const input = event.target as HTMLInputElement;
if (input.files) {
this.updateFileNames(input.files);
}
}
onDrop(event: DragEvent): void {
event.preventDefault();
event.stopPropagation();
if (event.dataTransfer && event.dataTransfer.files) {
this.updateFileNames(event.dataTransfer.files);
}
}
onDragOver(event: DragEvent): void {
event.preventDefault();
}
onDragLeave(event: DragEvent): void {
event.preventDefault();
}
private updateFileNames(files: FileList): void {
for (let i = 0; i < files.length; i++) {
this.fileNames.push(files[i].name);
}
}
removeFile(fileName: string): void {
const index = this.fileNames.indexOf(fileName);
this.fileNames.splice(index, 1);
}
}
Loading…
Cancel
Save