Merge branch 'feature/nearby-places' into 'develop'
Add nearby places See merge request tjohn/cc-data!25
This commit is contained in:
commit
8ae20d96aa
@ -28,6 +28,7 @@ import {
|
|||||||
MatChipsModule,
|
MatChipsModule,
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
MatDividerModule,
|
MatDividerModule,
|
||||||
|
MatListModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatSliderModule,
|
MatSliderModule,
|
||||||
MatSlideToggleModule,
|
MatSlideToggleModule,
|
||||||
@ -48,6 +49,7 @@ import {ShareDialogComponent} from './dialogs/share-dialog/share-dialog.componen
|
|||||||
import {TeamComponent} from './containers/team/team.component';
|
import {TeamComponent} from './containers/team/team.component';
|
||||||
import {DeviceDetectorModule} from 'ngx-device-detector';
|
import {DeviceDetectorModule} from 'ngx-device-detector';
|
||||||
import {ToggleSliderComponent} from './components/toggle-slider/toggle-slider.component';
|
import {ToggleSliderComponent} from './components/toggle-slider/toggle-slider.component';
|
||||||
|
import {PlaceComponent} from './components/place/place.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -67,7 +69,8 @@ import {ToggleSliderComponent} from './components/toggle-slider/toggle-slider.co
|
|||||||
ShareButtonComponent,
|
ShareButtonComponent,
|
||||||
ShareDialogComponent,
|
ShareDialogComponent,
|
||||||
TeamComponent,
|
TeamComponent,
|
||||||
ToggleSliderComponent
|
ToggleSliderComponent,
|
||||||
|
PlaceComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
@ -97,7 +100,8 @@ import {ToggleSliderComponent} from './components/toggle-slider/toggle-slider.co
|
|||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatSlideToggleModule,
|
MatSlideToggleModule,
|
||||||
MatSliderModule,
|
MatSliderModule,
|
||||||
MatChipsModule
|
MatChipsModule,
|
||||||
|
MatListModule
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
|
|||||||
6
frontend/src/app/components/place/place.component.html
Normal file
6
frontend/src/app/components/place/place.component.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<mat-card>
|
||||||
|
<img [src]="place.img_url" alt="Image of {{place.place_name}}">
|
||||||
|
<div class="footer">
|
||||||
|
<span class="name">{{place.place_name}}</span>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
28
frontend/src/app/components/place/place.component.scss
Normal file
28
frontend/src/app/components/place/place.component.scss
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
mat-card {
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: 20rem;
|
||||||
|
height: 11.25rem;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
width: 20rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
frontend/src/app/components/place/place.component.spec.ts
Normal file
25
frontend/src/app/components/place/place.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {PlaceComponent} from './place.component';
|
||||||
|
|
||||||
|
describe('PlaceComponent', () => {
|
||||||
|
let component: PlaceComponent;
|
||||||
|
let fixture: ComponentFixture<PlaceComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [PlaceComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PlaceComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
20
frontend/src/app/components/place/place.component.ts
Normal file
20
frontend/src/app/components/place/place.component.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
|
import {Place} from '../../interfaces/places.interface';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-place',
|
||||||
|
templateUrl: './place.component.html',
|
||||||
|
styleUrls: ['./place.component.scss']
|
||||||
|
})
|
||||||
|
export class PlaceComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
place: Place;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -66,6 +66,12 @@
|
|||||||
</mat-tab>
|
</mat-tab>
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="places-container">
|
||||||
|
<span class="group-title">Places</span>
|
||||||
|
<div class="places">
|
||||||
|
<app-place *ngFor="let place of places" [place]="place"></app-place>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="!region" class="spinner">
|
<div *ngIf="!region" class="spinner">
|
||||||
|
|||||||
@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
> .more-btn {
|
> .more-btn {
|
||||||
color: #8f8f8f;
|
color: #8f8f8f;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +67,27 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.places-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
> .group-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .places {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
|
||||||
|
app-place {
|
||||||
|
margin: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.spinner {
|
.spinner {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {ActivatedRoute, ParamMap} from '@angular/router';
|
|||||||
import {DataService} from '../../services/data.service';
|
import {DataService} from '../../services/data.service';
|
||||||
import {switchMap} from 'rxjs/operators';
|
import {switchMap} from 'rxjs/operators';
|
||||||
import {SearchParameter} from '../../interfaces/search-request.interface';
|
import {SearchParameter} from '../../interfaces/search-request.interface';
|
||||||
|
import {Place} from '../../interfaces/places.interface';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -36,6 +37,8 @@ export class RegionDetailsComponent implements AfterViewInit {
|
|||||||
/** Extend the description text */
|
/** Extend the description text */
|
||||||
isDescExtended = false;
|
isDescExtended = false;
|
||||||
|
|
||||||
|
places: Place[] = [];
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute, private ds: DataService) {
|
constructor(private route: ActivatedRoute, private ds: DataService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +48,7 @@ export class RegionDetailsComponent implements AfterViewInit {
|
|||||||
).subscribe((region: Region) => {
|
).subscribe((region: Region) => {
|
||||||
this.region = region;
|
this.region = region;
|
||||||
this.uriRegionName = encodeURI(this.region.name.toLowerCase());
|
this.uriRegionName = encodeURI(this.region.name.toLowerCase());
|
||||||
|
this.ds.getPlacesByRegion(this.region.region_id).then(places => this.places = places);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.container) {
|
if (this.container) {
|
||||||
this.container.nativeElement.scrollIntoView();
|
this.container.nativeElement.scrollIntoView();
|
||||||
|
|||||||
20
frontend/src/app/interfaces/places.interface.ts
Normal file
20
frontend/src/app/interfaces/places.interface.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
export interface Place {
|
||||||
|
/** The place id */
|
||||||
|
place_id: number;
|
||||||
|
/** The id of the parent region */
|
||||||
|
region_id: number;
|
||||||
|
/** The name of the place in english */
|
||||||
|
place_name: string;
|
||||||
|
/** The longitude position */
|
||||||
|
lon: number;
|
||||||
|
/** The latitude position */
|
||||||
|
lat: number;
|
||||||
|
/** The user rating between 0 and 5 */
|
||||||
|
rating: number;
|
||||||
|
/** Nearby address */
|
||||||
|
vicinity: string;
|
||||||
|
/** Google photo reference */
|
||||||
|
photo_reference: string;
|
||||||
|
/** URL to the image */
|
||||||
|
img_url: string;
|
||||||
|
}
|
||||||
@ -3,7 +3,11 @@ import {HttpClient, HttpParams} from '@angular/common/http';
|
|||||||
import {Preset} from '../interfaces/preset.interface';
|
import {Preset} from '../interfaces/preset.interface';
|
||||||
import {Result} from '../interfaces/result.interface';
|
import {Result} from '../interfaces/result.interface';
|
||||||
import {Region} from '../interfaces/region.interface';
|
import {Region} from '../interfaces/region.interface';
|
||||||
|
import {Place} from '../interfaces/places.interface';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data service handles all API interactions.
|
||||||
|
*/
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
@ -16,16 +20,27 @@ export class DataService {
|
|||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get results for specific search query.
|
||||||
|
* @param query The search query
|
||||||
|
*/
|
||||||
public searchRegions(query: string): Promise<Result[]> {
|
public searchRegions(query: string): Promise<Result[]> {
|
||||||
const params = new HttpParams().set('q', query);
|
const params = new HttpParams().set('q', query);
|
||||||
|
|
||||||
return this.http.get<Result[]>(this.API_URL + '/search', {params}).toPromise();
|
return this.http.get<Result[]>(this.API_URL + '/search', {params}).toPromise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all search presets.
|
||||||
|
*/
|
||||||
public getAllPresets(): Promise<Preset[]> {
|
public getAllPresets(): Promise<Preset[]> {
|
||||||
return this.http.get<Preset[]>(this.API_URL + '/search/presets').toPromise();
|
return this.http.get<Preset[]>(this.API_URL + '/search/presets').toPromise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all regions.
|
||||||
|
* @param max Limit the returned regions. Selected regions are random.
|
||||||
|
*/
|
||||||
public async getAllRegions(max?: number): Promise<Region[]> {
|
public async getAllRegions(max?: number): Promise<Region[]> {
|
||||||
let params = new HttpParams();
|
let params = new HttpParams();
|
||||||
if (max) {
|
if (max) {
|
||||||
@ -38,6 +53,10 @@ export class DataService {
|
|||||||
return regions;
|
return regions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets one region by its id.
|
||||||
|
* @param id The region id
|
||||||
|
*/
|
||||||
public async getRegion(id: number): Promise<Region> {
|
public async getRegion(id: number): Promise<Region> {
|
||||||
if (this.regionCache.has(id)) {
|
if (this.regionCache.has(id)) {
|
||||||
return this.regionCache.get(id);
|
return this.regionCache.get(id);
|
||||||
@ -48,8 +67,19 @@ export class DataService {
|
|||||||
|
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns POIs near the region.
|
||||||
|
* @param id The regions id
|
||||||
|
*/
|
||||||
|
public getPlacesByRegion(id: number): Promise<Place[]> {
|
||||||
|
return this.http.get<Place[]>(`${this.API_URL}/regions/${id}/nearby`).toPromise();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines meta data for all region parameters.
|
||||||
|
*/
|
||||||
export const REGION_PARAM_VIS: RegionParamVisLookup = {
|
export const REGION_PARAM_VIS: RegionParamVisLookup = {
|
||||||
temperature_mean: {
|
temperature_mean: {
|
||||||
icon: 'wb_sunny',
|
icon: 'wb_sunny',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user