From 55a8e793f3d26a63bcd5bba0fa0a0da82c4d52fb Mon Sep 17 00:00:00 2001 From: Daniil Chemerkin Date: Sat, 6 Dec 2025 23:51:26 +0000 Subject: [PATCH 1/4] AW-483-484-485-fix-bugs --- src/components/CompatibilityV2/pages/Email/index.tsx | 8 ++------ src/components/CompatibilityV3/pages/Email/index.tsx | 4 ++-- src/components/CompatibilityV4/pages/Email/index.tsx | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/components/CompatibilityV2/pages/Email/index.tsx b/src/components/CompatibilityV2/pages/Email/index.tsx index d153ecb..c529e02 100644 --- a/src/components/CompatibilityV2/pages/Email/index.tsx +++ b/src/components/CompatibilityV2/pages/Email/index.tsx @@ -206,12 +206,8 @@ function Email() { )} {!!error?.length && ( - - {translate( - "went_wrong", - undefined, - ELocalesPlacement.CompatibilityV2 - )} + <Title variant="h3" style={{ color: "red", margin: 0, fontSize: "14px", textAlign: "center" }}> + {error} )} diff --git a/src/components/CompatibilityV3/pages/Email/index.tsx b/src/components/CompatibilityV3/pages/Email/index.tsx index b6e28c5..f570390 100644 --- a/src/components/CompatibilityV3/pages/Email/index.tsx +++ b/src/components/CompatibilityV3/pages/Email/index.tsx @@ -181,8 +181,8 @@ function Email() { )} {!!error?.length && ( - - {translate("went_wrong", undefined, ELocalesPlacement.CompatibilityV3)} + <Title variant="h3" style={{ color: "red", margin: 0, fontSize: "14px", textAlign: "center" }}> + {error} )} diff --git a/src/components/CompatibilityV4/pages/Email/index.tsx b/src/components/CompatibilityV4/pages/Email/index.tsx index 3ac8389..5881fa6 100644 --- a/src/components/CompatibilityV4/pages/Email/index.tsx +++ b/src/components/CompatibilityV4/pages/Email/index.tsx @@ -181,8 +181,8 @@ function Email() { )} {!!error?.length && ( - - {translate("went_wrong", undefined, ELocalesPlacement.CompatibilityV4)} + <Title variant="h3" style={{ color: "red", margin: 0, fontSize: "14px", textAlign: "center" }}> + {error} )} From 8a0ffb2e8aa27793bf0c6c1a7f755c7c17a373b7 Mon Sep 17 00:00:00 2001 From: Daniil Chemerkin Date: Sun, 7 Dec 2025 01:17:14 +0000 Subject: [PATCH 2/4] Develop --- src/api/errors.ts | 76 +++++++++++++++++++ .../authentication/use-authentication.ts | 36 +++++++-- 2 files changed, 106 insertions(+), 6 deletions(-) diff --git a/src/api/errors.ts b/src/api/errors.ts index 1da7531..48a8766 100644 --- a/src/api/errors.ts +++ b/src/api/errors.ts @@ -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 +} diff --git a/src/hooks/authentication/use-authentication.ts b/src/hooks/authentication/use-authentication.ts index aacc1d4..16d9ccb 100644 --- a/src/hooks/authentication/use-authentication.ts +++ b/src/hooks/authentication/use-authentication.ts @@ -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(null); + const [suggestedEmail, setSuggestedEmail] = useState(null); const [token, setToken] = useState(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 ] ); } From 49c0b3121a785d346d5d7f00a325eff81f20e928 Mon Sep 17 00:00:00 2001 From: Daniil Chemerkin Date: Wed, 24 Dec 2025 00:29:54 +0000 Subject: [PATCH 3/4] Develop --- .npmrc | 5 +- index.html | 15 --- package-lock.json | 54 ++++++++++ package.json | 5 +- src/api/resources/Session.ts | 17 ++- src/hooks/session/useSession.ts | 181 ++++++++++++++++++++++++++++++-- src/init.tsx | 11 +- 7 files changed, 256 insertions(+), 32 deletions(-) diff --git a/.npmrc b/.npmrc index ca9f540..67a64db 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,4 @@ -node-options=--experimental-vm-modules --no-warnings \ No newline at end of file +node-options=--experimental-vm-modules --no-warnings + +@wit-lab-llc:registry=https://npm.pkg.github.com +//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} \ No newline at end of file diff --git a/index.html b/index.html index 5eddf29..1222d64 100755 --- a/index.html +++ b/index.html @@ -190,21 +190,6 @@ - - -