Develop
This commit is contained in:
parent
9a455af203
commit
8a0ffb2e8a
@ -63,7 +63,62 @@ export function isShortDomainError(error: MaybeError): error is ShortDomainError
|
||||
return typeof error === 'string'
|
||||
}
|
||||
|
||||
/**
|
||||
* Express-validator error format
|
||||
*/
|
||||
interface ValidationError {
|
||||
type: string
|
||||
value: string
|
||||
msg: string
|
||||
path: string
|
||||
location: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Service error format (e.g., ZeroBounce)
|
||||
*/
|
||||
interface ServiceErrorResponse {
|
||||
status: 'error'
|
||||
message: string
|
||||
}
|
||||
|
||||
function isValidationErrorArray(data: unknown): data is ValidationError[] {
|
||||
return Array.isArray(data) && data.length > 0 && 'msg' in data[0] && 'path' in data[0]
|
||||
}
|
||||
|
||||
function isServiceErrorResponse(data: unknown): data is ServiceErrorResponse {
|
||||
return typeof data === 'object' && data !== null && 'status' in data && 'message' in data
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract error message from ApiError
|
||||
* Handles multiple formats:
|
||||
* 1. { errors: [{ msg, path }] } - express-validator
|
||||
* 2. { status: "error", message: "..." } - service errors (ZeroBounce)
|
||||
* 3. { error: "..." } - single error
|
||||
* 4. { errors: { base: [...] } } - base errors
|
||||
*/
|
||||
export function extractErrorMessage(apiError: ApiError): string {
|
||||
const responseData = apiError.responseData
|
||||
|
||||
// Check for service error format: { status: "error", message: "..." }
|
||||
if (isServiceErrorResponse(responseData)) {
|
||||
return responseData.message
|
||||
}
|
||||
|
||||
// Check for express-validator format: { errors: [{ msg, path }] }
|
||||
if (responseData && typeof responseData === 'object' && 'errors' in responseData) {
|
||||
const errors = (responseData as { errors: unknown }).errors
|
||||
if (isValidationErrorArray(errors)) {
|
||||
const emailError = errors.find(e => e.path === 'email')
|
||||
if (emailError) {
|
||||
return emailError.msg
|
||||
}
|
||||
return errors[0].msg
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to original logic for other formats
|
||||
const body = isSingleErrorResponse(apiError.body) ? [apiError.body.error] : apiError.body.errors
|
||||
const errors = Array.isArray(body) ? body : body.base
|
||||
const firstError = errors.at(0)
|
||||
@ -78,3 +133,24 @@ export function extractErrorMessage(apiError: ApiError): string {
|
||||
}
|
||||
return firstError.title
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract email suggestion from error message
|
||||
* Parses "Did you mean user@gmail.com?" format
|
||||
*/
|
||||
export function extractEmailSuggestion(apiError: ApiError): string | null {
|
||||
const responseData = apiError.responseData
|
||||
|
||||
if (responseData && typeof responseData === 'object' && 'errors' in responseData) {
|
||||
const errors = (responseData as { errors: unknown }).errors
|
||||
if (isValidationErrorArray(errors)) {
|
||||
const emailError = errors.find(e => e.path === 'email')
|
||||
if (emailError) {
|
||||
const match = emailError.msg.match(/Did you mean (.+)\?/)
|
||||
return match ? match[1] : null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { ErrorPayload, useApi } from "@/api";
|
||||
import { ApiError, extractErrorMessage, extractEmailSuggestion } from "@/api/errors";
|
||||
import { EGender, ESourceAuthorization, ICreateAuthorizePayload, ICreateAuthorizeResponse } from "@/api/resources/User";
|
||||
import { useAuth } from "@/auth";
|
||||
import { getClientTimezone } from "@/locales";
|
||||
@ -23,6 +24,7 @@ export const useAuthentication = () => {
|
||||
const { updateSession } = useSession();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [suggestedEmail, setSuggestedEmail] = useState<string | null>(null);
|
||||
const [token, setToken] = useState<string | null>(null);
|
||||
const { user, signUp } = useAuth();
|
||||
const locale = i18n.language;
|
||||
@ -215,8 +217,17 @@ export const useAuthentication = () => {
|
||||
metricService.reachGoal(EGoals.ROSE_VIDEO_CREATION_START, [EMetrics.YANDEX, EMetrics.KLAVIYO]);
|
||||
}
|
||||
dispatch(actions.status.update("registred"));
|
||||
} catch (error) {
|
||||
setError((error as Error).message);
|
||||
} catch (err) {
|
||||
// Extract error message from API error
|
||||
if (err instanceof ApiError) {
|
||||
const message = extractErrorMessage(err);
|
||||
const suggestion = extractEmailSuggestion(err);
|
||||
setError(message);
|
||||
setSuggestedEmail(suggestion);
|
||||
} else {
|
||||
setError((err as Error).message);
|
||||
setSuggestedEmail(null);
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@ -251,31 +262,44 @@ export const useAuthentication = () => {
|
||||
metricService.reachGoal(EGoals.ROSE_VIDEO_CREATION_START, [EMetrics.YANDEX, EMetrics.KLAVIYO]);
|
||||
}
|
||||
dispatch(actions.status.update("registred"));
|
||||
} catch (error) {
|
||||
setError((error as Error).message);
|
||||
} catch (err) {
|
||||
if (err instanceof ApiError) {
|
||||
setError(extractErrorMessage(err));
|
||||
} else {
|
||||
setError((err as Error).message);
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [api, dispatch, getAuthorizationPayload, signUp])
|
||||
|
||||
const clearError = useCallback(() => {
|
||||
setError(null);
|
||||
setSuggestedEmail(null);
|
||||
}, []);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
isLoading,
|
||||
error,
|
||||
suggestedEmail,
|
||||
token,
|
||||
user,
|
||||
authorization,
|
||||
authorizationWithPassword,
|
||||
anonymousAuthorization
|
||||
anonymousAuthorization,
|
||||
clearError
|
||||
}),
|
||||
[
|
||||
isLoading,
|
||||
error,
|
||||
suggestedEmail,
|
||||
token,
|
||||
user,
|
||||
authorization,
|
||||
authorizationWithPassword,
|
||||
anonymousAuthorization
|
||||
anonymousAuthorization,
|
||||
clearError
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user