clean init

This commit is contained in:
Vincent BRIDIER 2022-09-28 15:17:52 +02:00
parent 72ec6fc19d
commit 25a8431861
No known key found for this signature in database
GPG key ID: 8571BFA20420D512
134 changed files with 7196 additions and 43909 deletions

View file

117
ComApp/App.js Normal file
View file

@ -0,0 +1,117 @@
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import React from 'react';
import type {Node} from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
* LTI update could not be added via codemod */
const Section = ({children, title}): Node => {
const isDarkMode = useColorScheme() === 'dark';
return (
<View style={styles.sectionContainer}>
<Text
style={[
styles.sectionTitle,
{
color: isDarkMode ? Colors.white : Colors.black,
},
]}>
{title}
</Text>
<Text
style={[
styles.sectionDescription,
{
color: isDarkMode ? Colors.light : Colors.dark,
},
]}>
{children}
</Text>
</View>
);
};
const App: () => Node = () => {
const isDarkMode = useColorScheme() === 'dark';
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};
return (
<SafeAreaView style={backgroundStyle}>
<StatusBar
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
backgroundColor={backgroundStyle.backgroundColor}
/>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={backgroundStyle}>
<Header />
<View
style={{
backgroundColor: isDarkMode ? Colors.black : Colors.white,
}}>
<Section title="Step One">
Edit <Text style={styles.highlight}>App.js</Text> to change this
screen and then come back to see your edits.
</Section>
<Section title="See Your Changes">
<ReloadInstructions />
</Section>
<Section title="Debug">
<DebugInstructions />
</Section>
<Section title="Learn More">
Read the docs to discover what to do next:
</Section>
<LearnMoreLinks />
</View>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
},
highlight: {
fontWeight: '700',
},
});
export default App;

View file

