| @@ -1,16 +1,44 @@ | |||
| import React from "react"; | |||
| import React, { useEffect } from "react"; | |||
| import { Router } from "react-router-dom"; | |||
| import { Helmet } from "react-helmet-async"; | |||
| import i18next from "i18next"; | |||
| import history from "./store/utils/history"; | |||
| import AppRoutes from "./AppRoutes"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { ToastContainer } from "react-toastify"; | |||
| import "react-toastify/dist/ReactToastify.css"; | |||
| import { StyledEngineProvider } from "@mui/material"; | |||
| import { authScopeStringGetHelper } from "util/helpers/authScopeHelpers"; | |||
| import { JWT_REFRESH_TOKEN, JWT_TOKEN, LANGUAGE } from "constants/localStorage"; | |||
| import { HOME_PAGE } from "constants/pages"; | |||
| const App = () => { | |||
| const { i18n } = useTranslation(); | |||
| useEffect(() => { | |||
| const lang = authScopeStringGetHelper(LANGUAGE); | |||
| if (lang) { | |||
| i18n.changeLanguage(lang); | |||
| } | |||
| }, []); | |||
| useEffect(() => { | |||
| const token = authScopeStringGetHelper(JWT_TOKEN); | |||
| const refreshToken = authScopeStringGetHelper(JWT_REFRESH_TOKEN); | |||
| if (token && refreshToken) { | |||
| history.push({ | |||
| pathname: HOME_PAGE, | |||
| state: { | |||
| from: history.location.pathname, | |||
| }, | |||
| }); | |||
| } | |||
| }, []); | |||
| return ( | |||
| <> | |||
| <Router history={history}> | |||
| @@ -1,6 +1,7 @@ | |||
| import React from 'react'; | |||
| import { Paper, Typography } from '@mui/material'; | |||
| import { DataGrid } from '@mui/x-data-grid'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| // Use these values from REDUX? | |||
| const rows = [ | |||
| @@ -16,10 +17,11 @@ const columns = [ | |||
| ]; | |||
| const DataGridExample = () => { | |||
| const {t} = useTranslation() | |||
| return ( | |||
| <Paper sx={{ p: 2 }} elevation={5}> | |||
| <Typography variant="h4" gutterBottom align="center"> | |||
| DataGrid Example | |||
| {t('common.dataGridExample')} | |||
| </Typography> | |||
| <DataGrid autoHeight rows={rows} columns={columns} /> | |||
| </Paper> | |||
| @@ -1,26 +1,44 @@ | |||
| import React, { useState } from 'react'; | |||
| import { Button, Menu, MenuItem } from '@mui/material'; | |||
| import React, { useState } from "react"; | |||
| import { Button, Menu, MenuItem } from "@mui/material"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { authScopeSetHelper } from "util/helpers/authScopeHelpers"; | |||
| import { LANGUAGE } from "constants/localStorage"; | |||
| const MenuListComponent = () => { | |||
| const [anchorEl, setAnchorEl] = useState(null); | |||
| const open = Boolean(anchorEl); | |||
| const handleClick = (event) => { | |||
| setAnchorEl(event.currentTarget); | |||
| }; | |||
| const handleClose = () => { | |||
| setAnchorEl(null); | |||
| }; | |||
| const { t, i18n } = useTranslation(); | |||
| const [anchorEl, setAnchorEl] = useState(null); | |||
| const open = Boolean(anchorEl); | |||
| const handleClick = (event) => { | |||
| setAnchorEl(event.currentTarget); | |||
| }; | |||
| const handleClose = () => { | |||
| setAnchorEl(null); | |||
| }; | |||
| return ( | |||
| <div> | |||
| <Button onClick={handleClick}>Menu List</Button> | |||
| <Menu id="menu-list" anchorEl={anchorEl} open={open} onClose={handleClose}> | |||
| <MenuItem onClick={handleClose}>Menu Item 1</MenuItem> | |||
| <MenuItem onClick={handleClose}>Menu Item 2</MenuItem> | |||
| <MenuItem onClick={handleClose}>Menu Item 3</MenuItem> | |||
| </Menu> | |||
| </div> | |||
| ); | |||
| const handleLanguageChange = (language) => { | |||
| i18n.changeLanguage(language); | |||
| authScopeSetHelper(LANGUAGE, language) | |||
| setAnchorEl(null); | |||
| }; | |||
| return ( | |||
| <div> | |||
| <Button onClick={handleClick}>{t("common.language")}</Button> | |||
| <Menu | |||
| id="menu-list" | |||
| anchorEl={anchorEl} | |||
| open={open} | |||
| onClose={handleClose} | |||
| > | |||
| <MenuItem onClick={() => handleLanguageChange("en")}> | |||
| {t("common.english")} | |||
| </MenuItem> | |||
| <MenuItem onClick={() => handleLanguageChange("sr")}> | |||
| {t("common.serbian")} | |||
| </MenuItem> | |||
| </Menu> | |||
| </div> | |||
| ); | |||
| }; | |||
| export default MenuListComponent; | |||
| @@ -1,13 +1,13 @@ | |||
| import React, { useEffect } from "react"; | |||
| import { Redirect, Route } from "react-router"; | |||
| import { useDispatch } from "react-redux"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { authenticateUser } from "store/actions/login/loginActions"; | |||
| import { LOGIN_PAGE } from "constants/pages"; | |||
| import { selectIsUserAuthenticated } from "store/selectors/userSelectors"; | |||
| const PrivateRoute = ({ ...props }) => { | |||
| const dispatch = useDispatch(); | |||
| // const isUserAuthenticated = useSelector(selectIsUserAuthenticated); | |||
| const isUserAuthenticated = true; | |||
| const isUserAuthenticated = useSelector(selectIsUserAuthenticated); | |||
| useEffect(() => { | |||
| if (!isUserAuthenticated) { | |||
| @@ -1,3 +1,4 @@ | |||
| export const JWT_TOKEN = 'JwtToken'; | |||
| export const JWT_REFRESH_TOKEN = 'JwtRefreshToken'; | |||
| export const REFRESH_TOKEN_CONST = 'RefreshToken'; | |||
| export const LANGUAGE = "Language" | |||
| @@ -1,18 +1,22 @@ | |||
| import { format as formatDate } from 'date-fns'; | |||
| import i18n from 'i18next'; | |||
| import { initReactI18next } from 'react-i18next'; | |||
| import { format as formatDate } from "date-fns"; | |||
| import i18n from "i18next"; | |||
| import { initReactI18next } from "react-i18next"; | |||
| import enTranslations from './resources/en'; | |||
| import enTranslations from "./resources/en"; | |||
| import srTranslations from "./resources/sr"; | |||
| i18n.use(initReactI18next).init({ | |||
| lng: 'en', | |||
| fallbackLng: 'en', | |||
| lng: "en", | |||
| fallbackLng: "en", | |||
| debug: false, | |||
| supportedLngs: ['en'], | |||
| supportedLngs: ["en", "sr"], | |||
| resources: { | |||
| en: { | |||
| translation: enTranslations, | |||
| }, | |||
| sr: { | |||
| translation: srTranslations, | |||
| }, | |||
| }, | |||
| interpolation: { | |||
| format: (value, format) => { | |||
| @@ -8,7 +8,11 @@ export default { | |||
| "You were registered as not active, please confirm that you are active in the next minute, if you don't you will be logged out.", | |||
| }, | |||
| common: { | |||
| language: "Language", | |||
| english: 'English', | |||
| serbian: "Serbian", | |||
| close: 'Close', | |||
| dataGridExample: 'Data Grid Example', | |||
| trademark: 'TM', | |||
| search: 'Search', | |||
| error: 'Error', | |||
| @@ -0,0 +1,111 @@ | |||
| export default { | |||
| app: { | |||
| title: 'React template' | |||
| }, | |||
| refresh: { | |||
| title: 'Are you active?', | |||
| cta: | |||
| "You were registered as not active, please confirm that you are active in the next minute, if you don't you will be logged out.", | |||
| }, | |||
| common: { | |||
| language: "Jezik", | |||
| english: 'Engleski', | |||
| serbian: "Srpski", | |||
| dataGridExample: 'Primer Data Grid-a', | |||
| close: 'Close', | |||
| trademark: 'TM', | |||
| search: 'Pretraga', | |||
| error: 'Greška', | |||
| continue: 'Nastavite', | |||
| labelUsername: 'Korisničko ime', | |||
| labelEmail: 'E-mail', | |||
| labelPassword: 'Šifra', | |||
| next: 'Napred', | |||
| nextPage: 'Sledeća stranica', | |||
| previousPage: 'Predhodna stranica', | |||
| back: 'Nazad', | |||
| goBack: 'Idite nazad', | |||
| ok: 'U redu', | |||
| done: 'Gotovo', | |||
| confirm: 'Potvrdite', | |||
| printDownload: 'Print/Download', | |||
| cancel: 'Cancel', | |||
| remove: 'Remove', | |||
| invite: 'Invite', | |||
| save: 'Save', | |||
| complete: 'Complete', | |||
| download: 'Download', | |||
| yes: 'Yes', | |||
| no: 'No', | |||
| to: 'to', | |||
| select: 'Select...', | |||
| none: 'None', | |||
| date: { | |||
| range: '{{start}} to {{end}}', | |||
| }, | |||
| }, | |||
| register: { | |||
| registerTitle: "Register", | |||
| usernameRequired: 'Username is required.', | |||
| emailFormat: 'Invalid email address format.', | |||
| emailRequired: 'An email or username is required.', | |||
| passwordLength: 'Your password contain between 8 and 50 characters.', | |||
| passwordRequired: 'A Password is required.', | |||
| }, | |||
| login: { | |||
| welcome: 'React template', | |||
| dontHaveAccount: "Nemate nalog? ", | |||
| emailFormat: 'Loš format email-a', | |||
| emailRequired: 'Email/korisničko ime je obavezno', | |||
| noUsers: 'Ne postoji korisnik', | |||
| passwordStrength: 'Your password is {{strength}}.', | |||
| passwordLength: 'Your password contain between 8 and 50 characters.', | |||
| signUpRecommendation: 'Registrujte se', | |||
| email: 'Please enter your email address or username to log in:', | |||
| logInTitle: 'Prijava', | |||
| logIn: 'Ulogujte se', | |||
| signUp: 'Sign Up', | |||
| usernameRequired: 'Username is required.', | |||
| passwordRequired: 'A Password is required.', | |||
| forgotYourPassword: 'Zaboravili ste šifru?', | |||
| forgotPasswordEmail:'Email', | |||
| useDifferentEmail: 'Use different email address or username', | |||
| }, | |||
| password: { | |||
| weak: 'weak', | |||
| average: 'average', | |||
| good: 'good', | |||
| strong: 'strong', | |||
| }, | |||
| forgotPassword: { | |||
| title: 'Forgot Password', | |||
| label: 'Send email', | |||
| emailRequired: 'An email is required.', | |||
| emailFormat: 'Invalid email address format.', | |||
| forgotPassword: { | |||
| title: 'Forgot Password', | |||
| subtitle: | |||
| 'Please answer the security question to gain access to your account:', | |||
| label: 'Reset Password', | |||
| }, | |||
| }, | |||
| notFound: { | |||
| text: "We're sorry but we couldn't find the page you were looking for.", | |||
| goBack: 'Go back to homepage', | |||
| }, | |||
| errorPage: { | |||
| text: | |||
| "We're sorry, an internal server error came up. Please be patient or try again later.", | |||
| goBack: 'Go back to homepage', | |||
| logout: 'Logout', | |||
| }, | |||
| apiErrors:{ | |||
| ClientIpAddressIsNullOrEmpty:"Client Ip address is null or empty", | |||
| UsernameDoesNotExist: "Username does not exist", | |||
| WrongCredentials: "Wrong credentials", | |||
| SomethingWentWrong: "Something went wrong", | |||
| WrongPasswordAccountIsLocked: "Wrong credentials, account is locked", | |||
| AccountIsLocked: "Account is locked" | |||
| } | |||
| }; | |||