refactor: adapt frontend error handling to support translated error variables
This commit is contained in:
parent
d69078d73f
commit
7dfaf56887
9 changed files with 24 additions and 30 deletions
|
@ -20,6 +20,9 @@ export type RpcErrorResponse = {
|
|||
stack: string;
|
||||
path: string; // TQuery
|
||||
zodError?: Record<string, string>;
|
||||
tError: {
|
||||
message: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -45,6 +48,9 @@ const jsonRpcErrorResponse = (path: string, status: number, message: string, zod
|
|||
stack: 'Error: Internal Server Error',
|
||||
path,
|
||||
zodError,
|
||||
tError: {
|
||||
message,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -47,8 +47,7 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
},
|
||||
onError: (e) => {
|
||||
invalidate();
|
||||
const toastMessage = t(e.data?.translatedError || (e.message as MessageKey));
|
||||
toast.error(toastMessage);
|
||||
toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables }));
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -61,7 +60,7 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
invalidate();
|
||||
toast.success(t('apps.app-details.uninstall-success'));
|
||||
},
|
||||
onError: (e) => toast.error(t(e.data?.translatedError || (e.message as MessageKey))),
|
||||
onError: (e) => toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables })),
|
||||
});
|
||||
|
||||
const stop = trpc.app.stopApp.useMutation({
|
||||
|
@ -73,7 +72,7 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
invalidate();
|
||||
toast.success(t('apps.app-details.stop-success'));
|
||||
},
|
||||
onError: (e) => toast.error(t(e.data?.translatedError || (e.message as MessageKey))),
|
||||
onError: (e) => toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables })),
|
||||
});
|
||||
|
||||
const update = trpc.app.updateApp.useMutation({
|
||||
|
@ -85,7 +84,7 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
invalidate();
|
||||
toast.success(t('apps.app-details.update-success'));
|
||||
},
|
||||
onError: (e) => toast.error(t(e.data?.translatedError || (e.message as MessageKey))),
|
||||
onError: (e) => toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables })),
|
||||
});
|
||||
|
||||
const start = trpc.app.startApp.useMutation({
|
||||
|
@ -96,7 +95,7 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
invalidate();
|
||||
toast.success(t('apps.app-details.start-success'));
|
||||
},
|
||||
onError: (e) => toast.error(t(e.data?.translatedError || (e.message as MessageKey))),
|
||||
onError: (e) => toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables })),
|
||||
});
|
||||
|
||||
const updateConfig = trpc.app.updateAppConfig.useMutation({
|
||||
|
@ -105,7 +104,7 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
invalidate();
|
||||
toast.success(t('apps.app-details.update-config-success'));
|
||||
},
|
||||
onError: (e) => toast.error(t(e.data?.translatedError || (e.message as MessageKey))),
|
||||
onError: (e) => toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables })),
|
||||
});
|
||||
|
||||
const updateAvailable = Number(app.version || 0) < Number(app?.latestVersion || 0);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { NextPage } from 'next';
|
||||
import React from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import type { MessageKey } from '@/server/utils/errors';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import type { MessageKey } from '@/server/utils/errors';
|
||||
import { Layout } from '../../../../components/Layout';
|
||||
import { ErrorPage } from '../../../../components/ui/ErrorPage';
|
||||
import { trpc } from '../../../../utils/trpc';
|
||||
|
@ -36,7 +36,7 @@ export const AppDetailsPage: NextPage<IProps> = ({ appId }) => {
|
|||
return (
|
||||
<Layout title={data?.info.name || ''} breadcrumbs={breadcrumb}>
|
||||
{data?.info && <AppDetailsContainer app={data} />}
|
||||
{error && <ErrorPage error={t(error.data?.translatedError || (error.message as MessageKey))} />}
|
||||
{error && <ErrorPage error={t(error.data?.tError.message as MessageKey, { ...error.data?.tError.variables })} />}
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import { useRouter } from 'next/router';
|
||||
import { NextPage } from 'next';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { MessageKey } from '@/server/utils/errors';
|
||||
import type { MessageKey } from '@/server/utils/errors';
|
||||
import { AppTile } from '../../../../components/AppTile';
|
||||
import { Layout } from '../../../../components/Layout';
|
||||
import { EmptyPage } from '../../../../components/ui/EmptyPage';
|
||||
|
@ -35,7 +35,7 @@ export const AppsPage: NextPage = () => {
|
|||
{!isLoading && data?.length === 0 && (
|
||||
<EmptyPage title={t('apps.my-apps.empty-title')} subtitle={t('apps.my-apps.empty-subtitle')} onAction={() => router.push('/app-store')} actionLabel={t('apps.my-apps.empty-action')} />
|
||||
)}
|
||||
{error && <ErrorPage error={t(error.data?.translatedError || (error.message as MessageKey))} />}
|
||||
{error && <ErrorPage error={t(error.data?.tError.message as MessageKey, { ...error.data?.tError?.variables })} />}
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
|
|
|
@ -16,10 +16,7 @@ export const LoginContainer: React.FC = () => {
|
|||
const router = useRouter();
|
||||
const utils = trpc.useContext();
|
||||
const login = trpc.auth.login.useMutation({
|
||||
onError: (e) => {
|
||||
const toastMessage = t(e.data?.translatedError || (e.message as MessageKey));
|
||||
toast.error(toastMessage);
|
||||
},
|
||||
onError: (e) => toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables })),
|
||||
onSuccess: (data) => {
|
||||
if (data.totpSessionId) {
|
||||
setTotpSessionId(data.totpSessionId);
|
||||
|
@ -31,10 +28,7 @@ export const LoginContainer: React.FC = () => {
|
|||
});
|
||||
|
||||
const verifyTotp = trpc.auth.verifyTotp.useMutation({
|
||||
onError: (e) => {
|
||||
const toastMessage = t(e.data?.translatedError || (e.message as MessageKey));
|
||||
toast.error(toastMessage);
|
||||
},
|
||||
onError: (e) => toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables })),
|
||||
onSuccess: () => {
|
||||
utils.auth.me.invalidate();
|
||||
router.push('/');
|
||||
|
|
|
@ -16,10 +16,7 @@ export const RegisterContainer: React.FC = () => {
|
|||
const router = useRouter();
|
||||
const utils = trpc.useContext();
|
||||
const register = trpc.auth.register.useMutation({
|
||||
onError: (e) => {
|
||||
const toastMessage = t(e.data?.translatedError || (e.message as MessageKey));
|
||||
toast.error(toastMessage);
|
||||
},
|
||||
onError: (e) => toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables })),
|
||||
onSuccess: () => {
|
||||
utils.auth.me.invalidate();
|
||||
router.push('/');
|
||||
|
|
|
@ -22,10 +22,7 @@ export const ResetPasswordContainer: React.FC<Props> = ({ isRequested }) => {
|
|||
onSuccess: () => {
|
||||
utils.auth.checkPasswordChangeRequest.invalidate();
|
||||
},
|
||||
onError: (e) => {
|
||||
const toastMessage = t(e.data?.translatedError || (e.message as MessageKey));
|
||||
toast.error(toastMessage);
|
||||
},
|
||||
onError: (e) => toast.error(t(e.data?.tError.message as MessageKey, { ...e.data?.tError?.variables })),
|
||||
});
|
||||
const cancelRequest = trpc.auth.cancelPasswordChangeRequest.useMutation({
|
||||
onSuccess: () => {
|
||||
|
|
|
@ -14,7 +14,7 @@ export const DashboardPage: NextPage = () => {
|
|||
return (
|
||||
<Layout title={t('dashboard.title')}>
|
||||
{data && <DashboardContainer data={data} />}
|
||||
{error && <ErrorPage error={t(error.data?.translatedError || (error.message as MessageKey))} />}
|
||||
{error && <ErrorPage error={t(error.data?.tError.message as MessageKey, { ...error.data?.tError.variables })} />}
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Locale } from '@/shared/internationalization/locales';
|
|||
import { type Context } from './context';
|
||||
import { AuthQueries } from './queries/auth/auth.queries';
|
||||
import { db } from './db';
|
||||
import { MessageKey, TranslatedError } from './utils/errors';
|
||||
import { type MessageKey, TranslatedError } from './utils/errors';
|
||||
|
||||
const authQueries = new AuthQueries(db);
|
||||
|
||||
|
@ -35,7 +35,8 @@ const t = initTRPC.context<Context>().create({
|
|||
data: {
|
||||
...shape.data,
|
||||
zodError: error.code === 'BAD_REQUEST' && error.cause instanceof ZodError ? zodErrorsToRecord(error.cause.flatten()) : null,
|
||||
translatedError: error.cause instanceof TranslatedError ? (error.cause.message as MessageKey) : null,
|
||||
tError:
|
||||
error.cause instanceof TranslatedError ? { message: error.cause.message as MessageKey, variables: error.cause.variableValues } : { message: error.message as MessageKey, variables: {} },
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue