Trail Edit / Waypoints from photos: prevent creating different waypoints for near-by locations (#457)
* trail edit / waypoints from photos: prevent creating different waypoints for near-by locations * remove not necessary imports * remove changes from gitignore * patch gitignore * waypoint merge radius as category property * change datamodel for merge radius (use more generic settings field for future implementations) * fix npm run check issues * several improvements/fixes * fix * move geo cluster code to db * fix compile issue * fix docker issue * merge with existing waypoints --------- Co-authored-by: Christian Beutel <> Co-authored-by: Flomp <Flomp@users.noreply.github.com>
This commit is contained in:
248
web/src/lib/components/waypoint/waypoint_merge_modal.svelte
Normal file
248
web/src/lib/components/waypoint/waypoint_merge_modal.svelte
Normal file
@@ -0,0 +1,248 @@
|
||||
<script module lang="ts">
|
||||
import type { Waypoint } from "$lib/models/waypoint";
|
||||
|
||||
export type WaypointMerge = {
|
||||
incoming: Waypoint;
|
||||
existing: Waypoint;
|
||||
};
|
||||
|
||||
export type WaypointMergeOptions = {
|
||||
photos: boolean;
|
||||
title: boolean;
|
||||
description: boolean;
|
||||
icon: boolean;
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { browser } from "$app/environment";
|
||||
import { _ } from "svelte-i18n";
|
||||
import Modal from "../base/modal.svelte";
|
||||
import RadioGroup, { type RadioItem } from "../base/radio_group.svelte";
|
||||
|
||||
interface Props {
|
||||
merge?: WaypointMerge;
|
||||
oncreate?: () => void;
|
||||
onmerge?: (options: WaypointMergeOptions) => void;
|
||||
oncancel?: () => void;
|
||||
}
|
||||
|
||||
let { merge, oncreate, onmerge, oncancel }: Props = $props();
|
||||
|
||||
const waypointMergeActionItems: RadioItem[] = [
|
||||
{
|
||||
text: $_("create-waypoint-anyway"),
|
||||
value: "create",
|
||||
},
|
||||
{
|
||||
text: $_("add-to-existing-waypoint"),
|
||||
value: "merge",
|
||||
},
|
||||
];
|
||||
|
||||
let modal: Modal;
|
||||
let waypointMergeAction: "merge" | "create" = $state("create");
|
||||
let waypointMergeActionIndex = $derived(
|
||||
waypointMergeActionItems.findIndex(
|
||||
(item) => item.value === waypointMergeAction,
|
||||
),
|
||||
);
|
||||
let appendWaypointPhotos = $state(true);
|
||||
let appendWaypointTitle = $state(true);
|
||||
let appendWaypointDescription = $state(true);
|
||||
let appendWaypointIcon = $state(false);
|
||||
|
||||
export function openModal() {
|
||||
loadWaypointMergePreferences();
|
||||
modal.openModal();
|
||||
}
|
||||
|
||||
export function closeModal() {
|
||||
modal.closeModal();
|
||||
}
|
||||
|
||||
function saveDecision() {
|
||||
if (waypointMergeAction === "create") {
|
||||
oncreate?.();
|
||||
return;
|
||||
}
|
||||
|
||||
onmerge?.({
|
||||
photos: appendWaypointPhotos,
|
||||
title: appendWaypointTitle,
|
||||
description: appendWaypointDescription,
|
||||
icon: appendWaypointIcon,
|
||||
});
|
||||
}
|
||||
|
||||
function loadWaypointMergePreferences() {
|
||||
waypointMergeAction = getWaypointMergePreference("action", false)
|
||||
? "merge"
|
||||
: "create";
|
||||
appendWaypointPhotos = getWaypointMergePreference("photos", true);
|
||||
appendWaypointTitle = getWaypointMergePreference("title", true);
|
||||
appendWaypointDescription = getWaypointMergePreference(
|
||||
"description",
|
||||
true,
|
||||
);
|
||||
appendWaypointIcon = getWaypointMergePreference("icon", false);
|
||||
}
|
||||
|
||||
function getWaypointMergePreference(key: string, fallback: boolean) {
|
||||
if (!browser) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
const value = localStorage.getItem(`waypoint-merge-${key}`);
|
||||
if (value == null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return value === "true";
|
||||
}
|
||||
|
||||
function setWaypointMergePreference(key: string, value: boolean) {
|
||||
if (browser) {
|
||||
localStorage.setItem(`waypoint-merge-${key}`, value.toString());
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
id="waypoint-merge-modal"
|
||||
title={$_("nearby-waypoint-found")}
|
||||
bind:this={modal}
|
||||
>
|
||||
{#snippet content()}
|
||||
{#if merge}
|
||||
<div class="space-y-4">
|
||||
<div
|
||||
class="flex items-center gap-3 rounded-md border border-input-border p-3"
|
||||
>
|
||||
<div
|
||||
class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-surface"
|
||||
>
|
||||
<i class="fa fa-{merge.existing.icon ?? 'circle'}"></i>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-medium">
|
||||
{merge.existing.name ||
|
||||
$_("waypoints", { values: { n: 1 } })}
|
||||
</p>
|
||||
<p class="text-sm text-gray-500">
|
||||
{merge.existing.lat.toFixed(5)},
|
||||
{merge.existing.lon.toFixed(5)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
{$_("nearby-waypoint-found-text", {
|
||||
values: {
|
||||
name:
|
||||
merge.existing.name ||
|
||||
$_("waypoints", { values: { n: 1 } }),
|
||||
},
|
||||
})}
|
||||
</p>
|
||||
<RadioGroup
|
||||
name="waypoint-merge-action"
|
||||
items={waypointMergeActionItems}
|
||||
selected={waypointMergeActionIndex}
|
||||
onchange={(item) => {
|
||||
waypointMergeAction = item.value as "merge" | "create";
|
||||
setWaypointMergePreference(
|
||||
"action",
|
||||
waypointMergeAction === "merge",
|
||||
);
|
||||
}}
|
||||
></RadioGroup>
|
||||
{#if waypointMergeAction === "merge"}
|
||||
<div class="space-y-2 pl-6">
|
||||
{#if merge.incoming._photos?.length}
|
||||
<label class="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={appendWaypointPhotos}
|
||||
onchange={() =>
|
||||
setWaypointMergePreference(
|
||||
"photos",
|
||||
appendWaypointPhotos,
|
||||
)}
|
||||
/>
|
||||
<span>{$_("append-waypoint-photos")}</span>
|
||||
</label>
|
||||
{/if}
|
||||
{#if merge.incoming.name?.trim()}
|
||||
<label class="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={appendWaypointTitle}
|
||||
onchange={() =>
|
||||
setWaypointMergePreference(
|
||||
"title",
|
||||
appendWaypointTitle,
|
||||
)}
|
||||
/>
|
||||
<span>
|
||||
{merge.existing.name?.trim()
|
||||
? $_("append-waypoint-title")
|
||||
: $_("use-waypoint-title")}
|
||||
</span>
|
||||
</label>
|
||||
{/if}
|
||||
{#if merge.incoming.description?.trim()}
|
||||
<label class="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={appendWaypointDescription}
|
||||
onchange={() =>
|
||||
setWaypointMergePreference(
|
||||
"description",
|
||||
appendWaypointDescription,
|
||||
)}
|
||||
/>
|
||||
<span>
|
||||
{merge.existing.description?.trim()
|
||||
? $_("append-waypoint-description")
|
||||
: $_("use-waypoint-description")}
|
||||
</span>
|
||||
</label>
|
||||
{/if}
|
||||
{#if merge.incoming.icon &&
|
||||
merge.incoming.icon !== merge.existing.icon}
|
||||
<label class="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={appendWaypointIcon}
|
||||
onchange={() =>
|
||||
setWaypointMergePreference(
|
||||
"icon",
|
||||
appendWaypointIcon,
|
||||
)}
|
||||
/>
|
||||
<span>
|
||||
{$_("use-new-waypoint-icon")}
|
||||
<i
|
||||
class="fa fa-{merge.incoming.icon} ml-1"
|
||||
></i>
|
||||
</span>
|
||||
</label>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/snippet}
|
||||
{#snippet footer()}
|
||||
<div class="flex flex-wrap items-center gap-4">
|
||||
<button class="btn-secondary" type="button" onclick={oncancel}
|
||||
>{$_("cancel")}</button
|
||||
>
|
||||
<button class="btn-primary" type="button" onclick={saveDecision}
|
||||
>{waypointMergeAction === "create"
|
||||
? $_("save")
|
||||
: $_("continue")}</button
|
||||
>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Modal>
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
interface Props {
|
||||
children?: Snippet<[any]>;
|
||||
onsave?: (waypoint: Waypoint) => void
|
||||
onsave?: (waypoint: Waypoint) => boolean | Promise<boolean> | void
|
||||
}
|
||||
|
||||
let { children, onsave }: Props = $props();
|
||||
@@ -32,6 +32,10 @@
|
||||
modal.openModal();
|
||||
}
|
||||
|
||||
export function closeModal() {
|
||||
modal.closeModal();
|
||||
}
|
||||
|
||||
const ClientWaypointCreateSchema = WaypointCreateSchema.extend({
|
||||
_photos: z.array(z.instanceof(File)).optional(),
|
||||
});
|
||||
@@ -42,9 +46,11 @@
|
||||
initialValues: $waypoint,
|
||||
extend: validator({ schema: ClientWaypointCreateSchema }),
|
||||
onSubmit: async (form) => {
|
||||
onsave?.(form);
|
||||
const shouldClose = await onsave?.(form);
|
||||
|
||||
modal.closeModal!();
|
||||
if (shouldClose !== false) {
|
||||
modal.closeModal!();
|
||||
}
|
||||
},
|
||||
transform: (values: unknown) => {
|
||||
const v = values as any;
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "Žádná data",
|
||||
"no-description-for-now": "Zatím bez popisu",
|
||||
"no-gps-data-in-image": "Obrázek neobsahuje GPS data",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "Bez mřížky",
|
||||
"no-notifications": "Žádná upozornění",
|
||||
"no-photos-here": "Zde nejsou žádné fotky ani videa",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"activity": "{n, plural, =1 {Aktivität} other {Aktivitäten}}",
|
||||
"add-bio": "Bio hinzufügen",
|
||||
"add-entry": "Eintrag hinzufügen",
|
||||
"add-to-existing-waypoint": "Zu bestehendem Wegpunkt hinzufügen",
|
||||
"add-to-list": "Listen verwalten",
|
||||
"add-waypoint": "Wegpunkt hinzufügen",
|
||||
"added-trail-to": "Route hinzugefügt zu",
|
||||
@@ -26,6 +27,9 @@
|
||||
"api-documentation": "API Dokumentation",
|
||||
"api-tokens": "",
|
||||
"api-tokens-hint": "",
|
||||
"append-waypoint-description": "Kommentar anhängen",
|
||||
"append-waypoint-photos": "Fotos hinzufügen",
|
||||
"append-waypoint-title": "Titel anhängen",
|
||||
"apply-user-settings": "",
|
||||
"attraction": "Sehenswürdigkeit",
|
||||
"author": "Autor",
|
||||
@@ -84,10 +88,12 @@
|
||||
"confirm-publish": "Veröffentlichung bestätigen",
|
||||
"confirm-share": "Teilen bestätigen",
|
||||
"connect": "Verbinden",
|
||||
"continue": "Fortfahren",
|
||||
"contribute": "Mitwirken",
|
||||
"copy-link": "Link kopieren",
|
||||
"create-new-list": "Neue Liste erstellen",
|
||||
"create-waypoint": "Wegpunkt erstellen",
|
||||
"create-waypoint-anyway": "Trotzdem erstellen",
|
||||
"creation-date": "Erstellungsdatum",
|
||||
"crop": "Zuschneiden",
|
||||
"cross": "Querfeldein",
|
||||
@@ -286,6 +292,8 @@
|
||||
"n-years-ago": "vor {n} Jahren",
|
||||
"name": "Name",
|
||||
"near": "Nahe",
|
||||
"nearby-waypoint-found": "Wegpunkt in der Nähe gefunden",
|
||||
"nearby-waypoint-found-text": "„{name}“ liegt nah genug, um mit diesem Wegpunkt zusammengeführt zu werden. Was möchtest du tun?",
|
||||
"never": "",
|
||||
"new-list": "Neue Liste",
|
||||
"new-password": "Neues Passwort",
|
||||
@@ -301,6 +309,7 @@
|
||||
"no-data": "Keine Daten",
|
||||
"no-description-for-now": "Noch keine Beschreibung",
|
||||
"no-gps-data-in-image": "Keine GPS-Daten im Bild",
|
||||
"waypoint-cluster-error": "Wegpunkt-Gruppen konnten nicht erstellt werden",
|
||||
"no-grid": "Kein Gitter",
|
||||
"no-notifications": "Keine Benachrichtigungen",
|
||||
"no-photos-here": "Hier sind noch keine Fotos",
|
||||
@@ -457,6 +466,9 @@
|
||||
"upload-new-file": "Neue Datei hochladen",
|
||||
"uploaded": "hochgeladen",
|
||||
"uploaded-trail-to-hammerhead": "Route erfolgreich zu Hammerhead hochgeladen",
|
||||
"use-new-waypoint-icon": "Icon ersetzen",
|
||||
"use-waypoint-description": "Kommentar übernehmen",
|
||||
"use-waypoint-title": "Titel übernehmen",
|
||||
"use-hills": "Hügel einbeziehen",
|
||||
"use-roads": "Nutze Straßen",
|
||||
"username": "Nutzername",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"activity": "{n, plural, =1 {Activity} other {Activities}}",
|
||||
"add-bio": "Add Bio",
|
||||
"add-entry": "Add Entry",
|
||||
"add-to-existing-waypoint": "Add to existing waypoint",
|
||||
"add-to-list": "Manage lists",
|
||||
"add-waypoint": "Add Waypoint",
|
||||
"added-trail-to": "Added trail to",
|
||||
@@ -26,6 +27,9 @@
|
||||
"api-documentation": "API Documentation",
|
||||
"api-tokens": "API Tokens",
|
||||
"api-tokens-hint": "API Tokens can be used to grant 3rd party applications access to your wanderer account.",
|
||||
"append-waypoint-description": "Append description",
|
||||
"append-waypoint-photos": "Add photos",
|
||||
"append-waypoint-title": "Append title",
|
||||
"apply-user-settings": "Apply user settings",
|
||||
"attraction": "Attraction",
|
||||
"author": "Author",
|
||||
@@ -84,10 +88,12 @@
|
||||
"confirm-publish": "Confirm publishing",
|
||||
"confirm-share": "Confirm share",
|
||||
"connect": "Connect",
|
||||
"continue": "Continue",
|
||||
"contribute": "Contribute",
|
||||
"copy-link": "Copy Link",
|
||||
"create-new-list": "Create new list",
|
||||
"create-waypoint": "Create waypoint",
|
||||
"create-waypoint-anyway": "Create anyway",
|
||||
"creation-date": "Creation date",
|
||||
"crop": "Crop",
|
||||
"cross": "Cross",
|
||||
@@ -286,6 +292,8 @@
|
||||
"n-years-ago": "{n} years ago",
|
||||
"name": "Name",
|
||||
"near": "Near",
|
||||
"nearby-waypoint-found": "Nearby waypoint found",
|
||||
"nearby-waypoint-found-text": "\"{name}\" is close enough to merge with this waypoint. What would you like to do?",
|
||||
"never": "Never",
|
||||
"new-list": "New List",
|
||||
"new-password": "New password",
|
||||
@@ -301,6 +309,7 @@
|
||||
"no-data": "No data",
|
||||
"no-description-for-now": "No description for now",
|
||||
"no-gps-data-in-image": "No GPS data in image",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "No Grid",
|
||||
"no-notifications": "No notifications",
|
||||
"no-photos-here": "No photos or videos here",
|
||||
@@ -457,6 +466,9 @@
|
||||
"upload-new-file": "Upload new file",
|
||||
"uploaded": "uploaded",
|
||||
"uploaded-trail-to-hammerhead": "Successfully uploaded trail to Hammerhead",
|
||||
"use-new-waypoint-icon": "Replace icon",
|
||||
"use-waypoint-description": "Use description",
|
||||
"use-waypoint-title": "Use title",
|
||||
"use-hills": "Use hills",
|
||||
"use-roads": "Use Roads",
|
||||
"username": "Username",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "No datos",
|
||||
"no-description-for-now": "Ninguna descripción de momento",
|
||||
"no-gps-data-in-image": "Sin datos GPS en la imagen",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "Ninguna cuadrícula",
|
||||
"no-notifications": "No notificaciones",
|
||||
"no-photos-here": "No fotos aquí",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "Ez dago daturik",
|
||||
"no-description-for-now": "Ez dago deskribapenik",
|
||||
"no-gps-data-in-image": "Ez dago GPS daturik irudian",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "Ez dago saretarik",
|
||||
"no-notifications": "Ez dago jakinarazpenik",
|
||||
"no-photos-here": "Ez dago argazki edo bideorik",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "Pas de données",
|
||||
"no-description-for-now": "Pas de description pour le moment",
|
||||
"no-gps-data-in-image": "Aucune donnée GPS dans l'image",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "Aucune grille",
|
||||
"no-notifications": "Pas de notifications",
|
||||
"no-photos-here": "Aucune photo ici",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "No data",
|
||||
"no-description-for-now": "No description for now",
|
||||
"no-gps-data-in-image": "No GPS data in image",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "No Grid",
|
||||
"no-notifications": "No notifications",
|
||||
"no-photos-here": "No photos here",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "Nessun dato",
|
||||
"no-description-for-now": "Nessuna descrizione per il momento",
|
||||
"no-gps-data-in-image": "No GPS data in image",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "Nessuna griglia",
|
||||
"no-notifications": "Nessuna notifica",
|
||||
"no-photos-here": "Nessuna foto qui",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "Geen data",
|
||||
"no-description-for-now": "Voorlopig geen beschrijving",
|
||||
"no-gps-data-in-image": "Geen GPS data in afbeelding",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "Geen raster",
|
||||
"no-notifications": "Geen meldingen",
|
||||
"no-photos-here": "No photos here",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "Ingen data",
|
||||
"no-description-for-now": "Ingen beskrivelse ennå",
|
||||
"no-gps-data-in-image": "Ingen GPS-data i bildet",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "Ingen rutenett",
|
||||
"no-notifications": "Ingen varsler",
|
||||
"no-photos-here": "Ingen bilder eller videoer her",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "Brak danych",
|
||||
"no-description-for-now": "Nie ma jeszcze opisu",
|
||||
"no-gps-data-in-image": "No GPS data in image",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "Brak Siatki",
|
||||
"no-notifications": "Brak powiadomień",
|
||||
"no-photos-here": "Nie ma tu zdjęć",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "Sem dados",
|
||||
"no-description-for-now": "No description for now",
|
||||
"no-gps-data-in-image": "No GPS data in image",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "No Grid",
|
||||
"no-notifications": "No notifications",
|
||||
"no-photos-here": "No photos here",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "Нет данных",
|
||||
"no-description-for-now": "Пока нет описания",
|
||||
"no-gps-data-in-image": "No GPS data in image",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "Без сетки",
|
||||
"no-notifications": "Нет уведомлений",
|
||||
"no-photos-here": "Здесь нет фото/видео",
|
||||
|
||||
@@ -301,6 +301,7 @@
|
||||
"no-data": "无数据",
|
||||
"no-description-for-now": "暂无描述",
|
||||
"no-gps-data-in-image": "图像中没有GPS数据",
|
||||
"waypoint-cluster-error": "Could not create waypoint clusters",
|
||||
"no-grid": "无网格",
|
||||
"no-notifications": "没有通知",
|
||||
"no-photos-here": "No photos here",
|
||||
|
||||
@@ -2,6 +2,13 @@ interface Category {
|
||||
id: string;
|
||||
name: string;
|
||||
img: string;
|
||||
settings?: Settings | null;
|
||||
}
|
||||
|
||||
export type {Category}
|
||||
interface Settings {
|
||||
wp_merge_enabled?: boolean;
|
||||
wp_merge_radius?: number;
|
||||
}
|
||||
|
||||
export type {Category}
|
||||
export type {Settings}
|
||||
|
||||
@@ -221,17 +221,37 @@ export async function trails_create(trail: Trail, photos: File[], gpx: File | Bl
|
||||
|
||||
let model: Trail = await r.json();
|
||||
|
||||
const createdSummitLogs: SummitLog[] = [];
|
||||
for (const summitLog of trail.expand?.summit_logs_via_trail ?? []) {
|
||||
summitLog.trail = model.id!;
|
||||
await summit_logs_create(summitLog, f);
|
||||
createdSummitLogs.push(await summit_logs_create(summitLog, f));
|
||||
}
|
||||
|
||||
const createdWaypoints: Waypoint[] = [];
|
||||
for (const wp of trail.expand?.waypoints_via_trail ?? []) {
|
||||
wp.trail = model.id!;
|
||||
await waypoints_create({
|
||||
createdWaypoints.push(await waypoints_create({
|
||||
...wp,
|
||||
marker: undefined,
|
||||
}, f, user);
|
||||
}, f, user));
|
||||
}
|
||||
|
||||
if (!model.expand) {
|
||||
model.expand = {};
|
||||
}
|
||||
|
||||
if (createdSummitLogs.length) {
|
||||
model.expand.summit_logs_via_trail = [
|
||||
...(model.expand.summit_logs_via_trail ?? []),
|
||||
...createdSummitLogs,
|
||||
];
|
||||
}
|
||||
|
||||
if (createdWaypoints.length) {
|
||||
model.expand.waypoints_via_trail = [
|
||||
...(model.expand.waypoints_via_trail ?? []),
|
||||
...createdWaypoints,
|
||||
];
|
||||
}
|
||||
|
||||
return model;
|
||||
|
||||
Reference in New Issue
Block a user