Merge branch 'feature/search-tag-ui' into 'develop'
Add tag search UI See merge request tjohn/cc-data!29
This commit is contained in:
commit
384992634d
@ -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,
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
<mat-chip-list>
|
||||
<!--suppress AngularInvalidExpressionResultType -->
|
||||
<mat-chip (click)="onChipClick(tag)" *ngFor="let tag of availableTags" [color]="isSelected(tag) ? 'accent' : 'none'"
|
||||
selected>{{tag}}</mat-chip>
|
||||
</mat-chip-list>
|
||||
@ -0,0 +1 @@
|
||||
|
||||
@ -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<MultiTagSelectComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MultiTagSelectComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MultiTagSelectComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -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<string[]>();
|
||||
|
||||
|
||||
rawValue: string[] = [];
|
||||
@Output() modelChange: EventEmitter<string[]> = new EventEmitter<string[]>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,7 @@
|
||||
<mat-tab label="Guided">
|
||||
|
||||
<mat-vertical-stepper>
|
||||
|
||||
<!-- Date input -->
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>When is your trip?</ng-template>
|
||||
<div class="vertical-wrap">
|
||||
@ -22,7 +22,7 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-step>
|
||||
|
||||
<!-- Multi presets -->
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>Which climate would you prefer?</ng-template>
|
||||
<div *ngFor="let key of multiPresetsKeys" class="sub-group">
|
||||
@ -37,7 +37,7 @@
|
||||
</mat-radio-group>
|
||||
</div>
|
||||
</mat-step>
|
||||
|
||||
<!-- Single presets -->
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>What else is important to you?</ng-template>
|
||||
<div class="vertical">
|
||||
@ -45,6 +45,12 @@
|
||||
[(ngModel)]="singlePresetSelection[preset.preset_id]">{{preset.tag_label|translate}}</mat-checkbox>
|
||||
</div>
|
||||
</mat-step>
|
||||
<!-- Tag selection -->
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>What needs to be fulfilled?</ng-template>
|
||||
<app-multi-tag-select [(model)]="selectedTags" [availableTags]="tags"></app-multi-tag-select>
|
||||
</mat-step>
|
||||
|
||||
</mat-vertical-stepper>
|
||||
</mat-tab>
|
||||
|
||||
@ -93,7 +99,6 @@
|
||||
<span class="title">Fincancial</span>
|
||||
<app-toggle-slider [(model)]="accommodation" [label]="'Accommodation'" [max]="60" [min]="0"></app-toggle-slider>
|
||||
</section>
|
||||
|
||||
</mat-tab>
|
||||
|
||||
</mat-tab-group>
|
||||
|
||||
@ -21,6 +21,9 @@ export class SearchInputComponent implements OnInit {
|
||||
singlePresets: Preset[];
|
||||
multiPresets: Map<string, Preset[]>;
|
||||
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;
|
||||
|
||||
@ -15,6 +15,7 @@ export interface Query {
|
||||
fulltext?: boolean;
|
||||
textfilter?: string;
|
||||
showRegionsWithNullScore?: boolean;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export enum SearchParameter {
|
||||
|
||||
@ -75,6 +75,13 @@ export class DataService {
|
||||
public getPlacesByRegion(id: number): Promise<Place[]> {
|
||||
return this.http.get<Place[]>(`${this.API_URL}/regions/${id}/nearby`).toPromise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available search tags.
|
||||
*/
|
||||
public getAllTags(): Promise<string[]> {
|
||||
return this.http.get<string[]>(`${this.API_URL}/search/tags`).toPromise();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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<string[]> {
|
||||
if (this.cachedTags) {
|
||||
return this.cachedTags;
|
||||
}
|
||||
const tags: string[] = await this.ds.getAllTags();
|
||||
this.cachedTags = tags;
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user