refactor zo zod and felte

This commit is contained in:
Christian Beutel
2024-12-30 19:52:44 +01:00
parent 75c94a3ce4
commit 871481a84e
45 changed files with 659 additions and 1040 deletions

View File

@@ -1,41 +1,50 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
import { type SummitLog } from "$lib/models/summit_log";
import {
SummitLogCreateSchema,
} from "$lib/models/api/summit_log_schema";
import GPX from "$lib/models/gpx/gpx";
import { summitLog } from "$lib/stores/summit_log_store";
import { createForm } from "$lib/vendor/svelte-form-lib/index";
import { util } from "$lib/vendor/svelte-form-lib/util";
import { createForm } from "felte";
import { validator } from "@felte/validator-zod";
import { _ } from "svelte-i18n";
import { date, object, string } from "yup";
import { z } from "zod";
import Datepicker from "../base/datepicker.svelte";
import Modal from "../base/modal.svelte";
import Textarea from "../base/textarea.svelte";
import TrailPicker from "../trail/trail_picker.svelte";
import GPX from "$lib/models/gpx/gpx";
import PhotoPicker from "../trail/photo_picker.svelte";
import TrailPicker from "../trail/trail_picker.svelte";
import { cloneDeep } from "$lib/util/deep_util";
export let openModal: (() => void) | undefined = undefined;
export let closeModal: (() => void) | undefined = undefined;
const dispatch = createEventDispatcher();
const summitLogSchema = object<SummitLog>({
id: string().optional(),
date: date().required("Required").typeError($_("invalid-date")),
text: string().optional(),
const ClientSummitLogCreateSchema = SummitLogCreateSchema.extend({
_photos: z.array(z.instanceof(File)).optional(),
_gpx: z.instanceof(File).optional().nullable(),
expand: z
.object({
gpx_data: z.string().optional(),
})
.optional(),
});
const { form, errors, handleChange, handleSubmit } = createForm<SummitLog>({
const { form, errors, data, setFields } = createForm<
z.infer<typeof ClientSummitLogCreateSchema>
>({
initialValues: $summitLog,
validationSchema: summitLogSchema,
onSubmit: async (submittedValues) => {
if (!$form.expand.gpx_data) {
$form.gpx = "";
extend: validator({ schema: ClientSummitLogCreateSchema }),
onSubmit: async (form) => {
if (!form.expand?.gpx_data) {
form.gpx = "";
}
if (
!$form._photos?.length &&
!$form.photos?.length &&
$form.expand?.gpx_data
!form._photos?.length &&
!form.photos?.length &&
form.expand?.gpx_data
) {
const canvas = document.querySelector(
"#trail-picker-map .maplibregl-canvas",
@@ -44,25 +53,25 @@
const dataURL = canvas.toDataURL();
const response = await fetch(dataURL);
const blob = await response.blob();
$form._photos = [new File([blob], "route")];
form._photos = [new File([blob], "route")];
}
dispatch("save", submittedValues);
dispatch("save", form);
closeModal!();
},
});
$: form.set(util.cloneDeep($summitLog));
$: setFields(cloneDeep($summitLog));
$: if ($summitLog._gpx) {
$form._gpx = $summitLog._gpx;
$data._gpx = $summitLog._gpx;
}
async function handleTrailSelection(trailData: string | null) {
if (!trailData) {
$form.duration = undefined;
$form.elevation_gain = undefined;
$form.elevation_loss = undefined;
$form.distance = undefined;
$data.duration = undefined;
$data.elevation_gain = undefined;
$data.elevation_loss = undefined;
$data.distance = undefined;
return;
}
const gpxObject = await GPX.parse(trailData);
@@ -72,16 +81,15 @@
const totals = gpxObject.getTotals();
$form.duration = totals.duration / 1000;
$form.elevation_gain = totals.elevationGain;
$form.elevation_loss = totals.elevationLoss;
$form.distance = totals.distance;
$data.duration = totals.duration / 1000;
$data.elevation_gain = totals.elevationGain;
$data.elevation_loss = totals.elevationLoss;
$data.distance = totals.distance;
}
</script>
<Modal
id="summit-log-modal"
title={$form.id ? $_("edit-entry") : $_("add-entry")}
title={$data.id ? $_("edit-entry") : $_("add-entry")}
let:openModal
bind:openModal
bind:closeModal
@@ -91,15 +99,10 @@
id="summit-log-form"
slot="content"
class="modal-content space-y-4"
on:submit={handleSubmit}
use:form
>
<div class="flex">
<Datepicker
name="date"
label={$_("date")}
bind:value={$form.date}
error={$errors.date}
on:change={handleChange}
<Datepicker name="date" label={$_("date")} error={$errors.date}
></Datepicker>
</div>
<div>
@@ -108,27 +111,27 @@
</label>
<PhotoPicker
id="summitlog-photo-input"
parent={$form}
bind:photos={$form.photos}
bind:photoFiles={$form._photos}
parent={$data}
bind:photos={$data.photos}
bind:photoFiles={$data._photos}
showThumbnailControls={false}
></PhotoPicker>
</div>
<div class="flex gap-4">
<TrailPicker
bind:trailFile={$form._gpx}
bind:trailData={$form.expand.gpx_data}
label={$_("trail", { values: { n: 1 } })}
on:change={(e) => handleTrailSelection(e.detail)}
></TrailPicker>
{#if $data.expand}
<TrailPicker
bind:trailFile={$data._gpx}
bind:trailData={$data.expand.gpx_data}
label={$_("trail", { values: { n: 1 } })}
on:change={(e) => handleTrailSelection(e.detail)}
></TrailPicker>
{/if}
<div class="basis-full">
<Textarea
name="text"
extraClasses="h-28"
label={$_("text")}
bind:value={$form.text}
error={$errors.text}
on:change={handleChange}
></Textarea>
</div>
</div>