diff --git a/ComApp/src/App.js b/ComApp/src/App.js index cd73224..7c6eb47 100644 --- a/ComApp/src/App.js +++ b/ComApp/src/App.js @@ -3,6 +3,14 @@ import React from 'react'; // Redux import { Provider } from 'react-redux'; import { store } from './App/Store/ConfigureStore'; +// Deps +import 'react-native-gesture-handler'; +import { NavigationContainer } from '@react-navigation/native'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; +import { TouchableOpacity, View, Image, Text, TextInput, StyleSheet, Alert } from 'react-native'; +import Icon from 'react-native-vector-icons/FontAwesome5'; +import FlashMessage, { showMessage } from 'react-native-flash-message'; +import * as SplashScreen from 'expo-splash-screen'; // i18n import i18n from "./I18n"; // Controllers @@ -10,117 +18,60 @@ import SyncController from './App/Controllers/SyncController'; // Views import InstallScreen from './App/Views/InstallScreen'; import LoginScreen from './App/Views/LoginScreen'; + +import OnlyVideosScreen from './App/Views/OnlyVideosScreen'; +import ContactScreen from './App/Views/ContactScreen'; +import ContactDetailsScreen from './App/Views/ContactDetailsScreen'; // END V2 import SyncScreen from './App/Views/SyncScreen'; import HomeScreen from './App/Views/HomeScreen'; -import 'react-native-gesture-handler'; -import { NavigationContainer } from '@react-navigation/native'; -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import { TouchableOpacity, View, Image, Text, TextInput, StyleSheet, Alert } from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome5'; - -import FlashMessage, { showMessage } from 'react-native-flash-message'; -import * as SplashScreen from 'expo-splash-screen'; import DirectoriesScreen from './Views/Directories'; import VideoScreen from './Views/Video'; import PDFScreen from './Views/PDF'; -import ContactScreen from './Views/Contact'; -import ContactDetailsScreen from './Views/ContactDetails'; -import OnlyVideosScreen from './Views/OnlyVideos'; + import SearchScreen from "./Views/Search"; import MySpaceScreen from './Views/MySpace'; +// V2 //SplashScreen.preventAutoHideAsync(); //Keep -// V2 store.dispatch({ type: 'INIT_APP' }); store.dispatch({ type: 'INIT_LOCALE' }); store.dispatch({ type: 'INIT_USERS' }); - // END V2 + const Stack = createNativeStackNavigator(); +// END V2 class App extends React.Component { state = { - logged: false, + isSetup: false, + isLogged: false, searchTxt: '', - sendEmail: '', - ShowIsActive: '0' + sendEmail: '' }; - componentDidMount(): void { - + componentDidMount() { const unsubscribe = store.subscribe(this.handleChange.bind(this)); - // if (Sync.isLogged()) { - // store.dispatch({ - // type: 'SET_CURRENT_USER', - // data: CommonModel.get('isLogged').value, - // }); - // store.dispatch({ type: 'SET_LOGGED', data: true }); - // } + if (SyncController.isLogged()) { + store.dispatch({ type: 'SET_CURRENT_USER' }); + store.dispatch({ type: 'SET_LOGGED', data: true }); + } + this.setState({ + isSetup: store.getState().app.isSetup, + isLogged: store.getState().app.logged, + }); } handleChange() { - const logged = store.getState().app.logged; - if (logged === false) { - CommonModel.delete('isLogged'); - } - if (logged !== undefined) { - this.setState({ logged: logged }); - } - this.setState({ ShowIsActive: store.getState().app.ShowIsActive }); - } - - LogoTitle(title) { - return ( - - - {title} - - ); - } - - SendEmail() { - return ( - - this.setState({ sendEmail: text })} /> - { - if (this.state.sendEmail.length > 0) { - if (Helpers.isEmailValid(this.state.sendEmail)) { - const email = { - email: this.state.sendEmail, - subject: i18n.t('app.file_sharing'), - message: '', - documents: JSON.stringify([store.getState().currentOpenedDoc]), - user_id: store.getState().currentUser.id - }; - store.dispatch({ type: 'SEND_BROCHURE', data: email }); - showMessage({ - message: i18n.t('global.message_sent') + '.', - description: i18n.t('global.message_will_be_sent_after_sync') + '.', - type: 'success', - duration: 1500, - }); - this.setState({ sendEmail: '' }); - } else { - Alert.alert(i18n.t('global.warning') + ' !', i18n.t('error.invalid_email_address') + '.', [ - { text: 'OK' }, - ], - { cancelable: false }, - ); - } - } - }}> - - - - ); + this.setState({ + isSetup: store.getState().app.isSetup, + isLogged: store.getState().app.logged, + }); // to force re-rendering + console.log("state changed") } render() { @@ -128,7 +79,7 @@ class App extends React.Component { - {store.getState().app.isSetup === false && + {this.state.isSetup === false && { store.dispatch({ type: 'EDIT_LOCALE' }); - this.setState({ state: this.state }); // to force re-rendering }} style={{ marginRight: 15 }}> @@ -149,7 +99,7 @@ class App extends React.Component { })} /> } - {this.state.logged === false ? ( + {this.state.isLogged === false ? ( { store.dispatch({ type: 'EDIT_LOCALE' }); - this.setState({ state: this.state }); // to force re-rendering }} style={{ marginRight: 15 }}> @@ -170,7 +119,7 @@ class App extends React.Component { })} /> ) : ( - ({ @@ -198,7 +147,7 @@ class App extends React.Component { style={{ marginRight: 25 }}> - {this.state.ShowIsActive === '1' && ( + {store.getState().app.ShowIsActive === '1' && ( navigation.navigation.navigate('MySpaceScreen')} style={{ marginRight: 25 }}> @@ -224,12 +173,14 @@ class App extends React.Component { ), })} - /> + /> )} this.LogoTitle(i18n.t('global.synchronization')) }} + options={{ + headerTitle: () => this.LogoTitle(i18n.t('global.synchronization')) + }} /> + + {title} + + ); + } + + SendEmail() { + return ( + + this.setState({ sendEmail: text })} /> + { + if (this.state.sendEmail.length > 0) { + if (Helpers.isEmailValid(this.state.sendEmail)) { + const email = { + email: this.state.sendEmail, + subject: i18n.t('app.file_sharing'), + message: '', + documents: JSON.stringify([store.getState().currentOpenedDoc]), + user_id: store.getState().currentUser.id + }; + store.dispatch({ type: 'SEND_BROCHURE', data: email }); + showMessage({ + message: i18n.t('global.message_sent') + '.', + description: i18n.t('global.message_will_be_sent_after_sync') + '.', + type: 'success', + duration: 1500, + }); + this.setState({ sendEmail: '' }); + } else { + Alert.alert(i18n.t('global.warning') + ' !', i18n.t('error.invalid_email_address') + '.', [ + { text: 'OK' }, + ], + { cancelable: false }, + ); + } + } + }}> + + + + ); + } + renderFlag() { let flag; switch (store.getState().locale.locale) { diff --git a/ComApp/src/App/Controllers/SyncController.js b/ComApp/src/App/Controllers/SyncController.js index fc9a75c..259566f 100644 --- a/ComApp/src/App/Controllers/SyncController.js +++ b/ComApp/src/App/Controllers/SyncController.js @@ -135,14 +135,6 @@ class SyncController { return true; } - isInstalled() { - const test = Setting.get('installed'); - if (test === false) { - return false; - } - return true; - } - isLogged() { const logged = Setting.get('isLogged'); const loggedTime = Setting.get('loggedTime'); diff --git a/ComApp/src/App/Store/Actions/actionType.js b/ComApp/src/App/Store/Actions/actionType.js index 510d597..0ed17e9 100644 --- a/ComApp/src/App/Store/Actions/actionType.js +++ b/ComApp/src/App/Store/Actions/actionType.js @@ -7,4 +7,6 @@ export const INIT_USERS = "INIT_USERS"; export const INIT_CONTACT = "INIT_CONTACT"; export const ADD_CONTACT = "ADD_CONTACT"; export const EDIT_CONTACT = "EDIT_CONTACT"; -export const DELETE_CONTACT = "DELETE_CONTACT"; \ No newline at end of file +export const DELETE_CONTACT = "DELETE_CONTACT"; +// Documents +export const INIT_DOCUMENTS = "INIT_DOCUMENTS"; \ No newline at end of file diff --git a/ComApp/src/App/Store/Actions/contacts.js b/ComApp/src/App/Store/Actions/contacts.js index e8b15f2..9773353 100644 --- a/ComApp/src/App/Store/Actions/contacts.js +++ b/ComApp/src/App/Store/Actions/contacts.js @@ -2,20 +2,23 @@ import { INIT_CONTACT, ADD_CONTACT, EDIT_CONTACT, DELETE_CONTACT } from "./actio /** * Init contact + * @param {object} currentUser The currentUser * @param {object} data The contact data */ -export const initContact = data => { +export const initContact = (currentUser, data) => { return { type: INIT_CONTACT, + currentUser, data, }; }; /** * Add contact + * @param {object} currentUser The currentUser * @param {object} data The contact data */ -export const addContact = data => { +export const addContact = (currentUser, data) => { return { type: ADD_CONTACT, data, @@ -24,10 +27,11 @@ export const addContact = data => { /** * Edit contact + * @param {object} currentUser The currentUser * @param {string} uid The contact uid * @param {object} data The contact data */ -export const editContact = (uid, data) => { +export const editContact = (currentUser, uid, data) => { return { type: EDIT_CONTACT, uid, @@ -37,9 +41,10 @@ export const editContact = (uid, data) => { /** * Delete contact + * @param {object} currentUser The currentUser * @param {string} uid The contact uid */ -export const deleteContact = uid => { +export const deleteContact = (currentUser, uid) => { return { type: DELETE_CONTACT, uid, diff --git a/ComApp/src/App/Store/Actions/documents.js b/ComApp/src/App/Store/Actions/documents.js new file mode 100644 index 0000000..87ae7c4 --- /dev/null +++ b/ComApp/src/App/Store/Actions/documents.js @@ -0,0 +1,16 @@ +import { INIT_DOCUMENTS } from "./actionType"; + +/** + * Init contact + * @param {string} lang The lang + * @param {object} directories Directories + * @param {object} data The document data + */ +export const initDocuments = (lang, directories, data) => { + return { + type: INIT_DOCUMENTS, + lang, + directories, + data, + }; +}; \ No newline at end of file diff --git a/ComApp/src/App/Store/Actions/locale.js b/ComApp/src/App/Store/Actions/locales.js similarity index 100% rename from ComApp/src/App/Store/Actions/locale.js rename to ComApp/src/App/Store/Actions/locales.js diff --git a/ComApp/src/App/Store/ConfigureStore.js b/ComApp/src/App/Store/ConfigureStore.js index 5b9f8a5..f0d1a8d 100644 --- a/ComApp/src/App/Store/ConfigureStore.js +++ b/ComApp/src/App/Store/ConfigureStore.js @@ -1,13 +1,15 @@ import { createStore, combineReducers } from "redux"; import appReducer from "./Reducers/AppReducer"; +import contactsReducer from "./Reducers/contacts"; +import documentsReducer from "./Reducers/documents"; import localesReducer from "./Reducers/locales"; import usersReducer from "./Reducers/users"; -import contactsReducer from "./Reducers/contacts"; const rootReducer = combineReducers({ app: appReducer, contacts: contactsReducer, + documents: documentsReducer, locale: localesReducer, users: usersReducer }); diff --git a/ComApp/src/App/Store/Reducers/AppReducer.js b/ComApp/src/App/Store/Reducers/AppReducer.js index 732e316..a6deb7f 100644 --- a/ComApp/src/App/Store/Reducers/AppReducer.js +++ b/ComApp/src/App/Store/Reducers/AppReducer.js @@ -1,15 +1,14 @@ import SyncController from "../../Controllers/SyncController"; // Database -import { Setting, Directory, Document, SendBrochure } from '../../../Database'; +import { Setting, Directory, SendBrochure } from '../../../Database'; const initialState = { isSetup: false, locale: 'fr', - directories: {}, - documents: {}, - syncVersion: 0, - logged: undefined, currentUser: {}, + logged: false, + directories: {}, + syncVersion: 0, currentOpenedDoc: {}, ShowIsActive: 0, }; @@ -34,26 +33,20 @@ const reducer = (state = initialState, action) => { let directories = Directory.getAll( state.currentUser.role, state.currentUser.authorizedFolders, - false, + true, state.locale ); - let docs = Document.getAll(directories); let ShowIsActive = Setting.get('ShowIsActive'); return { ...state, - directories: Directory.getAll( - state.currentUser.role, - state.currentUser.authorizedFolders, - true, - state.locale - ), - documents: docs.filter(item => item.lang === state.locale), + directories: directories, ShowIsActive: ShowIsActive === undefined ? false : ShowIsActive.value, }; case 'SET_CURRENT_USER': + let user = Setting.get('isLogged').value return { ...state, - currentUser: JSON.parse(action.data), + currentUser: JSON.parse(user), }; case 'SET_LOGGED': if (action.data === false) { diff --git a/ComApp/src/App/Store/Reducers/contacts.js b/ComApp/src/App/Store/Reducers/contacts.js index 07d83e7..d0c26ad 100644 --- a/ComApp/src/App/Store/Reducers/contacts.js +++ b/ComApp/src/App/Store/Reducers/contacts.js @@ -6,29 +6,33 @@ const initialState = []; const reducer = (state = initialState, action) => { switch (action.type) { - case INIT_CONTACT: + case INIT_CONTACT: { return { ...state, - contacts: Contact.getByUser(state.currentUser.id), + contacts: Contact.getByUser(action.currentUser.id), }; - case ADD_CONTACT: + } + case ADD_CONTACT: { Contact.add(action.data); return { ...state, - contacts: Contact.getByUser(state.currentUser.id), + contacts: Contact.getByUser(action.currentUser.id), }; - case EDIT_CONTACT: + } + case EDIT_CONTACT: { Contact.update(action.data); return { ...state, - contacts: Contact.getByUser(state.currentUser.id), + contacts: Contact.getByUser(action.currentUser.id), }; - case DELETE_CONTACT: + } + case DELETE_CONTACT: { Contact.delete(action.data); return { ...state, - contacts: Contact.getByUser(state.currentUser.id), + contacts: Contact.getByUser(action.currentUser.id), }; + } default: { return state; diff --git a/ComApp/src/App/Store/Reducers/documents.js b/ComApp/src/App/Store/Reducers/documents.js new file mode 100644 index 0000000..596a15d --- /dev/null +++ b/ComApp/src/App/Store/Reducers/documents.js @@ -0,0 +1,23 @@ +import { INIT_DOCUMENTS } from "../Actions/actionType"; +// Models +import { Document } from "../../../Database"; + +const initialState = []; + +const reducer = (state = initialState, action) => { + switch (action.type) { + case INIT_DOCUMENTS: { + let docs = Document.getAll(action.directories); + return [ + ...state, + docs.filter(item => item.lang === action.lang) + ]; + } + + default: { + return state; + } + } +}; + +export default reducer; diff --git a/ComApp/src/App/Views/ContactDetailsScreen.js b/ComApp/src/App/Views/ContactDetailsScreen.js index cb94e38..1dd5b40 100644 --- a/ComApp/src/App/Views/ContactDetailsScreen.js +++ b/ComApp/src/App/Views/ContactDetailsScreen.js @@ -31,7 +31,7 @@ import { BarCodeScanner } from 'expo-barcode-scanner'; function mapStateToProps(state) { return { - contacts: state.app.contacts, + contacts: state.contacts.contacts, currentUser: state.app.currentUser, }; } diff --git a/ComApp/src/App/Views/ContactScreen.js b/ComApp/src/App/Views/ContactScreen.js index c1420ae..c805aef 100644 --- a/ComApp/src/App/Views/ContactScreen.js +++ b/ComApp/src/App/Views/ContactScreen.js @@ -27,8 +27,8 @@ import styles from '../../Resources/Styles/ContactStyle'; function mapStateToProps(state) { return { - users: state.app.users, - contacts: state.app.contacts, + users: state.users.users, + contacts: state.contacts.contacts, documents: state.app.documents, currentUser: state.app.currentUser, }; diff --git a/ComApp/src/App/Views/HomeScreen.js b/ComApp/src/App/Views/HomeScreen.js index 1dff59f..cefdc8a 100644 --- a/ComApp/src/App/Views/HomeScreen.js +++ b/ComApp/src/App/Views/HomeScreen.js @@ -4,6 +4,7 @@ import { View, ImageBackground, TouchableOpacity, Text, Image } from 'react-nati import commonStyles from '../../Resources/CommonStyles'; // Redux import { connect } from 'react-redux'; +import { initDocuments } from '../Store/Actions/documents'; // Style import styles from '../../Resources/Styles/HomeStyle'; // Translations @@ -18,10 +19,19 @@ function mapStateToProps(state) { }; } +const mapDispatchToProps = dispatch => { + return { + init: (locale, directories) => { + dispatch({ type: 'INIT' }) + dispatch(initDocuments(locale, directories)) + } + }; +}; + class HomeScreen extends React.Component { componentDidMount() { - this.props.dispatch({ type: 'INIT' }); + this.props.init(this.props.locale.value, this.props.directories); } render() { @@ -52,4 +62,4 @@ class HomeScreen extends React.Component { } } -export default connect(mapStateToProps)(HomeScreen); \ No newline at end of file +export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen); \ No newline at end of file diff --git a/ComApp/src/App/Views/LoginScreen.js b/ComApp/src/App/Views/LoginScreen.js index 41f2cb5..929a4ef 100644 --- a/ComApp/src/App/Views/LoginScreen.js +++ b/ComApp/src/App/Views/LoginScreen.js @@ -1,6 +1,8 @@ import React from 'react'; import { View, ImageBackground, TextInput, Button, Image, Alert } from 'react-native'; +// Redux import { connect } from 'react-redux'; +import { initContact } from '../Store/Actions/contacts'; // Common Styles import commonStyles from '../../Resources/CommonStyles'; // Style @@ -17,11 +19,23 @@ import SyncController from '../Controllers/SyncController'; function mapStateToProps(state) { return { + app: state.app, users: state.users.users, locale: state.locale.locale, }; } +const mapDispatchToProps = dispatch => { + return { + initContact: currentUser => dispatch(initContact(currentUser)), + setCurrentUser: user => dispatch({ + type: 'SET_CURRENT_USER', + data: JSON.stringify(user), + }), + setIsLogged: () => dispatch({ type: 'SET_LOGGED', data: true }) + }; +}; + class LoginScreen extends React.Component { state = { login: 'v@b.t', @@ -85,7 +99,13 @@ class LoginScreen extends React.Component { return; } const lastUser = Setting.get('lastUser'); - if (lastUser === false || lastUser === undefined || lastUser.value === user.id.toString()) { + // Si on est sur une installation + if (lastUser === false || lastUser === undefined) { + this.loginAction(user, true); + return; + } + // Si on a deja une install avec une précédente connexion + if (lastUser.value === user.id.toString()) { this.loginAction(user); } else { // Si user !== last user && last user not synced @@ -108,15 +128,13 @@ class LoginScreen extends React.Component { loginAction(user, forceSync = false) { this.setState({ login: '', password: '' }); LoginController.login(user); - this.props.dispatch({ - type: 'SET_CURRENT_USER', - data: JSON.stringify(user), - }); - this.props.dispatch({ type: 'SET_LOGGED', data: true }); + this.props.setCurrentUser(user); + this.props.setIsLogged(); + this.props.initContact(this.props.app.currentUser); if (forceSync === true) { - this.props.navigation.navigate('SyncScreen', { isInstalled: true, forceSync: true }); + this.props.navigation.navigate('SyncScreen', { forceSync: true }); } } } -export default connect(mapStateToProps)(LoginScreen); \ No newline at end of file +export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen); \ No newline at end of file diff --git a/ComApp/src/App/Views/OnlyVideosScreen.js b/ComApp/src/App/Views/OnlyVideosScreen.js index 1db6193..19b2ccc 100644 --- a/ComApp/src/App/Views/OnlyVideosScreen.js +++ b/ComApp/src/App/Views/OnlyVideosScreen.js @@ -14,7 +14,7 @@ import styles from '../../Resources/Styles/OnlyVideosStyle'; function mapStateToProps(state) { return { - documents: state.app.documents, + documents: state.documents, }; } diff --git a/ComApp/src/App/Views/SyncScreen.js b/ComApp/src/App/Views/SyncScreen.js index eae4805..cfbbe90 100644 --- a/ComApp/src/App/Views/SyncScreen.js +++ b/ComApp/src/App/Views/SyncScreen.js @@ -2,6 +2,7 @@ import React from 'react'; import { View, Button, Alert, Text } from 'react-native'; // Redux import { connect } from 'react-redux'; +import { initDocuments } from '../Store/Actions/documents'; // Style import styles from '../../Resources/Styles/SyncStyle'; // Translations @@ -20,9 +21,28 @@ function mapStateToProps(state) { documents: state.app.documents, syncVersion: state.app.syncVersion, currentUser: state.app.currentUser, + directories: state.app.directories, + locale: state.locale.locale, }; } +const mapDispatchToProps = dispatch => { + return { + init: (locale, directories) => { + dispatch({ type: 'INIT' }) + dispatch(initDocuments(locale, directories)) + }, + updateVersion: version => dispatch({ + type: 'UPDATE_VERSION', + data: version, + }), + updateShowIsActive: value => dispatch({ + type: 'UPDATE_SHOW_IS_ACTIVE', + data: value, + }) + }; +}; + class SyncScreen extends React.Component { state = { progress: 0, @@ -86,14 +106,8 @@ class SyncScreen extends React.Component { i18n.t('error.error_has_occurred') ); }); - this.props.dispatch({ - type: 'UPDATE_VERSION', - data: resVersion.version, - }); - this.props.dispatch({ - type: 'UPDATE_SHOW_IS_ACTIVE', - data: resVersion.ShowIsActive, - }); + this.props.updateVersion(resVersion.version); + this.props.updateShowIsActive(resVersion.ShowIsActive); this.setState({ newApp: resVersion.newApp }); // getUsers this.setState({ txtStep: i18n.t('sync_s.updating_users') + '...' }); @@ -280,7 +294,7 @@ class SyncScreen extends React.Component { } finishSync(version) { - this.props.dispatch({ type: 'INIT' }); + this.props.init(this.props.locale.value, this.props.directories); SyncController.updateVersion(version); this.setState({ txtStep: i18n.t('sync_s.update_completed') + '.', processing: false }); if (this.state.newApp === true) { @@ -304,4 +318,4 @@ class SyncScreen extends React.Component { } -export default connect(mapStateToProps)(SyncScreen); \ No newline at end of file +export default connect(mapStateToProps, mapDispatchToProps)(SyncScreen); \ No newline at end of file diff --git a/ComApp/src/Locales/fr.json b/ComApp/src/Locales/fr.json index afc8fd6..cac7764 100644 --- a/ComApp/src/Locales/fr.json +++ b/ComApp/src/Locales/fr.json @@ -54,6 +54,7 @@ "no_result": "Aucun résultat" }, "sync_s": { + "back_home": "Retour à l'accueil", "download": "Téléchargement", "update_completed": "Mise à jour effectuée", "updating_docs": "Mise à jour des documents",