refactor zo zod and felte
This commit is contained in:
@@ -1,42 +1,58 @@
|
||||
<script lang="ts">
|
||||
import { Waypoint, waypointSchema } from "$lib/models/waypoint";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
||||
import { WaypointCreateSchema } from "$lib/models/api/waypoint_schema";
|
||||
import { convertDMSToDD } from "$lib/models/gpx/utils";
|
||||
import { show_toast } from "$lib/stores/toast_store";
|
||||
import { waypoint } from "$lib/stores/waypoint_store";
|
||||
import { cloneDeep } from "$lib/util/deep_util";
|
||||
import { icons } from "$lib/util/icon_util";
|
||||
import EXIF from "$lib/vendor/exif-js/exif";
|
||||
import { createForm } from "$lib/vendor/svelte-form-lib/index";
|
||||
import { util } from "$lib/vendor/svelte-form-lib/util";
|
||||
import { validator } from "@felte/validator-zod";
|
||||
import { createForm } from "felte";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { z } from "zod";
|
||||
import Combobox from "../base/combobox.svelte";
|
||||
import Modal from "../base/modal.svelte";
|
||||
import TextField from "../base/text_field.svelte";
|
||||
import Textarea from "../base/textarea.svelte";
|
||||
import PhotoPicker from "../trail/photo_picker.svelte";
|
||||
import { show_toast } from "$lib/stores/toast_store";
|
||||
import { convertDMSToDD } from "$lib/models/gpx/utils";
|
||||
|
||||
export let openModal: (() => void) | undefined = undefined;
|
||||
export let closeModal: (() => void) | undefined = undefined;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
const { form, errors, handleChange, handleSubmit } = createForm<Waypoint>({
|
||||
const ClientWaypointCreateSchema = WaypointCreateSchema.extend({
|
||||
_photos: z.array(z.instanceof(File)).optional(),
|
||||
});
|
||||
|
||||
const { form, errors, data, setFields } = createForm<
|
||||
z.infer<typeof ClientWaypointCreateSchema>
|
||||
>({
|
||||
initialValues: $waypoint,
|
||||
validationSchema: waypointSchema,
|
||||
onSubmit: async (submittedWaypoint) => {
|
||||
dispatch("save", submittedWaypoint);
|
||||
extend: validator({ schema: ClientWaypointCreateSchema }),
|
||||
onSubmit: async (form) => {
|
||||
dispatch("save", form);
|
||||
|
||||
closeModal!();
|
||||
},
|
||||
transform: (values: unknown) => {
|
||||
const v = values as any;
|
||||
return {
|
||||
...v,
|
||||
lat: parseFloat(v.lat),
|
||||
lon: parseFloat(v.lon),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
$: form.set(util.cloneDeep($waypoint));
|
||||
$: setFields(cloneDeep($waypoint));
|
||||
|
||||
$: filteredIcons =
|
||||
($form.icon?.length ?? 0) > 2
|
||||
($data.icon?.length ?? 0) > 2
|
||||
? icons
|
||||
.filter((i) => i.includes($form.icon ?? ""))
|
||||
.filter((i) => i.includes($data.icon ?? ""))
|
||||
.map((i) => ({ text: i, value: i, icon: i }))
|
||||
: [];
|
||||
|
||||
@@ -48,8 +64,8 @@
|
||||
const lonDir = EXIF.getTag(p, "GPSLongitudeRef");
|
||||
|
||||
if (lat && lon) {
|
||||
$form.lat = convertDMSToDD(lat, latDir);
|
||||
$form.lon = convertDMSToDD(lon, lonDir);
|
||||
setFields("lat", convertDMSToDD(lat, latDir));
|
||||
setFields("lon", convertDMSToDD(lon, lonDir));
|
||||
} else {
|
||||
show_toast({
|
||||
text: "No GPS data in image",
|
||||
@@ -63,7 +79,7 @@
|
||||
|
||||
<Modal
|
||||
id="waypoint-modal"
|
||||
title={$form.id ? $_("edit-waypoint") : $_("add-waypoint")}
|
||||
title={$data.id ? $_("edit-waypoint") : $_("add-waypoint")}
|
||||
let:openModal
|
||||
bind:openModal
|
||||
bind:closeModal
|
||||
@@ -73,50 +89,31 @@
|
||||
id="waypoint-form"
|
||||
slot="content"
|
||||
class="modal-content space-y-4"
|
||||
on:submit={handleSubmit}
|
||||
use:form
|
||||
>
|
||||
<div class="flex gap-4">
|
||||
<div class="basis-2/3">
|
||||
<TextField
|
||||
name="name"
|
||||
label={$_("name")}
|
||||
bind:value={$form.name}
|
||||
error={$errors.name}
|
||||
on:change={handleChange}
|
||||
<TextField name="name" label={$_("name")} error={$errors.name}
|
||||
></TextField>
|
||||
</div>
|
||||
|
||||
<Combobox
|
||||
name="icon"
|
||||
bind:value={$form.icon}
|
||||
icon={$form.icon}
|
||||
icon={$data.icon}
|
||||
items={filteredIcons}
|
||||
label={$_("icon")}
|
||||
on:change={handleChange}
|
||||
></Combobox>
|
||||
</div>
|
||||
|
||||
<Textarea
|
||||
name="description"
|
||||
label={$_("description")}
|
||||
bind:value={$form.description}
|
||||
error={$errors.description}
|
||||
on:change={handleChange}
|
||||
></Textarea>
|
||||
<div class="flex gap-4">
|
||||
<TextField
|
||||
name="lat"
|
||||
label={$_("latitude")}
|
||||
bind:value={$form.lat}
|
||||
error={$errors.lat}
|
||||
on:change={handleChange}
|
||||
<TextField name="lat" label={$_("latitude")} error={$errors.lat}
|
||||
></TextField>
|
||||
<TextField
|
||||
name="lon"
|
||||
label={$_("longitude")}
|
||||
bind:value={$form.lon}
|
||||
error={$errors.lat}
|
||||
on:change={handleChange}
|
||||
<TextField name="lon" label={$_("longitude")} error={$errors.lat}
|
||||
></TextField>
|
||||
</div>
|
||||
<div>
|
||||
@@ -125,10 +122,10 @@
|
||||
</label>
|
||||
<PhotoPicker
|
||||
id="waypoint-photo-input"
|
||||
parent={$form}
|
||||
parent={$data}
|
||||
on:exif={(e) => getCoordinatesFromPhoto(e.detail)}
|
||||
bind:photos={$form.photos}
|
||||
bind:photoFiles={$form._photos}
|
||||
bind:photos={$data.photos}
|
||||
bind:photoFiles={$data._photos}
|
||||
showThumbnailControls={false}
|
||||
showExifControls={true}
|
||||
></PhotoPicker>
|
||||
|
||||
Reference in New Issue
Block a user