diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 2fcdfc9..33b8239 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -50,6 +50,7 @@ import {TeamComponent} from './containers/team/team.component'; import {DeviceDetectorModule} from 'ngx-device-detector'; import {ToggleSliderComponent} from './components/toggle-slider/toggle-slider.component'; import {PlaceComponent} from './components/place/place.component'; +import {MultiTagSelectComponent} from './components/multi-tag-select/multi-tag-select.component'; @NgModule({ @@ -70,7 +71,8 @@ import {PlaceComponent} from './components/place/place.component'; ShareDialogComponent, TeamComponent, ToggleSliderComponent, - PlaceComponent + PlaceComponent, + MultiTagSelectComponent ], imports: [ BrowserModule, diff --git a/frontend/src/app/components/multi-tag-select/multi-tag-select.component.html b/frontend/src/app/components/multi-tag-select/multi-tag-select.component.html new file mode 100644 index 0000000..5e80dde --- /dev/null +++ b/frontend/src/app/components/multi-tag-select/multi-tag-select.component.html @@ -0,0 +1,5 @@ + + + {{tag}} + diff --git a/frontend/src/app/components/multi-tag-select/multi-tag-select.component.scss b/frontend/src/app/components/multi-tag-select/multi-tag-select.component.scss new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/frontend/src/app/components/multi-tag-select/multi-tag-select.component.scss @@ -0,0 +1 @@ + diff --git a/frontend/src/app/components/multi-tag-select/multi-tag-select.component.spec.ts b/frontend/src/app/components/multi-tag-select/multi-tag-select.component.spec.ts new file mode 100644 index 0000000..2f41ea7 --- /dev/null +++ b/frontend/src/app/components/multi-tag-select/multi-tag-select.component.spec.ts @@ -0,0 +1,25 @@ +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; + +import {MultiTagSelectComponent} from './multi-tag-select.component'; + +describe('MultiTagSelectComponent', () => { + let component: MultiTagSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [MultiTagSelectComponent] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MultiTagSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/components/multi-tag-select/multi-tag-select.component.ts b/frontend/src/app/components/multi-tag-select/multi-tag-select.component.ts new file mode 100644 index 0000000..4782495 --- /dev/null +++ b/frontend/src/app/components/multi-tag-select/multi-tag-select.component.ts @@ -0,0 +1,59 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; + +@Component({ + selector: 'app-multi-tag-select', + templateUrl: './multi-tag-select.component.html', + styleUrls: ['./multi-tag-select.component.scss'] +}) +export class MultiTagSelectComponent implements OnInit { + + @Input() + availableTags: string[] = []; + + @Output() + selection = new EventEmitter(); + + + rawValue: string[] = []; + @Output() modelChange: EventEmitter = new EventEmitter(); + + constructor() { + } + + get value(): string[] { + return this.rawValue; + } + + set value(value: string[]) { + this.rawValue = value; + this.modelChange.emit(value); + } + + @Input() + set model(value: string[]) { + this.rawValue = value; + } + + ngOnInit() { + } + + onChipClick(tag: string) { + if (this.isSelected(tag)) { + this.deselectTag(tag); + } else { + this.selectTag(tag); + } + } + + isSelected(tag: string) { + return this.value && this.value.includes(tag); + } + + private deselectTag(tag: string) { + this.value = this.value.filter(i => i !== tag); + } + + private selectTag(tag: string) { + this.value = this.value.concat(tag); + } +} diff --git a/frontend/src/app/components/search-input/search-input.component.html b/frontend/src/app/components/search-input/search-input.component.html index 2f046e4..34810a1 100644 --- a/frontend/src/app/components/search-input/search-input.component.html +++ b/frontend/src/app/components/search-input/search-input.component.html @@ -8,7 +8,7 @@ - + When is your trip?
@@ -22,7 +22,7 @@
- + Which climate would you prefer?
@@ -37,7 +37,7 @@
- + What else is important to you?
@@ -45,6 +45,12 @@ [(ngModel)]="singlePresetSelection[preset.preset_id]">{{preset.tag_label|translate}}
+ + + What needs to be fulfilled? + + +
@@ -93,7 +99,6 @@ Fincancial - diff --git a/frontend/src/app/components/search-input/search-input.component.ts b/frontend/src/app/components/search-input/search-input.component.ts index e27d705..6bd040d 100644 --- a/frontend/src/app/components/search-input/search-input.component.ts +++ b/frontend/src/app/components/search-input/search-input.component.ts @@ -21,6 +21,9 @@ export class SearchInputComponent implements OnInit { singlePresets: Preset[]; multiPresets: Map; multiPresetsKeys: string[]; + selectedTags: string[] = []; + + tags: string[]; from: string; to: string; @@ -55,6 +58,8 @@ export class SearchInputComponent implements OnInit { this.multiPresets = this.ps.multiPresets; this.multiPresetsKeys = [...this.multiPresets.keys()]; + this.tags = await this.ss.getAvailableTags(); + this.loadSearch(); } @@ -62,6 +67,7 @@ export class SearchInputComponent implements OnInit { this.saveSearch(isAdvanced); const query = isAdvanced ? this.getQueryFromAdvanced() : this.getQueryFromGuided(); + console.log(query); await this.router.navigate(['/search'], {queryParams: {q: objToBase64(query)}}); } @@ -96,6 +102,7 @@ export class SearchInputComponent implements OnInit { const query: Query = { from: new Date(this.from).getTime(), to: new Date(this.to).getTime(), + tags: this.selectedTags }; for (const preset of this.singlePresets) { @@ -138,6 +145,7 @@ export class SearchInputComponent implements OnInit { to: this.to, singlePresetSelection: this.singlePresetSelection, multiPresetSelection: this.multiPresetSelection, + tags: this.selectedTags, fullText: this.fullText, textFiler: this.textFilter, tempMeanMax: this.temperatureMeanMax, @@ -154,6 +162,7 @@ export class SearchInputComponent implements OnInit { this.to = prevInput.to; this.singlePresetSelection = prevInput.singlePresetSelection; this.multiPresetSelection = prevInput.multiPresetSelection; + this.selectedTags = prevInput.tags; this.textFilter = prevInput.textFiler; this.fullText = prevInput.fullText; this.selectedTab = prevInput.wasAdvanced ? 1 : 0; diff --git a/frontend/src/app/interfaces/search-request.interface.ts b/frontend/src/app/interfaces/search-request.interface.ts index 5b511cb..688e568 100644 --- a/frontend/src/app/interfaces/search-request.interface.ts +++ b/frontend/src/app/interfaces/search-request.interface.ts @@ -15,6 +15,7 @@ export interface Query { fulltext?: boolean; textfilter?: string; showRegionsWithNullScore?: boolean; + tags?: string[]; } export enum SearchParameter { diff --git a/frontend/src/app/services/data.service.ts b/frontend/src/app/services/data.service.ts index c71b429..7208192 100644 --- a/frontend/src/app/services/data.service.ts +++ b/frontend/src/app/services/data.service.ts @@ -75,6 +75,13 @@ export class DataService { public getPlacesByRegion(id: number): Promise { return this.http.get(`${this.API_URL}/regions/${id}/nearby`).toPromise(); } + + /** + * Returns all available search tags. + */ + public getAllTags(): Promise { + return this.http.get(`${this.API_URL}/search/tags`).toPromise(); + } } /** diff --git a/frontend/src/app/services/search.service.ts b/frontend/src/app/services/search.service.ts index a4d0f6f..b2eabdf 100644 --- a/frontend/src/app/services/search.service.ts +++ b/frontend/src/app/services/search.service.ts @@ -8,6 +8,7 @@ export interface SearchInput { to: string; singlePresetSelection: object; multiPresetSelection: object; + tags: string[]; textFiler: string; fullText: boolean; tempMeanMax: number; @@ -21,6 +22,7 @@ export interface SearchInput { export class SearchService { private searchInput: SearchInput; + private cachedTags: string[]; constructor(private ds: DataService) { } @@ -36,4 +38,13 @@ export class SearchService { public loadSearchInput(): SearchInput { return this.searchInput; } + + public async getAvailableTags(): Promise { + if (this.cachedTags) { + return this.cachedTags; + } + const tags: string[] = await this.ds.getAllTags(); + this.cachedTags = tags; + return tags; + } }