From 67b28cac065ea7a8d4a80bc0832fa564e09b89f5 Mon Sep 17 00:00:00 2001 From: Gildas Garcia <1122076+djhi@users.noreply.github.com> Date: Tue, 25 Aug 2026 12:20:10 +0200 Subject: [PATCH] Improve validation, add notes --- .../SignIn/LostAccountAccessForm.tsx | 92 ++++++++++++------- .../misc/create-account-recovery-request.ts | 28 +++++- 2 files changed, 83 insertions(+), 37 deletions(-) diff --git a/apps/studio/components/interfaces/SignIn/LostAccountAccessForm.tsx b/apps/studio/components/interfaces/SignIn/LostAccountAccessForm.tsx index ffcb60a4010..f60cf7e5eaf 100644 --- a/apps/studio/components/interfaces/SignIn/LostAccountAccessForm.tsx +++ b/apps/studio/components/interfaces/SignIn/LostAccountAccessForm.tsx @@ -5,7 +5,7 @@ import Link from 'next/link' import { useRef, useState } from 'react' import { SubmitHandler, useForm } from 'react-hook-form' import { toast } from 'sonner' -import { Button, Calendar, Form, FormControl, FormField, Input, Separator } from 'ui' +import { Button, Calendar, Form, FormControl, FormField, Input, Separator, Textarea } from 'ui' import { Admonition } from 'ui-patterns/Admonition' import { DatePicker, @@ -18,21 +18,20 @@ import { SingleValueFieldArray } from 'ui-patterns/form/SingleValueFieldArray/Si import * as z from 'zod' import { useCreateAccountRecoveryRequestMutation } from '@/data/misc/create-account-recovery-request' -import { BASE_PATH } from '@/lib/constants' const lostAccountSchema = z.object({ email: z.string().min(1, 'Please provide an email address').email('Must be a valid email'), - organization: z.string().min(1, 'Please provide an organization name or id'), - projectIds: z.array( + organization: z.string(), + projectRefs: z.array( z.object({ value: z.string().optional(), }) ), invoices: z.array( z.object({ - number: z.string().min(1, 'Please enter the invoice number').optional(), - amount: z.string().min(1, 'Please enter the invoice amount').optional(), - date: z.date().optional(), + number: z.string().optional(), + amount: z.union([z.literal(''), z.coerce.number()]).optional(), + issueDate: z.date().optional(), }) ), members: z.array( @@ -40,6 +39,7 @@ const lostAccountSchema = z.object({ value: z.union([z.literal(''), z.string().email('Must be a valid email')]), }) ), + notes: z.string().optional(), }) type LostAccountAccessFormData = z.infer @@ -56,14 +56,16 @@ export const LostAccountAccessFormWizard = () => { const ConfirmAccountRecoveryRequest = ({ email }: { email: string }) => { return ( - - Supabase will never ask you for your password, a token, an API key, or a database connection - string during account recovery — by email, in this flow, or anywhere else.{' '} - What we will and won't ask for. + +

+ If elligible, you'll get an email with next steps. This can take a little while — there's + nothing else to do here right now +

+

+ Supabase will never ask you for your password, a token, an API key, or a database connection + string during account recovery — by email, in this flow, or anywhere else.{' '} + What we will and won't ask for. +

) } @@ -77,7 +79,7 @@ const LostAccountAccessForm = ({ onSuccess }: { onSuccess: (email: string) => vo defaultValues: { email: '', organization: '', - projectIds: [{ value: '' }], + projectRefs: [{ value: '' }], members: [{ value: '' }], }, }) @@ -101,19 +103,22 @@ const LostAccountAccessForm = ({ onSuccess }: { onSuccess: (email: string) => vo token = captchaResponse?.response ?? null } - // TODO: remove this (for dev purpose until backend is ready) - return onSuccess(data.email) + const projectRefs = data.projectRefs.map((p) => p.value).filter((p) => isNotEmpty(p)) + const memberEmails = data.members.map((m) => m.value).filter((p) => isNotEmpty(p)) - // TODO: restore this (for dev purpose until backend is ready) - // createAccountRecoveryRequest({ - // email: data.email, - // hcaptchaToken: token, - // redirectTo: `${ - // process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview' - // ? location.origin - // : process.env.NEXT_PUBLIC_SITE_URL - // }${BASE_PATH}/reset-password`, - // }) + createAccountRecoveryRequest({ + email: data.email, + organization: data.organization, + projectRefs, + invoices: data.invoices.map((i) => ({ + amount: i.amount != '' ? i.amount : undefined, + number: i.number, + issueDate: i.issueDate != null ? format(i.issueDate, 'yyyy-MM-dd') : undefined, + })), + memberEmails, + notes: data.notes, + hcaptchaToken: token, + }) } return ( @@ -160,7 +165,7 @@ const LostAccountAccessForm = ({ onSuccess }: { onSuccess: (email: string) => vo ( vo > ({ value: '' })} placeholder="hpjxqfdtriqhiwoqrdyz" @@ -231,7 +236,7 @@ const LostAccountAccessForm = ({ onSuccess }: { onSuccess: (email: string) => vo render={({ field }) => ( Amount}> - + )} @@ -242,14 +247,14 @@ const LostAccountAccessForm = ({ onSuccess }: { onSuccess: (email: string) => vo render={({ field }) => ( Amount}> - + )} /> ( Date}> @@ -274,7 +279,7 @@ const LostAccountAccessForm = ({ onSuccess }: { onSuccess: (email: string) => vo /> ( Date}> @@ -323,6 +328,21 @@ const LostAccountAccessForm = ({ onSuccess }: { onSuccess: (email: string) => vo )} /> + ( + + +