Merge branch 'staging'
This commit is contained in:
commit
185e884fa8
86 changed files with 19310 additions and 15248 deletions
21
.editorconfig
Normal file
21
.editorconfig
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.{vue,js}]
|
||||
indent_size = 2
|
||||
|
||||
[docker-compose.yml]
|
||||
indent_size = 4
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.vscode/*
|
||||
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
9
.idea/com-app.iml
generated
Normal file
9
.idea/com-app.iml
generated
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/com-app.iml" filepath="$PROJECT_DIR$/.idea/com-app.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
23
.vscode/settings.json
vendored
Normal file
23
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"workbench.colorCustomizations": {
|
||||
"activityBar.activeBackground": "#3e8040",
|
||||
"activityBar.activeBorder": "#ffffff",
|
||||
"activityBar.background": "#3e8040",
|
||||
"activityBar.foreground": "#e7e7e7",
|
||||
"activityBar.inactiveForeground": "#e7e7e799",
|
||||
"activityBarBadge.background": "#aaa9d5",
|
||||
"activityBarBadge.foreground": "#15202b",
|
||||
"sash.hoverBorder": "#3e8040",
|
||||
"statusBar.background": "#2d5e2f",
|
||||
"statusBar.foreground": "#e7e7e7",
|
||||
"statusBarItem.hoverBackground": "#3e8040",
|
||||
"statusBarItem.remoteBackground": "#2d5e2f",
|
||||
"statusBarItem.remoteForeground": "#e7e7e7",
|
||||
"titleBar.activeBackground": "#8d1800",
|
||||
"titleBar.activeForeground": "#e7e7e7",
|
||||
"titleBar.inactiveBackground": "#2d5e2f99",
|
||||
"titleBar.inactiveForeground": "#e7e7e799",
|
||||
"commandCenter.border": "#e7e7e799"
|
||||
},
|
||||
"peacock.remoteColor": "#2d5e2f"
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
module.exports = {
|
||||
arrowParens: 'avoid',
|
||||
bracketSameLine: true,
|
||||
bracketSpacing: false,
|
||||
bracketSpacing: true,
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,30 @@
|
|||
# 2.0.0
|
||||
## Bug
|
||||
# CHANGELOG
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Bug - 3.0.0
|
||||
|
||||
- Fix add contact from HomeScreen Error
|
||||
- Fixed appID was not properly setup `com.comapp.ldc`
|
||||
- Lint du Code, Ajout de définitions
|
||||
- L'ordre d'affichage des contacts est respecté
|
||||
- Tri des contact lors de l'envoi d'un contact
|
||||
|
||||
### Évolution - 3.0.0
|
||||
|
||||
- Ajout d'une synchronisation users discrete on Login (pour sync les news users apres que l'app ai déjà été installé)
|
||||
- Changed les Formulaires sont dynamiques
|
||||
- La synchro utilise 3 méthodes pour les contacts
|
||||
- Ajout de timestamp sur contact pour définir le contact le plus a jour a conserver (pour un utilisateur)
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Bug - 2.0.0
|
||||
|
||||
- Fix format vidéo lors de la rotation de l'écran
|
||||
## Évolution
|
||||
|
||||
### Évolution - 2.0.0
|
||||
|
||||
- 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.
|
||||
|
|
@ -11,4 +34,4 @@
|
|||
- 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.
|
||||
- Ajout d'un espace plus important entre les éléments cliquables du header + ajout d'un menu en overlay.
|
||||
|
|
|
|||
|
|
@ -25,4 +25,8 @@
|
|||
- react-native-blob-util
|
||||
- react-native-flash-message
|
||||
- @react-native-picker/picker
|
||||
- vcard-parser
|
||||
- vcard-parser
|
||||
- react-native-email-link
|
||||
- buffer
|
||||
- react-native-sectioned-multi-select
|
||||
- react-native-uuid
|
||||
|
|
|
|||
|
|
@ -35,12 +35,12 @@ android_library(
|
|||
|
||||
android_build_config(
|
||||
name = "build_config",
|
||||
package = "com.comapp",
|
||||
package = "com.comapp.ldc",
|
||||
)
|
||||
|
||||
android_resource(
|
||||
name = "res",
|
||||
package = "com.comapp",
|
||||
package = "com.comapp.ldc",
|
||||
res = "src/main/res",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ android {
|
|||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "2.0.0"
|
||||
versionName "3.0.0"
|
||||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
||||
|
||||
if (isNewArchitectureEnabled()) {
|
||||
|
|
@ -329,4 +329,4 @@ def isNewArchitectureEnabled() {
|
|||
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
|
||||
}
|
||||
|
||||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
||||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||
* directory of this source tree.
|
||||
*/
|
||||
package com.comapp;
|
||||
package com.comapp.ldc;
|
||||
|
||||
import android.content.Context;
|
||||
import com.facebook.flipper.android.AndroidFlipperClient;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.comapp">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.comapp.ldc">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<application
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.comapp;
|
||||
package com.comapp.ldc;
|
||||
|
||||
import expo.modules.ReactActivityDelegateWrapper;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.comapp;
|
||||
package com.comapp.ldc;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import expo.modules.ApplicationLifecycleDispatcher;
|
||||
|
|
@ -13,7 +13,7 @@ import com.facebook.react.ReactNativeHost;
|
|||
import com.facebook.react.ReactPackage;
|
||||
import com.facebook.react.config.ReactFeatureFlags;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
import com.comapp.newarchitecture.MainApplicationReactNativeHost;
|
||||
import com.comapp.ldc.newarchitecture.MainApplicationReactNativeHost;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ public class MainApplication extends Application implements ReactApplication {
|
|||
We use reflection here to pick up the class that initializes Flipper,
|
||||
since Flipper library is not available in release mode
|
||||
*/
|
||||
Class<?> aClass = Class.forName("com.comapp.ReactNativeFlipper");
|
||||
Class<?> aClass = Class.forName("com.comapp.ldc.ReactNativeFlipper");
|
||||
aClass
|
||||
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
|
||||
.invoke(null, context, reactInstanceManager);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.comapp.newarchitecture;
|
||||
package com.comapp.ldc.newarchitecture;
|
||||
|
||||
import android.app.Application;
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -19,9 +19,9 @@ import com.facebook.react.fabric.CoreComponentsRegistry;
|
|||
import com.facebook.react.fabric.FabricJSIModuleProvider;
|
||||
import com.facebook.react.fabric.ReactNativeConfig;
|
||||
import com.facebook.react.uimanager.ViewManagerRegistry;
|
||||
import com.comapp.BuildConfig;
|
||||
import com.comapp.newarchitecture.components.MainComponentsRegistry;
|
||||
import com.comapp.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
|
||||
import com.comapp.ldc.BuildConfig;
|
||||
import com.comapp.ldc.newarchitecture.components.MainComponentsRegistry;
|
||||
import com.comapp.ldc.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.comapp.newarchitecture.components;
|
||||
package com.comapp.ldc.newarchitecture.components;
|
||||
|
||||
import com.facebook.jni.HybridData;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.comapp.newarchitecture.modules;
|
||||
package com.comapp.ldc.newarchitecture.modules;
|
||||
|
||||
import com.facebook.jni.HybridData;
|
||||
import com.facebook.react.ReactPackage;
|
||||
|
|
|
|||
|
|
@ -41,5 +41,5 @@ newArchEnabled=false
|
|||
|
||||
MYAPP_UPLOAD_STORE_FILE=upload.keystore
|
||||
MYAPP_UPLOAD_KEY_ALIAS=app-native-1
|
||||
MYAPP_UPLOAD_STORE_PASSWORD=9LjCAts7qtetVqMT
|
||||
MYAPP_UPLOAD_KEY_PASSWORD=9LjCAts7qtetVqMT
|
||||
MYAPP_UPLOAD_STORE_PASSWORD=
|
||||
MYAPP_UPLOAD_KEY_PASSWORD=
|
||||
|
|
|
|||
796
ComApp/package-lock.json
generated
796
ComApp/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -11,16 +11,17 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@react-native-community/netinfo": "^9.3.7",
|
||||
"@react-native-community/slider": "^4.3.2",
|
||||
"@react-native-community/slider": "4.2.4",
|
||||
"@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",
|
||||
"@rneui/base": "^4.0.0-rc.7",
|
||||
"@rneui/themed": "^4.0.0-rc.7",
|
||||
"@sentry/react-native": "^4.12.0",
|
||||
"axios": "^0.27.2",
|
||||
"buffer": "^6.0.3",
|
||||
"expo": "^47.0.10",
|
||||
"expo-av": "^13.0.2",
|
||||
"expo-av": "~13.0.3",
|
||||
"expo-barcode-scanner": "^11.4.0",
|
||||
"expo-splash-screen": "^0.16.2",
|
||||
"expo-video-player": "^2.2.0",
|
||||
|
|
@ -33,13 +34,16 @@
|
|||
"react-native-animated-tree-view": "^0.1.4",
|
||||
"react-native-b-crypt-bridge": "file:react-native-b-crypt-bridge-2.1.0.tgz",
|
||||
"react-native-blob-util": "^0.16.2",
|
||||
"react-native-email-link": "^1.14.6",
|
||||
"react-native-flash-message": "^0.3.1",
|
||||
"react-native-gesture-handler": "^2.7.0",
|
||||
"react-native-pdf": "^6.6.2",
|
||||
"react-native-progress": "^5.0.0",
|
||||
"react-native-safe-area-context": "^4.4.1",
|
||||
"react-native-screens": "^3.18.0",
|
||||
"react-native-sectioned-multi-select": "^0.10.0",
|
||||
"react-native-svg": "^13.2.0",
|
||||
"react-native-uuid": "^2.0.1",
|
||||
"react-native-vector-icons": "^9.2.0",
|
||||
"react-redux": "^8.0.4",
|
||||
"realm": "^11.0.0-rc.2",
|
||||
|
|
|
|||
|
|
@ -1,49 +1,59 @@
|
|||
import React from 'react';
|
||||
// Sentry
|
||||
import * as Sentry from "@sentry/react-native";
|
||||
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';
|
||||
import { store } from './App/Store/ConfigureStore';
|
||||
// Deps
|
||||
import 'react-native-gesture-handler';
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||
import { 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 {
|
||||
Alert,
|
||||
Button,
|
||||
DrawerLayoutAndroid,
|
||||
Image,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import FlashMessage, { showMessage } from 'react-native-flash-message';
|
||||
import 'react-native-gesture-handler';
|
||||
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||
import { navigate, navigationRef } from './Navigation';
|
||||
// Application infos
|
||||
import * as Application from 'expo-application';
|
||||
// i18n
|
||||
import i18n from "./I18n";
|
||||
import i18n from './I18n';
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
// Views
|
||||
import ContactDetailsScreen from './App/Views/ContactDetailsScreen';
|
||||
import ContactScreen from './App/Views/ContactScreen';
|
||||
import DirectoriesScreen from './App/Views/DirectoriesScreen';
|
||||
import HomeScreen from './App/Views/HomeScreen';
|
||||
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';
|
||||
import OnlyVideosScreen from './App/Views/OnlyVideosScreen';
|
||||
import PDFScreen from './App/Views/PDFScreen';
|
||||
import SearchScreen from './App/Views/SearchScreen';
|
||||
import SyncScreen from './App/Views/SyncScreen';
|
||||
import VideoScreen from './App/Views/VideoScreen';
|
||||
// Style
|
||||
import Helpers from './App/Lib/Helpers';
|
||||
import styles from './Resources/Styles/NavigationStyle';
|
||||
// Controllers
|
||||
import SyncController from './App/Controllers/SyncController';
|
||||
|
||||
Sentry.init({
|
||||
dsn: "https://ab87e8d840324f41873c95b06903b0bf@o4504314935640064.ingest.sentry.io/4504441255886848",
|
||||
dsn: 'https://ab87e8d840324f41873c95b06903b0bf@o4504314935640064.ingest.sentry.io/4504441255886848',
|
||||
});
|
||||
|
||||
Sentry.setContext("app", {
|
||||
boUrl: SyncController.getUrlBo()
|
||||
Sentry.setContext('app', {
|
||||
boUrl: SyncController.getUrlBo(),
|
||||
});
|
||||
|
||||
SplashScreen.preventAutoHideAsync(); //Keep
|
||||
|
|
@ -61,7 +71,7 @@ class App extends React.Component {
|
|||
searchTxt: '',
|
||||
sendEmail: '',
|
||||
mainColor: '',
|
||||
drawerRef: React.createRef()
|
||||
drawerRef: React.createRef(),
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
|
|
@ -69,7 +79,7 @@ class App extends React.Component {
|
|||
this.setState({
|
||||
isSetup: store.getState().app.isSetup,
|
||||
isLogged: store.getState().app.logged,
|
||||
mainColor: store.getState().app.mainColor
|
||||
mainColor: store.getState().app.mainColor,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -77,9 +87,8 @@ class App extends React.Component {
|
|||
this.setState({
|
||||
isSetup: store.getState().app.isSetup,
|
||||
isLogged: store.getState().app.logged,
|
||||
mainColor: store.getState().app.mainColor
|
||||
mainColor: store.getState().app.mainColor,
|
||||
}); // to force re-rendering
|
||||
console.log("state changed")
|
||||
}
|
||||
|
||||
navigationView = () => (
|
||||
|
|
@ -89,16 +98,23 @@ class App extends React.Component {
|
|||
onPress={() => {
|
||||
this.state.drawerRef.current.closeDrawer();
|
||||
store.dispatch({ type: 'EDIT_LOCALE' });
|
||||
store.dispatch(initDocuments(store.getState().locale.locale, store.getState().directories.global))
|
||||
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>
|
||||
<Text style={styles.drawer.btnText}>
|
||||
{i18n.t('global.change_lang')}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.state.drawerRef.current.closeDrawer();
|
||||
navigate('SyncScreen')
|
||||
navigate('SyncScreen');
|
||||
}}
|
||||
style={styles.drawer.btn}>
|
||||
<Icon name="sync-alt" size={20} />
|
||||
|
|
@ -115,7 +131,9 @@ class App extends React.Component {
|
|||
</TouchableOpacity>
|
||||
</View>
|
||||
<View>
|
||||
<Text style={{ marginBottom: 10 }}>Version : {Application.nativeApplicationVersion}</Text>
|
||||
<Text style={{ marginBottom: 10 }}>
|
||||
Version : {Application.nativeApplicationVersion}
|
||||
</Text>
|
||||
<Button
|
||||
title={i18n.t('global.close')}
|
||||
color={this.state.mainColor}
|
||||
|
|
@ -132,202 +150,260 @@ class App extends React.Component {
|
|||
<DrawerLayoutAndroid
|
||||
ref={this.state.drawerRef}
|
||||
drawerWidth={300}
|
||||
drawerPosition={"right"}
|
||||
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>
|
||||
),
|
||||
})}
|
||||
/>
|
||||
) : (
|
||||
renderNavigationView={this.navigationView}>
|
||||
<Stack.Navigator initialRouteName="HomeScreen">
|
||||
{this.state.isSetup === false && (
|
||||
<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 })}
|
||||
/>
|
||||
name="InstallScreen"
|
||||
component={InstallScreen}
|
||||
options={(navigation, route) => ({
|
||||
headerTitle: () =>
|
||||
this.LogoTitle(
|
||||
navigation,
|
||||
i18n.t('install.installation'),
|
||||
false,
|
||||
),
|
||||
headerRight: () => (
|
||||
<View
|
||||
style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<TouchableOpacity
|
||||
style={{ ...styles.btnSearch, backgroundColor: this.state.mainColor }}
|
||||
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: false,
|
||||
onlyVideos: true,
|
||||
});
|
||||
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} />
|
||||
<Icon name={'search'} size={20} color={'white'} />
|
||||
</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>
|
||||
/>
|
||||
<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>
|
||||
|
|
@ -338,20 +414,23 @@ class App extends React.Component {
|
|||
LogoTitle(navigation, title, wantBtn = true) {
|
||||
return (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
<TouchableOpacity onPress={() => {
|
||||
if (wantBtn) {
|
||||
navigation.navigation.navigate('HomeScreen')
|
||||
}
|
||||
}}>
|
||||
<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' }}
|
||||
source={{
|
||||
uri: FileSystem.documentDirectory + 'RectangleLogo.png',
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
style={{ width: 100, height: 50, resizeMode: 'stretch' }}
|
||||
source={require('./Resources/assets/img/logo.png')}
|
||||
source={require('./Resources/assets/img/logo.png')}
|
||||
/>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
|
@ -362,35 +441,47 @@ class App extends React.Component {
|
|||
|
||||
SendEmail() {
|
||||
return (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', marginRight: 10 }}>
|
||||
<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 = {
|
||||
email: this.state.sendEmail,
|
||||
subject: i18n.t('app.file_sharing'),
|
||||
message: '',
|
||||
documents: JSON.stringify([store.getState().currentOpenedDoc]),
|
||||
user_id: store.getState().currentUser.id
|
||||
};
|
||||
store.dispatch({ type: 'SEND_BROCHURE', data: email });
|
||||
showMessage({
|
||||
message: i18n.t('global.message_sent') + '.',
|
||||
description: i18n.t('global.message_will_be_sent_after_sync') + '.',
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
});
|
||||
this.setState({ sendEmail: '' });
|
||||
} else {
|
||||
Alert.alert(i18n.t('global.warning') + ' !', i18n.t('error.invalid_email_address') + '.', [
|
||||
{ text: 'OK' },
|
||||
],
|
||||
{ cancelable: false },
|
||||
);
|
||||
<View
|
||||
style={{ flexDirection: 'row', alignItems: 'center', marginRight: 10 }}>
|
||||
<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 = {
|
||||
email: this.state.sendEmail,
|
||||
subject: i18n.t('app.file_sharing'),
|
||||
message: '',
|
||||
documents: JSON.stringify([
|
||||
store.getState().app.currentOpenedDoc,
|
||||
]),
|
||||
app_user_id: store.getState().app.currentUser.id,
|
||||
};
|
||||
store.dispatch({ type: 'SEND_BROCHURE', data: email });
|
||||
showMessage({
|
||||
message: i18n.t('global.message_sent') + '.',
|
||||
description:
|
||||
i18n.t('global.message_will_be_sent_after_sync') + '.',
|
||||
type: 'success',
|
||||
duration: 1500,
|
||||
});
|
||||
this.setState({ sendEmail: '' });
|
||||
} else {
|
||||
Alert.alert(
|
||||
i18n.t('global.warning') + ' !',
|
||||
i18n.t('error.invalid_email_address') + '.',
|
||||
[{ text: 'OK' }],
|
||||
{ cancelable: false },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}}>
|
||||
}}>
|
||||
<Icon name={'paper-plane'} size={20} color={'white'} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
|
@ -400,22 +491,21 @@ class App extends React.Component {
|
|||
renderFlag() {
|
||||
let flag;
|
||||
switch (store.getState().locale.locale) {
|
||||
case "fr":
|
||||
case 'fr':
|
||||
flag = require('./assets/img/flags/fr.png');
|
||||
break;
|
||||
case "en":
|
||||
case 'en':
|
||||
flag = require('./assets/img/flags/en.png');
|
||||
break;
|
||||
case "de":
|
||||
case 'de':
|
||||
flag = require('./assets/img/flags/de.png');
|
||||
break;
|
||||
case "es":
|
||||
case 'es':
|
||||
flag = require('./assets/img/flags/es.png');
|
||||
break;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Sentry.wrap(App);
|
||||
|
|
|
|||
|
|
@ -1,63 +1,72 @@
|
|||
import { Alert } from "react-native";
|
||||
import { Alert } from 'react-native';
|
||||
// Lodash
|
||||
import _ from 'lodash';
|
||||
// Http Client
|
||||
import axios from 'axios';
|
||||
// Network Infos
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
import NetInfo from '@react-native-community/netinfo';
|
||||
// Translations
|
||||
import i18n from "../../I18n";
|
||||
import i18n from '../../I18n';
|
||||
// Database
|
||||
import { Setting } from "../../Database";
|
||||
import { Setting } from '../../Database';
|
||||
|
||||
const api_token = 'G9Q62jt8eL8gN4Ls';
|
||||
class InstallController {
|
||||
async getConfig(url) {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: url + '/api/settings',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getConfig(url) {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: url + '/api/settings',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getAppConfig(url) {
|
||||
NetInfo.fetch().then(state => {
|
||||
if (state.isConnected) {
|
||||
axios({
|
||||
method: 'GET',
|
||||
url: url + '/api/app',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token
|
||||
},
|
||||
})
|
||||
.then(function (response) {
|
||||
if (response.data) {
|
||||
if (response.data.status === "OK") {
|
||||
Setting.upsert({ key: 'HomeFolders', value: JSON.stringify(response.data.datas.folders) });
|
||||
} 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"));
|
||||
getAppConfig(url) {
|
||||
NetInfo.fetch().then(state => {
|
||||
if (state.isConnected) {
|
||||
axios({
|
||||
method: 'GET',
|
||||
url: url + '/api/app',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
})
|
||||
.then(function (response) {
|
||||
if (response.data) {
|
||||
if (response.data.status === 'OK') {
|
||||
Setting.upsert({
|
||||
key: 'HomeFolders',
|
||||
value: JSON.stringify(response.data.datas.folders),
|
||||
});
|
||||
} else {
|
||||
Alert.alert(
|
||||
i18n.t('alert.error'),
|
||||
i18n.t('error.error_has_occurred'),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(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;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default new InstallController();
|
||||
export default new InstallController();
|
||||
|
|
|
|||
|
|
@ -1,28 +1,24 @@
|
|||
// Database
|
||||
import { Setting } from "../../Database";
|
||||
import { Setting } from '../../Database';
|
||||
// BCrypt
|
||||
import { verify } from 'react-native-b-crypt-bridge';
|
||||
|
||||
class LoginController {
|
||||
async verify(user, password) {
|
||||
return await verify(password, user.password);
|
||||
}
|
||||
|
||||
verify(user, password) {
|
||||
return verify(
|
||||
password,
|
||||
user.password
|
||||
);
|
||||
}
|
||||
|
||||
login(user) {
|
||||
Setting.upsert({
|
||||
key: 'isLogged',
|
||||
value: JSON.stringify(user),
|
||||
});
|
||||
Setting.upsert({
|
||||
key: 'loggedTime',
|
||||
value: Date.now().toString(),
|
||||
});
|
||||
Setting.upsert({ key: 'lastUser', value: user.id.toString() });
|
||||
}
|
||||
login(user) {
|
||||
Setting.upsert({
|
||||
key: 'isLogged',
|
||||
value: JSON.stringify(user),
|
||||
});
|
||||
Setting.upsert({
|
||||
key: 'loggedTime',
|
||||
value: Date.now().toString(),
|
||||
});
|
||||
Setting.upsert({ key: 'lastUser', value: user.id.toString() });
|
||||
}
|
||||
}
|
||||
|
||||
export default new LoginController();
|
||||
export default new LoginController();
|
||||
|
|
|
|||
|
|
@ -1,213 +1,277 @@
|
|||
// Lodash
|
||||
import _ from 'lodash';
|
||||
// Http Client
|
||||
import axios from 'axios';
|
||||
// Network Infos
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
import NetInfo from '@react-native-community/netinfo';
|
||||
// Application infos
|
||||
import * as Application from 'expo-application';
|
||||
// Database
|
||||
import { Setting, Contact, SendBrochure, Document } from '../../Database';
|
||||
// Database
|
||||
import { Contact, Document, SendBrochure, Setting } from '../../Database';
|
||||
import { ContactData } from '../Models/Contact';
|
||||
|
||||
const api_token = 'G9Q62jt8eL8gN4Ls';
|
||||
|
||||
class SyncController {
|
||||
|
||||
getUrlBo() {
|
||||
const test = Setting.get('bo_url');
|
||||
if (test === false || test === undefined) {
|
||||
return "noset";
|
||||
}
|
||||
return test.value;
|
||||
getUrlBo() {
|
||||
const test = Setting.get('bo_url');
|
||||
if (test === null) {
|
||||
return 'noset';
|
||||
}
|
||||
return test.value;
|
||||
}
|
||||
|
||||
getAppStoreUUID() {
|
||||
const test = Setting.get('AppStoreUUID');
|
||||
if (test === false || test === undefined) {
|
||||
return "noset";
|
||||
}
|
||||
return test.value;
|
||||
getAppStoreUUID() {
|
||||
const test = Setting.get('AppStoreUUID');
|
||||
if (test === null) {
|
||||
return 'noset';
|
||||
}
|
||||
return test.value;
|
||||
}
|
||||
|
||||
async checkConnection() {
|
||||
return NetInfo.fetch();
|
||||
async checkConnection() {
|
||||
return NetInfo.fetch();
|
||||
}
|
||||
|
||||
async getVersion() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * version
|
||||
url: this.getUrlBo() + '/api/version',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
app_uuid: this.getAppStoreUUID(),
|
||||
app_version: Application.nativeApplicationVersion,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getUsers() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * users.index
|
||||
url: this.getUrlBo() + '/api/users',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} app_user_id
|
||||
*/
|
||||
async getContacts(app_user_id) {
|
||||
// * We retrieve all contacts avec upsert and destroy
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * contacts.index
|
||||
url: this.getUrlBo() + `/api/contacts/${app_user_id}`,
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} app_user_id
|
||||
*/
|
||||
async upsertContacts(app_user_id) {
|
||||
const contacts = Contact.getAll(app_user_id).map(contact => {
|
||||
// * This casts contact to a simple Object
|
||||
// * Realm object does not support changing prop type
|
||||
/** @type {ContactData} */
|
||||
contact = contact.toJSON();
|
||||
// * Convert to UTC timestamp
|
||||
contact.timestamp = contact.timestamp.toUTCString();
|
||||
|
||||
// * Unstringify complex Fields
|
||||
contact.data = JSON.parse(contact.data);
|
||||
contact.visits = JSON.parse(contact.visits);
|
||||
return contact;
|
||||
});
|
||||
return axios({
|
||||
method: 'POST',
|
||||
// * contacts.index
|
||||
url: this.getUrlBo() + `/api/contacts/${app_user_id}`,
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
data: {
|
||||
contacts: contacts,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} app_user_id
|
||||
*/
|
||||
async deleteContacts(app_user_id) {
|
||||
const contactsToDelete = Contact.getAllToDelete(app_user_id);
|
||||
return axios({
|
||||
method: 'DELETE',
|
||||
// * contacts.index
|
||||
url: this.getUrlBo() + `/api/contacts/${app_user_id}`,
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
data: {
|
||||
contactUuidList: contactsToDelete.map(contact => contact.id),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async sendBrochure(brochure) {
|
||||
return axios({
|
||||
method: 'POST',
|
||||
// * send-flyers
|
||||
url: this.getUrlBo() + '/api/sendBrochure',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
emails: brochure,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getDirectories() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * directories.index
|
||||
url: this.getUrlBo() + '/api/directories',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getDocuments() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * documents.index
|
||||
url: this.getUrlBo() + '/api/documents',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getFormularies() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * formularies.index
|
||||
url: this.getUrlBo() + '/api/formularies',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
updateLastModificationDoc(id, date) {
|
||||
Document.update({ id: id, updated_at: date.toString() }, true);
|
||||
}
|
||||
|
||||
updateVersion(version) {
|
||||
const localVersion = Setting.get('version');
|
||||
if (localVersion === null) {
|
||||
Setting.add({ key: 'version', value: version });
|
||||
} else {
|
||||
Setting.update({ id: localVersion.id, key: 'version', value: version });
|
||||
}
|
||||
}
|
||||
|
||||
async getVersion() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: this.getUrlBo() + '/api/version',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
app_uuid: this.getAppStoreUUID(),
|
||||
app_version: Application.nativeApplicationVersion
|
||||
},
|
||||
});
|
||||
updateShowIsActive(value) {
|
||||
const local = Setting.get('ShowIsActive');
|
||||
if (local === null) {
|
||||
Setting.add({ key: 'ShowIsActive', value: value });
|
||||
} else {
|
||||
Setting.update({ id: local.id, key: 'ShowIsActive', value: value });
|
||||
}
|
||||
}
|
||||
|
||||
async getUsers() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: this.getUrlBo() + '/api/users',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @param {number} app_user_id
|
||||
* @returns
|
||||
*/
|
||||
isSynced(app_user_id) {
|
||||
const brochures = SendBrochure.getAll();
|
||||
const Contacts = Contact.getAll(app_user_id);
|
||||
|
||||
async getContacts(userId) {
|
||||
let contacts = Contact.getAll();
|
||||
return axios({
|
||||
method: 'POST',
|
||||
url: this.getUrlBo() + '/api/contacts',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token
|
||||
},
|
||||
data: {
|
||||
contacts: contacts,
|
||||
userId: userId,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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: this.getUrlBo() + '/api/directories',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getDocuments() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: this.getUrlBo() + '/api/documents',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
updateLastModificationDoc(id, date) {
|
||||
Document.update({ id: id, updated_at: date.toString() }, true);
|
||||
}
|
||||
|
||||
updateVersion(version) {
|
||||
const localVersion = Setting.get('version');
|
||||
if (localVersion === false || localVersion === undefined) {
|
||||
Setting.add({ key: 'version', value: version });
|
||||
} else {
|
||||
Setting.update({ id: localVersion.id, key: 'version', value: version });
|
||||
}
|
||||
}
|
||||
|
||||
updateShowIsActive(value) {
|
||||
const local = Setting.get('ShowIsActive');
|
||||
if (local === false || local === undefined) {
|
||||
Setting.add({ key: 'ShowIsActive', value: value });
|
||||
} else {
|
||||
Setting.update({ id: local.id, key: 'ShowIsActive', value: value });
|
||||
}
|
||||
}
|
||||
|
||||
isSynced() {
|
||||
const brochures = SendBrochure.getAll();
|
||||
const Contacts = Contact.getAll();
|
||||
|
||||
if (brochures !== undefined && Contacts !== undefined) {
|
||||
const noSynced = Contacts.filtered('synced = false');
|
||||
if (brochures.length > 0 || noSynced.length > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
isLogged() {
|
||||
const logged = Setting.get('isLogged');
|
||||
const loggedTime = Setting.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;
|
||||
}
|
||||
if (brochures !== undefined && Contacts !== undefined) {
|
||||
const noSynced = Contacts.filtered('synced = false');
|
||||
if (brochures.length > 0 || noSynced.length > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
isLogged() {
|
||||
const logged = Setting.get('isLogged');
|
||||
const loggedTime = Setting.get('loggedTime');
|
||||
if (logged !== null && loggedTime !== null) {
|
||||
let seconds =
|
||||
Math.abs(new Date(Number(loggedTime.value)) - Date.now()) / 1000;
|
||||
if (seconds < 14400) {
|
||||
// 4h
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
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 === null ||
|
||||
localVersion.value !== response.data.version
|
||||
) {
|
||||
return callback();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
setInstalled(remove = false) {
|
||||
if (remove) {
|
||||
Setting.delete('installed');
|
||||
} else {
|
||||
Setting.add({ key: 'installed', value: "true" });
|
||||
}
|
||||
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;
|
||||
isInstalled() {
|
||||
const test = Setting.get('installed');
|
||||
if (test === null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default new SyncController();
|
||||
export default new SyncController();
|
||||
|
|
|
|||
17
ComApp/src/App/Enums/InputStatus.js
Normal file
17
ComApp/src/App/Enums/InputStatus.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/** InputStatusEnum */
|
||||
|
||||
/**
|
||||
* @typedef {keyof InputStatusKeys} InputStatus
|
||||
*/
|
||||
export const InputStatus = {
|
||||
SYSTEM: 1,
|
||||
LOCKED: 2,
|
||||
DEFAULT: 3,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const InputStatusKeys = {
|
||||
1: 'SYSTEM',
|
||||
2: 'LOCKED',
|
||||
3: 'DEFAULT',
|
||||
};
|
||||
25
ComApp/src/App/Enums/InputType.js
Normal file
25
ComApp/src/App/Enums/InputType.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/** InputTypeEnum */
|
||||
|
||||
/**
|
||||
* @typedef {keyof InputTypeKeys} InputType
|
||||
*/
|
||||
export const InputType = {
|
||||
TEXT: 1,
|
||||
EMAIL: 2,
|
||||
PHONE: 3,
|
||||
RADIO: 4,
|
||||
SELECT: 5,
|
||||
SELECT_MULTIPLE: 6,
|
||||
CHECKBOX: 7,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const InputTypeKeys = {
|
||||
1: 'TEXT',
|
||||
2: 'EMAIL',
|
||||
3: 'PHONE',
|
||||
4: 'RADIO',
|
||||
5: 'SELECT',
|
||||
6: 'SELECT_MULTIPLE',
|
||||
7: 'CHECKBOX',
|
||||
};
|
||||
|
|
@ -1,50 +1,78 @@
|
|||
class Helpers {
|
||||
compareValues(key, order = 'asc') {
|
||||
return function innerSort(a, b) {
|
||||
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')
|
||||
? 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());
|
||||
}
|
||||
|
||||
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.toLowerCase());
|
||||
}
|
||||
|
||||
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();
|
||||
class Helpers {
|
||||
compareValues(key, order = 'asc') {
|
||||
return function innerSort(a, b) {
|
||||
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' ? 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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test url is valid
|
||||
* @param {string} value Url to test.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isUrlValid(value) {
|
||||
const re_weburl = new RegExp(
|
||||
'^' +
|
||||
// protocol identifier (optional)
|
||||
// short syntax // still required
|
||||
'(?:(?:(?:https?|ftp):)?\\/\\/)' +
|
||||
// user:pass BasicAuth (optional)
|
||||
'(?:\\S+(?::\\S*)?@)?' +
|
||||
'(?:' +
|
||||
// IP address exclusion
|
||||
// private & local networks
|
||||
'(?!(?: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})' +
|
||||
// IP address dotted notation octets
|
||||
// excludes loopback network 0.0.0.0
|
||||
// excludes reserved space >= 224.0.0.0
|
||||
// excludes network & broadcast addresses
|
||||
// (first & last IP address of each class)
|
||||
'(?:[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]))' +
|
||||
'|' +
|
||||
// host & domain names, may end with dot
|
||||
// can be replaced by a shortest alternative
|
||||
// (?![-_])(?:[-\\w\\u00a1-\\uffff]{0,63}[^-_]\\.)+
|
||||
'(?:' +
|
||||
'(?:' +
|
||||
'[a-z0-9\\u00a1-\\uffff]' +
|
||||
'[a-z0-9\\u00a1-\\uffff_-]{0,62}' +
|
||||
')?' +
|
||||
'[a-z0-9\\u00a1-\\uffff]\\.' +
|
||||
')+' +
|
||||
// TLD identifier name, may end with dot
|
||||
'(?:[a-z\\u00a1-\\uffff]{2,}\\.?)' +
|
||||
')' +
|
||||
// port number (optional)
|
||||
'(?::\\d{2,5})?' +
|
||||
// resource path (optional)
|
||||
'(?:[/?#]\\S*)?' +
|
||||
'$',
|
||||
'i',
|
||||
);
|
||||
return re_weburl.test(value.toLowerCase());
|
||||
}
|
||||
}
|
||||
export default new Helpers();
|
||||
|
|
|
|||
|
|
@ -1,107 +1,195 @@
|
|||
import { default as UuidGenerator } from 'react-native-uuid';
|
||||
import { UpdateMode } from 'realm';
|
||||
import { InputType } from './../Enums/InputType';
|
||||
|
||||
/**
|
||||
* @typedef {typeof ContactData} ContactData
|
||||
*/
|
||||
export const ContactData = {
|
||||
/** @type {string|undefined} */
|
||||
id: undefined,
|
||||
/** @type {string} */
|
||||
email: undefined,
|
||||
/** @type {string|null} */
|
||||
lastname: null,
|
||||
/** @type {string|null} */
|
||||
firstname: null,
|
||||
/** @type {string|null} */
|
||||
phone: null,
|
||||
/** @type {Array<InputDataType>} */
|
||||
data: [],
|
||||
/** @type {string|null} */
|
||||
notes: null,
|
||||
/** @type {Array<Record<string,string>>|null} */
|
||||
visits: null,
|
||||
/** @type {Date} */
|
||||
timestamp: null,
|
||||
/** @type {number} The app user id */
|
||||
app_user_id: undefined,
|
||||
/** @type {number|null} The app user id that should receive this contact on sync */
|
||||
send_to_app_user_id: null,
|
||||
/** @type {boolean} If this model is to delete */
|
||||
to_delete: false,
|
||||
/** @type {boolean} This model need sync */
|
||||
synced: true,
|
||||
};
|
||||
|
||||
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 },
|
||||
...ContactData,
|
||||
...{
|
||||
id: 'string',
|
||||
email: 'string',
|
||||
lastname: { type: 'string', optional: true },
|
||||
firstname: { type: 'string', optional: true },
|
||||
phone: { type: 'string', optional: true },
|
||||
/** Json encoded string of ContactData.data */
|
||||
data: { type: 'string', default: '[]' },
|
||||
notes: { type: 'string', optional: true },
|
||||
/** Json encoded string of ContactData.visists */
|
||||
visits: { type: 'string', default: '[]' },
|
||||
timestamp: 'date',
|
||||
send_to_app_user_id: { type: 'int', optional: true, default: null },
|
||||
app_user_id: 'int',
|
||||
to_delete: { type: 'bool', default: false },
|
||||
synced: { type: 'bool', default: true },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {typeof InputData} InputDataType
|
||||
*/
|
||||
export const InputData = {
|
||||
title: '',
|
||||
formSlug: '',
|
||||
/** @type {import('./../Enums/InputType').InputType} */
|
||||
type: InputType.TEXT,
|
||||
/** @type {string|Array<number,string>} */
|
||||
value: '',
|
||||
required: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof ContactData> & import('realm').Object} Contact
|
||||
*/
|
||||
|
||||
class ContactModel {
|
||||
/**
|
||||
* ContactModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Contacts';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
add(data) {
|
||||
data.uniq_id = data.id;
|
||||
data.id = undefined;
|
||||
/** @return {Unmanaged<typeof ContactData>} */
|
||||
new() {
|
||||
return Object.assign({}, ContactData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set contact
|
||||
* ! We can use only set since all contacts are dropped and redownloaded on sync
|
||||
* @param {Contact} data
|
||||
*/
|
||||
set(data) {
|
||||
const isNew = typeof data.id !== 'string' || !data.id?.length;
|
||||
if (isNew) {
|
||||
console.debug('is new', data);
|
||||
// * Set Local UUID until it get synced
|
||||
//* it will be ignore and new one will be generated by BO
|
||||
data.id = UuidGenerator.v4();
|
||||
}
|
||||
this.realm.write(() => {
|
||||
if (data.id === undefined) {
|
||||
let id = this.realm.objects(this.schema).max('id');
|
||||
data.id = id === undefined ? 1 : id + 1;
|
||||
}
|
||||
try {
|
||||
this.realm.create(this.schema, data, 'never');
|
||||
this.realm.create(
|
||||
this.schema,
|
||||
data,
|
||||
isNew ? UpdateMode.Never : UpdateMode.Modified,
|
||||
);
|
||||
} catch (e) {
|
||||
console.log('db setting add', e);
|
||||
console.error('db contact set', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
upsert(data) {
|
||||
let tmp = this.get(data.key);
|
||||
if (tmp === false || tmp === undefined) {
|
||||
this.add(data);
|
||||
} else {
|
||||
if (data.id === undefined) {
|
||||
data.id = tmp.id;
|
||||
}
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
update(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
|
||||
get(id) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
/**
|
||||
* get contact with uuid
|
||||
* @param {number} app_user_id App User id
|
||||
* @param {string} uuid
|
||||
* @returns {Contact?}
|
||||
*/
|
||||
get(app_user_id, uuid) {
|
||||
/** @type {import('realm').Results<Contact>} */
|
||||
const tmp = this.realm
|
||||
.objects(this.schema)
|
||||
.filtered(`app_user_id = ${app_user_id}`);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('id = ' + id)[0];
|
||||
return null;
|
||||
}
|
||||
return tmp;
|
||||
return tmp.filtered(`id = '${uuid}'`)[0] ?? null;
|
||||
}
|
||||
|
||||
getByUser(userId) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
tmp = tmp.filtered('to_delete = false AND user_id = ' + userId);
|
||||
return tmp;
|
||||
/**
|
||||
* @param {number} app_user_id App User id
|
||||
* @returns {import('realm').Results<Contact>}
|
||||
*/
|
||||
getAll(app_user_id) {
|
||||
return this.realm
|
||||
.objects(this.schema)
|
||||
.filtered(`to_delete = false AND app_user_id = ${app_user_id}`);
|
||||
}
|
||||
|
||||
getAll() {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
return tmp;
|
||||
/**
|
||||
* @param {number} app_user_id App User id
|
||||
* @returns {import('realm').Results<Contact>}
|
||||
*/
|
||||
getAllEditable(app_user_id) {
|
||||
return this.realm
|
||||
.objects(this.schema)
|
||||
.filtered(
|
||||
`to_delete = false AND send_to_app_user_id = null AND app_user_id = ${app_user_id}`,
|
||||
);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.getAll());
|
||||
});
|
||||
/**
|
||||
* @param {number} app_user_id App User id
|
||||
* @returns {import('realm').Results<Contact>}
|
||||
*/
|
||||
getAllToDelete(app_user_id) {
|
||||
return this.realm
|
||||
.objects(this.schema)
|
||||
.filtered(`to_delete = true AND app_user_id = ${app_user_id}`);
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const tmp = this.get(key);
|
||||
if (typeof tmp === 'object') {
|
||||
/**
|
||||
* delete contact with id
|
||||
* @param {number} app_user_id App User id
|
||||
* @param {string} uuid
|
||||
*/
|
||||
delete(app_user_id, uuid) {
|
||||
const contact = this.get(app_user_id, uuid);
|
||||
if (typeof contact === 'object') {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(tmp);
|
||||
this.realm.delete(contact);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} app_user_id App User id
|
||||
*/
|
||||
clear(app_user_id) {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.getAll(app_user_id));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default ContactModel;
|
||||
|
|
|
|||
|
|
@ -2,58 +2,91 @@ export const DirectoriesSchema = {
|
|||
name: 'Directories',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
/** @type {number} */
|
||||
id: 'int',
|
||||
name: 'string',
|
||||
/** @type {number|null} */
|
||||
parent: { type: 'int', optional: true },
|
||||
/** @type {number} */
|
||||
order: 'int',
|
||||
/** @type {number} */
|
||||
needAuthorization: 'int',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof DirectoriesSchema.properties> & import('realm').Object} Directory
|
||||
*/
|
||||
|
||||
class DirectoryModel {
|
||||
/**
|
||||
* DirectoryModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Directories';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Directory} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Directory} data
|
||||
*/
|
||||
update(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get directory with id
|
||||
* @param {number} id
|
||||
* @returns {Directory?}
|
||||
*/
|
||||
get(id) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
/** @type {import('realm').Results<Directory>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('id = ' + id)[0];
|
||||
return null;
|
||||
}
|
||||
return tmp;
|
||||
return tmp.filtered('id = ' + id)[0] ?? null;
|
||||
}
|
||||
|
||||
getAll(role, authorizedFolders, format, lang) {
|
||||
if (authorizedFolders !== null && authorizedFolders !== undefined) {
|
||||
authorizedFolders = JSON.parse(authorizedFolders);
|
||||
}
|
||||
/**
|
||||
* @param {string} role
|
||||
* @param {string} authorizedDirs JSON array of {Directory}
|
||||
* @param {boolean} format
|
||||
* @param {string} lang
|
||||
* @returns {import('realm').Results<Directory>}
|
||||
*/
|
||||
getAll(role, authorizedDirs, format, lang) {
|
||||
/** @type {Array<Directory>} */
|
||||
const allowedDirs =
|
||||
authorizedDirs !== null && authorizedDirs !== undefined
|
||||
? JSON.parse(authorizedDirs)
|
||||
: [];
|
||||
/** @type {import('realm').Results<Directory>} */
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
if (role === 'USER') {
|
||||
if (authorizedFolders.length > 0) {
|
||||
if (allowedDirs.length > 0) {
|
||||
tmp = tmp.filtered(
|
||||
'needAuthorization = 0 OR ' +
|
||||
authorizedFolders
|
||||
.map(folder => ' id = "' + folder.id + '"')
|
||||
.join(' OR '),
|
||||
allowedDirs
|
||||
.map(directory => ' id = "' + directory.id + '"')
|
||||
.join(' OR '),
|
||||
);
|
||||
} else {
|
||||
tmp = tmp.filtered(
|
||||
'needAuthorization = 0'
|
||||
);
|
||||
tmp = tmp.filtered('needAuthorization = 0');
|
||||
}
|
||||
}
|
||||
if (format) {
|
||||
|
|
@ -62,18 +95,28 @@ class DirectoryModel {
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/** Delete all */
|
||||
clear() {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.realm.objects(this.schema));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive Dir filter
|
||||
*
|
||||
* @param {import('realm').Results<Directory>} list
|
||||
* @param {string} lang
|
||||
* @param {DirectoryData} parent
|
||||
* @returns {DirectoryData[]}
|
||||
*/
|
||||
_recursiveDir(list, lang, parent = null) {
|
||||
let root = list.filter(e => e.parent === parent);
|
||||
let tmp = [];
|
||||
const root = list.filter(e => e.parent === parent);
|
||||
const 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);
|
||||
const childs = this._recursiveDir(list, lang, root[i].id);
|
||||
/** @type {Object<string,string>} */
|
||||
const name = JSON.parse(root[i].name);
|
||||
tmp[i] = {};
|
||||
tmp[i].id = root[i].id;
|
||||
tmp[i].name = this.getI18nName(lang, name);
|
||||
|
|
@ -89,19 +132,26 @@ class DirectoryModel {
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get i18n name
|
||||
* @param {string} lang
|
||||
* @param {Record<string,string>} name
|
||||
* @returns {string}
|
||||
*/
|
||||
getI18nName(lang, name) {
|
||||
let tmp = undefined;
|
||||
/** @type {string} */
|
||||
let tmp;
|
||||
switch (lang) {
|
||||
case "fr":
|
||||
case 'fr':
|
||||
tmp = name.fr;
|
||||
break;
|
||||
case "en":
|
||||
case 'en':
|
||||
tmp = name.en;
|
||||
break;
|
||||
case "de":
|
||||
case 'de':
|
||||
tmp = name.de;
|
||||
break;
|
||||
case "es":
|
||||
case 'es':
|
||||
tmp = name.es;
|
||||
break;
|
||||
}
|
||||
|
|
@ -110,7 +160,6 @@ class DirectoryModel {
|
|||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DirectoryModel;
|
||||
|
|
|
|||
|
|
@ -1,79 +1,126 @@
|
|||
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',
|
||||
},
|
||||
name: 'Documents',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
/** @type {number} */
|
||||
id: 'int',
|
||||
uuid: 'string',
|
||||
title: 'string',
|
||||
type: 'string',
|
||||
path: 'string',
|
||||
/** @type {number} */
|
||||
directory: 'int',
|
||||
lang: 'string',
|
||||
updated_at: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof DocumentsSchema.properties> & import('realm').Object} Document
|
||||
*/
|
||||
|
||||
class DocumentModel {
|
||||
constructor(realm) {
|
||||
this.schema = 'Documents';
|
||||
this.realm = realm;
|
||||
}
|
||||
/**
|
||||
* DocumentModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Documents';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
add(document) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, document, 'never');
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @param {Document} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'never');
|
||||
});
|
||||
}
|
||||
|
||||
update(document, updatedAtChange = false) {
|
||||
let tmp = this.get(document.id);
|
||||
if (tmp === undefined) {
|
||||
this.add(document);
|
||||
/**
|
||||
* @param {Document} data
|
||||
* @param {boolean} updatedAtChange
|
||||
*/
|
||||
update(data, updatedAtChange = false) {
|
||||
const tmp = this.get(data.id);
|
||||
if (tmp === null) {
|
||||
this.add(data);
|
||||
} else {
|
||||
this.realm.write(() => {
|
||||
if (updatedAtChange === false) {
|
||||
this.realm.create(
|
||||
this.schema,
|
||||
{
|
||||
id: tmp.id,
|
||||
uuid: data.uuid,
|
||||
title: data.title,
|
||||
type: data.type,
|
||||
path: data.path,
|
||||
directory: data.directory,
|
||||
},
|
||||
'modified',
|
||||
);
|
||||
} else {
|
||||
this.realm.write(() => {
|
||||
if (updatedAtChange === false) {
|
||||
this.realm.create(this.schema, {
|
||||
id: tmp.id,
|
||||
uuid: document.uuid,
|
||||
title: document.title,
|
||||
type: document.type,
|
||||
path: document.path,
|
||||
directory: document.directory
|
||||
}, 'modified');
|
||||
} else {
|
||||
this.realm.create(this.schema, document, 'modified');
|
||||
}
|
||||
});
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get(id) {
|
||||
let tmp = this.realm.objects(this.schema).filtered('id = ' + id)[0];
|
||||
return tmp;
|
||||
/**
|
||||
* get document with id
|
||||
* @param {number} id
|
||||
* @returns {Document?}
|
||||
*/
|
||||
get(id) {
|
||||
/** @type {Realm.Results<Document>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return tmp.filtered('id = ' + id)[0] ?? null;
|
||||
}
|
||||
|
||||
getAll(authorizedDirs = false) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
if (authorizedDirs) {
|
||||
authorizedDirs = authorizedDirs.map(item => item.id);
|
||||
tmp = tmp.filter(doc => authorizedDirs.includes(doc.directory));
|
||||
}
|
||||
return tmp;
|
||||
/**
|
||||
* @param {Array<import("./Directory").Directory>} authorizedDirs
|
||||
* @returns {import('realm').Results<Document>}
|
||||
*/
|
||||
getAll(authorizedDirs = false) {
|
||||
/** @type {Realm.Results<Document>} */
|
||||
let tmp = this.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 });
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(doc);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @typedef { { uuid: typeof DocumentsSchema.properties.uuid, type: typeof DocumentsSchema.properties.type } } DocumentCleared
|
||||
*/
|
||||
|
||||
/**
|
||||
* Delete all
|
||||
* @param {Array<Document>} docs
|
||||
* @param {Array<DocumentCleared>} toDelete
|
||||
* @returns {Array<DocumentCleared>}
|
||||
*/
|
||||
clear(docs, toDelete = []) {
|
||||
const localDocs = this.getAll();
|
||||
localDocs.forEach(doc => {
|
||||
const tmp = docs.filter(item => item.uuid === doc.uuid);
|
||||
if (tmp.length === 0) {
|
||||
toDelete.push({ uuid: doc.uuid, type: doc.type });
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(doc);
|
||||
});
|
||||
return toDelete;
|
||||
}
|
||||
}
|
||||
});
|
||||
return toDelete;
|
||||
}
|
||||
}
|
||||
|
||||
export default DocumentModel;
|
||||
|
|
|
|||
107
ComApp/src/App/Models/Form.js
Normal file
107
ComApp/src/App/Models/Form.js
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import { UpdateMode } from 'realm';
|
||||
|
||||
export const FormData = {
|
||||
/** @type {number} */
|
||||
id: undefined,
|
||||
/** @type {import('./../Enums/InputType').InputType} */
|
||||
type: undefined,
|
||||
/** @type {string} */
|
||||
name: undefined,
|
||||
/** @type {string} */
|
||||
slug: undefined,
|
||||
|
||||
/** @type {import('realm').Dictionary<string>} list of translated placeholders Map<string,string> */
|
||||
placeholder: {},
|
||||
/** @type {import('realm').List<string>} list of json encoded translated details, list of Map<string,string> */
|
||||
details: [],
|
||||
/** @type {boolean} */
|
||||
is_visible: false,
|
||||
/** @type {boolean} */
|
||||
required: false,
|
||||
/** @type {import('./../Enums/InputStatus').InputStatus} */
|
||||
status: 0,
|
||||
/** @type {number} */
|
||||
order: 0,
|
||||
};
|
||||
|
||||
export const FormsSchema = {
|
||||
name: 'Formularies',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
type: 'int',
|
||||
name: 'string',
|
||||
slug: 'string',
|
||||
placeholder: { type: 'dictionary', objectType: 'string' },
|
||||
details: { type: 'list', objectType: 'string' },
|
||||
is_visible: 'bool',
|
||||
required: 'bool',
|
||||
status: 'int',
|
||||
order: 'int',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof FormData> & import('realm').Object} Form
|
||||
*/
|
||||
|
||||
class FormModel {
|
||||
/**
|
||||
* DocumentModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Formularies';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Form} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, UpdateMode.Never);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get document with id
|
||||
* @param {number} id
|
||||
* @returns {Form?}
|
||||
*/
|
||||
get(id) {
|
||||
/** @type {Realm.Results<Form>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return tmp.filtered(`id = ${id}`)[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('./../Enums/InputStatus').InputStatus|null} status
|
||||
* @returns {import('realm').Results<Form>}
|
||||
*/
|
||||
getAll(status = null) {
|
||||
const objects = this.realm.objects(this.schema);
|
||||
if (status !== null) {
|
||||
return objects.filtered(`status = ${status}`);
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef { { uuid: typeof FormsSchema.properties.uuid, type: typeof FormsSchema.properties.type } } DocumentCleared
|
||||
*/
|
||||
|
||||
/** Delete all */
|
||||
clear() {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.getAll());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default FormModel;
|
||||
|
|
@ -2,21 +2,36 @@ export const SendBrochuresSchema = {
|
|||
name: 'SendBrochures',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
/** @type {number} */
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
subject: 'string',
|
||||
message: 'string',
|
||||
documents: 'string',
|
||||
user_id: 'int'
|
||||
/** @type {number} */
|
||||
app_user_id: 'int',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof SendBrochuresSchema.properties> & import('realm').Object} SendBrochure
|
||||
*/
|
||||
|
||||
class SendBrochureModel {
|
||||
/**
|
||||
* SendBrochureModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'SendBrochures';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SendBrochure} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
if (data.id === undefined) {
|
||||
|
|
@ -26,14 +41,17 @@ class SendBrochureModel {
|
|||
try {
|
||||
this.realm.create(this.schema, data, 'never');
|
||||
} catch (e) {
|
||||
console.log('db setting add', e);
|
||||
console.error('db setting add', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SendBrochure} data
|
||||
*/
|
||||
upsert(data) {
|
||||
let tmp = this.get(data.key);
|
||||
if (tmp === false || tmp === undefined) {
|
||||
const tmp = this.get(data.key);
|
||||
if (tmp === null) {
|
||||
this.add(data);
|
||||
} else {
|
||||
if (data.id === undefined) {
|
||||
|
|
@ -45,42 +63,55 @@ class SendBrochureModel {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SendBrochure} data
|
||||
*/
|
||||
update(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get sendBrochure with id
|
||||
* @param {number} id
|
||||
* @returns {SendBrochure?}
|
||||
*/
|
||||
get(id) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
/** @type {import('realm').Results<SendBrochure>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('id = ' + id)[0];
|
||||
return null;
|
||||
}
|
||||
return tmp;
|
||||
return tmp.filtered('id = ' + id)[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import('realm').Results<SendBrochure>}
|
||||
*/
|
||||
getAll() {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
return tmp;
|
||||
return this.realm.objects(this.schema);
|
||||
}
|
||||
|
||||
/** Delete all */
|
||||
clear() {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.getAll());
|
||||
});
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const tmp = this.get(key);
|
||||
/**
|
||||
* delete sendBrochure with id
|
||||
* @param {number} id id
|
||||
*/
|
||||
delete(id) {
|
||||
const tmp = this.get(id);
|
||||
if (typeof tmp === 'object') {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(tmp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SendBrochureModel;
|
||||
|
|
|
|||
|
|
@ -2,35 +2,52 @@ export const SettingsSchema = {
|
|||
name: 'Settings',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
/** @type {number} */
|
||||
id: 'int',
|
||||
key: 'string',
|
||||
value: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof SettingsSchema.properties> & import('realm').Object} Setting
|
||||
*/
|
||||
|
||||
class SettingModel {
|
||||
/**
|
||||
* SettingModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
this.schema = 'Settings';
|
||||
this.realm = realm;
|
||||
/** @type string */
|
||||
this.schema = 'Settings';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {Setting} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
if (data.id === undefined) {
|
||||
let id = this.realm.objects(this.schema).max('id');
|
||||
const id = this.realm.objects(this.schema).max('id');
|
||||
data.id = id === undefined ? 1 : id + 1;
|
||||
}
|
||||
try {
|
||||
this.realm.create(this.schema, data, 'never');
|
||||
} catch (e) {
|
||||
console.log('db setting add', e);
|
||||
console.error('db setting add', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Setting} data
|
||||
*/
|
||||
upsert(data) {
|
||||
let tmp = this.get(data.key);
|
||||
if (tmp === false || tmp === undefined) {
|
||||
const tmp = this.get(data.key);
|
||||
if (tmp === null) {
|
||||
this.add(data);
|
||||
} else {
|
||||
if (data.id === undefined) {
|
||||
|
|
@ -42,31 +59,41 @@ class SettingModel {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Setting} data
|
||||
*/
|
||||
update(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get setting with key
|
||||
* @param {string} key
|
||||
* @returns {Setting?}
|
||||
*/
|
||||
get(key) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
/** @type {import('realm').Results<Setting>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('key = "' + key + '"')[0];
|
||||
return null;
|
||||
}
|
||||
return tmp;
|
||||
return tmp.filtered('key = "' + key + '"')[0] ?? null;
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const tmp = this.get(key);
|
||||
/**
|
||||
* delete setting with id
|
||||
* @param {number} id id
|
||||
*/
|
||||
delete(id) {
|
||||
const tmp = this.get(id);
|
||||
if (typeof tmp === 'object') {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(tmp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SettingModel;
|
||||
export default SettingModel;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,55 @@
|
|||
/**
|
||||
* @typedef {typeof UserData} UserData
|
||||
*/
|
||||
export const UserData = {
|
||||
/** @type {string|undefined} */
|
||||
id: undefined,
|
||||
/** @type {string} */
|
||||
surname: undefined,
|
||||
/** @type {string|null} */
|
||||
lastname: null,
|
||||
/** @type {string|null} */
|
||||
firstname: null,
|
||||
/** @type {string|null} */
|
||||
role: null,
|
||||
/** @type {string|null} */
|
||||
authorizedFolders: null,
|
||||
};
|
||||
export const UsersSchema = {
|
||||
name: 'Users',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
/** @type {number} */
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
surname: 'string',
|
||||
firstname: 'string',
|
||||
password: 'string',
|
||||
role: 'string',
|
||||
/** Json encoded string of {import('./Models/Directory').Directory[]} */
|
||||
authorizedFolders: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof UsersSchema.properties> & import('realm').Object} User
|
||||
*/
|
||||
|
||||
class UserModel {
|
||||
/**
|
||||
* UserModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Users';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {User} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
if (data.id === undefined) {
|
||||
|
|
@ -27,13 +59,16 @@ class UserModel {
|
|||
try {
|
||||
this.realm.create(this.schema, data, 'never');
|
||||
} catch (e) {
|
||||
console.log('db setting add', e);
|
||||
console.error('db setting add', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {User} data
|
||||
*/
|
||||
upsert(data) {
|
||||
let tmp = this.get(data.key);
|
||||
const tmp = this.get(data.key);
|
||||
if (tmp === false || tmp === undefined) {
|
||||
this.add(data);
|
||||
} else {
|
||||
|
|
@ -46,33 +81,42 @@ class UserModel {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {User} data
|
||||
*/
|
||||
update(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get user with id
|
||||
* @param {number} id
|
||||
* @returns {User?}
|
||||
*/
|
||||
get(id) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
/** @type {import('realm').Results<User>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('id = ' + id)[0];
|
||||
return null;
|
||||
}
|
||||
return tmp;
|
||||
return tmp.filtered('key = "' + id + '"')[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import('realm').Results<User>}
|
||||
*/
|
||||
getAll() {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
return tmp;
|
||||
return this.realm.objects(this.schema);
|
||||
}
|
||||
|
||||
/** Delete all */
|
||||
clear() {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.getAll());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default UserModel;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
// Locale
|
||||
export const INIT_LOCALE = "INIT_LOCALE";
|
||||
export const EDIT_LOCALE = "EDIT_LOCALE";
|
||||
export const INIT_LOCALE = 'INIT_LOCALE';
|
||||
export const EDIT_LOCALE = 'EDIT_LOCALE';
|
||||
// Users
|
||||
export const INIT_USERS = "INIT_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";
|
||||
export const INIT_CONTACT = 'INIT_CONTACT';
|
||||
export const SET_CONTACT = 'ADD_CONTACT';
|
||||
export const DELETE_CONTACT = 'DELETE_CONTACT';
|
||||
// Directories
|
||||
export const INIT_DIRECTORIES = "INIT_DIRECTORIES";
|
||||
export const INIT_DIRECTORIES = 'INIT_DIRECTORIES';
|
||||
// Documents
|
||||
export const INIT_DOCUMENTS = "INIT_DOCUMENTS";
|
||||
export const INIT_DOCUMENTS = 'INIT_DOCUMENTS';
|
||||
// Formularies
|
||||
export const INIT_FORMS = 'INIT_FORMS';
|
||||
|
|
|
|||
|
|
@ -1,53 +1,52 @@
|
|||
import { INIT_CONTACT, ADD_CONTACT, EDIT_CONTACT, DELETE_CONTACT } from "./actionType";
|
||||
import { DELETE_CONTACT, INIT_CONTACT, SET_CONTACT } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {currentUser: import('../../Models/User').User, data: import('../../Models/Contact').Contact} } InitContactAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {object} data The contact data
|
||||
* @param {import('../../Models/User').User} currentUser The currentUser
|
||||
* @param {import('../../Models/Contact').Contact} data The contact data
|
||||
*/
|
||||
export const initContact = (currentUser, data) => {
|
||||
return {
|
||||
type: INIT_CONTACT,
|
||||
currentUser,
|
||||
data,
|
||||
};
|
||||
return {
|
||||
type: INIT_CONTACT,
|
||||
currentUser,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef { {currentUser: import('../../Models/User').User, data: import('../../Models/Contact').Contact} } SetContactAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {object} data The contact data
|
||||
* @param {import('../../Models/User').User} currentUser The currentUser
|
||||
* @param {import('../../Models/Contact').Contact} data The contact data
|
||||
*/
|
||||
export const addContact = (currentUser, data) => {
|
||||
return {
|
||||
type: ADD_CONTACT,
|
||||
currentUser,
|
||||
data,
|
||||
};
|
||||
export const setContact = (currentUser, data) => {
|
||||
return {
|
||||
type: SET_CONTACT,
|
||||
currentUser,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Edit contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {object} data The contact data
|
||||
* @typedef { {currentUser: import('../../Models/User').User, uuid: string} } DeleteContactAction
|
||||
*/
|
||||
export const editContact = (currentUser, data) => {
|
||||
return {
|
||||
type: EDIT_CONTACT,
|
||||
currentUser,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {string} id The contact id
|
||||
* @param {import('../../Models/User').User} currentUser The currentUser
|
||||
* @param {string} uuid The contact uuid
|
||||
*/
|
||||
export const deleteContact = (currentUser, id) => {
|
||||
return {
|
||||
type: DELETE_CONTACT,
|
||||
currentUser,
|
||||
id,
|
||||
};
|
||||
};
|
||||
export const deleteContact = (currentUser, uuid) => {
|
||||
return {
|
||||
type: DELETE_CONTACT,
|
||||
currentUser,
|
||||
uuid: uuid,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
import { INIT_DIRECTORIES } from "./actionType";
|
||||
import { INIT_DIRECTORIES } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof INIT_DIRECTORIES, lang: string, user: import('../../Models/User').User, data: import('../../Models/Directory').Directory} } InitDirectoryAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init
|
||||
* @param {string} lang The lang
|
||||
* @param {object} user User
|
||||
* @param {object} data The document data
|
||||
* @param {import('../../Models/User').User} user
|
||||
* @param {import('../../Models/Directory').Directory} data The document data
|
||||
* @returns {InitDirectoryAction}
|
||||
*/
|
||||
export const initDirectories = (lang, user, data) => {
|
||||
return {
|
||||
type: INIT_DIRECTORIES,
|
||||
lang,
|
||||
user,
|
||||
data,
|
||||
};
|
||||
};
|
||||
return {
|
||||
type: INIT_DIRECTORIES,
|
||||
lang,
|
||||
user,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
import { INIT_DOCUMENTS } from "./actionType";
|
||||
import { INIT_DOCUMENTS } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof INIT_DOCUMENTS, lang: string, directories: import('realm').Results<import('../../Models/Directory').Directory>, data: import('../../Models/Document').Document } } InitDocumentsAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init contact
|
||||
* @param {string} lang The lang
|
||||
* @param {object} directories Directories
|
||||
* @param {object} data The document data
|
||||
* @param {Realm.Results<import('../../Models/Directory').Directory>} directories Directories
|
||||
* @param {import('../../Models/Document').Document} data The document data
|
||||
*/
|
||||
export const initDocuments = (lang, directories, data) => {
|
||||
return {
|
||||
type: INIT_DOCUMENTS,
|
||||
lang,
|
||||
directories,
|
||||
data,
|
||||
};
|
||||
};
|
||||
return {
|
||||
type: INIT_DOCUMENTS,
|
||||
lang,
|
||||
directories,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
16
ComApp/src/App/Store/Actions/formularies.js
Normal file
16
ComApp/src/App/Store/Actions/formularies.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { INIT_FORMS } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof INIT_FORMS, data: import('../../Models/Form').Form } } InitFormAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init forms
|
||||
* @param {import('../../Models/Form').Form} data The forms data
|
||||
*/
|
||||
export const initFormularies = data => {
|
||||
return {
|
||||
type: INIT_FORMS,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
|
@ -1,23 +1,31 @@
|
|||
import { INIT_LOCALE, EDIT_LOCALE } from "./actionType";
|
||||
import { EDIT_LOCALE, INIT_LOCALE } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof INIT_LOCALE, data: string } } InitLocaleAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init locale
|
||||
* @param {object} data The locale data
|
||||
* @param {string} data The locale data
|
||||
*/
|
||||
export const initLocale = data => {
|
||||
return {
|
||||
type: INIT_LOCALE,
|
||||
data,
|
||||
};
|
||||
return {
|
||||
type: INIT_LOCALE,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof EDIT_LOCALE, data: string } } EditLocaleAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Edit locale
|
||||
* @param {object} data The locale data
|
||||
* @param {string} data The locale data
|
||||
*/
|
||||
export const editLocale = data => {
|
||||
return {
|
||||
type: EDIT_LOCALE,
|
||||
data,
|
||||
};
|
||||
return {
|
||||
type: EDIT_LOCALE,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
import { INIT_USERS } from "./actionType";
|
||||
import { INIT_USERS } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof INIT_USERS, data: import('../../Models/User').User } } InitUserAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init users
|
||||
* @param {object} data The users data
|
||||
* @param {import('../../Models/User').User} data The users data
|
||||
*/
|
||||
export const initUsers = data => {
|
||||
return {
|
||||
type: INIT_USERS,
|
||||
data,
|
||||
};
|
||||
};
|
||||
return {
|
||||
type: INIT_USERS,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,19 +1,21 @@
|
|||
import { createStore, combineReducers } from "redux";
|
||||
import { combineReducers, createStore } 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";
|
||||
import appReducer from './Reducers/AppReducer';
|
||||
import contactsReducer from './Reducers/contacts';
|
||||
import directoriesReducer from './Reducers/directories';
|
||||
import documentsReducer from './Reducers/documents';
|
||||
import formulariesReducer from './Reducers/formularies';
|
||||
import localesReducer from './Reducers/locales';
|
||||
import usersReducer from './Reducers/users';
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
app: appReducer,
|
||||
contacts: contactsReducer,
|
||||
documents: documentsReducer,
|
||||
directories: directoriesReducer,
|
||||
locale: localesReducer,
|
||||
users: usersReducer
|
||||
app: appReducer,
|
||||
contacts: contactsReducer,
|
||||
documents: documentsReducer,
|
||||
directories: directoriesReducer,
|
||||
locale: localesReducer,
|
||||
users: usersReducer,
|
||||
formularies: formulariesReducer,
|
||||
});
|
||||
|
||||
export const store = createStore(rootReducer);
|
||||
export const store = createStore(rootReducer);
|
||||
|
|
|
|||
|
|
@ -1,125 +1,123 @@
|
|||
import SyncController from "../../Controllers/SyncController";
|
||||
// Database
|
||||
import { Setting, SendBrochure } from '../../../Database';
|
||||
import SyncController from '../../Controllers/SyncController';
|
||||
// Database
|
||||
import { SendBrochure, Setting } from '../../../Database';
|
||||
|
||||
const initialState = {
|
||||
isSetup: false,
|
||||
locale: 'fr',
|
||||
currentUser: {},
|
||||
logged: false,
|
||||
syncVersion: 0,
|
||||
forceSync: false,
|
||||
currentOpenedDoc: {},
|
||||
ShowIsActive: 0,
|
||||
HomeBtns: {},
|
||||
mainColor: '#D4021D',
|
||||
FormSelect1: {},
|
||||
FormSelect2: {},
|
||||
FormCheck: [],
|
||||
isSetup: false,
|
||||
locale: 'fr',
|
||||
currentUser: {},
|
||||
logged: false,
|
||||
syncVersion: 0,
|
||||
forceSync: false,
|
||||
currentOpenedDoc: {},
|
||||
ShowIsActive: 0,
|
||||
HomeBtns: {},
|
||||
mainColor: '#D4021D',
|
||||
};
|
||||
|
||||
const reducer = (state = initialState, action) => {
|
||||
let saved;
|
||||
switch (action.type) {
|
||||
case 'INIT':
|
||||
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,
|
||||
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_HOME_BTNS': {
|
||||
let HomeFolders = Setting.get('HomeFolders');
|
||||
let Btns = JSON.parse(HomeFolders.value);
|
||||
return {
|
||||
...state,
|
||||
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':
|
||||
let user = false;
|
||||
let isLogged = false;
|
||||
if (action.data === false) {
|
||||
Setting.delete('isLogged');
|
||||
} else {
|
||||
userObj = Setting.get('isLogged').value
|
||||
user = JSON.parse(userObj)
|
||||
isLogged = true
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
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,
|
||||
currentOpenedDoc: action.data
|
||||
};
|
||||
case 'UPDATE_VERSION':
|
||||
return {
|
||||
...state,
|
||||
syncVersion: action.data,
|
||||
};
|
||||
case 'UPDATE_SHOW_IS_ACTIVE':
|
||||
SyncController.updateShowIsActive(action.data);
|
||||
return {
|
||||
...state,
|
||||
ShowIsActive: action.data,
|
||||
};
|
||||
case 'SEND_BROCHURE':
|
||||
SendBrochure.add(action.data);
|
||||
return state;
|
||||
default:
|
||||
return state;
|
||||
let saved;
|
||||
switch (action.type) {
|
||||
case 'INIT':
|
||||
let ShowIsActive = Setting.get('ShowIsActive');
|
||||
let MainColor = Setting.get('MainColor');
|
||||
saved = Setting.get('isSetup');
|
||||
return {
|
||||
...state,
|
||||
isSetup:
|
||||
saved === undefined ? false : saved?.value === 'true' ? true : false,
|
||||
ShowIsActive: ShowIsActive ? ShowIsActive?.value : false,
|
||||
mainColor:
|
||||
MainColor === undefined
|
||||
? initialState.mainColor
|
||||
: MainColor === null
|
||||
? initialState.mainColor
|
||||
: MainColor?.value,
|
||||
};
|
||||
case 'INIT_HOME_BTNS': {
|
||||
let HomeFolders = Setting.get('HomeFolders');
|
||||
let Btns = HomeFolders ? JSON.parse(HomeFolders?.value) : [];
|
||||
return {
|
||||
...state,
|
||||
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':
|
||||
let user = false;
|
||||
let isLogged = false;
|
||||
if (action.data === false) {
|
||||
Setting.delete('isLogged');
|
||||
} else {
|
||||
let userObj = Setting.get('isLogged');
|
||||
user = userObj ? JSON.parse(userObj?.value) : false;
|
||||
isLogged = true;
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
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,
|
||||
currentOpenedDoc: action.data,
|
||||
};
|
||||
case 'UPDATE_VERSION':
|
||||
return {
|
||||
...state,
|
||||
syncVersion: action.data,
|
||||
};
|
||||
case 'UPDATE_SHOW_IS_ACTIVE':
|
||||
SyncController.updateShowIsActive(action.data);
|
||||
return {
|
||||
...state,
|
||||
ShowIsActive: action.data,
|
||||
};
|
||||
case 'SEND_BROCHURE':
|
||||
SendBrochure.add(action.data);
|
||||
return state;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
export default reducer;
|
||||
|
|
|
|||
|
|
@ -1,32 +1,38 @@
|
|||
import { INIT_CONTACT, ADD_CONTACT, EDIT_CONTACT, DELETE_CONTACT } from "../Actions/actionType";
|
||||
import {
|
||||
DELETE_CONTACT,
|
||||
INIT_CONTACT,
|
||||
SET_CONTACT,
|
||||
} from '../Actions/actionType';
|
||||
// Models
|
||||
import { Contact } from "../../../Database";
|
||||
import { Contact } from '../../../Database';
|
||||
|
||||
/** @type {import('../../Models/Contact').Contact[]} */
|
||||
const initialState = [];
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/contacts').InitContactAction|import('../Actions/contacts').SetContactAction|import('../Actions/contacts').DeleteContactAction} action
|
||||
* @returns {import('realm').Results<import('../../Models/Contact').Contact>}
|
||||
*/
|
||||
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;
|
||||
}
|
||||
switch (action.type) {
|
||||
case INIT_CONTACT: {
|
||||
return Contact.getAllEditable(action.currentUser.id);
|
||||
}
|
||||
case SET_CONTACT: {
|
||||
action.data.app_user_id = action.currentUser.id;
|
||||
Contact.set(action.data);
|
||||
return Contact.getAllEditable(action.currentUser.id);
|
||||
}
|
||||
case DELETE_CONTACT: {
|
||||
Contact.delete(action.currentUser.id, action.uuid);
|
||||
return Contact.getAllEditable(action.currentUser.id);
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
|
|
|
|||
|
|
@ -1,32 +1,42 @@
|
|||
import { INIT_DIRECTORIES } from "../Actions/actionType";
|
||||
import { Directory } from '../../../Database';
|
||||
import { INIT_DIRECTORIES } from '../Actions/actionType';
|
||||
// Models
|
||||
import { Directory } from "../../../Database";
|
||||
|
||||
const initialState = [];
|
||||
const initialState = {
|
||||
/** @type {Realm.Results<import('../../Models/Directory').Directory>} */
|
||||
global: [],
|
||||
/** @type {Realm.Results<import('../../Models/Directory').Directory>} */
|
||||
treeview: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/directories').InitDirectoryAction} action
|
||||
* @returns
|
||||
*/
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,29 @@
|
|||
import { INIT_DOCUMENTS } from "../Actions/actionType";
|
||||
import { INIT_DOCUMENTS } from '../Actions/actionType';
|
||||
// Models
|
||||
import { Document } from "../../../Database";
|
||||
import { Document } from '../../../Database';
|
||||
|
||||
/** @type {import('../../Models/Document').Document[]} */
|
||||
const initialState = [];
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/documents').InitDocumentsAction} action
|
||||
* @returns
|
||||
*/
|
||||
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;
|
||||
}
|
||||
switch (action.type) {
|
||||
case INIT_DOCUMENTS: {
|
||||
const 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;
|
||||
|
|
|
|||
30
ComApp/src/App/Store/Reducers/formularies.js
Normal file
30
ComApp/src/App/Store/Reducers/formularies.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { INIT_FORMS } from '../Actions/actionType';
|
||||
// Models
|
||||
import { Form } from '../../../Database';
|
||||
|
||||
const initialState = {
|
||||
/** @type {Realm.Results<import('../../Models/Form').Form>} */
|
||||
users: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/formularies').InitFormAction} action
|
||||
* @returns
|
||||
*/
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_FORMS: {
|
||||
return {
|
||||
...state,
|
||||
forms: Form.getAll(),
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
|
|
@ -1,45 +1,55 @@
|
|||
import { INIT_LOCALE, EDIT_LOCALE } from "../Actions/actionType";
|
||||
import { EDIT_LOCALE, INIT_LOCALE } from '../Actions/actionType';
|
||||
// Models
|
||||
import { Setting } from "../../../Database";
|
||||
import { Setting } from '../../../Database';
|
||||
// Translations
|
||||
import i18n from "../../../I18n";
|
||||
import i18n from '../../../I18n';
|
||||
|
||||
const initialState = [];
|
||||
const initialState = {
|
||||
locale: 'fr',
|
||||
};
|
||||
const availableLocales = ['fr', 'en', 'de'];
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/locales').InitLocaleAction|import('../Actions/locales').EditLocaleAction} action
|
||||
* @returns
|
||||
*/
|
||||
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;
|
||||
}
|
||||
switch (action.type) {
|
||||
case INIT_LOCALE: {
|
||||
const savedLocale = Setting.get('locale');
|
||||
return {
|
||||
...state,
|
||||
locale: savedLocale === null ? initialState.locale : savedLocale.value,
|
||||
};
|
||||
}
|
||||
|
||||
case EDIT_LOCALE: {
|
||||
let nxt;
|
||||
if (action.data === undefined) {
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -1,22 +1,30 @@
|
|||
import { INIT_USERS } from "../Actions/actionType";
|
||||
import { INIT_USERS } from '../Actions/actionType';
|
||||
// Models
|
||||
import { User } from "../../../Database";
|
||||
import { User } from '../../../Database';
|
||||
|
||||
const initialState = [];
|
||||
const initialState = {
|
||||
/** @type {Realm.Results<import('../../Models/User').User>} */
|
||||
users: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/users').InitUserAction} action
|
||||
* @returns
|
||||
*/
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_USERS: {
|
||||
return {
|
||||
...state,
|
||||
users: User.getAll(),
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
switch (action.type) {
|
||||
case INIT_USERS: {
|
||||
return {
|
||||
...state,
|
||||
users: User.getAll(),
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,14 +1,7 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
Image
|
||||
} from 'react-native';
|
||||
import { Image, ScrollView, Text, TouchableOpacity, View } 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,72 +12,72 @@ import arrowDown from '../../Resources/assets/img/arrow_down.png';
|
|||
import styles from '../../Resources/Styles/DirectoriesStyle';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.documents,
|
||||
directories: state.directories,
|
||||
locale: state.locale.locale,
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
return {
|
||||
documents: state.documents,
|
||||
directories: state.directories,
|
||||
locale: state.locale.locale,
|
||||
mainColor: state.app.mainColor,
|
||||
};
|
||||
}
|
||||
|
||||
class DirectoriesScreen extends React.Component {
|
||||
state = {
|
||||
documents: [],
|
||||
};
|
||||
state = {
|
||||
documents: [],
|
||||
};
|
||||
|
||||
render() {
|
||||
const { folder } = this.props.route.params;
|
||||
let documentList = this.state.documents.map(document => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={document.id.toString()}
|
||||
style={{ ...styles.file, backgroundColor: this.props.mainColor }}
|
||||
onPress={() => this.openDocument(document)}>
|
||||
{document.type === 'pdf' ? (
|
||||
<FontAwesome5 name="file-pdf" color={'white'} size={60} />
|
||||
) : (
|
||||
<FontAwesome5 name="file-video" color={'white'} size={60} />
|
||||
)}
|
||||
<Text style={styles.fileTxt}>{document.title}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
});
|
||||
render() {
|
||||
const { folder } = this.props.route.params;
|
||||
let documentList = this.state.documents.map(document => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={document.id.toString()}
|
||||
style={{ ...styles.file, backgroundColor: this.props.mainColor }}
|
||||
onPress={() => this.openDocument(document)}>
|
||||
{document.type === 'pdf' ? (
|
||||
<FontAwesome5 name="file-pdf" color={'white'} size={60} />
|
||||
) : (
|
||||
<FontAwesome5 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={{ uri: Image.resolveAssetSource(arrowDown).uri }}
|
||||
containerStyle={styles.treeviewContainer}
|
||||
onClick={folder => {
|
||||
this.setState({
|
||||
documents: this.props.documents.filter(
|
||||
tmp => tmp.directory === folder.id,
|
||||
)
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<ScrollView style={styles.scrollview}>
|
||||
<View style={styles.filesContainer}>{documentList}</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View
|
||||
style={{ width: 290, borderRightWidth: 1, borderColor: 'lightgrey' }}>
|
||||
<TreeView
|
||||
data={folder}
|
||||
leftImage={{}}
|
||||
rightImage={{ uri: Image.resolveAssetSource(arrowDown).uri }}
|
||||
containerStyle={styles.treeviewContainer}
|
||||
onClick={folder => {
|
||||
this.setState({
|
||||
documents: this.props.documents.filter(
|
||||
tmp => tmp.directory === folder.id,
|
||||
),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<ScrollView style={styles.scrollview}>
|
||||
<View style={styles.filesContainer}>{documentList}</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
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.error('Type de document Inconnu');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(DirectoriesScreen);
|
||||
|
|
|
|||
|
|
@ -1,18 +1,24 @@
|
|||
import React from 'react';
|
||||
import { View, ImageBackground, TouchableOpacity, Text, Image } from 'react-native';
|
||||
// Common Styles
|
||||
import {
|
||||
Image,
|
||||
ImageBackground,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
// Common Styles
|
||||
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 { initDocuments } from '../Store/Actions/documents';
|
||||
// SplashScreen
|
||||
import * as SplashScreen from 'expo-splash-screen';
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/HomeStyle';
|
||||
// Translations
|
||||
import i18n from "../../I18n";
|
||||
import i18n from '../../I18n';
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
// NetInfo
|
||||
|
|
@ -21,105 +27,140 @@ import NetInfo from '@react-native-community/netinfo';
|
|||
import SyncController from '../Controllers/SyncController';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
btns: state.app.HomeBtns,
|
||||
directories: state.directories,
|
||||
locale: state.locale.locale,
|
||||
currentUser: state.app.currentUser
|
||||
};
|
||||
return {
|
||||
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)),
|
||||
|
||||
};
|
||||
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',
|
||||
};
|
||||
|
||||
state = {
|
||||
lastSyncCall: '1970-01-01',
|
||||
};
|
||||
componentDidMount() {
|
||||
if (!SyncController.isInstalled()) {
|
||||
return this.openSync();
|
||||
}
|
||||
this.props.initBtns();
|
||||
console.debug(this.props.currentUser);
|
||||
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);
|
||||
|
||||
componentDidMount() {
|
||||
if (!SyncController.isInstalled()) {
|
||||
return this.openSync();
|
||||
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));
|
||||
}
|
||||
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();
|
||||
}
|
||||
openSync() {
|
||||
this.props.navigation.navigate('SyncScreen', { forceSync: true });
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
render() {
|
||||
i18n.locale = this.props.locale;
|
||||
return (
|
||||
<ImageBackground
|
||||
source={{ uri: FileSystem.documentDirectory + 'BackgroundImage.png' }}
|
||||
style={commonStyles.background}
|
||||
resizeMode="cover">
|
||||
<View style={styles.container}>
|
||||
{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
|
||||
key={'Contacts'}
|
||||
onPress={() => {
|
||||
this.props.initDocuments(
|
||||
this.props.locale,
|
||||
this.props.directories.global,
|
||||
);
|
||||
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>
|
||||
</View>
|
||||
</ImageBackground>
|
||||
);
|
||||
}
|
||||
|
||||
openSync() {
|
||||
this.props.navigation.navigate('SyncScreen', { forceSync: true });
|
||||
}
|
||||
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>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
i18n.locale = this.props.locale;
|
||||
return (
|
||||
<ImageBackground source={{ uri: FileSystem.documentDirectory + 'BackgroundImage.png' }} style={commonStyles.background} resizeMode='cover'>
|
||||
<View style={styles.container}>
|
||||
{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 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>
|
||||
</View>
|
||||
</ImageBackground>
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
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 });
|
||||
}
|
||||
openFolder(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, mapDispatchToProps)(HomeScreen);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);
|
||||
|
|
|
|||
|
|
@ -1,191 +1,219 @@
|
|||
import React from 'react';
|
||||
import { ImageBackground, View, Image, Text, TextInput, Button, Alert } from 'react-native';
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Image,
|
||||
ImageBackground,
|
||||
Text,
|
||||
TextInput,
|
||||
View,
|
||||
} from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
// Sentry
|
||||
import * as Sentry from "@sentry/react-native";
|
||||
// SplashScreen
|
||||
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
|
||||
// Common Styles
|
||||
import commonStyles from '../../Resources/CommonStyles';
|
||||
// Style
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/InstallStyle';
|
||||
// Translations
|
||||
import i18n from "../../I18n";
|
||||
import i18n from '../../I18n';
|
||||
// Controller
|
||||
import InstallController from '../Controllers/InstallController';
|
||||
import SyncController from '../Controllers/SyncController';
|
||||
// Database
|
||||
import { User, Setting } from '../../Database';
|
||||
// Database
|
||||
import { Setting, User } from '../../Database';
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
isSetup: state.app.isSetup,
|
||||
locale: state.locale.locale,
|
||||
};
|
||||
return {
|
||||
isSetup: state.app.isSetup,
|
||||
locale: state.locale.locale,
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setIsSetup: () => dispatch({ type: 'SET_ISSETUP' }),
|
||||
init: () => dispatch({ type: 'INIT' })
|
||||
};
|
||||
return {
|
||||
setIsSetup: () => dispatch({ type: 'SET_ISSETUP' }),
|
||||
init: () => dispatch({ type: 'INIT' }),
|
||||
};
|
||||
};
|
||||
class InstallScreen extends React.Component {
|
||||
state = {
|
||||
processing: false,
|
||||
txtStep: '',
|
||||
url: "",
|
||||
}
|
||||
state = {
|
||||
processing: false,
|
||||
txtStep: '',
|
||||
url: '',
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
SplashScreen.hideAsync();
|
||||
}
|
||||
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 })}
|
||||
value={this.state.url}
|
||||
/>
|
||||
<Button
|
||||
disabled={this.state.processing}
|
||||
color={'#D4021D'}
|
||||
title={ i18n.t('install.install')}
|
||||
onPress={() => {
|
||||
if (this.state.url.length === 0) {
|
||||
Alert.alert(i18n.t("alert.error"), i18n.t("install.enter_url"));
|
||||
} else {
|
||||
if (Helpers.isUrlValid(this.state.url)) {
|
||||
this.install();
|
||||
} else {
|
||||
Alert.alert(i18n.t("alert.error"), i18n.t("install.url_invalid"));
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.actions}>
|
||||
<Text>
|
||||
{this.state.txtStep}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</ImageBackground>
|
||||
);
|
||||
}
|
||||
|
||||
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: 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;
|
||||
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 })}
|
||||
value={this.state.url}
|
||||
/>
|
||||
<Button
|
||||
disabled={this.state.processing}
|
||||
color={'#D4021D'}
|
||||
title={i18n.t('install.install')}
|
||||
onPress={() => {
|
||||
if (this.state.url.length === 0) {
|
||||
Alert.alert(
|
||||
i18n.t('alert.error'),
|
||||
i18n.t('install.enter_url'),
|
||||
);
|
||||
} else {
|
||||
Alert.alert(i18n.t("alert.error"), i18n.t("error.error_has_occurred"));
|
||||
return false;
|
||||
// * Ignore ths check on dev, just install.
|
||||
if (__DEV__ || Helpers.isUrlValid(this.state.url)) {
|
||||
this.install();
|
||||
} else {
|
||||
Alert.alert(
|
||||
i18n.t('alert.error'),
|
||||
i18n.t('install.url_invalid'),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).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;
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.actions}>
|
||||
<Text>{this.state.txtStep}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</ImageBackground>
|
||||
);
|
||||
}
|
||||
|
||||
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: "" });
|
||||
async install() {
|
||||
let url = this.state.url.toLowerCase();
|
||||
Setting.upsert({ key: 'bo_url', value: url });
|
||||
const isConnected = await SyncController.checkConnection()
|
||||
.then(state => {
|
||||
console.debug(state.isConnected);
|
||||
return state.isConnected;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
return false;
|
||||
});
|
||||
if (!isConnected) {
|
||||
Alert.alert(
|
||||
i18n.t('global.warning'),
|
||||
i18n.t('error.must_be_connected_internet_sync'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
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':
|
||||
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);
|
||||
console.error(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.debug('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.error(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 connect(mapStateToProps, mapDispatchToProps)(InstallScreen);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(InstallScreen);
|
||||
|
|
|
|||
|
|
@ -1,151 +1,297 @@
|
|||
import React from 'react';
|
||||
import { View, ImageBackground, TextInput, Button, Image, Alert } from 'react-native';
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Image,
|
||||
ImageBackground,
|
||||
TextInput,
|
||||
View,
|
||||
} from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
// SplashScreen
|
||||
// SplashScreen
|
||||
import * as SplashScreen from 'expo-splash-screen';
|
||||
// Common Styles
|
||||
// Common Styles
|
||||
import commonStyles from '../../Resources/CommonStyles';
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/LoginStyle';
|
||||
// Translations
|
||||
import i18n from "../../I18n";
|
||||
import i18n from '../../I18n';
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
// Controller
|
||||
import LoginController from '../Controllers/LoginController';
|
||||
// Database
|
||||
import { Setting } from '../../Database';
|
||||
import _ from 'lodash';
|
||||
import { Setting, User } from '../../Database';
|
||||
import InstallController from '../Controllers/InstallController';
|
||||
import SyncController from '../Controllers/SyncController';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
app: state.app,
|
||||
users: state.users.users,
|
||||
locale: state.locale.locale,
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
return {
|
||||
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' }),
|
||||
};
|
||||
return {
|
||||
setCurrentUser: () => dispatch({ type: 'SET_CURRENT_USER' }),
|
||||
setIsSetup: () => dispatch({ type: 'SET_ISSETUP' }),
|
||||
init: () => dispatch({ type: 'INIT' }),
|
||||
};
|
||||
};
|
||||
|
||||
class LoginScreen extends React.Component {
|
||||
state = {
|
||||
login: '',
|
||||
password: '',
|
||||
};
|
||||
state = {
|
||||
syncWorking: false,
|
||||
login: '',
|
||||
password: '',
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if (SyncController.isLogged()) {
|
||||
this.props.setCurrentUser(false);
|
||||
}
|
||||
SplashScreen.hideAsync();
|
||||
componentDidMount() {
|
||||
if (SyncController.isLogged()) {
|
||||
this.props.setCurrentUser(false);
|
||||
}
|
||||
SplashScreen.hideAsync();
|
||||
this.syncUsersIfPossibleAsync();
|
||||
this.syncAppConfigIfPossibleAsync();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ImageBackground source={{ uri: FileSystem.documentDirectory + 'BackgroundImage.png' }} style={commonStyles.background}>
|
||||
<View style={styles.container}>
|
||||
<Image source={{ uri: FileSystem.documentDirectory + 'SquaredLogo.png' }} style={styles.logo} />
|
||||
<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.toLowerCase(), this.state.password)}
|
||||
color={this.props.mainColor}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</ImageBackground >
|
||||
render() {
|
||||
return (
|
||||
<ImageBackground
|
||||
source={{ uri: FileSystem.documentDirectory + 'BackgroundImage.png' }}
|
||||
style={commonStyles.background}>
|
||||
<View style={styles.container}>
|
||||
<Image
|
||||
source={{ uri: FileSystem.documentDirectory + 'SquaredLogo.png' }}
|
||||
style={styles.logo}
|
||||
/>
|
||||
<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
|
||||
disabled={this.state.syncWorking}
|
||||
title={i18n.t('global.login')}
|
||||
onPress={() =>
|
||||
this.login(this.state.login.toLowerCase(), this.state.password)
|
||||
}
|
||||
color={!this.state.syncWorking ? this.props.mainColor : 'gray'}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</ImageBackground>
|
||||
);
|
||||
}
|
||||
|
||||
async login(login, password) {
|
||||
if (login === '' || password === '') {
|
||||
Alert.alert(
|
||||
i18n.t('global.warning'),
|
||||
i18n.t('error.must_fill_login_fields'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
/** @type {Array<import('../Models/User').User>} */
|
||||
const users = this.props.users;
|
||||
if (users.length === 0) {
|
||||
Alert.alert(i18n.t('global.warning'), i18n.t('login_s.missing_users'));
|
||||
return;
|
||||
}
|
||||
const user = users.find(tmp => tmp.email === login);
|
||||
if (user === undefined) {
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.incorrect_credentials'));
|
||||
return;
|
||||
}
|
||||
const verified = await LoginController.verify(user, password);
|
||||
if (!verified) {
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.incorrect_credentials'));
|
||||
return;
|
||||
}
|
||||
const isConnected = await SyncController.checkConnection()
|
||||
.then(state => {
|
||||
console.debug(state.isConnected);
|
||||
return state.isConnected;
|
||||
})
|
||||
.catch(error => {
|
||||
console.debug(error);
|
||||
return false;
|
||||
});
|
||||
const lastUser = Setting.get('lastUser');
|
||||
|
||||
// * Si on est sur une installation
|
||||
if (lastUser === null) {
|
||||
console.debug('New Install');
|
||||
// * 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;
|
||||
}
|
||||
return this.loginAction(user);
|
||||
}
|
||||
|
||||
async login(login, password) {
|
||||
if (login === '' || password === '') {
|
||||
Alert.alert(i18n.t("global.warning"), i18n.t('error.must_fill_login_fields'));
|
||||
return;
|
||||
}
|
||||
var usersSize = Object.keys(this.props.users).length;
|
||||
if (usersSize === 0) {
|
||||
Alert.alert(i18n.t("global.warning"), i18n.t('login_s.missing_users'));
|
||||
return;
|
||||
}
|
||||
let user = this.props.users.filter(tmp => tmp.email === login);
|
||||
if (user.length === 0) {
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.incorrect_credentials'));
|
||||
return;
|
||||
}
|
||||
user = user[0];
|
||||
const verified = LoginController.verify(user, password).then(verified => verified);
|
||||
if (!verified) {
|
||||
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;
|
||||
// * On a deja eu une install
|
||||
|
||||
// * Si on a une précédente connexion
|
||||
if (lastUser.value === user.id.toString()) {
|
||||
console.debug('Was previously logged in');
|
||||
return this.loginAction(user);
|
||||
}
|
||||
// Si le user precedent est different du user courant
|
||||
// Si user !== last user && last user not synced
|
||||
if (!SyncController.isSynced(user.id)) {
|
||||
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 (!isConnected) {
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.tablet_not_connected_internet'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('New user loggin');
|
||||
SyncController.setInstalled(true);
|
||||
return this.loginAction(user, true);
|
||||
}
|
||||
|
||||
async syncUsersIfPossibleAsync() {
|
||||
const isConnected = await SyncController.checkConnection();
|
||||
if (!isConnected.isInternetReachable) {
|
||||
return;
|
||||
}
|
||||
console.debug('sync users ?');
|
||||
this.setState({ syncWorking: true });
|
||||
if (InstallController.getAppConfig(SyncController.getUrlBo())) {
|
||||
// getUsers
|
||||
const resUsers = await SyncController.getUsers()
|
||||
.then(res => {
|
||||
User.clear();
|
||||
console.debug('got users');
|
||||
return res.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
this.setState({ syncWorking: false });
|
||||
return [];
|
||||
});
|
||||
const lastUser = Setting.get('lastUser');
|
||||
// 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;
|
||||
}
|
||||
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 (!isConnected) {
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.tablet_not_connected_internet'));
|
||||
return;
|
||||
}
|
||||
SyncController.setInstalled(true);
|
||||
this.loginAction(user, true);
|
||||
}
|
||||
}
|
||||
if (!resUsers?.length) {
|
||||
this.setState({ syncWorking: false });
|
||||
return;
|
||||
}
|
||||
resUsers.forEach(user => {
|
||||
User.add(user);
|
||||
});
|
||||
this.setState({ syncWorking: false });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
loginAction(user) {
|
||||
this.setState({ login: '', password: '' });
|
||||
LoginController.login(user);
|
||||
this.props.setCurrentUser();
|
||||
async syncAppConfigIfPossibleAsync() {
|
||||
const isConnected = await SyncController.checkConnection();
|
||||
if (!isConnected.isInternetReachable) {
|
||||
return;
|
||||
}
|
||||
console.debug('sync settings ?');
|
||||
this.setState({ syncWorking: true });
|
||||
const url = Setting.get('bo_url')?.value;
|
||||
if (!url) {
|
||||
console.warn('url config is wrong');
|
||||
return;
|
||||
}
|
||||
const toDL = await InstallController.getConfig(url)
|
||||
.then(response => {
|
||||
const toDLArray = [];
|
||||
if (response.data) {
|
||||
if (response.data.status === 'OK') {
|
||||
console.debug('got settings');
|
||||
_.forEach(response.data.datas, function (value, key) {
|
||||
switch (key) {
|
||||
case 'MainColor':
|
||||
case 'AppStoreUUID':
|
||||
Setting.upsert({ key: key, value: value });
|
||||
break;
|
||||
case 'SquaredLogo':
|
||||
case 'RectangleLogo':
|
||||
case 'BackgroundImage':
|
||||
case 'HomeButtonImage':
|
||||
toDLArray.push({
|
||||
source: url + '/' + value,
|
||||
dest: FileSystem.documentDirectory + key + '.png',
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
return toDLArray;
|
||||
} else {
|
||||
console.debug('got Ko settings');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
console.debug(response);
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error);
|
||||
console.error(error.response);
|
||||
return [];
|
||||
});
|
||||
if (!toDL?.length) {
|
||||
this.setState({ syncWorking: false });
|
||||
return false;
|
||||
}
|
||||
for await (const file of toDL) {
|
||||
await FileSystem.downloadAsync(file.source, file.dest)
|
||||
.then(({ uri }) => {
|
||||
console.debug('Finished downloading to ', uri);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
this.setState({ syncWorking: false });
|
||||
return false;
|
||||
});
|
||||
}
|
||||
this.props.init();
|
||||
this.props.setIsSetup();
|
||||
this.setState({ syncWorking: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('../Models/User').User} user
|
||||
*/
|
||||
loginAction(user) {
|
||||
this.setState({ login: '', password: '' });
|
||||
console.debug('loginAction');
|
||||
LoginController.login(user);
|
||||
this.props.setCurrentUser();
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);
|
||||
|
|
|
|||
|
|
@ -1,28 +1,24 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/MySpaceStyle';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.app.documents,
|
||||
};
|
||||
}
|
||||
|
||||
class MySpaceScreen extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Mon Espace</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(MySpaceScreen);
|
||||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/MySpaceStyle';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.app.documents,
|
||||
};
|
||||
}
|
||||
|
||||
class MySpaceScreen extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Mon Espace</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(MySpaceScreen);
|
||||
|
|
|
|||
|
|
@ -1,61 +1,63 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
// Icons
|
||||
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/OnlyVideosStyle';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.documents,
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
}
|
||||
|
||||
class OnlyVideosScreen extends React.Component {
|
||||
state = {
|
||||
documents: [],
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({ documents: this.props.documents.filter(tmp => tmp.type === 'mp4') });
|
||||
}
|
||||
|
||||
render() {
|
||||
let documentList = this.state.documents.map(document => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={document.id.toString()}
|
||||
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 });
|
||||
}}>
|
||||
{document.type === 'pdf' ? (
|
||||
<FontAwesome5 name="file-pdf" color={'white'} size={60} />
|
||||
) : (
|
||||
<FontAwesome5 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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(OnlyVideosScreen);
|
||||
import React from 'react';
|
||||
import { ScrollView, Text, TouchableOpacity, View } from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
// Icons
|
||||
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/OnlyVideosStyle';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.documents,
|
||||
mainColor: state.app.mainColor,
|
||||
};
|
||||
}
|
||||
|
||||
class OnlyVideosScreen extends React.Component {
|
||||
state = {
|
||||
documents: [],
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
documents: this.props.documents.filter(tmp => tmp.type === 'mp4'),
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let documentList = this.state.documents.map(document => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={document.id.toString()}
|
||||
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,
|
||||
});
|
||||
}}>
|
||||
{document.type === 'pdf' ? (
|
||||
<FontAwesome5 name="file-pdf" color={'white'} size={60} />
|
||||
) : (
|
||||
<FontAwesome5 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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(OnlyVideosScreen);
|
||||
|
|
|
|||
|
|
@ -8,33 +8,33 @@ import * as FileSystem from 'expo-file-system';
|
|||
import styles from '../../Resources/Styles/PDFStyle';
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
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.debug(`number of pages: ${numberOfPages}`);
|
||||
}}
|
||||
onPageChanged={(page, numberOfPages) => {
|
||||
console.debug(`current page: ${page}`);
|
||||
}}
|
||||
onError={error => {
|
||||
console.error(error);
|
||||
}}
|
||||
onPressLink={uri => {
|
||||
console.debug(`Link presse: ${uri}`);
|
||||
}}
|
||||
style={styles.pdf}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PDFScreen;
|
||||
|
|
|
|||
|
|
@ -1,86 +1,87 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
// Reduxs
|
||||
import { connect } from 'react-redux';
|
||||
// Helpers
|
||||
import Helpers from "../Lib/Helpers";
|
||||
// Translations
|
||||
import i18n from "../../I18n";
|
||||
// Icons
|
||||
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/SearchStyle';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.documents,
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
}
|
||||
|
||||
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() {
|
||||
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, backgroundColor: this.props.mainColor }}
|
||||
onPress={() => this.openDocument(document)}>
|
||||
{document.type === 'pdf' ? (
|
||||
<FontAwesome5 name="file-pdf" color={'white'} size={60} />
|
||||
) : (
|
||||
<FontAwesome5 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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(SearchScreen);
|
||||
import React from 'react';
|
||||
import { ScrollView, Text, TouchableOpacity, View } from 'react-native';
|
||||
// Reduxs
|
||||
import { connect } from 'react-redux';
|
||||
// Helpers
|
||||
import Helpers from '../Lib/Helpers';
|
||||
// Translations
|
||||
import i18n from '../../I18n';
|
||||
// Icons
|
||||
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/SearchStyle';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
documents: state.documents,
|
||||
mainColor: state.app.mainColor,
|
||||
};
|
||||
}
|
||||
|
||||
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.error('Type de document inconnu');
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
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, backgroundColor: this.props.mainColor }}
|
||||
onPress={() => this.openDocument(document)}>
|
||||
{document.type === 'pdf' ? (
|
||||
<FontAwesome5 name="file-pdf" color={'white'} size={60} />
|
||||
) : (
|
||||
<FontAwesome5 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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(SearchScreen);
|
||||
|
|
|
|||
|
|
@ -1,379 +1,507 @@
|
|||
import React from 'react';
|
||||
import { View, Button, Alert, Text } from 'react-native';
|
||||
import { Alert, Button, Linking, Text, View } from 'react-native';
|
||||
// Redux
|
||||
import { connect } from 'react-redux';
|
||||
import { initDirectories } from '../Store/Actions/directories';
|
||||
import { initContact } from '../Store/Actions/contacts';
|
||||
import { initDirectories } from '../Store/Actions/directories';
|
||||
import { initDocuments } from '../Store/Actions/documents';
|
||||
// Sentry
|
||||
import * as Sentry from "@sentry/react-native";
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
|
||||
// Style
|
||||
import styles from '../../Resources/Styles/SyncStyle';
|
||||
// Translations
|
||||
import i18n from "../../I18n";
|
||||
// Controller
|
||||
import i18n from '../../I18n';
|
||||
// Controller
|
||||
import SyncController from '../Controllers/SyncController';
|
||||
// Progress
|
||||
import * as Progress from 'react-native-progress';
|
||||
// Database
|
||||
import { User, Contact, Directory, Document, SendBrochure } from '../../Database';
|
||||
// Database
|
||||
import {
|
||||
Contact,
|
||||
Directory,
|
||||
Document,
|
||||
Form,
|
||||
SendBrochure,
|
||||
User,
|
||||
} from '../../Database';
|
||||
// FileSytem
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
syncVersion: state.app.syncVersion,
|
||||
currentUser: state.app.currentUser,
|
||||
locale: state.locale.locale,
|
||||
mainColor: state.app.mainColor,
|
||||
directories: state.directories
|
||||
};
|
||||
return {
|
||||
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,
|
||||
})
|
||||
};
|
||||
return {
|
||||
init: () => dispatch({ type: 'INIT' }),
|
||||
initUsers: () => dispatch({ type: 'INIT_USERS' }),
|
||||
initFormularies: () => dispatch({ type: 'INIT_FORMS' }),
|
||||
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,
|
||||
txtStep: '',
|
||||
downloadProgress: 0,
|
||||
downloadingFile: false,
|
||||
processing: false,
|
||||
newApp: false,
|
||||
forced: false
|
||||
state = {
|
||||
progress: 0,
|
||||
txtStep: '',
|
||||
downloadProgress: 0,
|
||||
downloadingFile: false,
|
||||
processing: false,
|
||||
newApp: false,
|
||||
forced: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { forceSync } = this.props.route.params;
|
||||
if (forceSync === true) {
|
||||
this.setState({ forced: true });
|
||||
this.sync();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const fileProgress = this.fileProgress();
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Progress.Circle
|
||||
size={250}
|
||||
progress={this.state.progress}
|
||||
showsText={true}
|
||||
color={this.props.mainColor}
|
||||
/>
|
||||
<View style={styles.btnWrapper}>
|
||||
<Button
|
||||
disabled={this.state.processing}
|
||||
color={this.props.mainColor}
|
||||
title={i18n.t('sync_s.start_sync')}
|
||||
onPress={() => this.sync()}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.btnWrapper}>
|
||||
<Text>
|
||||
{this.state.txtStep} {fileProgress}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
async sync() {
|
||||
let errorStatus = false;
|
||||
|
||||
console.debug('Sync');
|
||||
|
||||
/**
|
||||
* @param {Promise<import('@react-native-community/netinfo').NetInfoState>} promise
|
||||
* @param {(error:any) => void|null} onError
|
||||
*/
|
||||
const getCall = (promise, onError = null) => {
|
||||
if (onError === null) {
|
||||
/** @param {import('axios').AxiosError} error */
|
||||
onError = error => {
|
||||
let message = 'Erreur de la communication serveur';
|
||||
if (error?.response?.status === 422) {
|
||||
message =
|
||||
this.parseValidationErrors(error.response?.data?.errors ?? {}) ||
|
||||
message;
|
||||
console.warn(error.response?.data?.errors ?? {});
|
||||
} else if (error?.response?.status === 419) {
|
||||
// * CSRF TOKEN MISMATCH (On ne pourrais plus faire d'appels AJAX sans recharger la page)
|
||||
message = 'Votre session a expiré, la page va être rechargée';
|
||||
} else if (error?.response?.status === 403) {
|
||||
// * Access denied
|
||||
message = "Vous n'êtes pas autorisé a effectuer cette action";
|
||||
} else {
|
||||
console.error(error);
|
||||
}
|
||||
console.warn(message);
|
||||
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred'),
|
||||
);
|
||||
errorStatus = true;
|
||||
};
|
||||
}
|
||||
return promise.catch(onError);
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { forceSync } = this.props.route.params;
|
||||
if (forceSync === true) {
|
||||
this.setState({ forced: true });
|
||||
this.sync();
|
||||
}
|
||||
const isConnected = await SyncController.checkConnection().catch(
|
||||
error => false,
|
||||
);
|
||||
if (!isConnected) {
|
||||
Alert.alert(
|
||||
i18n.t('global.warning'),
|
||||
i18n.t('error.must_be_connected_internet_sync'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.setState({ processing: true });
|
||||
|
||||
// * --- getVersion
|
||||
const resVersion = await getCall(
|
||||
SyncController.getVersion().then(res => {
|
||||
return res.data;
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
this.props.updateVersion(resVersion.version);
|
||||
this.props.updateShowIsActive(resVersion.ShowIsActive);
|
||||
this.setState({ newApp: resVersion.newApp });
|
||||
|
||||
// * --- getUsers
|
||||
this.setState({
|
||||
progress: 0.1,
|
||||
txtStep: i18n.t('sync_s.updating_users') + '...',
|
||||
});
|
||||
const resUsers = await getCall(
|
||||
SyncController.getUsers().then(res => {
|
||||
User.clear();
|
||||
return res.data;
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resUsers.forEach(user => {
|
||||
User.add(user);
|
||||
});
|
||||
|
||||
// * --- Contacts Sync
|
||||
/*
|
||||
* This is done only for actual app user
|
||||
- 1 Upsert all contacts
|
||||
- 2 Delete contacts where to_delete is true
|
||||
- 3 Get all contacts
|
||||
*/
|
||||
this.setState({
|
||||
progress: 0.2,
|
||||
txtStep: i18n.t('sync_s.updating_contacts') + '...',
|
||||
});
|
||||
|
||||
// * --- Contacts Sync -- STEP 1
|
||||
await getCall(SyncController.upsertContacts(this.props.currentUser.id));
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
const fileProgress = this.fileProgress();
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Progress.Circle
|
||||
size={250}
|
||||
progress={this.state.progress}
|
||||
showsText={true}
|
||||
color={this.props.mainColor}
|
||||
/>
|
||||
<View style={styles.btnWrapper}>
|
||||
<Button
|
||||
disabled={this.state.processing}
|
||||
color={this.props.mainColor}
|
||||
title={i18n.t('sync_s.start_sync')}
|
||||
onPress={() => this.sync()}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.btnWrapper}>
|
||||
<Text>
|
||||
{this.state.txtStep} {fileProgress}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
// * --- Contacts Sync -- STEP 2
|
||||
this.setState({
|
||||
progress: 0.23,
|
||||
});
|
||||
await getCall(SyncController.deleteContacts(this.props.currentUser.id));
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
async sync() {
|
||||
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')
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.setState({ processing: true });
|
||||
// getVersion
|
||||
const resVersion = await SyncController.getVersion().then(res => {
|
||||
return res.data;
|
||||
}).catch(error => {
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred')
|
||||
);
|
||||
errorStatus = true
|
||||
});
|
||||
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') + '...' });
|
||||
const resUsers = await SyncController.getUsers().then(res => {
|
||||
User.clear();
|
||||
return res.data;
|
||||
}).catch(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(this.props.currentUser.id).then(res => {
|
||||
Contact.clear();
|
||||
return res.data;
|
||||
}).catch(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') + '...' });
|
||||
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;
|
||||
// * --- Contacts Sync -- STEP 3
|
||||
this.setState({
|
||||
progress: 0.26,
|
||||
});
|
||||
const resContacts = await getCall(
|
||||
SyncController.getContacts(this.props.currentUser.id).then(res => {
|
||||
// * Clear Contacts, in order to fetch them all after.
|
||||
Contact.clear(this.props.currentUser.id);
|
||||
return res.data;
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
/** @type {(contact: import('./../Models/Contact').ContactData ) => void} */
|
||||
const contactMapper = contact => {
|
||||
// * Stringify complex Fields
|
||||
contact.data = JSON.stringify(contact.data);
|
||||
contact.visits = JSON.stringify(contact.visits);
|
||||
contact.timestamp = new Date(contact.timestamp);
|
||||
Contact.set(contact);
|
||||
};
|
||||
resContacts.forEach(contactMapper);
|
||||
|
||||
// * --- sendBrochures
|
||||
this.setState({
|
||||
progress: 0.3,
|
||||
txtStep: i18n.t('sync_s.sending_flyers') + '...',
|
||||
});
|
||||
const brochures = SendBrochure.getAll();
|
||||
for (const brochure of brochures) {
|
||||
await getCall(
|
||||
SyncController.sendBrochure(brochure).then(res => {
|
||||
SendBrochure.delete(brochure.id);
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// * --- getDirectories
|
||||
this.setState({
|
||||
progress: 0.4,
|
||||
txtStep: i18n.t('sync_s.updating_folders') + '...',
|
||||
});
|
||||
const resDirectories = await getCall(
|
||||
SyncController.getDirectories().then(res => {
|
||||
Directory.clear();
|
||||
return res.data;
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resDirectories.forEach(dir => {
|
||||
Directory.add(dir);
|
||||
});
|
||||
|
||||
// * --- getFormularies
|
||||
this.setState({
|
||||
progress: 0.5,
|
||||
txtStep: i18n.t('sync_s.updating_forms') + '...',
|
||||
});
|
||||
const resFormularies = await getCall(
|
||||
SyncController.getFormularies().then(res => {
|
||||
Form.clear();
|
||||
return res.data;
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resFormularies.forEach(form => Form.add(form));
|
||||
|
||||
// * --- getDocuments
|
||||
this.setState({
|
||||
progress: 0.6,
|
||||
txtStep: i18n.t('sync_s.updating_docs') + '...',
|
||||
});
|
||||
const resDocuments = await getCall(
|
||||
SyncController.getDocuments().then(res => {
|
||||
return res.data;
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
const toDelete = Document.clear(resDocuments);
|
||||
resDocuments.forEach(document => {
|
||||
Document.update(document);
|
||||
});
|
||||
this.downloadDocuments(Document.getAll(), toDelete);
|
||||
|
||||
// * --- End
|
||||
}
|
||||
|
||||
fileProgress() {
|
||||
if (this.state.downloadingFile === true) {
|
||||
return this.state.downloadProgress + ' %';
|
||||
}
|
||||
}
|
||||
|
||||
downloadDocuments(docs, toDelete) {
|
||||
const version = this.props.syncVersion;
|
||||
this.getToDL(docs, 0).then(toDownload => {
|
||||
if (toDownload.length > 0) {
|
||||
this.setState({ progress: 0.6 });
|
||||
const docProgress = 0.4 / toDownload.length;
|
||||
this.download(toDownload, docProgress, 0).then(status => {
|
||||
if (status === true) {
|
||||
this.deleteFile(toDelete, 0).then(delStatus => {
|
||||
this.finishSync(version);
|
||||
});
|
||||
}
|
||||
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 => {
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred')
|
||||
);
|
||||
errorStatus = true
|
||||
} else {
|
||||
this.setState({
|
||||
txtStep: i18n.t('error.error_has_occurred') + '.',
|
||||
});
|
||||
}
|
||||
});
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resDirectories.forEach(dir => {
|
||||
Directory.add(dir);
|
||||
} else {
|
||||
this.deleteFile(toDelete, 0).then(status => {
|
||||
this.setState({ progress: 1 });
|
||||
this.finishSync(version);
|
||||
});
|
||||
// getDocuments
|
||||
this.setState({ progress: 0.4, txtStep: i18n.t('sync_s.updating_docs') + '...' });
|
||||
const resDocuments = await SyncController.getDocuments().then(res => {
|
||||
return res.data;
|
||||
}).catch(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(Document.getAll(), toDelete);
|
||||
// End
|
||||
this.setState({ txtStep: i18n.t('sync_s.update_completed') + '.', processing: false });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fileProgress() {
|
||||
if (this.state.downloadingFile === true) {
|
||||
return this.state.downloadProgress + ' %';
|
||||
}
|
||||
async getToDL(docs, i, toDL = []) {
|
||||
if (docs.length < 1) {
|
||||
return toDL;
|
||||
}
|
||||
|
||||
downloadDocuments(docs, toDelete) {
|
||||
const version = this.props.syncVersion;
|
||||
this.getToDL(docs, 0).then(toDownload => {
|
||||
if (toDownload.length > 0) {
|
||||
this.setState({ progress: 0.5 });
|
||||
const docProgress = 0.5 / toDownload.length;
|
||||
this.download(toDownload, docProgress, 0).then(status => {
|
||||
if (status === true) {
|
||||
this.deleteFile(toDelete, 0).then(status => {
|
||||
this.finishSync(version);
|
||||
});
|
||||
} else {
|
||||
this.setState({ txtStep: i18n.t('error.error_has_occurred') + '.' });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.deleteFile(toDelete, 0).then(status => {
|
||||
this.setState({ progress: 1 });
|
||||
this.finishSync(version);
|
||||
});
|
||||
}
|
||||
});
|
||||
const item = docs[i];
|
||||
const { exists, modificationTime } = await FileSystem.getInfoAsync(
|
||||
FileSystem.documentDirectory + item.uuid + '.' + item.type,
|
||||
);
|
||||
if (exists === false) {
|
||||
toDL.push(item);
|
||||
} else {
|
||||
if (modificationTime.toString() !== item.updated_at) {
|
||||
toDL.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
async getToDL(docs, i, toDL = []) {
|
||||
if (docs.length < 1)
|
||||
return toDL;
|
||||
const item = docs[i];
|
||||
const { exists, modificationTime } = await FileSystem.getInfoAsync(FileSystem.documentDirectory + item.uuid + '.' + item.type);
|
||||
if (exists === false) {
|
||||
toDL.push(item);
|
||||
} else {
|
||||
if (modificationTime.toString() !== item.updated_at) {
|
||||
toDL.push(item);
|
||||
}
|
||||
}
|
||||
if (i < docs.length - 1) {
|
||||
return this.getToDL(docs, i + 1, toDL);
|
||||
}
|
||||
return toDL;
|
||||
if (i < docs.length - 1) {
|
||||
return this.getToDL(docs, i + 1, toDL);
|
||||
}
|
||||
return toDL;
|
||||
}
|
||||
|
||||
async deleteFile(docs, i) {
|
||||
if (docs.length > 0) {
|
||||
const file = docs[i];
|
||||
await FileSystem.deleteAsync(FileSystem.documentDirectory + file.uuid + '.' + file.type, { idempotent: true });
|
||||
if (i < docs.length - 1) {
|
||||
return this.deleteFile(docs, i + 1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
async deleteFile(docs, i) {
|
||||
if (docs.length > 0) {
|
||||
const file = docs[i];
|
||||
await FileSystem.deleteAsync(
|
||||
FileSystem.documentDirectory + file.uuid + '.' + file.type,
|
||||
{ idempotent: true },
|
||||
);
|
||||
if (i < docs.length - 1) {
|
||||
return this.deleteFile(docs, i + 1);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
callback(downloadProgress) {
|
||||
let progress =
|
||||
(downloadProgress.totalBytesWritten /
|
||||
downloadProgress.totalBytesExpectedToWrite) *
|
||||
100;
|
||||
progress = Math.round(progress);
|
||||
progress = progress.toString();
|
||||
this.setState({
|
||||
downloadProgress: progress,
|
||||
});
|
||||
callback(downloadProgress) {
|
||||
let progress =
|
||||
(downloadProgress.totalBytesWritten /
|
||||
downloadProgress.totalBytesExpectedToWrite) *
|
||||
100;
|
||||
progress = Math.round(progress);
|
||||
progress = progress.toString();
|
||||
this.setState({
|
||||
downloadProgress: progress,
|
||||
});
|
||||
}
|
||||
|
||||
downloadResumable(url, uuid, type) {
|
||||
return FileSystem.createDownloadResumable(
|
||||
url,
|
||||
FileSystem.documentDirectory + uuid + '.' + type,
|
||||
{},
|
||||
this.callback.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
async download(documents, progress, i) {
|
||||
if (this.state.downloadingFile === false) {
|
||||
this.setState({ downloadingFile: true });
|
||||
}
|
||||
|
||||
downloadResumable(url, uuid, type) {
|
||||
return FileSystem.createDownloadResumable(
|
||||
url,
|
||||
FileSystem.documentDirectory + uuid + '.' + type,
|
||||
{},
|
||||
this.callback.bind(this),
|
||||
);
|
||||
const endpoint = SyncController.getUrlBo() + '/storage/docs/';
|
||||
const doc = documents[i];
|
||||
this.setState({
|
||||
txtStep:
|
||||
i18n.t('sync_s.download') +
|
||||
' : ' +
|
||||
doc.title +
|
||||
' (' +
|
||||
doc.type.toUpperCase() +
|
||||
') ...',
|
||||
});
|
||||
try {
|
||||
const uri = `${endpoint}${doc.uuid}.${doc.type}`;
|
||||
await this.downloadResumable(
|
||||
endpoint + doc.uuid + '.' + doc.type,
|
||||
doc.uuid,
|
||||
doc.type,
|
||||
).downloadAsync();
|
||||
const { modificationTime } = await FileSystem.getInfoAsync(
|
||||
FileSystem.documentDirectory + doc.uuid + '.' + doc.type,
|
||||
);
|
||||
SyncController.updateLastModificationDoc(doc.id, modificationTime);
|
||||
console.debug('Finished downloading to ', uri);
|
||||
this.setState({ progress: this.state.progress + progress });
|
||||
if (i < documents.length - 1) {
|
||||
return this.download(documents, progress, i + 1);
|
||||
}
|
||||
this.setState({ downloadingFile: false });
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async download(documents, progress, i) {
|
||||
if (this.state.downloadingFile === false) {
|
||||
this.setState({ downloadingFile: true });
|
||||
}
|
||||
const endpoint = SyncController.getUrlBo() + '/storage/docs/'
|
||||
const doc = documents[i];
|
||||
this.setState({
|
||||
txtStep:
|
||||
i18n.t('sync_s.download') + ' : ' +
|
||||
doc.title +
|
||||
' (' +
|
||||
doc.type.toUpperCase() +
|
||||
') ...',
|
||||
});
|
||||
try {
|
||||
await this.downloadResumable(
|
||||
endpoint + doc.uuid + "." + doc.type,
|
||||
doc.uuid,
|
||||
doc.type,
|
||||
).downloadAsync();
|
||||
const { modificationTime } = await FileSystem.getInfoAsync(FileSystem.documentDirectory + doc.uuid + '.' + doc.type);
|
||||
SyncController.updateLastModificationDoc(doc.id, modificationTime);
|
||||
//console.log('Finished downloading to ', uri);
|
||||
this.setState({ progress: this.state.progress + progress });
|
||||
if (i < documents.length - 1) {
|
||||
return this.download(documents, progress, i + 1);
|
||||
}
|
||||
this.setState({ downloadingFile: false });
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false;
|
||||
}
|
||||
finishSync(version) {
|
||||
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();
|
||||
}
|
||||
|
||||
finishSync(version) {
|
||||
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 = SyncController.getAppStoreUUID();
|
||||
const url = 'https://store.ldc.fr' + '/app/' + appUUID;
|
||||
Alert.alert(
|
||||
'LDC Store',
|
||||
i18n.t('sync_s.new_app_version'),
|
||||
[
|
||||
{
|
||||
text: i18n.t('global.cancel'),
|
||||
onPress: () => console.log('Cancel Pressed'),
|
||||
style: 'cancel',
|
||||
},
|
||||
{ text: i18n.t('sync_s.open_store'), onPress: () => Linking.openURL(url).catch((err) => console.error('An error occurred', err)) },
|
||||
],
|
||||
{ cancelable: false },
|
||||
);
|
||||
}
|
||||
SyncController.updateVersion(version);
|
||||
this.setState({
|
||||
txtStep: i18n.t('sync_s.update_completed') + '.',
|
||||
processing: false,
|
||||
});
|
||||
if (this.state.newApp === true) {
|
||||
const appUUID = SyncController.getAppStoreUUID();
|
||||
const url = 'https://store.ldc.fr' + '/app/' + appUUID;
|
||||
Alert.alert(
|
||||
'LDC Store',
|
||||
i18n.t('sync_s.new_app_version'),
|
||||
[
|
||||
{
|
||||
text: i18n.t('global.cancel'),
|
||||
onPress: () => console.debug('Cancel Pressed'),
|
||||
style: 'cancel',
|
||||
},
|
||||
{
|
||||
text: i18n.t('sync_s.open_store'),
|
||||
onPress: () =>
|
||||
Linking.openURL(url).catch(err =>
|
||||
console.error('An error occurred', err),
|
||||
),
|
||||
},
|
||||
],
|
||||
{ cancelable: false },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse error messages for a specific input.
|
||||
*
|
||||
* @param {Record<string, Array<string>>} allErrors
|
||||
* @return {string | null}
|
||||
*/
|
||||
parseValidationErrors(allErrors = {}) {
|
||||
const errorList = Object.values(allErrors);
|
||||
if (!errorList.length) {
|
||||
return null;
|
||||
}
|
||||
return errorList
|
||||
.reduce((oldInputErrors, inputErrors) =>
|
||||
oldInputErrors ? oldInputErrors.concat(inputErrors) : inputErrors,
|
||||
)
|
||||
.reduce(
|
||||
(oldInputString, inputString) =>
|
||||
(oldInputString ? `${oldInputString}, ` : '') + inputString,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SyncScreen);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SyncScreen);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { View, Dimensions } from 'react-native';
|
||||
import { Dimensions, View } from 'react-native';
|
||||
// Reduxs
|
||||
import { connect } from 'react-redux';
|
||||
// FileSytem
|
||||
|
|
@ -7,53 +7,71 @@ import * as FileSystem from 'expo-file-system';
|
|||
// Video
|
||||
import { ResizeMode } from 'expo-av';
|
||||
import VideoPlayer from 'expo-video-player';
|
||||
// Sentry
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
mainColor: state.app.mainColor
|
||||
};
|
||||
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;
|
||||
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 style={{ flex: 1, backgroundColor: 'black' }}>
|
||||
<VideoPlayer
|
||||
defaultControlsVisible={true}
|
||||
fullscreen={{
|
||||
visible: false
|
||||
}}
|
||||
slider={{
|
||||
minimumTrackTintColor: this.props.mainColor,
|
||||
thumbTintColor: this.props.mainColor,
|
||||
}}
|
||||
style={{
|
||||
height: height,
|
||||
width: width
|
||||
}}
|
||||
videoProps={{
|
||||
shouldPlay: true,
|
||||
resizeMode: ResizeMode.CONTAIN,
|
||||
source: {
|
||||
uri: FileSystem.documentDirectory + uuid + '.mp4',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
// * If on portrait
|
||||
if (height > width) {
|
||||
const tmpHeight = height;
|
||||
height = width - 150;
|
||||
width = tmpHeight + 100;
|
||||
} else {
|
||||
height = height - 100;
|
||||
}
|
||||
const videoUri = `${FileSystem.documentDirectory}${uuid}.mp4`;
|
||||
console.debug({
|
||||
shouldPlay: true,
|
||||
resizeMode: ResizeMode.CONTAIN,
|
||||
source: {
|
||||
uri: videoUri,
|
||||
},
|
||||
});
|
||||
try {
|
||||
return (
|
||||
<View style={{ flex: 1, backgroundColor: 'black' }}>
|
||||
<VideoPlayer
|
||||
defaultControlsVisible={true}
|
||||
fullscreen={{
|
||||
visible: false,
|
||||
}}
|
||||
slider={{
|
||||
minimumTrackTintColor: this.props.mainColor,
|
||||
thumbTintColor: this.props.mainColor,
|
||||
}}
|
||||
style={{
|
||||
height: height,
|
||||
width: width,
|
||||
}}
|
||||
videoProps={{
|
||||
shouldPlay: true,
|
||||
resizeMode: ResizeMode.CONTAIN,
|
||||
source: {
|
||||
uri: videoUri,
|
||||
},
|
||||
}}
|
||||
errorCallback={e => {
|
||||
console.error(e);
|
||||
Sentry.captureException(e);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(VideoScreen);
|
||||
export default connect(mapStateToProps)(VideoScreen);
|
||||
|
|
|
|||
|
|
@ -1,29 +1,34 @@
|
|||
import Realm from "realm";
|
||||
|
||||
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: [
|
||||
ContactsSchema,
|
||||
DirectoriesSchema,
|
||||
DocumentsSchema,
|
||||
SendBrochuresSchema,
|
||||
SettingsSchema,
|
||||
UsersSchema
|
||||
],
|
||||
//encryptionKey: new Int8Array(64)
|
||||
};
|
||||
|
||||
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);
|
||||
import Realm from 'realm';
|
||||
|
||||
import ContactModel, { ContactsSchema } from './App/Models/Contact';
|
||||
import DirectoryModel, { DirectoriesSchema } from './App/Models/Directory';
|
||||
import DocumentModel, { DocumentsSchema } from './App/Models/Document';
|
||||
import FormModel, { FormsSchema } from './App/Models/Form';
|
||||
import SendBrochureModel, {
|
||||
SendBrochuresSchema,
|
||||
} from './App/Models/SendBrochure';
|
||||
import SettingModel, { SettingsSchema } from './App/Models/Setting';
|
||||
import UserModel, { UsersSchema } from './App/Models/User';
|
||||
|
||||
const Database = {
|
||||
schema: [
|
||||
ContactsSchema,
|
||||
DirectoriesSchema,
|
||||
DocumentsSchema,
|
||||
SendBrochuresSchema,
|
||||
SettingsSchema,
|
||||
UsersSchema,
|
||||
FormsSchema,
|
||||
],
|
||||
//encryptionKey: new Int8Array(64)
|
||||
};
|
||||
|
||||
let realm = new Realm(Database);
|
||||
|
||||
export const Contact = new ContactModel(realm);
|
||||
export const Directory = new DirectoryModel(realm);
|
||||
export const Document = new DocumentModel(realm);
|
||||
export const SendBrochure = new SendBrochureModel(realm);
|
||||
export const Setting = new SettingModel(realm);
|
||||
export const User = new UserModel(realm);
|
||||
export const Form = new FormModel(realm);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import { I18n } from 'i18n-js';
|
||||
|
||||
import fr from './Resources/Locales/fr';
|
||||
import en from './Resources/Locales/en';
|
||||
import de from './Resources/Locales/de';
|
||||
|
||||
const i18n = new I18n({
|
||||
fr: fr,
|
||||
en: en,
|
||||
de: de
|
||||
});
|
||||
|
||||
i18n.defaultLocale = 'fr';
|
||||
i18n.locale = 'fr';
|
||||
i18n.enableFallback = true;
|
||||
|
||||
export default i18n;
|
||||
import { I18n } from 'i18n-js';
|
||||
|
||||
import de from './Resources/Locales/de';
|
||||
import en from './Resources/Locales/en';
|
||||
import fr from './Resources/Locales/fr';
|
||||
|
||||
const i18n = new I18n({
|
||||
fr: fr,
|
||||
en: en,
|
||||
de: de,
|
||||
});
|
||||
|
||||
i18n.defaultLocale = 'fr';
|
||||
i18n.locale = 'fr';
|
||||
i18n.enableFallback = true;
|
||||
|
||||
export default i18n;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { createNavigationContainerRef } from '@react-navigation/native';
|
||||
|
||||
export const navigationRef = createNavigationContainerRef()
|
||||
export const navigationRef = createNavigationContainerRef();
|
||||
|
||||
export function navigate(name, params) {
|
||||
if (navigationRef.isReady()) {
|
||||
navigationRef.navigate(name, params);
|
||||
}
|
||||
}
|
||||
if (navigationRef.isReady()) {
|
||||
navigationRef.navigate(name, params);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { StyleSheet } from 'react-native';
|
|||
const commonStyles = StyleSheet.create({
|
||||
background: {
|
||||
flex: 1,
|
||||
justifyContent: "center"
|
||||
justifyContent: 'center',
|
||||
},
|
||||
textInput: {
|
||||
height: 40,
|
||||
|
|
@ -12,8 +12,8 @@ const commonStyles = StyleSheet.create({
|
|||
borderWidth: 1,
|
||||
marginBottom: 20,
|
||||
backgroundColor: 'white',
|
||||
paddingLeft: 10
|
||||
}
|
||||
paddingLeft: 10,
|
||||
},
|
||||
});
|
||||
|
||||
export default commonStyles;
|
||||
|
||||
export default commonStyles;
|
||||
|
|
|
|||
|
|
@ -1,118 +1,121 @@
|
|||
{
|
||||
"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",
|
||||
"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": {
|
||||
"username": "Benutzername",
|
||||
"password": "Passwort"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
{
|
||||
"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",
|
||||
"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",
|
||||
"lastname": "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": {
|
||||
"username": "Benutzername",
|
||||
"password": "Passwort"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "Keine Ergebnisse"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Download",
|
||||
"update_completed": "Update abgeschlossen",
|
||||
"updating_docs": "Dokumentaktualisierung",
|
||||
"updating_forms": "Formulare aktualisieren",
|
||||
"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 einen Benutzer aus",
|
||||
"transfer": "weiterleiten",
|
||||
"contact_list": "Kontaktliste",
|
||||
"documents_list": "Liste der Dokumente",
|
||||
"input_required": "Das Feld %{placeholder} ist erforderlich",
|
||||
"input_too_long": "Das Feld %{placeholder} ist zu lang",
|
||||
"input_email": "Das Feld %{placeholder} muss eine gültige E-Mail-Adresse sein"
|
||||
},
|
||||
"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",
|
||||
"description": "Beschreibung",
|
||||
"no_visits": "Kein Besuch",
|
||||
"visit_name": "Besuchsname",
|
||||
"input_select_please_choose": "Wähle einen Wert",
|
||||
"input_select_multiple_search": "Suchen"
|
||||
},
|
||||
"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",
|
||||
"invalid_firstname": "Vorname ist ungültig",
|
||||
"invalid_lastname": "Nachname ist ungültig",
|
||||
"invalid_phone": "Die Telefonnummer ist ungültig",
|
||||
"field_required": "Das Feld %{placeholder} ist erforderlich",
|
||||
"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.",
|
||||
"camera_permission_denied": "Kameraerlaubnis verweigert",
|
||||
"pending_camera_permission": "Warten auf Kameraerlaubnis"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,118 +1,121 @@
|
|||
{
|
||||
"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",
|
||||
"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": {
|
||||
"username": "Username",
|
||||
"password": "Password"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
{
|
||||
"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",
|
||||
"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",
|
||||
"lastname": "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": {
|
||||
"username": "Username",
|
||||
"password": "Password"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "No Result"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Download",
|
||||
"update_completed": "Update Done",
|
||||
"updating_docs": "Updating documents",
|
||||
"updating_forms": "Updating forms",
|
||||
"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 a user",
|
||||
"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",
|
||||
"description": "Description",
|
||||
"no_visits": "No visits available",
|
||||
"visit_name": "visits name",
|
||||
"input_select_please_choose": "Select a value",
|
||||
"input_select_multiple_search": "Search",
|
||||
"input_required": "The %{placeholder} field is required",
|
||||
"input_too_long": "%{placeholder} field is too long",
|
||||
"input_email": "The %{placeholder} field must be a valid email"
|
||||
},
|
||||
"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",
|
||||
"invalid_firstname": "Firstname is not valid",
|
||||
"invalid_lastname": "Lastname is not valid",
|
||||
"invalid_phone": "Phone is not valid",
|
||||
"field_required": "The %{placeholder} field is required",
|
||||
"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",
|
||||
"camera_permission_denied": "Camera Permission Denied",
|
||||
"pending_camera_permission": "Waiting for the camera permission"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,122 +1,125 @@
|
|||
{
|
||||
"install": {
|
||||
"installation": "Installation",
|
||||
"install": "Installer",
|
||||
"enter_url": "Veuillez entrer le lien de votre back-office",
|
||||
"url_invalid": "Le lien saisi est invalide.",
|
||||
"resource_dl_error": "Une erreur est survenue lors du téléchargement de la ressource suivante : ",
|
||||
"install_complete": "Installation terminée !",
|
||||
"get_app_setting": "Récupération de la configuration de l'application",
|
||||
"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",
|
||||
"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": {
|
||||
"username": "Identifiant",
|
||||
"password": "Mot de passe",
|
||||
"missing_users": "Utilisateurs introuvables"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"alert": {
|
||||
"error": "Erreur",
|
||||
"info": "Information"
|
||||
}
|
||||
}
|
||||
{
|
||||
"install": {
|
||||
"installation": "Installation",
|
||||
"install": "Installer",
|
||||
"enter_url": "Veuillez entrer le lien de votre back-office",
|
||||
"url_invalid": "Le lien saisi est invalide.",
|
||||
"resource_dl_error": "Une erreur est survenue lors du téléchargement de la ressource suivante : ",
|
||||
"install_complete": "Installation terminée !",
|
||||
"get_app_setting": "Récupération de la configuration de l'application",
|
||||
"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",
|
||||
"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",
|
||||
"lastname": "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": {
|
||||
"username": "Identifiant",
|
||||
"password": "Mot de passe",
|
||||
"missing_users": "Utilisateurs introuvables"
|
||||
},
|
||||
"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_forms": "Mise à jour des formulaires",
|
||||
"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 un utilisateur",
|
||||
"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",
|
||||
"description": "Description",
|
||||
"no_visits": "Aucune visites",
|
||||
"visit_name": "Nom de la visite",
|
||||
"input_select_please_choose": "Selectionnez un élément",
|
||||
"input_select_multiple_search": "Recherche",
|
||||
"input_required": "Le champ %{placeholder} est obligatoire",
|
||||
"input_too_long": "Le champ %{placeholder} est trop long",
|
||||
"input_email": "Le champ %{placeholder} doit être un email valide"
|
||||
},
|
||||
"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",
|
||||
"invalid_firstname": "Prénom invalide",
|
||||
"invalid_lastname": "Nom invalide",
|
||||
"invalid_phone": "Téléphone invalide",
|
||||
"field_required": "Le champ %{placeholder} est obligatoire",
|
||||
"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",
|
||||
"camera_permission_denied": "Permission caméra refusée",
|
||||
"pending_camera_permission": "En attente de permission caméra"
|
||||
},
|
||||
"alert": {
|
||||
"error": "Erreur",
|
||||
"info": "Information"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,43 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
input: {
|
||||
backgroundColor: 'white',
|
||||
margin: 10,
|
||||
padding: 10,
|
||||
},
|
||||
clearCheckbox: {
|
||||
backgroundColor: '#00000000',
|
||||
borderWidth: 0,
|
||||
},
|
||||
clearRadio: {
|
||||
flex: 1,
|
||||
backgroundColor: '#00000000',
|
||||
borderWidth: 0,
|
||||
},
|
||||
select: {
|
||||
flex: 2,
|
||||
margin: 10,
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
textArea: {
|
||||
flex: 1,
|
||||
margin: 10,
|
||||
padding: 10,
|
||||
backgroundColor: 'white',
|
||||
textAlignVertical: 'top',
|
||||
},
|
||||
button: {
|
||||
width: 35,
|
||||
height: 35,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
margin: 2,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
input: {
|
||||
backgroundColor: 'white',
|
||||
margin: 10,
|
||||
padding: 10,
|
||||
},
|
||||
clearCheckbox: {
|
||||
backgroundColor: '#00000000',
|
||||
borderWidth: 0,
|
||||
},
|
||||
clearRadio: {
|
||||
flex: 1,
|
||||
backgroundColor: '#00000000',
|
||||
borderWidth: 0,
|
||||
},
|
||||
select: {
|
||||
flex: 2,
|
||||
margin: 10,
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
textArea: {
|
||||
flex: 1,
|
||||
margin: 10,
|
||||
padding: 10,
|
||||
backgroundColor: 'white',
|
||||
textAlignVertical: 'top',
|
||||
},
|
||||
button: {
|
||||
width: 35,
|
||||
height: 35,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
margin: 2,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,74 +1,74 @@
|
|||
import { StyleSheet, Dimensions } from 'react-native';
|
||||
import {Dimensions, StyleSheet} from 'react-native';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
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,
|
||||
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'
|
||||
}
|
||||
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,
|
||||
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',
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,36 +1,36 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
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,
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
padding: 5
|
||||
}
|
||||
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,
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
padding: 5,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,39 +1,39 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
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'
|
||||
}
|
||||
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 styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
logo: {
|
||||
width: 150,
|
||||
height: 150,
|
||||
marginBottom: 20
|
||||
},
|
||||
actions: {
|
||||
marginTop: 20
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
logo: {
|
||||
width: 150,
|
||||
height: 150,
|
||||
marginBottom: 20,
|
||||
},
|
||||
actions: {
|
||||
marginTop: 20,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
logo: {
|
||||
width: 150,
|
||||
height: 150,
|
||||
marginBottom: 20
|
||||
},
|
||||
text: {
|
||||
height: 40,
|
||||
width: 300,
|
||||
borderColor: 'grey',
|
||||
borderWidth: 1,
|
||||
marginBottom: 20,
|
||||
backgroundColor: 'white',
|
||||
paddingLeft: 10
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
logo: {
|
||||
width: 150,
|
||||
height: 150,
|
||||
marginBottom: 20,
|
||||
},
|
||||
text: {
|
||||
height: 40,
|
||||
width: 300,
|
||||
borderColor: 'grey',
|
||||
borderWidth: 1,
|
||||
marginBottom: 20,
|
||||
backgroundColor: 'white',
|
||||
paddingLeft: 10,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,38 +1,38 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
searchInput: {
|
||||
borderWidth: 1,
|
||||
width: 200,
|
||||
paddingLeft: 20,
|
||||
searchInput: {
|
||||
borderWidth: 1,
|
||||
width: 200,
|
||||
paddingLeft: 20,
|
||||
},
|
||||
btnSearch: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
drawer: {
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
backgroundColor: '#ffffff',
|
||||
padding: 20,
|
||||
},
|
||||
btnSearch: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
btn: {
|
||||
borderWidth: 1,
|
||||
borderColor: 'black',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: 10,
|
||||
marginBottom: 10,
|
||||
},
|
||||
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
|
||||
},
|
||||
}
|
||||
btnText: {
|
||||
marginLeft: 10,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,33 +1,33 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
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,
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
padding: 5
|
||||
}
|
||||
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,
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
padding: 5,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
import { StyleSheet, Dimensions } from 'react-native';
|
||||
import { Dimensions, StyleSheet } from 'react-native';
|
||||
|
||||
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,
|
||||
},
|
||||
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 styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,33 +1,33 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
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,
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
padding: 5
|
||||
}
|
||||
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,
|
||||
margin: 10,
|
||||
},
|
||||
fileTxt: {
|
||||
textAlign: 'center',
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
padding: 5,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
export default styles;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
btnWrapper: {
|
||||
marginTop: 20
|
||||
}
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
btnWrapper: {
|
||||
marginTop: 20,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
export default styles;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
17042
ComApp/yarn.lock
17042
ComApp/yarn.lock
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue