From 871481a84e41a4c4ba7470f2ef9f24b7b337f37e Mon Sep 17 00:00:00 2001 From: Christian Beutel <> Date: Mon, 30 Dec 2024 19:52:44 +0100 Subject: [PATCH] refactor zo zod and felte --- web/package-lock.json | 76 +++-- web/package.json | 3 +- web/src/lib/components/base/datepicker.svelte | 16 +- web/src/lib/components/base/select.svelte | 2 +- web/src/lib/components/base/text_field.svelte | 16 +- web/src/lib/components/base/textarea.svelte | 16 +- .../notification/notification_dropdown.svelte | 6 +- .../components/settings/email_modal.svelte | 35 ++- .../components/settings/password_modal.svelte | 86 +++--- .../summit_log/summit_log_modal.svelte | 103 +++---- .../lib/components/trail/trail_picker.svelte | 13 +- .../components/waypoint/waypoint_modal.svelte | 81 +++--- web/src/lib/i18n/locales/de.json | 2 + web/src/lib/i18n/locales/en.json | 2 + web/src/lib/i18n/locales/fr.json | 2 + web/src/lib/i18n/locales/hu.json | 2 + web/src/lib/i18n/locales/it.json | 2 + web/src/lib/i18n/locales/nl.json | 2 + web/src/lib/i18n/locales/pl.json | 2 + web/src/lib/i18n/locales/pt.json | 2 + web/src/lib/i18n/locales/zh.json | 2 + web/src/lib/models/api/list_schema.ts | 5 +- web/src/lib/models/api/summit_log_schema.ts | 4 +- web/src/lib/models/api/trail_schema.ts | 7 +- web/src/lib/models/api/waypoint_schema.ts | 4 +- web/src/lib/models/list.ts | 6 +- web/src/lib/models/summit_log.ts | 3 +- web/src/lib/models/trail.ts | 11 +- web/src/lib/models/waypoint.ts | 15 +- web/src/lib/stores/trail_store.ts | 6 +- web/src/lib/util/deep_util.ts | 37 +++ .../lib/vendor/svelte-form-lib/create-form.js | 261 ----------------- web/src/lib/vendor/svelte-form-lib/index.d.ts | 103 ------- web/src/lib/vendor/svelte-form-lib/index.js | 1 - web/src/lib/vendor/svelte-form-lib/util.js | 134 --------- web/src/routes/api/v1/comment/[id]/+server.ts | 6 +- web/src/routes/api/v1/list/[id]/+server.ts | 6 +- .../auth/confirm-reset/[token]/+page.svelte | 46 +-- web/src/routes/auth/reset/+page.svelte | 21 +- web/src/routes/lists/edit/[id]/+page.svelte | 128 ++++---- web/src/routes/lists/edit/[id]/+page.ts | 3 +- web/src/routes/login/+page.svelte | 23 +- web/src/routes/register/+page.svelte | 45 ++- web/src/routes/settings/account/+page.svelte | 79 +++-- web/src/routes/trail/edit/[id]/+page.svelte | 274 +++++++++--------- 45 files changed, 659 insertions(+), 1040 deletions(-) create mode 100644 web/src/lib/util/deep_util.ts delete mode 100644 web/src/lib/vendor/svelte-form-lib/create-form.js delete mode 100644 web/src/lib/vendor/svelte-form-lib/index.d.ts delete mode 100644 web/src/lib/vendor/svelte-form-lib/index.js delete mode 100644 web/src/lib/vendor/svelte-form-lib/util.js diff --git a/web/package-lock.json b/web/package-lock.json index 244a3345..26e75e0f 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -8,6 +8,7 @@ "name": "wanderer", "version": "0.12.0", "dependencies": { + "@felte/validator-zod": "^1.0.18", "@fortawesome/fontawesome-free": "^6.5.1", "@sveltejs/adapter-node": "^4.0.1", "@threlte/core": "^7.1.0", @@ -22,6 +23,7 @@ "chartjs-plugin-crosshair": "^2.0.0", "chartjs-plugin-zoom": "^2.1.0", "crypto-random-string": "^5.0.0", + "felte": "^1.3.0", "heic2any": "^0.0.4", "instead": "^1.0.3", "isomorphic-xml2js": "^0.1.3", @@ -38,7 +40,6 @@ "svelte-i18n": "^4.0.0", "three": "^0.161.0", "xmldom": "^0.6.0", - "yup": "^1.3.3", "zod": "^3.24.1" }, "devDependencies": { @@ -438,6 +439,39 @@ "node": ">=12" } }, + "node_modules/@felte/common": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@felte/common/-/common-1.1.9.tgz", + "integrity": "sha512-d9e9M5FWc7AyaX/fb2I78AvwIAAA6S8ncKoTd3vYdPGQfgryl18oMU+ScM1WgFnbOBSoItdt61oaZAuRqfE4AA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@felte/core": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@felte/core/-/core-1.4.4.tgz", + "integrity": "sha512-qXEofmfc0tKvd1MOP9T1ixoI4+u0ZcUtC7JpBfb2A/lr/mhc8HrkvVWGatrGBnNovTc4lgIKWOySVVFswa4BYg==", + "dependencies": { + "@felte/common": "1.1.9" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@felte/validator-zod": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/@felte/validator-zod/-/validator-zod-1.0.18.tgz", + "integrity": "sha512-nLhy3qhCrL14iMxIHXtIH0MckZr/dmpqRd/KcqQ6HJoT2tjvv8gPpgOGJdOR15Wfzd25n/UUr3tyX7ydgXA5xQ==", + "dependencies": { + "@felte/common": "1.1.9" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "zod": "^3.2.0" + } + }, "node_modules/@formatjs/ecma402-abstract": { "version": "1.18.2", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.2.tgz", @@ -2717,6 +2751,20 @@ "reusify": "^1.0.4" } }, + "node_modules/felte": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/felte/-/felte-1.3.0.tgz", + "integrity": "sha512-J09vuOC2Hw/d+ajhT4ueVEcSU0af+tlnfwF9QWVTuOWQf286pSGS48cFYhjmS7K7hUNMRUIwXwCnHWpyasadmA==", + "dependencies": { + "@felte/core": "1.4.4" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "svelte": "^3.31.0 || ^4.0.0 || ^5.0.0" + } + }, "node_modules/fflate": { "version": "0.6.10", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", @@ -4823,11 +4871,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "node_modules/property-expr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", - "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" - }, "node_modules/protocol-buffers-schema": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", @@ -5866,11 +5909,6 @@ "next-tick": "1" } }, - "node_modules/tiny-case": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", - "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" - }, "node_modules/tiny-glob": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", @@ -5926,11 +5964,6 @@ "node": ">=8.0" } }, - "node_modules/toposort": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" - }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", @@ -6729,17 +6762,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yup": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/yup/-/yup-1.3.3.tgz", - "integrity": "sha512-v8QwZSsHH2K3/G9WSkp6mZKO+hugKT1EmnMqLNUcfu51HU9MDyhlETT/JgtzprnrnQHPWsjc6MUDMBp/l9fNnw==", - "dependencies": { - "property-expr": "^2.0.5", - "tiny-case": "^1.0.3", - "toposort": "^2.0.2", - "type-fest": "^2.19.0" - } - }, "node_modules/zod": { "version": "3.24.1", "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", diff --git a/web/package.json b/web/package.json index 73cef91e..902a993c 100644 --- a/web/package.json +++ b/web/package.json @@ -30,6 +30,7 @@ }, "type": "module", "dependencies": { + "@felte/validator-zod": "^1.0.18", "@fortawesome/fontawesome-free": "^6.5.1", "@sveltejs/adapter-node": "^4.0.1", "@threlte/core": "^7.1.0", @@ -44,6 +45,7 @@ "chartjs-plugin-crosshair": "^2.0.0", "chartjs-plugin-zoom": "^2.1.0", "crypto-random-string": "^5.0.0", + "felte": "^1.3.0", "heic2any": "^0.0.4", "instead": "^1.0.3", "isomorphic-xml2js": "^0.1.3", @@ -60,7 +62,6 @@ "svelte-i18n": "^4.0.0", "three": "^0.161.0", "xmldom": "^0.6.0", - "yup": "^1.3.3", "zod": "^3.24.1" } } diff --git a/web/src/lib/components/base/datepicker.svelte b/web/src/lib/components/base/datepicker.svelte index 39e15e6c..571c351c 100644 --- a/web/src/lib/components/base/datepicker.svelte +++ b/web/src/lib/components/base/datepicker.svelte @@ -1,8 +1,10 @@
@@ -15,15 +17,17 @@ 0} - class:bg-red-50={error.length > 0} + class:border-red-400={(error?.length ?? 0) > 0} + class:bg-input-background-error={(error?.length ?? 0) > 0} type="date" bind:value on:change />
- - {error} - + {#if error} + + {error instanceof Array ? $_(error[0]) : error} + + {/if} diff --git a/web/src/lib/components/base/select.svelte b/web/src/lib/components/base/select.svelte index 0bc9e0da..284f477e 100644 --- a/web/src/lib/components/base/select.svelte +++ b/web/src/lib/components/base/select.svelte @@ -9,8 +9,8 @@ import { createEventDispatcher } from "svelte"; export let name: string = ""; - export let value: any; export let items: SelectItem[] = []; + export let value: any = items.at(0)?.value ?? ""; export let label: string = ""; export let disabled: boolean = false; diff --git a/web/src/lib/components/base/text_field.svelte b/web/src/lib/components/base/text_field.svelte index 32a7baba..d70e0206 100644 --- a/web/src/lib/components/base/text_field.svelte +++ b/web/src/lib/components/base/text_field.svelte @@ -1,10 +1,12 @@ @@ -19,12 +21,14 @@ class="bg-input-background border border-input-border rounded-md p-3 resize-none transition-colors focus:border-input-border-focus focus:outline-none focus:ring-0 w-full {extraClasses}" {rows} {placeholder} - class:border-red-400={error.length > 0} - class:bg-red-50={error.length > 0} + class:border-red-400={(error?.length ?? 0) > 0} + class:bg-input-background-error={(error?.length ?? 0) > 0} bind:value on:change /> - - {error} - + {#if error} + + {error instanceof Array ? $_(error[0]) : error} + + {/if} diff --git a/web/src/lib/components/notification/notification_dropdown.svelte b/web/src/lib/components/notification/notification_dropdown.svelte index 8b2f5402..afda6602 100644 --- a/web/src/lib/components/notification/notification_dropdown.svelte +++ b/web/src/lib/components/notification/notification_dropdown.svelte @@ -125,13 +125,17 @@ {#each { length: 5 } as _, index} {/each} - {:else} + {:else if notifications.length} {#each notifications as notification} {/each} + {:else} +

+ No notifications +

{/if} {/if} diff --git a/web/src/lib/components/settings/email_modal.svelte b/web/src/lib/components/settings/email_modal.svelte index 850b3585..e772aff8 100644 --- a/web/src/lib/components/settings/email_modal.svelte +++ b/web/src/lib/components/settings/email_modal.svelte @@ -1,16 +1,17 @@ -
-
@@ -108,27 +111,27 @@
- handleTrailSelection(e.detail)} - > + {#if $data.expand} + handleTrailSelection(e.detail)} + > + {/if}
diff --git a/web/src/lib/components/trail/trail_picker.svelte b/web/src/lib/components/trail/trail_picker.svelte index 0ef3b002..2d05ea70 100644 --- a/web/src/lib/components/trail/trail_picker.svelte +++ b/web/src/lib/components/trail/trail_picker.svelte @@ -3,7 +3,7 @@ import { fromFile, toGeoJson } from "$lib/util/gpx_util"; import { createEventDispatcher, onMount } from "svelte"; - export let trailFile: File | null; + export let trailFile: File | undefined | null; export let trailData: string | undefined; export let label: string = ""; @@ -31,7 +31,7 @@ attributionControl: false, dragPan: false, scrollZoom: false, - preserveDrawingBuffer: true + preserveDrawingBuffer: true, }); } @@ -95,9 +95,12 @@ }, }); layer = map.getLayer(layerId) as M.LineLayerSpecification; - source = map.getSource(sourceId) as M.GeoJSONSource; - map.resize() - map.fitBounds(geojson.bbox as M.LngLatBoundsLike, {animate: false, padding: 8}); + source = map.getSource(sourceId) as M.GeoJSONSource; + map.resize(); + map.fitBounds(geojson.bbox as M.LngLatBoundsLike, { + animate: false, + padding: 8, + }); } function removeTrailFromMap() { diff --git a/web/src/lib/components/waypoint/waypoint_modal.svelte b/web/src/lib/components/waypoint/waypoint_modal.svelte index 89480dd6..e1b0d5dd 100644 --- a/web/src/lib/components/waypoint/waypoint_modal.svelte +++ b/web/src/lib/components/waypoint/waypoint_modal.svelte @@ -1,42 +1,58 @@ {$form.id ? `${$form.name} | ${$_("edit")}` : $_("new-list")} | wanderer{$formData.id ? `${$formData.name} | ${$_("edit")}` : $_("new-list")} | + wanderer @@ -235,7 +267,7 @@

{$page.params.id === "new" ? $_("new-list") : $_("edit-list")} @@ -270,23 +302,15 @@ > - - +

{$_("trail", { values: { n: 2 } })}

@@ -296,8 +320,8 @@ placeholder="{$_('search-trails')}..." items={searchDropdownItems} > - {#if $form.expand?.trails?.length} - {#each $form.expand?.trails ?? [] as trail, i} + {#if $formData.expand?.trails?.length} + {#each $formData.expand?.trails ?? [] as trail, i}
{/if} - {#if i < $form.expand?.trails?.length - 1} + {#if i < $formData.expand?.trails?.length - 1}
-
+
{#if editingBasicInfo} @@ -708,75 +712,63 @@

{$_("distance")}

{formatDistance($form.distance)}{formatDistance($formData.distance)}

{$_("est-duration")}

{formatTimeHHMM($form.duration)}{formatTimeHHMM($formData.duration)}

{$_("elevation-gain")}

{formatElevation($form.elevation_gain)}{formatElevation($formData.elevation_gain)}

{$_("elevation-loss")}

{formatElevation($form.elevation_loss)}{formatElevation($formData.elevation_loss)}
{/if} - - -
- + - -
- +

{$_("waypoints", { values: { n: 2 } })}

    - {#each $form.expand?.waypoints ?? [] as waypoint, i} + {#each $formData.expand?.waypoints ?? [] as waypoint, i}
  • openMarkerPopup(waypoint)}> {$_("photos")}

    {$_("summit-book")}

      - {#each $form.expand?.summit_logs ?? [] as log, i} + {#each $formData.expand?.summit_logs ?? [] as log, i}
    • {#each data.lists.items as list} - {#if $form.id && list.trails?.includes($form.id)} + {#if $formData.id && list.trails?.includes($formData.id)}
      @@ -873,7 +863,7 @@