💄 GMaps autocompletion: loading indicator

This commit is contained in:
itskovacs 2025-11-09 19:44:32 +01:00
parent a7adec2675
commit cfe4baa794
3 changed files with 62 additions and 10 deletions

View File

@ -6,9 +6,16 @@
(keydown.control.enter)="closeDialog()" />
<label for="name">Name</label>
</p-floatlabel>
<p-button icon="pi pi-sparkles" variant="text" [disabled]="!placeForm.get('name')!.value"
class="absolute right-2 top-1/2 -translate-y-1/2" pTooltip="Complete using GMaps API"
(click)="gmapsSearchText()" />
<div class="absolute right-2 top-1/2 -translate-y-1/2">
@if (gmapsLoading) {
<svg viewBox="25 25 50 50">
<circle r="20" cy="50" cx="50"></circle>
</svg>
} @else {
<p-button icon="pi pi-sparkles" variant="text" [disabled]="!placeForm.get('name')!.value" pTooltip="Complete using GMaps API"
(click)="gmapsSearchText()" />
}
</div>
</div>
<p-floatlabel variant="in">

View File

@ -14,3 +14,40 @@
.p-floatlabel:has(.p-inputwrapper-focus) input::placeholder {
color: var(--p-inputtext-placeholder-color) !important;
}
svg {
width: 2rem;
animation: loading-rotate 1.5s linear infinite;
}
circle {
fill: none;
stroke: #4f46e5;
stroke-width: 2;
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
stroke-linecap: round;
animation: loading-dash 1.5s ease-in-out infinite;
}
@keyframes loading-rotate {
100% {
transform: rotate(360deg);
}
}
@keyframes loading-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 200;
stroke-dashoffset: -35px;
}
100% {
stroke-dashoffset: -125px;
}
}

View File

@ -47,6 +47,7 @@ export class PlaceCreateModalComponent {
categories$?: Observable<Category[]>;
previous_image_id: number | null = null;
previous_image: string | null = null;
gmapsLoading = false;
placeInputTooltip: string =
"<div class='text-center'>You can paste a Google Maps Place link to fill <i>Name</i>, <i>Place</i>, <i>Lat</i>, <i>Lng</i>.</div>\n<div class='text-sm text-center'>https://google.com/maps/place/XXX</div>\n<div class='text-xs text-center'>Either « click » on a point of interest or « search » for it (eg: British Museum) and copy the URL</div>";
@ -209,23 +210,27 @@ export class PlaceCreateModalComponent {
gmapsToForm(r: GooglePlaceResult) {
this.placeForm.patchValue({ ...r, lat: formatLatLng(r.lat), lng: formatLatLng(r.lng), place: r.name || '' });
this.placeForm.get('category')?.markAsDirty();
this.gmapsLoading = false;
if (r.category) {
this.categories$?.pipe(take(1)).subscribe({next: categories => {
const category: Category | undefined = categories.find(c => c.name == r.category);
if (!category) return;
this.placeForm.get('category')?.setValue(category.id);
}})
this.categories$?.pipe(take(1)).subscribe({
next: categories => {
const category: Category | undefined = categories.find(c => c.name == r.category);
if (!category) return;
this.placeForm.get('category')?.setValue(category.id);
}
})
}
}
gmapsSearchText() {
this.gmapsLoading = true;
const query = this.placeForm.get('name')?.value;
if (!query) return;
this.apiService.gmapsSearchText(query).subscribe({
next: (results) => {
if (!results.length) {
this.utilsService.toast('warn', 'No result', 'No result available for this autocompletion');
this.gmapsLoading = false;
return;
}
@ -250,7 +255,10 @@ export class PlaceCreateModalComponent {
modal.onClose.pipe(take(1)).subscribe({
next: (result: GooglePlaceResult | null) => {
if (!result) return;
if (!result) {
this.gmapsLoading = false;
return;
}
this.gmapsToForm(result);
},
});