Merge branch 'staging'
14
ComApp/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# 2.0.0
|
||||
## Bug
|
||||
- Fix format vidéo lors de la rotation de l'écran
|
||||
## Évolution
|
||||
- Bump React Native 0.70.1 -> 0.70.6
|
||||
- Amélioration de l'usage de Redux avec reducers, actions, etc.
|
||||
- Amélioration sur l'arborescence du projet.
|
||||
- Mise à jour du module BCrypt Bridge
|
||||
- Ajout de Sentry pour remonter les erreurs.
|
||||
- Création (+ BO) d'une configuration d'application pour permettre le maintiens d'un seul APK.
|
||||
- Mise en place de vérification par regex des champs obligatoires sur le formulaire de contact.
|
||||
- Ajout d'un bouton dans le header de la home pour aller directement sur la page d'ajout de contact.
|
||||
- Ajout de la possibilité de revenir à l'écran d'accueil en cliquant sur le logo présent dans le header.
|
||||
- Ajout d'un espace plus important entre les éléments cliquables du header + ajout d'un menu en overlay.
|
||||
|
|
@ -135,11 +135,11 @@ android {
|
|||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.comintl.app"
|
||||
applicationId "com.comapp.ldc"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.2"
|
||||
versionName "2.0.0"
|
||||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/primary"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:src="@drawable/launch_screen" />
|
||||
</LinearLayout>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
ComApp/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
BIN
ComApp/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
BIN
ComApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
BIN
ComApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 12 KiB |
BIN
ComApp/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -1,5 +1,5 @@
|
|||
<resources>
|
||||
<!-- Below line is handled by '@expo/configure-splash-screen' command and it's discouraged to modify it manually -->
|
||||
<string name="expo_splash_screen_resize_mode" translatable="false">contain</string>
|
||||
<string name="app_name">Commerciaux - LDC International</string>
|
||||
<string name="app_name">Commerciaux LDC</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -49,3 +49,17 @@ allprojects {
|
|||
maven { url 'https://www.jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
// Patch needed for https://github.com/facebook/react-native/issues/35210
|
||||
// This is a patch to short-circuit the "+" dependencies inside the
|
||||
// users' app/build.gradle file and the various .gradle files of libraries.
|
||||
// As using plain "+" dependencies causes Gradle to always download the latest,
|
||||
// this logic forces Gradle to use latest release in the minor series.
|
||||
project.rootProject.allprojects {
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
force "com.facebook.react:react-native:0.70.+"
|
||||
force "com.facebook.react:hermes-engine:0.70.+"
|
||||
}
|
||||
}
|
||||
}
|
||||
3381
ComApp/package-lock.json
generated
|
|
@ -10,16 +10,17 @@
|
|||
"lint": "eslint ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-community/netinfo": "^9.3.2",
|
||||
"@react-native-community/netinfo": "^9.3.7",
|
||||
"@react-native-community/slider": "^4.3.2",
|
||||
"@react-native-picker/picker": "^2.4.6",
|
||||
"@react-navigation/native": "^6.0.13",
|
||||
"@react-navigation/native-stack": "^6.9.0",
|
||||
"@rneui/base": "^0.0.0-edge.2",
|
||||
"@rneui/themed": "^0.0.0-edge.2",
|
||||
"@sentry/react-native": "^4.12.0",
|
||||
"axios": "^0.27.2",
|
||||
"expo": "^46.0.13",
|
||||
"expo-av": "^12.0.4",
|
||||
"expo": "^47.0.10",
|
||||
"expo-av": "^13.0.2",
|
||||
"expo-barcode-scanner": "^11.4.0",
|
||||
"expo-splash-screen": "^0.16.2",
|
||||
"expo-video-player": "^2.2.0",
|
||||
|
|
@ -28,9 +29,9 @@
|
|||
"lodash": "^4.17.21",
|
||||
"npm": "^8.19.2",
|
||||
"react": "18.1.0",
|
||||
"react-native": "0.70.1",
|
||||
"react-native": "^0.70.6",
|
||||
"react-native-animated-tree-view": "^0.1.4",
|
||||
"react-native-b-crypt-bridge": "file:react-native-b-crypt-bridge-2.0.0.tgz",
|
||||
"react-native-b-crypt-bridge": "file:react-native-b-crypt-bridge-2.1.0.tgz",
|
||||
"react-native-blob-util": "^0.16.2",
|
||||
"react-native-flash-message": "^0.3.1",
|
||||
"react-native-gesture-handler": "^2.7.0",
|
||||
|
|
@ -52,7 +53,7 @@
|
|||
"babel-jest": "^26.6.3",
|
||||
"eslint": "^7.32.0",
|
||||
"jest": "^26.6.3",
|
||||
"metro-react-native-babel-preset": "^0.72.1",
|
||||
"metro-react-native-babel-preset": "^0.72.3",
|
||||
"react-test-renderer": "18.1.0"
|
||||
},
|
||||
"jest": {
|
||||
|
|
|
|||
BIN
ComApp/react-native-b-crypt-bridge-2.1.0.tgz
Normal file
|
|
@ -1,215 +1,360 @@
|
|||
import 'react-native-gesture-handler';
|
||||
import React from 'react';
|
||||
import { createStore } from 'redux';
|
||||
// Sentry
|
||||
import * as Sentry from "@sentry/react-native";
|
||||
// Redux
|
||||
import { Provider } from 'react-redux';
|
||||
import { store } from './App/Store/ConfigureStore';
|
||||
import { initDocuments } from './App/Store/Actions/documents';
|
||||
// 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 { navigationRef, navigate } from './Navigation';
|
||||
import { TouchableOpacity, View, Image, Text, TextInput, Alert, DrawerLayoutAndroid, Button } 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 LoginScreen from './Views/Login';
|
||||
import HomeScreen from './Views/Home';
|
||||
import DirectoriesScreen from './Views/Directories';
|
||||
import VideoScreen from './Views/Video';
|
||||
import PDFScreen from './Views/PDF';
|
||||
import SyncScreen from './Views/Sync';
|
||||
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';
|
||||
|
||||
import UsersModel from './Models/Users';
|
||||
import DirectoriesModel from './Models/Directories';
|
||||
import DocumentsModel from './Models/Documents';
|
||||
import ContactsModel from './Models/Contacts';
|
||||
import SendBrochureModel from './Models/SendBrochure';
|
||||
import CommonModel from './Models/Common';
|
||||
|
||||
import Sync from './Controllers/Sync';
|
||||
import Helpers from "./Controllers/Helpers";
|
||||
// Application infos
|
||||
import * as Application from 'expo-application';
|
||||
// i18n
|
||||
import i18n from "./I18n";
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
// Views
|
||||
import InstallScreen from './App/Views/InstallScreen';
|
||||
import LoginScreen from './App/Views/LoginScreen';
|
||||
import SyncScreen from './App/Views/SyncScreen';
|
||||
import HomeScreen from './App/Views/HomeScreen';
|
||||
import DirectoriesScreen from './App/Views/DirectoriesScreen';
|
||||
import PDFScreen from './App/Views/PDFScreen';
|
||||
import VideoScreen from './App/Views/VideoScreen';
|
||||
import OnlyVideosScreen from './App/Views/OnlyVideosScreen';
|
||||
import ContactScreen from './App/Views/ContactScreen';
|
||||
import ContactDetailsScreen from './App/Views/ContactDetailsScreen';
|
||||
import SearchScreen from "./App/Views/SearchScreen";
|
||||
import MySpaceScreen from './App/Views/MySpaceScreen';
|
||||
// Style
|
||||
import styles from './Resources/Styles/NavigationStyle';
|
||||
// Controllers
|
||||
import SyncController from './App/Controllers/SyncController';
|
||||
|
||||
SplashScreen.preventAutoHideAsync();
|
||||
Sentry.init({
|
||||
dsn: "https://ab87e8d840324f41873c95b06903b0bf@o4504314935640064.ingest.sentry.io/4504441255886848",
|
||||
});
|
||||
|
||||
const initialState = {
|
||||
locale: 'fr',
|
||||
users: {},
|
||||
directories: {},
|
||||
documents: {},
|
||||
contacts: {},
|
||||
syncVersion: 0,
|
||||
logged: undefined,
|
||||
currentUser: {},
|
||||
currentOpenedDoc: {},
|
||||
ShowIsActive: 0,
|
||||
};
|
||||
Sentry.setContext("app", {
|
||||
boUrl: SyncController.getUrlBo()
|
||||
});
|
||||
|
||||
function reducer(state = initialState, action) {
|
||||
//console.log('reducer', state, action);
|
||||
//console.log('DISPATCH');
|
||||
|
||||
switch (action.type) {
|
||||
case 'INIT':
|
||||
let docs = DocumentsModel.getAll(DirectoriesModel.getAll(
|
||||
state.currentUser.role,
|
||||
state.currentUser.authorizedFolders,
|
||||
false,
|
||||
state.locale
|
||||
));
|
||||
return {
|
||||
...state,
|
||||
users: UsersModel.getAll(),
|
||||
directories: DirectoriesModel.getAll(
|
||||
state.currentUser.role,
|
||||
state.currentUser.authorizedFolders,
|
||||
true,
|
||||
state.locale
|
||||
),
|
||||
documents: docs.filter(item => item.lang === state.locale),
|
||||
contacts: ContactsModel.getByUser(state.currentUser.id),
|
||||
ShowIsActive: CommonModel.get('ShowIsActive')['value'],
|
||||
};
|
||||
case 'INIT_USERS':
|
||||
return {
|
||||
...state,
|
||||
users: UsersModel.getAll(),
|
||||
};
|
||||
case 'SET_CURRENT_USER':
|
||||
return {
|
||||
...state,
|
||||
currentUser: JSON.parse(action.data),
|
||||
};
|
||||
case 'SET_LOGGED':
|
||||
if (action.data === false) {
|
||||
CommonModel.delete('isLogged');
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
logged: action.data,
|
||||
};
|
||||
case 'UPDATE_LOCALE':
|
||||
let nxt;
|
||||
if (action.data === undefined) {
|
||||
const availableLocales = ['fr', 'en', 'de'];
|
||||
if (availableLocales.indexOf(i18n.locale) === availableLocales.length - 1) {
|
||||
nxt = availableLocales[0];
|
||||
} else {
|
||||
nxt = availableLocales[availableLocales.indexOf(i18n.locale) + 1];
|
||||
}
|
||||
} else {
|
||||
nxt = action.data;
|
||||
}
|
||||
i18n.locale = nxt;
|
||||
CommonModel.update({ key: 'locale', value: nxt });
|
||||
let docsL = DocumentsModel.getAll(DirectoriesModel.getAll(
|
||||
state.currentUser.role,
|
||||
state.currentUser.authorizedFolders,
|
||||
false,
|
||||
nxt
|
||||
));
|
||||
return {
|
||||
...state,
|
||||
locale: nxt,
|
||||
directories: DirectoriesModel.getAll(
|
||||
state.currentUser.role,
|
||||
state.currentUser.authorizedFolders,
|
||||
true,
|
||||
nxt
|
||||
),
|
||||
documents: docsL.filter(item => item.lang === nxt),
|
||||
};
|
||||
case 'SET_CURRENT_OPENED_DOC':
|
||||
return {
|
||||
...state,
|
||||
currentOpenedDoc: action.data
|
||||
};
|
||||
case 'UPDATE_VERSION':
|
||||
return {
|
||||
...state,
|
||||
syncVersion: action.data,
|
||||
};
|
||||
case 'UPDATE_SHOW_IS_ACTIVE':
|
||||
Sync.updateShowIsActive(action.data);
|
||||
return {
|
||||
...state,
|
||||
ShowIsActive: action.data,
|
||||
};
|
||||
case 'UPDATE_CONTACT':
|
||||
ContactsModel.update(action.data);
|
||||
return {
|
||||
...state,
|
||||
contacts: ContactsModel.getByUser(state.currentUser.id),
|
||||
};
|
||||
case 'ADD_CONTACT':
|
||||
ContactsModel.add(action.data);
|
||||
return {
|
||||
...state,
|
||||
contacts: ContactsModel.getByUser(state.currentUser.id),
|
||||
};
|
||||
case 'DELETE_CONTACT':
|
||||
ContactsModel.delete(action.data);
|
||||
return {
|
||||
...state,
|
||||
contacts: ContactsModel.getByUser(state.currentUser.id),
|
||||
};
|
||||
case 'SEND_BROCHURE':
|
||||
SendBrochureModel.add(action.data);
|
||||
return state;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
const store = createStore(reducer);
|
||||
const Stack = createNativeStackNavigator();
|
||||
SplashScreen.preventAutoHideAsync(); //Keep
|
||||
|
||||
store.dispatch({ type: 'INIT' });
|
||||
store.dispatch({ type: 'INIT_LOCALE' });
|
||||
store.dispatch({ type: 'INIT_USERS' });
|
||||
|
||||
const Stack = createNativeStackNavigator();
|
||||
|
||||
class App extends React.Component {
|
||||
state = {
|
||||
logged: false,
|
||||
isSetup: false,
|
||||
isLogged: false,
|
||||
searchTxt: '',
|
||||
sendEmail: '',
|
||||
ShowIsActive: '0'
|
||||
mainColor: '',
|
||||
drawerRef: React.createRef()
|
||||
};
|
||||
|
||||
componentDidMount(): void {
|
||||
componentDidMount() {
|
||||
const unsubscribe = store.subscribe(this.handleChange.bind(this));
|
||||
if (Sync.isInstalled() && Sync.isLogged()) {
|
||||
store.dispatch({
|
||||
type: 'SET_CURRENT_USER',
|
||||
data: CommonModel.get('isLogged').value,
|
||||
});
|
||||
store.dispatch({ type: 'SET_LOGGED', data: true });
|
||||
}
|
||||
const savedLocale = CommonModel.get('locale');
|
||||
if (savedLocale !== undefined && savedLocale !== false) {
|
||||
store.dispatch({ type: 'UPDATE_LOCALE', data: savedLocale.value });
|
||||
}
|
||||
this.setState({
|
||||
isSetup: store.getState().app.isSetup,
|
||||
isLogged: store.getState().app.logged,
|
||||
mainColor: store.getState().app.mainColor
|
||||
});
|
||||
}
|
||||
|
||||
handleChange() {
|
||||
const logged = store.getState().logged;
|
||||
if (logged === false) {
|
||||
CommonModel.delete('isLogged');
|
||||
}
|
||||
if (logged !== undefined) {
|
||||
this.setState({ logged: logged });
|
||||
}
|
||||
this.setState({ ShowIsActive: store.getState().ShowIsActive });
|
||||
this.setState({
|
||||
isSetup: store.getState().app.isSetup,
|
||||
isLogged: store.getState().app.logged,
|
||||
mainColor: store.getState().app.mainColor
|
||||
}); // to force re-rendering
|
||||
console.log("state changed")
|
||||
}
|
||||
|
||||
LogoTitle(title) {
|
||||
navigationView = () => (
|
||||
<View style={styles.drawer.container}>
|
||||
<View>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.state.drawerRef.current.closeDrawer();
|
||||
store.dispatch({ type: 'EDIT_LOCALE' });
|
||||
store.dispatch(initDocuments(store.getState().locale.locale, store.getState().directories.global))
|
||||
}}
|
||||
style={styles.drawer.btn}>
|
||||
<Image source={this.renderFlag()} style={{ width: 25, height: 25 }} />
|
||||
<Text style={styles.drawer.btnText}>{i18n.t('global.change_lang')}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.state.drawerRef.current.closeDrawer();
|
||||
navigate('SyncScreen')
|
||||
}}
|
||||
style={styles.drawer.btn}>
|
||||
<Icon name="sync-alt" size={20} />
|
||||
<Text style={styles.drawer.btnText}>{i18n.t('global.sync')}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.state.drawerRef.current.closeDrawer();
|
||||
store.dispatch({ type: 'SET_CURRENT_USER', data: false });
|
||||
}}
|
||||
style={styles.drawer.btn}>
|
||||
<Icon name="sign-out-alt" size={20} />
|
||||
<Text style={styles.drawer.btnText}>{i18n.t('global.logout')}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View>
|
||||
<Text style={{ marginBottom: 10 }}>Version : {Application.nativeApplicationVersion}</Text>
|
||||
<Button
|
||||
title={i18n.t('global.close')}
|
||||
color={this.state.mainColor}
|
||||
onPress={() => this.state.drawerRef.current.closeDrawer()}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<NavigationContainer ref={navigationRef}>
|
||||
<DrawerLayoutAndroid
|
||||
ref={this.state.drawerRef}
|
||||
drawerWidth={300}
|
||||
drawerPosition={"right"}
|
||||
drawerLockMode={'locked-open'}
|
||||
renderNavigationView={this.navigationView}
|
||||
>
|
||||
<Stack.Navigator initialRouteName="HomeScreen">
|
||||
{this.state.isSetup === false &&
|
||||
<Stack.Screen
|
||||
name="InstallScreen"
|
||||
component={InstallScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('install.installation'), false),
|
||||
headerRight: () => (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
store.dispatch({ type: 'EDIT_LOCALE' });
|
||||
}}
|
||||
style={{ marginRight: 15 }}>
|
||||
<Image source={this.renderFlag()} style={{ width: 25, height: 25 }} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
),
|
||||
})}
|
||||
/>
|
||||
}
|
||||
{this.state.isLogged === false ? (
|
||||
<Stack.Screen
|
||||
name="LoginScreen"
|
||||
component={LoginScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('global.login'), false),
|
||||
headerRight: () => (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
store.dispatch({ type: 'EDIT_LOCALE' });
|
||||
}}
|
||||
style={{ marginRight: 15 }}>
|
||||
<Image source={this.renderFlag()} style={{ width: 25, height: 25 }} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
),
|
||||
})}
|
||||
/>
|
||||
) : (
|
||||
<Stack.Screen
|
||||
name="HomeScreen"
|
||||
component={HomeScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('global.home')),
|
||||
headerRight: () => (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<View style={{ flexDirection: 'row', marginRight: 50 }}>
|
||||
<TextInput
|
||||
style={{ ...styles.searchInput, borderColor: this.state.mainColor }}
|
||||
placeholder={i18n.t('global.search')}
|
||||
value={this.state.searchTxt}
|
||||
onChangeText={(text) => this.setState({ searchTxt: text })}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
style={{ ...styles.btnSearch, backgroundColor: this.state.mainColor }}
|
||||
onPress={() => {
|
||||
if (this.state.searchTxt.length > 0) {
|
||||
navigation.navigation.navigate('SearchScreen', {
|
||||
needle: this.state.searchTxt,
|
||||
onlyVideos: false,
|
||||
});
|
||||
this.setState({ searchTxt: '' });
|
||||
}
|
||||
}}>
|
||||
<Icon name={'search'} size={20} color={'white'} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
{store.getState().app.ShowIsActive === '1' && (
|
||||
<TouchableOpacity
|
||||
onPress={() => navigation.navigation.navigate('MySpaceScreen')}
|
||||
style={{ marginRight: 25 }}>
|
||||
<Icon name="user-circle" size={25} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<TouchableOpacity
|
||||
onPress={() => navigation.navigation.navigate('ContactScreen', {
|
||||
action: 'add',
|
||||
})}
|
||||
style={{ marginRight: 25 }}>
|
||||
<Icon name="user-plus" size={20} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.state.drawerRef.current.openDrawer()
|
||||
}}
|
||||
style={{ marginRight: 25 }}>
|
||||
<Icon name="sliders-h" size={20} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
),
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
<Stack.Screen
|
||||
name="SyncScreen"
|
||||
component={SyncScreen}
|
||||
initialParams={{ forceSync: false }}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('global.synchronization'))
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="DirectoriesScreen"
|
||||
component={DirectoriesScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('app.folders'))
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="OnlyVideosScreen"
|
||||
component={OnlyVideosScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('global.videos')),
|
||||
headerRight: () => (
|
||||
<View style={{ flexDirection: 'row', marginRight: 5 }}>
|
||||
<TextInput style={{ ...styles.searchInput, borderColor: this.state.mainColor }} placeholder={i18n.t('global.search')} value={this.state.searchTxt} onChangeText={(text) => this.setState({ searchTxt: text })} />
|
||||
<TouchableOpacity style={{ ...styles.btnSearch, backgroundColor: this.state.mainColor }} onPress={() => {
|
||||
if (this.state.searchTxt.length > 0) {
|
||||
navigation.navigation.navigate('SearchScreen', {
|
||||
needle: this.state.searchTxt,
|
||||
onlyVideos: true,
|
||||
});
|
||||
this.setState({ searchTxt: '' });
|
||||
}
|
||||
}}>
|
||||
<Icon name={'search'} size={20} color={'white'} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
),
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="VideoScreen"
|
||||
component={VideoScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('app.video')),
|
||||
headerRight: () => this.SendEmail(),
|
||||
orientation: 'landscape'
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="PDFScreen"
|
||||
component={PDFScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, 'PDF'),
|
||||
headerRight: () => this.SendEmail()
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="ContactScreen"
|
||||
component={ContactScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('global.contacts'))
|
||||
})}
|
||||
initialParams={{ contactAdded: false }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="ContactDetailsScreen"
|
||||
component={ContactDetailsScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('app.contact_details'))
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="SearchScreen"
|
||||
component={SearchScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('app.results_search'))
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="MySpaceScreen"
|
||||
component={MySpaceScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(navigation, i18n.t('app.my_space')),
|
||||
headerRight: () => (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
const folder = store.getState().directories.treeview.filter(tmp => tmp.id === 1);
|
||||
navigation.navigation.navigate('DirectoriesScreen', { folder: folder })
|
||||
}}
|
||||
style={{ marginRight: 15 }}>
|
||||
<Icon name="briefcase" size={20} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
),
|
||||
})}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
<FlashMessage position="top" />
|
||||
</DrawerLayoutAndroid>
|
||||
</NavigationContainer>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
||||
LogoTitle(navigation, title, wantBtn = true) {
|
||||
return (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<Image
|
||||
style={{ width: 100, height: 50, resizeMode: 'stretch' }}
|
||||
source={require('./assets/img/logo.png')}
|
||||
/>
|
||||
<TouchableOpacity onPress={() => {
|
||||
if (wantBtn) {
|
||||
navigation.navigation.navigate('HomeScreen')
|
||||
}
|
||||
}}>
|
||||
{this.state.isSetup ? (
|
||||
<Image
|
||||
style={{ width: 100, height: 50, resizeMode: 'stretch' }}
|
||||
source={{ uri: FileSystem.documentDirectory + 'RectangleLogo.png' }}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
style={{ width: 100, height: 50, resizeMode: 'stretch' }}
|
||||
source={require('./Resources/assets/img/logo.png')}
|
||||
/>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
<Text style={{ marginLeft: 10, fontSize: 18 }}>{title}</Text>
|
||||
</View>
|
||||
);
|
||||
|
|
@ -218,8 +363,8 @@ class App extends React.Component {
|
|||
SendEmail() {
|
||||
return (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', marginRight: 10 }}>
|
||||
<TextInput style={styles.searchInput} placeholder={i18n.t('global.email')} value={this.state.sendEmail} onChangeText={(text) => this.setState({ sendEmail: text })} />
|
||||
<TouchableOpacity style={styles.btnSearch} onPress={() => {
|
||||
<TextInput style={{ ...styles.searchInput, borderColor: this.state.mainColor }} placeholder={i18n.t('global.email')} value={this.state.sendEmail} onChangeText={(text) => this.setState({ sendEmail: text })} />
|
||||
<TouchableOpacity style={{ ...styles.btnSearch, backgroundColor: this.state.mainColor }} onPress={() => {
|
||||
if (this.state.sendEmail.length > 0) {
|
||||
if (Helpers.isEmailValid(this.state.sendEmail)) {
|
||||
const email = {
|
||||
|
|
@ -252,217 +397,25 @@ class App extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const savedLocale = CommonModel.get('locale');
|
||||
let locale;
|
||||
if (savedLocale !== undefined) {
|
||||
locale = savedLocale.value;
|
||||
} else {
|
||||
locale = store.getState().locale;
|
||||
}
|
||||
renderFlag() {
|
||||
let flag;
|
||||
switch (locale) {
|
||||
switch (store.getState().locale.locale) {
|
||||
case "fr":
|
||||
flag = require('./assets/img/flags/fr.png');
|
||||
break;
|
||||
break;
|
||||
case "en":
|
||||
flag = require('./assets/img/flags/en.png');
|
||||
break;
|
||||
break;
|
||||
case "de":
|
||||
flag = require('./assets/img/flags/de.png');
|
||||
break;
|
||||
break;
|
||||
case "es":
|
||||
flag = require('./assets/img/flags/es.png');
|
||||
break;
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<NavigationContainer>
|
||||
<Stack.Navigator>
|
||||
{this.state.logged === false ? (
|
||||
<Stack.Screen
|
||||
name="LoginScreen"
|
||||
component={LoginScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(i18n.t('global.login')),
|
||||
headerRight: () => (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
store.dispatch({ type: 'UPDATE_LOCALE' });
|
||||
this.setState({ state: this.state }); // to force re-rendering
|
||||
}}
|
||||
style={{ marginRight: 15 }}>
|
||||
<Image source={flag} style={{ width: 25, height: 25 }} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
),
|
||||
})}
|
||||
/>
|
||||
) : (
|
||||
<Stack.Screen
|
||||
name="HomeScreen"
|
||||
component={HomeScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(i18n.t('global.home')),
|
||||
headerRight: () => (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<View style={{ flexDirection: 'row', marginRight: 50 }}>
|
||||
<TextInput style={styles.searchInput} placeholder={i18n.t('global.search')} value={this.state.searchTxt} onChangeText={(text) => this.setState({ searchTxt: text })} />
|
||||
<TouchableOpacity style={styles.btnSearch} onPress={() => {
|
||||
if (this.state.searchTxt.length > 0) {
|
||||
navigation.navigation.navigate('SearchScreen', {
|
||||
needle: this.state.searchTxt,
|
||||
onlyVideos: false,
|
||||
});
|
||||
this.setState({ searchTxt: '' });
|
||||
}
|
||||
}}>
|
||||
<Icon name={'search'} size={20} color={'white'} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
store.dispatch({ type: 'UPDATE_LOCALE' });
|
||||
}}
|
||||
style={{ marginRight: 25 }}>
|
||||
<Image source={flag} style={{ width: 25, height: 25 }} />
|
||||
</TouchableOpacity>
|
||||
{this.state.ShowIsActive === '1' && (
|
||||
<TouchableOpacity
|
||||
onPress={() => navigation.navigation.navigate('MySpaceScreen')}
|
||||
style={{ marginRight: 25 }}>
|
||||
<Icon name="user-circle" size={25} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<TouchableOpacity
|
||||
onPress={() =>
|
||||
navigation.navigation.navigate('SyncScreen', {
|
||||
isInstalled: true,
|
||||
})
|
||||
}
|
||||
style={{ marginRight: 25 }}>
|
||||
<Icon name="sync-alt" size={20} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
store.dispatch({ type: 'SET_LOGGED', data: false });
|
||||
}}
|
||||
style={{ marginRight: 25 }}>
|
||||
<Icon name="sign-out-alt" size={20} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
),
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
<Stack.Screen
|
||||
name="SyncScreen"
|
||||
component={SyncScreen}
|
||||
options={{ headerTitle: () => this.LogoTitle(i18n.t('global.synchronization')) }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="DirectoriesScreen"
|
||||
component={DirectoriesScreen}
|
||||
options={{ headerTitle: () => this.LogoTitle(i18n.t('app.folders')) }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="OnlyVideosScreen"
|
||||
component={OnlyVideosScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(i18n.t('global.videos')),
|
||||
headerRight: () => (
|
||||
<View style={{ flexDirection: 'row', marginRight: 5 }}>
|
||||
<TextInput style={styles.searchInput} placeholder={i18n.t('global.search')} value={this.state.searchTxt} onChangeText={(text) => this.setState({ searchTxt: text })} />
|
||||
<TouchableOpacity style={styles.btnSearch} onPress={() => {
|
||||
if (this.state.searchTxt.length > 0) {
|
||||
navigation.navigation.navigate('SearchScreen', {
|
||||
needle: this.state.searchTxt,
|
||||
onlyVideos: true,
|
||||
});
|
||||
this.setState({ searchTxt: '' });
|
||||
}
|
||||
}}>
|
||||
<Icon name={'search'} size={20} color={'white'} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
),
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="VideoScreen"
|
||||
component={VideoScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(i18n.t('app.video')),
|
||||
headerRight: () => this.SendEmail(),
|
||||
orientation: 'landscape'
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="PDFScreen"
|
||||
component={PDFScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle('PDF'),
|
||||
headerRight: () => this.SendEmail()
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="ContactScreen"
|
||||
component={ContactScreen}
|
||||
options={{ headerTitle: () => this.LogoTitle(i18n.t('global.contacts')) }}
|
||||
initialParams={{ contactAdded: false }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="ContactDetailsScreen"
|
||||
component={ContactDetailsScreen}
|
||||
options={{ headerTitle: () => this.LogoTitle(i18n.t('app.contact_details')) }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="SearchScreen"
|
||||
component={SearchScreen}
|
||||
options={{ headerTitle: () => this.LogoTitle(i18n.t('app.results_search')) }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="MySpaceScreen"
|
||||
component={MySpaceScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () => this.LogoTitle(i18n.t('app.my_space')),
|
||||
headerRight: () => (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
const folder = store.getState().directories.filter(tmp => tmp.id === 1);
|
||||
navigation.navigation.navigate('DirectoriesScreen', { folder: folder })
|
||||
}}
|
||||
style={{ marginRight: 15 }}>
|
||||
<Icon name="briefcase" size={20} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
),
|
||||
})}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
<FlashMessage position="top" />
|
||||
</NavigationContainer>
|
||||
</Provider>
|
||||
);
|
||||
return flag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
searchInput: {
|
||||
borderWidth: 1,
|
||||
borderColor: '#ea4f52',
|
||||
width: 200,
|
||||
paddingLeft: 20,
|
||||
},
|
||||
btnSearch: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#ea4f52'
|
||||
}
|
||||
});
|
||||
|
||||
export default App;
|
||||
export default Sentry.wrap(App);
|
||||
|
|
|
|||
|
|
@ -9,68 +9,19 @@ import NetInfo from "@react-native-community/netinfo";
|
|||
import i18n from "../../I18n";
|
||||
// Database
|
||||
import { Setting } from "../../Database";
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
|
||||
const api_token = 'toto';
|
||||
|
||||
const api_token = 'G9Q62jt8eL8gN4Ls';
|
||||
class InstallController {
|
||||
|
||||
getConfig(url) {
|
||||
NetInfo.fetch().then(state => {
|
||||
if (state.isConnected) {
|
||||
axios({
|
||||
method: 'GET',
|
||||
url: url + '/api/settings',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token
|
||||
},
|
||||
})
|
||||
.then(function (response) {
|
||||
if (response.data) {
|
||||
if (response.data.status === "OK") {
|
||||
_.forEach(response.data.datas, function (value, key) {
|
||||
switch (key) {
|
||||
case "MainColor":
|
||||
Setting.upsert({ key: key, value: value });
|
||||
break;
|
||||
case "SquaredLogo":
|
||||
case "RectangleLogo":
|
||||
case "BackgroundImage":
|
||||
case "HomeButtonImage":
|
||||
FileSystem.downloadAsync(
|
||||
url + "/" + value,
|
||||
FileSystem.documentDirectory + key + '.png'
|
||||
)
|
||||
.then(({ uri }) => {
|
||||
console.log('Finished downloading to ', uri);
|
||||
})
|
||||
.catch(error => {
|
||||
Alert.alert(i18n.t("alert.error"), i18n.t("install.resource_dl_error") + key);
|
||||
console.error(error);
|
||||
return false;
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Alert.alert(i18n.t("alert.error"), i18n.t("error.error_has_occurred"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error)
|
||||
Alert.alert(i18n.t("alert.error"), i18n.t("error.error_has_occurred"));
|
||||
return false;
|
||||
})
|
||||
} else {
|
||||
Alert.alert(i18n.t("alert.error"), i18n.t("error.tablet_not_connected_internet"));
|
||||
return false;
|
||||
}
|
||||
async getConfig(url) {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: url + '/api/settings',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token
|
||||
},
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
getAppConfig(url) {
|
||||
|
|
|
|||
|
|
@ -9,27 +9,38 @@ import * as Application from 'expo-application';
|
|||
// Database
|
||||
import { Setting, Contact, SendBrochure, Document } from '../../Database';
|
||||
|
||||
const api_token = 'toto';
|
||||
const app_uuid = '1f6eda31-1f6d-49fe-aa81-4f0aece0f7ca';
|
||||
const url = "https://dev-app.rhd-ldc.fr";
|
||||
const api_token = 'G9Q62jt8eL8gN4Ls';
|
||||
|
||||
class SyncController {
|
||||
|
||||
getUrlBo() {
|
||||
const test = Setting.get('bo_url');
|
||||
if (test === false || test === undefined) {
|
||||
return "noset";
|
||||
}
|
||||
return test.value;
|
||||
}
|
||||
|
||||
getAppStoreUUID() {
|
||||
const test = Setting.get('AppStoreUUID');
|
||||
if (test === false || test === undefined) {
|
||||
return "noset";
|
||||
}
|
||||
return test.value;
|
||||
}
|
||||
|
||||
async checkConnection() {
|
||||
NetInfo.fetch().then(state => {
|
||||
return state.isConnected;
|
||||
});
|
||||
return false;
|
||||
return NetInfo.fetch();
|
||||
}
|
||||
|
||||
async getVersion() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: url + '/api/version',
|
||||
url: this.getUrlBo() + '/api/version',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
app_uuid: app_uuid,
|
||||
app_uuid: this.getAppStoreUUID(),
|
||||
app_version: Application.nativeApplicationVersion
|
||||
},
|
||||
});
|
||||
|
|
@ -38,7 +49,7 @@ class SyncController {
|
|||
async getUsers() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: url + '/api/users',
|
||||
url: this.getUrlBo() + '/api/users',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token
|
||||
|
|
@ -50,7 +61,7 @@ class SyncController {
|
|||
let contacts = Contact.getAll();
|
||||
return axios({
|
||||
method: 'POST',
|
||||
url: url + '/api/contacts',
|
||||
url: this.getUrlBo() + '/api/contacts',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token
|
||||
|
|
@ -62,26 +73,22 @@ class SyncController {
|
|||
});
|
||||
}
|
||||
|
||||
async sendBrochures() {
|
||||
let brochures = SendBrochure.getAll();
|
||||
for (const brochure of brochures) {
|
||||
await axios({
|
||||
method: 'POST',
|
||||
url: url + '/api/sendBrochure',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
emails: brochure,
|
||||
},
|
||||
});
|
||||
}
|
||||
SendBrochure.clear();
|
||||
async sendBrochure(brochure) {
|
||||
return axios({
|
||||
method: 'POST',
|
||||
url: this.getUrlBo() + '/api/sendBrochure',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
emails: brochure,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getDirectories() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: url + '/api/directories',
|
||||
url: this.getUrlBo() + '/api/directories',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token
|
||||
|
|
@ -92,7 +99,7 @@ class SyncController {
|
|||
async getDocuments() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: url + '/api/documents',
|
||||
url: this.getUrlBo() + '/api/documents',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
|
|
@ -123,26 +130,18 @@ class SyncController {
|
|||
}
|
||||
|
||||
isSynced() {
|
||||
const SendBrochure = SendBrochure.getAll();
|
||||
const brochures = SendBrochure.getAll();
|
||||
const Contacts = Contact.getAll();
|
||||
|
||||
if (SendBrochure !== undefined && Contacts !== undefined) {
|
||||
if (brochures !== undefined && Contacts !== undefined) {
|
||||
const noSynced = Contacts.filtered('synced = false');
|
||||
if (SendBrochure.length > 0 || noSynced.length > 0) {
|
||||
if (brochures.length > 0 || noSynced.length > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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');
|
||||
|
|
@ -162,6 +161,53 @@ class SyncController {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
needSync(callback) {
|
||||
NetInfo.fetch().then(state => {
|
||||
if (state.isConnected) {
|
||||
axios({
|
||||
method: 'get',
|
||||
url: this.getUrlBo() + '/version',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
const localVersion = Setting.get('version');
|
||||
if (
|
||||
localVersion === undefined ||
|
||||
localVersion === false ||
|
||||
localVersion.value !== response.data.version
|
||||
) {
|
||||
return callback();
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
setInstalled(remove = false) {
|
||||
if (remove) {
|
||||
Setting.delete('installed');
|
||||
} else {
|
||||
Setting.add({ key: 'installed', value: "true" });
|
||||
}
|
||||
}
|
||||
|
||||
isInstalled() {
|
||||
const test = Setting.get('installed');
|
||||
if (test === false || test === undefined) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default new SyncController();
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
class Helpers {
|
||||
compareValues(key, order = 'asc') {
|
||||
return function innerSort(a, b) {
|
||||
if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
|
||||
if (!(key in a) || !(key in b)) {
|
||||
// property doesn't exist on either object
|
||||
return 0;
|
||||
}
|
||||
|
||||
const varA = (typeof a[key] === 'string')
|
||||
? a[key].toUpperCase() : a[key];
|
||||
const varB = (typeof b[key] === 'string')
|
||||
|
|
@ -29,7 +28,7 @@ class Helpers {
|
|||
}
|
||||
|
||||
isUrlValid(value) {
|
||||
return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value);
|
||||
return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value.toLowerCase());
|
||||
}
|
||||
|
||||
generateUUID() { // Public Domain/MIT
|
||||
|
|
|
|||
|
|
@ -1,3 +1,29 @@
|
|||
export const ContactsSchema = {
|
||||
name: 'Contacts',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
type: 'string',
|
||||
other: { type: 'string', optional: true },
|
||||
select1: { type: 'string', optional: true },
|
||||
select2: { type: 'string', optional: true },
|
||||
name: 'string',
|
||||
firstname: 'string',
|
||||
company: { type: 'string', optional: true },
|
||||
address: { type: 'string', optional: true },
|
||||
phone: 'string',
|
||||
products: { type: 'string', optional: true },
|
||||
// TODO : card_url ?
|
||||
notes: { type: 'string', optional: true },
|
||||
visits: { type: 'string', optional: true },
|
||||
user_id: 'int',
|
||||
uniq_id: 'string',
|
||||
to_delete: { type: 'bool', default: false },
|
||||
synced: { type: 'bool', default: true },
|
||||
},
|
||||
};
|
||||
|
||||
class ContactModel {
|
||||
constructor(realm) {
|
||||
this.schema = 'Contacts';
|
||||
|
|
@ -67,6 +93,15 @@ class ContactModel {
|
|||
});
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const tmp = this.get(key);
|
||||
if (typeof tmp === 'object') {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(tmp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ContactModel;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,14 @@
|
|||
export const DirectoriesSchema = {
|
||||
name: 'Directories',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
name: 'string',
|
||||
parent: { type: 'int', optional: true },
|
||||
order: 'int',
|
||||
needAuthorization: 'int',
|
||||
},
|
||||
};
|
||||
class DirectoryModel {
|
||||
constructor(realm) {
|
||||
this.schema = 'Directories';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,18 @@
|
|||
export const DocumentsSchema = {
|
||||
name: 'Documents',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
uuid: 'string',
|
||||
title: 'string',
|
||||
type: 'string',
|
||||
path: 'string',
|
||||
directory: 'int',
|
||||
lang: 'string',
|
||||
updated_at: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
class DocumentModel {
|
||||
constructor(realm) {
|
||||
this.schema = 'Documents';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,16 @@
|
|||
export const SendBrochuresSchema = {
|
||||
name: 'SendBrochures',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
subject: 'string',
|
||||
message: 'string',
|
||||
documents: 'string',
|
||||
user_id: 'int'
|
||||
},
|
||||
};
|
||||
|
||||
class SendBrochureModel {
|
||||
constructor(realm) {
|
||||
this.schema = 'SendBrochures';
|
||||
|
|
@ -59,6 +72,15 @@ class SendBrochureModel {
|
|||
});
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const tmp = this.get(key);
|
||||
if (typeof tmp === 'object') {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(tmp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SendBrochureModel;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,13 @@
|
|||
export const SettingsSchema = {
|
||||
name: 'Settings',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
key: 'string',
|
||||
value: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
class SettingModel {
|
||||
constructor(realm) {
|
||||
this.schema = 'Settings';
|
||||
|
|
@ -59,4 +69,4 @@ class SettingModel {
|
|||
|
||||
}
|
||||
|
||||
export default SettingModel;
|
||||
export default SettingModel;
|
||||
|
|
@ -1,3 +1,17 @@
|
|||
export const UsersSchema = {
|
||||
name: 'Users',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
surname: 'string',
|
||||
firstname: 'string',
|
||||
password: 'string',
|
||||
role: 'string',
|
||||
authorizedFolders: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
class UserModel {
|
||||
constructor(realm) {
|
||||
this.schema = 'Users';
|
||||
|
|
|
|||
14
ComApp/src/App/Store/Actions/actionType.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Locale
|
||||
export const INIT_LOCALE = "INIT_LOCALE";
|
||||
export const EDIT_LOCALE = "EDIT_LOCALE";
|
||||
// Users
|
||||
export const INIT_USERS = "INIT_USERS";
|
||||
// Contacts
|
||||
export const INIT_CONTACT = "INIT_CONTACT";
|
||||
export const ADD_CONTACT = "ADD_CONTACT";
|
||||
export const EDIT_CONTACT = "EDIT_CONTACT";
|
||||
export const DELETE_CONTACT = "DELETE_CONTACT";
|
||||
// Directories
|
||||
export const INIT_DIRECTORIES = "INIT_DIRECTORIES";
|
||||
// Documents
|
||||
export const INIT_DOCUMENTS = "INIT_DOCUMENTS";
|
||||
53
ComApp/src/App/Store/Actions/contacts.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { INIT_CONTACT, ADD_CONTACT, EDIT_CONTACT, DELETE_CONTACT } from "./actionType";
|
||||
|
||||
/**
|
||||
* Init contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {object} data The contact 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 = (currentUser, data) => {
|
||||
return {
|
||||
type: ADD_CONTACT,
|
||||
currentUser,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Edit contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {object} data The contact data
|
||||
*/
|
||||
export const editContact = (currentUser, data) => {
|
||||
return {
|
||||
type: EDIT_CONTACT,
|
||||
currentUser,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {string} id The contact id
|
||||
*/
|
||||
export const deleteContact = (currentUser, id) => {
|
||||
return {
|
||||
type: DELETE_CONTACT,
|
||||
currentUser,
|
||||
id,
|
||||
};
|
||||
};
|
||||
16
ComApp/src/App/Store/Actions/directories.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { INIT_DIRECTORIES } from "./actionType";
|
||||
|
||||
/**
|
||||
* Init
|
||||
* @param {string} lang The lang
|
||||
* @param {object} user User
|
||||
* @param {object} data The document data
|
||||
*/
|
||||
export const initDirectories = (lang, user, data) => {
|
||||
return {
|
||||
type: INIT_DIRECTORIES,
|
||||
lang,
|
||||
user,
|
||||
data,
|
||||
};
|
||||
};
|
||||
16
ComApp/src/App/Store/Actions/documents.js
Normal file
|
|
@ -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,
|
||||
};
|
||||
};
|
||||
23
ComApp/src/App/Store/Actions/locales.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { INIT_LOCALE, EDIT_LOCALE } from "./actionType";
|
||||
|
||||
/**
|
||||
* Init locale
|
||||
* @param {object} data The locale data
|
||||
*/
|
||||
export const initLocale = data => {
|
||||
return {
|
||||
type: INIT_LOCALE,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Edit locale
|
||||
* @param {object} data The locale data
|
||||
*/
|
||||
export const editLocale = data => {
|
||||
return {
|
||||
type: EDIT_LOCALE,
|
||||
data,
|
||||
};
|
||||
};
|
||||
12
ComApp/src/App/Store/Actions/users.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { INIT_USERS } from "./actionType";
|
||||
|
||||
/**
|
||||
* Init users
|
||||
* @param {object} data The users data
|
||||
*/
|
||||
export const initUsers = data => {
|
||||
return {
|
||||
type: INIT_USERS,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
|
@ -1,9 +1,19 @@
|
|||
import { createStore, combineReducers } from "redux";
|
||||
|
||||
import appReducer from "./Reducers/AppReducer";
|
||||
import contactsReducer from "./Reducers/contacts";
|
||||
import documentsReducer from "./Reducers/documents";
|
||||
import directoriesReducer from "./Reducers/directories";
|
||||
import localesReducer from "./Reducers/locales";
|
||||
import usersReducer from "./Reducers/users";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
app: appReducer
|
||||
app: appReducer,
|
||||
contacts: contactsReducer,
|
||||
documents: documentsReducer,
|
||||
directories: directoriesReducer,
|
||||
locale: localesReducer,
|
||||
users: usersReducer
|
||||
});
|
||||
|
||||
export const store = createStore(rootReducer);
|
||||
|
|
@ -1,94 +1,103 @@
|
|||
import SyncController from "../../Controllers/SyncController";
|
||||
// Database
|
||||
import { Setting, Contact, User, Directory, Document, SendBrochure } from '../../../Database';
|
||||
// Translations
|
||||
import i18n from "../../../I18n";
|
||||
import { Setting, SendBrochure } from '../../../Database';
|
||||
|
||||
const initialState = {
|
||||
isSetup: false,
|
||||
locale: 'fr',
|
||||
users: {},
|
||||
directories: {},
|
||||
documents: {},
|
||||
contacts: {},
|
||||
syncVersion: 0,
|
||||
logged: undefined,
|
||||
currentUser: {},
|
||||
logged: false,
|
||||
syncVersion: 0,
|
||||
forceSync: false,
|
||||
currentOpenedDoc: {},
|
||||
ShowIsActive: 0,
|
||||
HomeBtns: {},
|
||||
mainColor: '#D4021D',
|
||||
FormSelect1: {},
|
||||
FormSelect2: {},
|
||||
FormCheck: [],
|
||||
};
|
||||
|
||||
const reducer = (state = initialState, action) => {
|
||||
let saved;
|
||||
switch (action.type) {
|
||||
case 'INIT':
|
||||
let directories = Directory.getAll(
|
||||
state.currentUser.role,
|
||||
state.currentUser.authorizedFolders,
|
||||
false,
|
||||
state.locale
|
||||
);
|
||||
let docs = Document.getAll(directories);
|
||||
let ShowIsActive = Setting.get('ShowIsActive');
|
||||
let MainColor = Setting.get('MainColor');
|
||||
let FormSelect1 = Setting.get('FormSelect1');
|
||||
let FormSelect2 = Setting.get('FormSelect2');
|
||||
let FormCheck = Setting.get('FormCheck');
|
||||
saved = Setting.get('isSetup');
|
||||
return {
|
||||
...state,
|
||||
users: User.getAll(),
|
||||
directories: Directory.getAll(
|
||||
state.currentUser.role,
|
||||
state.currentUser.authorizedFolders,
|
||||
true,
|
||||
state.locale
|
||||
),
|
||||
documents: docs.filter(item => item.lang === state.locale),
|
||||
contacts: Contact.getByUser(state.currentUser.id),
|
||||
ShowIsActive: Setting.get('ShowIsActive')['value'],
|
||||
isSetup: saved === undefined ? false : saved.value === "true" ? true : false,
|
||||
ShowIsActive: ShowIsActive === undefined ? false : ShowIsActive.value,
|
||||
mainColor: MainColor === undefined ? initialState.mainColor : MainColor === false ? initialState.mainColor : MainColor.value,
|
||||
FormSelect1: FormSelect1 === undefined ? initialState.FormSelect1 : FormSelect1 === false ? initialState.FormSelect1 : JSON.parse(FormSelect1.value),
|
||||
FormSelect2: FormSelect2 === undefined ? initialState.FormSelect2 : FormSelect2 === false ? initialState.FormSelect2 : JSON.parse(FormSelect2.value),
|
||||
FormCheck: FormCheck === undefined ? initialState.FormCheck : FormCheck === false ? initialState.FormCheck : JSON.parse(FormCheck.value),
|
||||
};
|
||||
case 'INIT_USERS':
|
||||
case 'INIT_HOME_BTNS': {
|
||||
let HomeFolders = Setting.get('HomeFolders');
|
||||
let Btns = JSON.parse(HomeFolders.value);
|
||||
return {
|
||||
...state,
|
||||
users: User.getAll(),
|
||||
HomeBtns: Btns
|
||||
}
|
||||
}
|
||||
case 'SET_ISSETUP':
|
||||
Setting.upsert({ key: 'isSetup', value: "true" });
|
||||
saved = Setting.get('isSetup');
|
||||
return {
|
||||
...state,
|
||||
isSetup: saved === undefined ? false : saved.value === "true" ? true : false
|
||||
};
|
||||
case 'SET_CURRENT_USER':
|
||||
return {
|
||||
...state,
|
||||
currentUser: JSON.parse(action.data),
|
||||
};
|
||||
case 'SET_LOGGED':
|
||||
let user = false;
|
||||
let isLogged = false;
|
||||
if (action.data === false) {
|
||||
Setting.delete('isLogged');
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
logged: action.data,
|
||||
};
|
||||
case 'UPDATE_LOCALE':
|
||||
let nxt;
|
||||
if (action.data === undefined) {
|
||||
const availableLocales = ['fr', 'en', 'de'];
|
||||
if (availableLocales.indexOf(i18n.locale) === availableLocales.length - 1) {
|
||||
nxt = availableLocales[0];
|
||||
} else {
|
||||
nxt = availableLocales[availableLocales.indexOf(i18n.locale) + 1];
|
||||
}
|
||||
} else {
|
||||
nxt = action.data;
|
||||
userObj = Setting.get('isLogged').value
|
||||
user = JSON.parse(userObj)
|
||||
isLogged = true
|
||||
}
|
||||
i18n.locale = nxt;
|
||||
Setting.upsert({ key: 'locale', value: nxt });
|
||||
let docsL = Document.getAll(Directory.getAll(
|
||||
state.currentUser.role,
|
||||
state.currentUser.authorizedFolders,
|
||||
false,
|
||||
nxt
|
||||
));
|
||||
return {
|
||||
...state,
|
||||
locale: nxt,
|
||||
directories: Directory.getAll(
|
||||
state.currentUser.role,
|
||||
state.currentUser.authorizedFolders,
|
||||
true,
|
||||
nxt
|
||||
),
|
||||
documents: docsL.filter(item => item.lang === nxt),
|
||||
currentUser: user !== false ? user : initialState.currentUser,
|
||||
logged: isLogged
|
||||
};
|
||||
// case 'UPDATE_LOCALE':
|
||||
// let nxt;
|
||||
// if (action.data === undefined) {
|
||||
// const availableLocales = ['fr', 'en', 'de'];
|
||||
// if (availableLocales.indexOf(i18n.locale) === availableLocales.length - 1) {
|
||||
// nxt = availableLocales[0];
|
||||
// } else {
|
||||
// nxt = availableLocales[availableLocales.indexOf(i18n.locale) + 1];
|
||||
// }
|
||||
// } else {
|
||||
// nxt = action.data;
|
||||
// }
|
||||
// i18n.locale = nxt;
|
||||
// Setting.upsert({ key: 'locale', value: nxt });
|
||||
// let docsL = Document.getAll(Directory.getAll(
|
||||
// state.currentUser.role,
|
||||
// state.currentUser.authorizedFolders,
|
||||
// false,
|
||||
// nxt
|
||||
// ));
|
||||
// return {
|
||||
// ...state,
|
||||
// locale: nxt,
|
||||
// directories: Directory.getAll(
|
||||
// state.currentUser.role,
|
||||
// state.currentUser.authorizedFolders,
|
||||
// true,
|
||||
// nxt
|
||||
// ),
|
||||
// documents: docsL.filter(item => item.lang === nxt),
|
||||
// };
|
||||
case 'SET_CURRENT_OPENED_DOC':
|
||||
return {
|
||||
...state,
|
||||
|
|
@ -105,24 +114,6 @@ const reducer = (state = initialState, action) => {
|
|||
...state,
|
||||
ShowIsActive: action.data,
|
||||
};
|
||||
case 'UPDATE_CONTACT':
|
||||
Contact.update(action.data);
|
||||
return {
|
||||
...state,
|
||||
contacts: Contact.getByUser(state.currentUser.id),
|
||||
};
|
||||
case 'ADD_CONTACT':
|
||||
Contact.add(action.data);
|
||||
return {
|
||||
...state,
|
||||
contacts: Contact.getByUser(state.currentUser.id),
|
||||
};
|
||||
case 'DELETE_CONTACT':
|
||||
Contact.delete(action.data);
|
||||
return {
|
||||
...state,
|
||||
contacts: Contact.getByUser(state.currentUser.id),
|
||||
};
|
||||
case 'SEND_BROCHURE':
|
||||
SendBrochure.add(action.data);
|
||||
return state;
|
||||
|
|
|
|||
32
ComApp/src/App/Store/Reducers/contacts.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { INIT_CONTACT, ADD_CONTACT, EDIT_CONTACT, DELETE_CONTACT } from "../Actions/actionType";
|
||||
// Models
|
||||
import { Contact } from "../../../Database";
|
||||
|
||||
const initialState = [];
|
||||
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_CONTACT: {
|
||||
return Contact.getByUser(action.currentUser.id);
|
||||
}
|
||||
case ADD_CONTACT: {
|
||||
action.data.user_id = action.currentUser.id;
|
||||
Contact.add(action.data);
|
||||
return Contact.getByUser(action.currentUser.id);
|
||||
}
|
||||
case EDIT_CONTACT: {
|
||||
Contact.update(action.data);
|
||||
return Contact.getByUser(action.currentUser.id);
|
||||
}
|
||||
case DELETE_CONTACT: {
|
||||
Contact.delete(action.id);
|
||||
return Contact.getByUser(action.currentUser.id);
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
32
ComApp/src/App/Store/Reducers/directories.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { INIT_DIRECTORIES } from "../Actions/actionType";
|
||||
// Models
|
||||
import { Directory } from "../../../Database";
|
||||
|
||||
const initialState = [];
|
||||
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_DIRECTORIES: {
|
||||
return {
|
||||
global: Directory.getAll(
|
||||
action.user.role,
|
||||
action.user.authorizedFolders,
|
||||
false,
|
||||
action.lang
|
||||
),
|
||||
treeview: Directory.getAll(
|
||||
action.user.role,
|
||||
action.user.authorizedFolders,
|
||||
true,
|
||||
action.lang
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
23
ComApp/src/App/Store/Reducers/documents.js
Normal file
|
|
@ -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);
|
||||
if (docs.length === 0) {
|
||||
return state
|
||||
}
|
||||
return docs.filter(item => item.lang === action.lang);
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
45
ComApp/src/App/Store/Reducers/locales.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import { INIT_LOCALE, EDIT_LOCALE } from "../Actions/actionType";
|
||||
// Models
|
||||
import { Setting } from "../../../Database";
|
||||
// Translations
|
||||
import i18n from "../../../I18n";
|
||||
|
||||
const initialState = [];
|
||||
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_LOCALE: {
|
||||
const savedLocale = Setting.get('locale');
|
||||
return {
|
||||
...state,
|
||||
locale: savedLocale === undefined ? 'fr' : savedLocale === false ? 'fr' : savedLocale.value
|
||||
};
|
||||
}
|
||||
|
||||
case EDIT_LOCALE: {
|
||||
let nxt;
|
||||
if (action.data === undefined) {
|
||||
const availableLocales = ['fr', 'en', 'de'];
|
||||
if (availableLocales.indexOf(i18n.locale) === availableLocales.length - 1) {
|
||||
nxt = availableLocales[0];
|
||||
} else {
|
||||
nxt = availableLocales[availableLocales.indexOf(i18n.locale) + 1];
|
||||
}
|
||||
} else {
|
||||
nxt = action.data;
|
||||
}
|
||||
i18n.locale = nxt;
|
||||
Setting.upsert({ key: 'locale', value: nxt });
|
||||
return {
|
||||
...state,
|
||||
locale: nxt,
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
22
ComApp/src/App/Store/Reducers/users.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { INIT_USERS } from "../Actions/actionType";
|
||||
// Models
|
||||
import { User } from "../../../Database";
|
||||
|
||||
const initialState = [];
|
||||
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_USERS: {
|
||||
return {
|
||||
...state,
|
||||
users: User.getAll(),
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
|
|
@ -10,6 +10,7 @@ import {
|
|||
} from 'react-native';
|
||||
// Reduxs
|
||||
import { connect } from 'react-redux';
|
||||
import { addContact, editContact } from '../Store/Actions/contacts';
|
||||
// Helpers
|
||||
import Helpers from "../Lib/Helpers";
|
||||
// Translations
|
||||
|
|
@ -31,11 +32,23 @@ import { BarCodeScanner } from 'expo-barcode-scanner';
|
|||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
contacts: state.app.contacts,
|
||||
locale: state.locale.locale,
|
||||
contacts: state.contacts,
|
||||
currentUser: state.app.currentUser,
|
||||
mainColor: state.app.mainColor,
|
||||
FormSelect1: state.app.FormSelect1,
|
||||
FormSelect2: state.app.FormSelect2,
|
||||
FormCheck: state.app.FormCheck,
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
addContact: (user, data) => dispatch(addContact(user, data)),
|
||||
editContact: (user, data) => dispatch(editContact(user, data))
|
||||
};
|
||||
};
|
||||
|
||||
let date = new Date().getDate();
|
||||
if (date < 10) {
|
||||
date = '0' + date.toString();
|
||||
|
|
@ -69,15 +82,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
clientChecked: false,
|
||||
prospectChecked: false,
|
||||
otherChecked: false,
|
||||
p1: false,
|
||||
p2: false,
|
||||
p3: false,
|
||||
p4: false,
|
||||
p5: false,
|
||||
p6: false,
|
||||
p7: false,
|
||||
p8: false,
|
||||
p9: false,
|
||||
productsCheck: [],
|
||||
showQRcodevCard: false,
|
||||
parsedType: null,
|
||||
parsedDatas: [],
|
||||
|
|
@ -131,17 +136,6 @@ class ContactDetailsScreen extends React.Component {
|
|||
{ cancelable: false },
|
||||
);
|
||||
} else {
|
||||
const products = [
|
||||
this.state.p1,
|
||||
this.state.p2,
|
||||
this.state.p3,
|
||||
this.state.p4,
|
||||
this.state.p5,
|
||||
this.state.p6,
|
||||
this.state.p7,
|
||||
this.state.p8,
|
||||
this.state.p9
|
||||
];
|
||||
const contact = {
|
||||
id: Helpers.generateUUID(),
|
||||
email: this.state.tmpEmail,
|
||||
|
|
@ -154,7 +148,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
company: this.state.tmpCompany,
|
||||
address: this.state.tmpAddress,
|
||||
phone: this.state.tmpPhone,
|
||||
products: JSON.stringify(products),
|
||||
products: JSON.stringify(this.state.productsCheck),
|
||||
notes: this.state.tmpNote,
|
||||
visits: JSON.stringify(this.state.visits),
|
||||
to_delete: false,
|
||||
|
|
@ -162,7 +156,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
};
|
||||
if (action === 'edit') {
|
||||
contact.id = this.state.tmpID;
|
||||
this.props.dispatch({ type: 'UPDATE_CONTACT', data: contact });
|
||||
this.props.editContact(this.props.currentUser, contact);
|
||||
this.populate();
|
||||
showMessage({
|
||||
message: i18n.t('contact_details_s.contact_saved') + '.',
|
||||
|
|
@ -170,8 +164,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
duration: 500,
|
||||
});
|
||||
} else {
|
||||
contact.user_id = this.props.currentUser.id;
|
||||
this.props.dispatch({ type: 'ADD_CONTACT', data: contact });
|
||||
this.props.addContact(this.props.currentUser, contact);
|
||||
this.props.navigation.navigate('ContactScreen', { contactAdded: true });
|
||||
}
|
||||
}
|
||||
|
|
@ -261,7 +254,6 @@ class ContactDetailsScreen extends React.Component {
|
|||
tmpSelect1: contact.select1,
|
||||
tmpSelect2: contact.select2,
|
||||
tmpOther: contact.other,
|
||||
tmpProducts: contact.product,
|
||||
});
|
||||
if (contact.type === 'client') {
|
||||
this.setState({ clientChecked: true });
|
||||
|
|
@ -279,18 +271,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
}
|
||||
if (contact.products !== null) {
|
||||
const tmp = JSON.parse(contact.products);
|
||||
this.setState({
|
||||
p1: tmp[0],
|
||||
p2: tmp[1],
|
||||
p3: tmp[2],
|
||||
p4: tmp[3],
|
||||
p5: tmp[4],
|
||||
p6: tmp[5],
|
||||
p7: tmp[6],
|
||||
p8: tmp[7],
|
||||
p9: tmp[8],
|
||||
p10: tmp[9],
|
||||
});
|
||||
this.setState({ productsCheck: tmp });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -354,7 +335,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
justifyContent: 'center',
|
||||
}}>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.customer')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -364,7 +345,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
onPress={() => this.updateContactType('client')}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.prospect')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -374,7 +355,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
onPress={() => this.updateContactType('prospect')}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.other')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -452,29 +433,8 @@ class ContactDetailsScreen extends React.Component {
|
|||
this.setState({ tmpSelect1: itemValue });
|
||||
}
|
||||
}}>
|
||||
<Picker.Item label={i18n.t('custom.select-1.title')} value="0" />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c1')} value="commerce-de-detail" />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c2')} value={'home-service-freezer-center'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c3')} value={'restauration-service-a-table'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c4')} value={'fast-food-et-snacking'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c5')} value={'cafetaria-self-service'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c6')} value={'societe-de-restauration'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c7')} value={'restauration-gre-a-gre-cuisine-centrale'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c8')} value={'distributeur-independant'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c9')} value={'boulangerie-patisserie'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c10')} value={'pai'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c11')} value={'destockeur'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c12')} value={'commerce-halal'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c13')} value={'restauration-d-hebergement'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c14')} value={'centrale-restauration-commerciale'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c15')} value={'restauration-evenementielle-et-parc'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c16')} value={'restauration-de-transport'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c17')} value={'marche-public'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c18')} value={'cash'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c19')} value={'distributeur-national'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c20')} value={'rungis'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c21')} value={'abbatoir'} />
|
||||
<Picker.Item label={i18n.t('custom.select-1.c22')} value={'autre'} />
|
||||
<Picker.Item label={this.props.FormSelect1.title[this.props.locale]} value="0" />
|
||||
{this.renderSelect(1)}
|
||||
</Picker>
|
||||
</View>
|
||||
<View style={{ flex: 1, flexDirection: 'row' }}>
|
||||
|
|
@ -487,19 +447,8 @@ class ContactDetailsScreen extends React.Component {
|
|||
this.setState({ tmpSelect2: itemValue });
|
||||
}
|
||||
}}>
|
||||
<Picker.Item label={i18n.t('custom.select-2.title')} value="0" />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c1')} value={'celvia-dinde'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c2')} value={'celvia-elabores'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c3')} value={'celvia-serent'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c4')} value={'procanar'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c5')} value={'celtys'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c6')} value={'farmor'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c7')} value={'robichon'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c8')} value={'les-volailles-de-keranna'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c9')} value={'bosher-volaille'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c10')} value={'ldc-bretagne'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c11')} value={'doux-farmor'} />
|
||||
<Picker.Item label={i18n.t('custom.select-2.c12')} value={'favreau'} />
|
||||
<Picker.Item label={this.props.FormSelect2.title[this.props.locale]} value="0" />
|
||||
{this.renderSelect(2)}
|
||||
</Picker>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -509,41 +458,14 @@ class ContactDetailsScreen extends React.Component {
|
|||
flexWrap: 'wrap',
|
||||
justifyContent: 'center',
|
||||
}}>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
title={i18n.t('custom.interest.p1')}
|
||||
checked={this.state.p1}
|
||||
onPress={() => this.setState({ p1: !this.state.p1 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
title={i18n.t('custom.interest.p2')}
|
||||
checked={this.state.p2}
|
||||
onPress={() => this.setState({ p2: !this.state.p2 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
title={i18n.t('custom.interest.p3')}
|
||||
checked={this.state.p3}
|
||||
onPress={() => this.setState({ p3: !this.state.p3 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
title={i18n.t('custom.interest.p4')}
|
||||
checked={this.state.p4}
|
||||
onPress={() => this.setState({ p4: !this.state.p4 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
{this.renderProductsCheck()}
|
||||
</View>
|
||||
</ScrollView>
|
||||
<View style={{ flex: 1, margin: 5 }}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<ButtonGroup
|
||||
buttons={[i18n.t('contact_details_s.visits'), i18n.t('contact_details_s.notes')]}
|
||||
selectedButtonStyle={{ backgroundColor: '#ea4f52' }}
|
||||
selectedButtonStyle={{ backgroundColor: this.props.mainColor }}
|
||||
containerStyle={{ height: 30 }}
|
||||
selectedIndex={this.state.selectedIndex}
|
||||
onPress={index => this.setState({ selectedIndex: index })}
|
||||
|
|
@ -595,13 +517,13 @@ class ContactDetailsScreen extends React.Component {
|
|||
<TouchableOpacity
|
||||
style={styles.button}
|
||||
onPress={() => this.setState({ showNewVisit: true })}>
|
||||
<FontAwesome5 name="plus-circle" size={20} color={'#ea4f52'} />
|
||||
<FontAwesome5 name="plus-circle" size={20} color={this.props.mainColor} />
|
||||
</TouchableOpacity>
|
||||
{this.state.visits.length > 0 && (
|
||||
<TouchableOpacity
|
||||
style={styles.button}
|
||||
onPress={() => this.deleteVisit()}>
|
||||
<FontAwesome5 name="trash" size={20} color={'#ea4f52'} />
|
||||
<FontAwesome5 name="trash" size={20} color={this.props.mainColor} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
|
|
@ -634,10 +556,10 @@ class ContactDetailsScreen extends React.Component {
|
|||
<View style={{ flexDirection: 'row', justifyContent: 'space-evenly' }}>
|
||||
{this.state.action === 'add' && (
|
||||
<>
|
||||
<Button title="QRCode vCard" onPress={() => this.setState({ showQRcodevCard: true })} color={'#ea4f52'} />
|
||||
<Button title="QRCode vCard" onPress={() => this.setState({ showQRcodevCard: true })} color={this.props.mainColor} />
|
||||
</>
|
||||
)}
|
||||
<Button title={i18n.t('global.save')} onPress={() => this.updateContact()} color={'#ea4f52'} />
|
||||
<Button title={i18n.t('global.save')} onPress={() => this.updateContact()} color={this.props.mainColor} />
|
||||
</View>
|
||||
</View>
|
||||
<Overlay
|
||||
|
|
@ -671,9 +593,9 @@ class ContactDetailsScreen extends React.Component {
|
|||
<Button
|
||||
title={i18n.t('global.cancel')}
|
||||
onPress={() => this.setState({ showNewVisit: false })}
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
/>
|
||||
<Button title={i18n.t('global.add')} onPress={() => this.newVisit()} color={'#ea4f52'} />
|
||||
<Button title={i18n.t('global.add')} onPress={() => this.newVisit()} color={this.props.mainColor} />
|
||||
</View>
|
||||
</View>
|
||||
</Overlay>
|
||||
|
|
@ -707,9 +629,9 @@ class ContactDetailsScreen extends React.Component {
|
|||
<Button
|
||||
title={i18n.t('global.cancel')}
|
||||
onPress={() => this.setState({ showQRcodevCard: false, scanned: false })}
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
/>
|
||||
{this.state.scanned && <Button title={i18n.t('global.retry')} onPress={() => this.setState({ scanned: false })} color={'#ea4f52'} />}
|
||||
{this.state.scanned && <Button title={i18n.t('global.retry')} onPress={() => this.setState({ scanned: false })} color={this.props.mainColor} />}
|
||||
</View>
|
||||
</View>
|
||||
</Overlay>
|
||||
|
|
@ -814,7 +736,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
<Button
|
||||
title={i18n.t('global.cancel')}
|
||||
onPress={() => this.setState({ showDynContact: false, scanned: false, parsedName: '', parsedFirstname: '', parsedEmail: '', parsedCompany: '', parsedAddress: '', parsedPhone: '' })}
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
/>
|
||||
<Button
|
||||
title={i18n.t('global.next')}
|
||||
|
|
@ -834,7 +756,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
showDynContact: false,
|
||||
scanned: false,
|
||||
})}
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -842,6 +764,43 @@ class ContactDetailsScreen extends React.Component {
|
|||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
renderSelect(num) {
|
||||
let objSelect = {};
|
||||
let locale = this.props.locale;
|
||||
if (num === 1) {
|
||||
objSelect = this.props.FormSelect1.values;
|
||||
} else if (num === 2) {
|
||||
objSelect = this.props.FormSelect2.values;
|
||||
}
|
||||
return Object.keys(objSelect).map((item) => {
|
||||
return (
|
||||
<Picker.Item key={item} label={objSelect[item][locale]} value={item} />
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
renderProductsCheck() {
|
||||
let locale = this.props.locale;
|
||||
let obj = obj = this.props.FormCheck;
|
||||
return Object.keys(obj).map((item) => {
|
||||
return (
|
||||
<CheckBox
|
||||
key={item}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={obj[item][locale]}
|
||||
checked={this.state.productsCheck[item]}
|
||||
onPress={() => {
|
||||
let pc = this.state.productsCheck;
|
||||
pc[item] = !pc[item]
|
||||
console.log(pc)
|
||||
this.setState({ productsCheck: pc });
|
||||
}}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(ContactDetailsScreen);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ContactDetailsScreen);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import {
|
|||
} from 'react-native';
|
||||
// Reduxs
|
||||
import { connect } from 'react-redux';
|
||||
import { editContact } from '../Store/Actions/contacts';
|
||||
import { deleteContact } from '../Store/Actions/contacts';
|
||||
// Helpers
|
||||
import Helpers from "../Lib/Helpers";
|
||||
// Translations
|
||||
|
|
@ -27,13 +29,22 @@ import styles from '../../Resources/Styles/ContactStyle';
|
|||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
users: state.app.users,
|
||||
contacts: state.app.contacts,
|
||||
documents: state.app.documents,
|
||||
users: state.users.users,
|
||||
contacts: state.contacts,
|
||||
documents: state.documents,
|
||||
currentUser: state.app.currentUser,
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
editContact: (user, data) => dispatch(editContact(user, data)),
|
||||
deleteContact: (user, id) => dispatch(deleteContact(user, id)),
|
||||
sendBrochure: (email) => dispatch({ type: 'SEND_BROCHURE', data: email })
|
||||
};
|
||||
};
|
||||
|
||||
class ContactScreen extends React.Component {
|
||||
state = {
|
||||
contacts: [],
|
||||
|
|
@ -69,7 +80,7 @@ class ContactScreen extends React.Component {
|
|||
documents: JSON.stringify(this.state.sendDocumentList),
|
||||
user_id: this.props.currentUser.id
|
||||
};
|
||||
this.props.dispatch({ type: 'SEND_BROCHURE', data: email });
|
||||
this.props.sendBrochure(email);
|
||||
this.setState({
|
||||
showSendBrochure: false,
|
||||
tmpSendBrochureEmail: '',
|
||||
|
|
@ -115,7 +126,7 @@ class ContactScreen extends React.Component {
|
|||
synced: false,
|
||||
user_id: nextUser.id,
|
||||
};
|
||||
this.props.dispatch({ type: 'UPDATE_CONTACT', data: contact });
|
||||
this.props.editContact(this.props.currentUser, contact);
|
||||
this.setState({ showTransferContact: false });
|
||||
showMessage({
|
||||
message: i18n.t('contact_s.contact_transferred') + '.',
|
||||
|
|
@ -125,7 +136,7 @@ class ContactScreen extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
deleteContact(id) {
|
||||
deleteContactAction(id) {
|
||||
Alert.alert(
|
||||
i18n.t('global.confirmation'),
|
||||
i18n.t('contact_s.confirm_contact_delete'),
|
||||
|
|
@ -139,7 +150,7 @@ class ContactScreen extends React.Component {
|
|||
text: i18n.t('global.yes'),
|
||||
onPress: () => {
|
||||
this.setState({ contacts: [], sortedEmails: [] });
|
||||
this.props.dispatch({ type: 'DELETE_CONTACT', data: id });
|
||||
this.props.deleteContact(this.props.currentUser, id);
|
||||
showMessage({
|
||||
message: i18n.t('contact_s.contact_deleted') + '.',
|
||||
type: 'success',
|
||||
|
|
@ -162,7 +173,7 @@ class ContactScreen extends React.Component {
|
|||
contactId: item.id,
|
||||
})
|
||||
}>
|
||||
<Text style={styles.clickable}>
|
||||
<Text style={{ ...styles.clickable, color: this.props.mainColor }}>
|
||||
{item.name.toUpperCase()} {item.firstname}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
|
@ -172,9 +183,9 @@ class ContactScreen extends React.Component {
|
|||
<TouchableOpacity
|
||||
style={styles.button}
|
||||
onPress={() => {
|
||||
this.deleteContact(item.id);
|
||||
this.deleteContactAction(item.id);
|
||||
}}>
|
||||
<FontAwesome5 name="trash" size={20} color={'#ea4f52'} />
|
||||
<FontAwesome5 name="trash" size={20} color={this.props.mainColor} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.button}
|
||||
|
|
@ -184,7 +195,7 @@ class ContactScreen extends React.Component {
|
|||
contactToTransfer: item,
|
||||
});
|
||||
}}>
|
||||
<FontAwesome5 name="paper-plane" size={20} color={'#ea4f52'} />
|
||||
<FontAwesome5 name="paper-plane" size={20} color={this.props.mainColor} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -211,12 +222,12 @@ class ContactScreen extends React.Component {
|
|||
<TouchableOpacity onPress={() => {
|
||||
this.sortContacts('name');
|
||||
}}>
|
||||
<Text style={styles.clickable}>{i18n.t('global.name')} <FontAwesome5 name={'sort'} /></Text>
|
||||
<Text style={{ ...styles.clickable, color: this.props.mainColor }}>{i18n.t('global.name')} <FontAwesome5 name={'sort'} /></Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => {
|
||||
this.sortContacts('company');
|
||||
}}>
|
||||
<Text style={styles.clickable}>{i18n.t('global.company')} <FontAwesome5 name={'sort'} /></Text>
|
||||
<Text style={{ ...styles.clickable, color: this.props.mainColor }}>{i18n.t('global.company')} <FontAwesome5 name={'sort'} /></Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.email}>{i18n.t('global.email')}</Text>
|
||||
<Text style={styles.buttons} />
|
||||
|
|
@ -272,7 +283,12 @@ class ContactScreen extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { contactAdded } = this.props.route.params;
|
||||
const { contactAdded, action } = this.props.route.params;
|
||||
if (action === 'add') {
|
||||
this.props.navigation.navigate('ContactDetailsScreen', {
|
||||
action: 'add',
|
||||
})
|
||||
}
|
||||
if (contactAdded === true) {
|
||||
this.props.navigation.setParams({ contactAdded: false });
|
||||
showMessage({
|
||||
|
|
@ -291,7 +307,7 @@ class ContactScreen extends React.Component {
|
|||
alignItems: 'center',
|
||||
}}>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
title={i18n.t('global.add')}
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate('ContactDetailsScreen', {
|
||||
|
|
@ -300,13 +316,13 @@ class ContactScreen extends React.Component {
|
|||
}
|
||||
/>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
title={i18n.t('contact_s.send_flyer')}
|
||||
onPress={() => this.setState({ showSendBrochure: true })}
|
||||
/>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
<TextInput placeholder={i18n.t('global.search')} style={styles.inputSearch} value={this.state.searchTxt} onChangeText={(text) => this.handleSearchTxt(text)} />
|
||||
<TouchableOpacity style={styles.btnSearch} onPress={() => this.handleSearchBtn()}>
|
||||
<TouchableOpacity style={{ ...styles.btnSearch, backgroundColor: this.props.mainColor }} onPress={() => this.handleSearchBtn()}>
|
||||
{this.state.searchTxt.length > 0 ? (
|
||||
<FontAwesome5 name={'times'} size={20} color={'white'} />
|
||||
) : (
|
||||
|
|
@ -354,12 +370,12 @@ class ContactScreen extends React.Component {
|
|||
width: 400,
|
||||
}}>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
title={i18n.t('global.cancel')}
|
||||
onPress={() => this.setState({ showTransferContact: false })}
|
||||
/>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
title={i18n.t('contact_s.transfer')}
|
||||
onPress={() => this.transferContact()}
|
||||
/>
|
||||
|
|
@ -480,6 +496,7 @@ class ContactScreen extends React.Component {
|
|||
{this.state.sendDocumentList.map((item, index) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={index}
|
||||
onPress={() => {
|
||||
let tmp = this.state.sendDocumentList;
|
||||
tmp.splice(this.props.documents[index], 1);
|
||||
|
|
@ -514,7 +531,7 @@ class ContactScreen extends React.Component {
|
|||
marginTop: 15,
|
||||
}}>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
title={i18n.t('global.cancel')}
|
||||
onPress={() =>
|
||||
this.setState({
|
||||
|
|
@ -528,7 +545,7 @@ class ContactScreen extends React.Component {
|
|||
})
|
||||
}
|
||||
/>
|
||||
<Button title={i18n.t('global.send')} onPress={() => this.sendBrochure()} color={'#ea4f52'} />
|
||||
<Button title={i18n.t('global.send')} onPress={() => this.sendBrochure()} color={this.props.mainColor} />
|
||||
</View>
|
||||
</View>
|
||||
</Overlay>
|
||||
|
|
@ -537,4 +554,4 @@ class ContactScreen extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(ContactScreen);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ContactScreen);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
} from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
import { initDocuments } from '../Store/Actions/documents';
|
||||
// Treeview
|
||||
import TreeView from 'react-native-animated-tree-view';
|
||||
// Icon
|
||||
|
|
@ -19,7 +20,10 @@ import styles from '../../Resources/Styles/DirectoriesStyle';
|
|||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.app.documents,
|
||||
documents: state.documents,
|
||||
directories: state.directories,
|
||||
locale: state.locale.locale,
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +38,7 @@ class DirectoriesScreen extends React.Component {
|
|||
return (
|
||||
<TouchableOpacity
|
||||
key={document.id.toString()}
|
||||
style={styles.file}
|
||||
style={{ ...styles.file, backgroundColor: this.props.mainColor }}
|
||||
onPress={() => this.openDocument(document)}>
|
||||
{document.type === 'pdf' ? (
|
||||
<FontAwesome5 name="file-pdf" color={'white'} size={60} />
|
||||
|
|
|
|||
|
|
@ -4,40 +4,93 @@ 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';
|
||||
import { initContact } from '../Store/Actions/contacts';
|
||||
import { initDirectories } from '../Store/Actions/directories';
|
||||
// SplashScreen
|
||||
import * as SplashScreen from 'expo-splash-screen';
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/HomeStyle';
|
||||
// Translations
|
||||
import i18n from "../../I18n";
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
// NetInfo
|
||||
import NetInfo from '@react-native-community/netinfo';
|
||||
// Controller
|
||||
import SyncController from '../Controllers/SyncController';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
directories: state.app.directories,
|
||||
locale: state.app.locale,
|
||||
btns: state.app.HomeBtns,
|
||||
directories: state.directories,
|
||||
locale: state.locale.locale,
|
||||
currentUser: state.app.currentUser
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
initBtns: () => dispatch({ type: 'INIT_HOME_BTNS' }),
|
||||
initDocuments: (lang, directories) => dispatch(initDocuments(lang, directories)),
|
||||
initContact: currentUser => dispatch(initContact(currentUser)),
|
||||
initDirectories: (lang, user) => dispatch(initDirectories(lang, user)),
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
class HomeScreen extends React.Component {
|
||||
|
||||
state = {
|
||||
lastSyncCall: '1970-01-01',
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch({ type: 'INIT' });
|
||||
if (!SyncController.isInstalled()) {
|
||||
return this.openSync();
|
||||
}
|
||||
this.props.initBtns();
|
||||
this.props.initContact(this.props.currentUser);
|
||||
this.props.initDirectories(this.props.locale, this.props.currentUser);
|
||||
this.props.initDocuments(this.props.locale, this.props.directories.global);
|
||||
|
||||
SplashScreen.hideAsync();
|
||||
}
|
||||
|
||||
unsubscribe() {
|
||||
NetInfo.addEventListener(state => {
|
||||
if (state.isConnected === true) {
|
||||
let seconds =
|
||||
Math.abs(new Date(this.state.lastSyncCall) - Date.now()) / 1000;
|
||||
if (seconds > 30) {
|
||||
this.setState({ lastSyncCall: Date.now() });
|
||||
SyncController.needSync(this.openSync.bind(this));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openSync() {
|
||||
this.props.navigation.navigate('SyncScreen', { forceSync: true });
|
||||
}
|
||||
|
||||
render() {
|
||||
i18n.locale = this.props.locale;
|
||||
return (
|
||||
<ImageBackground source={{ uri: FileSystem.documentDirectory + 'BackgroundImage.png' }} style={commonStyles.background}>
|
||||
<ImageBackground source={{ uri: FileSystem.documentDirectory + 'BackgroundImage.png' }} style={commonStyles.background} resizeMode='cover'>
|
||||
<View style={styles.container}>
|
||||
<TouchableOpacity onPress={() => this.openFolder(2)} style={styles.button}>
|
||||
{this.renderBtns()}
|
||||
<TouchableOpacity
|
||||
key={'OnlyVideos'}
|
||||
onPress={() => {
|
||||
this.props.initDocuments(this.props.locale, this.props.directories.global);
|
||||
this.props.navigation.navigate('OnlyVideosScreen');
|
||||
}}
|
||||
style={styles.button}>
|
||||
<Image source={{ uri: FileSystem.documentDirectory + 'HomeButtonImage.png' }} style={styles.btnImg} />
|
||||
<Text style={styles.btnTxt}>{i18n.t('global.videos')}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => this.props.navigation.navigate('OnlyVideosScreen')} style={styles.button}>
|
||||
<Image source={{ uri: FileSystem.documentDirectory + 'HomeButtonImage.png' }} style={styles.btnImg} />
|
||||
<Text style={styles.btnTxt}>{i18n.t('global.videos')}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => this.props.navigation.navigate('ContactScreen')} style={styles.button}>
|
||||
<TouchableOpacity key={'Contacts'} onPress={() => this.props.navigation.navigate('ContactScreen')} style={styles.button}>
|
||||
<Image source={{ uri: FileSystem.documentDirectory + 'HomeButtonImage.png' }} style={styles.btnImg} />
|
||||
<Text style={styles.btnTxt}>{i18n.t('global.contacts')}</Text>
|
||||
</TouchableOpacity>
|
||||
|
|
@ -46,10 +99,27 @@ class HomeScreen extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
renderBtns() {
|
||||
let locale = this.props.locale;
|
||||
let objBtns = this.props.btns;
|
||||
let array = Object.keys(objBtns).map(function (key) { return objBtns[key]; });
|
||||
return array.map((item, index) => {
|
||||
let names = JSON.parse(item.name);
|
||||
let name = (locale in names) ? names[locale] : names.fr;
|
||||
return (
|
||||
<TouchableOpacity key={index} onPress={() => this.openFolder(item.id)} style={styles.button}>
|
||||
<Image source={{ uri: FileSystem.documentDirectory + 'HomeButtonImage.png' }} style={styles.btnImg} />
|
||||
<Text style={styles.btnTxt}>{name}</Text>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
openFolder(id) {
|
||||
const folder = this.props.directories.filter(tmp => tmp.id === id);
|
||||
this.props.initDocuments(this.props.locale, this.props.directories.global);
|
||||
const folder = this.props.directories.treeview.filter(tmp => tmp.id === id);
|
||||
this.props.navigation.navigate('DirectoriesScreen', { folder: folder });
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(HomeScreen);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);
|
||||
|
|
@ -1,7 +1,15 @@
|
|||
import React from 'react';
|
||||
import { ImageBackground, View, Image, Text, TextInput, Button, Alert } from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
// Sentry
|
||||
import * as Sentry from "@sentry/react-native";
|
||||
// SplashScreen
|
||||
import * as SplashScreen from 'expo-splash-screen';
|
||||
// Helpers
|
||||
import Helpers from '../Lib/Helpers';
|
||||
// Lodash
|
||||
import _ from 'lodash';
|
||||
// Common Styles
|
||||
import commonStyles from '../../Resources/CommonStyles';
|
||||
// Style
|
||||
|
|
@ -11,21 +19,45 @@ import i18n from "../../I18n";
|
|||
// Controller
|
||||
import InstallController from '../Controllers/InstallController';
|
||||
import SyncController from '../Controllers/SyncController';
|
||||
// Database
|
||||
import { User, Setting } from '../../Database';
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
isSetup: state.app.isSetup,
|
||||
locale: state.locale.locale,
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setIsSetup: () => dispatch({ type: 'SET_ISSETUP' }),
|
||||
init: () => dispatch({ type: 'INIT' })
|
||||
};
|
||||
};
|
||||
class InstallScreen extends React.Component {
|
||||
state = {
|
||||
processing: false,
|
||||
txtStep: '',
|
||||
url: "https://dev-app.rhd-ldc.fr",
|
||||
url: "",
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
SplashScreen.hideAsync();
|
||||
}
|
||||
|
||||
render() {
|
||||
i18n.locale = this.props.locale;
|
||||
return (
|
||||
<ImageBackground source={require('../../Resources/assets/img/background_ldc.png')} style={commonStyles.background}>
|
||||
<View style={styles.container}>
|
||||
<Image source={require('../../Resources/assets/img/logo-square-ldc.png')} style={styles.logo} />
|
||||
<View style={styles.actions}>
|
||||
<TextInput
|
||||
keyboardType='url'
|
||||
autoCapitalize='none'
|
||||
style={commonStyles.textInput}
|
||||
placeholder={i18n.t("install.enter_url")}
|
||||
onChangeText={(newText) => this.setState({ url: newText })}
|
||||
|
|
@ -58,16 +90,102 @@ class InstallScreen extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
install() {
|
||||
this.setState({ processing: true, txtStep: i18n.t("install.get_app_setting") });
|
||||
if (InstallController.getConfig(this.state.url)) {
|
||||
this.setState({ txtStep: i18n.t("install.get_content_setting") });
|
||||
if (InstallController.getAppConfig(this.state.url)) {
|
||||
this.props.navigation.navigate('SyncScreen', { forceSync: true });
|
||||
}
|
||||
async install() {
|
||||
let url = this.state.url.toLowerCase();
|
||||
Setting.upsert({ key: 'bo_url', value: url });
|
||||
const isConnected = await SyncController.checkConnection().then(state => {
|
||||
//console.log(state.isConnected)
|
||||
return state.isConnected
|
||||
}).catch(error => {
|
||||
//console.log(error);
|
||||
return false;
|
||||
});
|
||||
if (!isConnected) {
|
||||
Alert.alert(
|
||||
i18n.t('global.warning'),
|
||||
i18n.t('error.must_be_connected_internet_sync')
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.setState({ processing: false });
|
||||
this.setState({ processing: true, txtStep: i18n.t("install.get_app_setting") });
|
||||
const toDL = await InstallController.getConfig(url).then(response => {
|
||||
let toDL = [];
|
||||
if (response.data) {
|
||||
if (response.data.status === "OK") {
|
||||
_.forEach(response.data.datas, function (value, key) {
|
||||
switch (key) {
|
||||
case "MainColor":
|
||||
case "AppStoreUUID":
|
||||
case "FormSelect1":
|
||||
case "FormSelect2":
|
||||
case "FormCheck":
|
||||
Setting.upsert({ key: key, value: value });
|
||||
break;
|
||||
case "SquaredLogo":
|
||||
case "RectangleLogo":
|
||||
case "BackgroundImage":
|
||||
case "HomeButtonImage":
|
||||
toDL.push({
|
||||
source: url + "/" + value,
|
||||
dest: FileSystem.documentDirectory + key + '.png'
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
return toDL;
|
||||
} else {
|
||||
Alert.alert(i18n.t("alert.error"), i18n.t("error.error_has_occurred"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}).catch(function (error) {
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(i18n.t("alert.error"), i18n.t("error.error_has_occurred"));
|
||||
return false;
|
||||
});
|
||||
if (!toDL) {
|
||||
this.setState({ processing: false, txtStep: "" });
|
||||
return false;
|
||||
}
|
||||
for await (const file of toDL) {
|
||||
await FileSystem.downloadAsync(
|
||||
file.source,
|
||||
file.dest
|
||||
)
|
||||
.then(({ uri }) => {
|
||||
console.log('Finished downloading to ', uri);
|
||||
})
|
||||
.catch(error => {
|
||||
Alert.alert(i18n.t("alert.error"), i18n.t("install.resource_dl_error") + file.dest);
|
||||
console.error(error);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({ txtStep: i18n.t("install.get_content_setting") });
|
||||
if (InstallController.getAppConfig(url)) {
|
||||
// getUsers
|
||||
this.setState({ txtStep: i18n.t('sync_s.updating_users') + '...' });
|
||||
const resUsers = await SyncController.getUsers().then(res => {
|
||||
User.clear();
|
||||
return res.data;
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred')
|
||||
);
|
||||
return
|
||||
});
|
||||
resUsers.forEach(user => {
|
||||
User.add(user);
|
||||
});
|
||||
this.props.init();
|
||||
this.props.setIsSetup();
|
||||
this.props.navigation.navigate('LoginScreen');
|
||||
}
|
||||
this.setState({ processing: false, txtStep: "" });
|
||||
}
|
||||
}
|
||||
|
||||
export default InstallScreen;
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(InstallScreen);
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
import React from 'react';
|
||||
import { View, ImageBackground, TextInput, Button, Image, Alert } from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
// SplashScreen
|
||||
import * as SplashScreen from 'expo-splash-screen';
|
||||
// Common Styles
|
||||
import commonStyles from '../../Resources/CommonStyles';
|
||||
// Style
|
||||
|
|
@ -17,17 +20,32 @@ import SyncController from '../Controllers/SyncController';
|
|||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
users: state.app.users,
|
||||
locale: state.app.locale,
|
||||
app: state.app,
|
||||
users: state.users.users,
|
||||
locale: state.locale.locale,
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setCurrentUser: () => dispatch({ type: 'SET_CURRENT_USER' }),
|
||||
};
|
||||
};
|
||||
|
||||
class LoginScreen extends React.Component {
|
||||
state = {
|
||||
login: 'v@b.t',
|
||||
password: 'test',
|
||||
login: '',
|
||||
password: '',
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if (SyncController.isLogged()) {
|
||||
this.props.setCurrentUser(false);
|
||||
}
|
||||
SplashScreen.hideAsync();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ImageBackground source={{ uri: FileSystem.documentDirectory + 'BackgroundImage.png' }} style={commonStyles.background}>
|
||||
|
|
@ -54,8 +72,8 @@ class LoginScreen extends React.Component {
|
|||
/>
|
||||
<Button
|
||||
title={i18n.t('global.login')}
|
||||
onPress={() => this.login(this.state.login, this.state.password)}
|
||||
color={'#ea4f52'}
|
||||
onPress={() => this.login(this.state.login.toLowerCase(), this.state.password)}
|
||||
color={this.props.mainColor}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -63,7 +81,7 @@ class LoginScreen extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
login(login, password) {
|
||||
async login(login, password) {
|
||||
if (login === '' || password === '') {
|
||||
Alert.alert(i18n.t("global.warning"), i18n.t('error.must_fill_login_fields'));
|
||||
return;
|
||||
|
|
@ -84,39 +102,50 @@ class LoginScreen extends React.Component {
|
|||
Alert.alert(i18n.t('error.error'), i18n.t('error.incorrect_credentials'));
|
||||
return;
|
||||
}
|
||||
const isConnected = await SyncController.checkConnection().then(state => {
|
||||
//console.log(state.isConnected)
|
||||
return state.isConnected
|
||||
}).catch(error => {
|
||||
//console.log(error);
|
||||
return false;
|
||||
});
|
||||
const lastUser = Setting.get('lastUser');
|
||||
if (lastUser === false || lastUser === undefined || lastUser.value === user.id.toString()) {
|
||||
this.loginAction(user);
|
||||
} else {
|
||||
// Si user !== last user && last user not synced
|
||||
if (lastUser.value !== user.id.toString() && !SyncController.isSynced()) {
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.tablet_not_synced_last_user'));
|
||||
// Si on est sur une installation
|
||||
if (lastUser === false || lastUser == undefined) {
|
||||
// Si la tablette est connectée à internet pour forcer la synchro
|
||||
if (!isConnected) {
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.tablet_not_connected_internet'));
|
||||
return;
|
||||
}
|
||||
// Si user !== last user
|
||||
if (lastUser.value !== user.id.toString()) {
|
||||
return this.loginAction(user);
|
||||
}
|
||||
// Si on a deja une install
|
||||
if (lastUser !== false && lastUser !== undefined) {
|
||||
// Si on a une précédente connexion
|
||||
if (lastUser.value === user.id.toString()) {
|
||||
this.loginAction(user);
|
||||
} else { // Si le user precedent est different du user courant
|
||||
// Si user !== last user && last user not synced
|
||||
if (!SyncController.isSynced()) {
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.tablet_not_synced_last_user'));
|
||||
return;
|
||||
}
|
||||
// Si la tablette est connectée à internet pour forcer la synchro
|
||||
if (!SyncController.checkConnection()) {
|
||||
if (!isConnected) {
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.tablet_not_connected_internet'));
|
||||
return;
|
||||
}
|
||||
SyncController.setInstalled(true);
|
||||
this.loginAction(user, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loginAction(user, forceSync = false) {
|
||||
loginAction(user) {
|
||||
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 });
|
||||
if (forceSync === true) {
|
||||
this.props.navigation.navigate('SyncScreen', { isInstalled: true, forceSync: true });
|
||||
}
|
||||
this.props.setCurrentUser();
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(LoginScreen);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);
|
||||
|
|
@ -14,7 +14,8 @@ import styles from '../../Resources/Styles/OnlyVideosStyle';
|
|||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.app.documents,
|
||||
documents: state.documents,
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -32,7 +33,7 @@ class OnlyVideosScreen extends React.Component {
|
|||
return (
|
||||
<TouchableOpacity
|
||||
key={document.id.toString()}
|
||||
style={styles.file}
|
||||
style={{ ...styles.file, backgroundColor: this.props.mainColor }}
|
||||
onPress={() => {
|
||||
this.props.dispatch({ type: 'SET_CURRENT_OPENED_DOC', data: document });
|
||||
this.props.navigation.navigate('VideoScreen', { uuid: document.uuid });
|
||||
|
|
|
|||
|
|
@ -19,16 +19,16 @@ class PDFScreen extends React.Component {
|
|||
<Pdf
|
||||
source={source}
|
||||
onLoadComplete={(numberOfPages, filePath) => {
|
||||
console.log(`number of pages: ${numberOfPages}`);
|
||||
//console.log(`number of pages: ${numberOfPages}`);
|
||||
}}
|
||||
onPageChanged={(page, numberOfPages) => {
|
||||
console.log(`current page: ${page}`);
|
||||
//console.log(`current page: ${page}`);
|
||||
}}
|
||||
onError={error => {
|
||||
console.log(error);
|
||||
}}
|
||||
onPressLink={uri => {
|
||||
console.log(`Link presse: ${uri}`);
|
||||
//console.log(`Link presse: ${uri}`);
|
||||
}}
|
||||
style={styles.pdf}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ import styles from '../../Resources/Styles/SearchStyle';
|
|||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.app.documents,
|
||||
documents: state.documents,
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ class SearchScreen extends React.Component {
|
|||
return (
|
||||
<TouchableOpacity
|
||||
key={document.id.toString()}
|
||||
style={styles.file}
|
||||
style={{ ...styles.file, backgroundColor: this.props.mainColor }}
|
||||
onPress={() => this.openDocument(document)}>
|
||||
{document.type === 'pdf' ? (
|
||||
<FontAwesome5 name="file-pdf" color={'white'} size={60} />
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@ import React from 'react';
|
|||
import { View, Button, Alert, Text } from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
import { initDirectories } from '../Store/Actions/directories';
|
||||
import { initContact } from '../Store/Actions/contacts';
|
||||
import { initDocuments } from '../Store/Actions/documents';
|
||||
// Sentry
|
||||
import * as Sentry from "@sentry/react-native";
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/SyncStyle';
|
||||
// Translations
|
||||
|
|
@ -11,18 +16,39 @@ import SyncController from '../Controllers/SyncController';
|
|||
// Progress
|
||||
import * as Progress from 'react-native-progress';
|
||||
// Database
|
||||
import { User, Contact, Directory, Document } from '../../Database';
|
||||
import { User, Contact, Directory, Document, SendBrochure } from '../../Database';
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.app.documents,
|
||||
syncVersion: state.app.syncVersion,
|
||||
currentUser: state.app.currentUser,
|
||||
locale: state.locale.locale,
|
||||
mainColor: state.app.mainColor,
|
||||
directories: state.directories
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
init: () => dispatch({ type: 'INIT' }),
|
||||
initUsers: () => dispatch({ type: 'INIT_USERS' }),
|
||||
initDirectories: (lang, user) => dispatch(initDirectories(lang, user)),
|
||||
initDocuments: (lang, directories) => dispatch(initDocuments(lang, directories)),
|
||||
initContact: currentUser => dispatch(initContact(currentUser)),
|
||||
initBtns: () => dispatch({ type: 'INIT_HOME_BTNS' }),
|
||||
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,
|
||||
|
|
@ -30,12 +56,14 @@ class SyncScreen extends React.Component {
|
|||
downloadProgress: 0,
|
||||
downloadingFile: false,
|
||||
processing: false,
|
||||
newApp: false
|
||||
newApp: false,
|
||||
forced: false
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { forceSync } = this.props.route.params;
|
||||
if (forceSync === true) {
|
||||
this.setState({ forced: true });
|
||||
this.sync();
|
||||
}
|
||||
}
|
||||
|
|
@ -48,12 +76,12 @@ class SyncScreen extends React.Component {
|
|||
size={250}
|
||||
progress={this.state.progress}
|
||||
showsText={true}
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
/>
|
||||
<View style={styles.btnWrapper}>
|
||||
<Button
|
||||
disabled={this.state.processing}
|
||||
color={'#ea4f52'}
|
||||
color={this.props.mainColor}
|
||||
title={i18n.t('sync_s.start_sync')}
|
||||
onPress={() => this.sync()}
|
||||
/>
|
||||
|
|
@ -68,7 +96,15 @@ class SyncScreen extends React.Component {
|
|||
}
|
||||
|
||||
async sync() {
|
||||
if (!SyncController.checkConnection()) {
|
||||
let errorStatus = false;
|
||||
const isConnected = await SyncController.checkConnection().then(state => {
|
||||
//console.log(state.isConnected)
|
||||
return state.isConnected
|
||||
}).catch(error => {
|
||||
//console.log(error);
|
||||
return false;
|
||||
});
|
||||
if (!isConnected) {
|
||||
Alert.alert(
|
||||
i18n.t('global.warning'),
|
||||
i18n.t('error.must_be_connected_internet_sync')
|
||||
|
|
@ -80,20 +116,18 @@ class SyncScreen extends React.Component {
|
|||
const resVersion = await SyncController.getVersion().then(res => {
|
||||
return res.data;
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred')
|
||||
);
|
||||
errorStatus = true
|
||||
});
|
||||
this.props.dispatch({
|
||||
type: 'UPDATE_VERSION',
|
||||
data: resVersion.version,
|
||||
});
|
||||
this.props.dispatch({
|
||||
type: 'UPDATE_SHOW_IS_ACTIVE',
|
||||
data: resVersion.ShowIsActive,
|
||||
});
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
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') + '...' });
|
||||
|
|
@ -101,45 +135,72 @@ class SyncScreen extends React.Component {
|
|||
User.clear();
|
||||
return res.data;
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred')
|
||||
);
|
||||
errorStatus = true
|
||||
});
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resUsers.forEach(user => {
|
||||
User.add(user);
|
||||
});
|
||||
// getContacts
|
||||
this.setState({ progress: 0.1, txtStep: i18n.t('sync_s.updating_contacts') + '...' });
|
||||
const resContacts = await SyncController.getContacts().then(res => {
|
||||
const resContacts = await SyncController.getContacts(this.props.currentUser.id).then(res => {
|
||||
Contact.clear();
|
||||
return res.data;
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred')
|
||||
);
|
||||
errorStatus = true
|
||||
});
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resContacts.forEach(contact => {
|
||||
Contact.add(contact);
|
||||
});
|
||||
//sendBrochures
|
||||
this.setState({ progress: 0.2, txtStep: i18n.t('sync_s.sending_flyers') + '...' });
|
||||
await SyncController.sendBrochures();
|
||||
let brochures = SendBrochure.getAll();
|
||||
for (const brochure of brochures) {
|
||||
await SyncController.sendBrochure(brochure).then(res => {
|
||||
SendBrochure.delete(brochure.id);
|
||||
}).catch(error => {
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred') + ' : Brochures'
|
||||
);
|
||||
errorStatus = true;
|
||||
});
|
||||
}
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
//getDirectories
|
||||
this.setState({ progress: 0.3, txtStep: i18n.t('sync_s.updating_folders') + '...' });
|
||||
const resDirectories = await SyncController.getDirectories().then(res => {
|
||||
Directory.clear();
|
||||
return res.data;
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred')
|
||||
);
|
||||
errorStatus = true
|
||||
});
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resDirectories.forEach(dir => {
|
||||
Directory.add(dir);
|
||||
});
|
||||
|
|
@ -148,17 +209,21 @@ class SyncScreen extends React.Component {
|
|||
const resDocuments = await SyncController.getDocuments().then(res => {
|
||||
return res.data;
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred')
|
||||
);
|
||||
errorStatus = true
|
||||
});
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
const toDelete = Document.clear(resDocuments);
|
||||
resDocuments.forEach(document => {
|
||||
Document.update(document);
|
||||
});
|
||||
this.downloadDocuments(resDocuments, toDelete);
|
||||
this.downloadDocuments(Document.getAll(), toDelete);
|
||||
// End
|
||||
this.setState({ txtStep: i18n.t('sync_s.update_completed') + '.', processing: false });
|
||||
}
|
||||
|
|
@ -247,7 +312,7 @@ class SyncScreen extends React.Component {
|
|||
if (this.state.downloadingFile === false) {
|
||||
this.setState({ downloadingFile: true });
|
||||
}
|
||||
const endpoint = 'https://dev-app.rhd-ldc.fr/storage/docs/'
|
||||
const endpoint = SyncController.getUrlBo() + '/storage/docs/'
|
||||
const doc = documents[i];
|
||||
this.setState({
|
||||
txtStep:
|
||||
|
|
@ -258,8 +323,7 @@ class SyncScreen extends React.Component {
|
|||
') ...',
|
||||
});
|
||||
try {
|
||||
//console.log(endpoint + doc.uuid + "." + doc.type);
|
||||
const { uri } = await this.downloadResumable(
|
||||
await this.downloadResumable(
|
||||
endpoint + doc.uuid + "." + doc.type,
|
||||
doc.uuid,
|
||||
doc.type,
|
||||
|
|
@ -280,12 +344,19 @@ class SyncScreen extends React.Component {
|
|||
}
|
||||
|
||||
finishSync(version) {
|
||||
console.log('here')
|
||||
this.props.dispatch({ type: 'INIT' });
|
||||
this.props.init();
|
||||
this.props.initUsers();
|
||||
this.props.initContact(this.props.currentUser);
|
||||
this.props.initDirectories(this.props.locale, this.props.currentUser);
|
||||
this.props.initDocuments(this.props.locale, this.props.directories.global);
|
||||
this.props.initBtns();
|
||||
if (this.state.forced) {
|
||||
SyncController.setInstalled();
|
||||
}
|
||||
SyncController.updateVersion(version);
|
||||
this.setState({ txtStep: i18n.t('sync_s.update_completed') + '.', processing: false });
|
||||
if (this.state.newApp === true) {
|
||||
const appUUID = '1f6eda31-1f6d-49fe-aa81-4f0aece0f7ca';
|
||||
const appUUID = SyncController.getAppStoreUUID();
|
||||
const url = 'https://store.ldc.fr' + '/app/' + appUUID;
|
||||
Alert.alert(
|
||||
'LDC Store',
|
||||
|
|
@ -305,4 +376,4 @@ class SyncScreen extends React.Component {
|
|||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(SyncScreen);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SyncScreen);
|
||||
|
|
@ -1,32 +1,59 @@
|
|||
import React from 'react';
|
||||
import { View, Dimensions } from 'react-native';
|
||||
// Reduxs
|
||||
import { connect } from 'react-redux';
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
// Video
|
||||
import { Video } from 'expo-av';
|
||||
import { ResizeMode } from 'expo-av';
|
||||
import VideoPlayer from 'expo-video-player';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
}
|
||||
|
||||
class VideoScreen extends React.Component {
|
||||
render() {
|
||||
const { uuid } = this.props.route.params;
|
||||
let width = Dimensions.get("window").width;
|
||||
let height = Dimensions.get("window").height;
|
||||
|
||||
// if portrait
|
||||
if (height > width) {
|
||||
let tmpHeight = height;
|
||||
height = width - 150;
|
||||
width = tmpHeight + 100;
|
||||
} else {
|
||||
height = height - 100;
|
||||
}
|
||||
return (
|
||||
<View>
|
||||
<View style={{ flex: 1, backgroundColor: 'black' }}>
|
||||
<VideoPlayer
|
||||
height={Dimensions.get('window').height - 100}
|
||||
defaultControlsVisible={true}
|
||||
fullscreen={{
|
||||
visible: false
|
||||
}}
|
||||
slider={{
|
||||
minimumTrackTintColor: this.props.mainColor,
|
||||
thumbTintColor: this.props.mainColor,
|
||||
}}
|
||||
style={{
|
||||
height: height,
|
||||
width: width
|
||||
}}
|
||||
videoProps={{
|
||||
shouldPlay: true,
|
||||
resizeMode: Video.RESIZE_MODE_COVER,
|
||||
resizeMode: ResizeMode.CONTAIN,
|
||||
source: {
|
||||
uri: FileSystem.documentDirectory + uuid + '.mp4',
|
||||
},
|
||||
}}
|
||||
showFullscreenButton={false}
|
||||
sliderColor={'#ea4f52'}
|
||||
showControlsOnLoad={true}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default VideoScreen;
|
||||
export default connect(mapStateToProps)(VideoScreen);
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
class Helpers {
|
||||
compareValues(key, order = 'asc') {
|
||||
return function innerSort(a, b) {
|
||||
//console.log("--", "A :", a, "B : ", b, "KEY : ", key, a.hasOwnProperty(key), b.hasOwnProperty(key), a.name);
|
||||
if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
|
||||
// property doesn't exist on either object
|
||||
return 0;
|
||||
}
|
||||
|
||||
const varA = (typeof a[key] === 'string')
|
||||
? a[key].toUpperCase() : a[key];
|
||||
const varB = (typeof b[key] === 'string')
|
||||
? b[key].toUpperCase() : b[key];
|
||||
|
||||
let comparison = 0;
|
||||
if (varA > varB) {
|
||||
comparison = 1;
|
||||
} else if (varA < varB) {
|
||||
comparison = -1;
|
||||
}
|
||||
return (
|
||||
(order === 'desc') ? (comparison * -1) : comparison
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
isEmailValid(email) {
|
||||
const expression = /(?!.*\.{2})^([a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i;
|
||||
return expression.test(String(email).toLowerCase());
|
||||
}
|
||||
|
||||
isValidRequiredString(string) {
|
||||
const expression = /.*\S.*/i;
|
||||
return expression.test(String(string));
|
||||
}
|
||||
|
||||
generateUUID() { // Public Domain/MIT
|
||||
let d = new Date().getTime();//Timestamp
|
||||
let d2 = new Date().getUTCMilliseconds() + Math.random();//Time in microseconds since page-load or 0 if unsupported
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let r = Math.random() * 16;//random number between 0 and 16
|
||||
if(d > 0){//Use timestamp until depleted
|
||||
r = (d + r)%16 | 0;
|
||||
d = Math.floor(d/16);
|
||||
} else {//Use microseconds since page-load if supported
|
||||
r = (d2 + r)%16 | 0;
|
||||
d2 = Math.floor(d2/16);
|
||||
}
|
||||
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
||||
});
|
||||
}
|
||||
}
|
||||
export default new Helpers();
|
||||
|
|
@ -1,271 +0,0 @@
|
|||
import NetInfo from '@react-native-community/netinfo';
|
||||
import Constants from 'expo-constants';
|
||||
|
||||
const axios = require('axios');
|
||||
const api_url = 'https://app-intl.ldc.fr';
|
||||
const api_token = 'gP8K77n4568UXYLV63bqykDRs8pyMy';
|
||||
const endpoint = api_url + '/api';
|
||||
const app_uuid = '746ceb52-2354-40d9-b270-57ca541f2751';
|
||||
|
||||
import UsersModel from '../Models/Users';
|
||||
import DirectoriesModel from '../Models/Directories';
|
||||
import DocumentsModel from '../Models/Documents';
|
||||
import ContactsModel from '../Models/Contacts';
|
||||
import CommonModel from '../Models/Common';
|
||||
import SendBrochureModel from '../Models/SendBrochure';
|
||||
|
||||
class Sync {
|
||||
getEndpointDocs() {
|
||||
return api_url + '/storage/docs/';
|
||||
}
|
||||
|
||||
getApiToken() {
|
||||
return api_token;
|
||||
}
|
||||
|
||||
getAppUUID() {
|
||||
return app_uuid;
|
||||
}
|
||||
|
||||
getVersion(callback, errorCallback) {
|
||||
axios({
|
||||
method: 'get',
|
||||
url: endpoint + '/version',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: this.getApiToken(),
|
||||
app_uuid: app_uuid,
|
||||
app_version: Constants.nativeAppVersion
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
return callback(response.data.version, response.data.ShowIsActive, response.data.newApp);
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error);
|
||||
return errorCallback(error);
|
||||
});
|
||||
}
|
||||
|
||||
needSync(callback) {
|
||||
NetInfo.fetch().then(state => {
|
||||
if (state.isConnected) {
|
||||
axios({
|
||||
method: 'get',
|
||||
url: endpoint + '/version',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: this.getApiToken(),
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
const localVersion = CommonModel.get('version');
|
||||
if (
|
||||
localVersion === undefined ||
|
||||
localVersion === false ||
|
||||
localVersion.value !== response.data.version
|
||||
) {
|
||||
return callback();
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
setInstalled() {
|
||||
CommonModel.add({key: 'installed', value: '1'});
|
||||
CommonModel.add({key: 'locale', value: 'fr'});
|
||||
CommonModel.add({key: 'ShowIsActive', value: '0'});
|
||||
}
|
||||
|
||||
getUsers(callback) {
|
||||
axios({
|
||||
method: 'get',
|
||||
url: endpoint + '/users',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: this.getApiToken(),
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
UsersModel.clear();
|
||||
response.data.forEach(user => {
|
||||
UsersModel.add(user);
|
||||
});
|
||||
console.log('Users Update Done');
|
||||
return callback();
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
getDirectories(callback) {
|
||||
axios({
|
||||
method: 'get',
|
||||
url: endpoint + '/directories',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: this.getApiToken(),
|
||||
},
|
||||
})
|
||||
.then(function(response) {
|
||||
DirectoriesModel.clear();
|
||||
response.data.forEach(dir => {
|
||||
DirectoriesModel.add(dir);
|
||||
});
|
||||
console.log('Directories Update Done');
|
||||
return callback();
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
getDocuments(callback) {
|
||||
axios({
|
||||
method: 'get',
|
||||
url: endpoint + '/documents',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: this.getApiToken(),
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
const toDelete = DocumentsModel.clear(response.data);
|
||||
response.data.forEach(document => {
|
||||
DocumentsModel.update(document);
|
||||
});
|
||||
console.log('Documents Update Done');
|
||||
return callback(DocumentsModel.getAll(), toDelete);
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
getContacts(callback, userId, errorCallback) {
|
||||
let contacts = ContactsModel.getAll();
|
||||
axios({
|
||||
method: 'post',
|
||||
url: endpoint + '/contacts' + '?token=' + this.getApiToken(),
|
||||
responseType: 'json',
|
||||
data: {
|
||||
contacts: contacts,
|
||||
userId: userId,
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
ContactsModel.clear();
|
||||
response.data.forEach(contact => {
|
||||
ContactsModel.add(contact);
|
||||
});
|
||||
console.log('Contacts Update Done');
|
||||
callback();
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
errorCallback(error);
|
||||
});
|
||||
}
|
||||
|
||||
async sendBrochure(brochures, i) {
|
||||
if (brochures.length > 0) {
|
||||
const item = brochures[i];
|
||||
let response = await axios({
|
||||
method: 'post',
|
||||
url: endpoint + '/sendBrochure',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: this.getApiToken(),
|
||||
emails: {item},
|
||||
},
|
||||
});
|
||||
if (i < brochures.length - 1) {
|
||||
return this.sendBrochure(brochures, i + 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
sendBrochures(callback) {
|
||||
this.sendBrochure(SendBrochureModel.getAll(), 0).then(res => {
|
||||
SendBrochureModel.clear();
|
||||
console.log('SendBrochures Update Done');
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
updateVersion(version) {
|
||||
const localVersion = CommonModel.get('version');
|
||||
if (localVersion === false || localVersion === undefined) {
|
||||
CommonModel.add({key: 'version', value: version});
|
||||
} else {
|
||||
CommonModel.update({id: localVersion.id, key: 'version', value: version});
|
||||
}
|
||||
}
|
||||
|
||||
updateShowIsActive(value) {
|
||||
const local = CommonModel.get('ShowIsActive');
|
||||
if (local === false || local === undefined) {
|
||||
CommonModel.add({key: 'ShowIsActive', value: value});
|
||||
} else {
|
||||
CommonModel.update({id: local.id, key: 'ShowIsActive', value: value});
|
||||
}
|
||||
}
|
||||
|
||||
isLogged() {
|
||||
const logged = CommonModel.get('isLogged');
|
||||
const loggedTime = CommonModel.get('loggedTime');
|
||||
if (
|
||||
logged !== false &&
|
||||
loggedTime !== false &&
|
||||
logged !== undefined &&
|
||||
loggedTime !== undefined
|
||||
) {
|
||||
let seconds =
|
||||
Math.abs(new Date(Number(loggedTime.value)) - Date.now()) / 1000;
|
||||
if (seconds < 14400) {
|
||||
// 4h
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isInstalled() {
|
||||
const test = CommonModel.get('installed');
|
||||
if (test === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
updateLastModificationDoc(id, date) {
|
||||
DocumentsModel.update({id: id, updated_at: date.toString()}, true);
|
||||
}
|
||||
|
||||
isSynced() {
|
||||
const SendBrochure = SendBrochureModel.getAll();
|
||||
const Contacts = ContactsModel.getAll();
|
||||
|
||||
if (SendBrochure !== undefined && Contacts !== undefined) {
|
||||
const noSynced = Contacts.filtered('synced = false');
|
||||
if (SendBrochure.length > 0 || noSynced.length > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default new Sync();
|
||||
|
|
@ -1,103 +1,29 @@
|
|||
const CommonSchema = {
|
||||
name: 'Common',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
key: 'string',
|
||||
value: 'string',
|
||||
},
|
||||
};
|
||||
import Realm from "realm";
|
||||
|
||||
const UserSchema = {
|
||||
name: 'Users',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
surname: 'string',
|
||||
firstname: 'string',
|
||||
password: 'string',
|
||||
role: 'string',
|
||||
authorizedFolders: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
const DirectoriesSchema = {
|
||||
name: 'Directories',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
name: 'string',
|
||||
parent: { type: 'int', optional: true },
|
||||
order: 'int',
|
||||
needAuthorization: 'int',
|
||||
},
|
||||
};
|
||||
|
||||
const DocumentsSchema = {
|
||||
name: 'Documents',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
uuid: 'string',
|
||||
title: 'string',
|
||||
type: 'string',
|
||||
path: 'string',
|
||||
directory: 'int',
|
||||
lang: 'string',
|
||||
updated_at: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
const ContactsSchema = {
|
||||
name: 'Contacts',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
type: 'string',
|
||||
other: { type: 'string', optional: true },
|
||||
select1: { type: 'string', optional: true },
|
||||
select2: { type: 'string', optional: true },
|
||||
name: 'string',
|
||||
firstname: 'string',
|
||||
company: { type: 'string', optional: true },
|
||||
address: { type: 'string', optional: true },
|
||||
phone: 'string',
|
||||
products: { type: 'string', optional: true },
|
||||
// TODO : card_url ?
|
||||
notes: { type: 'string', optional: true },
|
||||
visits: { type: 'string', optional: true },
|
||||
user_id: 'int',
|
||||
uniq_id: 'string',
|
||||
to_delete: { type: 'bool', default: false },
|
||||
synced: { type: 'bool', default: true },
|
||||
},
|
||||
};
|
||||
|
||||
const SendBrochureSchema = {
|
||||
name: 'SendBrochure',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
subject: 'string',
|
||||
message: 'string',
|
||||
documents: 'string',
|
||||
user_id: 'int'
|
||||
},
|
||||
};
|
||||
import ContactModel, { ContactsSchema } from "./App/Models/Contact";
|
||||
import DirectoryModel, { DirectoriesSchema } from "./App/Models/Directory";
|
||||
import DocumentModel, { DocumentsSchema } from "./App/Models/Document";
|
||||
import SendBrochureModel, { SendBrochuresSchema } from "./App/Models/SendBrochure";
|
||||
import SettingModel, { SettingsSchema } from "./App/Models/Setting";
|
||||
import UserModel, { UsersSchema } from "./App/Models/User";
|
||||
|
||||
const Database = {
|
||||
schema: [
|
||||
CommonSchema,
|
||||
UserSchema,
|
||||
ContactsSchema,
|
||||
DirectoriesSchema,
|
||||
DocumentsSchema,
|
||||
ContactsSchema,
|
||||
SendBrochureSchema,
|
||||
SendBrochuresSchema,
|
||||
SettingsSchema,
|
||||
UsersSchema
|
||||
],
|
||||
encryptionKey: new Int8Array(64)
|
||||
//encryptionKey: new Int8Array(64)
|
||||
};
|
||||
|
||||
export default Database;
|
||||
let realm = new Realm(Database);
|
||||
|
||||
export let Contact = new ContactModel(realm);
|
||||
export let Directory = new DirectoryModel(realm);
|
||||
export let Document = new DocumentModel(realm);
|
||||
export let SendBrochure = new SendBrochureModel(realm);
|
||||
export let Setting = new SettingModel(realm);
|
||||
export let User = new UserModel(realm);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { I18n } from 'i18n-js';
|
||||
|
||||
import fr from './Locales/fr';
|
||||
import en from './Locales/en';
|
||||
import de from './Locales/de';
|
||||
import fr from './Resources/Locales/fr';
|
||||
import en from './Resources/Locales/en';
|
||||
import de from './Resources/Locales/de';
|
||||
|
||||
const i18n = new I18n({
|
||||
fr: fr,
|
||||
|
|
@ -12,7 +12,6 @@ const i18n = new I18n({
|
|||
|
||||
i18n.defaultLocale = 'fr';
|
||||
i18n.locale = 'fr';
|
||||
i18n.fallbacks = true;
|
||||
i18n.translations = { fr, en, de };
|
||||
i18n.enableFallback = true;
|
||||
|
||||
export default i18n;
|
||||
|
|
|
|||
|
|
@ -1,157 +0,0 @@
|
|||
{
|
||||
"global": {
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"home": "Startseite",
|
||||
"search": "Suche",
|
||||
"login": "Verbindung",
|
||||
"email": "Email",
|
||||
"message_sent": "Email geschickt",
|
||||
"message_will_be_sent_after_sync": "Die Nachricht wird nach Synchronisation geschickt",
|
||||
"warning": "Achtung",
|
||||
"synchronization": "Synchronisation ",
|
||||
"videos": "Videos",
|
||||
"contacts": "Kontakt",
|
||||
"confirmation": "Bestätigung",
|
||||
"name": "Name",
|
||||
"firstname": "Vorname",
|
||||
"address": "Adresse",
|
||||
"phone": "Telefonnummer",
|
||||
"company": "Firma",
|
||||
"add": "Addieren",
|
||||
"cancel": "Abbrechen",
|
||||
"subject": "Betreff",
|
||||
"message": "Nachricht",
|
||||
"send": "Senden",
|
||||
"required": "erforderlich",
|
||||
"save": "Speichern",
|
||||
"retry": "Noch einmal versuchen",
|
||||
"next": "Nächstes"
|
||||
},
|
||||
"app": {
|
||||
"file_sharing": " Dateifreigabe",
|
||||
"folders": "Ordner",
|
||||
"video": "Video",
|
||||
"contact_details": "Kontaktdaten",
|
||||
"results_search": "Suchergebnisse",
|
||||
"my_space": "Mein Raum"
|
||||
},
|
||||
"login_s": {
|
||||
"install": "Installieren",
|
||||
"username": "Benutzername",
|
||||
"password": "Passwort"
|
||||
},
|
||||
"home_s": {
|
||||
"1": "Die Gruppe",
|
||||
"2": "Unsere Marken",
|
||||
"3": "Andere"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "Keine Ergebnisse"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Download",
|
||||
"update_completed": "Update abgeschlossen",
|
||||
"updating_docs": "Dokumentaktualisierung",
|
||||
"updating_folders": "Dateien aktualisieren",
|
||||
"sending_flyers": "Brochure senden",
|
||||
"updating_contacts": "Kontakt aktualisieren",
|
||||
"user_install_completed": "Benutzerinstallation abgeschlossen",
|
||||
"updating_users": "Benutzer-Update",
|
||||
"user_install": "Benutzerinstallation",
|
||||
"start_sync": "Synchronisation starten",
|
||||
"new_app_version": "Eine neue Version der Anwendung ist verfügbar!",
|
||||
"open_store": "Öffnen Sie den App Store"
|
||||
},
|
||||
"contact_s": {
|
||||
"contact_transferred": "Kontakt weiterleiten",
|
||||
"contact_will_be_sent_after_sync": "Der Kontakt wird nach der Synchronisation gesendet",
|
||||
"confirm_contact_delete": "Möchten Sie diesen Kontakt wirklich löschen?",
|
||||
"contact_deleted": "Kontakt gelöscht",
|
||||
"contact_added": "Kontakt hinzugefügt",
|
||||
"send_flyer": "Senden Sie eine Broschüre",
|
||||
"select_contact": "Wählen Sie den Kontakt",
|
||||
"transfer": "weiterleiten",
|
||||
"contact_list": "Kontaktliste",
|
||||
"documents_list": "Liste der Dokumente"
|
||||
},
|
||||
"contact_details_s": {
|
||||
"visits": "Besuche",
|
||||
"notes": "Notes",
|
||||
"contact_saved": "Kontakt gespeichert",
|
||||
"confirm_visit_delete": "Sind Sie sicher, dass Sie diesen Besuch löschen möchten?",
|
||||
"qrcode_not_vcard_format": "Dieser QRCode ist nicht im vCard-Format",
|
||||
"customer": "Kunde",
|
||||
"prospect": "potenzieller Kunde",
|
||||
"other": "Andere",
|
||||
"description": "Beschreibung",
|
||||
"no_visits": "Kein Besuch",
|
||||
"visit_name": "Besuchsname"
|
||||
},
|
||||
"error": {
|
||||
"error": "Fehler ",
|
||||
"tablet_not_connected_internet": "Das Tablet ist nicht mit dem Internet verbunden.",
|
||||
"tablet_not_synced_last_user": "Das Tablet wurde vom vorherigen Benutzer nicht synchronisiert",
|
||||
"incorrect_credentials": "Falsche Anmeldeinformationen",
|
||||
"must_fill_login_fields": "Sie müssen die Verbindungsfelder ausfüllen",
|
||||
"invalid_email_address": "Ungültige E-Mail-Adresse",
|
||||
"error_has_occurred": "Ein Fehler ist aufgetreten",
|
||||
"must_be_connected_internet_sync": "Sie müssen mit dem Internet verbunden sein, um die Synchronisierung zu starten",
|
||||
"incomplete_form": "Unvollständiges Formular",
|
||||
"fill_all_fields_and_1_doc_min": "Bitte füllen Sie alle Felder, mindestens 1 Dokument und eine gültige E-Mail-Adresse aus.",
|
||||
"fill_other_field": "Füllen Sie das Beschreibungsfeld für: Andere",
|
||||
"specify_type_contact": "Bitte geben Sie die Art des Kontakts an",
|
||||
"invalid_name": "ungültiger Name",
|
||||
"invalid_firstname": "ungültiger Vorname",
|
||||
"camera_permission_denied": "Kameraerlaubnis verweigert",
|
||||
"pending_camera_permission": "Warten auf Kameraerlaubnis"
|
||||
},
|
||||
"custom": {
|
||||
"select-1": {
|
||||
"title": "Art des Geschäfts",
|
||||
"c1": "Einzelhandel",
|
||||
"c2": "Home Service / Freezer Center",
|
||||
"c3": "Restauration Tischservice",
|
||||
"c4": "Fast Food und Snacking",
|
||||
"c5": "Cafeteria / Selbstbedienungsladen",
|
||||
"c6": "Catering-Unternehmen",
|
||||
"c7": "Freihändige Verpflegung / Centrale Küche",
|
||||
"c8": "Unabhängiger Vertriebspartner",
|
||||
"c9": "Bäckerei Konditorei",
|
||||
"c10": "Lebensmittel Zwischenprodukte",
|
||||
"c11": "Destocker",
|
||||
"c12": "Halal-Handel",
|
||||
"c13": "Verpflegung von Unterkünften",
|
||||
"c14": "Zentrale Geschäftsrestauration",
|
||||
"c15": "Catering und Park",
|
||||
"c16": "Verpflegung von Transport",
|
||||
"c17": "Öffentlicher Markt",
|
||||
"c18": "Cash",
|
||||
"c19": "Nationaler Vertriebspartner",
|
||||
"c20": "Rungis",
|
||||
"c21": "Schlachthof",
|
||||
"c22": "Andere"
|
||||
},
|
||||
"select-2": {
|
||||
"title": "Site",
|
||||
"c1": "Celvia Dinde",
|
||||
"c2": "Celvia Elaborés",
|
||||
"c3": "Celvia Sérent",
|
||||
"c4": "Procanar",
|
||||
"c5": "Celtys",
|
||||
"c6": "Farmor",
|
||||
"c7": "Robichon",
|
||||
"c8": "Les Volailles de Kerana",
|
||||
"c9": "Bosher Volaille",
|
||||
"c10": "LDC Bretagne",
|
||||
"c11": "Doux Farmor",
|
||||
"c12": "Favreau"
|
||||
},
|
||||
"interest": {
|
||||
"p1": "Huhn",
|
||||
"p2": "Pute",
|
||||
"p3": "Ente",
|
||||
"p4": "Andere"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
{
|
||||
"global": {
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"home": "Home",
|
||||
"search": "Search",
|
||||
"login": "Login",
|
||||
"email": "Email",
|
||||
"message_sent": "Message Sent",
|
||||
"message_will_be_sent_after_sync": "Message will be send after synchronization",
|
||||
"warning": "Warning",
|
||||
"synchronization": "Synchronization",
|
||||
"videos": "Videos",
|
||||
"contacts": "Contacts",
|
||||
"confirmation": "Confirmation",
|
||||
"name": "Lastname",
|
||||
"firstname": "Firstname",
|
||||
"address": "Adress",
|
||||
"phone": "Phone number",
|
||||
"company": "Company",
|
||||
"add": "Add",
|
||||
"cancel": "Cancel",
|
||||
"subject": "Object",
|
||||
"message": "Message",
|
||||
"send": "Send",
|
||||
"required": "required",
|
||||
"save": "Save",
|
||||
"retry": "Retry",
|
||||
"next": "Next"
|
||||
},
|
||||
"app": {
|
||||
"file_sharing": "File Sharing",
|
||||
"folders": "Folders",
|
||||
"video": "Video",
|
||||
"contact_details": "Contact information",
|
||||
"results_search": "Search results",
|
||||
"my_space": "Personal Dashboard"
|
||||
},
|
||||
"login_s": {
|
||||
"install": "Install",
|
||||
"username": "Username",
|
||||
"password": "Password"
|
||||
},
|
||||
"home_s": {
|
||||
"1": "The Group",
|
||||
"2": "Our Brands",
|
||||
"3": "Others"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "No Result"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Download",
|
||||
"update_completed": "Update Done",
|
||||
"updating_docs": "Updating documents",
|
||||
"updating_folders": "Updating folders",
|
||||
"sending_flyers": "Sending documents",
|
||||
"updating_contacts": "Updating contacts",
|
||||
"user_install_completed": "User install completed",
|
||||
"updating_users": "Updating Users",
|
||||
"user_install": "Installing Users",
|
||||
"start_sync": "START SYNCHRONIZATION",
|
||||
"new_app_version": "A new version of the application is available!",
|
||||
"open_store": "Open the store"
|
||||
},
|
||||
"contact_s": {
|
||||
"contact_transferred": "Contact Transferred",
|
||||
"contact_will_be_sent_after_sync": "The contact will be sent after synchronization",
|
||||
"confirm_contact_delete": "Are you sure to delete this contact ?",
|
||||
"contact_deleted": "Contact deleted",
|
||||
"contact_added": "Contact added",
|
||||
"send_flyer": "Send a document",
|
||||
"select_contact": "Select the contact",
|
||||
"transfer": "Transfer",
|
||||
"contact_list": "Contact List",
|
||||
"documents_list": "Documents List"
|
||||
},
|
||||
"contact_details_s": {
|
||||
"visits": "Visits",
|
||||
"notes": "Notes",
|
||||
"contact_saved": "Contact saved",
|
||||
"confirm_visit_delete": "are you sure to delete this visit ?",
|
||||
"qrcode_not_vcard_format": "This QRCode is not a VCard",
|
||||
"customer": "Customer",
|
||||
"prospect": "Prospect",
|
||||
"other": "Other",
|
||||
"description": "Description",
|
||||
"no_visits": "No visits available",
|
||||
"visit_name": "visits name"
|
||||
},
|
||||
"error": {
|
||||
"error": "Error",
|
||||
"tablet_not_connected_internet": "The tablet is not connected to Internet",
|
||||
"tablet_not_synced_last_user": "The previous user didn't synchronised the tablet",
|
||||
"incorrect_credentials": "Incorrect Credentials",
|
||||
"must_fill_login_fields": "You must fill the login fields.",
|
||||
"invalid_email_address": "Invalid E-mail adress",
|
||||
"error_has_occurred": "An error occured",
|
||||
"must_be_connected_internet_sync": "You must be connected to internet to be able to synchronize",
|
||||
"incomplete_form": "Incomplete Form",
|
||||
"fill_all_fields_and_1_doc_min": "Please fill up all the fields, at least one document and a valid e-mail adress",
|
||||
"fill_other_field": "You must fill the description field for : Other",
|
||||
"specify_type_contact": "You must specify the contact type",
|
||||
"invalid_name": "Invalid lastname",
|
||||
"invalid_firstname": "Invalid firstname",
|
||||
"camera_permission_denied": "Camera Permission Denied",
|
||||
"pending_camera_permission": "Waiting for the camera permission"
|
||||
},
|
||||
"custom": {
|
||||
"select-1": {
|
||||
"title": "Type of business",
|
||||
"c1": "Retail trade",
|
||||
"c2": "Home Service / Freezer Center",
|
||||
"c3": "Catering table service",
|
||||
"c4": "Fast food and snacking",
|
||||
"c5": "Cafeteria / Self Service",
|
||||
"c6": "Catering company",
|
||||
"c7": "Contract catering / Central kitchen",
|
||||
"c8": "Independent distributor",
|
||||
"c9": "Bakery and pastry shop",
|
||||
"c10": "Intermediate Food Products",
|
||||
"c11": "Destocker",
|
||||
"c12": "Halal trade",
|
||||
"c13": "Accommodation catering",
|
||||
"c14": "Commercial catering centre",
|
||||
"c15": "Event catering and park",
|
||||
"c16": "Restoration of transport",
|
||||
"c17": "Public procurement",
|
||||
"c18": "Cash",
|
||||
"c19": "National distributor",
|
||||
"c20": "Rungis",
|
||||
"c21": "Slaughterhouse",
|
||||
"c22": "Other"
|
||||
},
|
||||
"select-2": {
|
||||
"title": "Site",
|
||||
"c1": "Celvia Dinde",
|
||||
"c2": "Celvia Elaborés",
|
||||
"c3": "Celvia Sérent",
|
||||
"c4": "Procanar",
|
||||
"c5": "Celtys",
|
||||
"c6": "Farmor",
|
||||
"c7": "Robichon",
|
||||
"c8": "Les Volailles de Kerana",
|
||||
"c9": "Bosher Volaille",
|
||||
"c10": "LDC Bretagne",
|
||||
"c11": "Doux Farmor",
|
||||
"c12": "Favreau"
|
||||
},
|
||||
"interest": {
|
||||
"p1": "Chicken",
|
||||
"p2": "Turkey",
|
||||
"p3": "Duck",
|
||||
"p4": "Other"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
{
|
||||
"global": {
|
||||
"yes": "Oui",
|
||||
"no": "Non",
|
||||
"home": "Accueil",
|
||||
"search": "Recherche",
|
||||
"login": "Connexion",
|
||||
"email": "Email",
|
||||
"message_sent": "Message envoyé",
|
||||
"message_will_be_sent_after_sync": "Le message sera envoyé après synchronisation",
|
||||
"warning": "Attention",
|
||||
"synchronization": "Synchronisation",
|
||||
"videos": "Vidéos",
|
||||
"contacts": "Contacts",
|
||||
"confirmation": "Confirmation",
|
||||
"name": "Nom",
|
||||
"firstname": "Prénom",
|
||||
"address": "Adresse",
|
||||
"phone": "Téléphone",
|
||||
"company": "Société",
|
||||
"add": "Ajouter",
|
||||
"cancel": "Annuler",
|
||||
"subject": "Objet",
|
||||
"message": "Message",
|
||||
"send": "Envoyer",
|
||||
"required": "requis",
|
||||
"save": "Enregistrer",
|
||||
"retry": "Réessayer",
|
||||
"next": "Suivant"
|
||||
},
|
||||
"app": {
|
||||
"file_sharing": "Partage de fichier",
|
||||
"folders": "Dossiers",
|
||||
"video": "Vidéo",
|
||||
"contact_details": "Détails du contact",
|
||||
"results_search": "Résultat(s) de votre recherche",
|
||||
"my_space": "Mon espace"
|
||||
},
|
||||
"login_s": {
|
||||
"install": "Installer",
|
||||
"username": "Identifiant",
|
||||
"password": "Mot de passe"
|
||||
},
|
||||
"home_s": {
|
||||
"1": "Le Groupe",
|
||||
"2": "Nos Marques",
|
||||
"3": "Autres"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "Aucun résultat"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Téléchargement",
|
||||
"update_completed": "Mise à jour effectuée",
|
||||
"updating_docs": "Mise à jour des documents",
|
||||
"updating_folders": "Mise à jour des dossiers",
|
||||
"sending_flyers": "Envoi des brochures",
|
||||
"updating_contacts": "Mise à jour des contacts",
|
||||
"user_install_completed": "Installation des utilisateurs effectuée",
|
||||
"updating_users": "Mise à jour des utilisateurs",
|
||||
"user_install": "Installation des utilisateurs",
|
||||
"start_sync": "LANCER LA SYNCHRONISATION",
|
||||
"new_app_version": "Une nouvelle version de l'application est disponible !",
|
||||
"open_store": "Ouvrir le store"
|
||||
},
|
||||
"contact_s": {
|
||||
"contact_transferred": "Contact transféré",
|
||||
"contact_will_be_sent_after_sync": "Le contact sera envoyé après synchronisation",
|
||||
"confirm_contact_delete": "Êtes-vous sûr de vouloir supprimer ce contact ?",
|
||||
"contact_deleted": "Contact supprimé",
|
||||
"contact_added": "Contact ajouté",
|
||||
"send_flyer": "Envoyer une brochure",
|
||||
"select_contact": "Sélectionnez le contact",
|
||||
"transfer": "Transférer",
|
||||
"contact_list": "Liste des contacts",
|
||||
"documents_list": "Liste des documents"
|
||||
},
|
||||
"contact_details_s": {
|
||||
"visits": "Visites",
|
||||
"notes": "Notes",
|
||||
"contact_saved": "Contact enregistré",
|
||||
"confirm_visit_delete": "Êtes-vous sûr de vouloir supprimer cette visite ?",
|
||||
"qrcode_not_vcard_format": "Ce QRCode n'est pas au format vCard",
|
||||
"customer": "Client",
|
||||
"prospect": "Prospect",
|
||||
"other": "Autre",
|
||||
"description": "Description",
|
||||
"no_visits": "Aucune visites",
|
||||
"visit_name": "Nom de la visite"
|
||||
},
|
||||
"error": {
|
||||
"error": "Erreur",
|
||||
"tablet_not_connected_internet": "La tablette n'est pas connectée à internet.",
|
||||
"tablet_not_synced_last_user": "La tablette n'as pas été synchronisée par l'utilisateur précédent.",
|
||||
"incorrect_credentials": "Identifiants incorrect.",
|
||||
"must_fill_login_fields": "Vous devez-remplir les champs de connexion.",
|
||||
"invalid_email_address": "Adresse email invalide",
|
||||
"error_has_occurred": "Une erreur est survenue",
|
||||
"must_be_connected_internet_sync": "Vous devez être connecté à internet pour lancer la synchronisation",
|
||||
"incomplete_form": "Formulaire incomplet",
|
||||
"fill_all_fields_and_1_doc_min": "Veuillez remplir tous les champs, 1 document minimum et une adresse email valide",
|
||||
"fill_other_field": "Vous devez remplir le champs description pour : Autre",
|
||||
"specify_type_contact": "Vous devez préciser le type de contact",
|
||||
"invalid_name": "Nom invalide",
|
||||
"invalid_firstname": "Prénom invalide",
|
||||
"camera_permission_denied": "Permission caméra refusée",
|
||||
"pending_camera_permission": "En attente de permission caméra"
|
||||
},
|
||||
"custom": {
|
||||
"select-1": {
|
||||
"title": "Type de commerce",
|
||||
"c1": "Commerce de détail",
|
||||
"c2": "Home Service / Freezer Center",
|
||||
"c3": "Restauration service à table",
|
||||
"c4": "Fast food et snacking",
|
||||
"c5": "Cafétaria / Self Service",
|
||||
"c6": "Société de restauration",
|
||||
"c7": "Restauration gré à gré / cuisine Centrale",
|
||||
"c8": "Distributeur indépendant",
|
||||
"c9": "Boulangerie pâtisserie",
|
||||
"c10": "PAI",
|
||||
"c11": "Destockeur",
|
||||
"c12": "Commerce Halal",
|
||||
"c13": "Restauration d'hébergement",
|
||||
"c14": "Centrale restauration commerciale",
|
||||
"c15": "Restauration évenementielle et parc",
|
||||
"c16": "Restauration de transport",
|
||||
"c17": "Marché public",
|
||||
"c18": "Cash",
|
||||
"c19": "Distributeur national",
|
||||
"c20": "Rungis",
|
||||
"c21": "Abbatoir",
|
||||
"c22": "Autre"
|
||||
},
|
||||
"select-2": {
|
||||
"title": "Site",
|
||||
"c1": "Celvia Dinde",
|
||||
"c2": "Celvia Elaborés",
|
||||
"c3": "Celvia Sérent",
|
||||
"c4": "Procanar",
|
||||
"c5": "Celtys",
|
||||
"c6": "Farmor",
|
||||
"c7": "Robichon",
|
||||
"c8": "Les Volailles de Kerana",
|
||||
"c9": "Bosher Volaille",
|
||||
"c10": "LDC Bretagne",
|
||||
"c11": "Doux Farmor",
|
||||
"c12": "Favreau"
|
||||
},
|
||||
"interest": {
|
||||
"p1": "Poulet",
|
||||
"p2": "Dinde",
|
||||
"p3": "Canard",
|
||||
"p4": "Autre"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
import Database from '../Database';
|
||||
|
||||
const Realm = require('realm');
|
||||
let realm = new Realm(Database);
|
||||
|
||||
class CommonModel {
|
||||
constructor() {
|
||||
this.schema = 'Common';
|
||||
}
|
||||
|
||||
add(data) {
|
||||
realm.write(() => {
|
||||
if (data.id === undefined) {
|
||||
let id: any = realm.objects(this.schema).max('id');
|
||||
data.id = id === undefined ? 1 : id + 1;
|
||||
}
|
||||
try {
|
||||
realm.create(this.schema, data, 'never');
|
||||
} catch (e) {
|
||||
console.log('db common add', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
update(data) {
|
||||
let tmp = this.get(data.key);
|
||||
if (tmp === undefined) {
|
||||
this.add(data);
|
||||
} else {
|
||||
if (data.id === undefined) {
|
||||
data.id = tmp.id;
|
||||
}
|
||||
realm.write(() => {
|
||||
realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get(key) {
|
||||
let tmp = realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('key = "' + key + '"')[0];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
getAll() {
|
||||
let tmp = realm.objects(this.schema);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const tmp = this.get(key);
|
||||
if (typeof tmp === 'object') {
|
||||
realm.write(() => {
|
||||
realm.delete(tmp);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new CommonModel();
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
import Database from '../Database';
|
||||
|
||||
const Realm = require('realm');
|
||||
let realm = new Realm(Database);
|
||||
|
||||
class ContactsModel {
|
||||
constructor() {
|
||||
this.schema = 'Contacts';
|
||||
}
|
||||
|
||||
add(contact) {
|
||||
contact.uniq_id = contact.id;
|
||||
contact.id = undefined;
|
||||
realm.write(() => {
|
||||
if (contact.id === undefined) {
|
||||
let id: any = realm.objects(this.schema).max('id');
|
||||
contact.id = id === undefined ? 1 : id + 1;
|
||||
}
|
||||
realm.create(this.schema, contact);
|
||||
});
|
||||
}
|
||||
|
||||
update(contact) {
|
||||
realm.write(() => {
|
||||
realm.create(this.schema, contact, true);
|
||||
});
|
||||
}
|
||||
|
||||
get(id) {
|
||||
let tmp = realm.objects(this.schema).filtered('id = ' + id)[0];
|
||||
return tmp;
|
||||
}
|
||||
|
||||
getAll() {
|
||||
let tmp = realm.objects(this.schema);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
getByUser(userId) {
|
||||
let tmp = realm.objects(this.schema);
|
||||
tmp = tmp.filtered('to_delete = false AND user_id = ' + userId);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
delete(id) {
|
||||
const tmp = this.get(id);
|
||||
realm.write(() => {
|
||||
tmp.to_delete = true;
|
||||
// HARD DELETE - > realm.delete(tmp);
|
||||
});
|
||||
}
|
||||
|
||||
clear() {
|
||||
realm.write(() => {
|
||||
realm.delete(this.getAll());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new ContactsModel();
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
import Database from '../Database';
|
||||
|
||||
const Realm = require('realm');
|
||||
let realm = new Realm(Database);
|
||||
|
||||
class DirectoriesModel {
|
||||
constructor() {
|
||||
this.schema = 'Directories';
|
||||
}
|
||||
|
||||
add(directory) {
|
||||
realm.write(() => {
|
||||
realm.create(this.schema, directory);
|
||||
});
|
||||
}
|
||||
|
||||
update(directory) {
|
||||
realm.write(() => {
|
||||
realm.create(this.schema, directory, true);
|
||||
});
|
||||
}
|
||||
|
||||
get(id) {
|
||||
let tmp = realm.objects(this.schema).filtered('id = ' + id)[0];
|
||||
return tmp;
|
||||
}
|
||||
|
||||
getAll(role, authorizedFolders, format, lang) {
|
||||
if (authorizedFolders !== null && authorizedFolders !== undefined) {
|
||||
authorizedFolders = JSON.parse(authorizedFolders);
|
||||
}
|
||||
let tmp = realm.objects(this.schema);
|
||||
if (role === 'USER') {
|
||||
if (authorizedFolders.length > 0) {
|
||||
tmp = tmp.filtered(
|
||||
'needAuthorization = 0 OR ' +
|
||||
authorizedFolders
|
||||
.map(folder => ' id = "' + folder.id + '"')
|
||||
.join(' OR '),
|
||||
);
|
||||
} else {
|
||||
tmp = tmp.filtered(
|
||||
'needAuthorization = 0'
|
||||
);
|
||||
}
|
||||
}
|
||||
if (format) {
|
||||
return this._recursiveDir(tmp, lang);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
clear() {
|
||||
realm.write(() => {
|
||||
realm.delete(this.getAll('SYNC', null, false));
|
||||
});
|
||||
}
|
||||
|
||||
_recursiveDir(list, lang, parent = null) {
|
||||
let root = list.filter(e => e.parent === parent);
|
||||
let tmp = [];
|
||||
for (let i = 0; i < root.length; i++) {
|
||||
let childs = this._recursiveDir(list, lang, root[i].id);
|
||||
let name = JSON.parse(root[i].name);
|
||||
tmp[i] = {};
|
||||
tmp[i].id = root[i].id;
|
||||
tmp[i].name = this.getI18nName(lang, name);
|
||||
tmp[i].items = [];
|
||||
for (let j = 0; j < childs.length; j++) {
|
||||
childs[j].value = childs[j].id;
|
||||
tmp[i].items.push(childs[j]);
|
||||
}
|
||||
if (!tmp[i].items.length) {
|
||||
delete tmp[i].items;
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
getI18nName(lang, name) {
|
||||
let tmp = undefined;
|
||||
switch (lang) {
|
||||
case "fr":
|
||||
tmp = name.fr;
|
||||
break;
|
||||
case "en":
|
||||
tmp = name.en;
|
||||
break;
|
||||
case "de":
|
||||
tmp = name.de;
|
||||
break;
|
||||
case "es":
|
||||
tmp = name.es;
|
||||
break;
|
||||
}
|
||||
if (tmp === undefined) {
|
||||
tmp = name.fr;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default new DirectoriesModel();
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
import Database from '../Database';
|
||||
|
||||
const Realm = require('realm');
|
||||
let realm = new Realm(Database);
|
||||
|
||||
class DocumentsModel {
|
||||
constructor() {
|
||||
this.schema = 'Documents';
|
||||
}
|
||||
|
||||
add(document) {
|
||||
realm.write(() => {
|
||||
realm.create(this.schema, document, 'never');
|
||||
});
|
||||
}
|
||||
|
||||
update(document, updatedAtChange = false) {
|
||||
let tmp = this.get(document.id);
|
||||
if (tmp === undefined) {
|
||||
this.add(document);
|
||||
} else {
|
||||
realm.write(() => {
|
||||
if (updatedAtChange === false) {
|
||||
realm.create(this.schema, {
|
||||
id: tmp.id,
|
||||
uuid: document.uuid,
|
||||
title: document.title,
|
||||
type: document.type,
|
||||
path: document.path,
|
||||
directory: document.directory
|
||||
}, 'modified');
|
||||
} else {
|
||||
realm.create(this.schema, document, 'modified');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get(id) {
|
||||
let tmp = realm.objects(this.schema).filtered('id = ' + id)[0];
|
||||
return tmp;
|
||||
}
|
||||
|
||||
getAll(authorizedDirs = false) {
|
||||
let tmp = realm.objects(this.schema);
|
||||
if (authorizedDirs) {
|
||||
authorizedDirs = authorizedDirs.map(item => item.id);
|
||||
tmp = tmp.filter(doc => authorizedDirs.includes(doc.directory));
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
clear(docs, toDelete = []) {
|
||||
const localDocs = this.getAll();
|
||||
localDocs.forEach(doc => {
|
||||
let tmp = docs.filter(item => item.uuid === doc.uuid);
|
||||
if (tmp.length === 0) {
|
||||
toDelete.push({uuid: doc.uuid, type: doc.type});
|
||||
realm.write(() => {
|
||||
realm.delete(doc);
|
||||
});
|
||||
}
|
||||
});
|
||||
return toDelete;
|
||||
}
|
||||
}
|
||||
|
||||
export default new DocumentsModel();
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
import Database from '../Database';
|
||||
|
||||
const Realm = require('realm');
|
||||
let realm = new Realm(Database);
|
||||
|
||||
class SendBrochureModel {
|
||||
constructor() {
|
||||
this.schema = 'SendBrochure';
|
||||
}
|
||||
|
||||
add(data) {
|
||||
realm.write(() => {
|
||||
if (data.id === undefined) {
|
||||
let id: any = realm.objects(this.schema).max('id');
|
||||
data.id = id === undefined ? 1 : id + 1;
|
||||
}
|
||||
realm.create(this.schema, data);
|
||||
});
|
||||
}
|
||||
|
||||
update(data) {
|
||||
realm.write(() => {
|
||||
realm.create(this.schema, data, true);
|
||||
});
|
||||
}
|
||||
|
||||
get(id) {
|
||||
let tmp = realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('id = ' + id)[0];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
getAll() {
|
||||
let tmp = realm.objects(this.schema);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
clear() {
|
||||
realm.write(() => {
|
||||
realm.delete(this.getAll());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new SendBrochureModel();
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
import Database from '../Database';
|
||||
|
||||
const Realm = require('realm');
|
||||
let realm = new Realm(Database);
|
||||
|
||||
class UsersModel {
|
||||
constructor() {
|
||||
this.schema = 'Users';
|
||||
}
|
||||
|
||||
add(user) {
|
||||
realm.write(() => {
|
||||
realm.create(this.schema, user);
|
||||
});
|
||||
}
|
||||
|
||||
update(user) {
|
||||
realm.write(() => {
|
||||
realm.create(this.schema, user, true);
|
||||
});
|
||||
}
|
||||
|
||||
get(id) {
|
||||
let tmp = realm.objects(this.schema).filtered('id = ' + id)[0];
|
||||
return tmp;
|
||||
}
|
||||
|
||||
getAll() {
|
||||
let tmp = realm.objects(this.schema);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
clear() {
|
||||
realm.write(() => {
|
||||
realm.delete(this.getAll());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new UsersModel();
|
||||
|
|
@ -1,19 +1,9 @@
|
|||
import { View, Text, Image } from 'react-native';
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
import { createNavigationContainerRef } from '@react-navigation/native';
|
||||
|
||||
class CustomNavigation {
|
||||
LogoTitle(title) {
|
||||
return (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<Image
|
||||
style={{ width: 100, height: 50, resizeMode: 'stretch' }}
|
||||
source={{ uri: FileSystem.documentDirectory + 'RectangleLogo.png' }}
|
||||
/>
|
||||
<Text style={{ marginLeft: 10, fontSize: 18 }}>{title}</Text>
|
||||
</View>
|
||||
);
|
||||
export const navigationRef = createNavigationContainerRef()
|
||||
|
||||
export function navigate(name, params) {
|
||||
if (navigationRef.isReady()) {
|
||||
navigationRef.navigate(name, params);
|
||||
}
|
||||
}
|
||||
|
||||
export default new CustomNavigation();
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const commonStyles = StyleSheet.create({
|
||||
background: {
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
background: {
|
||||
flex: 1,
|
||||
justifyContent: "center"
|
||||
},
|
||||
textInput: {
|
||||
height: 40,
|
||||
width: 300,
|
||||
borderColor: 'grey',
|
||||
borderWidth: 1,
|
||||
marginBottom: 20,
|
||||
backgroundColor: 'white',
|
||||
paddingLeft: 10
|
||||
}
|
||||
textInput: {
|
||||
height: 40,
|
||||
width: 300,
|
||||
borderColor: 'grey',
|
||||
borderWidth: 1,
|
||||
marginBottom: 20,
|
||||
backgroundColor: 'white',
|
||||
paddingLeft: 10
|
||||
}
|
||||
});
|
||||
|
||||
export default commonStyles;
|
||||
|
|
@ -1,5 +1,19 @@
|
|||
{
|
||||
"install": {
|
||||
"installation": "Installation",
|
||||
"install": "Installieren Sie",
|
||||
"enter_url": "Bitte geben Sie den Link zu Ihrem Backoffice ein",
|
||||
"url_invalid": "Der eingegebene Link ist ungültig.",
|
||||
"resource_dl_error": "Beim Herunterladen der folgenden Lerneinheit ist ein Fehler aufgetreten: ",
|
||||
"install_complete": "Installation abgeschlossen!",
|
||||
"get_app_setting": "Wiederherstellen der Konfiguration der Anwendung",
|
||||
"get_content_setting": "Abrufen der Konfiguration des Inhalts der Anwendung"
|
||||
},
|
||||
"global": {
|
||||
"change_lang": "Sprache wechseln",
|
||||
"sync": "Synchronisation",
|
||||
"logout": "Abmeldung",
|
||||
"close": "Schließen Sie",
|
||||
"install": "Installieren",
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
|
|
@ -41,11 +55,6 @@
|
|||
"username": "Benutzername",
|
||||
"password": "Passwort"
|
||||
},
|
||||
"home_s": {
|
||||
"1": "Kataloge",
|
||||
"2": "Datenblätter",
|
||||
"3": "Andere"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "Keine Ergebnisse"
|
||||
},
|
||||
|
|
@ -105,53 +114,5 @@
|
|||
"invalid_firstname": "ungültiger Vorname",
|
||||
"camera_permission_denied": "Kameraerlaubnis verweigert",
|
||||
"pending_camera_permission": "Warten auf Kameraerlaubnis"
|
||||
},
|
||||
"custom": {
|
||||
"select-1": {
|
||||
"title": "Type de commerce",
|
||||
"c1": "Commerce de détail",
|
||||
"c2": "Home Service / Freezer Center",
|
||||
"c3": "Restauration service à table",
|
||||
"c4": "Fast food et snacking",
|
||||
"c5": "Cafétaria / Self Service",
|
||||
"c6": "Société de restauration",
|
||||
"c7": "Restauration gré à gré / cuisine Centrale",
|
||||
"c8": "Distributeur indépendant",
|
||||
"c9": "Boulangerie pâtisserie",
|
||||
"c10": "PAI",
|
||||
"c11": "Destockeur",
|
||||
"c12": "Commerce Halal",
|
||||
"c13": "Restauration d'hébergement",
|
||||
"c14": "Centrale restauration commerciale",
|
||||
"c15": "Restauration évenementielle et parc",
|
||||
"c16": "Restauration de transport",
|
||||
"c17": "Marché public",
|
||||
"c18": "Cash",
|
||||
"c19": "Distributeur national",
|
||||
"c20": "Rungis",
|
||||
"c21": "Abbatoir",
|
||||
"c22": "Autre"
|
||||
},
|
||||
"select-2": {
|
||||
"title": "Site",
|
||||
"c1": "Celvia Dinde",
|
||||
"c2": "Celvia Elaborés",
|
||||
"c3": "Celvia Sérent",
|
||||
"c4": "Procanar",
|
||||
"c5": "Celtys",
|
||||
"c6": "Farmor",
|
||||
"c7": "Robichon",
|
||||
"c8": "Les Volailles de Kerana",
|
||||
"c9": "Bosher Volaille",
|
||||
"c10": "LDC Bretagne",
|
||||
"c11": "Doux Farmor",
|
||||
"c12": "Favreau"
|
||||
},
|
||||
"interest": {
|
||||
"p1": "Poulet",
|
||||
"p2": "Dinde",
|
||||
"p3": "Canard",
|
||||
"p4": "Autre"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,19 @@
|
|||
{
|
||||
"install": {
|
||||
"installation": "Installation",
|
||||
"install": "Install",
|
||||
"enter_url": "Please enter your back office link",
|
||||
"url_invalid": "The link you entered is invalid.",
|
||||
"resource_dl_error": "An error occurred while downloading the following resource: ",
|
||||
"install_complete": "Installation is complete!",
|
||||
"get_app_setting": "Retrieving the application's configuration",
|
||||
"get_content_setting": "Retrieving the configuration of the application content"
|
||||
},
|
||||
"global": {
|
||||
"change_lang": "Change language",
|
||||
"sync": "Synchronization",
|
||||
"logout": "Logout",
|
||||
"close": "Close",
|
||||
"install": "Install",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
|
|
@ -41,11 +55,6 @@
|
|||
"username": "Username",
|
||||
"password": "Password"
|
||||
},
|
||||
"home_s": {
|
||||
"1": "Catalogs",
|
||||
"2": "Data sheets",
|
||||
"3": "Others"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "No Result"
|
||||
},
|
||||
|
|
@ -105,53 +114,5 @@
|
|||
"invalid_firstname": "Invalid firstname",
|
||||
"camera_permission_denied": "Camera Permission Denied",
|
||||
"pending_camera_permission": "Waiting for the camera permission"
|
||||
},
|
||||
"custom": {
|
||||
"select-1": {
|
||||
"title": "Type de commerce",
|
||||
"c1": "Commerce de détail",
|
||||
"c2": "Home Service / Freezer Center",
|
||||
"c3": "Restauration service à table",
|
||||
"c4": "Fast food et snacking",
|
||||
"c5": "Cafétaria / Self Service",
|
||||
"c6": "Société de restauration",
|
||||
"c7": "Restauration gré à gré / cuisine Centrale",
|
||||
"c8": "Distributeur indépendant",
|
||||
"c9": "Boulangerie pâtisserie",
|
||||
"c10": "PAI",
|
||||
"c11": "Destockeur",
|
||||
"c12": "Commerce Halal",
|
||||
"c13": "Restauration d'hébergement",
|
||||
"c14": "Centrale restauration commerciale",
|
||||
"c15": "Restauration évenementielle et parc",
|
||||
"c16": "Restauration de transport",
|
||||
"c17": "Marché public",
|
||||
"c18": "Cash",
|
||||
"c19": "Distributeur national",
|
||||
"c20": "Rungis",
|
||||
"c21": "Abbatoir",
|
||||
"c22": "Autre"
|
||||
},
|
||||
"select-2": {
|
||||
"title": "Site",
|
||||
"c1": "Celvia Dinde",
|
||||
"c2": "Celvia Elaborés",
|
||||
"c3": "Celvia Sérent",
|
||||
"c4": "Procanar",
|
||||
"c5": "Celtys",
|
||||
"c6": "Farmor",
|
||||
"c7": "Robichon",
|
||||
"c8": "Les Volailles de Kerana",
|
||||
"c9": "Bosher Volaille",
|
||||
"c10": "LDC Bretagne",
|
||||
"c11": "Doux Farmor",
|
||||
"c12": "Favreau"
|
||||
},
|
||||
"interest": {
|
||||
"p1": "Poulet",
|
||||
"p2": "Dinde",
|
||||
"p3": "Canard",
|
||||
"p4": "Autre"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
"get_content_setting": "Récupération de la configuration du contenu de l'application"
|
||||
},
|
||||
"global": {
|
||||
"change_lang": "Changer de langue",
|
||||
"sync": "Synchronisation",
|
||||
"logout": "Se déconnecter",
|
||||
"close": "Fermer",
|
||||
"yes": "Oui",
|
||||
"no": "Non",
|
||||
"home": "Accueil",
|
||||
|
|
@ -51,11 +55,6 @@
|
|||
"password": "Mot de passe",
|
||||
"missing_users": "Utilisateurs introuvables"
|
||||
},
|
||||
"home_s": {
|
||||
"1": "Catalogues",
|
||||
"2": "Fiches techniques",
|
||||
"3": "Autres"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "Aucun résultat"
|
||||
},
|
||||
|
|
@ -119,53 +118,5 @@
|
|||
"alert": {
|
||||
"error": "Erreur",
|
||||
"info": "Information"
|
||||
},
|
||||
"custom": {
|
||||
"select-1": {
|
||||
"title": "Type de commerce",
|
||||
"c1": "Commerce de détail",
|
||||
"c2": "Home Service / Freezer Center",
|
||||
"c3": "Restauration service à table",
|
||||
"c4": "Fast food et snacking",
|
||||
"c5": "Cafétaria / Self Service",
|
||||
"c6": "Société de restauration",
|
||||
"c7": "Restauration gré à gré / cuisine Centrale",
|
||||
"c8": "Distributeur indépendant",
|
||||
"c9": "Boulangerie pâtisserie",
|
||||
"c10": "PAI",
|
||||
"c11": "Destockeur",
|
||||
"c12": "Commerce Halal",
|
||||
"c13": "Restauration d'hébergement",
|
||||
"c14": "Centrale restauration commerciale",
|
||||
"c15": "Restauration évenementielle et parc",
|
||||
"c16": "Restauration de transport",
|
||||
"c17": "Marché public",
|
||||
"c18": "Cash",
|
||||
"c19": "Distributeur national",
|
||||
"c20": "Rungis",
|
||||
"c21": "Abbatoir",
|
||||
"c22": "Autre"
|
||||
},
|
||||
"select-2": {
|
||||
"title": "Site",
|
||||
"c1": "Celvia Dinde",
|
||||
"c2": "Celvia Elaborés",
|
||||
"c3": "Celvia Sérent",
|
||||
"c4": "Procanar",
|
||||
"c5": "Celtys",
|
||||
"c6": "Farmor",
|
||||
"c7": "Robichon",
|
||||
"c8": "Les Volailles de Kerana",
|
||||
"c9": "Bosher Volaille",
|
||||
"c10": "LDC Bretagne",
|
||||
"c11": "Doux Farmor",
|
||||
"c12": "Favreau"
|
||||
},
|
||||
"interest": {
|
||||
"p1": "Poulet",
|
||||
"p2": "Dinde",
|
||||
"p3": "Canard",
|
||||
"p4": "Autre"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ const styles = StyleSheet.create({
|
|||
textAlign: 'center',
|
||||
fontSize: 18,
|
||||
width: width / 4,
|
||||
color: '#ea4f52',
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
company: {
|
||||
|
|
@ -68,8 +67,7 @@ const styles = StyleSheet.create({
|
|||
btnSearch: {
|
||||
width: 50,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#ea4f52'
|
||||
justifyContent: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ const styles = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
height: 200,
|
||||
width: 180,
|
||||
backgroundColor: '#ea4f52',
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { StyleSheet } from 'react-native';
|
|||
const styles = StyleSheet.create({
|
||||
searchInput: {
|
||||
borderWidth: 1,
|
||||
borderColor: '#ea4f52',
|
||||
width: 200,
|
||||
paddingLeft: 20,
|
||||
},
|
||||
|
|
@ -12,7 +11,27 @@ const styles = StyleSheet.create({
|
|||
height: 50,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#ea4f52'
|
||||
},
|
||||
drawer: {
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
backgroundColor: "#ffffff",
|
||||
padding: 20
|
||||
},
|
||||
btn: {
|
||||
borderWidth: 1,
|
||||
borderColor: 'black',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: 10,
|
||||
marginBottom: 10
|
||||
},
|
||||
btnText: {
|
||||
marginLeft: 10
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ const styles = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
height: 200,
|
||||
width: 180,
|
||||
backgroundColor: '#ea4f52',
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ const styles = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
height: 200,
|
||||
width: 180,
|
||||
backgroundColor: '#ea4f52',
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.5 KiB |
BIN
ComApp/src/Resources/assets/img/logo.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
ComApp/src/Resources/assets/img/splashscreen.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -1,614 +0,0 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
Button,
|
||||
FlatList,
|
||||
Text,
|
||||
Dimensions,
|
||||
TouchableOpacity,
|
||||
Alert,
|
||||
TextInput,
|
||||
} from 'react-native';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome';
|
||||
import { connect, ReactReduxContext } from 'react-redux';
|
||||
import { showMessage } from 'react-native-flash-message';
|
||||
import { Overlay } from '@rneui/themed';
|
||||
import Helpers from "../Controllers/Helpers";
|
||||
import i18n from "../I18n";
|
||||
import { Picker } from '@react-native-picker/picker';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
users: state.users,
|
||||
contacts: state.contacts,
|
||||
documents: state.documents,
|
||||
currentUser: state.currentUser,
|
||||
};
|
||||
}
|
||||
|
||||
class ContactScreen extends React.Component {
|
||||
state = {
|
||||
contacts: [],
|
||||
sortType: 'asc',
|
||||
sortField: 'name',
|
||||
searchTxt: '',
|
||||
showTransferContact: false,
|
||||
selectedTransferUser: 0,
|
||||
contactToTransfer: {},
|
||||
showSendBrochure: false,
|
||||
selectedDocument: -1,
|
||||
sendDocumentList: [],
|
||||
selectedSendBrochureEmail: -1,
|
||||
tmpSendBrochureEmail: '',
|
||||
tmpSendBrochureSubject: '',
|
||||
tmpSendBrochureMessage: '',
|
||||
sortedDocuments: [],
|
||||
sortedEmails: [],
|
||||
};
|
||||
|
||||
sendBrochure() {
|
||||
if (
|
||||
this.state.tmpSendBrochureEmail !== '' &&
|
||||
this.state.tmpSendBrochureSubject !== '' &&
|
||||
this.state.tmpSendBrochureMessage !== '' &&
|
||||
this.state.sendDocumentList.length > 0 &&
|
||||
Helpers.isEmailValid(this.state.tmpSendBrochureEmail)
|
||||
) {
|
||||
const email = {
|
||||
email: this.state.tmpSendBrochureEmail,
|
||||
subject: this.state.tmpSendBrochureSubject,
|
||||
message: this.state.tmpSendBrochureMessage,
|
||||
documents: JSON.stringify(this.state.sendDocumentList),
|
||||
user_id: this.props.currentUser.id
|
||||
};
|
||||
this.props.dispatch({ type: 'SEND_BROCHURE', data: email });
|
||||
this.setState({
|
||||
showSendBrochure: false,
|
||||
tmpSendBrochureEmail: '',
|
||||
tmpSendBrochureSubject: '',
|
||||
tmpSendBrochureMessage: '',
|
||||
selectedSendBrochureEmail: -1,
|
||||
selectedDocument: -1,
|
||||
sendDocumentList: [],
|
||||
});
|
||||
showMessage({
|
||||
message: i18n.t('global.message_sent') + '.',
|
||||
description: i18n.t('global.message_will_be_sent_after_sync') + '.',
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
});
|
||||
} else {
|
||||
Alert.alert(
|
||||
i18n.t('error.incomplete_form'),
|
||||
i18n.t('error.fill_all_fields_and_1_doc_min') + '.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
transferContact() {
|
||||
const nextUser = this.props.users.filter(user => user.id !== this.props.currentUser.id)[this.state.selectedTransferUser];
|
||||
const transferContact = this.state.contactToTransfer;
|
||||
const contact = {
|
||||
id: transferContact.id,
|
||||
email: transferContact.email,
|
||||
type: transferContact.type,
|
||||
other: transferContact.other,
|
||||
network: transferContact.network,
|
||||
name: transferContact.name,
|
||||
firstname: transferContact.firstname,
|
||||
office: transferContact.office,
|
||||
company: transferContact.company,
|
||||
address: transferContact.address,
|
||||
phone: transferContact.phone,
|
||||
products: transferContact.products,
|
||||
notes: transferContact.note,
|
||||
visits: transferContact.visits,
|
||||
to_delete: false,
|
||||
synced: false,
|
||||
user_id: nextUser.id,
|
||||
};
|
||||
this.props.dispatch({ type: 'UPDATE_CONTACT', data: contact });
|
||||
this.setState({ showTransferContact: false });
|
||||
showMessage({
|
||||
message: i18n.t('contact_s.contact_transferred') + '.',
|
||||
description: i18n.t('contact_s.contact_will_be_sent_after_sync') + '.',
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
});
|
||||
}
|
||||
|
||||
deleteContact(id) {
|
||||
Alert.alert(
|
||||
i18n.t('global.confirmation'),
|
||||
i18n.t('contact_s.confirm_contact_delete'),
|
||||
[
|
||||
{
|
||||
text: i18n.t('global.no'),
|
||||
onPress: () => console.log('Cancel Pressed'),
|
||||
style: 'cancel',
|
||||
},
|
||||
{
|
||||
text: i18n.t('global.yes'),
|
||||
onPress: () => {
|
||||
this.setState({ contacts: [], sortedEmails: [] });
|
||||
this.props.dispatch({ type: 'DELETE_CONTACT', data: id });
|
||||
showMessage({
|
||||
message: i18n.t('contact_s.contact_deleted') + '.',
|
||||
type: 'success',
|
||||
duration: 500,
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
{ cancelable: false },
|
||||
);
|
||||
}
|
||||
|
||||
Item(item) {
|
||||
return (
|
||||
<View style={styles.item}>
|
||||
<TouchableOpacity
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate('ContactDetailsScreen', {
|
||||
action: 'edit',
|
||||
contactId: item.id,
|
||||
})
|
||||
}>
|
||||
<Text style={styles.clickable}>
|
||||
{item.name.toUpperCase()} {item.firstname}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.company}>{item.company}</Text>
|
||||
<Text style={styles.email}>{item.email}</Text>
|
||||
<View style={styles.buttons}>
|
||||
<TouchableOpacity
|
||||
style={styles.button}
|
||||
onPress={() => {
|
||||
this.deleteContact(item.id);
|
||||
}}>
|
||||
<Icon name="trash" size={20} color={'#ea4f52'} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.button}
|
||||
onPress={() => {
|
||||
this.setState({
|
||||
showTransferContact: true,
|
||||
contactToTransfer: item,
|
||||
});
|
||||
}}>
|
||||
<Icon name="paper-plane" size={20} color={'#ea4f52'} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
sortContacts(field) {
|
||||
let sort;
|
||||
if (field !== this.state.sortField) {
|
||||
sort = 'asc';
|
||||
} else {
|
||||
if (this.state.sortType === 'asc') {
|
||||
sort = 'desc';
|
||||
} else {
|
||||
sort = 'asc';
|
||||
}
|
||||
}
|
||||
let obj = this.props.contacts;
|
||||
let array = Object.keys(obj).map(function (key) { return obj[key]; });
|
||||
this.setState({ contacts: array.sort(Helpers.compareValues(field, sort)), sortType: sort, sortField: field });
|
||||
//this.setState({ contacts: this.state.contacts.sort(Helpers.compareValues(field, sort)), sortType: sort, sortField: field });
|
||||
}
|
||||
|
||||
HeaderItem() {
|
||||
return (
|
||||
<View style={styles.item}>
|
||||
<TouchableOpacity onPress={() => {
|
||||
this.sortContacts('name');
|
||||
}}>
|
||||
<Text style={styles.clickable}>{i18n.t('global.name')} <Icon name={'sort'} /></Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => {
|
||||
this.sortContacts('company');
|
||||
}}>
|
||||
<Text style={styles.clickable}>{i18n.t('global.company')} <Icon name={'sort'} /></Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.email}>{i18n.t('global.email')}</Text>
|
||||
<Text style={styles.buttons} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
handleSearchBtn() {
|
||||
if (this.state.searchTxt.length > 0) {
|
||||
let obj = this.props.contacts;
|
||||
let array = Object.keys(obj).map(function (key) { return obj[key]; });
|
||||
this.setState({ contacts: array.sort(Helpers.compareValues('name', 'asc')), sortType: 'asc', searchTxt: '' });
|
||||
}
|
||||
}
|
||||
handleSearchTxt(text) {
|
||||
this.setState({ searchTxt: text });
|
||||
if (text.length > 0) {
|
||||
let tmpContactsName = this.props.contacts.filter(item => item.name.toLowerCase().indexOf(text.toLowerCase()) >= 0);
|
||||
let tmpContactsCompany = this.props.contacts.filter(item => {
|
||||
if (item.company === null) {
|
||||
return false;
|
||||
}
|
||||
return item.company.toLowerCase().indexOf(text.toLowerCase()) >= 0
|
||||
});
|
||||
let resSearch = Object.assign(tmpContactsName, tmpContactsCompany);
|
||||
this.setState({ contacts: resSearch.sort(Helpers.compareValues('name', 'asc')), sortType: 'asc' });
|
||||
} else {
|
||||
let obj = this.props.contacts;
|
||||
let array = Object.keys(obj).map(function (key) { return obj[key]; });
|
||||
this.setState({ contacts: array.sort(Helpers.compareValues('name', 'asc')), sortType: 'asc' });
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (prevProps.contacts !== this.props.contacts) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
let objContacts = this.props.contacts;
|
||||
let objDocs = this.props.documents;
|
||||
let arrayContacts = Object.keys(objContacts).map(function (key) { return objContacts[key]; });
|
||||
let arrayEmails = Object.keys(objContacts).map(function (key) { return objContacts[key]; });
|
||||
let arrayDocs = Object.keys(objDocs).map(function (key) { return objDocs[key]; });
|
||||
|
||||
this.setState({
|
||||
contacts: arrayContacts.sort(Helpers.compareValues('name', 'asc')),
|
||||
sortedDocuments: arrayDocs.sort(Helpers.compareValues('title', 'asc')),
|
||||
sortedEmails: arrayEmails.sort(Helpers.compareValues('email', 'asc')),
|
||||
sortType: 'asc',
|
||||
sortField: 'name',
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { contactAdded } = this.props.route.params;
|
||||
if (contactAdded === true) {
|
||||
this.props.navigation.setParams({ contactAdded: false });
|
||||
showMessage({
|
||||
message: i18n.t('contact_s.contact_added') + '.',
|
||||
type: 'success',
|
||||
duration: 500,
|
||||
});
|
||||
}
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View
|
||||
style={{
|
||||
marginTop: 20,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-evenly',
|
||||
alignItems: 'center',
|
||||
}}>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
title={i18n.t('global.add')}
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate('ContactDetailsScreen', {
|
||||
action: 'add',
|
||||
})
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
title={i18n.t('contact_s.send_flyer')}
|
||||
onPress={() => this.setState({ showSendBrochure: true })}
|
||||
/>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
<TextInput placeholder={i18n.t('global.search')} style={styles.inputSearch} value={this.state.searchTxt} onChangeText={(text) => this.handleSearchTxt(text)} />
|
||||
<TouchableOpacity style={styles.btnSearch} onPress={() => this.handleSearchBtn()}>
|
||||
{this.state.searchTxt.length > 0 ? (
|
||||
<Icon name={'times'} size={20} color={'white'} />
|
||||
) : (
|
||||
<Icon name={'search'} size={20} color={'white'} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
<View style={{ flex: 1, marginTop: 20 }}>
|
||||
<FlatList
|
||||
data={this.state.contacts}
|
||||
renderItem={({ item }) => this.Item(item)}
|
||||
ListHeaderComponent={this.HeaderItem.bind(this)}
|
||||
keyExtractor={item => item.id.toString()}
|
||||
/>
|
||||
</View>
|
||||
<Overlay
|
||||
isVisible={this.state.showTransferContact}
|
||||
windowBackgroundColor="rgba(255, 255, 255, .9)"
|
||||
overlayBackgroundColor="white"
|
||||
width={400}
|
||||
height={300}>
|
||||
<View
|
||||
style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text style={{ marginBottom: 10 }}>{i18n.t('contact_s.select_contact')} :</Text>
|
||||
<Picker
|
||||
style={{
|
||||
width: 300,
|
||||
marginBottom: 15,
|
||||
paddingLeft: 10,
|
||||
}}
|
||||
selectedValue={this.state.selectedTransferUser}
|
||||
onValueChange={(itemValue, itemIndex) => {
|
||||
this.setState({ selectedTransferUser: itemIndex });
|
||||
}}>
|
||||
{this.props.users.filter(user => user.id !== this.props.currentUser.id).map((item, index) => {
|
||||
return <Picker.Item label={item.email} value={index} key={item.id.toString()} />;
|
||||
})}
|
||||
</Picker>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-evenly',
|
||||
alignItems: 'center',
|
||||
width: 400,
|
||||
}}>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
title={i18n.t('global.cancel')}
|
||||
onPress={() => this.setState({ showTransferContact: false })}
|
||||
/>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
title={i18n.t('contact_s.transfer')}
|
||||
onPress={() => this.transferContact()}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</Overlay>
|
||||
<Overlay
|
||||
isVisible={this.state.showSendBrochure}
|
||||
windowBackgroundColor="rgba(255, 255, 255, .9)"
|
||||
overlayBackgroundColor="white"
|
||||
width={600}
|
||||
height={500}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={{ flex: 2, flexDirection: 'row' }}>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
}}>
|
||||
<TextInput
|
||||
style={styles.txtSendBrochure}
|
||||
placeholder={i18n.t('global.email')}
|
||||
autoCompleteType="email"
|
||||
autoCapitalize="none"
|
||||
keyboardType={'email-address'}
|
||||
value={this.state.tmpSendBrochureEmail}
|
||||
onChangeText={text =>
|
||||
this.setState({ tmpSendBrochureEmail: text })
|
||||
}
|
||||
/>
|
||||
<Picker
|
||||
style={{
|
||||
width: 300,
|
||||
marginBottom: 15,
|
||||
paddingLeft: 10,
|
||||
}}
|
||||
selectedValue={this.state.selectedSendBrochureEmail}
|
||||
onValueChange={(itemValue, itemIndex) => {
|
||||
if (itemValue !== '-1') {
|
||||
this.setState({
|
||||
tmpSendBrochureEmail: this.state.sortedEmails[itemIndex - 1]
|
||||
.email,
|
||||
});
|
||||
}
|
||||
}}>
|
||||
<Picker.Item label={i18n.t('contact_s.contact_list') + ' :'} value="-1" />
|
||||
{this.state.sortedEmails.map((item, index) => {
|
||||
return <Picker.Item label={item.email} value={index} key={item.id.toString()} />;
|
||||
})}
|
||||
</Picker>
|
||||
<TextInput
|
||||
style={styles.txtSendBrochure}
|
||||
placeholder={i18n.t('global.subject')}
|
||||
value={this.state.tmpSendBrochureSubject}
|
||||
onChangeText={text =>
|
||||
this.setState({ tmpSendBrochureSubject: text })
|
||||
}
|
||||
/>
|
||||
<TextInput
|
||||
style={styles.textAreaSendBrochure}
|
||||
placeholder={i18n.t('global.message')}
|
||||
value={this.state.tmpSendBrochureMessage}
|
||||
multiline={true}
|
||||
underlineColorAndroid="transparent"
|
||||
onChangeText={text =>
|
||||
this.setState({ tmpSendBrochureMessage: text })
|
||||
}
|
||||
/>
|
||||
<Picker
|
||||
style={{
|
||||
width: 300,
|
||||
marginBottom: 15,
|
||||
paddingLeft: 10,
|
||||
}}
|
||||
selectedValue={this.state.selectedDocument}
|
||||
onValueChange={(itemValue, itemIndex) => {
|
||||
if (
|
||||
itemValue !== '-1' &&
|
||||
this.state.sendDocumentList.length < 8
|
||||
) {
|
||||
let tmp = this.state.sendDocumentList;
|
||||
const toPush = this.state.sortedDocuments[itemIndex - 1];
|
||||
const test = this.state.sendDocumentList.filter(
|
||||
item => item.id === toPush.id,
|
||||
);
|
||||
if (test.length === 0) {
|
||||
tmp.push(toPush);
|
||||
this.setState({
|
||||
sendDocumentList: tmp,
|
||||
});
|
||||
}
|
||||
}
|
||||
}}>
|
||||
<Picker.Item label={i18n.t('contact_s.documents_list') + ' :'} value="-1" />
|
||||
{this.state.sortedDocuments.map((item, index) => {
|
||||
return (
|
||||
<Picker.Item
|
||||
label={
|
||||
item.title + ' (' + item.type.toUpperCase() + ')'
|
||||
}
|
||||
value={index}
|
||||
key={item.id.toString()}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Picker>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
borderWidth: 1,
|
||||
borderColor: 'lightgrey',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: 600,
|
||||
}}>
|
||||
{this.state.sendDocumentList.map((item, index) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
let tmp = this.state.sendDocumentList;
|
||||
tmp.splice(this.props.documents[index], 1);
|
||||
this.setState({
|
||||
sendDocumentList: tmp,
|
||||
});
|
||||
}}>
|
||||
<View
|
||||
style={{
|
||||
borderWidth: 1,
|
||||
borderColor: 'lightgrey',
|
||||
padding: 5,
|
||||
margin: 5,
|
||||
borderRadius: 5,
|
||||
}}>
|
||||
<Text>
|
||||
{item.title} ({item.type.toUpperCase()}){' '}
|
||||
<Icon name="minus" size={15} />
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-evenly',
|
||||
alignItems: 'center',
|
||||
width: 600,
|
||||
marginTop: 15,
|
||||
}}>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
title={i18n.t('global.cancel')}
|
||||
onPress={() =>
|
||||
this.setState({
|
||||
showSendBrochure: false,
|
||||
tmpSendBrochureEmail: '',
|
||||
tmpSendBrochureSubject: '',
|
||||
tmpSendBrochureMessage: '',
|
||||
selectedSendBrochureEmail: -1,
|
||||
selectedDocument: -1,
|
||||
sendDocumentList: [],
|
||||
})
|
||||
}
|
||||
/>
|
||||
<Button title={i18n.t('global.send')} onPress={() => this.sendBrochure()} color={'#ea4f52'} />
|
||||
</View>
|
||||
</View>
|
||||
</Overlay>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
},
|
||||
item: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
borderBottomWidth: 1,
|
||||
padding: 15,
|
||||
marginHorizontal: 15,
|
||||
},
|
||||
clickable: {
|
||||
textAlign: 'center',
|
||||
fontSize: 18,
|
||||
width: width / 4,
|
||||
color: '#ea4f52',
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
company: {
|
||||
textAlign: 'center',
|
||||
fontSize: 15,
|
||||
width: width / 4,
|
||||
},
|
||||
email: {
|
||||
textAlign: 'center',
|
||||
fontSize: 15,
|
||||
width: width / 4,
|
||||
},
|
||||
buttons: {
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row',
|
||||
fontSize: 15,
|
||||
width: width / 4,
|
||||
},
|
||||
button: {
|
||||
width: 35,
|
||||
height: 35,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
margin: 2,
|
||||
},
|
||||
txtSendBrochure: {
|
||||
borderWidth: 1,
|
||||
borderColor: 'lightgrey',
|
||||
width: 280,
|
||||
marginBottom: 5,
|
||||
paddingLeft: 10,
|
||||
},
|
||||
textAreaSendBrochure: {
|
||||
borderWidth: 1,
|
||||
borderColor: 'lightgrey',
|
||||
width: 280,
|
||||
height: 150,
|
||||
marginBottom: 5,
|
||||
paddingLeft: 10,
|
||||
textAlignVertical: 'top',
|
||||
},
|
||||
inputSearch: {
|
||||
backgroundColor: 'white',
|
||||
width: 200,
|
||||
paddingLeft: 20
|
||||
},
|
||||
btnSearch: {
|
||||
width: 50,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#ea4f52'
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(ContactScreen);
|
||||
|
|
@ -152,7 +152,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
};
|
||||
if (action === 'edit') {
|
||||
contact.id = this.state.tmpID;
|
||||
this.props.dispatch({ type: 'UPDATE_CONTACT', data: contact });
|
||||
this.props.dispatch({ type: 'EDIT_CONTACT', data: contact });
|
||||
this.populate();
|
||||
showMessage({
|
||||
message: i18n.t('contact_details_s.contact_saved') + '.',
|
||||
|
|
@ -344,7 +344,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
justifyContent: 'center',
|
||||
}}>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.customer')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -354,7 +354,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
onPress={() => this.updateContactType('client')}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.prospect')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -364,7 +364,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
onPress={() => this.updateContactType('prospect')}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.other')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -500,28 +500,28 @@ class ContactDetailsScreen extends React.Component {
|
|||
justifyContent: 'center',
|
||||
}}>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p1')}
|
||||
checked={this.state.p1}
|
||||
onPress={() => this.setState({ p1: !this.state.p1 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p2')}
|
||||
checked={this.state.p2}
|
||||
onPress={() => this.setState({ p2: !this.state.p2 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p3')}
|
||||
checked={this.state.p3}
|
||||
onPress={() => this.setState({ p3: !this.state.p3 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p4')}
|
||||
checked={this.state.p4}
|
||||
onPress={() => this.setState({ p4: !this.state.p4 })}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
};
|
||||
if (action === 'edit') {
|
||||
contact.id = this.state.tmpID;
|
||||
this.props.dispatch({ type: 'UPDATE_CONTACT', data: contact });
|
||||
this.props.dispatch({ type: 'EDIT_CONTACT', data: contact });
|
||||
this.populate();
|
||||
showMessage({
|
||||
message: i18n.t('contact_details_s.contact_saved') + '.',
|
||||
|
|
@ -344,7 +344,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
justifyContent: 'center',
|
||||
}}>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.customer')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -354,7 +354,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
onPress={() => this.updateContactType('client')}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.prospect')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -364,7 +364,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
onPress={() => this.updateContactType('prospect')}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.other')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -500,28 +500,28 @@ class ContactDetailsScreen extends React.Component {
|
|||
justifyContent: 'center',
|
||||
}}>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p1')}
|
||||
checked={this.state.p1}
|
||||
onPress={() => this.setState({ p1: !this.state.p1 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p2')}
|
||||
checked={this.state.p2}
|
||||
onPress={() => this.setState({ p2: !this.state.p2 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p3')}
|
||||
checked={this.state.p3}
|
||||
onPress={() => this.setState({ p3: !this.state.p3 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p4')}
|
||||
checked={this.state.p4}
|
||||
onPress={() => this.setState({ p4: !this.state.p4 })}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
};
|
||||
if (action === 'edit') {
|
||||
contact.id = this.state.tmpID;
|
||||
this.props.dispatch({ type: 'UPDATE_CONTACT', data: contact });
|
||||
this.props.dispatch({ type: 'EDIT_CONTACT', data: contact });
|
||||
this.populate();
|
||||
showMessage({
|
||||
message: i18n.t('contact_details_s.contact_saved') + '.',
|
||||
|
|
@ -343,7 +343,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
justifyContent: 'center',
|
||||
}}>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.customer')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -353,7 +353,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
onPress={() => this.updateContactType('client')}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.prospect')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -363,7 +363,7 @@ class ContactDetailsScreen extends React.Component {
|
|||
onPress={() => this.updateContactType('prospect')}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
center
|
||||
title={i18n.t('contact_details_s.other')}
|
||||
checkedIcon="dot-circle-o"
|
||||
|
|
@ -480,63 +480,63 @@ class ContactDetailsScreen extends React.Component {
|
|||
justifyContent: 'center',
|
||||
}}>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p1')}
|
||||
checked={this.state.p1}
|
||||
onPress={() => this.setState({ p1: !this.state.p1 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p2')}
|
||||
checked={this.state.p2}
|
||||
onPress={() => this.setState({ p2: !this.state.p2 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p3')}
|
||||
checked={this.state.p3}
|
||||
onPress={() => this.setState({ p3: !this.state.p3 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p4')}
|
||||
checked={this.state.p4}
|
||||
onPress={() => this.setState({ p4: !this.state.p4 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p5')}
|
||||
checked={this.state.p5}
|
||||
onPress={() => this.setState({ p5: !this.state.p5 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p6')}
|
||||
checked={this.state.p6}
|
||||
onPress={() => this.setState({ p6: !this.state.p6 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p7')}
|
||||
checked={this.state.p7}
|
||||
onPress={() => this.setState({ p7: !this.state.p7 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p8')}
|
||||
checked={this.state.p8}
|
||||
onPress={() => this.setState({ p8: !this.state.p8 })}
|
||||
containerStyle={styles.clearCheckbox}
|
||||
/>
|
||||
<CheckBox
|
||||
checkedColor={'#ea4f52'}
|
||||
checkedColor={this.props.mainColor}
|
||||
title={i18n.t('custom.interest.p9')}
|
||||
checked={this.state.p9}
|
||||
onPress={() => this.setState({ p9: !this.state.p9 })}
|
||||
|
|
|
|||
|
|
@ -1,114 +0,0 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
import {connect} from 'react-redux';
|
||||
import TreeView from 'react-native-animated-tree-view';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.documents,
|
||||
};
|
||||
}
|
||||
|
||||
class DirectoriesScreen extends React.Component {
|
||||
state = {
|
||||
documents: [],
|
||||
};
|
||||
|
||||
showDocuments(folder) {
|
||||
const documents = this.props.documents.filter(
|
||||
tmp => tmp.directory === folder.id,
|
||||
);
|
||||
this.setState({documents: documents});
|
||||
}
|
||||
|
||||
openDocument(document) {
|
||||
this.props.dispatch({type: 'SET_CURRENT_OPENED_DOC', data: document});
|
||||
if (document.type === 'pdf') {
|
||||
this.props.navigation.navigate('PDFScreen', {uuid: document.uuid});
|
||||
} else if (document.type === 'mp4') {
|
||||
this.props.navigation.navigate('VideoScreen', {uuid: document.uuid});
|
||||
} else {
|
||||
console.log('Inconnu');
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {folder} = this.props.route.params;
|
||||
let documentList = this.state.documents.map(document => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={document.id.toString()}
|
||||
style={styles.file}
|
||||
onPress={() => this.openDocument(document)}>
|
||||
{document.type === 'pdf' ? (
|
||||
<Icon name="file-pdf" color={'white'} size={60}/>
|
||||
) : (
|
||||
<Icon name="file-video" color={'white'} size={60}/>
|
||||
)}
|
||||
<Text style={styles.fileTxt}>{document.title}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View
|
||||
style={{width: 290, borderRightWidth: 1, borderColor: 'lightgrey'}}>
|
||||
<TreeView
|
||||
data={folder}
|
||||
leftImage={{}}
|
||||
rightImage={require('../assets/img/arrow_down.png')}
|
||||
containerStyle={styles.treeviewContainer}
|
||||
onClick={tmp => this.showDocuments(tmp)}
|
||||
/>
|
||||
</View>
|
||||
<ScrollView style={styles.scrollview}>
|
||||
<View style={styles.filesContainer}>{documentList}</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
treeviewContainer: {
|
||||
width: 290,
|
||||
},
|
||||
scrollview: {
|
||||
flex: 2,
|
||||
},
|
||||
filesContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
file: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: 200,
|
||||
width: 180,
|
||||
backgroundColor: '#ea4f52',
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
padding: 5
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(DirectoriesScreen);
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
import React from 'react';
|
||||
import { View, StyleSheet, ImageBackground, TouchableOpacity, Text, Image } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import NetInfo from '@react-native-community/netinfo';
|
||||
import Sync from '../Controllers/Sync';
|
||||
import * as SplashScreen from 'expo-splash-screen';
|
||||
import i18n from "../I18n";
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
directories: state.directories,
|
||||
locale: state.locale,
|
||||
};
|
||||
}
|
||||
|
||||
class HomeScreen extends React.Component {
|
||||
state = {
|
||||
lastSyncCall: '2020-02-12',
|
||||
};
|
||||
componentDidMount() {
|
||||
this.props.dispatch({ type: 'INIT' });
|
||||
SplashScreen.hideAsync();
|
||||
}
|
||||
|
||||
unsubscribe() {
|
||||
NetInfo.addEventListener(state => {
|
||||
if (state.isConnected === true) {
|
||||
let seconds =
|
||||
Math.abs(new Date(this.state.lastSyncCall) - Date.now()) / 1000;
|
||||
//console.log(seconds);
|
||||
if (seconds > 30) {
|
||||
this.setState({ lastSyncCall: Date.now() });
|
||||
Sync.needSync(this.openSync.bind(this));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openSync() {
|
||||
this.props.navigation.navigate('SyncScreen', { isInstalled: true });
|
||||
}
|
||||
|
||||
openFolder(folderID) {
|
||||
const folder = this.props.directories.filter(tmp => tmp.id === folderID);
|
||||
this.props.navigation.navigate('DirectoriesScreen', { folder: folder });
|
||||
}
|
||||
|
||||
render() {
|
||||
i18n.locale = this.props.locale;
|
||||
this.unsubscribe();
|
||||
return (
|
||||
<ImageBackground source={require('../assets/img/background.jpg')} style={{ width: '100%', height: '100%' }}>
|
||||
<View style={styles.container}>
|
||||
<TouchableOpacity onPress={() => this.openFolder(2)} style={styles.button}>
|
||||
<Image source={require('../assets/img/guillemets.png')} style={styles.btnImg} />
|
||||
<Text style={styles.btnTxt}>{i18n.t('home_s.1')}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => this.openFolder(3)} style={styles.button}>
|
||||
<Image source={require('../assets/img/guillemets.png')} style={styles.btnImg} />
|
||||
<Text style={styles.btnTxt}>{i18n.t('home_s.2')}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => this.props.navigation.navigate('OnlyVideosScreen')} style={styles.button}>
|
||||
<Image source={require('../assets/img/guillemets.png')} style={styles.btnImg} />
|
||||
<Text style={styles.btnTxt}>{i18n.t('global.videos')}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => this.props.navigation.navigate('ContactScreen')} style={styles.button}>
|
||||
<Image source={require('../assets/img/guillemets.png')} style={styles.btnImg} />
|
||||
<Text style={styles.btnTxt}>{i18n.t('global.contacts')}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ImageBackground>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
text: {
|
||||
height: 40,
|
||||
width: 300,
|
||||
borderColor: 'grey',
|
||||
borderWidth: 1,
|
||||
marginBottom: 20,
|
||||
},
|
||||
button: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'white',
|
||||
marginBottom: 20,
|
||||
marginRight: 50,
|
||||
width: 400,
|
||||
height: 80,
|
||||
borderRadius: 10
|
||||
},
|
||||
btnTxt: {
|
||||
fontSize: 20
|
||||
},
|
||||
btnImg: {
|
||||
position: 'absolute',
|
||||
left: 15,
|
||||
height: 50,
|
||||
width: 50,
|
||||
resizeMode: 'stretch'
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(HomeScreen);
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
import React from 'react';
|
||||
import { View, StyleSheet, TextInput, Button, Alert, ImageBackground, Image } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { verify } from 'react-native-b-crypt-bridge';
|
||||
import Sync from '../Controllers/Sync';
|
||||
import CommonModel from '../Models/Common';
|
||||
import * as SplashScreen from 'expo-splash-screen';
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
import i18n from "../I18n";
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
users: state.users,
|
||||
locale: state.locale,
|
||||
};
|
||||
}
|
||||
|
||||
class LoginScreen extends React.Component {
|
||||
state = {
|
||||
login: '',
|
||||
password: '',
|
||||
};
|
||||
|
||||
componentDidMount(): void {
|
||||
SplashScreen.hideAsync();
|
||||
}
|
||||
|
||||
login(login, password) {
|
||||
if (login !== '' && password !== '') {
|
||||
let user = this.props.users.filter(tmp => tmp.email === login);
|
||||
if (user.length > 0) {
|
||||
user = user[0];
|
||||
verify(
|
||||
password,
|
||||
user.password
|
||||
).then(verified => {
|
||||
if (verified === true) {
|
||||
// Si user === last user
|
||||
const lastUser = CommonModel.get('lastUser');
|
||||
if (lastUser !== false && lastUser !== undefined && lastUser.value === user.id.toString()) {
|
||||
this.loginAction(user);
|
||||
} else {
|
||||
// Si la tablette est synchronisée avec le serveur
|
||||
if (Sync.isSynced()) {
|
||||
// Si la tablette est connectée à internet pour forcer la synchro
|
||||
NetInfo.fetch().then(state => {
|
||||
if (state.isConnected) {
|
||||
this.loginAction(user, true);
|
||||
} else {
|
||||
Alert.alert(i18n.t('error.tablet_not_connected_internet'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Alert.alert(i18n.t('error.tablet_not_synced_last_user'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Alert.alert(i18n.t('error.incorrect_credentials'));
|
||||
}
|
||||
}).catch(error => console.log(error));
|
||||
} else {
|
||||
Alert.alert(i18n.t('error.incorrect_credentials'));
|
||||
}
|
||||
} else {
|
||||
Alert.alert(i18n.t('error.must_fill_login_fields'));
|
||||
}
|
||||
}
|
||||
|
||||
loginAction(user, forceSync = false) {
|
||||
this.setState({ login: '', password: '' });
|
||||
CommonModel.update({
|
||||
key: 'isLogged',
|
||||
value: JSON.stringify(user),
|
||||
});
|
||||
CommonModel.update({
|
||||
key: 'loggedTime',
|
||||
value: Date.now().toString(),
|
||||
});
|
||||
CommonModel.update({ key: 'lastUser', value: user.id.toString() });
|
||||
this.props.dispatch({
|
||||
type: 'SET_CURRENT_USER',
|
||||
data: JSON.stringify(user),
|
||||
});
|
||||
this.props.dispatch({ type: 'SET_LOGGED', data: true });
|
||||
if (forceSync === true) {
|
||||
this.props.navigation.navigate('SyncScreen', { isInstalled: true, forceSync: true });
|
||||
}
|
||||
}
|
||||
|
||||
renderInstallBtn() {
|
||||
if (!Sync.isInstalled()) {
|
||||
return (
|
||||
<View style={{ marginTop: 20 }}>
|
||||
<Button
|
||||
color={'#ea4f52'}
|
||||
title={i18n.t('login_s.install')}
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate('SyncScreen', { isInstalled: false })
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
i18n.locale = this.props.locale;
|
||||
return (
|
||||
<ImageBackground source={require('../assets/img/background.jpg')} style={{ width: '100%', height: '100%' }}>
|
||||
<View style={styles.container}>
|
||||
<Image source={require('../assets/img/logo-square.png')} style={{ width: 150, height: 150, marginBottom: 20 }} />
|
||||
{Sync.isInstalled() && (
|
||||
<View>
|
||||
<TextInput
|
||||
style={styles.text}
|
||||
placeholder={i18n.t('login_s.username')}
|
||||
value={this.state.login}
|
||||
onChangeText={text => this.setState({ login: text })}
|
||||
autoCapitalize={'none'}
|
||||
autoCorrect={false}
|
||||
keyboardType={'email-address'}
|
||||
/>
|
||||
<TextInput
|
||||
style={styles.text}
|
||||
placeholder={i18n.t('login_s.password')}
|
||||
value={this.state.password}
|
||||
onChangeText={text => this.setState({ password: text })}
|
||||
secureTextEntry={true}
|
||||
autoCapitalize={'none'}
|
||||
autoCorrect={false}
|
||||
/>
|
||||
<Button
|
||||
title={i18n.t('global.login')}
|
||||
onPress={() => this.login(this.state.login, this.state.password)}
|
||||
color={'#ea4f52'}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
{this.renderInstallBtn()}
|
||||
</View>
|
||||
</ImageBackground>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
text: {
|
||||
height: 40,
|
||||
width: 300,
|
||||
borderColor: 'grey',
|
||||
borderWidth: 1,
|
||||
marginBottom: 20,
|
||||
backgroundColor: 'white',
|
||||
paddingLeft: 10
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(LoginScreen);
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.documents,
|
||||
};
|
||||
}
|
||||
|
||||
class MySpaceScreen extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Mon Espace</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(MySpaceScreen);
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
import {connect} from 'react-redux';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.documents,
|
||||
};
|
||||
}
|
||||
|
||||
class OnlyVideosScreen extends React.Component {
|
||||
state = {
|
||||
documents: [],
|
||||
};
|
||||
|
||||
showDocuments() {
|
||||
const documents = this.props.documents.filter(tmp => tmp.type === 'mp4');
|
||||
this.setState({documents: documents});
|
||||
}
|
||||
|
||||
openDocument(document) {
|
||||
this.props.dispatch({type: 'SET_CURRENT_OPENED_DOC', data: document});
|
||||
this.props.navigation.navigate('VideoScreen', {uuid: document.uuid});
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this.showDocuments();
|
||||
}
|
||||
|
||||
render() {
|
||||
let documentList = this.state.documents.map(document => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={document.id.toString()}
|
||||
style={styles.file}
|
||||
onPress={() => this.openDocument(document)}>
|
||||
{document.type === 'pdf' ? (
|
||||
<Icon name="file-pdf" color={'white'} size={60}/>
|
||||
) : (
|
||||
<Icon name="file-video" color={'white'} size={60}/>
|
||||
)}
|
||||
<Text style={styles.fileTxt}>{document.title}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ScrollView style={styles.scrollview}>
|
||||
<View style={styles.filesContainer}>{documentList}</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
scrollview: {
|
||||
flex: 2,
|
||||
},
|
||||
filesContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
file: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: 200,
|
||||
width: 180,
|
||||
backgroundColor: '#ea4f52',
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
padding: 5
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(OnlyVideosScreen);
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
import React from 'react';
|
||||
import { View, StyleSheet, Dimensions } from 'react-native';
|
||||
|
||||
import Pdf from 'react-native-pdf';
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
|
||||
class PDFScreen extends React.Component {
|
||||
render() {
|
||||
const { uuid } = this.props.route.params;
|
||||
const source = {
|
||||
uri: FileSystem.documentDirectory + uuid + '.pdf',
|
||||
cache: false,
|
||||
};
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Pdf
|
||||
source={source}
|
||||
onLoadComplete={(numberOfPages, filePath) => {
|
||||
console.log(`number of pages: ${numberOfPages}`);
|
||||
}}
|
||||
onPageChanged={(page, numberOfPages) => {
|
||||
console.log(`current page: ${page}`);
|
||||
}}
|
||||
onError={error => {
|
||||
console.log(error);
|
||||
}}
|
||||
onPressLink={uri => {
|
||||
console.log(`Link presse: ${uri}`);
|
||||
}}
|
||||
style={styles.pdf}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
text: {
|
||||
height: 40,
|
||||
width: 300,
|
||||
borderColor: 'grey',
|
||||
borderWidth: 1,
|
||||
marginBottom: 20,
|
||||
},
|
||||
pdf: {
|
||||
flex: 1,
|
||||
width: Dimensions.get('window').width,
|
||||
height: Dimensions.get('window').height,
|
||||
},
|
||||
});
|
||||
|
||||
export default PDFScreen;
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
import {connect} from 'react-redux';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||
import Helpers from "../Controllers/Helpers";
|
||||
import i18n from "../I18n";
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.documents,
|
||||
};
|
||||
}
|
||||
|
||||
class SearchScreen extends React.Component {
|
||||
state = {
|
||||
documents: [],
|
||||
};
|
||||
|
||||
openDocument(document) {
|
||||
this.props.dispatch({type: 'SET_CURRENT_OPENED_DOC', data: document});
|
||||
if (document.type === 'pdf') {
|
||||
this.props.navigation.navigate('PDFScreen', {uuid: document.uuid});
|
||||
} else if (document.type === 'mp4') {
|
||||
this.props.navigation.navigate('VideoScreen', {uuid: document.uuid});
|
||||
} else {
|
||||
console.log('Inconnu');
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
const {needle, onlyVideos} = this.props.route.params;
|
||||
let objDocs = this.props.documents;
|
||||
let arrayDocs = Object.keys(objDocs).map(function (key) { return objDocs[key]; });
|
||||
let sorted = arrayDocs.sort(Helpers.compareValues('title', 'asc'));
|
||||
let filtered = sorted.filter(item => item.title.toLowerCase().indexOf(needle.toLowerCase()) >= 0);
|
||||
if (onlyVideos === true) {
|
||||
filtered = filtered.filter(item => item.type === 'mp4');
|
||||
}
|
||||
this.setState({
|
||||
documents: filtered,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let documentList = this.state.documents.map(document => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={document.id.toString()}
|
||||
style={styles.file}
|
||||
onPress={() => this.openDocument(document)}>
|
||||
{document.type === 'pdf' ? (
|
||||
<Icon name="file-pdf" color={'white'} size={60}/>
|
||||
) : (
|
||||
<Icon name="file-video" color={'white'} size={60}/>
|
||||
)}
|
||||
<Text style={styles.fileTxt}>{document.title}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ScrollView style={styles.scrollview}>
|
||||
<View style={styles.filesContainer}>{documentList}</View>
|
||||
{this.state.documents.length === 0 && (
|
||||
<Text style={{textAlign: 'center', marginTop: 50, fontSize: 30}}>{i18n.t('search_s.no_result')}</Text>
|
||||
)}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
scrollview: {
|
||||
flex: 2,
|
||||
},
|
||||
filesContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
file: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: 200,
|
||||
width: 180,
|
||||
backgroundColor: '#ea4f52',
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
padding: 5
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(SearchScreen);
|
||||