diff --git a/package-lock.json b/package-lock.json index 1027011..43f90a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12803,6 +12803,16 @@ "workbox-webpack-plugin": "5.1.4" } }, + "react-toastify": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-6.2.0.tgz", + "integrity": "sha512-XpjFrcBhQ0/nBOL4syqgP/TywFnOyxmstYLWgSQWcj39qpp+WU4vPt3C/ayIDx7RFyxRWfzWTdR2qOcDGo7G0w==", + "requires": { + "clsx": "^1.1.1", + "prop-types": "^15.7.2", + "react-transition-group": "^4.4.1" + } + }, "react-transition-group": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", diff --git a/package.json b/package.json index d39d47b..c6f932a 100644 --- a/package.json +++ b/package.json @@ -8,17 +8,18 @@ "@testing-library/jest-dom": "^5.11.6", "@testing-library/react": "^11.2.2", "@testing-library/user-event": "^12.5.0", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "react-router-dom": "^5.2.0", - "react-scripts": "4.0.1", + "axios": "^0.19.2", "i18next": "^19.4.4", "i18next-browser-languagedetector": "^4.1.1", "i18next-http-backend": "^1.0.10", - "react-i18next": "^11.4.0", "moment": "^2.25.3", - "axios": "^0.19.2", - "react-flags": "^0.1.18" + "react": "^17.0.1", + "react-dom": "^17.0.1", + "react-flags": "^0.1.18", + "react-i18next": "^11.4.0", + "react-router-dom": "^5.2.0", + "react-scripts": "4.0.1", + "react-toastify": "^6.2.0" }, "scripts": { "start": "react-scripts start", diff --git a/public/locales/en/translations.json b/public/locales/en/translations.json index 06ed6aa..e84a894 100644 --- a/public/locales/en/translations.json +++ b/public/locales/en/translations.json @@ -20,6 +20,7 @@ "Login": { "Username": "Username", "Password": "Password", - "Label": "Login" + "Label": "Login", + "IncorrectCredentials": "Incorrect credentials." } } diff --git a/public/locales/ro/translations.json b/public/locales/ro/translations.json index 644e73e..856f529 100644 --- a/public/locales/ro/translations.json +++ b/public/locales/ro/translations.json @@ -11,6 +11,7 @@ "Login": { "Username": "Utilizator", "Password": "Parolă", - "Label": "Autentificare" + "Label": "Autentificare", + "IncorrectCredentials": "Credențiale incorecte." } } diff --git a/src/components/App.js b/src/components/App.js index 681fd41..9a373a9 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -9,6 +9,8 @@ import { ApplicationStateContext, ApplicationDispatchContext } from "../state/ApplicationContexts"; +import { ToastContainer, Slide } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; const App = () => { //il fac pt test dar e gresit. daca va fi un singur state se va redesena toata aplicatia de fiecare data. @@ -19,11 +21,26 @@ const App = () => { ]); return ( - - -
- - + <> + + +
+ + + + ); }; diff --git a/src/features/login/components/LoginContainer.js b/src/features/login/components/LoginContainer.js index 60f784b..a23f64c 100644 --- a/src/features/login/components/LoginContainer.js +++ b/src/features/login/components/LoginContainer.js @@ -5,10 +5,14 @@ import { ApplicationStateContext, ApplicationDispatchContext } from "../../../state/ApplicationContexts"; +import { useToast } from "../../../hooks"; +import { useTranslation } from "react-i18next"; const LoginContainer = () => { const state = useContext(ApplicationStateContext); const dispatchActions = useContext(ApplicationDispatchContext); + const { error } = useToast(); + const { t } = useTranslation(); const handleChange = prop => event => { dispatchActions.onCredentialsChange(prop, event.target.value); @@ -16,7 +20,15 @@ const LoginContainer = () => { const handleLogin = async () => { const { userName, password } = state.credentials; - await authenticate(userName, password); + + try { + const response = await authenticate(userName, password); + if (response.status === "BAD_CREDENTIALS") { + error(t("Login.IncorrectCredentials")); + } + } catch (err) { + error(err.message); + } }; return ( diff --git a/src/hooks/index.js b/src/hooks/index.js new file mode 100644 index 0000000..bc64692 --- /dev/null +++ b/src/hooks/index.js @@ -0,0 +1 @@ +export { useToast } from "./useToast"; diff --git a/src/hooks/useAuthorizationToken.js b/src/hooks/useAuthorizationToken.js deleted file mode 100644 index 92ebf3a..0000000 --- a/src/hooks/useAuthorizationToken.js +++ /dev/null @@ -1,7 +0,0 @@ -import { useContext } from "react"; -import { ApplicationStateContext } from "../state/ApplicationContexts"; - -export const useAuthorizationToken = () => { - const state = useContext(ApplicationStateContext); - return state.security.authorization.token; -}; diff --git a/src/hooks/useToast.js b/src/hooks/useToast.js new file mode 100644 index 0000000..22305c7 --- /dev/null +++ b/src/hooks/useToast.js @@ -0,0 +1,11 @@ +import { toast } from "react-toastify"; + +export const useToast = () => { + const info = message => toast.info(message); + const success = message => toast.success(message); + const warning = message => toast.warning(message); + const error = message => toast.error(message); + const dark = message => toast.dark(message); + + return { info, success, warning, error, dark }; +}; diff --git a/src/utils/identity.js b/src/utils/identity.js index 298f25e..f7e105f 100644 --- a/src/utils/identity.js +++ b/src/utils/identity.js @@ -14,10 +14,12 @@ const authenticate = async (username, password) => { method: "post" }; - const token = await request(url, options); - setItem(storageKeys.TOKEN, token); + const response = await request(url, options); + if (response.status === "SUCCESS") { + setItem(storageKeys.TOKEN, response.token); + } - return token; + return response; }; export { storageKeys, authenticate };