From b5c264b807e92800550ac8a5bebaa649be80771f Mon Sep 17 00:00:00 2001 From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com> Date: Fri, 15 Jan 2021 18:32:29 +0100 Subject: [PATCH 1/3] feat: add address search with auto-complete --- src/app/home/home.component.html | 1 + .../address-autocomplete.component.html | 16 +++++++++ .../address-autocomplete.component.scss | 22 ++++++++++++ .../address-autocomplete.component.spec.ts | 25 +++++++++++++ .../address-autocomplete.component.ts | 35 +++++++++++++++++++ src/app/shared/components/index.ts | 3 ++ .../shared/service/address.service.spec.ts | 16 +++++++++ src/app/shared/service/address.service.ts | 14 ++++++++ src/app/shared/shared.module.ts | 3 +- 9 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 src/app/shared/components/address-autocomplete/address-autocomplete.component.html create mode 100644 src/app/shared/components/address-autocomplete/address-autocomplete.component.scss create mode 100644 src/app/shared/components/address-autocomplete/address-autocomplete.component.spec.ts create mode 100644 src/app/shared/components/address-autocomplete/address-autocomplete.component.ts create mode 100644 src/app/shared/service/address.service.spec.ts create mode 100644 src/app/shared/service/address.service.ts diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html index 11b58a671..44ce7a91d 100644 --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -1,4 +1,5 @@ <div fxLayout="row" class="content-container"> + <app-address-autocomplete></app-address-autocomplete> <app-structure-list (searchEvent)="getStructures($event)" [structureList]="structures" diff --git a/src/app/shared/components/address-autocomplete/address-autocomplete.component.html b/src/app/shared/components/address-autocomplete/address-autocomplete.component.html new file mode 100644 index 000000000..73a660d26 --- /dev/null +++ b/src/app/shared/components/address-autocomplete/address-autocomplete.component.html @@ -0,0 +1,16 @@ +<div class="search-bar"> + <div> + <input + id="search-address" + type="text" + placeholder="ex: 20 rue du lac, Lyon" + (input)="onSearchChange($event.target.value)" + #searchAddress + /> + </div> + <div class="autocomplete-items"> + <p *ngFor="let hit of data" (click)="selectedResult(hit)" class="autocomplete-item"> + {{ parseHitToAddress(hit) }} + </p> + </div> +</div> diff --git a/src/app/shared/components/address-autocomplete/address-autocomplete.component.scss b/src/app/shared/components/address-autocomplete/address-autocomplete.component.scss new file mode 100644 index 000000000..433d3afca --- /dev/null +++ b/src/app/shared/components/address-autocomplete/address-autocomplete.component.scss @@ -0,0 +1,22 @@ +@import '../../../../assets/scss/color'; + +.search-bar { + display: flex; + flex-direction: column; +} +.autocomplete-items { + border: 0.0625rem solid #d4d4d4; + border-top: none; + border-bottom: none; + z-index: 99; + background-color: #fff; + cursor: pointer; +} +.autocomplete-item { + margin: 0; + padding: 1em 0; +} +.autocomplete-item:hover { + background-color: #dee6ee; + cursor: pointer; +} diff --git a/src/app/shared/components/address-autocomplete/address-autocomplete.component.spec.ts b/src/app/shared/components/address-autocomplete/address-autocomplete.component.spec.ts new file mode 100644 index 000000000..a74f2a401 --- /dev/null +++ b/src/app/shared/components/address-autocomplete/address-autocomplete.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddressAutocompleteComponent } from './address-autocomplete.component'; + +describe('AddressAutocompleteComponent', () => { + let component: AddressAutocompleteComponent; + let fixture: ComponentFixture<AddressAutocompleteComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AddressAutocompleteComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AddressAutocompleteComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts b/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts new file mode 100644 index 000000000..aead77070 --- /dev/null +++ b/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts @@ -0,0 +1,35 @@ +import { Component, ElementRef, EventEmitter, Output, ViewChild } from '@angular/core'; +import { AddressService } from '../../service/address.service'; + +@Component({ + selector: 'app-address-autocomplete', + templateUrl: './address-autocomplete.component.html', + styleUrls: ['./address-autocomplete.component.scss'], +}) +export class AddressAutocompleteComponent { + public data = []; + @ViewChild('searchAddress', { static: true }) searchAddress: ElementRef; + @Output() selectedAddress: EventEmitter<string> = new EventEmitter<string>(); + + constructor(private addressService: AddressService) {} + + public onSearchChange(searchString: string) { + this.addressService.searchAddress(searchString).subscribe((data) => { + this.data = data.hits.hits; + }); + } + + public selectedResult(hit: any): void { + const value = this.parseHitToAddress(hit); + // Set input value + this.searchAddress.nativeElement.value = value; + // Reset autocomplete + this.data = []; + // Emit choosen value + this.selectedAddress.emit(value); + } + + public parseHitToAddress(hit: any): string { + return `${hit._source['data-fr'].properties.numero_str} ${hit._source['data-fr'].properties.voie_str} ${hit._source['data-fr'].properties.commune_str}`; + } +} diff --git a/src/app/shared/components/index.ts b/src/app/shared/components/index.ts index 89b310d72..e4d55982f 100644 --- a/src/app/shared/components/index.ts +++ b/src/app/shared/components/index.ts @@ -6,6 +6,7 @@ import { SignInModalComponent } from './signin-modal/signin-modal.component'; import { SvgIconComponent } from './svg-icon/svg-icon.component'; import { ValidatorFormComponent } from './validator-form/validator-form.component'; import { CreateAccountFormComponent } from './create-account-form/create-account-form.component'; +import { AddressAutocompleteComponent } from './address-autocomplete/address-autocomplete.component'; // tslint:disable-next-line: max-line-length export { @@ -17,6 +18,7 @@ export { SignUpModalComponent, SignInModalComponent, CreateAccountFormComponent, + AddressAutocompleteComponent, }; // tslint:disable-next-line:variable-name @@ -29,4 +31,5 @@ export const SharedComponents = [ SignUpModalComponent, SignInModalComponent, CreateAccountFormComponent, + AddressAutocompleteComponent, ]; diff --git a/src/app/shared/service/address.service.spec.ts b/src/app/shared/service/address.service.spec.ts new file mode 100644 index 000000000..f0cd890c8 --- /dev/null +++ b/src/app/shared/service/address.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { AddressService } from './address.service'; + +describe('AddressService', () => { + let service: AddressService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(AddressService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/shared/service/address.service.ts b/src/app/shared/service/address.service.ts new file mode 100644 index 000000000..38f66f8d1 --- /dev/null +++ b/src/app/shared/service/address.service.ts @@ -0,0 +1,14 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root', +}) +export class AddressService { + constructor(private http: HttpClient) {} + + public searchAddress(searchQuery: string): Observable<any> { + return this.http.post<any>(`api/structures/address`, { searchQuery }); + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 7a91eef73..2709454bd 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -7,9 +7,10 @@ import { SharedComponents } from './components'; import { SharedPipes } from './pipes'; import { SharedDirectives } from './directives'; import { SvgIconComponent } from './components/svg-icon/svg-icon.component'; +import { AddressAutocompleteComponent } from './components/address-autocomplete/address-autocomplete.component'; @NgModule({ imports: [CommonModule, RouterModule, FlexLayoutModule, ReactiveFormsModule], - declarations: [...SharedPipes, ...SharedComponents, ...SharedDirectives, SvgIconComponent], + declarations: [...SharedPipes, ...SharedComponents, ...SharedDirectives, SvgIconComponent, AddressAutocompleteComponent], exports: [ ...SharedPipes, ...SharedComponents, -- GitLab From b1dba86db8287cb7926e5f6373269d1ff5537ac2 Mon Sep 17 00:00:00 2001 From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com> Date: Mon, 18 Jan 2021 17:28:48 +0100 Subject: [PATCH 2/3] feat(style): add form-input style --- .../address-autocomplete.component.html | 1 + .../address-autocomplete.component.ts | 3 ++- src/assets/scss/_inputs.scss | 16 ++++++++++++++++ src/assets/scss/_shapes.scss | 2 +- src/styles.scss | 1 + 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/app/shared/components/address-autocomplete/address-autocomplete.component.html b/src/app/shared/components/address-autocomplete/address-autocomplete.component.html index 73a660d26..537de506d 100644 --- a/src/app/shared/components/address-autocomplete/address-autocomplete.component.html +++ b/src/app/shared/components/address-autocomplete/address-autocomplete.component.html @@ -5,6 +5,7 @@ type="text" placeholder="ex: 20 rue du lac, Lyon" (input)="onSearchChange($event.target.value)" + class="form-input" #searchAddress /> </div> diff --git a/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts b/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts index aead77070..4e6d5cc97 100644 --- a/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts +++ b/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts @@ -7,6 +7,7 @@ import { AddressService } from '../../service/address.service'; styleUrls: ['./address-autocomplete.component.scss'], }) export class AddressAutocompleteComponent { + public readonly AUTOCOMPLETE_NBR = 5; public data = []; @ViewChild('searchAddress', { static: true }) searchAddress: ElementRef; @Output() selectedAddress: EventEmitter<string> = new EventEmitter<string>(); @@ -15,7 +16,7 @@ export class AddressAutocompleteComponent { public onSearchChange(searchString: string) { this.addressService.searchAddress(searchString).subscribe((data) => { - this.data = data.hits.hits; + this.data = data.hits.hits.slice(0, this.AUTOCOMPLETE_NBR); }); } diff --git a/src/assets/scss/_inputs.scss b/src/assets/scss/_inputs.scss index dac479e10..e672692f6 100644 --- a/src/assets/scss/_inputs.scss +++ b/src/assets/scss/_inputs.scss @@ -1,3 +1,6 @@ +@import './color'; +@import './shapes'; + @mixin input-search { width: 100%; border: none; @@ -7,3 +10,16 @@ outline: none; font-style: italic; } + +.form-input { + min-width: 290px; + background: $grey-6; + border: 1px solid $grey-4; + box-sizing: border-box; + border-radius: $input-radius; + height: 40px; +} +.form-input:focus { + border: 1px solid $blue; + outline: none !important; +} diff --git a/src/assets/scss/_shapes.scss b/src/assets/scss/_shapes.scss index fec384566..c85355e0f 100644 --- a/src/assets/scss/_shapes.scss +++ b/src/assets/scss/_shapes.scss @@ -2,7 +2,7 @@ $card-radius: 0.625em; $bouton-radius: 0.625em; -$input-radius: 0.3125em; +$input-radius: 4px; $bouton-width: 12.25em; $round-bouton-radius: 1.25em; $round-radius: 50%; diff --git a/src/styles.scss b/src/styles.scss index 3e993cf99..1773ee54c 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -4,6 +4,7 @@ @import 'assets/scss/color'; @import 'assets/scss/breakpoint'; @import 'assets/scss/icons'; +@import 'assets/scss/inputs'; @import '../node_modules/leaflet.locatecontrol/dist/L.Control.Locate.css'; html { -- GitLab From 729e20f81813400c0ae24c518c3985d88b373fe9 Mon Sep 17 00:00:00 2001 From: Hugo SUBTIL <ext.sopra.husubtil@grandlyon.com> Date: Mon, 18 Jan 2021 17:32:33 +0100 Subject: [PATCH 3/3] fix: remove test component from home --- src/app/home/home.component.html | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html index 44ce7a91d..11b58a671 100644 --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -1,5 +1,4 @@ <div fxLayout="row" class="content-container"> - <app-address-autocomplete></app-address-autocomplete> <app-structure-list (searchEvent)="getStructures($event)" [structureList]="structures" -- GitLab