From 7a6ed361807e5dca9ae44c622b20e4901a413bd3 Mon Sep 17 00:00:00 2001 From: Vyacheslav Matyukhin Date: Sat, 30 Nov 2024 17:51:50 -0300 Subject: [PATCH] trying next-safe-action --- packages/hub/package.json | 1 + packages/hub/src/app/new/model/NewModel.tsx | 71 +++++----- packages/hub/src/lib/server/utils.ts | 21 ++- .../src/models/actions/createModelAction.ts | 132 ++++++++++++++++++ .../createSquiggleSnippetModelAction.ts | 91 ------------ 5 files changed, 188 insertions(+), 128 deletions(-) create mode 100644 packages/hub/src/models/actions/createModelAction.ts delete mode 100644 packages/hub/src/models/actions/createSquiggleSnippetModelAction.ts diff --git a/packages/hub/package.json b/packages/hub/package.json index 22cd7b96fe..3159874aa4 100644 --- a/packages/hub/package.json +++ b/packages/hub/package.json @@ -41,6 +41,7 @@ "lodash": "^4.17.21", "next": "^15.0.3", "next-auth": "5.0.0-beta.25", + "next-safe-action": "^7.9.9", "nodemailer": "^6.9.13", "pako": "^2.1.0", "react": "19.0.0-rc-66855b96-20241106", diff --git a/packages/hub/src/app/new/model/NewModel.tsx b/packages/hub/src/app/new/model/NewModel.tsx index 7ec8e46c3c..b754fcee56 100644 --- a/packages/hub/src/app/new/model/NewModel.tsx +++ b/packages/hub/src/app/new/model/NewModel.tsx @@ -1,25 +1,14 @@ "use client"; -import { useRouter } from "next/navigation"; +import { useAction } from "next-safe-action/hooks"; import { FC, useState } from "react"; -import { FormProvider } from "react-hook-form"; +import { FormProvider, useForm } from "react-hook-form"; -import { generateSeed } from "@quri/squiggle-lang"; -import { Button, CheckboxFormField } from "@quri/ui"; -import { defaultSquiggleVersion } from "@quri/versioned-squiggle-components"; +import { Button, CheckboxFormField, useToast } from "@quri/ui"; import { SelectGroup, SelectGroupOption } from "@/components/SelectGroup"; import { H1 } from "@/components/ui/Headers"; import { SlugFormField } from "@/components/ui/SlugFormField"; -import { useServerActionForm } from "@/lib/hooks/useServerActionForm"; -import { modelRoute } from "@/lib/routes"; -import { createSquiggleSnippetModelAction } from "@/models/actions/createSquiggleSnippetModelAction"; - -const defaultCode = `/* -Describe your code here -*/ - -a = normal(2, 5) -`; +import { createModelAction } from "@/models/actions/createModelAction"; type FormShape = { slug: string | undefined; @@ -32,36 +21,42 @@ export const NewModel: FC<{ initialGroup: SelectGroupOption | null }> = ({ }) => { const [group] = useState(initialGroup); - const router = useRouter(); + const toast = useToast(); + + const { executeAsync, status } = useAction(createModelAction, { + onError: ({ error, ...rest }) => { + console.trace("onError", error, rest); + if (error.serverError) { + toast(error.serverError, "error"); + return; + } - const { form, onSubmit, inFlight } = useServerActionForm< - FormShape, - typeof createSquiggleSnippetModelAction - >({ + const slugError = error.validationErrors?.slug?._errors?.[0]; + if (slugError) { + form.setError("slug", { + message: slugError, + }); + } else { + toast("Internal error", "error"); + } + }, + }); + + const form = useForm({ mode: "onChange", defaultValues: { // don't pass `slug: ""` here, it will lead to form reset if a user started to type in a value before JS finished loading group, isPrivate: false, }, - blockOnSuccess: true, - action: createSquiggleSnippetModelAction, - formDataToVariables: (data) => ({ + }); + + const onSubmit = form.handleSubmit(async (data) => { + await executeAsync({ slug: data.slug ?? "", // shouldn't happen but satisfies Typescript groupSlug: data.group?.slug, isPrivate: data.isPrivate, - code: defaultCode, - version: defaultSquiggleVersion, - seed: generateSeed(), - }), - onCompleted: (result) => { - router.push( - modelRoute({ - owner: result.model.owner.slug, - slug: result.model.slug, - }) - ); - }, + }); }); return ( @@ -86,7 +81,11 @@ export const NewModel: FC<{ initialGroup: SelectGroupOption | null }> = ({