improvement: error handeling structure changed and unified all across the app. user no longer sees inappropriate messages.

This commit is contained in:
2026-07-12 18:27:38 +03:30
parent 901d838a2c
commit fab5111aa8
45 changed files with 977 additions and 241 deletions

View File

@@ -7,10 +7,12 @@ import { Link, useRouter } from '@/i18n/navigation';
import { useSearchParams } from 'next/navigation';
import { Button } from '@/components/ui/shared/Button';
import { Input } from '@/components/ui/shared/Input';
import { getUserFacingError } from '@/components/shared/formatApiError';
import { staffApi } from '@/lib/api/staff';
function AcceptInviteContent() {
const t = useTranslations('auth');
const tErrors = useTranslations('errors');
const params = useSearchParams();
const router = useRouter();
const token = useMemo(() => params.get('token') || '', [params]);
@@ -49,8 +51,7 @@ function AcceptInviteContent() {
setSuccess(t('invitationAlreadyAccepted'));
}
} catch (e: unknown) {
const message = e && typeof e === 'object' && 'message' in e ? String(e.message) : '';
setError(message || t('errorLoadInvitation'));
setError(getUserFacingError(e, tErrors, t('errorLoadInvitation')));
} finally {
setLoading(false);
}
@@ -86,8 +87,7 @@ function AcceptInviteContent() {
router.replace('/login');
}, 1000);
} catch (e: unknown) {
const message = e && typeof e === 'object' && 'message' in e ? String(e.message) : '';
setError(message || t('errorAcceptInvitation'));
setError(getUserFacingError(e, tErrors, t('errorAcceptInvitation')));
} finally {
setSubmitting(false);
}

View File

@@ -14,6 +14,7 @@ import { Button } from '@/components/ui/shared/Button';
import { Input } from '@/components/ui/shared/Input';
import { OrganizationDetailsFields } from '@/components/ui/auth/OrganizationDetailsFields';
import { RegistrationProgressSteps } from '@/components/ui/auth/RegistrationProgressSteps';
import { getUserFacingError } from '@/components/shared/formatApiError';
import { organizationApi } from '@/lib/api/organization';
type AcceptOrganizationInviteForm = {
@@ -27,6 +28,7 @@ type AcceptOrganizationInviteForm = {
function AcceptOrganizationInviteContent() {
const t = useTranslations('auth');
const tErrors = useTranslations('errors');
const tCommon = useTranslations('common');
const tValidation = useTranslations('validation');
const params = useSearchParams();
@@ -115,8 +117,7 @@ function AcceptOrganizationInviteContent() {
setSuccess(t('invitationAlreadyAccepted'));
}
} catch (e: unknown) {
const message = e && typeof e === 'object' && 'message' in e ? String(e.message) : '';
setError(message || t('errorLoadInvitation'));
setError(getUserFacingError(e, tErrors, t('errorLoadInvitation')));
} finally {
setLoading(false);
}
@@ -148,8 +149,7 @@ function AcceptOrganizationInviteContent() {
setSuccess(t('organizationAcceptedRedirect'));
setTimeout(() => router.replace('/login'), 1000);
} catch (e: unknown) {
const message = e && typeof e === 'object' && 'message' in e ? String(e.message) : '';
setError(message || t('errorAcceptInvitation'));
setError(getUserFacingError(e, tErrors, t('errorAcceptInvitation')));
} finally {
setSubmitting(false);
}

View File

@@ -8,6 +8,7 @@ import { useTranslations } from 'next-intl';
import { Link, useRouter } from '@/i18n/navigation';
import { Phone, ShieldCheck } from 'lucide-react';
import { authApi } from '@/lib/api/auth';
import { getUserFacingError } from '@/components/shared/formatApiError';
import { useAuth } from '@/lib/hooks/useAuth';
import { AuthPageShell } from '@/components/ui/auth/AuthPageShell';
import { Button } from '@/components/ui/shared/Button';
@@ -29,6 +30,7 @@ export default function ForgotPasswordPage() {
const t = useTranslations('auth');
const tCommon = useTranslations('common');
const tValidation = useTranslations('validation');
const tErrors = useTranslations('errors');
const router = useRouter();
const { refreshSession } = useAuth();
const [step, setStep] = useState<'mobile' | 'code'>('mobile');
@@ -76,8 +78,7 @@ export default function ForgotPasswordPage() {
setSentMobile(mobile);
setStep('code');
} catch (err: unknown) {
const message = err instanceof Error ? err.message : t('codeSendFailed');
setError(message || t('codeSendFailed'));
setError(getUserFacingError(err, tErrors, t('codeSendFailed')));
} finally {
setIsSending(false);
}
@@ -116,8 +117,7 @@ export default function ForgotPasswordPage() {
await refreshSession();
router.push('/settings/account?reset=1');
} catch (err: unknown) {
const message = err instanceof Error ? err.message : t('verifyFailed');
setError(message || t('verifyFailed'));
setError(getUserFacingError(err, tErrors, t('verifyFailed')));
} finally {
setIsVerifying(false);
}

View File

@@ -8,6 +8,7 @@ import * as z from 'zod';
import { useTranslations } from 'next-intl';
import { Link } from '@/i18n/navigation';
import { Mail, Lock } from 'lucide-react';
import { getUserFacingError } from '@/components/shared/formatApiError';
import { useAuth } from '@/lib/hooks/useAuth';
import { getRememberedEmail } from '@/lib/auth/rememberMe';
import { AuthPageShell } from '@/components/ui/auth/AuthPageShell';
@@ -25,6 +26,7 @@ export default function LoginPage() {
const t = useTranslations('auth');
const tCommon = useTranslations('common');
const tValidation = useTranslations('validation');
const tErrors = useTranslations('errors');
const { login, isLoading, user, isAuthReady } = useAuth();
const router = useRouter();
const [error, setError] = useState<string | null>(null);
@@ -67,8 +69,7 @@ export default function LoginPage() {
setError(null);
await login(data.email, data.password, data.rememberMe);
} catch (err: unknown) {
const message = err instanceof Error ? err.message : t('invalidCredentials');
setError(message || t('invalidCredentials'));
setError(getUserFacingError(err, tErrors, t('invalidCredentials')));
}
};

View File

@@ -7,6 +7,7 @@ import * as z from 'zod';
import { useTranslations } from 'next-intl';
import { Link } from '@/i18n/navigation';
import { Mail, Lock, User, Phone } from 'lucide-react';
import { getUserFacingError } from '@/components/shared/formatApiError';
import { useAuth } from '@/lib/hooks/useAuth';
import { AuthPageShell } from '@/components/ui/auth/AuthPageShell';
import { OrganizationDetailsFields } from '@/components/ui/auth/OrganizationDetailsFields';
@@ -36,6 +37,7 @@ export default function RegisterPage() {
const t = useTranslations('auth');
const tCommon = useTranslations('common');
const tValidation = useTranslations('validation');
const tErrors = useTranslations('errors');
const { registerTrial, isLoading } = useAuth();
const [step, setStep] = useState(1);
const [error, setError] = useState<string | null>(null);
@@ -110,8 +112,7 @@ export default function RegisterPage() {
data.organizationType,
);
} catch (err: unknown) {
const message = err instanceof Error ? err.message : t('registrationFailed');
setError(message || t('registrationFailed'));
setError(getUserFacingError(err, tErrors, t('registrationFailed')));
}
};