@ -35,12 +35,12 @@ android_library(
android_build_config(
name = "build_config",
package = "com.awesomeproject",
package = "com.comapp",
)
android_resource(
name = "res",
package = "com.awesomeproject",
package = "com.comapp",
res = "src/main/res",
)

View file

@ -135,7 +135,7 @@ android {
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {
applicationId "com.awesomeproject"
applicationId "com.comapp"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
@ -246,15 +246,6 @@ android {
}
}
packagingOptions {
pickFirst 'lib/x86/libc++_shared.so'
pickFirst 'lib/x86_64/libjsc.so'
pickFirst 'lib/arm64-v8a/libjsc.so'
pickFirst 'lib/arm64-v8a/libc++_shared.so'
pickFirst 'lib/x86_64/libc++_shared.so'
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
}
}
dependencies {

View file

@ -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.awesomeproject;
package com.comapp;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;

View file

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.awesomeproject">
package="com.comapp">
<uses-permission android:name="android.permission.INTERNET" />

View file

@ -1,4 +1,4 @@
package com.awesomeproject;
package com.comapp;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
@ -12,7 +12,7 @@ public class MainActivity extends ReactActivity {
*/
@Override
protected String getMainComponentName() {
return "AwesomeProject";
return "ComApp";
}
/**

View file

@ -1,4 +1,4 @@
package com.awesomeproject;
package com.comapp;
import android.app.Application;
import android.content.Context;
@ -9,7 +9,7 @@ import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.soloader.SoLoader;
import com.awesomeproject.newarchitecture.MainApplicationReactNativeHost;
import com.comapp.newarchitecture.MainApplicationReactNativeHost;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
@ -73,7 +73,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.awesomeproject.ReactNativeFlipper");
Class<?> aClass = Class.forName("com.comapp.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);

View file

@ -1,4 +1,4 @@
package com.awesomeproject.newarchitecture;
package com.comapp.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.awesomeproject.BuildConfig;
import com.awesomeproject.newarchitecture.components.MainComponentsRegistry;
import com.awesomeproject.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
import com.comapp.BuildConfig;
import com.comapp.newarchitecture.components.MainComponentsRegistry;
import com.comapp.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
import java.util.ArrayList;
import java.util.List;

View file

@ -1,4 +1,4 @@
package com.awesomeproject.newarchitecture.components;
package com.comapp.newarchitecture.components;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;

View file

@ -1,4 +1,4 @@
package com.awesomeproject.newarchitecture.modules;
package com.comapp.newarchitecture.modules;
import com.facebook.jni.HybridData;
import com.facebook.react.ReactPackage;
@ -41,7 +41,7 @@ public class MainApplicationTurboModuleManagerDelegate
if (!sIsSoLibraryLoaded) {
// If you change the name of your application .so file in the Android.mk file,
// make sure you update the name here as well.
SoLoader.loadLibrary("awesomeproject_appmodules");
SoLoader.loadLibrary("comapp_appmodules");
sIsSoLibraryLoaded = true;
}
}

View file

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.13)
# Define the library name here.
project(awesomeproject_appmodules)
project(comapp_appmodules)
# This file includes all the necessary to let you build your application with the New Architecture.
include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake)

View file

@ -14,7 +14,7 @@ class MainApplicationTurboModuleManagerDelegate
public:
// Adapt it to the package you used for your Java class.
static constexpr auto kJavaDescriptor =
"Lcom/awesomeproject/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
"Lcom/comapp/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>);

View file

@ -13,7 +13,7 @@ class MainComponentsRegistry
public:
// Adapt it to the package you used for your Java class.
constexpr static auto kJavaDescriptor =
"Lcom/awesomeproject/newarchitecture/components/MainComponentsRegistry;";
"Lcom/comapp/newarchitecture/components/MainComponentsRegistry;";
static void registerNatives();

View file

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 3 KiB

View file

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View file

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 9 KiB

After

Width:  |  Height:  |  Size: 9 KiB

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,3 @@
<resources>
<string name="app_name">ComApp</string>
</resources>

View file

@ -1,4 +1,4 @@
rootProject.name = 'AwesomeProject'
rootProject.name = 'ComApp'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'
includeBuild('../node_modules/react-native-gradle-plugin')

4
ComApp/app.json Normal file
View file

@ -0,0 +1,4 @@
{
"name": "ComApp",
"displayName": "ComApp"
}

View file

@ -3,7 +3,7 @@
*/
import {AppRegistry} from 'react-native';
import App from './src/App';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);

View file

@ -7,12 +7,12 @@
objects = {
/* Begin PBXBuildFile section */
00E356F31AD99517003FC87E /* AwesomeProjectTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* AwesomeProjectTests.m */; };
0C80B921A6F3F58F76C31292 /* libPods-AwesomeProject.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-AwesomeProject.a */; };
00E356F31AD99517003FC87E /* ComAppTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ComAppTests.m */; };
0C80B921A6F3F58F76C31292 /* libPods-ComApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-ComApp.a */; };
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
7699B88040F8A987B510C191 /* libPods-AwesomeProject-AwesomeProjectTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-AwesomeProject-AwesomeProjectTests.a */; };
7699B88040F8A987B510C191 /* libPods-ComApp-ComAppTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-ComApp-ComAppTests.a */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
@ -22,27 +22,27 @@
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = AwesomeProject;
remoteInfo = ComApp;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
00E356EE1AD99517003FC87E /* AwesomeProjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AwesomeProjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356EE1AD99517003FC87E /* ComAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ComAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* AwesomeProjectTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AwesomeProjectTests.m; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* AwesomeProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AwesomeProject.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = AwesomeProject/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = AwesomeProject/AppDelegate.mm; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = AwesomeProject/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = AwesomeProject/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = AwesomeProject/main.m; sourceTree = "<group>"; };
19F6CBCC0A4E27FBF8BF4A61 /* libPods-AwesomeProject-AwesomeProjectTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AwesomeProject-AwesomeProjectTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
3B4392A12AC88292D35C810B /* Pods-AwesomeProject.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AwesomeProject.debug.xcconfig"; path = "Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject.debug.xcconfig"; sourceTree = "<group>"; };
5709B34CF0A7D63546082F79 /* Pods-AwesomeProject.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AwesomeProject.release.xcconfig"; path = "Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject.release.xcconfig"; sourceTree = "<group>"; };
5B7EB9410499542E8C5724F5 /* Pods-AwesomeProject-AwesomeProjectTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AwesomeProject-AwesomeProjectTests.debug.xcconfig"; path = "Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests.debug.xcconfig"; sourceTree = "<group>"; };
5DCACB8F33CDC322A6C60F78 /* libPods-AwesomeProject.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AwesomeProject.a"; sourceTree = BUILT_PRODUCTS_DIR; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = AwesomeProject/LaunchScreen.storyboard; sourceTree = "<group>"; };
89C6BE57DB24E9ADA2F236DE /* Pods-AwesomeProject-AwesomeProjectTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AwesomeProject-AwesomeProjectTests.release.xcconfig"; path = "Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests.release.xcconfig"; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* ComAppTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ComAppTests.m; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* ComApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ComApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ComApp/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = ComApp/AppDelegate.mm; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ComApp/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ComApp/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ComApp/main.m; sourceTree = "<group>"; };
19F6CBCC0A4E27FBF8BF4A61 /* libPods-ComApp-ComAppTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ComApp-ComAppTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
3B4392A12AC88292D35C810B /* Pods-ComApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ComApp.debug.xcconfig"; path = "Target Support Files/Pods-ComApp/Pods-ComApp.debug.xcconfig"; sourceTree = "<group>"; };
5709B34CF0A7D63546082F79 /* Pods-ComApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ComApp.release.xcconfig"; path = "Target Support Files/Pods-ComApp/Pods-ComApp.release.xcconfig"; sourceTree = "<group>"; };
5B7EB9410499542E8C5724F5 /* Pods-ComApp-ComAppTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ComApp-ComAppTests.debug.xcconfig"; path = "Target Support Files/Pods-ComApp-ComAppTests/Pods-ComApp-ComAppTests.debug.xcconfig"; sourceTree = "<group>"; };
5DCACB8F33CDC322A6C60F78 /* libPods-ComApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ComApp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = ComApp/LaunchScreen.storyboard; sourceTree = "<group>"; };
89C6BE57DB24E9ADA2F236DE /* Pods-ComApp-ComAppTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ComApp-ComAppTests.release.xcconfig"; path = "Target Support Files/Pods-ComApp-ComAppTests/Pods-ComApp-ComAppTests.release.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
@ -51,7 +51,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7699B88040F8A987B510C191 /* libPods-AwesomeProject-AwesomeProjectTests.a in Frameworks */,
7699B88040F8A987B510C191 /* libPods-ComApp-ComAppTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -59,20 +59,20 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0C80B921A6F3F58F76C31292 /* libPods-AwesomeProject.a in Frameworks */,
0C80B921A6F3F58F76C31292 /* libPods-ComApp.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
00E356EF1AD99517003FC87E /* AwesomeProjectTests */ = {
00E356EF1AD99517003FC87E /* ComAppTests */ = {
isa = PBXGroup;
children = (
00E356F21AD99517003FC87E /* AwesomeProjectTests.m */,
00E356F21AD99517003FC87E /* ComAppTests.m */,
00E356F01AD99517003FC87E /* Supporting Files */,
);
path = AwesomeProjectTests;
path = ComAppTests;
sourceTree = "<group>";
};
00E356F01AD99517003FC87E /* Supporting Files */ = {
@ -83,7 +83,7 @@
name = "Supporting Files";
sourceTree = "<group>";
};
13B07FAE1A68108700A75B9A /* AwesomeProject */ = {
13B07FAE1A68108700A75B9A /* ComApp */ = {
isa = PBXGroup;
children = (
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
@ -93,15 +93,15 @@
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
13B07FB71A68108700A75B9A /* main.m */,
);
name = AwesomeProject;
name = ComApp;
sourceTree = "<group>";
};
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
5DCACB8F33CDC322A6C60F78 /* libPods-AwesomeProject.a */,
19F6CBCC0A4E27FBF8BF4A61 /* libPods-AwesomeProject-AwesomeProjectTests.a */,
5DCACB8F33CDC322A6C60F78 /* libPods-ComApp.a */,
19F6CBCC0A4E27FBF8BF4A61 /* libPods-ComApp-ComAppTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
@ -116,9 +116,9 @@
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
13B07FAE1A68108700A75B9A /* AwesomeProject */,
13B07FAE1A68108700A75B9A /* ComApp */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
00E356EF1AD99517003FC87E /* AwesomeProjectTests */,
00E356EF1AD99517003FC87E /* ComAppTests */,
83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */,
BBD78D7AC51CEA395F1C20DB /* Pods */,
@ -131,8 +131,8 @@
83CBBA001A601CBA00E9B192 /* Products */ = {
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* AwesomeProject.app */,
00E356EE1AD99517003FC87E /* AwesomeProjectTests.xctest */,
13B07F961A680F5B00A75B9A /* ComApp.app */,
00E356EE1AD99517003FC87E /* ComAppTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@ -140,10 +140,10 @@
BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup;
children = (
3B4392A12AC88292D35C810B /* Pods-AwesomeProject.debug.xcconfig */,
5709B34CF0A7D63546082F79 /* Pods-AwesomeProject.release.xcconfig */,
5B7EB9410499542E8C5724F5 /* Pods-AwesomeProject-AwesomeProjectTests.debug.xcconfig */,
89C6BE57DB24E9ADA2F236DE /* Pods-AwesomeProject-AwesomeProjectTests.release.xcconfig */,
3B4392A12AC88292D35C810B /* Pods-ComApp.debug.xcconfig */,
5709B34CF0A7D63546082F79 /* Pods-ComApp.release.xcconfig */,
5B7EB9410499542E8C5724F5 /* Pods-ComApp-ComAppTests.debug.xcconfig */,
89C6BE57DB24E9ADA2F236DE /* Pods-ComApp-ComAppTests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -151,9 +151,9 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
00E356ED1AD99517003FC87E /* AwesomeProjectTests */ = {
00E356ED1AD99517003FC87E /* ComAppTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "AwesomeProjectTests" */;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ComAppTests" */;
buildPhases = (
A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */,
00E356EA1AD99517003FC87E /* Sources */,
@ -167,14 +167,14 @@
dependencies = (
00E356F51AD99517003FC87E /* PBXTargetDependency */,
);
name = AwesomeProjectTests;
productName = AwesomeProjectTests;
productReference = 00E356EE1AD99517003FC87E /* AwesomeProjectTests.xctest */;
name = ComAppTests;
productName = ComAppTests;
productReference = 00E356EE1AD99517003FC87E /* ComAppTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
13B07F861A680F5B00A75B9A /* AwesomeProject */ = {
13B07F861A680F5B00A75B9A /* ComApp */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "AwesomeProject" */;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ComApp" */;
buildPhases = (
C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */,
@ -189,9 +189,9 @@
);
dependencies = (
);
name = AwesomeProject;
productName = AwesomeProject;
productReference = 13B07F961A680F5B00A75B9A /* AwesomeProject.app */;
name = ComApp;
productName = ComApp;
productReference = 13B07F961A680F5B00A75B9A /* ComApp.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
@ -211,7 +211,7 @@
};
};
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "AwesomeProject" */;
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ComApp" */;
compatibilityVersion = "Xcode 12.0";
developmentRegion = en;
hasScannedForEncodings = 0;
@ -224,8 +224,8 @@
projectDirPath = "";
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* AwesomeProject */,
00E356ED1AD99517003FC87E /* AwesomeProjectTests */,
13B07F861A680F5B00A75B9A /* ComApp */,
00E356ED1AD99517003FC87E /* ComAppTests */,
);
};
/* End PBXProject section */
@ -272,15 +272,15 @@
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-frameworks-${CONFIGURATION}-input-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ComApp/Pods-ComApp-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-frameworks-${CONFIGURATION}-output-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ComApp/Pods-ComApp-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ComApp/Pods-ComApp-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = {
@ -298,7 +298,7 @@
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-AwesomeProject-AwesomeProjectTests-checkManifestLockResult.txt",
"$(DERIVED_FILE_DIR)/Pods-ComApp-ComAppTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -320,7 +320,7 @@
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-AwesomeProject-checkManifestLockResult.txt",
"$(DERIVED_FILE_DIR)/Pods-ComApp-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -333,15 +333,15 @@
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ComApp-ComAppTests/Pods-ComApp-ComAppTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ComApp-ComAppTests/Pods-ComApp-ComAppTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ComApp-ComAppTests/Pods-ComApp-ComAppTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = {
@ -350,15 +350,15 @@
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-resources-${CONFIGURATION}-input-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ComApp/Pods-ComApp-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-resources-${CONFIGURATION}-output-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ComApp/Pods-ComApp-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject/Pods-AwesomeProject-resources.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ComApp/Pods-ComApp-resources.sh\"\n";
showEnvVarsInLog = 0;
};
F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = {
@ -367,15 +367,15 @@
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-resources-${CONFIGURATION}-input-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ComApp-ComAppTests/Pods-ComApp-ComAppTests-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-resources-${CONFIGURATION}-output-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ComApp-ComAppTests/Pods-ComApp-ComAppTests-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AwesomeProject-AwesomeProjectTests/Pods-AwesomeProject-AwesomeProjectTests-resources.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ComApp-ComAppTests/Pods-ComApp-ComAppTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
FD10A7F022414F080027D42C /* Start Packager */ = {
@ -404,7 +404,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
00E356F31AD99517003FC87E /* AwesomeProjectTests.m in Sources */,
00E356F31AD99517003FC87E /* ComAppTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -422,7 +422,7 @@
/* Begin PBXTargetDependency section */
00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 13B07F861A680F5B00A75B9A /* AwesomeProject */;
target = 13B07F861A680F5B00A75B9A /* ComApp */;
targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
@ -430,14 +430,14 @@
/* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-AwesomeProject-AwesomeProjectTests.debug.xcconfig */;
baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-ComApp-ComAppTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = AwesomeProjectTests/Info.plist;
INFOPLIST_FILE = ComAppTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@ -451,17 +451,17 @@
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AwesomeProject.app/AwesomeProject";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ComApp.app/ComApp";
};
name = Debug;
};
00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-AwesomeProject-AwesomeProjectTests.release.xcconfig */;
baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-ComApp-ComAppTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = AwesomeProjectTests/Info.plist;
INFOPLIST_FILE = ComAppTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@ -475,19 +475,19 @@
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AwesomeProject.app/AwesomeProject";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ComApp.app/ComApp";
};
name = Release;
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-AwesomeProject.debug.xcconfig */;
baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-ComApp.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = AwesomeProject/Info.plist;
INFOPLIST_FILE = ComApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -498,7 +498,7 @@
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = AwesomeProject;
PRODUCT_NAME = ComApp;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
@ -507,12 +507,12 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-AwesomeProject.release.xcconfig */;
baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-ComApp.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = AwesomeProject/Info.plist;
INFOPLIST_FILE = ComApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -523,7 +523,7 @@
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = AwesomeProject;
PRODUCT_NAME = ComApp;
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
@ -667,7 +667,7 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "AwesomeProjectTests" */ = {
00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ComAppTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
00E356F61AD99517003FC87E /* Debug */,
@ -676,7 +676,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "AwesomeProject" */ = {
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ComApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13B07F941A680F5B00A75B9A /* Debug */,
@ -685,7 +685,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "AwesomeProject" */ = {
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ComApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
83CBBA201A601CBA00E9B192 /* Debug */,

View file

@ -15,9 +15,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "AwesomeProject.app"
BlueprintName = "AwesomeProject"
ReferencedContainer = "container:AwesomeProject.xcodeproj">
BuildableName = "ComApp.app"
BlueprintName = "ComApp"
ReferencedContainer = "container:ComApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@ -33,9 +33,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
BuildableName = "AwesomeProjectTests.xctest"
BlueprintName = "AwesomeProjectTests"
ReferencedContainer = "container:AwesomeProject.xcodeproj">
BuildableName = "ComAppTests.xctest"
BlueprintName = "ComAppTests"
ReferencedContainer = "container:ComApp.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
@ -55,9 +55,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "AwesomeProject.app"
BlueprintName = "AwesomeProject"
ReferencedContainer = "container:AwesomeProject.xcodeproj">
BuildableName = "ComApp.app"
BlueprintName = "ComApp"
ReferencedContainer = "container:ComApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
@ -72,9 +72,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "AwesomeProject.app"
BlueprintName = "AwesomeProject"
ReferencedContainer = "container:AwesomeProject.xcodeproj">
BuildableName = "ComApp.app"
BlueprintName = "ComApp"
ReferencedContainer = "container:ComApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>

View file

@ -44,7 +44,7 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
#endif
NSDictionary *initProps = [self prepareInitialProps];
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"AwesomeProject", initProps);
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"ComApp", initProps);
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];

View file

@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>AwesomeProject</string>
<string>ComApp</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>

View file

@ -16,7 +16,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="AwesomeProject" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ComApp" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<rect key="frame" x="0.0" y="202" width="375" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<nil key="highlightedColor"/>

View file

@ -7,11 +7,11 @@
#define TIMEOUT_SECONDS 600
#define TEXT_TO_LOOK_FOR @"Welcome to React"
@interface AwesomeProjectTests : XCTestCase
@interface ComAppTests : XCTestCase
@end
@implementation AwesomeProjectTests
@implementation ComAppTests
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test
{

View file

@ -4,7 +4,7 @@ require_relative '../node_modules/@react-native-community/cli-platform-ios/nativ
platform :ios, '12.4'
install! 'cocoapods', :deterministic_uuids => false
target 'AwesomeProject' do
target 'ComApp' do
config = use_native_modules!
# Flags change depending on the env values.
@ -26,7 +26,7 @@ target 'AwesomeProject' do
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
target 'AwesomeProjectTests' do
target 'ComAppTests' do
inherit! :complete
# Pods for testing
end

29
ComApp/package.json Normal file
View file

@ -0,0 +1,29 @@
{
"name": "ComApp",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint ."
},
"dependencies": {
"react": "18.1.0",
"react-native": "0.70.1"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/runtime": "^7.12.5",
"@react-native-community/eslint-config": "^2.0.0",
"babel-jest": "^26.6.3",
"eslint": "^7.32.0",
"jest": "^26.6.3",
"metro-react-native-babel-preset": "^0.72.1",
"react-test-renderer": "18.1.0"
},
"jest": {
"preset": "react-native"
}
}

6922
ComApp/yarn.lock Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,3 +0,0 @@
<resources>
<string name="app_name">AwesomeProject</string>
</resources>

View file

@ -1,4 +0,0 @@
{
"name": "AwesomeProject",
"displayName": "AwesomeProject"
}

38541
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,53 +0,0 @@
{
"name": "AwesomeProject",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint ."
},
"dependencies": {
"@expo/vector-icons": "^13.0.0",
"@react-native-community/netinfo": "^9.3.2",
"@react-navigation/native": "^6.0.13",
"@react-navigation/stack": "^6.3.1",
"axios": "^0.27.2",
"expo-barcode-scanner": "^11.4.0",
"expo-file-system": "^14.1.0",
"expo-video-player": "^2.1.0",
"i18n-js": "^4.1.1",
"react": "18.1.0",
"react-native": "0.70.1",
"react-native-animated-tree-view": "^0.1.4",
"react-native-b-crypt-bridge": "^1.0.0",
"react-native-blob-util": "^0.16.2",
"react-native-elements": "^3.4.2",
"react-native-flash-message": "^0.3.1",
"react-native-gesture-handler": "^2.6.2",
"react-native-pdf": "^6.6.2",
"react-native-progress": "^5.0.0",
"react-native-splash-screen": "^3.3.0",
"react-native-unimodules": "^0.14.10",
"react-native-vector-icons": "^9.2.0",
"react-redux": "^8.0.4",
"realm": "^10.21.1",
"redux": "^4.2.0",
"vcard-parser": "^1.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/runtime": "^7.12.5",
"@react-native-community/eslint-config": "^2.0.0",
"babel-jest": "^26.6.3",
"eslint": "^7.32.0",
"jest": "^26.6.3",
"metro-react-native-babel-preset": "^0.72.1",
"react-test-renderer": "18.1.0"
},
"jest": {
"preset": "react-native"
}
}

View file

@ -1,464 +0,0 @@
import 'react-native-gesture-handler';
import React from 'react';
import {createStore} from 'redux';
import {Provider} from 'react-redux';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import {TouchableOpacity, View, Image, Text, TextInput, StyleSheet, Alert} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome5';
import FlashMessage, {showMessage} from 'react-native-flash-message';
import LoginScreen from './Views/Login';
import HomeScreen from './Views/Home';
import DirectoriesScreen from './Views/Directories';
import VideoScreen from './Views/Video';
import PDFScreen from './Views/PDF';
import SyncScreen from './Views/Sync';
import ContactScreen from './Views/Contact';
import ContactDetailsScreen from './Views/ContactDetails';
import OnlyVideosScreen from './Views/OnlyVideos';
import SearchScreen from "./Views/Search";
import MySpaceScreen from './Views/MySpace';
import UsersModel from './Models/Users';
import DirectoriesModel from './Models/Directories';
import DocumentsModel from './Models/Documents';
import ContactsModel from './Models/Contacts';
import SendBrochureModel from './Models/SendBrochure';
import CommonModel from './Models/Common';
import Sync from './Controllers/Sync';
import Helpers from "./Controllers/Helpers";
import i18n from "./I18n";
const initialState = {
locale: 'fr',
users: {},
directories: {},
documents: {},
contacts: {},
syncVersion: 0,
logged: undefined,
currentUser: {},
currentOpenedDoc: {},
ShowIsActive: 0,
};
function reducer(state = initialState, action) {
//console.log('reducer', state, action);
//console.log('DISPATCH');
switch (action.type) {
case 'INIT':
let docs = DocumentsModel.getAll(DirectoriesModel.getAll(
state.currentUser.role,
state.currentUser.authorizedFolders,
false,
state.locale
));
return {
...state,
users: UsersModel.getAll(),
directories: DirectoriesModel.getAll(
state.currentUser.role,
state.currentUser.authorizedFolders,
true,
state.locale
),
documents: docs.filter(item => item.lang === state.locale),
contacts: ContactsModel.getByUser(state.currentUser.id),
ShowIsActive: CommonModel.get('ShowIsActive')['value'],
};
case 'INIT_USERS':
return {
...state,
users: UsersModel.getAll(),
};
case 'SET_CURRENT_USER':
return {
...state,
currentUser: JSON.parse(action.data),
};
case 'SET_LOGGED':
if (action.data === false) {
CommonModel.delete('isLogged');
}
return {
...state,
logged: action.data,
};
case 'UPDATE_LOCALE':
let nxt;
if (action.data === undefined) {
const availableLocales = ['fr', 'en', 'de'];
if (availableLocales.indexOf(i18n.locale) === availableLocales.length - 1) {
nxt = availableLocales[0];
} else {
nxt = availableLocales[availableLocales.indexOf(i18n.locale) + 1];
}
} else {
nxt = action.data;
}
i18n.locale = nxt;
CommonModel.update({key: 'locale', value: nxt});
let docsL = DocumentsModel.getAll(DirectoriesModel.getAll(
state.currentUser.role,
state.currentUser.authorizedFolders,
false,
nxt
));
return {
...state,
locale: nxt,
directories: DirectoriesModel.getAll(
state.currentUser.role,
state.currentUser.authorizedFolders,
true,
nxt
),
documents: docsL.filter(item => item.lang === nxt),
};
case 'SET_CURRENT_OPENED_DOC':
return {
...state,
currentOpenedDoc: action.data
};
case 'UPDATE_VERSION':
return {
...state,
syncVersion: action.data,
};
case 'UPDATE_SHOW_IS_ACTIVE':
Sync.updateShowIsActive(action.data);
return {
...state,
ShowIsActive: action.data,
};
case 'UPDATE_CONTACT':
ContactsModel.update(action.data);
return {
...state,
contacts: ContactsModel.getByUser(state.currentUser.id),
};
case 'ADD_CONTACT':
ContactsModel.add(action.data);
return {
...state,
contacts: ContactsModel.getByUser(state.currentUser.id),
};
case 'DELETE_CONTACT':
ContactsModel.delete(action.data);
return {
...state,
contacts: ContactsModel.getByUser(state.currentUser.id),
};
case 'SEND_BROCHURE':
SendBrochureModel.add(action.data);
return state;
default:
return state;
}
}
const store = createStore(reducer);
const Stack = createStackNavigator();
store.dispatch({type: 'INIT_USERS'});
class App extends React.Component {
state = {
logged: false,
searchTxt: '',
sendEmail: '',
ShowIsActive: '0'
};
componentDidMount(): void {
const unsubscribe = store.subscribe(this.handleChange.bind(this));
if (Sync.isInstalled() && Sync.isLogged()) {
store.dispatch({
type: 'SET_CURRENT_USER',
data: CommonModel.get('isLogged').value,
});
store.dispatch({type: 'SET_LOGGED', data: true});
}
const savedLocale = CommonModel.get('locale');
if (savedLocale !== undefined && savedLocale !== false) {
store.dispatch({type: 'UPDATE_LOCALE', data: savedLocale.value});
}
}
handleChange() {
const logged = store.getState().logged;
if (logged === false) {
CommonModel.delete('isLogged');
}
if (logged !== undefined) {
this.setState({logged: logged});
}
this.setState({ShowIsActive: store.getState().ShowIsActive});
}
LogoTitle(title) {
return (
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Image
style={{ width: 100, height: 50, resizeMode: 'stretch' }}
source={require('./assets/img/logo.png')}
/>
<Text style={{marginLeft: 10, fontSize: 18}}>{title}</Text>
</View>
);
}
SendEmail() {
return (
<View style={{flexDirection: 'row', alignItems: 'center', marginRight: 10}}>
<TextInput style={styles.searchInput} placeholder={i18n.t('global.email')} value={this.state.sendEmail} onChangeText={(text) => this.setState({sendEmail: text})}/>
<TouchableOpacity style={styles.btnSearch} onPress={() => {
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},
);
}
}
}}>
<Icon name={'paper-plane'} size={20} color={'white'}/>
</TouchableOpacity>
</View>
);
}
render() {
const savedLocale = CommonModel.get('locale');
let locale;
if (savedLocale !== undefined) {
locale = savedLocale.value;
} else {
locale = store.getState().locale;
}
let flag;
switch (locale) {
case "fr":
flag = require('./assets/img/flags/fr.png');
break;
case "en":
flag = require('./assets/img/flags/en.png');
break;
case "de":
flag = require('./assets/img/flags/de.png');
break;
case "es":
flag = require('./assets/img/flags/es.png');
break;
}
return (
<Provider store={store}>
<NavigationContainer>
<Stack.Navigator>
{this.state.logged === false ? (
<Stack.Screen
name="LoginScreen"
component={LoginScreen}
options={(navigation, route) => ({
headerTitle: () => this.LogoTitle(i18n.t('global.login')),
headerRight: () => (
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<TouchableOpacity
onPress={() => {
store.dispatch({type: 'UPDATE_LOCALE'});
this.setState({ state: this.state }); // to force re-rendering
}}
style={{marginRight: 15}}>
<Image source={flag} style={{width: 25, height: 25}}/>
</TouchableOpacity>
</View>
),
})}
/>
) : (
<Stack.Screen
name="HomeScreen"
component={HomeScreen}
options={(navigation, route) => ({
headerTitle: () => this.LogoTitle(i18n.t('global.home')),
headerRight: () => (
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<View style={{flexDirection: 'row', marginRight: 50}}>
<TextInput style={styles.searchInput} placeholder={i18n.t('global.search')} value={this.state.searchTxt} onChangeText={(text) => this.setState({searchTxt: text})}/>
<TouchableOpacity style={styles.btnSearch} onPress={() => {
if (this.state.searchTxt.length > 0) {
navigation.navigation.navigate('SearchScreen', {
needle: this.state.searchTxt,
onlyVideos: false,
});
this.setState({searchTxt: ''});
}
}}>
<Icon name={'search'} size={20} color={'white'}/>
</TouchableOpacity>
</View>
<TouchableOpacity
onPress={() => {
store.dispatch({type: 'UPDATE_LOCALE'});
}}
style={{marginRight: 15}}>
<Image source={flag} style={{width: 25, height: 25}}/>
</TouchableOpacity>
{this.state.ShowIsActive === '1' && (
<TouchableOpacity
onPress={() => navigation.navigation.navigate('MySpaceScreen')}
style={{marginRight: 15}}>
<Icon name="user-circle" size={25} />
</TouchableOpacity>
)}
<TouchableOpacity
onPress={() =>
navigation.navigation.navigate('SyncScreen', {
isInstalled: true,
})
}
style={{marginRight: 15}}>
<Icon name="sync-alt" size={20} />
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
store.dispatch({type: 'SET_LOGGED', data: false});
}}
style={{marginRight: 15}}>
<Icon name="sign-out-alt" size={20} />
</TouchableOpacity>
</View>
),
})}
/>
)}
<Stack.Screen
name="SyncScreen"
component={SyncScreen}
options={{headerTitle: () => this.LogoTitle(i18n.t('global.synchronization'))}}
/>
<Stack.Screen
name="DirectoriesScreen"
component={DirectoriesScreen}
options={{headerTitle: () => this.LogoTitle(i18n.t('app.folders'))}}
/>
<Stack.Screen
name="OnlyVideosScreen"
component={OnlyVideosScreen}
options={(navigation, route) => ({
headerTitle: () => this.LogoTitle(i18n.t('global.videos')),
headerRight: () => (
<View style={{flexDirection: 'row', marginRight: 5}}>
<TextInput style={styles.searchInput} placeholder={i18n.t('global.search')} value={this.state.searchTxt} onChangeText={(text) => this.setState({searchTxt: text})}/>
<TouchableOpacity style={styles.btnSearch} onPress={() => {
if (this.state.searchTxt.length > 0) {
navigation.navigation.navigate('SearchScreen', {
needle: this.state.searchTxt,
onlyVideos: true,
});
this.setState({searchTxt: ''});
}
}}>
<Icon name={'search'} size={20} color={'white'}/>
</TouchableOpacity>
</View>
),
})}
/>
<Stack.Screen
name="VideoScreen"
component={VideoScreen}
options={(navigation, route) => ({
headerTitle: () => this.LogoTitle(i18n.t('app.video')),
headerRight: () => this.SendEmail()
})}
/>
<Stack.Screen
name="PDFScreen"
component={PDFScreen}
options={(navigation, route) => ({
headerTitle: () => this.LogoTitle('PDF'),
headerRight: () => this.SendEmail()
})}
/>
<Stack.Screen
name="ContactScreen"
component={ContactScreen}
options={{headerTitle: () => this.LogoTitle(i18n.t('global.contacts'))}}
initialParams={{contactAdded: false}}
/>
<Stack.Screen
name="ContactDetailsScreen"
component={ContactDetailsScreen}
options={{headerTitle: () => this.LogoTitle(i18n.t('app.contact_details'))}}
/>
<Stack.Screen
name="SearchScreen"
component={SearchScreen}
options={{headerTitle: () => this.LogoTitle(i18n.t('app.results_search'))}}
/>
<Stack.Screen
name="MySpaceScreen"
component={MySpaceScreen}
options={(navigation, route) => ({
headerTitle: () => this.LogoTitle(i18n.t('app.my_space')),
headerRight: () => (
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<TouchableOpacity
onPress={() => {
const folder = store.getState().directories.filter(tmp => tmp.id === 131);
navigation.navigation.navigate('DirectoriesScreen', {folder: folder})
}}
style={{marginRight: 15}}>
<Icon name="briefcase" size={20} />
</TouchableOpacity>
</View>
),
})}
/>
</Stack.Navigator>
<FlashMessage position="top" />
</NavigationContainer>
</Provider>
);
}
}
const styles = StyleSheet.create({
searchInput: {
borderWidth: 1,
borderColor: '#ce3029',
width: 200,
paddingLeft: 20,
},
btnSearch: {
width: 50,
height: 50,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ce3029'
}
});
export default App;

View file

