feat(stores): saving routes
Some checks failed
TrafficCue CI / check (push) Failing after 1m33s
TrafficCue CI / build (push) Failing after 8m32s
TrafficCue CI / build-android (push) Failing after 12m45s

This commit is contained in:
2025-09-27 20:44:11 +02:00
parent f68cff1df4
commit 004ba9047f
4 changed files with 83 additions and 46 deletions

View File

@ -0,0 +1,25 @@
<script lang="ts">
import Button from "$lib/components/ui/button/button.svelte";
import { stores } from "$lib/services/stores.svelte";
import { view } from "../view.svelte";
const saved = stores<{ name: string }>("route");
</script>
{#if saved.current.length != 0}
<div>
<h2 style="margin: 5px; margin-left: 0; font-size: 1.2em;">
Saved Routes
</h2>
<div style="display: flex; flex-direction: column; gap: 10px;">
{#each saved.current as save, _index (save.name)}
<Button
variant="secondary"
onclick={() => {
view.switch("trip", { route: save.data });
}}>{save.data.name}</Button>
{/each}
</div>
</div>
{/if}

View File

@ -16,9 +16,9 @@
import RequiresCapability from "../RequiresCapability.svelte"; import RequiresCapability from "../RequiresCapability.svelte";
import { saved } from "$lib/saved.svelte"; import { saved } from "$lib/saved.svelte";
import { m } from "$lang/messages"; import { m } from "$lang/messages";
import { getSaved } from "$lib/services/lnv";
import { view } from "../view.svelte"; import { view } from "../view.svelte";
import * as Card from "$lib/components/ui/card"; import * as Card from "$lib/components/ui/card";
import SavedRoutes from "../main/SavedRoutes.svelte";
</script> </script>
<div <div
@ -159,27 +159,8 @@
</Card.Root> </Card.Root>
{/if} {/if}
<RequiresCapability capability="saved-routes"> <RequiresCapability capability="stores">
{#await getSaved() then saved} <SavedRoutes />
{#if saved.length != 0}
<div>
<h2 style="margin: 5px; margin-left: 0; font-size: 1.2em;">
Saved Routes
</h2>
<div style="display: flex; flex-direction: column; gap: 10px;">
{#each saved as save, _index (save.name)}
<Button
variant="secondary"
onclick={() => {
view.switch("trip", { route: JSON.parse(save.data) });
}}>{save.name}</Button
>
{/each}
</div>
</div>
{/if}
{/await}
</RequiresCapability> </RequiresCapability>
<RequiresCapability capability="post"> <RequiresCapability capability="post">

View File

@ -10,20 +10,28 @@
import { RouteIcon, SaveIcon, SendIcon } from "@lucide/svelte"; import { RouteIcon, SaveIcon, SendIcon } from "@lucide/svelte";
import { map } from "../map.svelte"; import { map } from "../map.svelte";
import { m } from "$lang/messages"; import { m } from "$lang/messages";
import { deleteSaved, isSaved, putSaved } from "$lib/services/lnv";
import { view } from "../view.svelte";
import RequiresCapability from "../RequiresCapability.svelte"; import RequiresCapability from "../RequiresCapability.svelte";
import { hasStore, updateStore } from "$lib/services/stores.svelte";
let { const {
route, route,
}: { }: {
route: Trip; route: Trip;
} = $props(); } = $props();
onMount(() => { onMount(async () => {
removeAllRoutes(); removeAllRoutes();
drawRoute(route); drawRoute(route);
if(route) {
isSaved = await hasStore({
name: route.locations.map((l) => l.lat + "-" + l.lon).join(";"),
type: "route",
}); });
}
});
let isSaved = $state(false);
</script> </script>
<SidebarHeader <SidebarHeader
@ -46,25 +54,34 @@
<RouteIcon /> <RouteIcon />
{m["sidebar.trip.start"]()} {m["sidebar.trip.start"]()}
</Button> </Button>
<RequiresCapability capability="saved-routes"> <RequiresCapability capability="stores">
{#await isSaved($state.snapshot(route)) then saved}
<Button <Button
variant="secondary" variant="secondary"
onclick={async () => { onclick={async () => {
if (saved) { if (isSaved) {
await deleteSaved(saved); await updateStore({
view.back(); name: route.locations.map(l => l.lat + "-" + l.lon).join(";"),
type: "route"
}, null);
isSaved = false;
// view.back();
} else { } else {
const name = prompt("Trip name?"); const name = prompt("Trip name?");
if (!name) return; if (!name) return;
await putSaved(name, route); await updateStore({
name: route.locations.map(l => l.lat + "-" + l.lon).join(";"),
type: "route"
}, {
...route,
name
})
isSaved = true;
} }
}} }}
> >
<SaveIcon /> <SaveIcon />
{saved ? m.unsave() : m["sidebar.trip.save"]()} {isSaved ? m.unsave() : m["sidebar.trip.save"]()}
</Button> </Button>
{/await}
</RequiresCapability> </RequiresCapability>
<Button variant="secondary" disabled> <Button variant="secondary" disabled>
<SendIcon /> <SendIcon />

View File

@ -159,7 +159,13 @@ export async function updateStore(info: StoreInfo, data: object | null) {
info.type, info.type,
]); ]);
if (!store) { if (!store) {
if (data === null) return; if (data === null) {
console.warn(
"[STORES] [updateStore] Tried to delete non-existing store",
info,
);
return;
}
return await createStore(info, data); return await createStore(info, data);
} }
// Update the store data // Update the store data
@ -176,6 +182,14 @@ export async function updateStore(info: StoreInfo, data: object | null) {
return store; return store;
} }
export async function hasStore(info: StoreInfo) {
const store = await db.getFromIndex("stores", "by-name-and-type", [
info.name,
info.type,
]);
return store !== undefined;
}
// export async function store<T extends object>(info: StoreInfo) { // export async function store<T extends object>(info: StoreInfo) {
// const store = await db.getFromIndex("stores", "by-name-and-type", [info.name, info.type]); // const store = await db.getFromIndex("stores", "by-name-and-type", [info.name, info.type]);
// if (!store) { // if (!store) {