diff --git a/apps/webapp/app/routes/account._index/route.tsx b/apps/webapp/app/routes/account._index/route.tsx
index 99ef9b87bb..3becdb99f1 100644
--- a/apps/webapp/app/routes/account._index/route.tsx
+++ b/apps/webapp/app/routes/account._index/route.tsx
@@ -22,6 +22,7 @@ import { useUser } from "~/hooks/useUser";
import { redirectWithSuccessMessage } from "~/models/message.server";
import { updateUser } from "~/models/user.server";
import { requireUserId } from "~/services/session.server";
+import { emailSchema, MAX_EMAIL_LENGTH } from "~/utils/emailValidation";
import { accountPath } from "~/utils/pathBuilder";
export const meta: MetaFunction = () => {
@@ -42,30 +43,31 @@ function createSchema(
.string({ required_error: "You must enter a name" })
.min(2, "Your name must be at least 2 characters long")
.max(50),
- email: z
- .string()
- .email()
- .superRefine((email, ctx) => {
- if (constraints.isEmailUnique === undefined) {
- //client-side validation skips this
+ email: emailSchema.superRefine((email, ctx) => {
+ if (email.length > MAX_EMAIL_LENGTH) {
+ return;
+ }
+
+ if (constraints.isEmailUnique === undefined) {
+ //client-side validation skips this
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: conformZodMessage.VALIDATION_UNDEFINED,
+ });
+ } else {
+ // Tell zod this is an async validation by returning the promise
+ return constraints.isEmailUnique(email).then((isUnique) => {
+ if (isUnique) {
+ return;
+ }
+
ctx.addIssue({
code: z.ZodIssueCode.custom,
- message: conformZodMessage.VALIDATION_UNDEFINED,
+ message: "Email is already being used by a different account",
});
- } else {
- // Tell zod this is an async validation by returning the promise
- return constraints.isEmailUnique(email).then((isUnique) => {
- if (isUnique) {
- return;
- }
-
- ctx.addIssue({
- code: z.ZodIssueCode.custom,
- message: "Email is already being used by a different account",
- });
- });
- }
- }),
+ });
+ }
+ }),
marketingEmails: z.preprocess((value) => value === "on", z.boolean()),
});
}
@@ -177,6 +179,7 @@ export default function Page() {
diff --git a/apps/webapp/app/routes/confirm-basic-details.tsx b/apps/webapp/app/routes/confirm-basic-details.tsx
index 9187823a73..ca14b53f0c 100644
--- a/apps/webapp/app/routes/confirm-basic-details.tsx
+++ b/apps/webapp/app/routes/confirm-basic-details.tsx
@@ -27,6 +27,7 @@ import { useUser } from "~/hooks/useUser";
import { redirectWithSuccessMessage } from "~/models/message.server";
import { updateUser } from "~/models/user.server";
import { requireUserId } from "~/services/session.server";
+import { emailSchema, MAX_EMAIL_LENGTH } from "~/utils/emailValidation";
import { rootPath } from "~/utils/pathBuilder";
import { getVercelInstallParams } from "~/v3/vercel";
@@ -72,29 +73,30 @@ function createSchema(
return z
.object({
name: z.string().min(3, "Your name must be at least 3 characters").max(50),
- email: z
- .string()
- .email()
- .superRefine((email, ctx) => {
- if (constraints.isEmailUnique === undefined) {
+ email: emailSchema.superRefine((email, ctx) => {
+ if (email.length > MAX_EMAIL_LENGTH) {
+ return;
+ }
+
+ if (constraints.isEmailUnique === undefined) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: conformZodMessage.VALIDATION_UNDEFINED,
+ });
+ } else {
+ return constraints.isEmailUnique(email).then((isUnique) => {
+ if (isUnique) {
+ return;
+ }
+
ctx.addIssue({
code: z.ZodIssueCode.custom,
- message: conformZodMessage.VALIDATION_UNDEFINED,
- });
- } else {
- return constraints.isEmailUnique(email).then((isUnique) => {
- if (isUnique) {
- return;
- }
-
- ctx.addIssue({
- code: z.ZodIssueCode.custom,
- message: "Email is already being used by a different account",
- });
+ message: "Email is already being used by a different account",
});
- }
- }),
- confirmEmail: z.string(),
+ });
+ }
+ }),
+ confirmEmail: emailSchema,
referralSource: z.string().optional(),
referralSourceOther: z.string().optional(),
role: z.string().optional(),
@@ -290,6 +292,7 @@ export default function Page() {
{
setEnteredEmail(e.target.value);
@@ -306,6 +309,7 @@ export default function Page() {
{
+ it("accepts an email at the maximum length", () => {
+ expect(emailSchema.safeParse(emailWithLength(MAX_EMAIL_LENGTH)).success).toBe(true);
+ });
+
+ it("rejects an email over the maximum length", () => {
+ const result = emailSchema.safeParse(emailWithLength(MAX_EMAIL_LENGTH + 1));
+
+ expect(result.success).toBe(false);
+ if (result.success) {
+ throw new Error("Expected an overlong email to be rejected");
+ }
+
+ expect(result.error.issues).toContainEqual(
+ expect.objectContaining({
+ message: `Email must be ${MAX_EMAIL_LENGTH} characters or fewer`,
+ })
+ );
+ });
+});