diff --git a/aliases.js b/aliases.js index 21bf642..c1626dc 100644 --- a/aliases.js +++ b/aliases.js @@ -7,7 +7,7 @@ const aliases = (prefix = `src`) => ({ 'app/shared-components': `${prefix}/app/shared-components`, 'app/configs': `${prefix}/app/configs`, 'app/theme-layouts': `${prefix}/app/theme-layouts`, - 'app/AppContext': `${prefix}/app/AppContext`, + 'app/contexts/AppContext': `${prefix}/app/contexts/AppContext`, }); module.exports = aliases; diff --git a/jsconfig.json b/jsconfig.json index ce5c5a7..b6a9964 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,16 +1,34 @@ { - "compilerOptions": { - "baseUrl": "./", - "paths": { - "@fuse/*": ["./src/@fuse/*"], - "@history*": ["./src/@history"], - "@lodash": ["./src/@lodash"], - "@mock-api": ["./src/@mock-api"], - "app/store/*": ["./src/app/store/*"], - "app/shared-components/*": ["./src/app/shared-components/*"], - "app/configs/*": ["./src/app/configs/*"], - "app/theme-layouts/*": ["./src/app/theme-layouts/*"], - "app/AppContext": ["./src/app/AppContext"] - } + "compilerOptions": { + "baseUrl": "./", + "paths": { + "@fuse/*": [ + "./src/@fuse/*" + ], + "@history*": [ + "./src/@history" + ], + "@lodash": [ + "./src/@lodash" + ], + "@mock-api": [ + "./src/@mock-api" + ], + "app/store/*": [ + "./src/app/store/*" + ], + "app/shared-components/*": [ + "./src/app/shared-components/*" + ], + "app/configs/*": [ + "./src/app/configs/*" + ], + "app/theme-layouts/*": [ + "./src/app/theme-layouts/*" + ], + "app/contexts/AppContext": [ + "./src/app/contexts/AppContext" + ] + } } -} +} \ No newline at end of file diff --git a/src/@fuse/core/FuseAuthorization/FuseAuthorization.js b/src/@fuse/core/FuseAuthorization/FuseAuthorization.js index 6915dde..e75fb2d 100644 --- a/src/@fuse/core/FuseAuthorization/FuseAuthorization.js +++ b/src/@fuse/core/FuseAuthorization/FuseAuthorization.js @@ -1,5 +1,5 @@ import FuseUtils from '@fuse/utils'; -import AppContext from 'app/AppContext'; +import AppContext from 'src/app/contexts/AppContext'; import { Component } from 'react'; import { matchRoutes } from 'react-router-dom'; import withRouter from '@fuse/core/withRouter'; diff --git a/src/@fuse/core/FuseLayout/FuseLayout.js b/src/@fuse/core/FuseLayout/FuseLayout.js index febcc93..d5975df 100644 --- a/src/@fuse/core/FuseLayout/FuseLayout.js +++ b/src/@fuse/core/FuseLayout/FuseLayout.js @@ -1,6 +1,6 @@ import { useDeepCompareEffect } from '@fuse/hooks'; import _ from '@lodash'; -import AppContext from 'app/AppContext'; +import AppContext from 'src/app/contexts/AppContext'; import { generateSettings, selectFuseCurrentSettings, diff --git a/src/app/App.js b/src/app/App.js index 42d55c4..fcbd9a6 100644 --- a/src/app/App.js +++ b/src/app/App.js @@ -14,7 +14,7 @@ import { selectMainTheme } from 'app/store/fuse/settingsSlice'; import FuseAuthorization from '@fuse/core/FuseAuthorization'; import settingsConfig from 'app/configs/settingsConfig'; import withAppProviders from './withAppProviders'; -import { AuthProvider } from './auth/AuthContext'; +import { AuthProvider } from './contexts/AuthContext'; // import axios from 'axios'; /** diff --git a/src/app/auth/index.js b/src/app/auth/index.js deleted file mode 100644 index 174e805..0000000 --- a/src/app/auth/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default as authRoles } from './authRoles'; diff --git a/src/app/auth/services/jwtService/index.js b/src/app/auth/services/jwtService/index.js deleted file mode 100644 index 1b18d9c..0000000 --- a/src/app/auth/services/jwtService/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import JwtService from './jwtService'; - -export default JwtService; diff --git a/src/app/auth/services/jwtService/jwtService.js b/src/app/auth/services/jwtService/jwtService.js deleted file mode 100644 index 99a7511..0000000 --- a/src/app/auth/services/jwtService/jwtService.js +++ /dev/null @@ -1,151 +0,0 @@ -import FuseUtils from '@fuse/utils/FuseUtils'; -import axios from 'axios'; -import jwtDecode from 'jwt-decode'; -import jwtServiceConfig from './jwtServiceConfig'; - -/* eslint-disable camelcase */ - -class JwtService extends FuseUtils.EventEmitter { - init() { - this.setInterceptors(); - this.handleAuthentication(); - } - - setInterceptors = () => { - axios.interceptors.response.use( - (response) => { - return response; - }, - (err) => { - return new Promise((resolve, reject) => { - if (err.response.status === 401 && err.config && !err.config.__isRetryRequest) { - // if you ever get an unauthorized response, logout the user - this.emit('onAutoLogout', 'Invalid access_token'); - this.setSession(null); - } - throw err; - }); - } - ); - }; - - handleAuthentication = () => { - const access_token = this.getAccessToken(); - - if (!access_token) { - this.emit('onNoAccessToken'); - - return; - } - - if (this.isAuthTokenValid(access_token)) { - this.setSession(access_token); - this.emit('onAutoLogin', true); - } else { - this.setSession(null); - this.emit('onAutoLogout', 'access_token expired'); - } - }; - - createUser = (data) => { - return new Promise((resolve, reject) => { - axios.post(jwtServiceConfig.signUp, data).then((response) => { - if (response.data.user) { - this.setSession(response.data.access_token); - resolve(response.data.user); - this.emit('onLogin', response.data.user); - } else { - reject(response.data.error); - } - }); - }); - }; - - signInWithEmailAndPassword = (email, password) => { - return new Promise((resolve, reject) => { - axios - .get(jwtServiceConfig.signIn, { - data: { - email, - password, - }, - }) - .then((response) => { - if (response.data.user) { - this.setSession(response.data.access_token); - resolve(response.data.user); - this.emit('onLogin', response.data.user); - } else { - reject(response.data.error); - } - }); - }); - }; - - signInWithToken = () => { - return new Promise((resolve, reject) => { - axios - .get(jwtServiceConfig.accessToken, { - data: { - access_token: this.getAccessToken(), - }, - }) - .then((response) => { - if (response.data.user) { - this.setSession(response.data.access_token); - resolve(response.data.user); - } else { - this.logout(); - reject(new Error('Failed to login with token.')); - } - }) - .catch((error) => { - this.logout(); - reject(new Error('Failed to login with token.')); - }); - }); - }; - - updateUserData = (user) => { - return axios.post(jwtServiceConfig.updateUser, { - user, - }); - }; - - setSession = (access_token) => { - if (access_token) { - localStorage.setItem('jwt_access_token', access_token); - axios.defaults.headers.common.Authorization = `Bearer ${access_token}`; - } else { - localStorage.removeItem('jwt_access_token'); - delete axios.defaults.headers.common.Authorization; - } - }; - - logout = () => { - this.setSession(null); - this.emit('onLogout', 'Logged out'); - }; - - isAuthTokenValid = (access_token) => { - if (!access_token) { - return false; - } - const decoded = jwtDecode(access_token); - const currentTime = Date.now() / 1000; - if (decoded.exp < currentTime) { - console.warn('access token expired'); - return false; - } - - return true; - }; - - getAccessToken = () => { - return window.localStorage.getItem('jwt_access_token'); - }; -} - -const instance = new JwtService(); - -export default instance; diff --git a/src/app/auth/services/jwtService/jwtServiceConfig.js b/src/app/auth/services/jwtService/jwtServiceConfig.js deleted file mode 100644 index 52dfa61..0000000 --- a/src/app/auth/services/jwtService/jwtServiceConfig.js +++ /dev/null @@ -1,8 +0,0 @@ -const jwtServiceConfig = { - signIn: 'api/auth/sign-in', - signUp: 'api/auth/sign-up', - accessToken: 'api/auth/access-token', - updateUser: 'api/auth/user/update', -}; - -export default jwtServiceConfig; diff --git a/src/app/auth/authRoles.js b/src/app/configs/authRoles.js similarity index 100% rename from src/app/auth/authRoles.js rename to src/app/configs/authRoles.js diff --git a/src/app/configs/settingsConfig.js b/src/app/configs/settingsConfig.js index edd84a6..e9f6191 100644 --- a/src/app/configs/settingsConfig.js +++ b/src/app/configs/settingsConfig.js @@ -19,7 +19,7 @@ const settingsConfig = { To make whole app accessible without authorization by default set defaultAuth: null *** The individual route configs which has auth option won't be overridden. */ - defaultAuth: ['admin'], + defaultAuth: ['admin', 'staff', 'user'], /* Default redirect url for the logged-in user, */ diff --git a/src/app/AppContext.js b/src/app/contexts/AppContext.js similarity index 100% rename from src/app/AppContext.js rename to src/app/contexts/AppContext.js diff --git a/src/app/auth/AuthContext.js b/src/app/contexts/AuthContext.js similarity index 67% rename from src/app/auth/AuthContext.js rename to src/app/contexts/AuthContext.js index bff0842..7cf9d2f 100644 --- a/src/app/auth/AuthContext.js +++ b/src/app/contexts/AuthContext.js @@ -4,7 +4,7 @@ import { useDispatch } from 'react-redux'; import FuseSplashScreen from '@fuse/core/FuseSplashScreen'; import { showMessage } from 'app/store/fuse/messageSlice'; import { logoutUser, setUser } from 'app/store/userSlice'; -import jwtService from './services/jwtService'; +import { authService, firebase } from '../services'; const AuthContext = React.createContext(); @@ -14,44 +14,35 @@ function AuthProvider({ children }) { const dispatch = useDispatch(); useEffect(() => { - jwtService.on('onAutoLogin', () => { - dispatch(showMessage({ message: 'Signing in with JWT' })); - - /** - * Sign in and retrieve user data with stored token - */ - jwtService - .signInWithToken() - .then((user) => { - success(user, 'Signed in with JWT'); - }) - .catch((error) => { - pass(error.message); - }); - }); - - jwtService.on('onLogin', (user) => { - success(user, 'Signed in'); - }); - - jwtService.on('onLogout', () => { + authService.on('onLogout', () => { pass('Signed out'); dispatch(logoutUser()); }); - jwtService.on('onAutoLogout', (message) => { - pass(message); + authService.init(firebase.auth, firebase.db); - dispatch(logoutUser()); + authService.onAuthStateChanged((authUser) => { + dispatch(showMessage({ message: 'Signing...' })); + if (authUser) { + authService + .getUserData(authUser.uid) + .then((user) => { + if (user) { + success(user, 'Signed in'); + } else { + const { displayName, photoURL, email } = authUser; + success({ role: 'user', data: { displayName, photoURL, email } }, 'Signed in'); + } + }) + .catch((error) => { + pass(error.message); + }); + } else { + pass('Signed out'); + } }); - jwtService.on('onNoAccessToken', () => { - pass(); - }); - - jwtService.init(); - function success(user, message) { if (message) { dispatch(showMessage({ message })); diff --git a/src/app/main/authPages/forgot-password/ForgotPasswordConfig.js b/src/app/main/authPages/forgot-password/ForgotPasswordConfig.js index c577997..338b1f6 100644 --- a/src/app/main/authPages/forgot-password/ForgotPasswordConfig.js +++ b/src/app/main/authPages/forgot-password/ForgotPasswordConfig.js @@ -1,7 +1,7 @@ import i18next from 'i18next'; import ForgotPasswordPage from './ForgotPasswordPage'; -import authRoles from '../../../auth/authRoles'; +import authRoles from '../../../configs/authRoles'; import en from './i18n/en'; i18next.addResourceBundle('en', 'forgotPasswordPage', en); diff --git a/src/app/main/authPages/forgot-password/ForgotPasswordPage.js b/src/app/main/authPages/forgot-password/ForgotPasswordPage.js index 550507c..14412c9 100644 --- a/src/app/main/authPages/forgot-password/ForgotPasswordPage.js +++ b/src/app/main/authPages/forgot-password/ForgotPasswordPage.js @@ -7,6 +7,7 @@ import Typography from '@mui/material/Typography'; import { Controller, useForm } from 'react-hook-form'; import { withTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; +import { authService } from 'src/app/services'; import * as yup from 'yup'; import LeftSideCanvas from '../shared-components/LeftSideCanvas'; @@ -19,7 +20,7 @@ function ForgotPasswordPage({ t }) { email: yup.string().email(t('email_error')).required(t('email_error')), }); - const { control, formState, handleSubmit, reset } = useForm({ + const { control, formState, handleSubmit, setError } = useForm({ mode: 'onChange', defaultValues, resolver: yupResolver(schema), @@ -27,8 +28,13 @@ function ForgotPasswordPage({ t }) { const { isValid, dirtyFields, errors } = formState; - function onSubmit() { - reset(defaultValues); + function onSubmit({ email }) { + authService.sendPasswordResetEmail(email).catch((error) => { + setError('root', { + type: 'manual', + message: error.message, + }); + }); } return ( diff --git a/src/app/main/authPages/sign-in/SignInConfig.js b/src/app/main/authPages/sign-in/SignInConfig.js index fa7d38a..8f48632 100644 --- a/src/app/main/authPages/sign-in/SignInConfig.js +++ b/src/app/main/authPages/sign-in/SignInConfig.js @@ -1,7 +1,7 @@ import i18next from 'i18next'; import SignInPage from './SignInPage'; -import authRoles from '../../../auth/authRoles'; +import authRoles from '../../../configs/authRoles'; import en from './i18n/en'; i18next.addResourceBundle('en', 'signInPage', en); diff --git a/src/app/main/authPages/sign-in/SignInPage.js b/src/app/main/authPages/sign-in/SignInPage.js index 761ab9c..d8e6ca3 100644 --- a/src/app/main/authPages/sign-in/SignInPage.js +++ b/src/app/main/authPages/sign-in/SignInPage.js @@ -10,13 +10,14 @@ import Typography from '@mui/material/Typography'; import { Controller, useForm } from 'react-hook-form'; import { withTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; +import { authService } from 'src/app/services'; import * as yup from 'yup'; import LeftSideCanvas from '../shared-components/LeftSideCanvas'; const defaultValues = { email: '', password: '', - remember: true, + remember: false, }; function SignInPage({ t }) { @@ -25,7 +26,7 @@ function SignInPage({ t }) { password: yup.string().required(t('password_error')).min(8, t('password_error')), }); - const { control, formState, handleSubmit, reset } = useForm({ + const { control, formState, handleSubmit, setError } = useForm({ mode: 'onChange', defaultValues, resolver: yupResolver(schema), @@ -33,8 +34,13 @@ function SignInPage({ t }) { const { isValid, dirtyFields, errors } = formState; - function onSubmit() { - reset(defaultValues); + function onSubmit(data) { + authService.signInWithEmailAndPassword(data).catch((error) => { + setError('root', { + type: 'manual', + message: error.message, + }); + }); } return ( @@ -145,6 +151,7 @@ function SignInPage({ t }) { > {t('sign_in_btn')} + {errors.root &&

{errors.root.message}

} diff --git a/src/app/main/authPages/sign-out/SignOutPage.js b/src/app/main/authPages/sign-out/SignOutPage.js index 8cb6be9..3332fcd 100644 --- a/src/app/main/authPages/sign-out/SignOutPage.js +++ b/src/app/main/authPages/sign-out/SignOutPage.js @@ -1,12 +1,12 @@ import Typography from '@mui/material/Typography'; import Paper from '@mui/material/Paper'; import { useEffect } from 'react'; -import JwtService from '../../../auth/services/jwtService'; +import { authService } from 'src/app/services'; function SignOutPage() { useEffect(() => { setTimeout(() => { - JwtService.logout(); + authService.logout(); }, 1000); }, []); diff --git a/src/app/main/authPages/sign-up/SignUpConfig.js b/src/app/main/authPages/sign-up/SignUpConfig.js index 3a7e9fc..1fdf098 100644 --- a/src/app/main/authPages/sign-up/SignUpConfig.js +++ b/src/app/main/authPages/sign-up/SignUpConfig.js @@ -1,7 +1,7 @@ import i18next from 'i18next'; import SignUpPage from './SignUpPage'; -import authRoles from '../../../auth/authRoles'; +import authRoles from '../../../configs/authRoles'; import en from './i18n/en'; i18next.addResourceBundle('en', 'signUpPage', en); diff --git a/src/app/main/authPages/sign-up/SignUpPage.js b/src/app/main/authPages/sign-up/SignUpPage.js index c1a3bf2..2519c73 100644 --- a/src/app/main/authPages/sign-up/SignUpPage.js +++ b/src/app/main/authPages/sign-up/SignUpPage.js @@ -11,6 +11,7 @@ import Typography from '@mui/material/Typography'; import { Controller, useForm } from 'react-hook-form'; import { withTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; +import { authService } from 'src/app/services'; import * as yup from 'yup'; import LeftSideCanvas from '../shared-components/LeftSideCanvas'; @@ -31,7 +32,7 @@ function SignUpPage({ t }) { acceptTermsConditions: yup.boolean().oneOf([true], t('accept_terms_error')), }); - const { control, formState, handleSubmit, reset } = useForm({ + const { control, formState, handleSubmit, setError } = useForm({ mode: 'onChange', defaultValues, resolver: yupResolver(schema), @@ -39,8 +40,19 @@ function SignUpPage({ t }) { const { isValid, dirtyFields, errors } = formState; - function onSubmit() { - reset(defaultValues); + function onSubmit({ name, password, email }) { + authService + .createUser({ + displayName: name, + password, + email, + }) + .catch((error) => { + setError('root', { + type: 'manual', + message: error.message, + }); + }); } return ( diff --git a/src/app/main/home/HomeConfig.js b/src/app/main/home/HomeConfig.js index 5f85cf0..a9a3608 100644 --- a/src/app/main/home/HomeConfig.js +++ b/src/app/main/home/HomeConfig.js @@ -12,6 +12,7 @@ const HomeConfig = { style: 'layout2', }, }, + auth: null, routes: [ { path: '/', diff --git a/src/app/main/navigationPages/dashboard/DashboardConfig.js b/src/app/main/navigationPages/dashboard/DashboardConfig.js index 1912a20..1c860bb 100644 --- a/src/app/main/navigationPages/dashboard/DashboardConfig.js +++ b/src/app/main/navigationPages/dashboard/DashboardConfig.js @@ -1,6 +1,6 @@ import i18next from 'i18next'; -import { authRoles } from 'src/app/auth'; +import authRoles from '../../../configs/authRoles'; import Dashboard from './Dashboard'; import en from './i18n/en'; diff --git a/src/app/main/navigationPages/favorites/FavoritesConfig.js b/src/app/main/navigationPages/favorites/FavoritesConfig.js index f041d50..5c1998e 100644 --- a/src/app/main/navigationPages/favorites/FavoritesConfig.js +++ b/src/app/main/navigationPages/favorites/FavoritesConfig.js @@ -1,6 +1,6 @@ import i18next from 'i18next'; -import { authRoles } from 'src/app/auth'; +import authRoles from '../../../configs/authRoles'; import Favorites from './Favorites'; import en from './i18n/en'; diff --git a/src/app/main/navigationPages/history/HistoryConfig.js b/src/app/main/navigationPages/history/HistoryConfig.js index 8b4943c..c19ee03 100644 --- a/src/app/main/navigationPages/history/HistoryConfig.js +++ b/src/app/main/navigationPages/history/HistoryConfig.js @@ -1,6 +1,6 @@ import i18next from 'i18next'; -import { authRoles } from 'src/app/auth'; +import authRoles from '../../../configs/authRoles'; import History from './History'; import en from './i18n/en'; diff --git a/src/app/main/navigationPages/profile/ProfileConfig.js b/src/app/main/navigationPages/profile/ProfileConfig.js index 73ed73a..1603bd4 100644 --- a/src/app/main/navigationPages/profile/ProfileConfig.js +++ b/src/app/main/navigationPages/profile/ProfileConfig.js @@ -1,6 +1,6 @@ import i18next from 'i18next'; -import { authRoles } from 'src/app/auth'; +import authRoles from '../../../configs/authRoles'; import en from './i18n/en'; import Profile from './Profile'; diff --git a/src/app/services/authService.js b/src/app/services/authService.js new file mode 100644 index 0000000..3e673ce --- /dev/null +++ b/src/app/services/authService.js @@ -0,0 +1,137 @@ +import FuseUtils from '@fuse/utils/FuseUtils'; +import _ from '@lodash'; +import * as firebaseAuth from 'firebase/auth'; +import * as firebaseDb from 'firebase/database'; + +export default class AuthService extends FuseUtils.EventEmitter { + #auth; + + #db; + + init(authInstance, dbInstance) { + this.#auth = authInstance; + this.#db = dbInstance; + } + + createUser = ({ displayName, email, password }) => { + return new Promise((resolve, reject) => { + firebaseAuth + .createUserWithEmailAndPassword(this.#auth, email, password) + .then((userCredential) => firebaseAuth.updateProfile(userCredential.user, { displayName })) + .then(() => { + const userRef = firebaseDb.ref(this.#db, `users/${this.#auth.currentUser.uid}`); + const value = { role: 'user', data: { displayName, email } }; + + return firebaseDb.set(userRef, value); + }) + .then(() => { + resolve(); + }) + .catch((error) => { + reject(error); + }); + }); + }; + + signInWithEmailAndPassword = ({ email, password, remember }) => { + const persistence = remember + ? firebaseAuth.browserLocalPersistence + : firebaseAuth.browserSessionPersistence; + + return new Promise((resolve, reject) => { + firebaseAuth + .setPersistence(this.#auth, persistence) + .then(() => firebaseAuth.signInWithEmailAndPassword(this.#auth, email, password)) + .then((userCredential) => { + resolve(userCredential.user); + const { user } = userCredential; + this.emit('onLogin', { + role: 'user', + data: { displayName: user.displayName, photoURL: user.photoURL, email: user.email }, + }); + }) + .catch((error) => { + reject(error); + }); + }); + }; + + updateUserData = (user) => { + return new Promise((resolve, reject) => { + if (_.isEmpty(user)) { + reject(Error('User data is empty')); + } + + const userRef = firebaseDb.ref(this.#db, `users/${this.#auth.currentUser.uid}`); + const value = { data: { ...user } }; + + firebaseDb + .set(userRef, value) + .then(() => { + if (user.email) { + return firebaseAuth.updateEmail(this.#auth, user.email); + } + + return null; + }) + .then(() => { + resolve(); + }) + .catch((error) => { + reject(error); + }); + }); + }; + + logout = () => { + this.#auth + .signOut() + .then(() => { + this.emit('onLogout', 'Logged out'); + }) + .catch((error) => { + console.warn('Logout error: ', error); + }); + }; + + getUserData = (userId) => { + return new Promise((resolve, reject) => { + const userRef = firebaseDb.ref(this.#db, `users/${userId}`); + firebaseDb.onValue( + userRef, + (snapshot) => { + const user = snapshot.val(); + resolve(user); + }, + (error) => { + reject(error); + } + ); + }); + }; + + sendPasswordResetEmail = (email) => { + return new Promise((resolve, reject) => { + if (email) { + reject(Error('Email is empty')); + } + + firebaseAuth + .sendPasswordResetEmail(this.#auth, email) + .then(() => { + resolve(); + }) + .catch((error) => { + reject(error); + }); + }); + }; + + onAuthStateChanged = (callback) => { + if (!this.#auth) { + return; + } + + this.#auth.onAuthStateChanged(callback); + }; +} diff --git a/src/app/services/firebaseService.js b/src/app/services/firebaseService.js new file mode 100644 index 0000000..e39e9b8 --- /dev/null +++ b/src/app/services/firebaseService.js @@ -0,0 +1,15 @@ +import { initializeApp } from 'firebase/app'; +import { getAuth } from 'firebase/auth'; +import { getDatabase } from 'firebase/database'; +import { getStorage } from 'firebase/storage'; + +export default class FirebaseService { + #app; + + constructor(config) { + this.app = initializeApp(config); + this.auth = getAuth(this.app); + this.db = getDatabase(this.app); + this.storage = getStorage(this.app); + } +} diff --git a/src/app/services/index.js b/src/app/services/index.js new file mode 100644 index 0000000..085d6b3 --- /dev/null +++ b/src/app/services/index.js @@ -0,0 +1,18 @@ +import AuthService from './authService'; +import FirebaseService from './firebaseService'; +// TODO: change to firebase secrets or to use firebase functions +const firebaseConfig = { + apiKey: 'AIzaSyBqMGmOF0-DkYDpnsmZwpf5S8w5cL3fBb8', + authDomain: 'rental-calculator-13a9e.firebaseapp.com', + databaseURL: 'https://rental-calculator-13a9e-default-rtdb.firebaseio.com', + projectId: 'rental-calculator-13a9e', + storageBucket: 'rental-calculator-13a9e.appspot.com', + messagingSenderId: '479612883365', + appId: '1:479612883365:web:fde2d2632ce4c42ce5184c', + measurementId: 'G-JW7J8ZQ9FJ', +}; + +const firebase = new FirebaseService(firebaseConfig); +const authService = new AuthService(); + +export { authService, firebase }; diff --git a/src/app/store/userSlice.js b/src/app/store/userSlice.js index d5058ff..d9d6da1 100644 --- a/src/app/store/userSlice.js +++ b/src/app/store/userSlice.js @@ -5,7 +5,7 @@ import _ from '@lodash'; import { setInitialSettings } from 'app/store/fuse/settingsSlice'; import { showMessage } from 'app/store/fuse/messageSlice'; import settingsConfig from 'app/configs/settingsConfig'; -import jwtService from '../auth/services/jwtService'; +import { authService } from '../services'; export const setUser = createAsyncThunk('user/setUser', async (user, { dispatch, getState }) => { /* @@ -30,24 +30,6 @@ export const updateUserSettings = createAsyncThunk( } ); -export const updateUserShortcuts = createAsyncThunk( - 'user/updateShortucts', - async (shortcuts, { dispatch, getState }) => { - const { user } = getState(); - const newUser = { - ...user, - data: { - ...user.data, - shortcuts, - }, - }; - - dispatch(updateUserData(newUser)); - - return newUser; - } -); - export const logoutUser = () => async (dispatch, getState) => { const { user } = getState(); @@ -71,10 +53,10 @@ export const updateUserData = (user) => async (dispatch, getState) => { return; } - jwtService + authService .updateUserData(user) .then(() => { - dispatch(showMessage({ message: 'User data saved with api' })); + dispatch(showMessage({ message: 'User data saved' })); }) .catch((error) => { dispatch(showMessage({ message: error.message })); @@ -87,7 +69,6 @@ const initialState = { displayName: 'John Doe', photoURL: 'assets/images/avatars/brian-hughes.jpg', email: 'johndoe@withinpixels.com', - shortcuts: ['apps.calendar', 'apps.mailbox', 'apps.contacts', 'apps.tasks'], }, }; @@ -99,7 +80,6 @@ const userSlice = createSlice({ }, extraReducers: { [updateUserSettings.fulfilled]: (state, action) => action.payload, - [updateUserShortcuts.fulfilled]: (state, action) => action.payload, [setUser.fulfilled]: (state, action) => action.payload, }, }); @@ -108,6 +88,4 @@ export const { userLoggedOut } = userSlice.actions; export const selectUser = ({ user }) => user; -export const selectUserShortcuts = ({ user }) => user.data.shortcuts; - export default userSlice.reducer; diff --git a/src/app/theme-layouts/layout1/Layout1.js b/src/app/theme-layouts/layout1/Layout1.js index a77107b..d0f4a0d 100644 --- a/src/app/theme-layouts/layout1/Layout1.js +++ b/src/app/theme-layouts/layout1/Layout1.js @@ -2,7 +2,7 @@ import FuseDialog from '@fuse/core/FuseDialog'; import FuseMessage from '@fuse/core/FuseMessage'; import FuseSuspense from '@fuse/core/FuseSuspense'; import { styled } from '@mui/material/styles'; -import AppContext from 'app/AppContext'; +import AppContext from 'src/app/contexts/AppContext'; import { selectFuseCurrentLayoutConfig } from 'app/store/fuse/settingsSlice'; import { memo, useContext } from 'react'; import { useSelector } from 'react-redux'; diff --git a/src/app/theme-layouts/layout2/Layout2.js b/src/app/theme-layouts/layout2/Layout2.js index 5d9ee88..185d68d 100644 --- a/src/app/theme-layouts/layout2/Layout2.js +++ b/src/app/theme-layouts/layout2/Layout2.js @@ -1,10 +1,11 @@ import FuseSuspense from '@fuse/core/FuseSuspense'; -import AppContext from 'app/AppContext'; +import AppContext from 'src/app/contexts/AppContext'; import { selectFuseCurrentLayoutConfig } from 'app/store/fuse/settingsSlice'; import i18next from 'i18next'; import { memo, useContext } from 'react'; import { useSelector } from 'react-redux'; import { useRoutes } from 'react-router-dom'; +import { useAuth } from 'src/app/contexts/AuthContext'; import FooterLayout2 from './components/FooterLayout2'; import HeaderLayout2 from './components/HeaderLayout2'; @@ -14,12 +15,13 @@ i18next.addResourceBundle('en', 'layout2', en); function Layout2(props) { const config = useSelector(selectFuseCurrentLayoutConfig); + const authContext = useAuth(); const appContext = useContext(AppContext); const { routes } = appContext; return ( <> - {config.header.display && } + {config.header.display && }
{useRoutes(routes)} {props.children} diff --git a/src/app/theme-layouts/layout2/components/FooterLayout2.js b/src/app/theme-layouts/layout2/components/FooterLayout2.js index 1973e2d..b9d6219 100644 --- a/src/app/theme-layouts/layout2/components/FooterLayout2.js +++ b/src/app/theme-layouts/layout2/components/FooterLayout2.js @@ -7,8 +7,8 @@ function FooterLayout2() { const { t } = useTranslation('layout2'); return ( -