Skip to content

Commit 3861c2f

Browse files
committed
feat: migrate ClearReplacePicture and SetPicturePoint to gRPC
1 parent 423caf7 commit 3861c2f

File tree

7 files changed

+465
-329
lines changed

7 files changed

+465
-329
lines changed

src/app/map/map.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export class MapComponent implements OnInit {
112112

113113
for (const item of data) {
114114
if (item.location) {
115-
const m = createMarker(item.location.lat, item.location.lng);
115+
const m = createMarker(item.location.latitude, item.location.longitude);
116116

117117
const popup = new Popup();
118118
m.on('click', () => {

src/app/moder/pictures/item/item.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ <h3 i18n *ngIf="picture.replaceable">Replacement</h3>
351351
<i class="bi bi-arrow-left-right" aria-hidden="true"></i>
352352
<ng-container i18n>Accept and remove double</ng-container>
353353
</button>
354-
<button class="btn btn-warning" *ngIf="picture.rights.accept" (click)="cancelReplace(picture.id)">
354+
<button class="btn btn-warning" *ngIf="picture.rights.accept" (click)="cancelReplace(picture.id + '')">
355355
<i class="bi bi-x" aria-hidden="true"></i>
356356
<ng-container i18n>Cancel replacement</ng-container>
357357
</button>

src/app/moder/pictures/item/item.component.ts

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -470,24 +470,18 @@ export class ModerPicturesItemComponent {
470470
});
471471
}
472472

473-
protected cancelReplace(id: number) {
473+
protected cancelReplace(id: string) {
474474
this.replaceLoading = true;
475475

476-
this.api
477-
.request<void>('PUT', 'picture/' + id, {
478-
body: {
479-
replace_picture_id: '',
480-
},
481-
})
482-
.subscribe({
483-
error: () => {
484-
this.replaceLoading = false;
485-
},
486-
next: () => {
487-
this.change$.next();
488-
this.replaceLoading = false;
489-
},
490-
});
476+
this.picturesClient.clearReplacePicture(new PictureIDRequest({id})).subscribe({
477+
error: () => {
478+
this.replaceLoading = false;
479+
},
480+
next: () => {
481+
this.change$.next();
482+
this.replaceLoading = false;
483+
},
484+
});
491485
}
492486

493487
protected acceptReplace(id: number) {

src/app/moder/pictures/item/place/place.component.html

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,46 +19,53 @@
1919
<h1 i18n>Location</h1>
2020
</div>
2121

22-
<form method="post" class="form-horizontal" (ngSubmit)="doSubmit(picture)" *ngIf="picture$ | async as picture">
23-
<div class="mb-3 row" *ngIf="map$ | async as map">
24-
<label class="col-md-2 col-form-label" i18n>Point</label>
25-
<div class="col-md-10 coords">
26-
<input
27-
type="text"
28-
name="lat"
29-
[(ngModel)]="lat"
30-
maxlength="20"
31-
size="20"
32-
placeholder="Latitude"
33-
i18n-placeholder
34-
class="form-control"
35-
(input)="coordsChanged(map)"
36-
/>
37-
<input
38-
type="text"
39-
name="lng"
40-
[(ngModel)]="lng"
41-
maxlength="20"
42-
size="20"
43-
placeholder="Longitude"
44-
i18n-placeholder
45-
class="form-control"
46-
(input)="coordsChanged(map)"
47-
/>
22+
<ng-container *ngIf="picture$ | async as picture">
23+
<form
24+
method="post"
25+
class="form-horizontal"
26+
(ngSubmit)="doSubmit(form, picture)"
27+
[formGroup]="form"
28+
*ngIf="form$ | async as form"
29+
>
30+
<div class="mb-3 row">
31+
<label class="col-md-2 col-form-label" i18n>Point</label>
32+
<div class="col-md-10 coords mb-3">
33+
<input
34+
type="text"
35+
name="lat"
36+
[formControl]="form.controls.lat"
37+
maxlength="20"
38+
size="20"
39+
placeholder="Latitude"
40+
i18n-placeholder
41+
class="form-control"
42+
/>
43+
<input
44+
type="text"
45+
name="lng"
46+
[formControl]="form.controls.lng"
47+
maxlength="20"
48+
size="20"
49+
placeholder="Longitude"
50+
i18n-placeholder
51+
class="form-control"
52+
/>
53+
</div>
4854
</div>
4955
<div
56+
*ngIf="map$ | async as map"
5057
style="height: 500px"
5158
class="mb-4 w-100"
5259
leaflet
5360
[leafletCenter]="map.center"
5461
[leafletOptions]="map.leafletOptions"
5562
[leafletLayers]="map.markers"
56-
(leafletMapReady)="onMapReady(map, $event)"
63+
(leafletMapReady)="onMapReady(map, $event, form)"
5764
></div>
58-
</div>
59-
<div class="mb-3 row">
60-
<div class="col-md-10 offset-md-2">
61-
<button type="submit" name="submit" class="btn btn-primary" i18n>Submit</button>
65+
<div class="mb-3 row">
66+
<div class="col-md-10 offset-md-2">
67+
<button type="submit" name="submit" class="btn btn-primary" i18n>Submit</button>
68+
</div>
6269
</div>
63-
</div>
64-
</form>
70+
</form>
71+
</ng-container>

src/app/moder/pictures/item/place/place.component.ts

Lines changed: 84 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,32 @@
11
import {Component, NgZone, OnInit} from '@angular/core';
2+
import {FormControl, FormGroup} from '@angular/forms';
23
import {ActivatedRoute, Router} from '@angular/router';
3-
import {APIService} from '@services/api.service';
4+
import {LatLng as grpcLatLng} from '@grpc/google/type/latlng.pb';
5+
import {SetPicturePointRequest} from '@grpc/spec.pb';
6+
import {PicturesClient} from '@grpc/spec.pbsc';
47
import {PageEnvService} from '@services/page-env.service';
58
import {APIPicture, PictureService} from '@services/picture';
69
import {LatLng, LeafletMouseEvent, Map, Marker, TileLayer, icon, latLng, marker, tileLayer} from 'leaflet';
710
import {EMPTY} from 'rxjs';
8-
import {catchError, debounceTime, distinctUntilChanged, map, shareReplay, switchMap} from 'rxjs/operators';
11+
import {catchError, debounceTime, distinctUntilChanged, map, shareReplay, startWith, switchMap} from 'rxjs/operators';
12+
13+
import {ToastsService} from '../../../../toasts/toasts.service';
914

1015
interface MapOptions {
1116
center: LatLng;
1217
leafletOptions: {center: LatLng; layers: TileLayer[]; zoom: number};
1318
markers: Marker[];
1419
}
1520

21+
function normalizeLat(lat: number) {
22+
return Math.max(lat, Math.min(lat, 90), -90);
23+
}
24+
25+
function normalizeLng(lng: number) {
26+
lng = ((lng - 180) % 360) + 180;
27+
return ((lng + 180) % 360) - 180;
28+
}
29+
1630
function createMarker(lat: number, lng: number): Marker {
1731
return marker([lat, lng], {
1832
icon: icon({
@@ -24,13 +38,20 @@ function createMarker(lat: number, lng: number): Marker {
2438
});
2539
}
2640

41+
interface PointForm {
42+
lat: FormControl<null | string>;
43+
lng: FormControl<null | string>;
44+
}
45+
2746
@Component({
2847
selector: 'app-moder-pictures-place',
2948
templateUrl: './place.component.html',
3049
})
3150
export class ModerPicturesItemPlaceComponent implements OnInit {
32-
protected lat: number = NaN;
33-
protected lng: number = NaN;
51+
private readonly form = new FormGroup<PointForm>({
52+
lat: new FormControl<string>(''),
53+
lng: new FormControl<string>(''),
54+
});
3455

3556
protected readonly picture$ = this.route.paramMap.pipe(
3657
map((params) => parseInt(params.get('id') || '', 10)),
@@ -46,9 +67,26 @@ export class ModerPicturesItemPlaceComponent implements OnInit {
4667
shareReplay(1),
4768
);
4869

49-
protected readonly map$ = this.picture$.pipe(
70+
protected readonly form$ = this.picture$.pipe(
5071
map((picture) => {
51-
const center = latLng(55.7423627, 37.6786422);
72+
let lat = null,
73+
lng = null;
74+
if (picture && picture.point && picture.point.lat && picture.point.lng) {
75+
lat = picture.point.lat + '';
76+
lng = picture.point.lng + '';
77+
}
78+
79+
this.form.setValue({lat, lng});
80+
81+
return this.form;
82+
}),
83+
shareReplay(1),
84+
);
85+
86+
protected readonly map$ = this.form$.pipe(
87+
switchMap((form) => form.valueChanges.pipe(startWith(form.value))),
88+
map((formValues) => {
89+
let center = latLng(55.7423627, 37.6786422);
5290

5391
const leafletOptions = {
5492
center: center,
@@ -60,15 +98,21 @@ export class ModerPicturesItemPlaceComponent implements OnInit {
6098
zoom: 8,
6199
};
62100

101+
let lat = formValues.lat ? parseFloat(formValues.lat) : NaN;
102+
let lng = formValues.lng ? parseFloat(formValues.lng) : NaN;
103+
63104
const markers: Marker[] = [];
64105

65-
if (picture && picture.point) {
66-
this.lat = picture.point.lat;
67-
this.lng = picture.point.lng;
68-
if (picture.point.lat && picture.point.lng) {
69-
markers.push(createMarker(picture.point.lat, picture.point.lng));
70-
leafletOptions.center = latLng(picture.point.lat, picture.point.lng);
71-
}
106+
let ll = null;
107+
if (!isNaN(lat) && !isNaN(lng)) {
108+
lat = normalizeLat(lat);
109+
lng = normalizeLng(lng);
110+
ll = latLng([lat, lng]);
111+
}
112+
if (ll) {
113+
markers.push(createMarker(ll.lat, ll.lng));
114+
center = ll;
115+
leafletOptions.center = ll;
72116
}
73117

74118
return {center, leafletOptions, markers};
@@ -81,7 +125,8 @@ export class ModerPicturesItemPlaceComponent implements OnInit {
81125
private readonly pictureService: PictureService,
82126
private readonly pageEnv: PageEnvService,
83127
private readonly zone: NgZone,
84-
private readonly api: APIService,
128+
private readonly picturesClient: PicturesClient,
129+
private readonly toastService: ToastsService,
85130
) {}
86131

87132
ngOnInit(): void {
@@ -95,45 +140,38 @@ export class ModerPicturesItemPlaceComponent implements OnInit {
95140
);
96141
}
97142

98-
protected coordsChanged(mapOptions: MapOptions) {
99-
const lat = this.lat;
100-
const lng = this.lng;
101-
102-
const ll = isNaN(lat) || isNaN(lng) ? null : latLng([lat, lng]);
103-
if (ll) {
104-
if (mapOptions.markers.length) {
105-
mapOptions.markers[0].setLatLng(ll);
106-
} else {
107-
mapOptions.markers = [createMarker(ll.lat, ll.lng)];
108-
}
109-
mapOptions.center = ll;
110-
mapOptions.leafletOptions.center = ll;
111-
} else {
112-
mapOptions.markers = [];
113-
}
114-
}
115-
116-
protected onMapReady(mapOptions: MapOptions, lmap: Map) {
143+
protected onMapReady(mapOptions: MapOptions, lmap: Map, form: FormGroup<PointForm>) {
117144
lmap.on('click', (event: LeafletMouseEvent) => {
118145
this.zone.run(() => {
119146
const ll: LatLng = event.latlng;
120-
mapOptions.markers = [createMarker(ll.lat, ll.lng)];
121-
this.lat = ll.lat;
122-
this.lng = ll.lng;
147+
const lat = normalizeLat(ll.lat);
148+
const lng = normalizeLng(ll.lng);
149+
mapOptions.markers = [createMarker(lat, lng)];
150+
form.setValue({
151+
lat: lat + '',
152+
lng: lng + '',
153+
});
123154
});
124155
});
125156
}
126157

127-
protected doSubmit(picture: APIPicture) {
128-
this.api
129-
.request<void>('PUT', 'picture/' + picture.id, {
130-
body: {
131-
point: {
132-
lat: this.lat,
133-
lng: this.lng,
134-
},
135-
},
136-
})
158+
protected doSubmit(form: FormGroup<PointForm>, picture: APIPicture) {
159+
this.picturesClient
160+
.setPicturePoint(
161+
new SetPicturePointRequest({
162+
pictureId: '' + picture.id,
163+
point: new grpcLatLng({
164+
latitude: form.controls.lat.value ? parseFloat(form.controls.lat.value) : 0,
165+
longitude: form.controls.lng.value ? parseFloat(form.controls.lng.value) : 0,
166+
}),
167+
}),
168+
)
169+
.pipe(
170+
catchError((response: unknown) => {
171+
this.toastService.handleError(response);
172+
return EMPTY;
173+
}),
174+
)
137175
.subscribe(() => {
138176
this.router.navigate(['/moder/pictures', picture.id]);
139177
});

0 commit comments

Comments
 (0)