Skip to content

Commit

Permalink
Upgrade valibot and modular forms
Browse files Browse the repository at this point in the history
  • Loading branch information
knpwrs committed Dec 17, 2024
1 parent a155ece commit 4811f08
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 69 deletions.
Binary file modified apps/web-next/bun.lockb
Binary file not shown.
6 changes: 3 additions & 3 deletions apps/web-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"dependencies": {
"@fontsource-variable/roboto-mono": "^5.1.0",
"@knpwrs/envariant": "^1.1.1",
"@modular-forms/solid": "^0.20.0",
"@modular-forms/solid": "^0.25.0",
"@sentry/browser": "^7.114.0",
"@solid-primitives/autofocus": "^0.0.111",
"@solid-primitives/input-mask": "^0.2.2",
Expand Down Expand Up @@ -59,7 +59,7 @@
"tailwind-merge": "^2.5.5",
"tailwindcss": "^3.4.16",
"tiny-invariant": "^1.3.3",
"valibot": "^0.30.0",
"valibot": "^v1.0.0-beta.9",
"video.js": "^8.21.0",
"vinxi": "^0.5.1",
"xss": "^1.0.15",
Expand Down Expand Up @@ -90,7 +90,7 @@
"prettier": "^3.4.2",
"prettier-plugin-tailwindcss": "^0.6.9",
"type-fest": "^4.30.2",
"typescript": "^5.4.5",
"typescript": "^5.7.2",
"vite-plugin-solid-svg": "^0.8.1",
"wait-on": "^7.2.0"
},
Expand Down
3 changes: 2 additions & 1 deletion apps/web-next/src/components/churches/churches.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,9 @@ export default function ChurchesApp(props: {
}

onMount(() => {
invariant(mapNode!, 'Map node should be defined');
const map = new mapboxgl.Map({
container: mapNode,
container: mapNode!,
style: 'mapbox://styles/mapbox/streets-v12',
center: murica,
zoom: 4,
Expand Down
94 changes: 43 additions & 51 deletions apps/web-next/src/components/churches/searchbox/location.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
parse,
string,
unknown,
type Input,
type InferInput,
looseObject,
objectWithRest,
} from 'valibot';
import { useSearchParams } from '@solidjs/router';
import { type Optional, cn, unwrapFirst } from '../../../util';
Expand All @@ -23,41 +25,32 @@ const sessionToken = window.crypto.randomUUID();
export const murica = [-97.9222112121185, 39.3812661305678] as [number, number];
const defaultRange = '100 mi';

const suggestionSchema = object(
{
name: string(),
feature_type: string(),
address: optional(string()),
full_address: optional(string()),
place_formatted: string(),
mapbox_id: string(),
},
unknown(),
);

const locationSuggestSchema = object(
{
suggestions: array(suggestionSchema),
},
unknown(),
);

const reverseGeocodeSchema = object(
{
features: array(
object(
{
place_name: string(),
},
unknown(),
),
const suggestionSchema = looseObject({
name: string(),
feature_type: string(),
address: optional(string()),
full_address: optional(string()),
place_formatted: string(),
mapbox_id: string(),
});

const locationSuggestSchema = looseObject({
suggestions: array(suggestionSchema),
});

const reverseGeocodeSchema = looseObject({
features: array(
objectWithRest(
{
place_name: string(),
},
unknown(),
),
},
unknown(),
);
),
});

async function reverseGeocode([long, lat]: [number, number]): Promise<
Input<typeof reverseGeocodeSchema>
InferInput<typeof reverseGeocodeSchema>
> {
const res = await fetch(
`https://api.mapbox.com/geocoding/v5/mapbox.places/${long},${lat}.json?access_token=${mbAccessToken}`,
Expand All @@ -66,26 +59,25 @@ async function reverseGeocode([long, lat]: [number, number]): Promise<
return parse(reverseGeocodeSchema, await res.json());
}

const retrieveSchema = object(
{
features: array(
object(
{
properties: object(
{
coordinates: object({ longitude: number(), latitude: number() }),
},
unknown(),
),
},
unknown(),
),
const retrieveSchema = looseObject({
features: array(
objectWithRest(
{
properties: objectWithRest(
{
coordinates: object({ longitude: number(), latitude: number() }),
},
unknown(),
),
},
unknown(),
),
},
unknown(),
);
),
});

async function retrieve(id: string): Promise<Input<typeof retrieveSchema>> {
async function retrieve(
id: string,
): Promise<InferInput<typeof retrieveSchema>> {
const res = await fetch(
`https://api.mapbox.com/search/searchbox/v1/retrieve/${id}?session_token=${sessionToken}&access_token=${mbAccessToken}`,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createEffect, type ParentProps } from 'solid-js';
import invariant from 'tiny-invariant';
import { type Optional, cn } from '../../../util';

export default function ResultRow(
Expand All @@ -11,6 +12,7 @@ export default function ResultRow(
let el: HTMLLIElement;

createEffect(() => {
invariant(el!, 'ResultRow: el is undefined');
if (props.activeId === props.id) {
el.scrollIntoView({ block: 'nearest' });
}
Expand Down
6 changes: 4 additions & 2 deletions apps/web-next/src/components/churches/searchbox/searchbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default function Searchbox(props: { hidden?: Optional<Array<string>> }) {
let inputEl: HTMLInputElement;

function clearInput() {
if (inputEl) {
if (inputEl!) {
inputEl.value = '';
inputEl.focus();
}
Expand Down Expand Up @@ -246,7 +246,9 @@ export default function Searchbox(props: { hidden?: Optional<Array<string>> }) {
ref={setReference}
class="flex cursor-text flex-wrap gap-2 rounded-md px-3 py-1.5 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-600"
onClick={() => {
inputEl?.focus();
if (inputEl!) {
inputEl.focus();
}
setFloatOpen((o) => !o);
}}
>
Expand Down
2 changes: 1 addition & 1 deletion apps/web-next/src/components/comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function CommentForm(props: {
let ref: HTMLTextAreaElement;

onMount(() => {
if (ref && props.autofocus) {
if (ref! && props.autofocus) {
ref.focus();
ref.scrollIntoView();
}
Expand Down
5 changes: 5 additions & 0 deletions apps/web-next/src/components/media/player/player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import type VideoJsPlayer from 'video.js/dist/types/player';
import 'video.js/dist/video-js.css';
import { isServer } from 'solid-js/web';
import invariant from 'tiny-invariant';
import {
MediaRouteRecordViewRangesMutation,
MediaRouteRecordViewRangesMutationVariables,
Expand Down Expand Up @@ -97,6 +98,8 @@ export default function Player(props: Props) {
return;
}

invariant(videoRef!, 'player reportTimeRanges: videoRef is undefined');

try {
const res = await recordViewRanges(
id,
Expand Down Expand Up @@ -134,6 +137,8 @@ export default function Player(props: Props) {
});
}

invariant(videoRef!, 'player onMount: videoRef is undefined');

player = videojs(
videoRef,
{
Expand Down
1 change: 1 addition & 0 deletions apps/web-next/src/components/media/player/waveform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default function Waveform(props: Props) {
setBarCount(Math.floor(entry.contentRect.width / TARGET_BAR_WIDTH));
});

invariant(container!, 'waveform: container is undefined');
rob.observe(container);
});

Expand Down
22 changes: 12 additions & 10 deletions apps/web-next/src/components/settings/church-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
optional,
parse,
string,
type Input as VInput,
type InferInput,
pipe,
} from 'valibot';
import {
For,
Expand Down Expand Up @@ -54,23 +55,25 @@ import { getAuthenticatedClientOrRedirect } from '~/util/gql/server';

export const formSchema = object({
id: optional(string()),
name: string([minLength(1, 'Please enter a name for your church.')]),
slug: string([minLength(3, 'Please enter a URL name for your church.')]),
name: pipe(string(), minLength(1, 'Please enter a name for your church.')),
slug: pipe(
string(),
minLength(3, 'Please enter a URL name for your church.'),
),
description: optional(nullable(string())),
tags: optional(array(string())),
websiteUrl: optional(nullable(string())),
primaryEmail: optional(nullable(string([email()]))),
primaryEmail: optional(nullable(pipe(string(), email()))),
primaryPhoneNumber: optional(nullable(string())),
leaders: optional(
array(
object({
name: optional(nullable(string())),
type: enum_(OrganizationLeaderType),
email: optional(nullable(string([email()]))),
email: optional(nullable(pipe(string(), email()))),
phoneNumber: optional(nullable(string())),
}),
),
[],
),
addresses: optional(
array(
Expand All @@ -83,14 +86,13 @@ export const formSchema = object({
streetAddress: optional(nullable(string()), null),
}),
),
[],
),
upstreamAssociations: optional(array(string()), []),
upstreamAssociations: optional(array(string())),
});

const phoneNumberMask = createInputMask<FieldEvent>('(999) 999-9999');

type FormSchema = VInput<typeof formSchema>;
type FormSchema = InferInput<typeof formSchema>;

const upsertChurch = action(async (data: FormSchema) => {
'use server';
Expand Down Expand Up @@ -375,7 +377,7 @@ function LeadershipForm(props: {

export default function ChurchForm(props: { initialValues?: FormSchema }) {
// TODO: Why do the initial values not render properly on refresh even though they do on navigation?
const store = createFormStore({
const store = createFormStore<FormSchema>({
validate: valiForm(formSchema),
...(props.initialValues ? { initialValues: props.initialValues } : {}),
});
Expand Down
2 changes: 1 addition & 1 deletion apps/web-next/src/components/turnstile/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function TurnstileClient(
let element: HTMLDivElement;

const ready = () => {
invariant(element);
invariant(element!);
window.onloadTurnstileCallback = undefined;
window.turnstile.render(element, {
sitekey: import.meta.env['VITE_TURNSTILE_SITEKEY'],
Expand Down
1 change: 1 addition & 0 deletions apps/web-next/src/routes/(root)/upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ export default function UploadRoute() {
let formRef: HTMLFormElement;

async function submitUpsert() {
invariant(formRef!, 'formRef should be defined');
const res = await upsertAction(new FormData(formRef));
setUploadRecordId(res.upsertUploadRecord.id);
}
Expand Down

0 comments on commit 4811f08

Please sign in to comment.