Skip to content

Commit 2c4ee48

Browse files
committed
fix(webapp): show an error instead of silently resetting the new-organization form
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GtcXLfR1Q5rbczH99Bfuhh
1 parent 6c6e58e commit 2c4ee48

2 files changed

Lines changed: 27 additions & 6 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: fix
4+
---
5+
6+
When creating an organization failed, the form quietly cleared the name you typed and showed nothing, so it was easy to submit again and end up with a duplicate. The name is now kept and an error message explains what happened.

apps/webapp/app/routes/_app.orgs.new/route.tsx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { GlobeLinesIcon } from "~/assets/icons/GlobeLinesIcon";
33
import { parseWithZod } from "@conform-to/zod";
44
import { BuildingOffice2Icon } from "@heroicons/react/20/solid";
55
import { RadioGroup } from "@radix-ui/react-radio-group";
6-
import { json, redirect, type ActionFunction, type LoaderFunctionArgs } from "@remix-run/node";
6+
import { json, redirect, type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/node";
77
import { Form, useActionData, useNavigation } from "@remix-run/react";
88
import { useState } from "react";
99
import { typedjson, useTypedLoaderData } from "remix-typedjson";
@@ -24,6 +24,7 @@ import { useFaviconUrl } from "~/hooks/useFaviconUrl";
2424
import { useFeatures } from "~/hooks/useFeatures";
2525
import { createOrganization } from "~/models/organization.server";
2626
import { NewOrganizationPresenter } from "~/presenters/NewOrganizationPresenter.server";
27+
import { logger } from "~/services/logger.server";
2728
import { requireUser, requireUserId } from "~/services/session.server";
2829
import { extractDomain, faviconUrl } from "~/utils/favicon";
2930
import { organizationPath, rootPath } from "~/utils/pathBuilder";
@@ -47,7 +48,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
4748
});
4849
};
4950

50-
export const action: ActionFunction = async ({ request }) => {
51+
export const action = async ({ request }: ActionFunctionArgs) => {
5152
const user = await requireUser(request);
5253
const formData = await request.formData();
5354
const submission = parseWithZod(formData, { schema });
@@ -106,14 +107,26 @@ export const action: ActionFunction = async ({ request }) => {
106107
}
107108

108109
return redirect(organizationPath(organization));
109-
} catch (error: any) {
110-
return json({ errors: { body: error.message } }, { status: 400 });
110+
} catch (error) {
111+
logger.error("Failed to create organization", {
112+
userId: user.id,
113+
error: error instanceof Error ? error.message : error,
114+
});
115+
116+
return json(
117+
submission.reply({
118+
formErrors: [
119+
"We couldn't create your organization. Check your organization list before trying again, and if this problem persists please contact support.",
120+
],
121+
}),
122+
{ status: 400 }
123+
);
111124
}
112125
};
113126

114127
export default function NewOrganizationPage() {
115128
const { hasOrganizations } = useTypedLoaderData<typeof loader>();
116-
const lastSubmission = useActionData();
129+
const lastSubmission = useActionData<typeof action>();
117130
const { isManagedCloud } = useFeatures();
118131
const navigation = useNavigation();
119132
const [companyUrl, setCompanyUrl] = useState("");
@@ -122,7 +135,7 @@ export default function NewOrganizationPage() {
122135

123136
const [form, { orgName }] = useForm({
124137
id: "create-organization",
125-
lastResult: lastSubmission as any,
138+
lastResult: lastSubmission,
126139
onValidate({ formData }) {
127140
return parseWithZod(formData, { schema });
128141
},
@@ -228,6 +241,8 @@ export default function NewOrganizationPage() {
228241
</>
229242
)}
230243

244+
<FormError id={form.errorId}>{form.errors}</FormError>
245+
231246
<FormButtons
232247
confirmButton={
233248
<Button type="submit" variant={"primary/small"} isLoading={isLoading}>

0 commit comments

Comments
 (0)