@ -1,47 +0,0 @@
class Helpers {
compareValues(key, order = 'asc') {
return function innerSort(a, b) {
if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
// property doesn't exist on either object
return 0;
}
const varA = (typeof a[key] === 'string')
? a[key].toUpperCase() : a[key];
const varB = (typeof b[key] === 'string')
? b[key].toUpperCase() : b[key];
let comparison = 0;
if (varA > varB) {
comparison = 1;
} else if (varA < varB) {
comparison = -1;
}
return (
(order === 'desc') ? (comparison * -1) : comparison
);
};
}
isEmailValid(email) {
const expression = /(?!.*\.{2})^([a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i;
return expression.test(String(email).toLowerCase());
}
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();

View file

@ -1,270 +0,0 @@
import NetInfo from '@react-native-community/netinfo';
import Constants from 'expo-constants';
const axios = require('axios');
const api_url = 'https://app.maitrecoq.fr';
const api_token = 'Np5smPey2q94HxY8xV27c2TN7C6VpC';
const endpoint = api_url + '/api';
const app_uuid = '1f6eda31-1f6d-49fe-aa81-4f0aece0f7ca';
import UsersModel from '../Models/Users';
import DirectoriesModel from '../Models/Directories';
import DocumentsModel from '../Models/Documents';
import ContactsModel from '../Models/Contacts';
import CommonModel from '../Models/Common';
import SendBrochureModel from '../Models/SendBrochure';
class Sync {
getEndpointDocs() {
return api_url + '/storage/docs/';
}
getApiToken() {
return api_token;
}
getAppUUID() {
return app_uuid;
}
getVersion(callback, errorCallback) {
axios({
method: 'get',
url: endpoint + '/version',
responseType: 'json',
params: {
token: this.getApiToken(),
app_uuid: app_uuid,
app_version: Constants.nativeAppVersion
},
})
.then(response => {
return callback(response.data.version, response.data.ShowIsActive, response.data.newApp);
})
.catch(function(error) {
console.log(error);
return errorCallback(error);
});
}
needSync(callback) {
NetInfo.fetch().then(state => {
if (state.isConnected) {
axios({
method: 'get',
url: endpoint + '/version',
responseType: 'json',
params: {
token: this.getApiToken(),
},
})
.then(response => {
const localVersion = CommonModel.get('version');
if (
localVersion === undefined ||
localVersion === false ||
localVersion.value !== response.data.version
) {
return callback();
}
return false;
})
.catch(function(error) {
console.log(error);
});
}
return false;
});
return false;
}
setInstalled() {
CommonModel.add({key: 'installed', value: '1'});
CommonModel.add({key: 'locale', value: 'fr'});
CommonModel.add({key: 'ShowIsActive', value: '0'});
}
getUsers(callback) {
axios({
method: 'get',
url: endpoint + '/users',
responseType: 'json',
params: {
token: this.getApiToken(),
},
})
.then(response => {
UsersModel.clear();
response.data.forEach(user => {
UsersModel.add(user);
});
console.log('Users Update Done');
return callback();
})
.catch(function(error) {
console.log(error);
});
}
getDirectories(callback) {
axios({
method: 'get',
url: endpoint + '/directories',
responseType: 'json',
params: {
token: this.getApiToken(),
},
})
.then(function(response) {
DirectoriesModel.clear();
response.data.forEach(dir => {
DirectoriesModel.add(dir);
});
console.log('Directories Update Done');
return callback();
})
.catch(function(error) {
console.log(error);
});
}
getDocuments(callback) {
axios({
method: 'get',
url: endpoint + '/documents',
responseType: 'json',
params: {
token: this.getApiToken(),
},
})
.then(response => {
const toDelete = DocumentsModel.clear(response.data);
response.data.forEach(document => {
DocumentsModel.update(document);
});
console.log('Documents Update Done');
return callback(DocumentsModel.getAll(), toDelete);
})
.catch(function(error) {
console.log(error);
});
}
getContacts(callback, userId) {
let contacts = ContactsModel.getAll();
axios({
method: 'post',
url: endpoint + '/contacts' + '?token=' + this.getApiToken(),
responseType: 'json',
data: {
contacts: contacts,
userId: userId,
},
})
.then(response => {
ContactsModel.clear();
response.data.forEach(contact => {
ContactsModel.add(contact);
});
console.log('Contacts Update Done');
callback();
})
.catch(function(error) {
console.log(error);
});
}
async sendBrochure(brochures, i) {
if (brochures.length > 0) {
const item = brochures[i];
let response = await axios({
method: 'post',
url: endpoint + '/sendBrochure',
responseType: 'json',
params: {
token: this.getApiToken(),
emails: {item},
},
});
if (i < brochures.length - 1) {
return this.sendBrochure(brochures, i + 1);
}
return true;
}
return true;
}
sendBrochures(callback) {
this.sendBrochure(SendBrochureModel.getAll(), 0).then(res => {
SendBrochureModel.clear();
console.log('SendBrochures Update Done');
callback();
});
}
updateVersion(version) {
const localVersion = CommonModel.get('version');
if (localVersion === false || localVersion === undefined) {
CommonModel.add({key: 'version', value: version});
} else {
CommonModel.update({id: localVersion.id, key: 'version', value: version});
}
}
updateShowIsActive(value) {
const local = CommonModel.get('ShowIsActive');
if (local === false || local === undefined) {
CommonModel.add({key: 'ShowIsActive', value: value});
} else {
CommonModel.update({id: local.id, key: 'ShowIsActive', value: value});
}
}
isLogged() {
const logged = CommonModel.get('isLogged');
const loggedTime = CommonModel.get('loggedTime');
if (
logged !== false &&
loggedTime !== false &&
logged !== undefined &&
loggedTime !== undefined
) {
let seconds =
Math.abs(new Date(Number(loggedTime.value)) - Date.now()) / 1000;
if (seconds < 14400) {
// 4h
return true;
}
return false;
}
return false;
}
isInstalled() {
const test = CommonModel.get('installed');
if (test === false) {
return false;
}
return true;
}
updateLastModificationDoc(id, date) {
DocumentsModel.update({id: id, updated_at: date.toString()}, true);
}
isSynced() {
const SendBrochure = SendBrochureModel.getAll();
const Contacts = ContactsModel.getAll();
if (SendBrochure !== undefined && Contacts !== undefined) {
const noSynced = Contacts.filtered('synced = false');
if (SendBrochure.length > 0 || noSynced.length > 0) {
return false;
}
}
return true;
}
}
export default new Sync();

View file

@ -1,103 +0,0 @@
const CommonSchema = {
name: 'Common',
primaryKey: 'id',
properties: {
id: 'int',
key: 'string',
value: 'string',
},
};
const UserSchema = {
name: 'Users',
primaryKey: 'id',
properties: {
id: 'int',
email: 'string',
surname: 'string',
firstname: 'string',
password: 'string',
role: 'string',
authorizedFolders: 'string',
},
};
const DirectoriesSchema = {
name: 'Directories',
primaryKey: 'id',
properties: {
id: 'int',
name: 'string',
parent: {type: 'int', optional: true},
order: 'int',
needAuthorization: 'int',
},
};
const DocumentsSchema = {
name: 'Documents',
primaryKey: 'id',
properties: {
id: 'int',
uuid: 'string',
title: 'string',
type: 'string',
path: 'string',
directory: 'int',
lang: 'string',
updated_at: 'string',
},
};
const ContactsSchema = {
name: 'Contacts',
primaryKey: 'id',
properties: {
id: 'int',
email: 'string',
type: 'string',
other: {type: 'string', optional: true},
select1: {type: 'string', optional: true},
select2: {type: 'string', optional: true},
name: 'string',
firstname: 'string',
company: {type: 'string', optional: true},
address: {type: 'string', optional: true},
phone: 'string',
products: {type: 'string', optional: true},
// TODO : card_url ?
notes: {type: 'string', optional: true},
visits: {type: 'string', optional: true},
user_id: 'int',
uniq_id: 'string',
to_delete: {type: 'bool', default: false},
synced: {type: 'bool', default: true},
},
};
const SendBrochureSchema = {
name: 'SendBrochure',
primaryKey: 'id',
properties: {
id: 'int',
email: 'string',
subject: 'string',
message: 'string',
documents: 'string',
user_id: 'int'
},
};
const Database = {
schema: [
CommonSchema,
UserSchema,
DirectoriesSchema,
DocumentsSchema,
ContactsSchema,
SendBrochureSchema,
],
encryptionKey: new Int8Array(64)
};
export default Database;

View file

@ -1,12 +0,0 @@
import i18n from 'i18n-js';
import fr from './Locales/fr';
import en from './Locales/en';
import de from './Locales/de';
i18n.defaultLocale = 'fr';
i18n.locale = 'fr';
i18n.fallbacks = true;
i18n.translations = { fr, en, de };
export default i18n;

View file

@ -1,157 +0,0 @@
{
"global": {
"yes": "Ja",
"no": "Nein",
"home": "Startseite",
"search": "Suche",
"login": "Verbindung",
"email": "Email",
"message_sent": "Email geschickt",
"message_will_be_sent_after_sync": "Die Nachricht wird nach Synchronisation geschickt",
"warning": "Achtung",
"synchronization": "Synchronisation ",
"videos": "Videos",
"contacts": "Kontakt",
"confirmation": "Bestätigung",
"name": "Name",
"firstname": "Vorname",
"address": "Adresse",
"phone": "Telefonnummer",
"company": "Firma",
"add": "Addieren",
"cancel": "Abbrechen",
"subject": "Betreff",
"message": "Nachricht",
"send": "Senden",
"required": "erforderlich",
"save": "Speichern",
"retry": "Noch einmal versuchen",
"next": "Nächstes"
},
"app": {
"file_sharing": " Dateifreigabe",
"folders": "Ordner",
"video": "Video",
"contact_details": "Kontaktdaten",
"results_search": "Suchergebnisse",
"my_space": "Mein Raum"
},
"login_s": {
"install": "Installieren",
"username": "Benutzername",
"password": "Passwort"
},
"home_s": {
"1": "Kataloge",
"2": "Datenblätter",
"3": "Andere"
},
"search_s": {
"no_result": "Keine Ergebnisse"
},
"sync_s": {
"download": "Download",
"update_completed": "Update abgeschlossen",
"updating_docs": "Dokumentaktualisierung",
"updating_folders": "Dateien aktualisieren",
"sending_flyers": "Brochure senden",
"updating_contacts": "Kontakt aktualisieren",
"user_install_completed": "Benutzerinstallation abgeschlossen",
"updating_users": "Benutzer-Update",
"user_install": "Benutzerinstallation",
"start_sync": "Synchronisation starten",
"new_app_version": "Eine neue Version der Anwendung ist verfügbar!",
"open_store": "Öffnen Sie den App Store"
},
"contact_s": {
"contact_transferred": "Kontakt weiterleiten",
"contact_will_be_sent_after_sync": "Der Kontakt wird nach der Synchronisation gesendet",
"confirm_contact_delete": "Möchten Sie diesen Kontakt wirklich löschen?",
"contact_deleted": "Kontakt gelöscht",
"contact_added": "Kontakt hinzugefügt",
"send_flyer": "Senden Sie eine Broschüre",
"select_contact": "Wählen Sie den Kontakt",
"transfer": "weiterleiten",
"contact_list": "Kontaktliste",
"documents_list": "Liste der Dokumente"
},
"contact_details_s": {
"visits": "Besuche",
"notes": "Notes",
"contact_saved": "Kontakt gespeichert",
"confirm_visit_delete": "Sind Sie sicher, dass Sie diesen Besuch löschen möchten?",
"qrcode_not_vcard_format": "Dieser QRCode ist nicht im vCard-Format",
"customer": "Kunde",
"prospect": "potenzieller Kunde",
"other": "Andere",
"description": "Beschreibung",
"no_visits": "Kein Besuch",
"visit_name": "Besuchsname"
},
"error": {
"error": "Fehler ",
"tablet_not_connected_internet": "Das Tablet ist nicht mit dem Internet verbunden.",
"tablet_not_synced_last_user": "Das Tablet wurde vom vorherigen Benutzer nicht synchronisiert",
"incorrect_credentials": "Falsche Anmeldeinformationen",
"must_fill_login_fields": "Sie müssen die Verbindungsfelder ausfüllen",
"invalid_email_address": "Ungültige E-Mail-Adresse",
"error_has_occurred": "Ein Fehler ist aufgetreten",
"must_be_connected_internet_sync": "Sie müssen mit dem Internet verbunden sein, um die Synchronisierung zu starten",
"incomplete_form": "Unvollständiges Formular",
"fill_all_fields_and_1_doc_min": "Bitte füllen Sie alle Felder, mindestens 1 Dokument und eine gültige E-Mail-Adresse aus.",
"fill_other_field": "Füllen Sie das Beschreibungsfeld für: Andere",
"specify_type_contact": "Bitte geben Sie die Art des Kontakts an",
"invalid_name": "ungültiger Name",
"invalid_firstname": "ungültiger Vorname",
"camera_permission_denied": "Kameraerlaubnis verweigert",
"pending_camera_permission": "Warten auf Kameraerlaubnis"
},
"custom": {
"select-1": {
"title": "Type de commerce",
"c1": "Commerce de détail",
"c2": "Home Service / Freezer Center",
"c3": "Restauration service à table",
"c4": "Fast food et snacking",
"c5": "Cafétaria / Self Service",
"c6": "Société de restauration",
"c7": "Restauration gré à gré / cuisine Centrale",
"c8": "Distributeur indépendant",
"c9": "Boulangerie pâtisserie",
"c10": "PAI",
"c11": "Destockeur",
"c12": "Commerce Halal",
"c13": "Restauration d'hébergement",
"c14": "Centrale restauration commerciale",
"c15": "Restauration évenementielle et parc",
"c16": "Restauration de transport",
"c17": "Marché public",
"c18": "Cash",
"c19": "Distributeur national",
"c20": "Rungis",
"c21": "Abbatoir",
"c22": "Autre"
},
"select-2": {
"title": "Site",
"c1": "Celvia Dinde",
"c2": "Celvia Elaborés",
"c3": "Celvia Sérent",
"c4": "Procanar",
"c5": "Celtys",
"c6": "Farmor",
"c7": "Robichon",
"c8": "Les Volailles de Kerana",
"c9": "Bosher Volaille",
"c10": "LDC Bretagne",
"c11": "Doux Farmor",
"c12": "Favreau"
},
"interest": {
"p1": "Poulet",
"p2": "Dinde",
"p3": "Canard",
"p4": "Autre"
}
}
}

View file

@ -1,157 +0,0 @@
{
"global": {
"yes": "Yes",
"no": "No",
"home": "Home",
"search": "Search",
"login": "Login",
"email": "Email",
"message_sent": "Message Sent",
"message_will_be_sent_after_sync": "Message will be send after synchronization",
"warning": "Warning",
"synchronization": "Synchronization",
"videos": "Videos",
"contacts": "Contacts",
"confirmation": "Confirmation",
"name": "Lastname",
"firstname": "Firstname",
"address": "Adress",
"phone": "Phone number",
"company": "Company",
"add": "Add",
"cancel": "Cancel",
"subject": "Object",
"message": "Message",
"send": "Send",
"required": "required",
"save": "Save",
"retry": "Retry",
"next": "Next"
},
"app": {
"file_sharing": "File Sharing",
"folders": "Folders",
"video": "Video",
"contact_details": "Contact information",
"results_search": "Search results",
"my_space": "Personal Dashboard"
},
"login_s": {
"install": "Install",
"username": "Username",
"password": "Password"
},
"home_s": {
"1": "Catalogs",
"2": "Data sheets",
"3": "Others"
},
"search_s": {
"no_result": "No Result"
},
"sync_s": {
"download": "Download",
"update_completed": "Update Done",
"updating_docs": "Updating documents",
"updating_folders": "Updating folders",
"sending_flyers": "Sending documents",
"updating_contacts": "Updating contacts",
"user_install_completed": "User install completed",
"updating_users": "Updating Users",
"user_install": "Installing Users",
"start_sync": "START SYNCHRONIZATION",
"new_app_version": "A new version of the application is available!",
"open_store": "Open the store"
},
"contact_s": {
"contact_transferred": "Contact Transferred",
"contact_will_be_sent_after_sync": "The contact will be sent after synchronization",
"confirm_contact_delete": "Are you sure to delete this contact ?",
"contact_deleted": "Contact deleted",
"contact_added": "Contact added",
"send_flyer": "Send a document",
"select_contact": "Select the contact",
"transfer": "Transfer",
"contact_list": "Contact List",
"documents_list": "Documents List"
},
"contact_details_s": {
"visits": "Visits",
"notes": "Notes",
"contact_saved": "Contact saved",
"confirm_visit_delete": "are you sure to delete this visit ?",
"qrcode_not_vcard_format": "This QRCode is not a VCard",
"customer": "Customer",
"prospect": "Prospect",
"other": "Other",
"description": "Description",
"no_visits": "No visits available",
"visit_name": "visits name"
},
"error": {
"error": "Error",
"tablet_not_connected_internet": "The tablet is not connected to Internet",
"tablet_not_synced_last_user": "The previous user didn't synchronised the tablet",
"incorrect_credentials": "Incorrect Credentials",
"must_fill_login_fields": "You must fill the login fields.",
"invalid_email_address": "Invalid E-mail adress",
"error_has_occurred": "An error occured",
"must_be_connected_internet_sync": "You must be connected to internet to be able to synchronize",
"incomplete_form": "Incomplete Form",
"fill_all_fields_and_1_doc_min": "Please fill up all the fields, at least one document and a valid e-mail adress",
"fill_other_field": "You must fill the description field for : Other",
"specify_type_contact": "You must specify the contact type",
"invalid_name": "Invalid lastname",
"invalid_firstname": "Invalid firstname",
"camera_permission_denied": "Camera Permission Denied",
"pending_camera_permission": "Waiting for the camera permission"
},
"custom": {
"select-1": {
"title": "Type de commerce",
"c1": "Commerce de détail",
"c2": "Home Service / Freezer Center",
"c3": "Restauration service à table",
"c4": "Fast food et snacking",
"c5": "Cafétaria / Self Service",
"c6": "Société de restauration",
"c7": "Restauration gré à gré / cuisine Centrale",
"c8": "Distributeur indépendant",
"c9": "Boulangerie pâtisserie",
"c10": "PAI",
"c11": "Destockeur",
"c12": "Commerce Halal",
"c13": "Restauration d'hébergement",
"c14": "Centrale restauration commerciale",
"c15": "Restauration évenementielle et parc",
"c16": "Restauration de transport",
"c17": "Marché public",
"c18": "Cash",
"c19": "Distributeur national",
"c20": "Rungis",
"c21": "Abbatoir",
"c22": "Autre"
},
"select-2": {
"title": "Site",
"c1": "Celvia Dinde",
"c2": "Celvia Elaborés",
"c3": "Celvia Sérent",
"c4": "Procanar",
"c5": "Celtys",
"c6": "Farmor",
"c7": "Robichon",
"c8": "Les Volailles de Kerana",
"c9": "Bosher Volaille",
"c10": "LDC Bretagne",
"c11": "Doux Farmor",
"c12": "Favreau"
},
"interest": {
"p1": "Poulet",
"p2": "Dinde",
"p3": "Canard",
"p4": "Autre"
}
}
}

View file

@ -1,157 +0,0 @@
{
"global": {
"yes": "Oui",
"no": "Non",
"home": "Accueil",
"search": "Recherche",
"login": "Connexion",
"email": "Email",
"message_sent": "Message envoyé",
"message_will_be_sent_after_sync": "Le message sera envoyé après synchronisation",
"warning": "Attention",
"synchronization": "Synchronisation",
"videos": "Vidéos",
"contacts": "Contacts",
"confirmation": "Confirmation",
"name": "Nom",
"firstname": "Prénom",
"address": "Adresse",
"phone": "Téléphone",
"company": "Société",
"add": "Ajouter",
"cancel": "Annuler",
"subject": "Objet",
"message": "Message",
"send": "Envoyer",
"required": "requis",
"save": "Enregistrer",
"retry": "Réessayer",
"next": "Suivant"
},
"app": {
"file_sharing": "Partage de fichier",
"folders": "Dossiers",
"video": "Vidéo",
"contact_details": "Détails du contact",
"results_search": "Résultat(s) de votre recherche",
"my_space": "Mon espace"
},
"login_s": {
"install": "Installer",
"username": "Identifiant",
"password": "Mot de passe"
},
"home_s": {
"1": "Catalogues",
"2": "Fiches techniques",
"3": "Autres"
},
"search_s": {
"no_result": "Aucun résultat"
},
"sync_s": {
"download": "Téléchargement",
"update_completed": "Mise à jour effectuée",
"updating_docs": "Mise à jour des documents",
"updating_folders": "Mise à jour des dossiers",
"sending_flyers": "Envoi des brochures",
"updating_contacts": "Mise à jour des contacts",
"user_install_completed": "Installation des utilisateurs effectuée",
"updating_users": "Mise à jour des utilisateurs",
"user_install": "Installation des utilisateurs",
"start_sync": "LANCER LA SYNCHRONISATION",
"new_app_version": "Une nouvelle version de l'application est disponible !",
"open_store": "Ouvrir le store"
},
"contact_s": {
"contact_transferred": "Contact transféré",
"contact_will_be_sent_after_sync": "Le contact sera envoyé après synchronisation",
"confirm_contact_delete": "Êtes-vous sûr de vouloir supprimer ce contact ?",
"contact_deleted": "Contact supprimé",
"contact_added": "Contact ajouté",
"send_flyer": "Envoyer une brochure",
"select_contact": "Sélectionnez le contact",
"transfer": "Transférer",
"contact_list": "Liste des contacts",
"documents_list": "Liste des documents"
},
"contact_details_s": {
"visits": "Visites",
"notes": "Notes",
"contact_saved": "Contact enregistré",
"confirm_visit_delete": "Êtes-vous sûr de vouloir supprimer cette visite ?",
"qrcode_not_vcard_format": "Ce QRCode n'est pas au format vCard",
"customer": "Client",
"prospect": "Prospect",
"other": "Autre",
"description": "Description",
"no_visits": "Aucune visites",
"visit_name": "Nom de la visite"
},
"error": {
"error": "Erreur",
"tablet_not_connected_internet": "La tablette n'est pas connectée à internet.",
"tablet_not_synced_last_user": "La tablette n'as pas été synchronisée par l'utilisateur précédent.",
"incorrect_credentials": "Identifiants incorrect.",
"must_fill_login_fields": "Vous devez-remplir les champs de connexion.",
"invalid_email_address": "Adresse email invalide",
"error_has_occurred": "Une erreur est survenue",
"must_be_connected_internet_sync": "Vous devez être connecté à internet pour lancer la synchronisation",
"incomplete_form": "Formulaire incomplet",
"fill_all_fields_and_1_doc_min": "Veuillez remplir tous les champs, 1 document minimum et une adresse email valide",
"fill_other_field": "Vous devez remplir le champs description pour : Autre",
"specify_type_contact": "Vous devez préciser le type de contact",
"invalid_name": "Nom invalide",
"invalid_firstname": "Prénom invalide",
"camera_permission_denied": "Permission caméra refusée",
"pending_camera_permission": "En attente de permission caméra"
},
"custom": {
"select-1": {
"title": "Type de commerce",
"c1": "Commerce de détail",
"c2": "Home Service / Freezer Center",
"c3": "Restauration service à table",
"c4": "Fast food et snacking",
"c5": "Cafétaria / Self Service",
"c6": "Société de restauration",
"c7": "Restauration gré à gré / cuisine Centrale",
"c8": "Distributeur indépendant",
"c9": "Boulangerie pâtisserie",
"c10": "PAI",
"c11": "Destockeur",
"c12": "Commerce Halal",
"c13": "Restauration d'hébergement",
"c14": "Centrale restauration commerciale",
"c15": "Restauration évenementielle et parc",
"c16": "Restauration de transport",
"c17": "Marché public",
"c18": "Cash",
"c19": "Distributeur national",
"c20": "Rungis",
"c21": "Abbatoir",
"c22": "Autre"
},
"select-2": {
"title": "Site",
"c1": "Celvia Dinde",
"c2": "Celvia Elaborés",
"c3": "Celvia Sérent",
"c4": "Procanar",
"c5": "Celtys",
"c6": "Farmor",
"c7": "Robichon",
"c8": "Les Volailles de Kerana",
"c9": "Bosher Volaille",
"c10": "LDC Bretagne",
"c11": "Doux Farmor",
"c12": "Favreau"
},
"interest": {
"p1": "Poulet",
"p2": "Dinde",
"p3": "Canard",
"p4": "Autre"
}
}
}

View file

@ -1,64 +0,0 @@
import Database from '../Database';
const Realm = require('realm');
let realm = new Realm(Database);
class CommonModel {
constructor() {
this.schema = 'Common';
}
add(data) {
realm.write(() => {
if (data.id === undefined) {
let id: any = realm.objects(this.schema).max('id');
data.id = id === undefined ? 1 : id + 1;
}
try {
realm.create(this.schema, data, 'never');
} catch (e) {
console.log('db common add', e);
}
});
}
update(data) {
let tmp = this.get(data.key);
if (tmp === undefined) {
this.add(data);
} else {
if (data.id === undefined) {
data.id = tmp.id;
}
realm.write(() => {
realm.create(this.schema, data, 'modified');
});
}
}
get(key) {
let tmp = realm.objects(this.schema);
if (tmp.length === 0) {
return false;
} else {
tmp = tmp.filtered('key = "' + key + '"')[0];
}
return tmp;
}
getAll() {
let tmp = realm.objects(this.schema);
return tmp;
}
delete(key) {
const tmp = this.get(key);
if (typeof tmp === 'object') {
realm.write(() => {
realm.delete(tmp);
});
}
}
}
export default new CommonModel();

View file

@ -1,60 +0,0 @@
import Database from '../Database';
const Realm = require('realm');
let realm = new Realm(Database);
class ContactsModel {
constructor() {
this.schema = 'Contacts';
}
add(contact) {
contact.uniq_id = contact.id;
contact.id = undefined;
realm.write(() => {
if (contact.id === undefined) {
let id: any = realm.objects(this.schema).max('id');
contact.id = id === undefined ? 1 : id + 1;
}
realm.create(this.schema, contact);
});
}
update(contact) {
realm.write(() => {
realm.create(this.schema, contact, true);
});
}
get(id) {
let tmp = realm.objects(this.schema).filtered('id = ' + id)[0];
return tmp;
}
getAll() {
let tmp = realm.objects(this.schema);
return tmp;
}
getByUser(userId) {
let tmp = realm.objects(this.schema);
tmp = tmp.filtered('to_delete = false AND user_id = ' + userId);
return tmp;
}
delete(id) {
const tmp = this.get(id);
realm.write(() => {
tmp.to_delete = true;
// HARD DELETE - > realm.delete(tmp);
});
}
clear() {
realm.write(() => {
realm.delete(this.getAll());
});
}
}
export default new ContactsModel();

View file

@ -1,104 +0,0 @@
import Database from '../Database';
const Realm = require('realm');
let realm = new Realm(Database);
class DirectoriesModel {
constructor() {
this.schema = 'Directories';
}
add(directory) {
realm.write(() => {
realm.create(this.schema, directory);
});
}
update(directory) {
realm.write(() => {
realm.create(this.schema, directory, true);
});
}
get(id) {
let tmp = realm.objects(this.schema).filtered('id = ' + id)[0];
return tmp;
}
getAll(role, authorizedFolders, format, lang) {
if (authorizedFolders !== null && authorizedFolders !== undefined) {
authorizedFolders = JSON.parse(authorizedFolders);
}
let tmp = realm.objects(this.schema);
if (role === 'USER') {
if (authorizedFolders.length > 0) {
tmp = tmp.filtered(
'needAuthorization = 0 OR ' +
authorizedFolders
.map(folder => ' id = "' + folder.id + '"')
.join(' OR '),
);
} else {
tmp = tmp.filtered(
'needAuthorization = 0'
);
}
}
if (format) {
return this._recursiveDir(tmp, lang);
}
return tmp;
}
clear() {
realm.write(() => {
realm.delete(this.getAll('SYNC', null, false));
});
}
_recursiveDir(list, lang, parent = null) {
let root = list.filter(e => e.parent === parent);
let tmp = [];
for (let i = 0; i < root.length; i++) {
let childs = this._recursiveDir(list, lang, root[i].id);
let name = JSON.parse(root[i].name);
tmp[i] = {};
tmp[i].id = root[i].id;
tmp[i].name = this.getI18nName(lang, name);
tmp[i].items = [];
for (let j = 0; j < childs.length; j++) {
childs[j].value = childs[j].id;
tmp[i].items.push(childs[j]);
}
if (!tmp[i].items.length) {
delete tmp[i].items;
}
}
return tmp;
}
getI18nName(lang, name) {
let tmp = undefined;
switch (lang) {
case "fr":
tmp = name.fr;
break;
case "en":
tmp = name.en;
break;
case "de":
tmp = name.de;
break;
case "es":
tmp = name.es;
break;
}
if (tmp === undefined) {
tmp = name.fr;
}
return tmp;
}
}
export default new DirectoriesModel();

View file

@ -1,68 +0,0 @@
import Database from '../Database';
const Realm = require('realm');
let realm = new Realm(Database);
class DocumentsModel {
constructor() {
this.schema = 'Documents';
}
add(document) {
realm.write(() => {
realm.create(this.schema, document, 'never');
});
}
update(document, updatedAtChange = false) {
let tmp = this.get(document.id);
if (tmp === undefined) {
this.add(document);
} else {
realm.write(() => {
if (updatedAtChange === false) {
realm.create(this.schema, {
id: tmp.id,
uuid: document.uuid,
title: document.title,
type: document.type,
path: document.path,
directory: document.directory
}, 'modified');
} else {
realm.create(this.schema, document, 'modified');
}
});
}
}
get(id) {
let tmp = realm.objects(this.schema).filtered('id = ' + id)[0];
return tmp;
}
getAll(authorizedDirs = false) {
let tmp = realm.objects(this.schema);
if (authorizedDirs) {
authorizedDirs = authorizedDirs.map(item => item.id);
tmp = tmp.filter(doc => authorizedDirs.includes(doc.directory));
}
return tmp;
}
clear(docs, toDelete = []) {
const localDocs = this.getAll();
localDocs.forEach(doc => {
let tmp = docs.filter(item => item.uuid === doc.uuid);
if (tmp.length === 0) {
toDelete.push({uuid: doc.uuid, type: doc.type});
realm.write(() => {
realm.delete(doc);
});
}
});
return toDelete;
}
}
export default new DocumentsModel();

View file

@ -1,49 +0,0 @@
import Database from '../Database';
const Realm = require('realm');
let realm = new Realm(Database);
class SendBrochureModel {
constructor() {
this.schema = 'SendBrochure';
}
add(data) {
realm.write(() => {
if (data.id === undefined) {
let id: any = realm.objects(this.schema).max('id');
data.id = id === undefined ? 1 : id + 1;
}
realm.create(this.schema, data);
});
}
update(data) {
realm.write(() => {
realm.create(this.schema, data, true);
});
}
get(id) {
let tmp = realm.objects(this.schema);
if (tmp.length === 0) {
return false;
} else {
tmp = tmp.filtered('id = ' + id)[0];
}
return tmp;
}
getAll() {
let tmp = realm.objects(this.schema);
return tmp;
}
clear() {
realm.write(() => {
realm.delete(this.getAll());
});
}
}
export default new SendBrochureModel();

View file

@ -1,40 +0,0 @@
import Database from '../Database';
const Realm = require('realm');
let realm = new Realm(Database);
class UsersModel {
constructor() {
this.schema = 'Users';
}
add(user) {
realm.write(() => {
realm.create(this.schema, user);
});
}
update(user) {
realm.write(() => {
realm.create(this.schema, user, true);
});
}
get(id) {
let tmp = realm.objects(this.schema).filtered('id = ' + id)[0];
return tmp;
}
getAll() {
let tmp = realm.objects(this.schema);
return tmp;
}
clear() {
realm.write(() => {
realm.delete(this.getAll());
});
}
}
export default new UsersModel();

View file

@ -1,606 +0,0 @@
import React from 'react';
import {
View,
StyleSheet,
Button,
FlatList,
Text,
Dimensions,
TouchableOpacity,
Alert,
TextInput,
Picker,
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import {connect, ReactReduxContext} from 'react-redux';
import {showMessage} from 'react-native-flash-message';
import {Overlay} from 'react-native-elements';
import Helpers from "../Controllers/Helpers";
import i18n from "../I18n";
function mapStateToProps(state) {
return {
users: state.users,
contacts: state.contacts,
documents: state.documents,
currentUser: state.currentUser,
};
}
class ContactScreen extends React.Component {
state = {
contacts: [],
sortType: 'asc',
sortField: 'name',
searchTxt: '',
showTransferContact: false,
selectedTransferUser: 0,
contactToTransfer: {},
showSendBrochure: false,
selectedDocument: -1,
sendDocumentList: [],
selectedSendBrochureEmail: -1,
tmpSendBrochureEmail: '',
tmpSendBrochureSubject: '',
tmpSendBrochureMessage: '',
sortedDocuments: [],
sortedEmails: [],
};
sendBrochure() {
if (
this.state.tmpSendBrochureEmail !== '' &&
this.state.tmpSendBrochureSubject !== '' &&
this.state.tmpSendBrochureMessage !== '' &&
this.state.sendDocumentList.length > 0 &&
Helpers.isEmailValid(this.state.tmpSendBrochureEmail)
) {
const email = {
email: this.state.tmpSendBrochureEmail,
subject: this.state.tmpSendBrochureSubject,
message: this.state.tmpSendBrochureMessage,
documents: JSON.stringify(this.state.sendDocumentList),
user_id: this.props.currentUser.id
};
this.props.dispatch({type: 'SEND_BROCHURE', data: email});
this.setState({
showSendBrochure: false,
tmpSendBrochureEmail: '',
tmpSendBrochureSubject: '',
tmpSendBrochureMessage: '',
selectedSendBrochureEmail: -1,
selectedDocument: -1,
sendDocumentList: [],
});
showMessage({
message: i18n.t('global.message_sent') + '.',
description: i18n.t('global.message_will_be_sent_after_sync') + '.',
type: 'success',
duration: 1500,
});
} else {
Alert.alert(
i18n.t('error.incomplete_form'),
i18n.t('error.fill_all_fields_and_1_doc_min') + '.',
);
}
}
transferContact() {
const nextUser = this.props.users.filter(user => user.id !== this.props.currentUser.id)[this.state.selectedTransferUser];
const transferContact = this.state.contactToTransfer;
const contact = {
id: transferContact.id,
email: transferContact.email,
type: transferContact.type,
other: transferContact.other,
network: transferContact.network,
name: transferContact.name,
firstname: transferContact.firstname,
office: transferContact.office,
company: transferContact.company,
address: transferContact.address,
phone: transferContact.phone,
products: transferContact.products,
notes: transferContact.note,
visits: transferContact.visits,
to_delete: false,
synced: false,
user_id: nextUser.id,
};
this.props.dispatch({type: 'UPDATE_CONTACT', data: contact});
this.setState({showTransferContact: false});
showMessage({
message: i18n.t('contact_s.contact_transferred') + '.',
description: i18n.t('contact_s.contact_will_be_sent_after_sync') + '.',
type: 'success',
duration: 1500,
});
}
deleteContact(id) {
Alert.alert(
i18n.t('global.confirmation'),
i18n.t('contact_s.confirm_contact_delete'),
[
{
text: i18n.t('global.no'),
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{
text: i18n.t('global.yes'),
onPress: () => {
this.setState({contacts: [], sortedEmails: []});
this.props.dispatch({type: 'DELETE_CONTACT', data: id});
showMessage({
message: i18n.t('contact_s.contact_deleted') + '.',
type: 'success',
duration: 500,
});
},
},
],
{cancelable: false},
);
}
Item(item) {
return (
<View style={styles.item}>
<TouchableOpacity
onPress={() =>
this.props.navigation.navigate('ContactDetailsScreen', {
action: 'edit',
contactId: item.id,
})
}>
<Text style={styles.clickable}>
{item.name.toUpperCase()} {item.firstname}
</Text>
</TouchableOpacity>
<Text style={styles.company}>{item.company}</Text>
<Text style={styles.email}>{item.email}</Text>
<View style={styles.buttons}>
<TouchableOpacity
style={styles.button}
onPress={() => {
this.deleteContact(item.id);
}}>
<Icon name="trash" size={20} color={'#ce3029'}/>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => {
this.setState({
showTransferContact: true,
contactToTransfer: item,
});
}}>
<Icon name="paper-plane" size={20} color={'#ce3029'}/>
</TouchableOpacity>
</View>
</View>
);
}
sortContacts(field) {
let sort;
if (field !== this.state.sortField) {
sort = 'asc';
}else{
if (this.state.sortType === 'asc') {
sort = 'desc';
} else {
sort = 'asc';
}
}
this.setState({contacts: this.state.contacts.sort(Helpers.compareValues(field, sort)), sortType: sort, sortField: field});
}
HeaderItem() {
return (
<View style={styles.item}>
<TouchableOpacity onPress={() => {
this.sortContacts('name');
}}>
<Text style={styles.clickable}>{i18n.t('global.name')} <Icon name={'sort'} /></Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {
this.sortContacts('company');
}}>
<Text style={styles.clickable}>{i18n.t('global.company')} <Icon name={'sort'} /></Text>
</TouchableOpacity>
<Text style={styles.email}>{i18n.t('global.email')}</Text>
<Text style={styles.buttons}/>
</View>
);
}
handleSearchBtn() {
if (this.state.searchTxt.length > 0) {
let obj = this.props.contacts;
let array = Object.keys(obj).map(function (key) { return obj[key]; });
this.setState({contacts: array.sort(Helpers.compareValues('name', 'asc')), sortType: 'asc', searchTxt: ''});
}
}
handleSearchTxt(text) {
this.setState({searchTxt: text});
if (text.length > 0) {
let tmpContactsName = this.props.contacts.filter(item => item.name.toLowerCase().indexOf(text.toLowerCase()) >= 0);
let tmpContactsCompany = this.props.contacts.filter(item => item.company.toLowerCase().indexOf(text.toLowerCase()) >= 0);
let resSearch = Object.assign(tmpContactsName, tmpContactsCompany);
this.setState({contacts: resSearch.sort(Helpers.compareValues('name', 'asc')), sortType: 'asc'});
} else {
let obj = this.props.contacts;
let array = Object.keys(obj).map(function (key) { return obj[key]; });
this.setState({contacts: array.sort(Helpers.compareValues('name', 'asc')), sortType: 'asc'});
}
}
componentDidMount() {
this.init();
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (prevProps.contacts !== this.props.contacts) {
this.init();
}
}
init() {
let objContacts = this.props.contacts;
let objDocs = this.props.documents;
let arrayContacts = Object.keys(objContacts).map(function (key) { return objContacts[key]; });
let arrayEmails = Object.keys(objContacts).map(function (key) { return objContacts[key]; });
let arrayDocs = Object.keys(objDocs).map(function (key) { return objDocs[key]; });
this.setState({
contacts: arrayContacts.sort(Helpers.compareValues('name', 'asc')),
sortedDocuments: arrayDocs.sort(Helpers.compareValues('title', 'asc')),
sortedEmails: arrayEmails.sort(Helpers.compareValues('email', 'asc')),
sortType: 'asc',
sortField: 'name',
});
}
render() {
const {contactAdded} = this.props.route.params;
if (contactAdded === true) {
this.props.navigation.setParams({contactAdded: false});
showMessage({
message: i18n.t('contact_s.contact_added') + '.',
type: 'success',
duration: 500,
});
}
return (
<View style={styles.container}>
<View
style={{
marginTop: 20,
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',
}}>
<Button
color={'#ce3029'}
title={i18n.t('global.add')}
onPress={() =>
this.props.navigation.navigate('ContactDetailsScreen', {
action: 'add',
})
}
/>
<Button
color={'#ce3029'}
title={i18n.t('contact_s.send_flyer')}
onPress={() => this.setState({showSendBrochure: true})}
/>
<View style={{flexDirection: 'row'}}>
<TextInput placeholder={i18n.t('global.search')} style={styles.inputSearch} value={this.state.searchTxt} onChangeText={(text) => this.handleSearchTxt(text)}/>
<TouchableOpacity style={styles.btnSearch} onPress={() => this.handleSearchBtn()}>
{this.state.searchTxt.length > 0 ? (
<Icon name={'times'} size={20} color={'white'}/>
) : (
<Icon name={'search'} size={20} color={'white'}/>
)}
</TouchableOpacity>
</View>
</View>
<View style={{flex: 1, marginTop: 20}}>
<FlatList
data={this.state.contacts}
renderItem={({item}) => this.Item(item)}
ListHeaderComponent={this.HeaderItem.bind(this)}
keyExtractor={item => item.id.toString()}
/>
</View>
<Overlay
isVisible={this.state.showTransferContact}
windowBackgroundColor="rgba(255, 255, 255, .9)"
overlayBackgroundColor="white"
width={400}
height={300}>
<View
style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text style={{marginBottom: 10}}>{i18n.t('contact_s.select_contact')} :</Text>
<Picker
style={{
width: 300,
marginBottom: 15,
paddingLeft: 10,
}}
selectedValue={this.state.selectedTransferUser}
onValueChange={(itemValue, itemIndex) => {
this.setState({selectedTransferUser: itemIndex});
}}>
{this.props.users.filter(user => user.id !== this.props.currentUser.id).map((item, index) => {
return <Picker.Item label={item.email} value={index} key={item.id.toString()} />;
})}
</Picker>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',
width: 400,
}}>
<Button
color={'#ce3029'}
title={i18n.t('global.cancel')}
onPress={() => this.setState({showTransferContact: false})}
/>
<Button
color={'#ce3029'}
title={i18n.t('contact_s.transfer')}
onPress={() => this.transferContact()}
/>
</View>
</View>
</Overlay>
<Overlay
isVisible={this.state.showSendBrochure}
windowBackgroundColor="rgba(255, 255, 255, .9)"
overlayBackgroundColor="white"
width={600}
height={500}>
<View style={{flex: 1}}>
<View style={{flex: 2, flexDirection: 'row'}}>
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'flex-start',
}}>
<TextInput
style={styles.txtSendBrochure}
placeholder={i18n.t('global.email')}
autoCompleteType="email"
autoCapitalize="none"
keyboardType={'email-address'}
value={this.state.tmpSendBrochureEmail}
onChangeText={text =>
this.setState({tmpSendBrochureEmail: text})
}
/>
<Picker
style={{
width: 300,
marginBottom: 15,
paddingLeft: 10,
}}
selectedValue={this.state.selectedSendBrochureEmail}
onValueChange={(itemValue, itemIndex) => {
if (itemValue !== '-1') {
this.setState({
tmpSendBrochureEmail: this.state.sortedEmails[itemIndex - 1]
.email,
});
}
}}>
<Picker.Item label={i18n.t('contact_s.contact_list') + ' :'} value="-1"/>
{this.state.sortedEmails.map((item, index) => {
return <Picker.Item label={item.email} value={index} key={item.id.toString()}/>;
})}
</Picker>
<TextInput
style={styles.txtSendBrochure}
placeholder={i18n.t('global.subject')}
value={this.state.tmpSendBrochureSubject}
onChangeText={text =>
this.setState({tmpSendBrochureSubject: text})
}
/>
<TextInput
style={styles.textAreaSendBrochure}
placeholder={i18n.t('global.message')}
value={this.state.tmpSendBrochureMessage}
multiline={true}
underlineColorAndroid="transparent"
onChangeText={text =>
this.setState({tmpSendBrochureMessage: text})
}
/>
<Picker
style={{
width: 300,
marginBottom: 15,
paddingLeft: 10,
}}
selectedValue={this.state.selectedDocument}
onValueChange={(itemValue, itemIndex) => {
if (
itemValue !== '-1' &&
this.state.sendDocumentList.length < 8
) {
let tmp = this.state.sendDocumentList;
const toPush = this.state.sortedDocuments[itemIndex - 1];
const test = this.state.sendDocumentList.filter(
item => item.id === toPush.id,
);
if (test.length === 0) {
tmp.push(toPush);
this.setState({
sendDocumentList: tmp,
});
}
}
}}>
<Picker.Item label={i18n.t('contact_s.documents_list') + ' :'} value="-1"/>
{this.state.sortedDocuments.map((item, index) => {
return (
<Picker.Item
label={
item.title + ' (' + item.type.toUpperCase() + ')'
}
value={index}
key={item.id.toString()}
/>
);
})}
</Picker>
</View>
<View
style={{
flex: 1,
borderWidth: 1,
borderColor: 'lightgrey',
alignItems: 'center',
justifyContent: 'center',
width: 600,
}}>
{this.state.sendDocumentList.map((item, index) => {
return (
<TouchableOpacity
onPress={() => {
let tmp = this.state.sendDocumentList;
tmp.splice(this.props.documents[index], 1);
this.setState({
sendDocumentList: tmp,
});
}}>
<View
style={{
borderWidth: 1,
borderColor: 'lightgrey',
padding: 5,
margin: 5,
borderRadius: 5,
}}>
<Text>
{item.title} ({item.type.toUpperCase()}){' '}
<Icon name="minus" size={15}/>
</Text>
</View>
</TouchableOpacity>
);
})}
</View>
</View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',
width: 600,
marginTop: 15,
}}>
<Button
color={'#ce3029'}
title={i18n.t('global.cancel')}
onPress={() =>
this.setState({
showSendBrochure: false,
tmpSendBrochureEmail: '',
tmpSendBrochureSubject: '',
tmpSendBrochureMessage: '',
selectedSendBrochureEmail: -1,
selectedDocument: -1,
sendDocumentList: [],
})
}
/>
<Button title={i18n.t('global.send')} onPress={() => this.sendBrochure()} color={'#ce3029'}/>
</View>
</View>
</Overlay>
</View>
);
}
}
const {width} = Dimensions.get('window');
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
item: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
borderBottomWidth: 1,
padding: 15,
marginHorizontal: 15,
},
clickable: {
textAlign: 'center',
fontSize: 18,
width: width / 4,
color: '#ce3029',
fontWeight: 'bold'
},
company: {
textAlign: 'center',
fontSize: 15,
width: width / 4,
},
email: {
textAlign: 'center',
fontSize: 15,
width: width / 4,
},
buttons: {
justifyContent: 'center',
flexDirection: 'row',
fontSize: 15,
width: width / 4,
},
button: {
width: 35,
height: 35,
justifyContent: 'center',
alignItems: 'center',
margin: 2,
},
txtSendBrochure: {
borderWidth: 1,
borderColor: 'lightgrey',
width: 280,
marginBottom: 5,
paddingLeft: 10,
},
textAreaSendBrochure: {
borderWidth: 1,
borderColor: 'lightgrey',
width: 280,
height: 150,
marginBottom: 5,
paddingLeft: 10,
textAlignVertical: 'top',
},
inputSearch: {
backgroundColor: 'white',
width: 200,
paddingLeft: 20
},
btnSearch: {
width: 50,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#ce3029'
}
});
export default connect(mapStateToProps)(ContactScreen);

View file

@ -1,877 +0,0 @@
import React from 'react';
import {
View,
StyleSheet,
Button,
TextInput,
Picker,
TouchableOpacity,
Text,
Alert,
ScrollView
} from 'react-native';
import {CheckBox, ButtonGroup, Overlay} from 'react-native-elements';
import {connect} from 'react-redux';
import Icon from 'react-native-vector-icons/FontAwesome';
import {showMessage} from 'react-native-flash-message';
import Helpers from "../Controllers/Helpers";
import i18n from "../I18n";
import { BarCodeScanner } from 'expo-barcode-scanner';
import vCard from 'vcard-parser';
function mapStateToProps(state) {
return {
contacts: state.contacts,
currentUser: state.currentUser,
};
}
let date = new Date().getDate();
if (date < 10) {
date = '0' + date.toString();
}
let month = new Date().getMonth() + 1;
if (month < 10) {
month = '0' + month.toString();
}
const year = new Date().getFullYear();
class ContactDetailsScreen extends React.Component {
state = {
action: 'add',
visits: [],
selectedVisit: 0,
tmpVisitNote: '',
newVisitTitle: date + '/' + month + '/' + year,
selectedIndex: 0,
showNewVisit: false,
tmpID: 0,
tmpNote: '',
tmpName: '',
tmpFirstname: '',
tmpEmail: '',
tmpCompany: '',
tmpAddress: '',
tmpPhone: '',
tmpSelect1: '',
tmpSelect2: '',
tmpOther: '',
clientChecked: false,
prospectChecked: false,
otherChecked: false,
p1: false,
p2: false,
p3: false,
p4: false,
p5: false,
p6: false,
p7: false,
p8: false,
p9: false,
showQRcodevCard: false,
parsedType: null,
parsedDatas: [],
hasPermission: null,
scanned: false,
showDynContact: false,
parsedName: '',
parsedFirstname: '',
parsedEmail: '',
parsedCompany: '',
parsedAddress: '',
parsedPhone: ''
};
updateContact() {
let error = '';
const {action} = this.props.route.params;
// On récupère le texte courant
if (this.state.visits.length > 0) {
this.state.visits[
this.state.selectedVisit
].note = this.state.tmpVisitNote;
}
let type;
if (this.state.clientChecked === true) {
type = 'client';
} else if (this.state.prospectChecked === true) {
type = 'prospect';
} else if (this.state.otherChecked === true) {
type = 'other';
if (this.state.tmpOther.length === 0) {
error = error.concat(i18n.t('error.fill_other_field') + '.\n');
}
} else {
error = error.concat(i18n.t('error.specify_type_contact') + '.\n');
}
if (this.state.tmpEmail.length < 5 || !Helpers.isEmailValid(this.state.tmpEmail)) {
error = error.concat(i18n.t('error.invalid_email_address') + '.\n');
}
if (this.state.tmpName.length === 0) {
error = error.concat(i18n.t('error.invalid_name') + '.\n');
}
if (this.state.tmpFirstname.length === 0) {
error = error.concat(i18n.t('error.invalid_firstname') + '.\n');
}
if (error.length > 0) {
Alert.alert(i18n.t('global.warning') + ' !', error, [
{text: 'OK'},
],
{cancelable: false},
);
} else {
const products = [
this.state.p1,
this.state.p2,
this.state.p3,
this.state.p4,
this.state.p5,
this.state.p6,
this.state.p7,
this.state.p8,
this.state.p9
];
const contact = {
id: Helpers.generateUUID(),
email: this.state.tmpEmail,
type: type,
other: this.state.tmpOther,
select1: this.state.tmpSelect1,
select2: this.state.tmpSelect2,
name: this.state.tmpName,
firstname: this.state.tmpFirstname,
company: this.state.tmpCompany,
address: this.state.tmpAddress,
phone: this.state.tmpPhone,
products: JSON.stringify(products),
notes: this.state.tmpNote,
visits: JSON.stringify(this.state.visits),
to_delete: false,
synced: false,
};
if (action === 'edit') {
contact.id = this.state.tmpID;
this.props.dispatch({type: 'UPDATE_CONTACT', data: contact});
this.populate();
showMessage({
message: i18n.t('contact_details_s.contact_saved') + '.',
type: 'success',
duration: 500,
});
} else {
contact.user_id = this.props.currentUser.id;
this.props.dispatch({type: 'ADD_CONTACT', data: contact});
this.props.navigation.navigate('ContactScreen', {contactAdded: true});
}
}
}
updateContactType(type) {
if (type === 'client') {
this.setState({
clientChecked: true,
prospectChecked: false,
otherChecked: false,
tmpOther: '',
});
} else if (type === 'prospect') {
this.setState({
clientChecked: false,
prospectChecked: true,
otherChecked: false,
tmpOther: '',
});
} else {
this.setState({
clientChecked: false,
prospectChecked: false,
otherChecked: true,
});
}
}
newVisit() {
this.state.visits.unshift({title: this.state.newVisitTitle, note: ''});
this.state.visits[this.state.selectedVisit].note = this.state.tmpVisitNote;
this.setState({
tmpVisitNote: '',
visits: this.state.visits,
showNewVisit: false,
selectedVisit: 0,
});
}
deleteVisit() {
Alert.alert(
i18n.t('global.confirmation'),
i18n.t('contact_details_s.confirm_visit_delete'),
[
{
text: i18n.t('global.no'),
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{
text: i18n.t('global.yes'),
onPress: () => {
this.state.visits.splice(this.state.selectedVisit, 1);
if (this.state.visits.length === 0) {
this.setState({
visits: this.state.visits,
selectedVisit: 0,
tmpVisitNote: '',
});
} else {
this.setState({
visits: this.state.visits,
selectedVisit: 0,
tmpVisitNote: this.state.visits[0].note,
});
}
},
},
],
{cancelable: false},
);
}
populate() {
const {contactId} = this.props.route.params;
const contact = this.props.contacts.filter(tmp => tmp.id === contactId)[0];
this.setState({
tmpID: contact.id,
tmpNote: contact.notes,
tmpName: contact.name,
tmpFirstname: contact.firstname,
tmpEmail: contact.email,
tmpCompany: contact.company,
tmpAddress: contact.address,
tmpPhone: contact.phone,
tmpSelect1: contact.select1,
tmpSelect2: contact.select2,
tmpOther: contact.other,
tmpProducts: contact.product,
});
if (contact.type === 'client') {
this.setState({clientChecked: true});
} else if (contact.type === 'prospect') {
this.setState({prospectChecked: true});
} else {
this.setState({otherChecked: true});
}
if (contact.visits !== null) {
const tmp = JSON.parse(contact.visits);
this.setState({visits: tmp});
if (tmp.length > 0) {
this.setState({tmpVisitNote: tmp[this.state.selectedVisit].note});
}
}
if (contact.products !== null) {
const tmp = JSON.parse(contact.products);
this.setState({
p1: tmp[0],
p2: tmp[1],
p3: tmp[2],
p4: tmp[3],
p5: tmp[4],
p6: tmp[5],
p7: tmp[6],
p8: tmp[7],
p9: tmp[8],
p10: tmp[9],
});
}
}
componentDidMount() {
const {action} = this.props.route.params;
if (action === 'edit') {
this.setState({action: 'edit'});
this.populate();
}
BarCodeScanner.requestPermissionsAsync().then(res => {
this.setState({hasPermission: res.status === 'granted'});
});
}
render() {
const handleBarCodeScanned = ({ type, data }) => {
this.setState({scanned: true});
if (data.includes('VCARD')) {
let datas = vCard.parse(data);
let tmpDatas = [];
if (datas['n'] !== undefined) {
const nx = Object.assign({n1: [{value: datas['n'][0].value[0]}]}, {n2: [{value: datas['n'][0].value[1]}]});
datas = Object.assign(datas, nx);
}
if (datas['adr'] !== undefined) {
let tmp = datas['adr'][0].value;
let tmpadr = '';
for (let i = 0; i < tmp.length; i++) {
if (tmp[i].length > 0) {
if (tmpadr.length > 0 ) {
tmpadr = tmpadr + ', ' + tmp[i];
} else {
tmpadr = tmp[i];
}
}
}
datas['adr'] = [{value: tmpadr}];
}
Object.keys(datas).map((objectKey, index) => {
if (objectKey === 'email' || objectKey === 'adr' || objectKey === 'tel' || objectKey === 'org' || objectKey === 'n1' || objectKey === 'n2') {
let value = datas[objectKey][0].value;
if (typeof value === 'string') {
tmpDatas.push(value);
}
}
});
this.setState({parsedType: 'vcard', parsedDatas: tmpDatas, showQRcodevCard: false, showDynContact: true})
} else {
Alert.alert(i18n.t('contact_details_s.qrcode_not_vcard_format'));
}
};
return (
<View style={styles.container}>
<ScrollView style={{flex: 1}}>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
}}>
<CheckBox
checkedColor={'#ce3029'}
center
title={i18n.t('contact_details_s.customer')}
checkedIcon="dot-circle-o"
uncheckedIcon="circle-o"
checked={this.state.clientChecked}
containerStyle={styles.clearRadio}
onPress={() => this.updateContactType('client')}
/>
<CheckBox
checkedColor={'#ce3029'}
center
title={i18n.t('contact_details_s.prospect')}
checkedIcon="dot-circle-o"
uncheckedIcon="circle-o"
checked={this.state.prospectChecked}
containerStyle={styles.clearRadio}
onPress={() => this.updateContactType('prospect')}
/>
<CheckBox
checkedColor={'#ce3029'}
center
title={i18n.t('contact_details_s.other')}
checkedIcon="dot-circle-o"
uncheckedIcon="circle-o"
checked={this.state.otherChecked}
containerStyle={styles.clearRadio}
onPress={() => this.updateContactType('other')}
/>
{this.state.otherChecked === true && (
<TextInput
style={{
backgroundColor: 'white',
margin: 10,
padding: 10,
flex: 2,
}}
value={this.state.tmpOther}
placeholder={i18n.t('contact_details_s.description')}
onChangeText={text => this.setState({tmpOther: text})}
/>
)}
</View>
<View style={{flexDirection: 'row'}}>
<TextInput
style={{backgroundColor: 'white', margin: 10, padding: 10, flex: 1}}
value={this.state.tmpName}
placeholder={i18n.t('global.name') + ' (' + i18n.t('global.required') + ')'}
onChangeText={text => this.setState({tmpName: text})}
/>
<TextInput
style={{backgroundColor: 'white', margin: 10, padding: 10, flex: 1}}
value={this.state.tmpFirstname}
placeholder={i18n.t('global.firstname') + ' (' + i18n.t('global.required') + ')'}
onChangeText={text => this.setState({tmpFirstname: text})}
/>
</View>
<TextInput
style={styles.input}
value={this.state.tmpEmail}
placeholder={i18n.t('global.email') + ' (' + i18n.t('global.required') + ')'}
onChangeText={text => this.setState({tmpEmail: text})}
autoCapitalize={'none'}
autoCorrect={false}
keyboardType={'email-address'}
/>
<TextInput
style={styles.input}
value={this.state.tmpCompany}
placeholder={i18n.t('global.company')}
onChangeText={text => this.setState({tmpCompany: text})}
/>
<TextInput
style={styles.input}
value={this.state.tmpAddress}
placeholder={i18n.t('global.address')}
onChangeText={text => this.setState({tmpAddress: text})}
/>
<TextInput
style={styles.input}
value={this.state.tmpPhone}
placeholder={i18n.t('global.phone')}
onChangeText={text => this.setState({tmpPhone: text})}
autoCompleteType={'tel'}
dataDetectorTypes={'phoneNumber'}
keyboardType={'phone-pad'}
/>
<View style={{flexDirection: 'row'}}>
<View style={{flex: 1, flexDirection: 'row'}}>
<Icon name="sort-down" size={20} color={'black'} style={{zIndex: 1, position: 'absolute', right: 25, top: 20}} />
<Picker
selectedValue={this.state.tmpSelect1}
style={styles.select}
onValueChange={(itemValue, itemIndex) => {
if (itemValue !== '0') {
this.setState({tmpSelect1: itemValue});
}
}}>
<Picker.Item label={i18n.t('custom.select-1.title')} value="0" />
<Picker.Item label={i18n.t('custom.select-1.c1')} value="commerce-de-detail" />
<Picker.Item label={i18n.t('custom.select-1.c2')} value={'home-service-freezer-center'} />
<Picker.Item label={i18n.t('custom.select-1.c3')} value={'restauration-service-a-table'} />
<Picker.Item label={i18n.t('custom.select-1.c4')} value={'fast-food-et-snacking'} />
<Picker.Item label={i18n.t('custom.select-1.c5')} value={'cafetaria-self-service'} />
<Picker.Item label={i18n.t('custom.select-1.c6')} value={'societe-de-restauration'} />
<Picker.Item label={i18n.t('custom.select-1.c7')} value={'restauration-gre-a-gre-cuisine-centrale'} />
<Picker.Item label={i18n.t('custom.select-1.c8')} value={'distributeur-independant'} />
<Picker.Item label={i18n.t('custom.select-1.c9')} value={'boulangerie-patisserie'} />
<Picker.Item label={i18n.t('custom.select-1.c10')} value={'pai'} />
<Picker.Item label={i18n.t('custom.select-1.c11')} value={'destockeur'} />
<Picker.Item label={i18n.t('custom.select-1.c12')} value={'commerce-halal'} />
<Picker.Item label={i18n.t('custom.select-1.c13')} value={'restauration-d-hebergement'} />
<Picker.Item label={i18n.t('custom.select-1.c14')} value={'centrale-restauration-commerciale'} />
<Picker.Item label={i18n.t('custom.select-1.c15')} value={'restauration-evenementielle-et-parc'} />
<Picker.Item label={i18n.t('custom.select-1.c16')} value={'restauration-de-transport'} />
<Picker.Item label={i18n.t('custom.select-1.c17')} value={'marche-public'} />
<Picker.Item label={i18n.t('custom.select-1.c18')} value={'cash'} />
<Picker.Item label={i18n.t('custom.select-1.c19')} value={'distributeur-national'} />
<Picker.Item label={i18n.t('custom.select-1.c20')} value={'rungis'} />
<Picker.Item label={i18n.t('custom.select-1.c21')} value={'abbatoir'} />
<Picker.Item label={i18n.t('custom.select-1.c22')} value={'autre'} />
</Picker>
</View>
<View style={{flex: 1, flexDirection: 'row'}}>
<Icon name="sort-down" size={20} color={'black'} style={{zIndex: 1, position: 'absolute', right: 25, top: 20}} />
<Picker
selectedValue={this.state.tmpSelect2}
style={styles.select}
onValueChange={(itemValue, itemIndex) => {
if (itemValue !== '0') {
this.setState({tmpSelect2: itemValue});
}
}}>
<Picker.Item label={i18n.t('custom.select-2.title')} value="0" />
<Picker.Item label={i18n.t('custom.select-2.c1')} value={'celvia-dinde'} />
<Picker.Item label={i18n.t('custom.select-2.c2')} value={'celvia-elabores'} />
<Picker.Item label={i18n.t('custom.select-2.c3')} value={'celvia-serent'} />
<Picker.Item label={i18n.t('custom.select-2.c4')} value={'procanar'} />
<Picker.Item label={i18n.t('custom.select-2.c5')} value={'celtys'} />
<Picker.Item label={i18n.t('custom.select-2.c6')} value={'farmor'} />
<Picker.Item label={i18n.t('custom.select-2.c7')} value={'robichon'} />
<Picker.Item label={i18n.t('custom.select-2.c8')} value={'les-volailles-de-keranna'} />
<Picker.Item label={i18n.t('custom.select-2.c9')} value={'bosher-volaille'} />
<Picker.Item label={i18n.t('custom.select-2.c10')} value={'ldc-bretagne'} />
<Picker.Item label={i18n.t('custom.select-2.c11')} value={'doux-farmor'} />
<Picker.Item label={i18n.t('custom.select-2.c12')} value={'favreau'} />
</Picker>
</View>
</View>
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
}}>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p1')}
checked={this.state.p1}
onPress={() => this.setState({p1: !this.state.p1})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p2')}
checked={this.state.p2}
onPress={() => this.setState({p2: !this.state.p2})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p3')}
checked={this.state.p3}
onPress={() => this.setState({p3: !this.state.p3})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p4')}
checked={this.state.p4}
onPress={() => this.setState({p4: !this.state.p4})}
containerStyle={styles.clearCheckbox}
/>
</View>
</ScrollView>
<View style={{flex: 1, margin: 5}}>
<View style={{flex: 1}}>
<ButtonGroup
buttons={[i18n.t('contact_details_s.visits'), i18n.t('contact_details_s.notes')]}
selectedButtonStyle={{backgroundColor: '#ce3029'}}
containerStyle={{height: 30}}
selectedIndex={this.state.selectedIndex}
onPress={index => this.setState({selectedIndex: index})}
/>
{this.state.selectedIndex === 0 && (
<View style={{flex: 1}}>
<View style={{flexDirection: 'row'}}>
{this.state.visits.length > 0 && (
<View style={{flex: 2, flexDirection: 'row'}}>
<Icon name="sort-down" size={20} color={'black'} style={{zIndex: 1, position: 'absolute', right: 25, top: 20}} />
<Picker
style={styles.select}
selectedValue={this.state.selectedVisit}
onValueChange={(itemValue, itemIndex) => {
this.state.visits[
this.state.selectedVisit
].note = this.state.tmpVisitNote;
this.setState({
visits: this.state.visits,
selectedVisit: itemIndex,
tmpVisitNote: this.state.visits[itemIndex].note,
});
}}>
{this.state.visits.map((item, index) => {
return <Picker.Item label={item.title} value={index} />;
})}
</Picker>
</View>
)}
{this.state.visits.length === 0 && (
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
}}>
<Text>{i18n.t('contact_details_s.no_visits')}.</Text>
</View>
)}
<View
style={{
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-evenly',
margin: 10,
}}>
<TouchableOpacity
style={styles.button}
onPress={() => this.setState({showNewVisit: true})}>
<Icon name="plus-circle" size={20} color={'#ce3029'} />
</TouchableOpacity>
{this.state.visits.length > 0 && (
<TouchableOpacity
style={styles.button}
onPress={() => this.deleteVisit()}>
<Icon name="trash" size={20} color={'#ce3029'} />
</TouchableOpacity>
)}
</View>
</View>
{this.state.visits.length > 0 && (
<TextInput
style={styles.textArea}
underlineColorAndroid="transparent"
placeholder={i18n.t('contact_details_s.notes') + '...'}
placeholderTextColor="grey"
multiline={true}
value={this.state.tmpVisitNote}
onChangeText={text => this.setState({tmpVisitNote: text})}
/>
)}
</View>
)}
{this.state.selectedIndex === 1 && (
<TextInput
style={styles.textArea}
underlineColorAndroid="transparent"
placeholder={i18n.t('contact_details_s.notes') + '...'}
placeholderTextColor="grey"
multiline={true}
value={this.state.tmpNote}
onChangeText={text => this.setState({tmpNote: text})}
/>
)}
</View>
<View style={{flexDirection: 'row', justifyContent: 'space-evenly'}}>
{this.state.action === 'add' && (
<>
<Button title="QRCode vCard" onPress={() => this.setState({showQRcodevCard: true})} color={'#ce3029'} />
</>
)}
<Button title={i18n.t('global.save')} onPress={() => this.updateContact()} color={'#ce3029'} />
</View>
</View>
<Overlay
isVisible={this.state.showNewVisit}
windowBackgroundColor="rgba(255, 255, 255, .9)"
overlayBackgroundColor="white"
width={400}
height={300}>
<View
style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text style={{marginBottom: 10}}>{i18n.t('contact_details_s.visit_name')} :</Text>
<TextInput
placeholder={i18n.t('contact_details_s.visit_name')}
value={this.state.newVisitTitle}
onChangeText={text => this.setState({newVisitTitle: text})}
style={{
borderWidth: 1,
borderColor: 'lightgrey',
width: 300,
marginBottom: 15,
paddingLeft: 10,
}}
/>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',
width: 400,
}}>
<Button
title={i18n.t('global.cancel')}
onPress={() => this.setState({showNewVisit: false})}
color={'#ce3029'}
/>
<Button title={i18n.t('global.add')} onPress={() => this.newVisit()} color={'#ce3029'} />
</View>
</View>
</Overlay>
<Overlay
isVisible={this.state.showQRcodevCard}
windowBackgroundColor="rgba(255, 255, 255, .9)"
overlayBackgroundColor="white"
width={400}
height={300}>
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
{this.state.hasPermission === true && (
<BarCodeScanner
onBarCodeScanned={this.state.scanned ? undefined : handleBarCodeScanned}
barCodeTypes={[BarCodeScanner.Constants.BarCodeType.qr]}
style={{flex: 1, width: 380, height: 200}}
/>
)}
{this.state.hasPermission === false && (
<Text>{i18n.t('error.camera_permission_denied')}.</Text>
)}
{this.state.hasPermission === null && (
<Text>{i18n.t('error.pending_camera_permission')}.</Text>
)}
<View
style={{
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',
width: 400,
}}>
<Button
title={i18n.t('global.cancel')}
onPress={() => this.setState({showQRcodevCard: false, scanned: false})}
color={'#ce3029'}
/>
{this.state.scanned && <Button title={i18n.t('global.retry')} onPress={() => this.setState({scanned: false})} color={'#ce3029'} />}
</View>
</View>
</Overlay>
<Overlay
isVisible={this.state.showDynContact}
windowBackgroundColor="rgba(255, 255, 255, .9)"
overlayBackgroundColor="white"
width={400}
height={400}>
<View style={{flex: 1, alignItems: 'center', justifyContent: 'space-evenly'}}>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.name')}</Text>
<Picker
selectedValue={this.state.parsedName}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) => {
this.setState({parsedName: itemValue});
}}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.firstname')}</Text>
<Picker
selectedValue={this.state.parsedFirstname}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) =>
this.setState({parsedFirstname: itemValue})
}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.email')}</Text>
<Picker
selectedValue={this.state.parsedEmail}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) =>
this.setState({parsedEmail: itemValue})
}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.company')}</Text>
<Picker
selectedValue={this.state.parsedCompany}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) =>
this.setState({parsedCompany: itemValue})
}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.address')}</Text>
<Picker
selectedValue={this.state.parsedAddress}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) =>
this.setState({parsedAddress: itemValue})
}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.phone')}</Text>
<Picker
selectedValue={this.state.parsedPhone}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) =>
this.setState({parsedPhone: itemValue})
}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',
width: 400,
}}>
<Button
title={i18n.t('global.cancel')}
onPress={() => this.setState({showDynContact: false, scanned: false, parsedName: '', parsedFirstname: '', parsedEmail: '', parsedCompany: '', parsedAddress: '', parsedPhone: ''})}
color={'#ce3029'}
/>
<Button
title={i18n.t('global.next')}
onPress={() => this.setState({
tmpName: this.state.parsedName,
tmpFirstname: this.state.parsedFirstname,
tmpEmail: this.state.parsedEmail,
tmpCompany: this.state.parsedCompany,
tmpAddress: this.state.parsedAddress,
tmpPhone: this.state.parsedPhone,
parsedName: '',
parsedFirstname: '',
parsedEmail: '',
parsedCompany: '',
parsedAddress: '',
parsedPhone: '',
showDynContact: false,
scanned: false,
})}
color={'#ce3029'}
/>
</View>
</View>
</Overlay>
</View>
);
}
}
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,
},
});
export default connect(mapStateToProps)(ContactDetailsScreen);

View file

@ -1,892 +0,0 @@
import React from 'react';
import {
View,
StyleSheet,
Button,
TextInput,
Picker,
TouchableOpacity,
Text,
Alert,
ScrollView
} from 'react-native';
import {CheckBox, ButtonGroup, Overlay} from 'react-native-elements';
import {connect} from 'react-redux';
import Icon from 'react-native-vector-icons/FontAwesome';
import {showMessage} from 'react-native-flash-message';
import Helpers from "../Controllers/Helpers";
import i18n from "../I18n";
import { BarCodeScanner } from 'expo-barcode-scanner';
import vCard from 'vcard-parser';
function mapStateToProps(state) {
return {
contacts: state.contacts,
currentUser: state.currentUser,
};
}
let date = new Date().getDate();
if (date < 10) {
date = '0' + date.toString();
}
let month = new Date().getMonth() + 1;
if (month < 10) {
month = '0' + month.toString();
}
const year = new Date().getFullYear();
class ContactDetailsScreen extends React.Component {
state = {
action: 'add',
visits: [],
selectedVisit: 0,
tmpVisitNote: '',
newVisitTitle: date + '/' + month + '/' + year,
selectedIndex: 0,
showNewVisit: false,
tmpID: 0,
tmpNote: '',
tmpName: '',
tmpFirstname: '',
tmpEmail: '',
tmpCompany: '',
tmpAddress: '',
tmpPhone: '',
tmpSelect1: '',
tmpSelect2: '',
tmpOther: '',
clientChecked: false,
prospectChecked: false,
otherChecked: false,
p1: false,
p2: false,
p3: false,
p4: false,
p5: false,
p6: false,
p7: false,
p8: false,
p9: false,
showQRcodevCard: false,
parsedType: null,
parsedDatas: [],
hasPermission: null,
scanned: false,
showDynContact: false,
parsedName: '',
parsedFirstname: '',
parsedEmail: '',
parsedCompany: '',
parsedAddress: '',
parsedPhone: ''
};
updateContact() {
let error = '';
const {action} = this.props.route.params;
// On récupère le texte courant
if (this.state.visits.length > 0) {
this.state.visits[
this.state.selectedVisit
].note = this.state.tmpVisitNote;
}
let type;
if (this.state.clientChecked === true) {
type = 'client';
} else if (this.state.prospectChecked === true) {
type = 'prospect';
} else if (this.state.otherChecked === true) {
type = 'other';
if (this.state.tmpOther.length === 0) {
error = error.concat(i18n.t('error.fill_other_field') + '.\n');
}
} else {
error = error.concat(i18n.t('error.specify_type_contact') + '.\n');
}
if (this.state.tmpEmail.length < 5 || !Helpers.isEmailValid(this.state.tmpEmail)) {
error = error.concat(i18n.t('error.invalid_email_address') + '.\n');
}
if (this.state.tmpName.length === 0) {
error = error.concat(i18n.t('error.invalid_name') + '.\n');
}
if (this.state.tmpFirstname.length === 0) {
error = error.concat(i18n.t('error.invalid_firstname') + '.\n');
}
if (error.length > 0) {
Alert.alert(i18n.t('global.warning') + ' !', error, [
{text: 'OK'},
],
{cancelable: false},
);
} else {
const products = [
this.state.p1,
this.state.p2,
this.state.p3,
this.state.p4,
this.state.p5,
this.state.p6,
this.state.p7,
this.state.p8,
this.state.p9
];
const contact = {
id: Helpers.generateUUID(),
email: this.state.tmpEmail,
type: type,
other: this.state.tmpOther,
select1: this.state.tmpSelect1,
select2: this.state.tmpSelect2,
name: this.state.tmpName,
firstname: this.state.tmpFirstname,
company: this.state.tmpCompany,
address: this.state.tmpAddress,
phone: this.state.tmpPhone,
products: JSON.stringify(products),
notes: this.state.tmpNote,
visits: JSON.stringify(this.state.visits),
to_delete: false,
synced: false,
};
if (action === 'edit') {
contact.id = this.state.tmpID;
this.props.dispatch({type: 'UPDATE_CONTACT', data: contact});
this.populate();
showMessage({
message: i18n.t('contact_details_s.contact_saved') + '.',
type: 'success',
duration: 500,
});
} else {
contact.user_id = this.props.currentUser.id;
this.props.dispatch({type: 'ADD_CONTACT', data: contact});
this.props.navigation.navigate('ContactScreen', {contactAdded: true});
}
}
}
updateContactType(type) {
if (type === 'client') {
this.setState({
clientChecked: true,
prospectChecked: false,
otherChecked: false,
tmpOther: '',
});
} else if (type === 'prospect') {
this.setState({
clientChecked: false,
prospectChecked: true,
otherChecked: false,
tmpOther: '',
});
} else {
this.setState({
clientChecked: false,
prospectChecked: false,
otherChecked: true,
});
}
}
newVisit() {
this.state.visits.unshift({title: this.state.newVisitTitle, note: ''});
this.state.visits[this.state.selectedVisit].note = this.state.tmpVisitNote;
this.setState({
tmpVisitNote: '',
visits: this.state.visits,
showNewVisit: false,
selectedVisit: 0,
});
}
deleteVisit() {
Alert.alert(
i18n.t('global.confirmation'),
i18n.t('contact_details_s.confirm_visit_delete'),
[
{
text: i18n.t('global.no'),
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{
text: i18n.t('global.yes'),
onPress: () => {
this.state.visits.splice(this.state.selectedVisit, 1);
if (this.state.visits.length === 0) {
this.setState({
visits: this.state.visits,
selectedVisit: 0,
tmpVisitNote: '',
});
} else {
this.setState({
visits: this.state.visits,
selectedVisit: 0,
tmpVisitNote: this.state.visits[0].note,
});
}
},
},
],
{cancelable: false},
);
}
populate() {
const {contactId} = this.props.route.params;
const contact = this.props.contacts.filter(tmp => tmp.id === contactId)[0];
this.setState({
tmpID: contact.id,
tmpNote: contact.notes,
tmpName: contact.name,
tmpFirstname: contact.firstname,
tmpEmail: contact.email,
tmpCompany: contact.company,
tmpAddress: contact.address,
tmpPhone: contact.phone,
tmpSelect1: contact.select1,
tmpSelect2: contact.select2,
tmpOther: contact.other,
tmpProducts: contact.product,
});
if (contact.type === 'client') {
this.setState({clientChecked: true});
} else if (contact.type === 'prospect') {
this.setState({prospectChecked: true});
} else {
this.setState({otherChecked: true});
}
if (contact.visits !== null) {
const tmp = JSON.parse(contact.visits);
this.setState({visits: tmp});
if (tmp.length > 0) {
this.setState({tmpVisitNote: tmp[this.state.selectedVisit].note});
}
}
if (contact.products !== null) {
const tmp = JSON.parse(contact.products);
this.setState({
p1: tmp[0],
p2: tmp[1],
p3: tmp[2],
p4: tmp[3],
p5: tmp[4],
p6: tmp[5],
p7: tmp[6],
p8: tmp[7],
p9: tmp[8]
});
}
}
componentDidMount() {
const {action} = this.props.route.params;
if (action === 'edit') {
this.setState({action: 'edit'});
this.populate();
}
BarCodeScanner.requestPermissionsAsync().then(res => {
this.setState({hasPermission: res.status === 'granted'});
});
}
render() {
const handleBarCodeScanned = ({ type, data }) => {
this.setState({scanned: true});
if (data.includes('VCARD')) {
let datas = vCard.parse(data);
let tmpDatas = [];
if (datas['n'] !== undefined) {
const nx = Object.assign({n1: [{value: datas['n'][0].value[0]}]}, {n2: [{value: datas['n'][0].value[1]}]});
datas = Object.assign(datas, nx);
}
if (datas['adr'] !== undefined) {
let tmp = datas['adr'][0].value;
let tmpadr = '';
for (let i = 0; i < tmp.length; i++) {
if (tmp[i].length > 0) {
if (tmpadr.length > 0 ) {
tmpadr = tmpadr + ', ' + tmp[i];
} else {
tmpadr = tmp[i];
}
}
}
datas['adr'] = [{value: tmpadr}];
}
Object.keys(datas).map((objectKey, index) => {
if (objectKey === 'email' || objectKey === 'adr' || objectKey === 'tel' || objectKey === 'org' || objectKey === 'n1' || objectKey === 'n2') {
let value = datas[objectKey][0].value;
if (typeof value === 'string') {
tmpDatas.push(value);
}
}
});
this.setState({parsedType: 'vcard', parsedDatas: tmpDatas, showQRcodevCard: false, showDynContact: true})
} else {
Alert.alert(i18n.t('contact_details_s.qrcode_not_vcard_format'));
}
};
return (
<View style={styles.container}>
<ScrollView style={{flex: 1}}>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
}}>
<CheckBox
checkedColor={'#ce3029'}
center
title={i18n.t('contact_details_s.customer')}
checkedIcon="dot-circle-o"
uncheckedIcon="circle-o"
checked={this.state.clientChecked}
containerStyle={styles.clearRadio}
onPress={() => this.updateContactType('client')}
/>
<CheckBox
checkedColor={'#ce3029'}
center
title={i18n.t('contact_details_s.prospect')}
checkedIcon="dot-circle-o"
uncheckedIcon="circle-o"
checked={this.state.prospectChecked}
containerStyle={styles.clearRadio}
onPress={() => this.updateContactType('prospect')}
/>
<CheckBox
checkedColor={'#ce3029'}
center
title={i18n.t('contact_details_s.other')}
checkedIcon="dot-circle-o"
uncheckedIcon="circle-o"
checked={this.state.otherChecked}
containerStyle={styles.clearRadio}
onPress={() => this.updateContactType('other')}
/>
{this.state.otherChecked === true && (
<TextInput
style={{
backgroundColor: 'white',
margin: 10,
padding: 10,
flex: 2,
}}
value={this.state.tmpOther}
placeholder={i18n.t('contact_details_s.description')}
onChangeText={text => this.setState({tmpOther: text})}
/>
)}
</View>
<View style={{flexDirection: 'row'}}>
<TextInput
style={{backgroundColor: 'white', margin: 10, padding: 10, flex: 1}}
value={this.state.tmpName}
placeholder={i18n.t('global.name') + ' (' + i18n.t('global.required') + ')'}
onChangeText={text => this.setState({tmpName: text})}
/>
<TextInput
style={{backgroundColor: 'white', margin: 10, padding: 10, flex: 1}}
value={this.state.tmpFirstname}
placeholder={i18n.t('global.firstname') + ' (' + i18n.t('global.required') + ')'}
onChangeText={text => this.setState({tmpFirstname: text})}
/>
</View>
<TextInput
style={styles.input}
value={this.state.tmpEmail}
placeholder={i18n.t('global.email') + ' (' + i18n.t('global.required') + ')'}
onChangeText={text => this.setState({tmpEmail: text})}
autoCapitalize={'none'}
autoCorrect={false}
keyboardType={'email-address'}
/>
<TextInput
style={styles.input}
value={this.state.tmpCompany}
placeholder={i18n.t('global.company')}
onChangeText={text => this.setState({tmpCompany: text})}
/>
<TextInput
style={styles.input}
value={this.state.tmpAddress}
placeholder={i18n.t('global.address')}
onChangeText={text => this.setState({tmpAddress: text})}
/>
<TextInput
style={styles.input}
value={this.state.tmpPhone}
placeholder={i18n.t('global.phone')}
onChangeText={text => this.setState({tmpPhone: text})}
autoCompleteType={'tel'}
dataDetectorTypes={'phoneNumber'}
keyboardType={'phone-pad'}
/>
<View style={{flexDirection: 'row'}}>
<View style={{flex: 1, flexDirection: 'row'}}>
<Icon name="sort-down" size={20} color={'black'} style={{zIndex: 1, position: 'absolute', right: 25, top: 20}} />
<Picker
selectedValue={this.state.tmpSelect1}
style={styles.select}
onValueChange={(itemValue, itemIndex) => {
if (itemValue !== '0') {
this.setState({tmpSelect1: itemValue});
}
}}>
<Picker.Item label={i18n.t('custom.select-1.title')} value="0" />
<Picker.Item label={i18n.t('custom.select-1.c1')} value={'pole-sable'} />
<Picker.Item label={i18n.t('custom.select-1.c2')} value={'snv'} />
<Picker.Item label={i18n.t('custom.select-1.c3')} value={'pole-sud-est'} />
<Picker.Item label={i18n.t('custom.select-1.c4')} value={'aquitaine'} />
<Picker.Item label={i18n.t('custom.select-1.c5')} value={'sbv'} />
<Picker.Item label={i18n.t('custom.select-1.c6')} value={'arrive'} />
<Picker.Item label={i18n.t('custom.select-1.c7')} value={'plusieurs-filiales'} />
<Picker.Item label={i18n.t('custom.select-1.c8')} value={'autre'} />
</Picker>
</View>
<View style={{flex: 1, flexDirection: 'row'}}>
<Icon name="sort-down" size={20} color={'black'} style={{zIndex: 1, position: 'absolute', right: 25, top: 20}} />
<Picker
selectedValue={this.state.tmpSelect2}
style={styles.select}
onValueChange={(itemValue, itemIndex) => {
if (itemValue !== '0') {
this.setState({tmpSelect2: itemValue});
}
}}>
<Picker.Item label={i18n.t('custom.select-2.title')} value="0" />
<Picker.Item label={i18n.t('custom.select-2.c1')} value={'commerce-de-detail'} />
<Picker.Item label={i18n.t('custom.select-2.c2')} value={'restauration-commerciale'} />
<Picker.Item label={i18n.t('custom.select-2.c3')} value={'restauration-collective'} />
<Picker.Item label={i18n.t('custom.select-2.c4')} value={'grossiste-distributeur-cash'} />
<Picker.Item label={i18n.t('custom.select-2.c5')} value={'pai'} />
<Picker.Item label={i18n.t('custom.select-2.c6')} value={'home-freezer-center'} />
<Picker.Item label={i18n.t('custom.select-2.c7')} value={'autres'} />
</Picker>
</View>
</View>
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
}}>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p1')}
checked={this.state.p1}
onPress={() => this.setState({p1: !this.state.p1})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p2')}
checked={this.state.p2}
onPress={() => this.setState({p2: !this.state.p2})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p3')}
checked={this.state.p3}
onPress={() => this.setState({p3: !this.state.p3})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p4')}
checked={this.state.p4}
onPress={() => this.setState({p4: !this.state.p4})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p5')}
checked={this.state.p5}
onPress={() => this.setState({p5: !this.state.p5})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p6')}
checked={this.state.p6}
onPress={() => this.setState({p6: !this.state.p6})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p7')}
checked={this.state.p7}
onPress={() => this.setState({p7: !this.state.p7})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p8')}
checked={this.state.p8}
onPress={() => this.setState({p8: !this.state.p8})}
containerStyle={styles.clearCheckbox}
/>
<CheckBox
checkedColor={'#ce3029'}
title={i18n.t('custom.interest.p9')}
checked={this.state.p9}
onPress={() => this.setState({p9: !this.state.p9})}
containerStyle={styles.clearCheckbox}
/>
</View>
</ScrollView>
<View style={{flex: 1, margin: 5}}>
<View style={{flex: 1}}>
<ButtonGroup
buttons={[i18n.t('contact_details_s.visits'), i18n.t('contact_details_s.notes')]}
selectedButtonStyle={{backgroundColor: '#ce3029'}}
containerStyle={{height: 30}}
selectedIndex={this.state.selectedIndex}
onPress={index => this.setState({selectedIndex: index})}
/>
{this.state.selectedIndex === 0 && (
<View style={{flex: 1}}>
<View style={{flexDirection: 'row'}}>
{this.state.visits.length > 0 && (
<View style={{flex: 2, flexDirection: 'row'}}>
<Icon name="sort-down" size={20} color={'black'} style={{zIndex: 1, position: 'absolute', right: 25, top: 20}} />
<Picker
style={styles.select}
selectedValue={this.state.selectedVisit}
onValueChange={(itemValue, itemIndex) => {
this.state.visits[
this.state.selectedVisit
].note = this.state.tmpVisitNote;
this.setState({
visits: this.state.visits,
selectedVisit: itemIndex,
tmpVisitNote: this.state.visits[itemIndex].note,
});
}}>
{this.state.visits.map((item, index) => {
return <Picker.Item label={item.title} value={index} />;
})}
</Picker>
</View>
)}
{this.state.visits.length === 0 && (
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
}}>
<Text>{i18n.t('contact_details_s.no_visits')}.</Text>
</View>
)}
<View
style={{
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-evenly',
margin: 10,
}}>
<TouchableOpacity
style={styles.button}
onPress={() => this.setState({showNewVisit: true})}>
<Icon name="plus-circle" size={20} color={'#ce3029'} />
</TouchableOpacity>
{this.state.visits.length > 0 && (
<TouchableOpacity
style={styles.button}
onPress={() => this.deleteVisit()}>
<Icon name="trash" size={20} color={'#ce3029'} />
</TouchableOpacity>
)}
</View>
</View>
{this.state.visits.length > 0 && (
<TextInput
style={styles.textArea}
underlineColorAndroid="transparent"
placeholder={i18n.t('contact_details_s.notes') + '...'}
placeholderTextColor="grey"
multiline={true}
value={this.state.tmpVisitNote}
onChangeText={text => this.setState({tmpVisitNote: text})}
/>
)}
</View>
)}
{this.state.selectedIndex === 1 && (
<TextInput
style={styles.textArea}
underlineColorAndroid="transparent"
placeholder={i18n.t('contact_details_s.notes') + '...'}
placeholderTextColor="grey"
multiline={true}
value={this.state.tmpNote}
onChangeText={text => this.setState({tmpNote: text})}
/>
)}
</View>
<View style={{flexDirection: 'row', justifyContent: 'space-evenly'}}>
{this.state.action === 'add' && (
<>
<Button title="QRCode vCard" onPress={() => this.setState({showQRcodevCard: true})} color={'#ce3029'} />
</>
)}
<Button title={i18n.t('global.save')} onPress={() => this.updateContact()} color={'#ce3029'} />
</View>
</View>
<Overlay
isVisible={this.state.showNewVisit}
windowBackgroundColor="rgba(255, 255, 255, .9)"
overlayBackgroundColor="white"
width={400}
height={300}>
<View
style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text style={{marginBottom: 10}}>{i18n.t('contact_details_s.visit_name')} :</Text>
<TextInput
placeholder={i18n.t('contact_details_s.visit_name')}
value={this.state.newVisitTitle}
onChangeText={text => this.setState({newVisitTitle: text})}
style={{
borderWidth: 1,
borderColor: 'lightgrey',
width: 300,
marginBottom: 15,
paddingLeft: 10,
}}
/>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',
width: 400,
}}>
<Button
title={i18n.t('global.cancel')}
onPress={() => this.setState({showNewVisit: false})}
color={'#ce3029'}
/>
<Button title={i18n.t('global.add')} onPress={() => this.newVisit()} color={'#ce3029'} />
</View>
</View>
</Overlay>
<Overlay
isVisible={this.state.showQRcodevCard}
windowBackgroundColor="rgba(255, 255, 255, .9)"
overlayBackgroundColor="white"
width={400}
height={300}>
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
{this.state.hasPermission === true && (
<BarCodeScanner
onBarCodeScanned={this.state.scanned ? undefined : handleBarCodeScanned}
barCodeTypes={[BarCodeScanner.Constants.BarCodeType.qr]}
style={{flex: 1, width: 380, height: 200}}
/>
)}
{this.state.hasPermission === false && (
<Text>{i18n.t('error.camera_permission_denied')}.</Text>
)}
{this.state.hasPermission === null && (
<Text>{i18n.t('error.pending_camera_permission')}.</Text>
)}
<View
style={{
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',
width: 400,
}}>
<Button
title={i18n.t('global.cancel')}
onPress={() => this.setState({showQRcodevCard: false, scanned: false})}
color={'#ce3029'}
/>
{this.state.scanned && <Button title={i18n.t('global.retry')} onPress={() => this.setState({scanned: false})} color={'#ce3029'} />}
</View>
</View>
</Overlay>
<Overlay
isVisible={this.state.showDynContact}
windowBackgroundColor="rgba(255, 255, 255, .9)"
overlayBackgroundColor="white"
width={400}
height={400}>
<View style={{flex: 1, alignItems: 'center', justifyContent: 'space-evenly'}}>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.name')}</Text>
<Picker
selectedValue={this.state.parsedName}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) => {
this.setState({parsedName: itemValue});
}}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.firstname')}</Text>
<Picker
selectedValue={this.state.parsedFirstname}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) =>
this.setState({parsedFirstname: itemValue})
}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.email')}</Text>
<Picker
selectedValue={this.state.parsedEmail}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) =>
this.setState({parsedEmail: itemValue})
}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.company')}</Text>
<Picker
selectedValue={this.state.parsedCompany}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) =>
this.setState({parsedCompany: itemValue})
}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.address')}</Text>
<Picker
selectedValue={this.state.parsedAddress}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) =>
this.setState({parsedAddress: itemValue})
}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={{flex: 1, paddingLeft: 10}}>{i18n.t('global.phone')}</Text>
<Picker
selectedValue={this.state.parsedPhone}
style={{height: 50, width: 250}}
onValueChange={(itemValue, itemIndex) =>
this.setState({parsedPhone: itemValue})
}>
<Picker.Item label="" value="0" key={0} />
{this.state.parsedType === 'vcard' && this.state.parsedDatas.map((item, index) => {
return <Picker.Item label={item} value={item} key={(index + 1).toString()} />;
})}
</Picker>
</View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',
width: 400,
}}>
<Button
title={i18n.t('global.cancel')}
onPress={() => this.setState({showDynContact: false, scanned: false, parsedName: '', parsedFirstname: '', parsedEmail: '', parsedCompany: '', parsedAddress: '', parsedPhone: ''})}
color={'#ce3029'}
/>
<Button
title={i18n.t('global.next')}
onPress={() => this.setState({
tmpName: this.state.parsedName,
tmpFirstname: this.state.parsedFirstname,
tmpEmail: this.state.parsedEmail,
tmpCompany: this.state.parsedCompany,
tmpAddress: this.state.parsedAddress,
tmpPhone: this.state.parsedPhone,
parsedName: '',
parsedFirstname: '',
parsedEmail: '',
parsedCompany: '',
parsedAddress: '',
parsedPhone: '',
showDynContact: false,
scanned: false,
})}
color={'#ce3029'}
/>
</View>
</View>
</Overlay>
</View>
);
}
}
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,
},
});
export default connect(mapStateToProps)(ContactDetailsScreen);

View file

@ -1,114 +0,0 @@
import React from 'react';
import {
View,
StyleSheet,
ScrollView,
TouchableOpacity,
Text,
} from 'react-native';
import {connect} from 'react-redux';
import TreeView from 'react-native-animated-tree-view';
import Icon from 'react-native-vector-icons/FontAwesome5';
function mapStateToProps(state) {
return {
documents: state.documents,
};
}
class DirectoriesScreen extends React.Component {
state = {
documents: [],
};
showDocuments(folder) {
const documents = this.props.documents.filter(
tmp => tmp.directory === folder.id,
);
this.setState({documents: documents});
}
openDocument(document) {
this.props.dispatch({type: 'SET_CURRENT_OPENED_DOC', data: document});
if (document.type === 'pdf') {
this.props.navigation.navigate('PDFScreen', {uuid: document.uuid});
} else if (document.type === 'mp4') {
this.props.navigation.navigate('VideoScreen', {uuid: document.uuid});
} else {
console.log('Inconnu');
}
}
render() {
const {folder} = this.props.route.params;
let documentList = this.state.documents.map(document => {
return (
<TouchableOpacity
key={document.id.toString()}
style={styles.file}
onPress={() => this.openDocument(document)}>
{document.type === 'pdf' ? (
<Icon name="file-pdf" color={'white'} size={60}/>
) : (
<Icon name="file-video" color={'white'} size={60}/>
)}
<Text style={styles.fileTxt}>{document.title}</Text>
</TouchableOpacity>
);
});
return (
<View style={styles.container}>
<View
style={{width: 290, borderRightWidth: 1, borderColor: 'lightgrey'}}>
<TreeView
data={folder}
leftImage={{}}
rightImage={require('../assets/img/arrow_down.png')}
containerStyle={styles.treeviewContainer}
onClick={tmp => this.showDocuments(tmp)}
/>
</View>
<ScrollView style={styles.scrollview}>
<View style={styles.filesContainer}>{documentList}</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
},
treeviewContainer: {
width: 290,
},
scrollview: {
flex: 2,
},
filesContainer: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
},
file: {
justifyContent: 'center',
alignItems: 'center',
height: 200,
width: 180,
backgroundColor: '#ce3029',
margin: 10,
},
fileTxt: {
textAlign: 'center',
color: 'white',
fontWeight: 'bold',
fontSize: 18,
padding: 5
}
});
export default connect(mapStateToProps)(DirectoriesScreen);

View file

@ -1,116 +0,0 @@
import React from 'react';
import {View, StyleSheet, ImageBackground, TouchableOpacity, Text, Image} from 'react-native';
import {connect} from 'react-redux';
import NetInfo from '@react-native-community/netinfo';
import Sync from '../Controllers/Sync';
import SplashScreen from 'react-native-splash-screen';
import i18n from "../I18n";
function mapStateToProps(state) {
return {
directories: state.directories,
locale: state.locale,
};
}
class HomeScreen extends React.Component {
state = {
lastSyncCall: '2020-02-12',
};
componentDidMount(): void {
this.props.dispatch({type: 'INIT'});
SplashScreen.hide();
}
unsubscribe() {
NetInfo.addEventListener(state => {
if (state.isConnected === true) {
let seconds =
Math.abs(new Date(this.state.lastSyncCall) - Date.now()) / 1000;
//console.log(seconds);
if (seconds > 30) {
this.setState({lastSyncCall: Date.now()});
Sync.needSync(this.openSync.bind(this));
}
}
});
}
openSync() {
this.props.navigation.navigate('SyncScreen', {isInstalled: true});
}
openFolder(folderID) {
const folder = this.props.directories.filter(tmp => tmp.id === folderID);
this.props.navigation.navigate('DirectoriesScreen', {folder: folder});
}
render() {
i18n.locale = this.props.locale;
this.unsubscribe();
return (
<ImageBackground source={require('../assets/img/background.jpg')} style={{width: '100%', height: '100%'}}>
<View style={styles.container}>
<TouchableOpacity onPress={() => this.openFolder(2)} style={styles.button}>
<Image source={require('../assets/img/guillemets.png')} style={styles.btnImg}/>
<Text style={styles.btnTxt}>{i18n.t('home_s.1')}</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.openFolder(3)} style={styles.button}>
<Image source={require('../assets/img/guillemets.png')} style={styles.btnImg}/>
<Text style={styles.btnTxt}>{i18n.t('home_s.2')}</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.openFolder(4)} style={styles.button}>
<Image source={require('../assets/img/guillemets.png')} style={styles.btnImg}/>
<Text style={styles.btnTxt}>{i18n.t('home_s.3')}</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.props.navigation.navigate('OnlyVideosScreen')} style={styles.button}>
<Image source={require('../assets/img/guillemets.png')} style={styles.btnImg}/>
<Text style={styles.btnTxt}>{i18n.t('global.videos')}</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.props.navigation.navigate('ContactScreen')} style={styles.button}>
<Image source={require('../assets/img/guillemets.png')} style={styles.btnImg}/>
<Text style={styles.btnTxt}>{i18n.t('global.contacts')}</Text>
</TouchableOpacity>
</View>
</ImageBackground>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'flex-end',
justifyContent: 'center',
},
text: {
height: 40,
width: 300,
borderColor: 'grey',
borderWidth: 1,
marginBottom: 20,
},
button: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
marginBottom: 20,
marginRight: 50,
width: 400,
height: 80,
borderRadius: 10
},
btnTxt: {
fontSize: 20
},
btnImg: {
position: 'absolute',
left: 15,
height: 50,
width: 50,
resizeMode: 'stretch'
}
});
export default connect(mapStateToProps)(HomeScreen);

View file

@ -1,167 +0,0 @@
import React from 'react';
import {View, StyleSheet, TextInput, Button, Alert, ImageBackground, Image} from 'react-native';
import {connect} from 'react-redux';
import BCryptBridge from 'react-native-b-crypt-bridge';
import Sync from '../Controllers/Sync';
import CommonModel from '../Models/Common';
import SplashScreen from 'react-native-splash-screen';
import NetInfo from "@react-native-community/netinfo";
import i18n from "../I18n";
function mapStateToProps(state) {
return {
users: state.users,
locale: state.locale,
};
}
class LoginScreen extends React.Component {
state = {
login: '',
password: '',
};
componentDidMount(): void {
SplashScreen.hide();
}
login(login, password) {
if (login !== '' && password !== '') {
let user = this.props.users.filter(tmp => tmp.email === login);
if (user.length > 0) {
user = user[0];
BCryptBridge.verify(
password,
user.password,
verified => {
if (verified === true) {
// Si user === last user
const lastUser = CommonModel.get('lastUser');
if (lastUser !== false && lastUser !== undefined && lastUser.value === user.id.toString()) {
this.loginAction(user);
} else {
// Si la tablette est synchronisée avec le serveur
if (Sync.isSynced()) {
// Si la tablette est connectée à internet pour forcer la synchro
NetInfo.fetch().then(state => {
if (state.isConnected) {
this.loginAction(user, true);
} else {
Alert.alert(i18n.t('error.tablet_not_connected_internet'));
}
});
} else {
Alert.alert(i18n.t('error.tablet_not_synced_last_user'));
}
}
} else {
Alert.alert(i18n.t('error.incorrect_credentials'));
}
},
error => {
console.log(error);
},
);
} else {
Alert.alert(i18n.t('error.incorrect_credentials'));
}
} else {
Alert.alert(i18n.t('error.must_fill_login_fields'));
}
}
loginAction(user, forceSync = false) {
this.setState({login: '', password: ''});
CommonModel.update({
key: 'isLogged',
value: JSON.stringify(user),
});
CommonModel.update({
key: 'loggedTime',
value: Date.now().toString(),
});
CommonModel.update({key: 'lastUser', value: user.id.toString()});
this.props.dispatch({
type: 'SET_CURRENT_USER',
data: JSON.stringify(user),
});
this.props.dispatch({type: 'SET_LOGGED', data: true});
if (forceSync === true) {
this.props.navigation.navigate('SyncScreen', {isInstalled: true, forceSync: true});
}
}
renderInstallBtn() {
if (!Sync.isInstalled()) {
return (
<View style={{marginTop: 20}}>
<Button
color={'#ce3029'}
title={i18n.t('login_s.install')}
onPress={() =>
this.props.navigation.navigate('SyncScreen', {isInstalled: false})
}
/>
</View>
);
}
}
render() {
i18n.locale = this.props.locale;
return (
<ImageBackground source={require('../assets/img/background.jpg')} style={{width: '100%', height: '100%'}}>
<View style={styles.container}>
<Image source={require('../assets/img/logo-square.png')} style={{width: 150, height: 150, marginBottom: 20}} />
{Sync.isInstalled() && (
<View>
<TextInput
style={styles.text}
placeholder={i18n.t('login_s.username')}
value={this.state.login}
onChangeText={text => this.setState({login: text})}
autoCapitalize={'none'}
autoCorrect={false}
keyboardType={'email-address'}
/>
<TextInput
style={styles.text}
placeholder={i18n.t('login_s.password')}
value={this.state.password}
onChangeText={text => this.setState({password: text})}
secureTextEntry={true}
autoCapitalize={'none'}
autoCorrect={false}
/>
<Button
title={i18n.t('global.login')}
onPress={() => this.login(this.state.login, this.state.password)}
color={'#ce3029'}
/>
</View>
)}
{this.renderInstallBtn()}
</View>
</ImageBackground>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
text: {
height: 40,
width: 300,
borderColor: 'grey',
borderWidth: 1,
marginBottom: 20,
backgroundColor: 'white',
paddingLeft: 10
},
});
export default connect(mapStateToProps)(LoginScreen);

View file

@ -1,35 +0,0 @@
import React from 'react';
import {
View,
StyleSheet,
ScrollView,
TouchableOpacity,
Text,
} from 'react-native';
import {connect} from 'react-redux';
function mapStateToProps(state) {
return {
documents: state.documents,
};
}
class MySpaceScreen extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Mon Espace</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
},
});
export default connect(mapStateToProps)(MySpaceScreen);

View file

@ -1,95 +0,0 @@
import React from 'react';
import {
View,
StyleSheet,
ScrollView,
TouchableOpacity,
Text,
} from 'react-native';
import {connect} from 'react-redux';
import Icon from 'react-native-vector-icons/FontAwesome5';
function mapStateToProps(state) {
return {
documents: state.documents,
};
}
class OnlyVideosScreen extends React.Component {
state = {
documents: [],
};
showDocuments() {
const documents = this.props.documents.filter(tmp => tmp.type === 'mp4');
this.setState({documents: documents});
}
openDocument(document) {
this.props.dispatch({type: 'SET_CURRENT_OPENED_DOC', data: document});
this.props.navigation.navigate('VideoScreen', {uuid: document.uuid});
}
componentDidMount(): void {
this.showDocuments();
}
render() {
let documentList = this.state.documents.map(document => {
return (
<TouchableOpacity
key={document.id.toString()}
style={styles.file}
onPress={() => this.openDocument(document)}>
{document.type === 'pdf' ? (
<Icon name="file-pdf" color={'white'} size={60}/>
) : (
<Icon name="file-video" color={'white'} size={60}/>
)}
<Text style={styles.fileTxt}>{document.title}</Text>
</TouchableOpacity>
);
});
return (
<View style={styles.container}>
<ScrollView style={styles.scrollview}>
<View style={styles.filesContainer}>{documentList}</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
},
scrollview: {
flex: 2,
},
filesContainer: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
},
file: {
justifyContent: 'center',
alignItems: 'center',
height: 200,
width: 180,
backgroundColor: '#ce3029',
margin: 10,
},
fileTxt: {
textAlign: 'center',
color: 'white',
fontWeight: 'bold',
fontSize: 18,
padding: 5
}
});
export default connect(mapStateToProps)(OnlyVideosScreen);

View file

@ -1,57 +0,0 @@
import React from 'react';
import {View, StyleSheet, Dimensions} from 'react-native';
import Pdf from 'react-native-pdf';
import {FileSystem} from 'react-native-unimodules';
class PDFScreen extends React.Component {
render() {
const {uuid} = this.props.route.params;
const source = {
uri: FileSystem.documentDirectory + uuid + '.pdf',
cache: false,
};
return (
<View style={styles.container}>
<Pdf
source={source}
onLoadComplete={(numberOfPages, filePath) => {
console.log(`number of pages: ${numberOfPages}`);
}}
onPageChanged={(page, numberOfPages) => {
console.log(`current page: ${page}`);
}}
onError={error => {
console.log(error);
}}
onPressLink={uri => {
console.log(`Link presse: ${uri}`);
}}
style={styles.pdf}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
text: {
height: 40,
width: 300,
borderColor: 'grey',
borderWidth: 1,
marginBottom: 20,
},
pdf: {
flex: 1,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
});
export default PDFScreen;

View file

@ -1,111 +0,0 @@
import React from 'react';
import {
View,
StyleSheet,
ScrollView,
TouchableOpacity,
Text,
} from 'react-native';
import {connect} from 'react-redux';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Helpers from "../Controllers/Helpers";
import i18n from "../I18n";
function mapStateToProps(state) {
return {
documents: state.documents,
};
}
class SearchScreen extends React.Component {
state = {
documents: [],
};
openDocument(document) {
this.props.dispatch({type: 'SET_CURRENT_OPENED_DOC', data: document});
if (document.type === 'pdf') {
this.props.navigation.navigate('PDFScreen', {uuid: document.uuid});
} else if (document.type === 'mp4') {
this.props.navigation.navigate('VideoScreen', {uuid: document.uuid});
} else {
console.log('Inconnu');
}
}
componentDidMount(): void {
const {needle, onlyVideos} = this.props.route.params;
let objDocs = this.props.documents;
let arrayDocs = Object.keys(objDocs).map(function (key) { return objDocs[key]; });
let sorted = arrayDocs.sort(Helpers.compareValues('title', 'asc'));
let filtered = sorted.filter(item => item.title.toLowerCase().indexOf(needle.toLowerCase()) >= 0);
if (onlyVideos === true) {
filtered = filtered.filter(item => item.type === 'mp4');
}
this.setState({
documents: filtered,
});
}
render() {
let documentList = this.state.documents.map(document => {
return (
<TouchableOpacity
key={document.id.toString()}
style={styles.file}
onPress={() => this.openDocument(document)}>
{document.type === 'pdf' ? (
<Icon name="file-pdf" color={'white'} size={60}/>
) : (
<Icon name="file-video" color={'white'} size={60}/>
)}
<Text style={styles.fileTxt}>{document.title}</Text>
</TouchableOpacity>
);
});
return (
<View style={styles.container}>
<ScrollView style={styles.scrollview}>
<View style={styles.filesContainer}>{documentList}</View>
{this.state.documents.length === 0 && (
<Text style={{textAlign: 'center', marginTop: 50, fontSize: 30}}>{i18n.t('search_s.no_result')}</Text>
)}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
},
scrollview: {
flex: 2,
},
filesContainer: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
},
file: {
justifyContent: 'center',
alignItems: 'center',
height: 200,
width: 180,
backgroundColor: '#ce3029',
margin: 10,
},
fileTxt: {
textAlign: 'center',
color: 'white',
fontWeight: 'bold',
fontSize: 18,
padding: 5
}
});
export default connect(mapStateToProps)(SearchScreen);

Some files were not shown because too many files have changed in this diff Show more