diff --git a/commafeed-client/.eslintrc.cjs b/commafeed-client/.eslintrc.cjs index 98f46470..38791f51 100644 --- a/commafeed-client/.eslintrc.cjs +++ b/commafeed-client/.eslintrc.cjs @@ -35,15 +35,10 @@ module.exports = { plugins: ["react"], rules: { "@typescript-eslint/consistent-type-assertions": ["error", { assertionStyle: "as" }], - "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/no-confusing-void-expression": ["error", { ignoreArrowShorthand: true }], "@typescript-eslint/no-floating-promises": "off", "@typescript-eslint/no-misused-promises": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/prefer-nullish-coalescing": ["error", { ignoreConditionalTests: true }], - "@typescript-eslint/strict-boolean-expressions": "off", - "@typescript-eslint/unbound-method": "off", "react/no-unescaped-entities": "off", "react/react-in-jsx-scope": "off", "react-hooks/exhaustive-deps": "error", diff --git a/commafeed-client/src/app/client.ts b/commafeed-client/src/app/client.ts index 449cfb17..8b642985 100644 --- a/commafeed-client/src/app/client.ts +++ b/commafeed-client/src/app/client.ts @@ -1,7 +1,8 @@ -import axios from "axios" +import axios, { AxiosError } from "axios" import { type AddCategoryRequest, type AdminSaveUserRequest, + AuthenticationError, type Category, type CategoryModificationRequest, type CollapseRequest, @@ -31,19 +32,18 @@ const axiosInstance = axios.create({ baseURL: "./rest", withCredentials: true }) axiosInstance.interceptors.response.use( response => response, error => { - if (axios.isAxiosError(error) && error.response) { - const { status, data } = error.response - if ( - (status === 401 && data?.message === "Credentials are required to access this resource.") || - (status === 403 && data?.message === "You don't have the required role to access this resource.") - ) { - window.location.hash = data?.allowRegistrations ? "/welcome" : "/login" - } + if (isAuthenticationError(error)) { + const data = error.response?.data + window.location.hash = data?.allowRegistrations ? "/welcome" : "/login" } throw error } ) +function isAuthenticationError(error: unknown): error is AxiosError { + return axios.isAxiosError(error) && !!error.response && [401, 403].includes(error.response.status) +} + export const client = { category: { getRoot: async () => await axiosInstance.get("category/get"), @@ -110,11 +110,18 @@ export const errorToStrings = (err: unknown) => { let strings: string[] = [] if (axios.isAxiosError(err) && err.response) { - const { data } = err.response - if (typeof data === "string") strings.push(data) - if (typeof data === "object" && data.message) strings.push(data.message as string) - if (typeof data === "object" && data.errors) strings = [...strings, ...data.errors] + if (typeof err.response.data === "string") strings.push(err.response.data) + if (isMessageError(err)) strings.push(err.response.data.message) + if (isMessageArrayError(err)) strings = [...strings, ...err.response.data.errors] } return strings } + +function isMessageError(err: AxiosError): err is AxiosError<{ message: string }> { + return !!err.response && !!err.response.data && typeof err.response.data === "object" && "message" in err.response.data +} + +function isMessageArrayError(err: AxiosError): err is AxiosError<{ errors: string[] }> { + return !!err.response && !!err.response.data && typeof err.response.data === "object" && "errors" in err.response.data +} diff --git a/commafeed-client/src/app/types.ts b/commafeed-client/src/app/types.ts index e642cb20..0d294a75 100644 --- a/commafeed-client/src/app/types.ts +++ b/commafeed-client/src/app/types.ts @@ -284,6 +284,11 @@ export interface AdminSaveUserRequest { admin: boolean } +export interface AuthenticationError { + message: string + allowRegistrations: boolean +} + export type ReadingMode = "all" | "unread" export type ReadingOrder = "asc" | "desc"