mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Use zod preprocess to coerce string to number and string to boolean before performing zod validations. Using error messages on UI.
This commit is contained in:
parent
4bda219c22
commit
0c295c66b4
5 changed files with 54 additions and 32 deletions
|
|
@ -3,20 +3,28 @@
|
|||
import { boredState } from '$lib/stores/boredState';
|
||||
|
||||
export let form: ActionData;
|
||||
const errors = form?.errors;
|
||||
let submitting = $boredState?.loading;
|
||||
let minAge = +form?.minAge || 1;
|
||||
let minPlayers = +form?.minPlayers || 1;
|
||||
let maxPlayers = +form?.maxPlayers || 1;
|
||||
let exactMinPlayers = form?.exactMinPlayers || false;
|
||||
let exactMaxPlayers = form?.exactMaxPlayers || false;
|
||||
let minAge = +form?.data?.minAge || 1;
|
||||
let minPlayers = +form?.data?.minPlayers || 1;
|
||||
let maxPlayers = +form?.data?.maxPlayers || 1;
|
||||
let exactMinPlayers = Boolean(form?.data?.exactMinPlayers) || false;
|
||||
let exactMaxPlayers = Boolean(form?.data?.exactMaxPlayers) || false;
|
||||
</script>
|
||||
|
||||
<fieldset class="advanced-search" aria-busy={submitting} disabled={submitting}>
|
||||
<div>
|
||||
<label for="minAge">
|
||||
Min Age
|
||||
<input id="minAge" name="minAge" bind:value={minAge} type="number" min="1" max="120" />
|
||||
<input id="minAge" name="minAge" bind:value={minAge} type="number" min={1} max={120} />
|
||||
</label>
|
||||
{#if form?.errors?.minAge}
|
||||
<div id="minPlayers-error" class="error">
|
||||
<p aria-label={`Error: ${form?.errors?.minAge}`} class="center">
|
||||
{form?.errors?.minAge}
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
<label for="minPlayers">
|
||||
|
|
@ -26,8 +34,8 @@
|
|||
name="minPlayers"
|
||||
bind:value={minPlayers}
|
||||
type="number"
|
||||
min="1"
|
||||
max="50"
|
||||
min={1}
|
||||
max={50}
|
||||
/>
|
||||
</label>
|
||||
<label for="exactMinPlayers" style="display: flex; gap: 1rem; place-items: center;">
|
||||
|
|
@ -37,12 +45,13 @@
|
|||
type="checkbox"
|
||||
name="exactMinPlayers"
|
||||
bind:checked={exactMinPlayers}
|
||||
bind:value={exactMinPlayers}
|
||||
/>
|
||||
</label>
|
||||
{#if form?.error?.id === 'minPlayers'}
|
||||
{#if form?.errors?.minPlayers}
|
||||
<div id="minPlayers-error" class="error">
|
||||
<p aria-label={`Error: ${form.error.message}`} class="center">
|
||||
Error: {form.error.message}
|
||||
<p aria-label={`Error: ${form?.errors?.minPlayers}`} class="center">
|
||||
{form?.errors?.minPlayers}
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -55,8 +64,8 @@
|
|||
name="maxPlayers"
|
||||
bind:value={maxPlayers}
|
||||
type="number"
|
||||
min="1"
|
||||
max="50"
|
||||
min={1}
|
||||
max={50}
|
||||
/>
|
||||
</label>
|
||||
<label for="exactMaxPlayers" style="display: flex; gap: 1rem; place-items: center;">
|
||||
|
|
@ -66,6 +75,7 @@
|
|||
type="checkbox"
|
||||
name="exactMaxPlayers"
|
||||
bind:checked={exactMaxPlayers}
|
||||
bind:value={exactMaxPlayers}
|
||||
/>
|
||||
</label>
|
||||
{#if form?.error?.id === 'maxPlayers'}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
// console.log('search page data', data);
|
||||
export let form: ActionData;
|
||||
// console.log('search page form', form);
|
||||
const errors = form?.errors;
|
||||
|
||||
export let showButton: boolean = false;
|
||||
export let advancedSearch: boolean = false;
|
||||
|
|
@ -37,7 +38,7 @@
|
|||
let totalItems = form?.totalCount || data?.totalCount || 0;
|
||||
let submitting = $boredState?.loading;
|
||||
let name = form?.name || '';
|
||||
let disclosureOpen = false;
|
||||
let disclosureOpen = errors || false;
|
||||
|
||||
$: skip = (page - 1) * pageSize;
|
||||
$: showPagination = $gameStore?.length > 1;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { z } from 'zod';
|
||||
import { z, ZodNumber, ZodOptional } from 'zod';
|
||||
import zodToJsonSchema from 'zod-to-json-schema';
|
||||
|
||||
export const BoardGameSearch = z.object({
|
||||
|
|
@ -16,14 +16,30 @@ export const saved_game_schema = z.object({
|
|||
playtime: z.string()
|
||||
});
|
||||
|
||||
// https://github.com/colinhacks/zod/discussions/330
|
||||
// function IntegerString
|
||||
// <schema extends (ZodNumber | ZodOptional<ZodNumber>)>
|
||||
// (schema: schema)
|
||||
// {
|
||||
// return (
|
||||
// z.preprocess((value) => (
|
||||
// ( (typeof value === "string") ? parseInt(value, 10)
|
||||
// : (typeof value === "number") ? value
|
||||
// : undefined
|
||||
// )), schema)
|
||||
// )
|
||||
// }
|
||||
|
||||
// minPlayers: IntegerString(z.number().min(1).max(50).optional());
|
||||
|
||||
export const search_schema = z.object({
|
||||
name: z.string().trim().optional(),
|
||||
minAge: z.number().min(1).max(120).optional(),
|
||||
minPlayers: z.number().min(1).max(50).optional(),
|
||||
maxPlayers: z.number().min(1).max(50).optional(),
|
||||
exactMinAge: z.boolean().optional(),
|
||||
exactMinPlayers: z.boolean().optional(),
|
||||
exactMaxPlayers: z.boolean().optional(),
|
||||
minAge: z.preprocess((a) => parseInt(z.string().parse(a), 10), z.number().min(1).max(120).optional()),
|
||||
minPlayers: z.preprocess((a) => parseInt(z.string().parse(a), 10), z.number().min(1).max(50).optional()),
|
||||
maxPlayers: z.preprocess((a) => parseInt(z.string().parse(a), 10), z.number().min(1).max(50).optional()),
|
||||
exactMinAge: z.preprocess((a) => Boolean(a), z.boolean().optional()),
|
||||
exactMinPlayers: z.preprocess((a) => Boolean(a), z.boolean().optional()),
|
||||
exactMaxPlayers: z.preprocess((a) => Boolean(a), z.boolean().optional())
|
||||
})
|
||||
.superRefine(({ minPlayers, maxPlayers, minAge, exactMinAge, exactMinPlayers, exactMaxPlayers }, ctx) => {
|
||||
console.log({ minPlayers, maxPlayers });
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
import Random from '$lib/components/random/index.svelte';
|
||||
|
||||
export let data: PageData;
|
||||
console.log('data', data);
|
||||
export let form: ActionData;
|
||||
console.log('form', form);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export const actions: Actions = {
|
|||
console.log("In search action specific")
|
||||
// Do things in here
|
||||
const formData = Object.fromEntries(await request.formData());
|
||||
console.log('formData', formData);
|
||||
console.log('passed in limit:', formData?.limit)
|
||||
console.log('passed in skip:', formData?.skip)
|
||||
const limit = formData?.limit || 10;
|
||||
|
|
@ -26,8 +27,8 @@ export const actions: Actions = {
|
|||
const queryParams: SearchQuery = {
|
||||
order_by: 'rank',
|
||||
ascending: false,
|
||||
limit: parseInt(limit),
|
||||
skip: parseInt(skip),
|
||||
limit: +limit,
|
||||
skip: +skip,
|
||||
client_id: BOARD_GAME_ATLAS_CLIENT_ID,
|
||||
fuzzy_match: true,
|
||||
name: ''
|
||||
|
|
@ -40,14 +41,8 @@ export const actions: Actions = {
|
|||
if (random) {
|
||||
queryParams.random = random;
|
||||
} else {
|
||||
// const minAge = form.get('minAge');
|
||||
// const minPlayers = form.get('minPlayers');
|
||||
// const maxPlayers = form.get('maxPlayers');
|
||||
// const exactMinAge = form.get('exactMinAge') || false;
|
||||
// const exactMinPlayers = form.get('exactMinPlayers') || false;
|
||||
// const exactMaxPlayers = form.get('exactMaxPlayers') || false;
|
||||
|
||||
try {
|
||||
console.log('Parsed', search_schema.parse(formData))
|
||||
const {
|
||||
name,
|
||||
minAge,
|
||||
|
|
@ -58,7 +53,6 @@ export const actions: Actions = {
|
|||
exactMaxPlayers
|
||||
} = search_schema.parse(formData);
|
||||
|
||||
console.log('Parsed', search_schema.parse(formData))
|
||||
|
||||
if (minAge) {
|
||||
if (exactMinAge) {
|
||||
|
|
@ -87,7 +81,6 @@ export const actions: Actions = {
|
|||
queryParams.name = name;
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
|
||||
if (error instanceof ZodError) {
|
||||
const { fieldErrors: errors } = error.flatten();
|
||||
return invalid(400, { data: formData, errors });
|
||||
|
|
|
|||
Loading…
Reference in a new issue