feat(stores): sync vehicles
Some checks failed
TrafficCue CI / check (push) Failing after 1m32s
TrafficCue CI / build (push) Failing after 8m32s
TrafficCue CI / build-android (push) Failing after 13m18s

This commit is contained in:
2025-09-27 13:28:52 +02:00
parent b712966cf7
commit b78f1aab06
4 changed files with 34 additions and 27 deletions

View File

@ -10,10 +10,9 @@
} from "@lucide/svelte"; } from "@lucide/svelte";
import Button, { buttonVariants } from "../ui/button/button.svelte"; import Button, { buttonVariants } from "../ui/button/button.svelte";
import { import {
addVehicle,
isValidFuel, isValidFuel,
selectVehicle, selectVehicle,
setVehicles,
vehicles,
type Vehicle, type Vehicle,
type VehicleType, type VehicleType,
} from "$lib/vehicles/vehicles.svelte"; } from "$lib/vehicles/vehicles.svelte";
@ -183,9 +182,10 @@
alert(m["vehicles.add.errors.select-fuel"]()); alert(m["vehicles.add.errors.select-fuel"]());
return; return;
} }
setVehicles([...vehicles, vehicle]); // setVehicles([...vehicles.current, vehicle]);
addVehicle(vehicle);
selectVehicle(vehicle); selectVehicle(vehicle);
location.reload(); // TODO // location.reload(); // TODO
}} }}
> >
<SaveIcon /> <SaveIcon />

View File

@ -55,18 +55,18 @@
> >
</Drawer.Header> </Drawer.Header>
<div class="p-4 pt-0 flex flex-col gap-2"> <div class="p-4 pt-0 flex flex-col gap-2">
{#each vehicles as vehicle (vehicle.name)} {#each vehicles.current as vehicle (vehicle.name)}
<Button <Button
variant={selectedVehicle() === vehicle ? "default" : "secondary"} variant={selectedVehicle() === vehicle.data ? "default" : "secondary"}
class="w-full p-5" class="w-full p-5"
onclick={() => { onclick={() => {
selectVehicle(vehicle); selectVehicle(vehicle.data);
open = false; open = false;
}} }}
> >
{@const Icon = getVehicleIcon(vehicle.type)} {@const Icon = getVehicleIcon(vehicle.data.type)}
<Icon /> <Icon />
{vehicle.name} {vehicle.data.name}
</Button> </Button>
{/each} {/each}

View File

@ -17,6 +17,12 @@ export interface StoreInfo {
name: string; name: string;
type: StoreType; type: StoreType;
} }
export interface WrappedValue<T> {
current: T;
}
export type StoreValue<T> = {
data: T;
} & Omit<Store, "data">;
interface TCDB extends DBSchema { interface TCDB extends DBSchema {
stores: { stores: {
@ -145,25 +151,25 @@ export async function updateStore(info: StoreInfo, data: object | null) {
// return state; // return state;
// } // }
export function stores<T extends object>(type: StoreType) { export function stores<T extends object>(type: StoreType): WrappedValue<StoreValue<T>[]> {
const state = $state<T[]>([]); const state = $state<StoreValue<T>[]>([]);
eventTarget.addEventListener("store-updated", async (event) => { eventTarget.addEventListener("store-updated", async (event) => {
const customEvent = event as CustomEvent; const customEvent = event as CustomEvent;
const updatedStore = customEvent.detail as Store; const updatedStore = customEvent.detail as Store;
if(updatedStore.type === type) { if(updatedStore.type === type) {
const stores = await db.getAllFromIndex("stores", "by-type", type); const stores = await db.getAllFromIndex("stores", "by-type", type);
state.splice(0, state.length, ...(stores.map(store => JSON.parse(store.data) as T).filter(store => store !== null))); state.splice(0, state.length, ...(stores.map(store => ({ ...store, data: JSON.parse(store.data) as T })).filter(store => store.data !== null)));
} }
}); });
(async () => { (async () => {
const stores = await db.getAllFromIndex("stores", "by-type", type); const stores = await db.getAllFromIndex("stores", "by-type", type);
state.splice(0, state.length, ...(stores.map(store => JSON.parse(store.data) as T).filter(store => store !== null))); state.splice(0, state.length, ...(stores.map(store => ({ ...store, data: JSON.parse(store.data) as T })).filter(store => store.data !== null)));
})(); })();
return { return {
get current() { get current() {
return state; return state;
}, },
set current(newValue: T[]) { set current(newValue: StoreValue<T>[]) {
state.splice(0, state.length, ...newValue); state.splice(0, state.length, ...newValue);
} }
} }

View File

@ -1,4 +1,5 @@
import { m } from "$lang/messages"; import { m } from "$lang/messages";
import { stores, updateStore, type StoreValue, type WrappedValue } from "$lib/services/stores.svelte";
/* /*
Valhalla costing: Valhalla costing:
@ -71,11 +72,7 @@ export const DefaultVehicle: Vehicle = {
interface StateValue<T> { interface StateValue<T> {
v: T; v: T;
} }
export const vehicles: Vehicle[] = $state( export const vehicles: WrappedValue<StoreValue<Vehicle>[]> = stores("vehicle");
localStorage.getItem("vehicles")
? JSON.parse(localStorage.getItem("vehicles")!)
: [],
);
export const selectedVehicleIdx: StateValue<number | null> = $state({ export const selectedVehicleIdx: StateValue<number | null> = $state({
v: localStorage.getItem("selectedVehicle") v: localStorage.getItem("selectedVehicle")
? parseInt(localStorage.getItem("selectedVehicle")!) ? parseInt(localStorage.getItem("selectedVehicle")!)
@ -83,23 +80,27 @@ export const selectedVehicleIdx: StateValue<number | null> = $state({
}); });
export const selectedVehicle: () => Vehicle | null = () => { export const selectedVehicle: () => Vehicle | null = () => {
return ( return (
vehicles[selectedVehicleIdx.v !== null ? selectedVehicleIdx.v : 0] || null vehicles.current[selectedVehicleIdx.v !== null ? selectedVehicleIdx.v : 0]?.data ?? null
); );
}; };
export function setVehicles(_vehicles: Vehicle[]) { // export function setVehicles(_vehicles: Vehicle[]) {
// vehicles = _vehicles; // // vehicles = _vehicles;
// Hack to update without reassigning the array // // Hack to update without reassigning the array
vehicles.length = 0; // vehicles.current.length = 0;
_vehicles.forEach((vehicle) => vehicles.push(vehicle)); // // _vehicles.forEach((vehicle) => vehicles.current.push({ data: vehicle }));
localStorage.setItem("vehicles", JSON.stringify(vehicles)); // // localStorage.setItem("vehicles", JSON.stringify(vehicles));
// }
export async function addVehicle(vehicle: Vehicle) {
await updateStore({ name: vehicle.name, type: "vehicle" }, vehicle);
} }
export function selectVehicle(vehicle: Vehicle | null) { export function selectVehicle(vehicle: Vehicle | null) {
if (vehicle == null) { if (vehicle == null) {
selectedVehicleIdx.v = null; selectedVehicleIdx.v = null;
} else { } else {
selectedVehicleIdx.v = vehicles.findIndex((v) => v.name === vehicle.name); selectedVehicleIdx.v = vehicles.current.findIndex((v) => v.name === vehicle.name);
if (selectedVehicleIdx.v === -1) { if (selectedVehicleIdx.v === -1) {
selectedVehicleIdx.v = null; selectedVehicleIdx.v = null;
} }