diff --git a/front/API.ts b/front/API.ts index e561790..ea25133 100644 --- a/front/API.ts +++ b/front/API.ts @@ -9,6 +9,7 @@ import User from "./models/User"; import Constants from "expo-constants"; import store from "./state/Store"; import { Platform } from "react-native"; +import { en } from "./i18n/Translations"; type AuthenticationInput = { username: string; password: string }; type RegistrationInput = AuthenticationInput & { email: string }; @@ -22,8 +23,23 @@ type FetchParams = { raw?: true; }; -const dummyIllustrations = -[ +// This Exception is intended to cover all business logic errors (invalid credentials, couldn't find a song, etc.) +// technical errors (network, server, etc.) should be handled as standard Error exceptions +// it helps to filter errors in the catch block, APIErrors messages should +// be safe to use in combination with the i18n library +export class APIError extends Error { + constructor( + message: string, + public status: number, + // Set the message to the correct error this is a placeholder + // when the error is only used internally (middleman) + public userMessage : keyof typeof en = "unknownError" + ) { + super(message); + } +} + +const dummyIllustrations = [ "https://i.discogs.com/syRCX8NaLwK2SMk8X6TVU_DWc8RRqE4b-tebAQ6kVH4/rs:fit/g:sm/q:90/h:600/w:600/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTgyNTQz/OC0xNjE3ODE0NDI2/LTU1MjUuanBlZw.jpeg", "https://folkr.fr/wp-content/uploads/2017/06/dua-lipa-folkr-2017-cover-04.jpg", "https://folkr.fr/wp-content/uploads/2017/06/dua-lipa-folkr-2017-cover-03.jpg", @@ -56,16 +72,20 @@ export default class API { header, body: JSON.stringify(params.body), method: params.method ?? "GET", + }).catch(() => { + throw new Error("Error while fetching API: " + baseAPIUrl); }); if (params.raw) { return response.arrayBuffer(); } const body = await response.text(); - try { const jsonResponse = body.length != 0 ? JSON.parse(body) : {}; if (!response.ok) { - throw new Error(jsonResponse.error ?? response.statusText); + throw new APIError( + jsonResponse ?? response.statusText, + response.status + ); } return jsonResponse; } catch (e) { @@ -82,7 +102,14 @@ export default class API { route: "/auth/login", body: authenticationInput, method: "POST", - }).then((responseBody) => responseBody.access_token); + }) + .then((responseBody) => responseBody.access_token) + .catch((e) => { + if (!(e instanceof APIError)) throw e; + + if (e.status == 401) throw new APIError("invalidCredentials", 401, "invalidCredentials"); + throw e; + }); } /** * Create a new user profile, with an email and a password diff --git a/front/i18n/Translations.ts b/front/i18n/Translations.ts index 765afe8..8efe6da 100644 --- a/front/i18n/Translations.ts +++ b/front/i18n/Translations.ts @@ -89,6 +89,7 @@ export const en = { forgottenPassword: 'Forgotten password', partition: 'Partition', + unknownError: 'Unknown error', }; export const fr: typeof en = { @@ -182,6 +183,7 @@ export const fr: typeof en = { forgottenPassword: "Mot de passe oublié", partition: 'Partition', + unknownError: 'Erreur inconnue', }; export const sp: typeof en = { @@ -277,4 +279,5 @@ export const sp: typeof en = { repeatPassword: 'Répéter le mot de passe', partition: 'Partition', + unknownError: 'Error desconocido', }; \ No newline at end of file diff --git a/front/views/AuthenticationView.tsx b/front/views/AuthenticationView.tsx index 2d64434..92109a8 100644 --- a/front/views/AuthenticationView.tsx +++ b/front/views/AuthenticationView.tsx @@ -1,7 +1,7 @@ import React from "react"; import { useDispatch } from '../state/Store'; import { Translate, translate } from "../i18n/i18n"; -import API from "../API"; +import API, { APIError } from "../API"; import { setAccessToken } from "../state/UserSlice"; import { Center, Button, Text } from 'native-base'; import SigninForm from "../components/forms/signinform"; @@ -14,7 +14,9 @@ const hanldeSignin = async (username: string, password: string, apiSetter: (acce apiSetter(apiAccess); return translate("loggedIn"); } catch (error) { - return "Username or password incorrect"; + if (error instanceof APIError) return translate(error.userMessage); + if (error instanceof Error) return error.message; + return "Unknown error"; } };