Handle invalid error in the request form

Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
Émile Ré
2025-12-15 12:43:09 +01:00
parent 64d2ecee59
commit 893617ef51
5 changed files with 60 additions and 6 deletions

View File

@@ -58,6 +58,18 @@ export class ForbiddenError extends Error {
} }
} }
export class InvalidError extends Error {
field?: string;
cause?: string;
constructor(message?: string, field?: string, cause?: string) {
super(message || "INVALID");
this.name = "InvalidError";
this.field = field;
this.cause = cause;
}
}
export function buildEndpoint(path: string): string { export function buildEndpoint(path: string): string {
const host = import.meta.env.VITE_API_URL; const host = import.meta.env.VITE_API_URL;
@@ -91,6 +103,9 @@ const hasUnauthorizedError = (error: GraphQLError) =>
const hasForbiddenError = (error: GraphQLError) => const hasForbiddenError = (error: GraphQLError) =>
error.extensions?.code == "FORBIDDEN"; error.extensions?.code == "FORBIDDEN";
const hasInvalidError = (error: GraphQLError) =>
error.extensions?.code == "INVALID_REQUEST";
const fetchRelay: FetchFunction = async ( const fetchRelay: FetchFunction = async (
request, request,
variables, variables,
@@ -183,6 +198,15 @@ const fetchRelay: FetchFunction = async (
if (forbiddenError) { if (forbiddenError) {
throw new ForbiddenError(forbiddenError.message); throw new ForbiddenError(forbiddenError.message);
} }
const invalidError = errors.find(hasInvalidError);
if (invalidError) {
throw new InvalidError(
invalidError.message,
invalidError.extensions.field as string ?? "",
invalidError.extensions.cause as string ?? "",
);
}
} }
return json; return json;

View File

@@ -17,6 +17,7 @@ import { useMutationWithToasts } from "/hooks/useMutationWithToast";
import { useTrustCenter } from "/hooks/useTrustCenter"; import { useTrustCenter } from "/hooks/useTrustCenter";
import { type FormEventHandler, type PropsWithChildren } from "react"; import { type FormEventHandler, type PropsWithChildren } from "react";
import { useIsAuthenticated } from "/hooks/useIsAuthenticated.ts"; import { useIsAuthenticated } from "/hooks/useIsAuthenticated.ts";
import { InvalidError } from "/providers/RelayProviders";
type Props = PropsWithChildren<{ type Props = PropsWithChildren<{
documentId?: string; documentId?: string;
@@ -40,7 +41,7 @@ export function RequestAccessDialog({
const trustCenter = useTrustCenter(); const trustCenter = useTrustCenter();
const { toast } = useToast(); const { toast } = useToast();
const { __ } = useTranslate(); const { __ } = useTranslate();
const { handleSubmit, register } = useFormWithSchema(schema, { const { handleSubmit, register, setError, formState } = useFormWithSchema(schema, {
defaultValues: { defaultValues: {
name: "", name: "",
email: "", email: "",
@@ -62,7 +63,11 @@ export function RequestAccessDialog({
dialogRef.current?.close(); dialogRef.current?.close();
}) })
.catch((error) => { .catch((error) => {
console.error(error); if (error instanceof InvalidError) {
if (error.field === "email") {
setError(error.field, {message: error.message})
}
}
toast({ toast({
title: __("Error"), title: __("Error"),
description: __("Cannot request access"), description: __("Cannot request access"),
@@ -109,6 +114,7 @@ export function RequestAccessDialog({
placeholder="john.doe@acme.com" placeholder="john.doe@acme.com"
{...register("email")} {...register("email")}
type="email" type="email"
error={formState.errors.email?.message}
/> />
</div> </div>
)} )}

View File

@@ -16,6 +16,18 @@ export class UnAuthenticatedError extends Error {
} }
} }
export class InvalidError extends Error {
field?: string;
cause?: string;
constructor(message?: string, field?: string, cause?: string) {
super(message || "INVALID");
this.name = "InvalidError";
this.field = field;
this.cause = cause;
}
}
export class InternalServerError extends Error { export class InternalServerError extends Error {
constructor() { constructor() {
super("INTERNAL_SERVER_ERROR"); super("INTERNAL_SERVER_ERROR");
@@ -47,6 +59,9 @@ export function buildEndpoint(path: string): string {
const hasUnauthenticatedError = (error: GraphQLError) => const hasUnauthenticatedError = (error: GraphQLError) =>
error.extensions?.code == "UNAUTHENTICATED"; error.extensions?.code == "UNAUTHENTICATED";
const hasInvalidError = (error: GraphQLError) =>
error.extensions?.code == "INVALID_REQUEST";
const fetchRelay: FetchFunction = async ( const fetchRelay: FetchFunction = async (
request, request,
variables, variables,
@@ -125,6 +140,15 @@ const fetchRelay: FetchFunction = async (
throw new UnAuthenticatedError(); throw new UnAuthenticatedError();
} }
const invalidError = errors.find(hasInvalidError);
if (invalidError) {
throw new InvalidError(
invalidError.message,
invalidError.extensions.field as string ?? "",
invalidError.extensions.cause as string ?? "",
);
}
throw new Error(`Error fetching GraphQL query '${request.name}'`); throw new Error(`Error fetching GraphQL query '${request.name}'`);
} }

View File

@@ -58,9 +58,9 @@ const (
func (tcar *TrustCenterAccessRequest) Validate() error { func (tcar *TrustCenterAccessRequest) Validate() error {
v := validator.New() v := validator.New()
v.Check(tcar.Email, "email", validator.NotOneOfSlice([]string{})) v.Check(tcar.Email, "email", validator.NotBlacklisted())
return nil return v.Error()
} }
func (s TrustCenterAccessService) ValidateToken( func (s TrustCenterAccessService) ValidateToken(
@@ -88,7 +88,7 @@ func (s TrustCenterAccessService) Request(
req *TrustCenterAccessRequest, req *TrustCenterAccessRequest,
) (*coredata.TrustCenterAccess, error) { ) (*coredata.TrustCenterAccess, error) {
if err := req.Validate(); err != nil { if err := req.Validate(); err != nil {
return nil, fmt.Errorf("invalid request arguments") return nil, fmt.Errorf("invalid request arguments: %w", err)
} }
now := time.Now() now := time.Now()

View File

@@ -37,7 +37,7 @@ func NotBlacklisted() ValidatorFunc {
if err == nil { if err == nil {
return newValidationError( return newValidationError(
ErrorCodeInvalidEnum, ErrorCodeInvalidEmail,
"must not be blacklisted", "must not be blacklisted",
) )
} }