SYNC 15 Major update, Formularies and Fixes
- Add type Definitions - Fix models methods - Sync controller add route names - Formularies sync OK - Closes https://lab.s-web.fr/ldc-web/projets/com-app-bo/-/issues/18 - Closes https://lab.s-web.fr/ldc-web/projets/com-app/-/issues/9
This commit is contained in:
parent
64c324d30a
commit
918e20a72b
41 changed files with 2929 additions and 1352 deletions
|
|
@ -11,4 +11,4 @@
|
|||
- Mise en place de vérification par regex des champs obligatoires sur le formulaire de contact.
|
||||
- Ajout d'un bouton dans le header de la home pour aller directement sur la page d'ajout de contact.
|
||||
- Ajout de la possibilité de revenir à l'écran d'accueil en cliquant sur le logo présent dans le header.
|
||||
- Ajout d'un espace plus important entre les éléments cliquables du header + ajout d'un menu en overlay.
|
||||
- Ajout d'un espace plus important entre les éléments cliquables du header + ajout d'un menu en overlay.
|
||||
|
|
|
|||
153
ComApp/package-lock.json
generated
153
ComApp/package-lock.json
generated
|
|
@ -17,6 +17,7 @@
|
|||
"@rneui/themed": "^0.0.0-edge.2",
|
||||
"@sentry/react-native": "^4.12.0",
|
||||
"axios": "^0.27.2",
|
||||
"buffer": "^6.0.3",
|
||||
"expo": "^47.0.10",
|
||||
"expo-av": "^13.0.2",
|
||||
"expo-barcode-scanner": "^11.4.0",
|
||||
|
|
@ -31,13 +32,16 @@
|
|||
"react-native-animated-tree-view": "^0.1.4",
|
||||
"react-native-b-crypt-bridge": "file:react-native-b-crypt-bridge-2.1.0.tgz",
|
||||
"react-native-blob-util": "^0.16.2",
|
||||
"react-native-email-link": "^1.14.6",
|
||||
"react-native-flash-message": "^0.3.1",
|
||||
"react-native-gesture-handler": "^2.7.0",
|
||||
"react-native-pdf": "^6.6.2",
|
||||
"react-native-progress": "^5.0.0",
|
||||
"react-native-safe-area-context": "^4.4.1",
|
||||
"react-native-screens": "^3.18.0",
|
||||
"react-native-sectioned-multi-select": "^0.10.0",
|
||||
"react-native-svg": "^13.2.0",
|
||||
"react-native-uuid": "^2.0.1",
|
||||
"react-native-vector-icons": "^9.2.0",
|
||||
"react-redux": "^8.0.4",
|
||||
"realm": "^11.0.0-rc.2",
|
||||
|
|
@ -6087,6 +6091,29 @@
|
|||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bl/node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/bl/node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
|
|
@ -6345,7 +6372,7 @@
|
|||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"node_modules/bson/node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
|
|
@ -6363,12 +6390,34 @@
|
|||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-alloc": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
|
||||
|
|
@ -12308,6 +12357,11 @@
|
|||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
|
|
@ -17361,6 +17415,15 @@
|
|||
"nullthrows": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-email-link": {
|
||||
"version": "1.14.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native-email-link/-/react-native-email-link-1.14.6.tgz",
|
||||
"integrity": "sha512-XsWgdSMgxutKrm6WJRLKd1DxQpFt2x6xLuIhmAE5CdMMjNKadsUM5Evub9+otTBhlphSerePAwzSaNoBXpisLg==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-native": ">=0.40.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-flash-message": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-flash-message/-/react-native-flash-message-0.3.1.tgz",
|
||||
|
|
@ -17459,6 +17522,23 @@
|
|||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-sectioned-multi-select": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-sectioned-multi-select/-/react-native-sectioned-multi-select-0.10.0.tgz",
|
||||
"integrity": "sha512-wD5USgM88cHNkgQLB94NxbubtYCLacgzk2vfFlF+HvOI7noDz1AZfzu2sVp1WKz4bFx20MFxM4mi1uZoyxAutg==",
|
||||
"dependencies": {
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"memoize-one": "^6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-sectioned-multi-select/node_modules/memoize-one": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
||||
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
|
||||
},
|
||||
"node_modules/react-native-size-matters": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.4.0.tgz",
|
||||
|
|
@ -17480,6 +17560,15 @@
|
|||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-uuid": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.1.tgz",
|
||||
"integrity": "sha512-cptnoIbL53GTCrWlb/+jrDC6tvb7ypIyzbXNJcpR3Vab0mkeaaVd5qnB3f0whXYzS+SMoSQLcUUB0gEWqkPC0g==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-vector-icons": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz",
|
||||
|
|
@ -25233,6 +25322,15 @@
|
|||
"readable-stream": "^3.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
|
|
@ -25419,15 +25517,26 @@
|
|||
"integrity": "sha512-Uu4OCZa0jouQJCKOk1EmmyqtdWAP5HVLru4lQxTwzJzxT+sJ13lVpEZU/MATDxtHiekWMAL84oQY3Xn1LpJVSg==",
|
||||
"requires": {
|
||||
"buffer": "^5.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"buffer-alloc": {
|
||||
|
|
@ -29743,6 +29852,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
|
||||
},
|
||||
"lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
|
||||
},
|
||||
"lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
|
|
@ -33389,6 +33503,12 @@
|
|||
"nullthrows": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"react-native-email-link": {
|
||||
"version": "1.14.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native-email-link/-/react-native-email-link-1.14.6.tgz",
|
||||
"integrity": "sha512-XsWgdSMgxutKrm6WJRLKd1DxQpFt2x6xLuIhmAE5CdMMjNKadsUM5Evub9+otTBhlphSerePAwzSaNoBXpisLg==",
|
||||
"requires": {}
|
||||
},
|
||||
"react-native-flash-message": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-flash-message/-/react-native-flash-message-0.3.1.tgz",
|
||||
|
|
@ -33461,6 +33581,22 @@
|
|||
"warn-once": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"react-native-sectioned-multi-select": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-sectioned-multi-select/-/react-native-sectioned-multi-select-0.10.0.tgz",
|
||||
"integrity": "sha512-wD5USgM88cHNkgQLB94NxbubtYCLacgzk2vfFlF+HvOI7noDz1AZfzu2sVp1WKz4bFx20MFxM4mi1uZoyxAutg==",
|
||||
"requires": {
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"memoize-one": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"memoize-one": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
|
||||
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-size-matters": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.4.0.tgz",
|
||||
|
|
@ -33476,6 +33612,11 @@
|
|||
"css-tree": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"react-native-uuid": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.1.tgz",
|
||||
"integrity": "sha512-cptnoIbL53GTCrWlb/+jrDC6tvb7ypIyzbXNJcpR3Vab0mkeaaVd5qnB3f0whXYzS+SMoSQLcUUB0gEWqkPC0g=="
|
||||
},
|
||||
"react-native-vector-icons": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
"@rneui/themed": "^0.0.0-edge.2",
|
||||
"@sentry/react-native": "^4.12.0",
|
||||
"axios": "^0.27.2",
|
||||
"buffer": "^6.0.3",
|
||||
"expo": "^47.0.10",
|
||||
"expo-av": "^13.0.2",
|
||||
"expo-barcode-scanner": "^11.4.0",
|
||||
|
|
@ -33,13 +34,16 @@
|
|||
"react-native-animated-tree-view": "^0.1.4",
|
||||
"react-native-b-crypt-bridge": "file:react-native-b-crypt-bridge-2.1.0.tgz",
|
||||
"react-native-blob-util": "^0.16.2",
|
||||
"react-native-email-link": "^1.14.6",
|
||||
"react-native-flash-message": "^0.3.1",
|
||||
"react-native-gesture-handler": "^2.7.0",
|
||||
"react-native-pdf": "^6.6.2",
|
||||
"react-native-progress": "^5.0.0",
|
||||
"react-native-safe-area-context": "^4.4.1",
|
||||
"react-native-screens": "^3.18.0",
|
||||
"react-native-sectioned-multi-select": "^0.10.0",
|
||||
"react-native-svg": "^13.2.0",
|
||||
"react-native-uuid": "^2.0.1",
|
||||
"react-native-vector-icons": "^9.2.0",
|
||||
"react-redux": "^8.0.4",
|
||||
"realm": "^11.0.0-rc.2",
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import SearchScreen from './App/Views/SearchScreen';
|
|||
import SyncScreen from './App/Views/SyncScreen';
|
||||
import VideoScreen from './App/Views/VideoScreen';
|
||||
// Style
|
||||
import Helpers from './App/Lib/Helpers';
|
||||
import styles from './Resources/Styles/NavigationStyle';
|
||||
// Controllers
|
||||
import SyncController from './App/Controllers/SyncController';
|
||||
|
|
@ -88,7 +89,6 @@ class App extends React.Component {
|
|||
isLogged: store.getState().app.logged,
|
||||
mainColor: store.getState().app.mainColor,
|
||||
}); // to force re-rendering
|
||||
console.log('state changed');
|
||||
}
|
||||
|
||||
navigationView = () => (
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@ import NetInfo from '@react-native-community/netinfo';
|
|||
import * as Application from 'expo-application';
|
||||
// Database
|
||||
import { Contact, Document, SendBrochure, Setting } from '../../Database';
|
||||
import { ContactData } from '../Models/Contact';
|
||||
|
||||
const api_token = 'G9Q62jt8eL8gN4Ls';
|
||||
|
||||
class SyncController {
|
||||
getUrlBo() {
|
||||
const test = Setting.get('bo_url');
|
||||
if (test === false || test === undefined) {
|
||||
if (test === null) {
|
||||
return 'noset';
|
||||
}
|
||||
return test.value;
|
||||
|
|
@ -21,7 +22,7 @@ class SyncController {
|
|||
|
||||
getAppStoreUUID() {
|
||||
const test = Setting.get('AppStoreUUID');
|
||||
if (test === false || test === undefined) {
|
||||
if (test === null) {
|
||||
return 'noset';
|
||||
}
|
||||
return test.value;
|
||||
|
|
@ -34,6 +35,7 @@ class SyncController {
|
|||
async getVersion() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * version
|
||||
url: this.getUrlBo() + '/api/version',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
|
|
@ -47,6 +49,7 @@ class SyncController {
|
|||
async getUsers() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * users.index
|
||||
url: this.getUrlBo() + '/api/users',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
|
|
@ -55,18 +58,68 @@ class SyncController {
|
|||
});
|
||||
}
|
||||
|
||||
async getContacts(userId) {
|
||||
let contacts = Contact.getAll();
|
||||
/**
|
||||
* @param {number} app_user_id
|
||||
*/
|
||||
async getContacts(app_user_id) {
|
||||
// * We retrieve all contacts avec upsert and destroy
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * contacts.index
|
||||
url: this.getUrlBo() + `/api/contacts/${app_user_id}`,
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} app_user_id
|
||||
*/
|
||||
async upsertContacts(app_user_id) {
|
||||
const contacts = Contact.getAll(app_user_id).map(contact => {
|
||||
// * This casts contact to a simple Object
|
||||
// * Realm object does not support changing prop type
|
||||
/** @type {ContactData} */
|
||||
contact = contact.toJSON();
|
||||
// * Convert to UTC timestamp
|
||||
contact.timestamp = contact.timestamp.toUTCString();
|
||||
|
||||
// * Unstringify complex Fields
|
||||
contact.data = JSON.parse(contact.data);
|
||||
contact.visits = JSON.parse(contact.visits);
|
||||
return contact;
|
||||
});
|
||||
return axios({
|
||||
method: 'POST',
|
||||
url: this.getUrlBo() + '/api/contacts',
|
||||
// * contacts.index
|
||||
url: this.getUrlBo() + `/api/contacts/${app_user_id}`,
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
data: {
|
||||
contacts: contacts,
|
||||
userId: userId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} app_user_id
|
||||
*/
|
||||
async deleteContacts(app_user_id) {
|
||||
const contactsToDelete = Contact.getAllToDelete(app_user_id);
|
||||
return axios({
|
||||
method: 'DELETE',
|
||||
// * contacts.index
|
||||
url: this.getUrlBo() + `/api/contacts/${app_user_id}`,
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
data: {
|
||||
contactUuidList: contactsToDelete.map(contact => contact.id),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -74,6 +127,7 @@ class SyncController {
|
|||
async sendBrochure(brochure) {
|
||||
return axios({
|
||||
method: 'POST',
|
||||
// * send-flyers
|
||||
url: this.getUrlBo() + '/api/sendBrochure',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
|
|
@ -86,6 +140,7 @@ class SyncController {
|
|||
async getDirectories() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * directories.index
|
||||
url: this.getUrlBo() + '/api/directories',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
|
|
@ -97,6 +152,7 @@ class SyncController {
|
|||
async getDocuments() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * documents.index
|
||||
url: this.getUrlBo() + '/api/documents',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
|
|
@ -105,13 +161,25 @@ class SyncController {
|
|||
});
|
||||
}
|
||||
|
||||
async getFormularies() {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
// * formularies.index
|
||||
url: this.getUrlBo() + '/api/formularies',
|
||||
responseType: 'json',
|
||||
params: {
|
||||
token: api_token,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
updateLastModificationDoc(id, date) {
|
||||
Document.update({ id: id, updated_at: date.toString() }, true);
|
||||
}
|
||||
|
||||
updateVersion(version) {
|
||||
const localVersion = Setting.get('version');
|
||||
if (localVersion === false || localVersion === undefined) {
|
||||
if (localVersion === null) {
|
||||
Setting.add({ key: 'version', value: version });
|
||||
} else {
|
||||
Setting.update({ id: localVersion.id, key: 'version', value: version });
|
||||
|
|
@ -120,16 +188,20 @@ class SyncController {
|
|||
|
||||
updateShowIsActive(value) {
|
||||
const local = Setting.get('ShowIsActive');
|
||||
if (local === false || local === undefined) {
|
||||
if (local === null) {
|
||||
Setting.add({ key: 'ShowIsActive', value: value });
|
||||
} else {
|
||||
Setting.update({ id: local.id, key: 'ShowIsActive', value: value });
|
||||
}
|
||||
}
|
||||
|
||||
isSynced() {
|
||||
/**
|
||||
* @param {number} app_user_id
|
||||
* @returns
|
||||
*/
|
||||
isSynced(app_user_id) {
|
||||
const brochures = SendBrochure.getAll();
|
||||
const Contacts = Contact.getAll();
|
||||
const Contacts = Contact.getAll(app_user_id);
|
||||
|
||||
if (brochures !== undefined && Contacts !== undefined) {
|
||||
const noSynced = Contacts.filtered('synced = false');
|
||||
|
|
@ -143,12 +215,7 @@ class SyncController {
|
|||
isLogged() {
|
||||
const logged = Setting.get('isLogged');
|
||||
const loggedTime = Setting.get('loggedTime');
|
||||
if (
|
||||
logged !== false &&
|
||||
loggedTime !== false &&
|
||||
logged !== undefined &&
|
||||
loggedTime !== undefined
|
||||
) {
|
||||
if (logged !== null && loggedTime !== null) {
|
||||
let seconds =
|
||||
Math.abs(new Date(Number(loggedTime.value)) - Date.now()) / 1000;
|
||||
if (seconds < 14400) {
|
||||
|
|
@ -174,8 +241,7 @@ class SyncController {
|
|||
.then(response => {
|
||||
const localVersion = Setting.get('version');
|
||||
if (
|
||||
localVersion === undefined ||
|
||||
localVersion === false ||
|
||||
localVersion === null ||
|
||||
localVersion.value !== response.data.version
|
||||
) {
|
||||
return callback();
|
||||
|
|
@ -183,7 +249,7 @@ class SyncController {
|
|||
return false;
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error);
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
|
|
@ -201,7 +267,7 @@ class SyncController {
|
|||
|
||||
isInstalled() {
|
||||
const test = Setting.get('installed');
|
||||
if (test === false || test === undefined) {
|
||||
if (test === null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
17
ComApp/src/App/Enums/InputStatus.js
Normal file
17
ComApp/src/App/Enums/InputStatus.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/** InputStatusEnum */
|
||||
|
||||
/**
|
||||
* @typedef {keyof InputStatusKeys} InputStatus
|
||||
*/
|
||||
export const InputStatus = {
|
||||
SYSTEM: 1,
|
||||
LOCKED: 2,
|
||||
DEFAULT: 3,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const InputStatusKeys = {
|
||||
1: 'SYSTEM',
|
||||
2: 'LOCKED',
|
||||
3: 'DEFAULT',
|
||||
};
|
||||
25
ComApp/src/App/Enums/InputType.js
Normal file
25
ComApp/src/App/Enums/InputType.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/** InputTypeEnum */
|
||||
|
||||
/**
|
||||
* @typedef {keyof InputTypeKeys} InputType
|
||||
*/
|
||||
export const InputType = {
|
||||
TEXT: 1,
|
||||
EMAIL: 2,
|
||||
PHONE: 3,
|
||||
RADIO: 4,
|
||||
SELECT: 5,
|
||||
SELECT_MULTIPLE: 6,
|
||||
CHECKBOX: 7,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const InputTypeKeys = {
|
||||
1: 'TEXT',
|
||||
2: 'EMAIL',
|
||||
3: 'PHONE',
|
||||
4: 'RADIO',
|
||||
5: 'SELECT',
|
||||
6: 'SELECT_MULTIPLE',
|
||||
7: 'CHECKBOX',
|
||||
};
|
||||
|
|
@ -29,27 +29,5 @@ class Helpers {
|
|||
value.toLowerCase(),
|
||||
);
|
||||
}
|
||||
|
||||
generateUUID() {
|
||||
// Public Domain/MIT
|
||||
let d = new Date().getTime(); //Timestamp
|
||||
let d2 = new Date().getUTCMilliseconds() + Math.random(); //Time in microseconds since page-load or 0 if unsupported
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
|
||||
/[xy]/g,
|
||||
function (c) {
|
||||
let r = Math.random() * 16; //random number between 0 and 16
|
||||
if (d > 0) {
|
||||
//Use timestamp until depleted
|
||||
r = (d + r) % 16 | 0;
|
||||
d = Math.floor(d / 16);
|
||||
} else {
|
||||
//Use microseconds since page-load if supported
|
||||
r = (d2 + r) % 16 | 0;
|
||||
d2 = Math.floor(d2 / 16);
|
||||
}
|
||||
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
export default new Helpers();
|
||||
|
|
|
|||
|
|
@ -1,106 +1,195 @@
|
|||
import { default as UuidGenerator } from 'react-native-uuid';
|
||||
import { UpdateMode } from 'realm';
|
||||
import { InputType } from './../Enums/InputType';
|
||||
|
||||
/**
|
||||
* @typedef {typeof ContactData} ContactData
|
||||
*/
|
||||
export const ContactData = {
|
||||
/** @type {string|undefined} */
|
||||
id: undefined,
|
||||
/** @type {string} */
|
||||
email: undefined,
|
||||
/** @type {string|null} */
|
||||
lastname: null,
|
||||
/** @type {string|null} */
|
||||
firstname: null,
|
||||
/** @type {string|null} */
|
||||
phone: null,
|
||||
/** @type {Array<InputDataType>} */
|
||||
data: [],
|
||||
/** @type {string|null} */
|
||||
notes: null,
|
||||
/** @type {Array<Record<string,string>>|null} */
|
||||
visits: null,
|
||||
/** @type {Date} */
|
||||
timestamp: null,
|
||||
/** @type {number} The app user id */
|
||||
app_user_id: undefined,
|
||||
/** @type {number|null} The app user id that should receive this contact on sync */
|
||||
send_to_app_user_id: null,
|
||||
/** @type {boolean} If this model is to delete */
|
||||
to_delete: false,
|
||||
/** @type {boolean} This model need sync */
|
||||
synced: true,
|
||||
};
|
||||
|
||||
export const ContactsSchema = {
|
||||
name: 'Contacts',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
type: 'string',
|
||||
other: { type: 'string', optional: true },
|
||||
select1: { type: 'string', optional: true },
|
||||
select2: { type: 'string', optional: true },
|
||||
name: 'string',
|
||||
firstname: 'string',
|
||||
company: { type: 'string', optional: true },
|
||||
address: { type: 'string', optional: true },
|
||||
phone: 'string',
|
||||
products: { type: 'string', optional: true },
|
||||
// TODO : card_url ?
|
||||
notes: { type: 'string', optional: true },
|
||||
visits: { type: 'string', optional: true },
|
||||
user_id: 'int',
|
||||
uniq_id: 'string',
|
||||
to_delete: { type: 'bool', default: false },
|
||||
synced: { type: 'bool', default: true },
|
||||
...ContactData,
|
||||
...{
|
||||
id: 'string',
|
||||
email: 'string',
|
||||
lastname: { type: 'string', optional: true },
|
||||
firstname: { type: 'string', optional: true },
|
||||
phone: { type: 'string', optional: true },
|
||||
/** Json encoded string of ContactData.data */
|
||||
data: { type: 'string', default: '[]' },
|
||||
notes: { type: 'string', optional: true },
|
||||
/** Json encoded string of ContactData.visists */
|
||||
visits: { type: 'string', default: '[]' },
|
||||
timestamp: 'date',
|
||||
send_to_app_user_id: { type: 'int', optional: true, default: null },
|
||||
app_user_id: 'int',
|
||||
to_delete: { type: 'bool', default: false },
|
||||
synced: { type: 'bool', default: true },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {typeof InputData} InputDataType
|
||||
*/
|
||||
export const InputData = {
|
||||
title: '',
|
||||
formSlug: '',
|
||||
/** @type {import('./../Enums/InputType').InputType} */
|
||||
type: InputType.TEXT,
|
||||
/** @type {string|Array<number,string>} */
|
||||
value: '',
|
||||
required: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof ContactData> & import('realm').Object} Contact
|
||||
*/
|
||||
|
||||
class ContactModel {
|
||||
/**
|
||||
* ContactModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Contacts';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
add(data) {
|
||||
data.uniq_id = data.id;
|
||||
data.id = undefined;
|
||||
/** @return {Unmanaged<typeof ContactData>} */
|
||||
new() {
|
||||
return Object.assign({}, ContactData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set contact
|
||||
* ! We can use only set since all contacts are dropped and redownloaded on sync
|
||||
* @param {Contact} data
|
||||
*/
|
||||
set(data) {
|
||||
const isNew = typeof data.id !== 'string' || !data.id?.length;
|
||||
if (isNew) {
|
||||
console.warn('is new', data);
|
||||
// * Set Local UUID until it get synced
|
||||
//* it will be ignore and new one will be generated by BO
|
||||
data.id = UuidGenerator.v4();
|
||||
}
|
||||
this.realm.write(() => {
|
||||
if (data.id === undefined) {
|
||||
let id = this.realm.objects(this.schema).max('id');
|
||||
data.id = id === undefined ? 1 : id + 1;
|
||||
}
|
||||
try {
|
||||
this.realm.create(this.schema, data, 'never');
|
||||
this.realm.create(
|
||||
this.schema,
|
||||
data,
|
||||
isNew ? UpdateMode.Never : UpdateMode.Modified,
|
||||
);
|
||||
} catch (e) {
|
||||
console.log('db setting add', e);
|
||||
console.error('db contact set', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
upsert(data) {
|
||||
let tmp = this.get(data.key);
|
||||
if (tmp === false || tmp === undefined) {
|
||||
this.add(data);
|
||||
} else {
|
||||
if (data.id === undefined) {
|
||||
data.id = tmp.id;
|
||||
}
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
update(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
|
||||
get(id) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
/**
|
||||
* get contact with uuid
|
||||
* @param {number} app_user_id App User id
|
||||
* @param {string} uuid
|
||||
* @returns {Contact?}
|
||||
*/
|
||||
get(app_user_id, uuid) {
|
||||
/** @type {import('realm').Results<Contact>} */
|
||||
const tmp = this.realm
|
||||
.objects(this.schema)
|
||||
.filtered(`app_user_id = ${app_user_id}`);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('id = ' + id)[0];
|
||||
return null;
|
||||
}
|
||||
return tmp;
|
||||
return tmp.filtered(`id = '${uuid}'`)[0] ?? null;
|
||||
}
|
||||
|
||||
getByUser(userId) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
tmp = tmp.filtered('to_delete = false AND user_id = ' + userId);
|
||||
return tmp;
|
||||
/**
|
||||
* @param {number} app_user_id App User id
|
||||
* @returns {import('realm').Results<Contact>}
|
||||
*/
|
||||
getAll(app_user_id) {
|
||||
return this.realm
|
||||
.objects(this.schema)
|
||||
.filtered(`to_delete = false AND app_user_id = ${app_user_id}`);
|
||||
}
|
||||
|
||||
getAll() {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
return tmp;
|
||||
/**
|
||||
* @param {number} app_user_id App User id
|
||||
* @returns {import('realm').Results<Contact>}
|
||||
*/
|
||||
getAllEditable(app_user_id) {
|
||||
return this.realm
|
||||
.objects(this.schema)
|
||||
.filtered(
|
||||
`to_delete = false AND send_to_app_user_id = null AND app_user_id = ${app_user_id}`,
|
||||
);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.getAll());
|
||||
});
|
||||
/**
|
||||
* @param {number} app_user_id App User id
|
||||
* @returns {import('realm').Results<Contact>}
|
||||
*/
|
||||
getAllToDelete(app_user_id) {
|
||||
return this.realm
|
||||
.objects(this.schema)
|
||||
.filtered(`to_delete = true AND app_user_id = ${app_user_id}`);
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const tmp = this.get(key);
|
||||
if (typeof tmp === 'object') {
|
||||
/**
|
||||
* delete contact with id
|
||||
* @param {number} app_user_id App User id
|
||||
* @param {string} uuid
|
||||
*/
|
||||
delete(app_user_id, uuid) {
|
||||
const contact = this.get(app_user_id, uuid);
|
||||
if (typeof contact === 'object') {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(tmp);
|
||||
this.realm.delete(contact);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} app_user_id App User id
|
||||
*/
|
||||
clear(app_user_id) {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.getAll(app_user_id));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default ContactModel;
|
||||
|
|
|
|||
|
|
@ -2,52 +2,87 @@ export const DirectoriesSchema = {
|
|||
name: 'Directories',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
/** @type {number} */
|
||||
id: 'int',
|
||||
name: 'string',
|
||||
parent: {type: 'int', optional: true},
|
||||
/** @type {number|null} */
|
||||
parent: { type: 'int', optional: true },
|
||||
/** @type {number} */
|
||||
order: 'int',
|
||||
/** @type {number} */
|
||||
needAuthorization: 'int',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof DirectoriesSchema.properties> & import('realm').Object} Directory
|
||||
*/
|
||||
|
||||
class DirectoryModel {
|
||||
/**
|
||||
* DirectoryModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Directories';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Directory} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Directory} data
|
||||
*/
|
||||
update(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get directory with id
|
||||
* @param {number} id
|
||||
* @returns {Directory?}
|
||||
*/
|
||||
get(id) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
/** @type {import('realm').Results<Directory>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('id = ' + id)[0];
|
||||
return null;
|
||||
}
|
||||
return tmp;
|
||||
return tmp.filtered('id = ' + id)[0] ?? null;
|
||||
}
|
||||
|
||||
getAll(role, authorizedFolders, format, lang) {
|
||||
if (authorizedFolders !== null && authorizedFolders !== undefined) {
|
||||
authorizedFolders = JSON.parse(authorizedFolders);
|
||||
}
|
||||
/**
|
||||
* @param {string} role
|
||||
* @param {string} authorizedDirs JSON array of {Directory}
|
||||
* @param {boolean} format
|
||||
* @param {string} lang
|
||||
* @returns {import('realm').Results<Directory>}
|
||||
*/
|
||||
getAll(role, authorizedDirs, format, lang) {
|
||||
/** @type {Array<Directory>} */
|
||||
const allowedDirs =
|
||||
authorizedDirs !== null && authorizedDirs !== undefined
|
||||
? JSON.parse(authorizedDirs)
|
||||
: [];
|
||||
/** @type {import('realm').Results<Directory>} */
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
if (role === 'USER') {
|
||||
if (authorizedFolders.length > 0) {
|
||||
if (allowedDirs.length > 0) {
|
||||
tmp = tmp.filtered(
|
||||
'needAuthorization = 0 OR ' +
|
||||
authorizedFolders
|
||||
.map(folder => ' id = "' + folder.id + '"')
|
||||
allowedDirs
|
||||
.map(directory => ' id = "' + directory.id + '"')
|
||||
.join(' OR '),
|
||||
);
|
||||
} else {
|
||||
|
|
@ -60,18 +95,28 @@ class DirectoryModel {
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/** Delete all */
|
||||
clear() {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.realm.objects(this.schema));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive Dir filter
|
||||
*
|
||||
* @param {import('realm').Results<Directory>} list
|
||||
* @param {string} lang
|
||||
* @param {DirectoryData} parent
|
||||
* @returns {DirectoryData[]}
|
||||
*/
|
||||
_recursiveDir(list, lang, parent = null) {
|
||||
let root = list.filter(e => e.parent === parent);
|
||||
let tmp = [];
|
||||
const root = list.filter(e => e.parent === parent);
|
||||
const tmp = [];
|
||||
for (let i = 0; i < root.length; i++) {
|
||||
let childs = this._recursiveDir(list, lang, root[i].id);
|
||||
let name = JSON.parse(root[i].name);
|
||||
const childs = this._recursiveDir(list, lang, root[i].id);
|
||||
/** @type {Object<string,string>} */
|
||||
const name = JSON.parse(root[i].name);
|
||||
tmp[i] = {};
|
||||
tmp[i].id = root[i].id;
|
||||
tmp[i].name = this.getI18nName(lang, name);
|
||||
|
|
@ -87,7 +132,14 @@ class DirectoryModel {
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get i18n name
|
||||
* @param {string} lang
|
||||
* @param {Record<string,string>} name
|
||||
* @returns {string}
|
||||
*/
|
||||
getI18nName(lang, name) {
|
||||
/** @type {string} */
|
||||
let tmp;
|
||||
switch (lang) {
|
||||
case 'fr':
|
||||
|
|
|
|||
|
|
@ -2,33 +2,52 @@ export const DocumentsSchema = {
|
|||
name: 'Documents',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
/** @type {number} */
|
||||
id: 'int',
|
||||
uuid: 'string',
|
||||
title: 'string',
|
||||
type: 'string',
|
||||
path: 'string',
|
||||
/** @type {number} */
|
||||
directory: 'int',
|
||||
lang: 'string',
|
||||
updated_at: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof DocumentsSchema.properties> & import('realm').Object} Document
|
||||
*/
|
||||
|
||||
class DocumentModel {
|
||||
/**
|
||||
* DocumentModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Documents';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
add(document) {
|
||||
/**
|
||||
* @param {Document} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, document, 'never');
|
||||
this.realm.create(this.schema, data, 'never');
|
||||
});
|
||||
}
|
||||
|
||||
update(document, updatedAtChange = false) {
|
||||
let tmp = this.get(document.id);
|
||||
if (tmp === undefined) {
|
||||
this.add(document);
|
||||
/**
|
||||
* @param {Document} data
|
||||
* @param {boolean} updatedAtChange
|
||||
*/
|
||||
update(data, updatedAtChange = false) {
|
||||
const tmp = this.get(data.id);
|
||||
if (tmp === null) {
|
||||
this.add(data);
|
||||
} else {
|
||||
this.realm.write(() => {
|
||||
if (updatedAtChange === false) {
|
||||
|
|
@ -36,27 +55,41 @@ class DocumentModel {
|
|||
this.schema,
|
||||
{
|
||||
id: tmp.id,
|
||||
uuid: document.uuid,
|
||||
title: document.title,
|
||||
type: document.type,
|
||||
path: document.path,
|
||||
directory: document.directory,
|
||||
uuid: data.uuid,
|
||||
title: data.title,
|
||||
type: data.type,
|
||||
path: data.path,
|
||||
directory: data.directory,
|
||||
},
|
||||
'modified',
|
||||
);
|
||||
} else {
|
||||
this.realm.create(this.schema, document, 'modified');
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get document with id
|
||||
* @param {number} id
|
||||
* @returns {Document?}
|
||||
*/
|
||||
get(id) {
|
||||
let tmp = this.realm.objects(this.schema).filtered('id = ' + id)[0];
|
||||
return tmp;
|
||||
/** @type {Realm.Results<Document>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return tmp.filtered('id = ' + id)[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<import("./Directory").Directory>} authorizedDirs
|
||||
* @returns {import('realm').Results<Document>}
|
||||
*/
|
||||
getAll(authorizedDirs = false) {
|
||||
/** @type {Realm.Results<Document>} */
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
if (authorizedDirs) {
|
||||
authorizedDirs = authorizedDirs.map(item => item.id);
|
||||
|
|
@ -65,12 +98,22 @@ class DocumentModel {
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef { { uuid: typeof DocumentsSchema.properties.uuid, type: typeof DocumentsSchema.properties.type } } DocumentCleared
|
||||
*/
|
||||
|
||||
/**
|
||||
* Delete all
|
||||
* @param {Array<Document>} docs
|
||||
* @param {Array<DocumentCleared>} toDelete
|
||||
* @returns {Array<DocumentCleared>}
|
||||
*/
|
||||
clear(docs, toDelete = []) {
|
||||
const localDocs = this.getAll();
|
||||
localDocs.forEach(doc => {
|
||||
let tmp = docs.filter(item => item.uuid === doc.uuid);
|
||||
const tmp = docs.filter(item => item.uuid === doc.uuid);
|
||||
if (tmp.length === 0) {
|
||||
toDelete.push({uuid: doc.uuid, type: doc.type});
|
||||
toDelete.push({ uuid: doc.uuid, type: doc.type });
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(doc);
|
||||
});
|
||||
|
|
|
|||
107
ComApp/src/App/Models/Form.js
Normal file
107
ComApp/src/App/Models/Form.js
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import { UpdateMode } from 'realm';
|
||||
|
||||
export const FormData = {
|
||||
/** @type {number} */
|
||||
id: undefined,
|
||||
/** @type {import('./../Enums/InputType').InputType} */
|
||||
type: undefined,
|
||||
/** @type {string} */
|
||||
name: undefined,
|
||||
/** @type {string} */
|
||||
slug: undefined,
|
||||
|
||||
/** @type {import('realm').Dictionary<string>} list of translated placeholders Map<string,string> */
|
||||
placeholder: {},
|
||||
/** @type {import('realm').List<string>} list of json encoded translated details, list of Map<string,string> */
|
||||
details: [],
|
||||
/** @type {boolean} */
|
||||
is_visible: false,
|
||||
/** @type {boolean} */
|
||||
required: false,
|
||||
/** @type {import('./../Enums/InputStatus').InputStatus} */
|
||||
status: 0,
|
||||
/** @type {number} */
|
||||
order: 0,
|
||||
};
|
||||
|
||||
export const FormsSchema = {
|
||||
name: 'Formularies',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
id: 'int',
|
||||
type: 'int',
|
||||
name: 'string',
|
||||
slug: 'string',
|
||||
placeholder: { type: 'dictionary', objectType: 'string' },
|
||||
details: { type: 'list', objectType: 'string' },
|
||||
is_visible: 'bool',
|
||||
required: 'bool',
|
||||
status: 'int',
|
||||
order: 'int',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof FormData> & import('realm').Object} Form
|
||||
*/
|
||||
|
||||
class FormModel {
|
||||
/**
|
||||
* DocumentModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Formularies';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Form} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, UpdateMode.Never);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get document with id
|
||||
* @param {number} id
|
||||
* @returns {Form?}
|
||||
*/
|
||||
get(id) {
|
||||
/** @type {Realm.Results<Form>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return tmp.filtered(`id = ${id}`)[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('./../Enums/InputStatus').InputStatus|null} status
|
||||
* @returns {import('realm').Results<Form>}
|
||||
*/
|
||||
getAll(status = null) {
|
||||
const objects = this.realm.objects(this.schema);
|
||||
if (status !== null) {
|
||||
return objects.filtered(`status = ${status}`);
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef { { uuid: typeof FormsSchema.properties.uuid, type: typeof FormsSchema.properties.type } } DocumentCleared
|
||||
*/
|
||||
|
||||
/** Delete all */
|
||||
clear() {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.getAll());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default FormModel;
|
||||
|
|
@ -2,21 +2,36 @@ export const SendBrochuresSchema = {
|
|||
name: 'SendBrochures',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
/** @type {number} */
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
subject: 'string',
|
||||
message: 'string',
|
||||
documents: 'string',
|
||||
user_id: 'int',
|
||||
/** @type {number} */
|
||||
app_user_id: 'int',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof SendBrochuresSchema.properties> & import('realm').Object} SendBrochure
|
||||
*/
|
||||
|
||||
class SendBrochureModel {
|
||||
/**
|
||||
* SendBrochureModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'SendBrochures';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SendBrochure} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
if (data.id === undefined) {
|
||||
|
|
@ -31,9 +46,12 @@ class SendBrochureModel {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SendBrochure} data
|
||||
*/
|
||||
upsert(data) {
|
||||
let tmp = this.get(data.key);
|
||||
if (tmp === false || tmp === undefined) {
|
||||
const tmp = this.get(data.key);
|
||||
if (tmp === null) {
|
||||
this.add(data);
|
||||
} else {
|
||||
if (data.id === undefined) {
|
||||
|
|
@ -45,35 +63,49 @@ class SendBrochureModel {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SendBrochure} data
|
||||
*/
|
||||
update(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get sendBrochure with id
|
||||
* @param {number} id
|
||||
* @returns {SendBrochure?}
|
||||
*/
|
||||
get(id) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
/** @type {import('realm').Results<SendBrochure>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('id = ' + id)[0];
|
||||
return null;
|
||||
}
|
||||
return tmp;
|
||||
return tmp.filtered('id = ' + id)[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import('realm').Results<SendBrochure>}
|
||||
*/
|
||||
getAll() {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
return tmp;
|
||||
return this.realm.objects(this.schema);
|
||||
}
|
||||
|
||||
/** Delete all */
|
||||
clear() {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.getAll());
|
||||
});
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const tmp = this.get(key);
|
||||
/**
|
||||
* delete sendBrochure with id
|
||||
* @param {number} id id
|
||||
*/
|
||||
delete(id) {
|
||||
const tmp = this.get(id);
|
||||
if (typeof tmp === 'object') {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(tmp);
|
||||
|
|
|
|||
|
|
@ -2,22 +2,36 @@ export const SettingsSchema = {
|
|||
name: 'Settings',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
/** @type {number} */
|
||||
id: 'int',
|
||||
key: 'string',
|
||||
value: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof SettingsSchema.properties> & import('realm').Object} Setting
|
||||
*/
|
||||
|
||||
class SettingModel {
|
||||
/**
|
||||
* SettingModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Settings';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Setting} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
if (data.id === undefined) {
|
||||
let id = this.realm.objects(this.schema).max('id');
|
||||
const id = this.realm.objects(this.schema).max('id');
|
||||
data.id = id === undefined ? 1 : id + 1;
|
||||
}
|
||||
try {
|
||||
|
|
@ -28,9 +42,12 @@ class SettingModel {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Setting} data
|
||||
*/
|
||||
upsert(data) {
|
||||
let tmp = this.get(data.key);
|
||||
if (tmp === false || tmp === undefined) {
|
||||
const tmp = this.get(data.key);
|
||||
if (tmp === null) {
|
||||
this.add(data);
|
||||
} else {
|
||||
if (data.id === undefined) {
|
||||
|
|
@ -42,24 +59,35 @@ class SettingModel {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Setting} data
|
||||
*/
|
||||
update(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get setting with key
|
||||
* @param {string} key
|
||||
* @returns {Setting?}
|
||||
*/
|
||||
get(key) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
/** @type {import('realm').Results<Setting>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('key = "' + key + '"')[0];
|
||||
return null;
|
||||
}
|
||||
return tmp;
|
||||
return tmp.filtered('key = "' + key + '"')[0] ?? null;
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
const tmp = this.get(key);
|
||||
/**
|
||||
* delete setting with id
|
||||
* @param {number} id id
|
||||
*/
|
||||
delete(id) {
|
||||
const tmp = this.get(id);
|
||||
if (typeof tmp === 'object') {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(tmp);
|
||||
|
|
|
|||
|
|
@ -1,23 +1,55 @@
|
|||
/**
|
||||
* @typedef {typeof UserData} UserData
|
||||
*/
|
||||
export const UserData = {
|
||||
/** @type {string|undefined} */
|
||||
id: undefined,
|
||||
/** @type {string} */
|
||||
surname: undefined,
|
||||
/** @type {string|null} */
|
||||
lastname: null,
|
||||
/** @type {string|null} */
|
||||
firstname: null,
|
||||
/** @type {string|null} */
|
||||
role: null,
|
||||
/** @type {string|null} */
|
||||
authorizedFolders: null,
|
||||
};
|
||||
export const UsersSchema = {
|
||||
name: 'Users',
|
||||
primaryKey: 'id',
|
||||
properties: {
|
||||
/** @type {number} */
|
||||
id: 'int',
|
||||
email: 'string',
|
||||
surname: 'string',
|
||||
firstname: 'string',
|
||||
password: 'string',
|
||||
role: 'string',
|
||||
/** Json encoded string of {import('./Models/Directory').Directory[]} */
|
||||
authorizedFolders: 'string',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Unmanaged<typeof UsersSchema.properties> & import('realm').Object} User
|
||||
*/
|
||||
|
||||
class UserModel {
|
||||
/**
|
||||
* UserModel
|
||||
* @param {Realm} realm
|
||||
*/
|
||||
constructor(realm) {
|
||||
/** @type string */
|
||||
this.schema = 'Users';
|
||||
/** @type {Realm} */
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {User} data
|
||||
*/
|
||||
add(data) {
|
||||
this.realm.write(() => {
|
||||
if (data.id === undefined) {
|
||||
|
|
@ -32,8 +64,11 @@ class UserModel {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {User} data
|
||||
*/
|
||||
upsert(data) {
|
||||
let tmp = this.get(data.key);
|
||||
const tmp = this.get(data.key);
|
||||
if (tmp === false || tmp === undefined) {
|
||||
this.add(data);
|
||||
} else {
|
||||
|
|
@ -46,27 +81,37 @@ class UserModel {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {User} data
|
||||
*/
|
||||
update(data) {
|
||||
this.realm.write(() => {
|
||||
this.realm.create(this.schema, data, 'modified');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* get user with id
|
||||
* @param {number} id
|
||||
* @returns {User?}
|
||||
*/
|
||||
get(id) {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
/** @type {import('realm').Results<User>} */
|
||||
const tmp = this.realm.objects(this.schema);
|
||||
if (tmp.length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
tmp = tmp.filtered('id = ' + id)[0];
|
||||
return null;
|
||||
}
|
||||
return tmp;
|
||||
return tmp.filtered('key = "' + id + '"')[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import('realm').Results<User>}
|
||||
*/
|
||||
getAll() {
|
||||
let tmp = this.realm.objects(this.schema);
|
||||
return tmp;
|
||||
return this.realm.objects(this.schema);
|
||||
}
|
||||
|
||||
/** Delete all */
|
||||
clear() {
|
||||
this.realm.write(() => {
|
||||
this.realm.delete(this.getAll());
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@ export const EDIT_LOCALE = 'EDIT_LOCALE';
|
|||
export const INIT_USERS = 'INIT_USERS';
|
||||
// Contacts
|
||||
export const INIT_CONTACT = 'INIT_CONTACT';
|
||||
export const ADD_CONTACT = 'ADD_CONTACT';
|
||||
export const EDIT_CONTACT = 'EDIT_CONTACT';
|
||||
export const SET_CONTACT = 'ADD_CONTACT';
|
||||
export const DELETE_CONTACT = 'DELETE_CONTACT';
|
||||
// Directories
|
||||
export const INIT_DIRECTORIES = 'INIT_DIRECTORIES';
|
||||
// Documents
|
||||
export const INIT_DOCUMENTS = 'INIT_DOCUMENTS';
|
||||
// Formularies
|
||||
export const INIT_FORMS = 'INIT_FORMS';
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
import {
|
||||
ADD_CONTACT,
|
||||
DELETE_CONTACT,
|
||||
EDIT_CONTACT,
|
||||
INIT_CONTACT,
|
||||
} from './actionType';
|
||||
import { DELETE_CONTACT, INIT_CONTACT, SET_CONTACT } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {currentUser: import('../../Models/User').User, data: import('../../Models/Contact').Contact} } InitContactAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {object} data The contact data
|
||||
* @param {import('../../Models/User').User} currentUser The currentUser
|
||||
* @param {import('../../Models/Contact').Contact} data The contact data
|
||||
*/
|
||||
export const initContact = (currentUser, data) => {
|
||||
return {
|
||||
|
|
@ -19,40 +18,35 @@ export const initContact = (currentUser, data) => {
|
|||
};
|
||||
|
||||
/**
|
||||
* Add contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {object} data The contact data
|
||||
* @typedef { {currentUser: import('../../Models/User').User, data: import('../../Models/Contact').Contact} } SetContactAction
|
||||
*/
|
||||
export const addContact = (currentUser, data) => {
|
||||
|
||||
/**
|
||||
* Add contact
|
||||
* @param {import('../../Models/User').User} currentUser The currentUser
|
||||
* @param {import('../../Models/Contact').Contact} data The contact data
|
||||
*/
|
||||
export const setContact = (currentUser, data) => {
|
||||
return {
|
||||
type: ADD_CONTACT,
|
||||
type: SET_CONTACT,
|
||||
currentUser,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Edit contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {object} data The contact data
|
||||
* @typedef { {currentUser: import('../../Models/User').User, uuid: string} } DeleteContactAction
|
||||
*/
|
||||
export const editContact = (currentUser, data) => {
|
||||
return {
|
||||
type: EDIT_CONTACT,
|
||||
currentUser,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete contact
|
||||
* @param {object} currentUser The currentUser
|
||||
* @param {string} id The contact id
|
||||
* @param {import('../../Models/User').User} currentUser The currentUser
|
||||
* @param {string} uuid The contact uuid
|
||||
*/
|
||||
export const deleteContact = (currentUser, id) => {
|
||||
export const deleteContact = (currentUser, uuid) => {
|
||||
return {
|
||||
type: DELETE_CONTACT,
|
||||
currentUser,
|
||||
id,
|
||||
uuid: uuid,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
import {INIT_DIRECTORIES} from './actionType';
|
||||
import { INIT_DIRECTORIES } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof INIT_DIRECTORIES, lang: string, user: import('../../Models/User').User, data: import('../../Models/Directory').Directory} } InitDirectoryAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init
|
||||
* @param {string} lang The lang
|
||||
* @param {object} user User
|
||||
* @param {object} data The document data
|
||||
* @param {import('../../Models/User').User} user
|
||||
* @param {import('../../Models/Directory').Directory} data The document data
|
||||
* @returns {InitDirectoryAction}
|
||||
*/
|
||||
export const initDirectories = (lang, user, data) => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
import {INIT_DOCUMENTS} from './actionType';
|
||||
import { INIT_DOCUMENTS } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof INIT_DOCUMENTS, lang: string, directories: import('realm').Results<import('../../Models/Directory').Directory>, data: import('../../Models/Document').Document } } InitDocumentsAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init contact
|
||||
* @param {string} lang The lang
|
||||
* @param {object} directories Directories
|
||||
* @param {object} data The document data
|
||||
* @param {Realm.Results<import('../../Models/Directory').Directory>} directories Directories
|
||||
* @param {import('../../Models/Document').Document} data The document data
|
||||
*/
|
||||
export const initDocuments = (lang, directories, data) => {
|
||||
return {
|
||||
|
|
|
|||
16
ComApp/src/App/Store/Actions/formularies.js
Normal file
16
ComApp/src/App/Store/Actions/formularies.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { INIT_FORMS } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof INIT_FORMS, data: import('../../Models/Form').Form } } InitFormAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init forms
|
||||
* @param {import('../../Models/Form').Form} data The forms data
|
||||
*/
|
||||
export const initFormularies = data => {
|
||||
return {
|
||||
type: INIT_FORMS,
|
||||
data,
|
||||
};
|
||||
};
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
import {EDIT_LOCALE, INIT_LOCALE} from './actionType';
|
||||
import { EDIT_LOCALE, INIT_LOCALE } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof INIT_LOCALE, data: string } } InitLocaleAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init locale
|
||||
* @param {object} data The locale data
|
||||
* @param {string} data The locale data
|
||||
*/
|
||||
export const initLocale = data => {
|
||||
return {
|
||||
|
|
@ -11,9 +15,13 @@ export const initLocale = data => {
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof EDIT_LOCALE, data: string } } EditLocaleAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Edit locale
|
||||
* @param {object} data The locale data
|
||||
* @param {string} data The locale data
|
||||
*/
|
||||
export const editLocale = data => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import {INIT_USERS} from './actionType';
|
||||
import { INIT_USERS } from './actionType';
|
||||
|
||||
/**
|
||||
* @typedef { {type: typeof INIT_USERS, data: import('../../Models/User').User } } InitUserAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* Init users
|
||||
* @param {object} data The users data
|
||||
* @param {import('../../Models/User').User} data The users data
|
||||
*/
|
||||
export const initUsers = data => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import {combineReducers, createStore} from 'redux';
|
||||
import { combineReducers, createStore } from 'redux';
|
||||
|
||||
import appReducer from './Reducers/AppReducer';
|
||||
import contactsReducer from './Reducers/contacts';
|
||||
import directoriesReducer from './Reducers/directories';
|
||||
import documentsReducer from './Reducers/documents';
|
||||
import formulariesReducer from './Reducers/formularies';
|
||||
import localesReducer from './Reducers/locales';
|
||||
import usersReducer from './Reducers/users';
|
||||
|
||||
|
|
@ -14,6 +15,7 @@ const rootReducer = combineReducers({
|
|||
directories: directoriesReducer,
|
||||
locale: localesReducer,
|
||||
users: usersReducer,
|
||||
formularies: formulariesReducer,
|
||||
});
|
||||
|
||||
export const store = createStore(rootReducer);
|
||||
|
|
|
|||
|
|
@ -13,9 +13,6 @@ const initialState = {
|
|||
ShowIsActive: 0,
|
||||
HomeBtns: {},
|
||||
mainColor: '#D4021D',
|
||||
FormSelect1: {},
|
||||
FormSelect2: {},
|
||||
FormCheck: [],
|
||||
};
|
||||
|
||||
const reducer = (state = initialState, action) => {
|
||||
|
|
@ -24,43 +21,22 @@ const reducer = (state = initialState, action) => {
|
|||
case 'INIT':
|
||||
let ShowIsActive = Setting.get('ShowIsActive');
|
||||
let MainColor = Setting.get('MainColor');
|
||||
let FormSelect1 = Setting.get('FormSelect1');
|
||||
let FormSelect2 = Setting.get('FormSelect2');
|
||||
let FormCheck = Setting.get('FormCheck');
|
||||
saved = Setting.get('isSetup');
|
||||
return {
|
||||
...state,
|
||||
isSetup:
|
||||
saved === undefined ? false : saved.value === 'true' ? true : false,
|
||||
ShowIsActive: ShowIsActive === undefined ? false : ShowIsActive.value,
|
||||
saved === undefined ? false : saved?.value === 'true' ? true : false,
|
||||
ShowIsActive: ShowIsActive ? ShowIsActive?.value : false,
|
||||
mainColor:
|
||||
MainColor === undefined
|
||||
? initialState.mainColor
|
||||
: MainColor === false
|
||||
: MainColor === null
|
||||
? initialState.mainColor
|
||||
: MainColor.value,
|
||||
FormSelect1:
|
||||
FormSelect1 === undefined
|
||||
? initialState.FormSelect1
|
||||
: FormSelect1 === false
|
||||
? initialState.FormSelect1
|
||||
: JSON.parse(FormSelect1.value),
|
||||
FormSelect2:
|
||||
FormSelect2 === undefined
|
||||
? initialState.FormSelect2
|
||||
: FormSelect2 === false
|
||||
? initialState.FormSelect2
|
||||
: JSON.parse(FormSelect2.value),
|
||||
FormCheck:
|
||||
FormCheck === undefined
|
||||
? initialState.FormCheck
|
||||
: FormCheck === false
|
||||
? initialState.FormCheck
|
||||
: JSON.parse(FormCheck.value),
|
||||
: MainColor?.value,
|
||||
};
|
||||
case 'INIT_HOME_BTNS': {
|
||||
let HomeFolders = Setting.get('HomeFolders');
|
||||
let Btns = JSON.parse(HomeFolders.value);
|
||||
let Btns = HomeFolders ? JSON.parse(HomeFolders?.value) : [];
|
||||
return {
|
||||
...state,
|
||||
HomeBtns: Btns,
|
||||
|
|
@ -72,7 +48,7 @@ const reducer = (state = initialState, action) => {
|
|||
return {
|
||||
...state,
|
||||
isSetup:
|
||||
saved === undefined ? false : saved.value === 'true' ? true : false,
|
||||
saved === undefined ? false : saved?.value === 'true' ? true : false,
|
||||
};
|
||||
case 'SET_CURRENT_USER':
|
||||
let user = false;
|
||||
|
|
@ -80,8 +56,8 @@ const reducer = (state = initialState, action) => {
|
|||
if (action.data === false) {
|
||||
Setting.delete('isLogged');
|
||||
} else {
|
||||
userObj = Setting.get('isLogged').value;
|
||||
user = JSON.parse(userObj);
|
||||
let userObj = Setting.get('isLogged');
|
||||
user = userObj ? JSON.parse(userObj?.value) : false;
|
||||
isLogged = true;
|
||||
}
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,31 +1,32 @@
|
|||
import {
|
||||
ADD_CONTACT,
|
||||
DELETE_CONTACT,
|
||||
EDIT_CONTACT,
|
||||
INIT_CONTACT,
|
||||
SET_CONTACT,
|
||||
} from '../Actions/actionType';
|
||||
// Models
|
||||
import {Contact} from '../../../Database';
|
||||
import { Contact } from '../../../Database';
|
||||
|
||||
/** @type {import('../../Models/Contact').Contact[]} */
|
||||
const initialState = [];
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/contacts').InitContactAction|import('../Actions/contacts').SetContactAction|import('../Actions/contacts').DeleteContactAction} action
|
||||
* @returns {import('realm').Results<import('../../Models/Contact').Contact>}
|
||||
*/
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_CONTACT: {
|
||||
return Contact.getByUser(action.currentUser.id);
|
||||
return Contact.getAllEditable(action.currentUser.id);
|
||||
}
|
||||
case ADD_CONTACT: {
|
||||
action.data.user_id = action.currentUser.id;
|
||||
Contact.add(action.data);
|
||||
return Contact.getByUser(action.currentUser.id);
|
||||
}
|
||||
case EDIT_CONTACT: {
|
||||
Contact.update(action.data);
|
||||
return Contact.getByUser(action.currentUser.id);
|
||||
case SET_CONTACT: {
|
||||
action.data.app_user_id = action.currentUser.id;
|
||||
Contact.set(action.data);
|
||||
return Contact.getAllEditable(action.currentUser.id);
|
||||
}
|
||||
case DELETE_CONTACT: {
|
||||
Contact.delete(action.id);
|
||||
return Contact.getByUser(action.currentUser.id);
|
||||
Contact.delete(action.currentUser.id, action.uuid);
|
||||
return Contact.getAllEditable(action.currentUser.id);
|
||||
}
|
||||
|
||||
default: {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,19 @@
|
|||
import {INIT_DIRECTORIES} from '../Actions/actionType';
|
||||
import { Directory } from '../../../Database';
|
||||
import { INIT_DIRECTORIES } from '../Actions/actionType';
|
||||
// Models
|
||||
import {Directory} from '../../../Database';
|
||||
|
||||
const initialState = [];
|
||||
const initialState = {
|
||||
/** @type {Realm.Results<import('../../Models/Directory').Directory>} */
|
||||
global: [],
|
||||
/** @type {Realm.Results<import('../../Models/Directory').Directory>} */
|
||||
treeview: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/directories').InitDirectoryAction} action
|
||||
* @returns
|
||||
*/
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_DIRECTORIES: {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
import {INIT_DOCUMENTS} from '../Actions/actionType';
|
||||
import { INIT_DOCUMENTS } from '../Actions/actionType';
|
||||
// Models
|
||||
import {Document} from '../../../Database';
|
||||
import { Document } from '../../../Database';
|
||||
|
||||
/** @type {import('../../Models/Document').Document[]} */
|
||||
const initialState = [];
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/documents').InitDocumentsAction} action
|
||||
* @returns
|
||||
*/
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_DOCUMENTS: {
|
||||
let docs = Document.getAll(action.directories);
|
||||
const docs = Document.getAll(action.directories);
|
||||
if (docs.length === 0) {
|
||||
return state;
|
||||
}
|
||||
|
|
|
|||
30
ComApp/src/App/Store/Reducers/formularies.js
Normal file
30
ComApp/src/App/Store/Reducers/formularies.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { INIT_FORMS } from '../Actions/actionType';
|
||||
// Models
|
||||
import { Form } from '../../../Database';
|
||||
|
||||
const initialState = {
|
||||
/** @type {Realm.Results<import('../../Models/Form').Form>} */
|
||||
users: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/formularies').InitFormAction} action
|
||||
* @returns
|
||||
*/
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_FORMS: {
|
||||
return {
|
||||
...state,
|
||||
forms: Form.getAll(),
|
||||
};
|
||||
}
|
||||
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default reducer;
|
||||
|
|
@ -1,30 +1,32 @@
|
|||
import {EDIT_LOCALE, INIT_LOCALE} from '../Actions/actionType';
|
||||
import { EDIT_LOCALE, INIT_LOCALE } from '../Actions/actionType';
|
||||
// Models
|
||||
import {Setting} from '../../../Database';
|
||||
import { Setting } from '../../../Database';
|
||||
// Translations
|
||||
import i18n from '../../../I18n';
|
||||
|
||||
const initialState = [];
|
||||
const initialState = {
|
||||
locale: 'fr',
|
||||
};
|
||||
const availableLocales = ['fr', 'en', 'de'];
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/locales').InitLocaleAction|import('../Actions/locales').EditLocaleAction} action
|
||||
* @returns
|
||||
*/
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_LOCALE: {
|
||||
const savedLocale = Setting.get('locale');
|
||||
return {
|
||||
...state,
|
||||
locale:
|
||||
savedLocale === undefined
|
||||
? 'fr'
|
||||
: savedLocale === false
|
||||
? 'fr'
|
||||
: savedLocale.value,
|
||||
locale: savedLocale === null ? initialState.locale : savedLocale.value,
|
||||
};
|
||||
}
|
||||
|
||||
case EDIT_LOCALE: {
|
||||
let nxt;
|
||||
if (action.data === undefined) {
|
||||
const availableLocales = ['fr', 'en', 'de'];
|
||||
if (
|
||||
availableLocales.indexOf(i18n.locale) ===
|
||||
availableLocales.length - 1
|
||||
|
|
@ -37,7 +39,7 @@ const reducer = (state = initialState, action) => {
|
|||
nxt = action.data;
|
||||
}
|
||||
i18n.locale = nxt;
|
||||
Setting.upsert({key: 'locale', value: nxt});
|
||||
Setting.upsert({ key: 'locale', value: nxt });
|
||||
return {
|
||||
...state,
|
||||
locale: nxt,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,17 @@
|
|||
import {INIT_USERS} from '../Actions/actionType';
|
||||
import { INIT_USERS } from '../Actions/actionType';
|
||||
// Models
|
||||
import {User} from '../../../Database';
|
||||
import { User } from '../../../Database';
|
||||
|
||||
const initialState = [];
|
||||
const initialState = {
|
||||
/** @type {Realm.Results<import('../../Models/User').User>} */
|
||||
users: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {typeof initialState} state
|
||||
* @param {import('../Actions/users').InitUserAction} action
|
||||
* @returns
|
||||
*/
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case INIT_USERS: {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3,14 +3,18 @@ import {
|
|||
Alert,
|
||||
Button,
|
||||
FlatList,
|
||||
Linking,
|
||||
Platform,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { openComposer } from 'react-native-email-link';
|
||||
|
||||
// Reduxs
|
||||
import { connect } from 'react-redux';
|
||||
import { deleteContact, editContact } from '../Store/Actions/contacts';
|
||||
import { deleteContact, setContact } from '../Store/Actions/contacts';
|
||||
// Helpers
|
||||
import Helpers from '../Lib/Helpers';
|
||||
// Translations
|
||||
|
|
@ -36,9 +40,15 @@ function mapStateToProps(state) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {(user: import('./../Models/User').User, data: import('./../Models/Contact').Contact) => void} setContact
|
||||
* @typedef {(user: import('./../Models/User').User, uuid: string ) => void} deleteContact
|
||||
* @typedef {(email: string ) => void} sendBrochure
|
||||
*/
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
editContact: (user, data) => dispatch(editContact(user, data)),
|
||||
setContact: (user, data) => dispatch(setContact(user, data)),
|
||||
deleteContact: (user, id) => dispatch(deleteContact(user, id)),
|
||||
sendBrochure: email => dispatch({ type: 'SEND_BROCHURE', data: email }),
|
||||
};
|
||||
|
|
@ -50,9 +60,6 @@ class ContactScreen extends React.Component {
|
|||
sortType: 'asc',
|
||||
sortField: 'name',
|
||||
searchTxt: '',
|
||||
showTransferContact: false,
|
||||
selectedTransferUser: 0,
|
||||
contactToTransfer: {},
|
||||
showSendBrochure: false,
|
||||
selectedDocument: -1,
|
||||
sendDocumentList: [],
|
||||
|
|
@ -62,9 +69,21 @@ class ContactScreen extends React.Component {
|
|||
tmpSendBrochureMessage: '',
|
||||
sortedDocuments: [],
|
||||
sortedEmails: [],
|
||||
|
||||
/** @type {number} The user index selected for transfert */
|
||||
selectedTransferUserIndex: 0,
|
||||
|
||||
/** @type {import('./../Models/Contact').Contact|null} The contact to transfert */
|
||||
contactToTransfer: null,
|
||||
|
||||
/** @type {boolean} Is tranfert contact model display ? */
|
||||
showTransferContact: false,
|
||||
};
|
||||
|
||||
// * --- ACTIONS
|
||||
|
||||
sendBrochure() {
|
||||
// FIXME: Si on n'a pas consulté les documents la liste des documents est vide apres initialisation
|
||||
if (
|
||||
this.state.tmpSendBrochureEmail !== '' &&
|
||||
this.state.tmpSendBrochureSubject !== '' &&
|
||||
|
|
@ -72,14 +91,16 @@ class ContactScreen extends React.Component {
|
|||
this.state.sendDocumentList.length > 0 &&
|
||||
Helpers.isEmailValid(this.state.tmpSendBrochureEmail)
|
||||
) {
|
||||
/** @type {sendBrochure} */
|
||||
const sendBrochure = this.props.sendBrochure;
|
||||
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,
|
||||
app_user_id: this.props.currentUser.id,
|
||||
};
|
||||
this.props.sendBrochure(email);
|
||||
sendBrochure(email);
|
||||
this.setState({
|
||||
showSendBrochure: false,
|
||||
tmpSendBrochureEmail: '',
|
||||
|
|
@ -104,31 +125,25 @@ class ContactScreen extends React.Component {
|
|||
}
|
||||
|
||||
transferContact() {
|
||||
/** @type {import('./../Models/User').User} */
|
||||
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.editContact(this.props.currentUser, contact);
|
||||
this.setState({ showTransferContact: false });
|
||||
)[this.state.selectedTransferUserIndex];
|
||||
/** @type {import('./../Models/Contact').ContactData} cloned contact */
|
||||
const transferContact = this.state.contactToTransfer.toJSON();
|
||||
if (transferContact === null) {
|
||||
throw new Error('No selected contact to transfert');
|
||||
}
|
||||
|
||||
// * Assign cloned contact to another user
|
||||
transferContact.send_to_app_user_id = nextUser.id;
|
||||
transferContact.timestamp = new Date();
|
||||
transferContact.synced = false;
|
||||
|
||||
/** @type {setContact} */
|
||||
const setContactHook = this.props.setContact;
|
||||
setContactHook(this.props.currentUser, transferContact);
|
||||
this.setState({ showTransferContact: false, contactToTransfer: null });
|
||||
showMessage({
|
||||
message: i18n.t('contact_s.contact_transferred') + '.',
|
||||
description: i18n.t('contact_s.contact_will_be_sent_after_sync') + '.',
|
||||
|
|
@ -137,7 +152,11 @@ class ContactScreen extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
deleteContactAction(id) {
|
||||
/**
|
||||
* Delete contact
|
||||
* @param {import('../Models/Contact').Contact} contact
|
||||
*/
|
||||
deleteContactAction(contact) {
|
||||
Alert.alert(
|
||||
i18n.t('global.confirmation'),
|
||||
i18n.t('contact_s.confirm_contact_delete'),
|
||||
|
|
@ -151,7 +170,12 @@ class ContactScreen extends React.Component {
|
|||
text: i18n.t('global.yes'),
|
||||
onPress: () => {
|
||||
this.setState({ contacts: [], sortedEmails: [] });
|
||||
this.props.deleteContact(this.props.currentUser, id);
|
||||
/** @type {setContact} */
|
||||
const setContactHook = this.props.setContact;
|
||||
/** @type {import('./../Models/Contact').ContactData} */
|
||||
const contactToDelete = contact.toJSON();
|
||||
contactToDelete.to_delete = true;
|
||||
setContactHook(this.props.currentUser, contactToDelete);
|
||||
showMessage({
|
||||
message: i18n.t('contact_s.contact_deleted') + '.',
|
||||
type: 'success',
|
||||
|
|
@ -164,27 +188,112 @@ class ContactScreen extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
Item(item) {
|
||||
/**
|
||||
* Try to call the number
|
||||
*
|
||||
* @param {string} phone
|
||||
*/
|
||||
callNumberIfSupported(phone) {
|
||||
let phoneNumber = phone;
|
||||
if (Platform.OS !== 'android') {
|
||||
phoneNumber = `telprompt:${phone}`;
|
||||
} else {
|
||||
phoneNumber = `tel:${phone}`;
|
||||
}
|
||||
Linking.canOpenURL(phoneNumber)
|
||||
.then(supported => {
|
||||
if (supported) {
|
||||
return Linking.openURL(phoneNumber);
|
||||
}
|
||||
})
|
||||
.catch(err => console.log(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new email to
|
||||
*
|
||||
* @param {string} email
|
||||
*/
|
||||
composeNewEmailTo(email) {
|
||||
openComposer({
|
||||
to: email,
|
||||
});
|
||||
}
|
||||
|
||||
// * END --- ACTIONS
|
||||
|
||||
/**
|
||||
* Render the table header
|
||||
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
HeaderItem() {
|
||||
return (
|
||||
<View style={styles.item}>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.sortContacts('lastname');
|
||||
}}>
|
||||
<Text style={{ ...styles.clickable, color: this.props.mainColor }}>
|
||||
{i18n.t('global.lastname')} <FontAwesome5 name={'sort'} />
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.sortContacts('email');
|
||||
}}>
|
||||
<Text style={{ ...styles.clickable, color: this.props.mainColor }}>
|
||||
{i18n.t('global.email')} <FontAwesome5 name={'sort'} />
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.sortContacts('phone');
|
||||
}}>
|
||||
<Text style={{ ...styles.clickable, color: this.props.mainColor }}>
|
||||
{i18n.t('global.phone')} <FontAwesome5 name={'sort'} />
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.buttons} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a line of contact
|
||||
* @param {import('../Models/Contact').Contact} contact
|
||||
* @returns
|
||||
*/
|
||||
Item(contact) {
|
||||
const displayName =
|
||||
String(contact.lastname ?? '').toUpperCase() + ' ' + contact.firstname;
|
||||
return (
|
||||
<View style={styles.item}>
|
||||
<TouchableOpacity
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate('ContactDetailsScreen', {
|
||||
action: 'edit',
|
||||
contactId: item.id,
|
||||
contactId: contact.id,
|
||||
})
|
||||
}>
|
||||
<Text style={{ ...styles.clickable, color: this.props.mainColor }}>
|
||||
{item.name.toUpperCase()} {item.firstname}
|
||||
{contact.lastname && contact.firstname ? displayName : contact.id}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.company}>{item.company}</Text>
|
||||
<Text style={styles.email}>{item.email}</Text>
|
||||
<TouchableOpacity onPress={() => this.composeNewEmailTo(contact.email)}>
|
||||
<Text style={{ ...styles.clickable }}>{contact.email}</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() =>
|
||||
contact.phone ? this.callNumberIfSupported(contact.phone) : false
|
||||
}>
|
||||
<Text style={{ ...styles.clickable }}>{contact.phone}</Text>
|
||||
</TouchableOpacity>
|
||||
<View style={styles.buttons}>
|
||||
<TouchableOpacity
|
||||
style={styles.button}
|
||||
onPress={() => {
|
||||
this.deleteContactAction(item.id);
|
||||
this.deleteContactAction(contact);
|
||||
}}>
|
||||
<FontAwesome5 name="trash" size={20} color={this.props.mainColor} />
|
||||
</TouchableOpacity>
|
||||
|
|
@ -193,7 +302,7 @@ class ContactScreen extends React.Component {
|
|||
onPress={() => {
|
||||
this.setState({
|
||||
showTransferContact: true,
|
||||
contactToTransfer: item,
|
||||
contactToTransfer: contact,
|
||||
});
|
||||
}}>
|
||||
<FontAwesome5
|
||||
|
|
@ -225,31 +334,6 @@ class ContactScreen extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
HeaderItem() {
|
||||
return (
|
||||
<View style={styles.item}>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.sortContacts('name');
|
||||
}}>
|
||||
<Text style={{ ...styles.clickable, color: this.props.mainColor }}>
|
||||
{i18n.t('global.name')} <FontAwesome5 name={'sort'} />
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.sortContacts('company');
|
||||
}}>
|
||||
<Text style={{ ...styles.clickable, color: this.props.mainColor }}>
|
||||
{i18n.t('global.company')} <FontAwesome5 name={'sort'} />
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.email}>{i18n.t('global.email')}</Text>
|
||||
<Text style={styles.buttons} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
handleSearchBtn() {
|
||||
if (this.state.searchTxt.length > 0) {
|
||||
let obj = this.props.contacts;
|
||||
|
|
@ -265,16 +349,34 @@ class ContactScreen extends React.Component {
|
|||
}
|
||||
handleSearchTxt(text) {
|
||||
this.setState({ searchTxt: text });
|
||||
/** @type {Array<import('./../Models/Contact').Contact>} */
|
||||
const contacts = this.props.contacts;
|
||||
if (text.length > 0) {
|
||||
let tmpContactsName = this.props.contacts.filter(
|
||||
item => item.name.toLowerCase().indexOf(text.toLowerCase()) >= 0,
|
||||
const tmpContactsLastname = contacts.filter(
|
||||
item => item.lastname?.toLowerCase()?.indexOf(text.toLowerCase()) >= 0,
|
||||
);
|
||||
let tmpContactsCompany = this.props.contacts.filter(
|
||||
item => item.company.toLowerCase().indexOf(text.toLowerCase()) >= 0,
|
||||
const tmpContactsFirstname = contacts.filter(
|
||||
item => item.firstname?.toLowerCase()?.indexOf(text.toLowerCase()) >= 0,
|
||||
);
|
||||
let resSearch = Object.assign(tmpContactsName, tmpContactsCompany);
|
||||
const tmpContactsEmail = contacts.filter(
|
||||
item => item.email.toLowerCase().indexOf(text.toLowerCase()) >= 0,
|
||||
);
|
||||
const tmpContactsPhone = contacts.filter(
|
||||
item => item.phone?.toLowerCase()?.indexOf(text.toLowerCase()) >= 0,
|
||||
);
|
||||
const resSearch = new Map();
|
||||
tmpContactsLastname.forEach(contact =>
|
||||
resSearch.set(contact.id, contact),
|
||||
);
|
||||
tmpContactsFirstname.forEach(contact =>
|
||||
resSearch.set(contact.id, contact),
|
||||
);
|
||||
tmpContactsEmail.forEach(contact => resSearch.set(contact.id, contact));
|
||||
tmpContactsPhone.forEach(contact => resSearch.set(contact.id, contact));
|
||||
this.setState({
|
||||
contacts: resSearch.sort(Helpers.compareValues('name', 'asc')),
|
||||
contacts: [...resSearch.values()].sort(
|
||||
Helpers.compareValues('name', 'asc'),
|
||||
),
|
||||
sortType: 'asc',
|
||||
});
|
||||
} else {
|
||||
|
|
@ -320,7 +422,7 @@ class ContactScreen extends React.Component {
|
|||
}
|
||||
|
||||
this.setState({
|
||||
contacts: arrayContacts.sort(Helpers.compareValues('name', 'asc')),
|
||||
contacts: arrayContacts.sort(Helpers.compareValues('timestamp', 'desc')),
|
||||
sortedDocuments: arrayDocs.sort(Helpers.compareValues('title', 'asc')),
|
||||
sortedEmails: arrayEmails.sort(Helpers.compareValues('email', 'asc')),
|
||||
sortType: 'asc',
|
||||
|
|
@ -341,6 +443,7 @@ class ContactScreen extends React.Component {
|
|||
}
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{/* ACTIONS */}
|
||||
<View
|
||||
style={{
|
||||
marginTop: 20,
|
||||
|
|
@ -383,6 +486,7 @@ class ContactScreen extends React.Component {
|
|||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
{/* TABLE view */}
|
||||
<View style={{ flex: 1, marginTop: 20 }}>
|
||||
<FlatList
|
||||
data={this.state.contacts}
|
||||
|
|
@ -391,6 +495,7 @@ class ContactScreen extends React.Component {
|
|||
keyExtractor={item => item.id.toString()}
|
||||
/>
|
||||
</View>
|
||||
{/* TRANSFERT CONTACT POPUP */}
|
||||
<Overlay
|
||||
isVisible={this.state.showTransferContact}
|
||||
windowBackgroundColor="rgba(255, 255, 255, .9)"
|
||||
|
|
@ -408,12 +513,13 @@ class ContactScreen extends React.Component {
|
|||
marginBottom: 15,
|
||||
paddingLeft: 10,
|
||||
}}
|
||||
selectedValue={this.state.selectedTransferUser}
|
||||
selectedValue={this.state.selectedTransferUserIndex}
|
||||
onValueChange={(itemValue, itemIndex) => {
|
||||
this.setState({ selectedTransferUser: itemIndex });
|
||||
this.setState({ selectedTransferUserIndex: itemIndex });
|
||||
}}>
|
||||
{this.props.users
|
||||
.filter(user => user.id !== this.props.currentUser.id)
|
||||
.sort(Helpers.compareValues('email', 'asc'))
|
||||
.map((item, index) => {
|
||||
return (
|
||||
<Picker.Item
|
||||
|
|
@ -444,6 +550,7 @@ class ContactScreen extends React.Component {
|
|||
</View>
|
||||
</View>
|
||||
</Overlay>
|
||||
{/* DELETE CONTACT POPUP */}
|
||||
<Overlay
|
||||
isVisible={this.state.showSendBrochure}
|
||||
windowBackgroundColor="rgba(255, 255, 255, .9)"
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import {
|
|||
// Common Styles
|
||||
import commonStyles from '../../Resources/CommonStyles';
|
||||
// Redux
|
||||
import {connect} from 'react-redux';
|
||||
import {initContact} from '../Store/Actions/contacts';
|
||||
import {initDirectories} from '../Store/Actions/directories';
|
||||
import {initDocuments} from '../Store/Actions/documents';
|
||||
import { connect } from 'react-redux';
|
||||
import { initContact } from '../Store/Actions/contacts';
|
||||
import { initDirectories } from '../Store/Actions/directories';
|
||||
import { initDocuments } from '../Store/Actions/documents';
|
||||
// SplashScreen
|
||||
import * as SplashScreen from 'expo-splash-screen';
|
||||
// Style
|
||||
|
|
@ -37,7 +37,7 @@ function mapStateToProps(state) {
|
|||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
initBtns: () => dispatch({type: 'INIT_HOME_BTNS'}),
|
||||
initBtns: () => dispatch({ type: 'INIT_HOME_BTNS' }),
|
||||
initDocuments: (lang, directories) =>
|
||||
dispatch(initDocuments(lang, directories)),
|
||||
initContact: currentUser => dispatch(initContact(currentUser)),
|
||||
|
|
@ -55,6 +55,7 @@ class HomeScreen extends React.Component {
|
|||
return this.openSync();
|
||||
}
|
||||
this.props.initBtns();
|
||||
console.debug(this.props.currentUser);
|
||||
this.props.initContact(this.props.currentUser);
|
||||
this.props.initDirectories(this.props.locale, this.props.currentUser);
|
||||
this.props.initDocuments(this.props.locale, this.props.directories.global);
|
||||
|
|
@ -68,7 +69,7 @@ class HomeScreen extends React.Component {
|
|||
let seconds =
|
||||
Math.abs(new Date(this.state.lastSyncCall) - Date.now()) / 1000;
|
||||
if (seconds > 30) {
|
||||
this.setState({lastSyncCall: Date.now()});
|
||||
this.setState({ lastSyncCall: Date.now() });
|
||||
SyncController.needSync(this.openSync.bind(this));
|
||||
}
|
||||
}
|
||||
|
|
@ -76,14 +77,14 @@ class HomeScreen extends React.Component {
|
|||
}
|
||||
|
||||
openSync() {
|
||||
this.props.navigation.navigate('SyncScreen', {forceSync: true});
|
||||
this.props.navigation.navigate('SyncScreen', { forceSync: true });
|
||||
}
|
||||
|
||||
render() {
|
||||
i18n.locale = this.props.locale;
|
||||
return (
|
||||
<ImageBackground
|
||||
source={{uri: FileSystem.documentDirectory + 'BackgroundImage.png'}}
|
||||
source={{ uri: FileSystem.documentDirectory + 'BackgroundImage.png' }}
|
||||
style={commonStyles.background}
|
||||
resizeMode="cover">
|
||||
<View style={styles.container}>
|
||||
|
|
@ -138,7 +139,9 @@ class HomeScreen extends React.Component {
|
|||
onPress={() => this.openFolder(item.id)}
|
||||
style={styles.button}>
|
||||
<Image
|
||||
source={{uri: FileSystem.documentDirectory + 'HomeButtonImage.png'}}
|
||||
source={{
|
||||
uri: FileSystem.documentDirectory + 'HomeButtonImage.png',
|
||||
}}
|
||||
style={styles.btnImg}
|
||||
/>
|
||||
<Text style={styles.btnTxt}>{name}</Text>
|
||||
|
|
@ -150,7 +153,7 @@ class HomeScreen extends React.Component {
|
|||
openFolder(id) {
|
||||
this.props.initDocuments(this.props.locale, this.props.directories.global);
|
||||
const folder = this.props.directories.treeview.filter(tmp => tmp.id === id);
|
||||
this.props.navigation.navigate('DirectoriesScreen', {folder: folder});
|
||||
this.props.navigation.navigate('DirectoriesScreen', { folder: folder });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -139,9 +139,6 @@ class InstallScreen extends React.Component {
|
|||
switch (key) {
|
||||
case 'MainColor':
|
||||
case 'AppStoreUUID':
|
||||
case 'FormSelect1':
|
||||
case 'FormSelect2':
|
||||
case 'FormCheck':
|
||||
Setting.upsert({ key: key, value: value });
|
||||
break;
|
||||
case 'SquaredLogo':
|
||||
|
|
|
|||
|
|
@ -107,17 +107,17 @@ class LoginScreen extends React.Component {
|
|||
);
|
||||
return;
|
||||
}
|
||||
var usersSize = Object.keys(this.props.users).length;
|
||||
if (usersSize === 0) {
|
||||
/** @type {Array<import('../Models/User').User>} */
|
||||
const users = this.props.users;
|
||||
if (users.length === 0) {
|
||||
Alert.alert(i18n.t('global.warning'), i18n.t('login_s.missing_users'));
|
||||
return;
|
||||
}
|
||||
let user = this.props.users.filter(tmp => tmp.email === login);
|
||||
if (user.length === 0) {
|
||||
const user = users.find(tmp => tmp.email === login);
|
||||
if (user === undefined) {
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.incorrect_credentials'));
|
||||
return;
|
||||
}
|
||||
user = user[0];
|
||||
const verified = LoginController.verify(user, password).then(
|
||||
verified => verified,
|
||||
);
|
||||
|
|
@ -135,9 +135,11 @@ class LoginScreen extends React.Component {
|
|||
return false;
|
||||
});
|
||||
const lastUser = Setting.get('lastUser');
|
||||
// Si on est sur une installation
|
||||
if (lastUser === false || lastUser == undefined) {
|
||||
// Si la tablette est connectée à internet pour forcer la synchro
|
||||
|
||||
// * Si on est sur une installation
|
||||
if (lastUser === null) {
|
||||
console.debug('New Install');
|
||||
// * Si la tablette est connectée à internet pour forcer la synchro
|
||||
if (!isConnected) {
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
|
|
@ -147,33 +149,35 @@ class LoginScreen extends React.Component {
|
|||
}
|
||||
return this.loginAction(user);
|
||||
}
|
||||
// Si on a deja une install
|
||||
if (lastUser !== false && lastUser !== undefined) {
|
||||
// Si on a une précédente connexion
|
||||
if (lastUser.value === user.id.toString()) {
|
||||
this.loginAction(user);
|
||||
} else {
|
||||
// Si le user precedent est different du user courant
|
||||
// Si user !== last user && last user not synced
|
||||
if (!SyncController.isSynced()) {
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.tablet_not_synced_last_user'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Si la tablette est connectée à internet pour forcer la synchro
|
||||
if (!isConnected) {
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.tablet_not_connected_internet'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
SyncController.setInstalled(true);
|
||||
this.loginAction(user, true);
|
||||
}
|
||||
|
||||
// * On a deja eu une install
|
||||
|
||||
// * Si on a une précédente connexion
|
||||
if (lastUser.value === user.id.toString()) {
|
||||
console.debug('Was previously logged in');
|
||||
return this.loginAction(user);
|
||||
}
|
||||
// Si le user precedent est different du user courant
|
||||
// Si user !== last user && last user not synced
|
||||
if (!SyncController.isSynced(user.id)) {
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.tablet_not_synced_last_user'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Si la tablette est connectée à internet pour forcer la synchro
|
||||
if (!isConnected) {
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.tablet_not_connected_internet'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('New user loggin');
|
||||
SyncController.setInstalled(true);
|
||||
return this.loginAction(user, true);
|
||||
}
|
||||
|
||||
async syncUsersIfPossibleAsync() {
|
||||
|
|
@ -205,8 +209,12 @@ class LoginScreen extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('../Models/User').User} user
|
||||
*/
|
||||
loginAction(user) {
|
||||
this.setState({ login: '', password: '' });
|
||||
console.debug('loginAction');
|
||||
LoginController.login(user);
|
||||
this.props.setCurrentUser();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import {
|
|||
Contact,
|
||||
Directory,
|
||||
Document,
|
||||
Form,
|
||||
SendBrochure,
|
||||
User,
|
||||
} from '../../Database';
|
||||
|
|
@ -40,6 +41,7 @@ const mapDispatchToProps = dispatch => {
|
|||
return {
|
||||
init: () => dispatch({ type: 'INIT' }),
|
||||
initUsers: () => dispatch({ type: 'INIT_USERS' }),
|
||||
initFormularies: () => dispatch({ type: 'INIT_FORMS' }),
|
||||
initDirectories: (lang, user) => dispatch(initDirectories(lang, user)),
|
||||
initDocuments: (lang, directories) =>
|
||||
dispatch(initDocuments(lang, directories)),
|
||||
|
|
@ -106,15 +108,48 @@ class SyncScreen extends React.Component {
|
|||
|
||||
async sync() {
|
||||
let errorStatus = false;
|
||||
const isConnected = await SyncController.checkConnection()
|
||||
.then(state => {
|
||||
//console.log(state.isConnected)
|
||||
return state.isConnected;
|
||||
})
|
||||
.catch(error => {
|
||||
//console.log(error);
|
||||
return false;
|
||||
});
|
||||
|
||||
console.debug('Sync');
|
||||
|
||||
/**
|
||||
* @param {Promise<import('@react-native-community/netinfo').NetInfoState>} promise
|
||||
* @param {(error:any) => void|null} onError
|
||||
*/
|
||||
const getCall = (promise, onError = null) => {
|
||||
if (onError === null) {
|
||||
/** @param {import('axios').AxiosError} error */
|
||||
onError = error => {
|
||||
let message = 'Erreur de la communication serveur';
|
||||
if (error?.response?.status === 422) {
|
||||
message =
|
||||
this.parseValidationErrors(error.response?.data?.errors ?? {}) ||
|
||||
message;
|
||||
console.warn(error.response?.data?.errors ?? {});
|
||||
} else if (error?.response?.status === 419) {
|
||||
// * CSRF TOKEN MISMATCH (On ne pourrais plus faire d'appels AJAX sans recharger la page)
|
||||
message = 'Votre session a expiré, la page va être rechargée';
|
||||
} else if (error?.response?.status === 403) {
|
||||
// * Access denied
|
||||
message = "Vous n'êtes pas autorisé a effectuer cette action";
|
||||
} else {
|
||||
console.error(error);
|
||||
}
|
||||
console.warn(message);
|
||||
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred'),
|
||||
);
|
||||
errorStatus = true;
|
||||
};
|
||||
}
|
||||
return promise.catch(onError);
|
||||
};
|
||||
|
||||
const isConnected = await SyncController.checkConnection().catch(
|
||||
error => false,
|
||||
);
|
||||
if (!isConnected) {
|
||||
Alert.alert(
|
||||
i18n.t('global.warning'),
|
||||
|
|
@ -123,121 +158,150 @@ class SyncScreen extends React.Component {
|
|||
return;
|
||||
}
|
||||
this.setState({ processing: true });
|
||||
// getVersion
|
||||
const resVersion = await SyncController.getVersion()
|
||||
.then(res => {
|
||||
|
||||
// * --- getVersion
|
||||
const resVersion = await getCall(
|
||||
SyncController.getVersion().then(res => {
|
||||
return res.data;
|
||||
})
|
||||
.catch(error => {
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.error_has_occurred'));
|
||||
errorStatus = true;
|
||||
});
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
this.props.updateVersion(resVersion.version);
|
||||
this.props.updateShowIsActive(resVersion.ShowIsActive);
|
||||
this.setState({ newApp: resVersion.newApp });
|
||||
// getUsers
|
||||
this.setState({ txtStep: i18n.t('sync_s.updating_users') + '...' });
|
||||
const resUsers = await SyncController.getUsers()
|
||||
.then(res => {
|
||||
|
||||
// * --- getUsers
|
||||
this.setState({
|
||||
progress: 0.1,
|
||||
txtStep: i18n.t('sync_s.updating_users') + '...',
|
||||
});
|
||||
const resUsers = await getCall(
|
||||
SyncController.getUsers().then(res => {
|
||||
User.clear();
|
||||
return res.data;
|
||||
})
|
||||
.catch(error => {
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.error_has_occurred'));
|
||||
errorStatus = true;
|
||||
});
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resUsers.forEach(user => {
|
||||
User.add(user);
|
||||
});
|
||||
// getContacts
|
||||
this.setState({
|
||||
progress: 0.1,
|
||||
txtStep: i18n.t('sync_s.updating_contacts') + '...',
|
||||
});
|
||||
const resContacts = await SyncController.getContacts(
|
||||
this.props.currentUser.id,
|
||||
)
|
||||
.then(res => {
|
||||
Contact.clear();
|
||||
return res.data;
|
||||
})
|
||||
.catch(error => {
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.error_has_occurred'));
|
||||
errorStatus = true;
|
||||
});
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resContacts.forEach(contact => {
|
||||
Contact.add(contact);
|
||||
});
|
||||
//sendBrochures
|
||||
|
||||
// * --- Contacts Sync
|
||||
/*
|
||||
* This is done only for actual app user
|
||||
- 1 Upsert all contacts
|
||||
- 2 Delete contacts where to_delete is true
|
||||
- 3 Get all contacts
|
||||
*/
|
||||
this.setState({
|
||||
progress: 0.2,
|
||||
txtStep: i18n.t('sync_s.updating_contacts') + '...',
|
||||
});
|
||||
|
||||
// * --- Contacts Sync -- STEP 1
|
||||
await getCall(SyncController.upsertContacts(this.props.currentUser.id));
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// * --- Contacts Sync -- STEP 2
|
||||
this.setState({
|
||||
progress: 0.23,
|
||||
});
|
||||
await getCall(SyncController.deleteContacts(this.props.currentUser.id));
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// * --- Contacts Sync -- STEP 3
|
||||
this.setState({
|
||||
progress: 0.26,
|
||||
});
|
||||
const resContacts = await getCall(
|
||||
SyncController.getContacts(this.props.currentUser.id).then(res => {
|
||||
// * Clear Contacts, in order to fetch them all after.
|
||||
Contact.clear(this.props.currentUser.id);
|
||||
return res.data;
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
/** @type {(contact: import('./../Models/Contact').ContactData ) => void} */
|
||||
const contactMapper = contact => {
|
||||
// * Stringify complex Fields
|
||||
contact.data = JSON.stringify(contact.data);
|
||||
contact.visits = JSON.stringify(contact.visits);
|
||||
contact.timestamp = new Date(contact.timestamp);
|
||||
Contact.set(contact);
|
||||
};
|
||||
resContacts.forEach(contactMapper);
|
||||
|
||||
// * --- sendBrochures
|
||||
this.setState({
|
||||
progress: 0.3,
|
||||
txtStep: i18n.t('sync_s.sending_flyers') + '...',
|
||||
});
|
||||
let brochures = SendBrochure.getAll();
|
||||
const brochures = SendBrochure.getAll();
|
||||
for (const brochure of brochures) {
|
||||
await SyncController.sendBrochure(brochure)
|
||||
.then(res => {
|
||||
await getCall(
|
||||
SyncController.sendBrochure(brochure).then(res => {
|
||||
SendBrochure.delete(brochure.id);
|
||||
})
|
||||
.catch(error => {
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(
|
||||
i18n.t('error.error'),
|
||||
i18n.t('error.error_has_occurred') + ' : Brochures',
|
||||
);
|
||||
errorStatus = true;
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
//getDirectories
|
||||
|
||||
// * --- getDirectories
|
||||
this.setState({
|
||||
progress: 0.3,
|
||||
progress: 0.4,
|
||||
txtStep: i18n.t('sync_s.updating_folders') + '...',
|
||||
});
|
||||
const resDirectories = await SyncController.getDirectories()
|
||||
.then(res => {
|
||||
const resDirectories = await getCall(
|
||||
SyncController.getDirectories().then(res => {
|
||||
Directory.clear();
|
||||
return res.data;
|
||||
})
|
||||
.catch(error => {
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.error_has_occurred'));
|
||||
errorStatus = true;
|
||||
});
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resDirectories.forEach(dir => {
|
||||
Directory.add(dir);
|
||||
});
|
||||
// getDocuments
|
||||
|
||||
// * --- getFormularies
|
||||
this.setState({
|
||||
progress: 0.4,
|
||||
progress: 0.5,
|
||||
txtStep: i18n.t('sync_s.updating_forms') + '...',
|
||||
});
|
||||
const resFormularies = await getCall(
|
||||
SyncController.getFormularies().then(res => {
|
||||
Form.clear();
|
||||
return res.data;
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
resFormularies.forEach(form => Form.add(form));
|
||||
|
||||
// * --- getDocuments
|
||||
this.setState({
|
||||
progress: 0.6,
|
||||
txtStep: i18n.t('sync_s.updating_docs') + '...',
|
||||
});
|
||||
const resDocuments = await SyncController.getDocuments()
|
||||
.then(res => {
|
||||
const resDocuments = await getCall(
|
||||
SyncController.getDocuments().then(res => {
|
||||
return res.data;
|
||||
})
|
||||
.catch(error => {
|
||||
Sentry.captureException(error);
|
||||
Alert.alert(i18n.t('error.error'), i18n.t('error.error_has_occurred'));
|
||||
errorStatus = true;
|
||||
});
|
||||
}),
|
||||
);
|
||||
if (errorStatus) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -246,11 +310,8 @@ class SyncScreen extends React.Component {
|
|||
Document.update(document);
|
||||
});
|
||||
this.downloadDocuments(Document.getAll(), toDelete);
|
||||
// End
|
||||
this.setState({
|
||||
txtStep: i18n.t('sync_s.update_completed') + '.',
|
||||
processing: false,
|
||||
});
|
||||
|
||||
// * --- End
|
||||
}
|
||||
|
||||
fileProgress() {
|
||||
|
|
@ -263,11 +324,11 @@ class SyncScreen extends React.Component {
|
|||
const version = this.props.syncVersion;
|
||||
this.getToDL(docs, 0).then(toDownload => {
|
||||
if (toDownload.length > 0) {
|
||||
this.setState({ progress: 0.5 });
|
||||
const docProgress = 0.5 / toDownload.length;
|
||||
this.setState({ progress: 0.6 });
|
||||
const docProgress = 0.4 / toDownload.length;
|
||||
this.download(toDownload, docProgress, 0).then(status => {
|
||||
if (status === true) {
|
||||
this.deleteFile(toDelete, 0).then(status => {
|
||||
this.deleteFile(toDelete, 0).then(delStatus => {
|
||||
this.finishSync(version);
|
||||
});
|
||||
} else {
|
||||
|
|
@ -418,6 +479,27 @@ class SyncScreen extends React.Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse error messages for a specific input.
|
||||
*
|
||||
* @param {Record<string, Array<string>>} allErrors
|
||||
* @return {string | null}
|
||||
*/
|
||||
parseValidationErrors(allErrors = {}) {
|
||||
const errorList = Object.values(allErrors);
|
||||
if (!errorList.length) {
|
||||
return null;
|
||||
}
|
||||
return errorList
|
||||
.reduce((oldInputErrors, inputErrors) =>
|
||||
oldInputErrors ? oldInputErrors.concat(inputErrors) : inputErrors,
|
||||
)
|
||||
.reduce(
|
||||
(oldInputString, inputString) =>
|
||||
(oldInputString ? `${oldInputString}, ` : '') + inputString,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SyncScreen);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Realm from 'realm';
|
|||
import ContactModel, { ContactsSchema } from './App/Models/Contact';
|
||||
import DirectoryModel, { DirectoriesSchema } from './App/Models/Directory';
|
||||
import DocumentModel, { DocumentsSchema } from './App/Models/Document';
|
||||
import FormModel, { FormsSchema } from './App/Models/Form';
|
||||
import SendBrochureModel, {
|
||||
SendBrochuresSchema,
|
||||
} from './App/Models/SendBrochure';
|
||||
|
|
@ -17,15 +18,17 @@ const Database = {
|
|||
SendBrochuresSchema,
|
||||
SettingsSchema,
|
||||
UsersSchema,
|
||||
FormsSchema,
|
||||
],
|
||||
//encryptionKey: new Int8Array(64)
|
||||
};
|
||||
|
||||
let realm = new Realm(Database);
|
||||
|
||||
export let Contact = new ContactModel(realm);
|
||||
export let Directory = new DirectoryModel(realm);
|
||||
export let Document = new DocumentModel(realm);
|
||||
export let SendBrochure = new SendBrochureModel(realm);
|
||||
export let Setting = new SettingModel(realm);
|
||||
export let User = new UserModel(realm);
|
||||
export const Contact = new ContactModel(realm);
|
||||
export const Directory = new DirectoryModel(realm);
|
||||
export const Document = new DocumentModel(realm);
|
||||
export const SendBrochure = new SendBrochureModel(realm);
|
||||
export const Setting = new SettingModel(realm);
|
||||
export const User = new UserModel(realm);
|
||||
export const Form = new FormModel(realm);
|
||||
|
|
|
|||
|
|
@ -1,118 +1,120 @@
|
|||
{
|
||||
"install": {
|
||||
"installation": "Installation",
|
||||
"install": "Installieren Sie",
|
||||
"enter_url": "Bitte geben Sie den Link zu Ihrem Backoffice ein",
|
||||
"url_invalid": "Der eingegebene Link ist ungültig.",
|
||||
"resource_dl_error": "Beim Herunterladen der folgenden Lerneinheit ist ein Fehler aufgetreten: ",
|
||||
"install_complete": "Installation abgeschlossen!",
|
||||
"get_app_setting": "Wiederherstellen der Konfiguration der Anwendung",
|
||||
"get_content_setting": "Abrufen der Konfiguration des Inhalts der Anwendung"
|
||||
},
|
||||
"global": {
|
||||
"change_lang": "Sprache wechseln",
|
||||
"sync": "Synchronisation",
|
||||
"logout": "Abmeldung",
|
||||
"close": "Schließen Sie",
|
||||
"install": "Installieren",
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"home": "Startseite",
|
||||
"search": "Suche",
|
||||
"login": "Verbindung",
|
||||
"email": "Email",
|
||||
"message_sent": "Email geschickt",
|
||||
"message_will_be_sent_after_sync": "Die Nachricht wird nach Synchronisation geschickt",
|
||||
"warning": "Achtung",
|
||||
"synchronization": "Synchronisation ",
|
||||
"videos": "Videos",
|
||||
"contacts": "Kontakt",
|
||||
"confirmation": "Bestätigung",
|
||||
"name": "Name",
|
||||
"firstname": "Vorname",
|
||||
"address": "Adresse",
|
||||
"phone": "Telefonnummer",
|
||||
"company": "Firma",
|
||||
"add": "Addieren",
|
||||
"cancel": "Abbrechen",
|
||||
"subject": "Betreff",
|
||||
"message": "Nachricht",
|
||||
"send": "Senden",
|
||||
"required": "erforderlich",
|
||||
"save": "Speichern",
|
||||
"retry": "Noch einmal versuchen",
|
||||
"next": "Nächstes"
|
||||
},
|
||||
"app": {
|
||||
"file_sharing": " Dateifreigabe",
|
||||
"folders": "Ordner",
|
||||
"video": "Video",
|
||||
"contact_details": "Kontaktdaten",
|
||||
"results_search": "Suchergebnisse",
|
||||
"my_space": "Mein Raum"
|
||||
},
|
||||
"login_s": {
|
||||
"username": "Benutzername",
|
||||
"password": "Passwort"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "Keine Ergebnisse"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Download",
|
||||
"update_completed": "Update abgeschlossen",
|
||||
"updating_docs": "Dokumentaktualisierung",
|
||||
"updating_folders": "Dateien aktualisieren",
|
||||
"sending_flyers": "Brochure senden",
|
||||
"updating_contacts": "Kontakt aktualisieren",
|
||||
"user_install_completed": "Benutzerinstallation abgeschlossen",
|
||||
"updating_users": "Benutzer-Update",
|
||||
"user_install": "Benutzerinstallation",
|
||||
"start_sync": "Synchronisation starten",
|
||||
"new_app_version": "Eine neue Version der Anwendung ist verfügbar!",
|
||||
"open_store": "Öffnen Sie den App Store"
|
||||
},
|
||||
"contact_s": {
|
||||
"contact_transferred": "Kontakt weiterleiten",
|
||||
"contact_will_be_sent_after_sync": "Der Kontakt wird nach der Synchronisation gesendet",
|
||||
"confirm_contact_delete": "Möchten Sie diesen Kontakt wirklich löschen?",
|
||||
"contact_deleted": "Kontakt gelöscht",
|
||||
"contact_added": "Kontakt hinzugefügt",
|
||||
"send_flyer": "Senden Sie eine Broschüre",
|
||||
"select_contact": "Wählen Sie den Kontakt",
|
||||
"transfer": "weiterleiten",
|
||||
"contact_list": "Kontaktliste",
|
||||
"documents_list": "Liste der Dokumente"
|
||||
},
|
||||
"contact_details_s": {
|
||||
"visits": "Besuche",
|
||||
"notes": "Notes",
|
||||
"contact_saved": "Kontakt gespeichert",
|
||||
"confirm_visit_delete": "Sind Sie sicher, dass Sie diesen Besuch löschen möchten?",
|
||||
"qrcode_not_vcard_format": "Dieser QRCode ist nicht im vCard-Format",
|
||||
"customer": "Kunde",
|
||||
"prospect": "potenzieller Kunde",
|
||||
"other": "Andere",
|
||||
"description": "Beschreibung",
|
||||
"no_visits": "Kein Besuch",
|
||||
"visit_name": "Besuchsname"
|
||||
},
|
||||
"error": {
|
||||
"error": "Fehler ",
|
||||
"tablet_not_connected_internet": "Das Tablet ist nicht mit dem Internet verbunden.",
|
||||
"tablet_not_synced_last_user": "Das Tablet wurde vom vorherigen Benutzer nicht synchronisiert",
|
||||
"incorrect_credentials": "Falsche Anmeldeinformationen",
|
||||
"must_fill_login_fields": "Sie müssen die Verbindungsfelder ausfüllen",
|
||||
"invalid_email_address": "Ungültige E-Mail-Adresse",
|
||||
"error_has_occurred": "Ein Fehler ist aufgetreten",
|
||||
"must_be_connected_internet_sync": "Sie müssen mit dem Internet verbunden sein, um die Synchronisierung zu starten",
|
||||
"incomplete_form": "Unvollständiges Formular",
|
||||
"fill_all_fields_and_1_doc_min": "Bitte füllen Sie alle Felder, mindestens 1 Dokument und eine gültige E-Mail-Adresse aus.",
|
||||
"fill_other_field": "Füllen Sie das Beschreibungsfeld für: Andere",
|
||||
"specify_type_contact": "Bitte geben Sie die Art des Kontakts an",
|
||||
"invalid_name": "ungültiger Name",
|
||||
"invalid_firstname": "ungültiger Vorname",
|
||||
"camera_permission_denied": "Kameraerlaubnis verweigert",
|
||||
"pending_camera_permission": "Warten auf Kameraerlaubnis"
|
||||
}
|
||||
}
|
||||
{
|
||||
"install": {
|
||||
"installation": "Installation",
|
||||
"install": "Installieren Sie",
|
||||
"enter_url": "Bitte geben Sie den Link zu Ihrem Backoffice ein",
|
||||
"url_invalid": "Der eingegebene Link ist ungültig.",
|
||||
"resource_dl_error": "Beim Herunterladen der folgenden Lerneinheit ist ein Fehler aufgetreten: ",
|
||||
"install_complete": "Installation abgeschlossen!",
|
||||
"get_app_setting": "Wiederherstellen der Konfiguration der Anwendung",
|
||||
"get_content_setting": "Abrufen der Konfiguration des Inhalts der Anwendung"
|
||||
},
|
||||
"global": {
|
||||
"change_lang": "Sprache wechseln",
|
||||
"sync": "Synchronisation",
|
||||
"logout": "Abmeldung",
|
||||
"close": "Schließen Sie",
|
||||
"install": "Installieren",
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"home": "Startseite",
|
||||
"search": "Suche",
|
||||
"login": "Verbindung",
|
||||
"email": "Email",
|
||||
"message_sent": "Email geschickt",
|
||||
"message_will_be_sent_after_sync": "Die Nachricht wird nach Synchronisation geschickt",
|
||||
"warning": "Achtung",
|
||||
"synchronization": "Synchronisation ",
|
||||
"videos": "Videos",
|
||||
"contacts": "Kontakt",
|
||||
"confirmation": "Bestätigung",
|
||||
"lastname": "Name",
|
||||
"firstname": "Vorname",
|
||||
"address": "Adresse",
|
||||
"phone": "Telefonnummer",
|
||||
"company": "Firma",
|
||||
"add": "Addieren",
|
||||
"cancel": "Abbrechen",
|
||||
"subject": "Betreff",
|
||||
"message": "Nachricht",
|
||||
"send": "Senden",
|
||||
"required": "erforderlich",
|
||||
"save": "Speichern",
|
||||
"retry": "Noch einmal versuchen",
|
||||
"next": "Nächstes"
|
||||
},
|
||||
"app": {
|
||||
"file_sharing": " Dateifreigabe",
|
||||
"folders": "Ordner",
|
||||
"video": "Video",
|
||||
"contact_details": "Kontaktdaten",
|
||||
"results_search": "Suchergebnisse",
|
||||
"my_space": "Mein Raum"
|
||||
},
|
||||
"login_s": {
|
||||
"username": "Benutzername",
|
||||
"password": "Passwort"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "Keine Ergebnisse"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Download",
|
||||
"update_completed": "Update abgeschlossen",
|
||||
"updating_docs": "Dokumentaktualisierung",
|
||||
"updating_forms": "Formulare aktualisieren",
|
||||
"updating_folders": "Dateien aktualisieren",
|
||||
"sending_flyers": "Brochure senden",
|
||||
"updating_contacts": "Kontakt aktualisieren",
|
||||
"user_install_completed": "Benutzerinstallation abgeschlossen",
|
||||
"updating_users": "Benutzer-Update",
|
||||
"user_install": "Benutzerinstallation",
|
||||
"start_sync": "Synchronisation starten",
|
||||
"new_app_version": "Eine neue Version der Anwendung ist verfügbar!",
|
||||
"open_store": "Öffnen Sie den App Store"
|
||||
},
|
||||
"contact_s": {
|
||||
"contact_transferred": "Kontakt weiterleiten",
|
||||
"contact_will_be_sent_after_sync": "Der Kontakt wird nach der Synchronisation gesendet",
|
||||
"confirm_contact_delete": "Möchten Sie diesen Kontakt wirklich löschen?",
|
||||
"contact_deleted": "Kontakt gelöscht",
|
||||
"contact_added": "Kontakt hinzugefügt",
|
||||
"send_flyer": "Senden Sie eine Broschüre",
|
||||
"select_contact": "Wählen Sie einen Benutzer aus",
|
||||
"transfer": "weiterleiten",
|
||||
"contact_list": "Kontaktliste",
|
||||
"documents_list": "Liste der Dokumente",
|
||||
"input_required": "Das Feld %{placeholder} ist erforderlich",
|
||||
"input_email": "Das Feld %{placeholder} muss eine gültige E-Mail-Adresse sein"
|
||||
},
|
||||
"contact_details_s": {
|
||||
"visits": "Besuche",
|
||||
"notes": "Notes",
|
||||
"contact_saved": "Kontakt gespeichert",
|
||||
"confirm_visit_delete": "Sind Sie sicher, dass Sie diesen Besuch löschen möchten?",
|
||||
"qrcode_not_vcard_format": "Dieser QRCode ist nicht im vCard-Format",
|
||||
"description": "Beschreibung",
|
||||
"no_visits": "Kein Besuch",
|
||||
"visit_name": "Besuchsname",
|
||||
"input_select_please_choose": "Wähle einen Wert",
|
||||
"input_select_multiple_search": "Suchen"
|
||||
},
|
||||
"error": {
|
||||
"error": "Fehler ",
|
||||
"tablet_not_connected_internet": "Das Tablet ist nicht mit dem Internet verbunden.",
|
||||
"tablet_not_synced_last_user": "Das Tablet wurde vom vorherigen Benutzer nicht synchronisiert",
|
||||
"incorrect_credentials": "Falsche Anmeldeinformationen",
|
||||
"must_fill_login_fields": "Sie müssen die Verbindungsfelder ausfüllen",
|
||||
"invalid_email_address": "Ungültige E-Mail-Adresse",
|
||||
"invalid_firstname": "Vorname ist ungültig",
|
||||
"invalid_lastname": "Nachname ist ungültig",
|
||||
"invalid_phone": "Die Telefonnummer ist ungültig",
|
||||
"field_required": "Das Feld %{placeholder} ist erforderlich",
|
||||
"error_has_occurred": "Ein Fehler ist aufgetreten",
|
||||
"must_be_connected_internet_sync": "Sie müssen mit dem Internet verbunden sein, um die Synchronisierung zu starten",
|
||||
"incomplete_form": "Unvollständiges Formular",
|
||||
"fill_all_fields_and_1_doc_min": "Bitte füllen Sie alle Felder, mindestens 1 Dokument und eine gültige E-Mail-Adresse aus.",
|
||||
"camera_permission_denied": "Kameraerlaubnis verweigert",
|
||||
"pending_camera_permission": "Warten auf Kameraerlaubnis"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,118 +1,120 @@
|
|||
{
|
||||
"install": {
|
||||
"installation": "Installation",
|
||||
"install": "Install",
|
||||
"enter_url": "Please enter your back office link",
|
||||
"url_invalid": "The link you entered is invalid.",
|
||||
"resource_dl_error": "An error occurred while downloading the following resource: ",
|
||||
"install_complete": "Installation is complete!",
|
||||
"get_app_setting": "Retrieving the application's configuration",
|
||||
"get_content_setting": "Retrieving the configuration of the application content"
|
||||
},
|
||||
"global": {
|
||||
"change_lang": "Change language",
|
||||
"sync": "Synchronization",
|
||||
"logout": "Logout",
|
||||
"close": "Close",
|
||||
"install": "Install",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"home": "Home",
|
||||
"search": "Search",
|
||||
"login": "Login",
|
||||
"email": "Email",
|
||||
"message_sent": "Message Sent",
|
||||
"message_will_be_sent_after_sync": "Message will be send after synchronization",
|
||||
"warning": "Warning",
|
||||
"synchronization": "Synchronization",
|
||||
"videos": "Videos",
|
||||
"contacts": "Contacts",
|
||||
"confirmation": "Confirmation",
|
||||
"name": "Lastname",
|
||||
"firstname": "Firstname",
|
||||
"address": "Adress",
|
||||
"phone": "Phone number",
|
||||
"company": "Company",
|
||||
"add": "Add",
|
||||
"cancel": "Cancel",
|
||||
"subject": "Object",
|
||||
"message": "Message",
|
||||
"send": "Send",
|
||||
"required": "required",
|
||||
"save": "Save",
|
||||
"retry": "Retry",
|
||||
"next": "Next"
|
||||
},
|
||||
"app": {
|
||||
"file_sharing": "File Sharing",
|
||||
"folders": "Folders",
|
||||
"video": "Video",
|
||||
"contact_details": "Contact information",
|
||||
"results_search": "Search results",
|
||||
"my_space": "Personal Dashboard"
|
||||
},
|
||||
"login_s": {
|
||||
"username": "Username",
|
||||
"password": "Password"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "No Result"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Download",
|
||||
"update_completed": "Update Done",
|
||||
"updating_docs": "Updating documents",
|
||||
"updating_folders": "Updating folders",
|
||||
"sending_flyers": "Sending documents",
|
||||
"updating_contacts": "Updating contacts",
|
||||
"user_install_completed": "User install completed",
|
||||
"updating_users": "Updating Users",
|
||||
"user_install": "Installing Users",
|
||||
"start_sync": "START SYNCHRONIZATION",
|
||||
"new_app_version": "A new version of the application is available!",
|
||||
"open_store": "Open the store"
|
||||
},
|
||||
"contact_s": {
|
||||
"contact_transferred": "Contact Transferred",
|
||||
"contact_will_be_sent_after_sync": "The contact will be sent after synchronization",
|
||||
"confirm_contact_delete": "Are you sure to delete this contact ?",
|
||||
"contact_deleted": "Contact deleted",
|
||||
"contact_added": "Contact added",
|
||||
"send_flyer": "Send a document",
|
||||
"select_contact": "Select the contact",
|
||||
"transfer": "Transfer",
|
||||
"contact_list": "Contact List",
|
||||
"documents_list": "Documents List"
|
||||
},
|
||||
"contact_details_s": {
|
||||
"visits": "Visits",
|
||||
"notes": "Notes",
|
||||
"contact_saved": "Contact saved",
|
||||
"confirm_visit_delete": "are you sure to delete this visit ?",
|
||||
"qrcode_not_vcard_format": "This QRCode is not a VCard",
|
||||
"customer": "Customer",
|
||||
"prospect": "Prospect",
|
||||
"other": "Other",
|
||||
"description": "Description",
|
||||
"no_visits": "No visits available",
|
||||
"visit_name": "visits name"
|
||||
},
|
||||
"error": {
|
||||
"error": "Error",
|
||||
"tablet_not_connected_internet": "The tablet is not connected to Internet",
|
||||
"tablet_not_synced_last_user": "The previous user didn't synchronised the tablet",
|
||||
"incorrect_credentials": "Incorrect Credentials",
|
||||
"must_fill_login_fields": "You must fill the login fields.",
|
||||
"invalid_email_address": "Invalid E-mail adress",
|
||||
"error_has_occurred": "An error occured",
|
||||
"must_be_connected_internet_sync": "You must be connected to internet to be able to synchronize",
|
||||
"incomplete_form": "Incomplete Form",
|
||||
"fill_all_fields_and_1_doc_min": "Please fill up all the fields, at least one document and a valid e-mail adress",
|
||||
"fill_other_field": "You must fill the description field for : Other",
|
||||
"specify_type_contact": "You must specify the contact type",
|
||||
"invalid_name": "Invalid lastname",
|
||||
"invalid_firstname": "Invalid firstname",
|
||||
"camera_permission_denied": "Camera Permission Denied",
|
||||
"pending_camera_permission": "Waiting for the camera permission"
|
||||
}
|
||||
}
|
||||
{
|
||||
"install": {
|
||||
"installation": "Installation",
|
||||
"install": "Install",
|
||||
"enter_url": "Please enter your back office link",
|
||||
"url_invalid": "The link you entered is invalid.",
|
||||
"resource_dl_error": "An error occurred while downloading the following resource: ",
|
||||
"install_complete": "Installation is complete!",
|
||||
"get_app_setting": "Retrieving the application's configuration",
|
||||
"get_content_setting": "Retrieving the configuration of the application content"
|
||||
},
|
||||
"global": {
|
||||
"change_lang": "Change language",
|
||||
"sync": "Synchronization",
|
||||
"logout": "Logout",
|
||||
"close": "Close",
|
||||
"install": "Install",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"home": "Home",
|
||||
"search": "Search",
|
||||
"login": "Login",
|
||||
"email": "Email",
|
||||
"message_sent": "Message Sent",
|
||||
"message_will_be_sent_after_sync": "Message will be send after synchronization",
|
||||
"warning": "Warning",
|
||||
"synchronization": "Synchronization",
|
||||
"videos": "Videos",
|
||||
"contacts": "Contacts",
|
||||
"confirmation": "Confirmation",
|
||||
"lastname": "Lastname",
|
||||
"firstname": "Firstname",
|
||||
"address": "Adress",
|
||||
"phone": "Phone number",
|
||||
"company": "Company",
|
||||
"add": "Add",
|
||||
"cancel": "Cancel",
|
||||
"subject": "Object",
|
||||
"message": "Message",
|
||||
"send": "Send",
|
||||
"required": "required",
|
||||
"save": "Save",
|
||||
"retry": "Retry",
|
||||
"next": "Next"
|
||||
},
|
||||
"app": {
|
||||
"file_sharing": "File Sharing",
|
||||
"folders": "Folders",
|
||||
"video": "Video",
|
||||
"contact_details": "Contact information",
|
||||
"results_search": "Search results",
|
||||
"my_space": "Personal Dashboard"
|
||||
},
|
||||
"login_s": {
|
||||
"username": "Username",
|
||||
"password": "Password"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "No Result"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Download",
|
||||
"update_completed": "Update Done",
|
||||
"updating_docs": "Updating documents",
|
||||
"updating_forms": "Updating forms",
|
||||
"updating_folders": "Updating folders",
|
||||
"sending_flyers": "Sending documents",
|
||||
"updating_contacts": "Updating contacts",
|
||||
"user_install_completed": "User install completed",
|
||||
"updating_users": "Updating Users",
|
||||
"user_install": "Installing Users",
|
||||
"start_sync": "START SYNCHRONIZATION",
|
||||
"new_app_version": "A new version of the application is available!",
|
||||
"open_store": "Open the store"
|
||||
},
|
||||
"contact_s": {
|
||||
"contact_transferred": "Contact Transferred",
|
||||
"contact_will_be_sent_after_sync": "The contact will be sent after synchronization",
|
||||
"confirm_contact_delete": "Are you sure to delete this contact ?",
|
||||
"contact_deleted": "Contact deleted",
|
||||
"contact_added": "Contact added",
|
||||
"send_flyer": "Send a document",
|
||||
"select_contact": "Select a user",
|
||||
"transfer": "Transfer",
|
||||
"contact_list": "Contact List",
|
||||
"documents_list": "Documents List"
|
||||
},
|
||||
"contact_details_s": {
|
||||
"visits": "Visits",
|
||||
"notes": "Notes",
|
||||
"contact_saved": "Contact saved",
|
||||
"confirm_visit_delete": "are you sure to delete this visit ?",
|
||||
"qrcode_not_vcard_format": "This QRCode is not a VCard",
|
||||
"description": "Description",
|
||||
"no_visits": "No visits available",
|
||||
"visit_name": "visits name",
|
||||
"input_select_please_choose": "Select a value",
|
||||
"input_select_multiple_search": "Search",
|
||||
"input_required": "The %{placeholder} field is required",
|
||||
"input_email": "The %{placeholder} field must be a valid email"
|
||||
},
|
||||
"error": {
|
||||
"error": "Error",
|
||||
"tablet_not_connected_internet": "The tablet is not connected to Internet",
|
||||
"tablet_not_synced_last_user": "The previous user didn't synchronised the tablet",
|
||||
"incorrect_credentials": "Incorrect Credentials",
|
||||
"must_fill_login_fields": "You must fill the login fields.",
|
||||
"invalid_email_address": "Invalid E-mail adress",
|
||||
"invalid_firstname": "Firstname is not valid",
|
||||
"invalid_lastname": "Lastname is not valid",
|
||||
"invalid_phone": "Phone is not valid",
|
||||
"field_required": "The %{placeholder} field is required",
|
||||
"error_has_occurred": "An error occured",
|
||||
"must_be_connected_internet_sync": "You must be connected to internet to be able to synchronize",
|
||||
"incomplete_form": "Incomplete Form",
|
||||
"fill_all_fields_and_1_doc_min": "Please fill up all the fields, at least one document and a valid e-mail adress",
|
||||
"camera_permission_denied": "Camera Permission Denied",
|
||||
"pending_camera_permission": "Waiting for the camera permission"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,122 +1,124 @@
|
|||
{
|
||||
"install": {
|
||||
"installation": "Installation",
|
||||
"install": "Installer",
|
||||
"enter_url": "Veuillez entrer le lien de votre back-office",
|
||||
"url_invalid": "Le lien saisi est invalide.",
|
||||
"resource_dl_error": "Une erreur est survenue lors du téléchargement de la ressource suivante : ",
|
||||
"install_complete": "Installation terminée !",
|
||||
"get_app_setting": "Récupération de la configuration de l'application",
|
||||
"get_content_setting": "Récupération de la configuration du contenu de l'application"
|
||||
},
|
||||
"global": {
|
||||
"change_lang": "Changer de langue",
|
||||
"sync": "Synchronisation",
|
||||
"logout": "Se déconnecter",
|
||||
"close": "Fermer",
|
||||
"yes": "Oui",
|
||||
"no": "Non",
|
||||
"home": "Accueil",
|
||||
"search": "Recherche",
|
||||
"login": "Connexion",
|
||||
"email": "Email",
|
||||
"message_sent": "Message envoyé",
|
||||
"message_will_be_sent_after_sync": "Le message sera envoyé après synchronisation",
|
||||
"warning": "Attention",
|
||||
"synchronization": "Synchronisation",
|
||||
"videos": "Vidéos",
|
||||
"contacts": "Contacts",
|
||||
"confirmation": "Confirmation",
|
||||
"name": "Nom",
|
||||
"firstname": "Prénom",
|
||||
"address": "Adresse",
|
||||
"phone": "Téléphone",
|
||||
"company": "Société",
|
||||
"add": "Ajouter",
|
||||
"cancel": "Annuler",
|
||||
"subject": "Objet",
|
||||
"message": "Message",
|
||||
"send": "Envoyer",
|
||||
"required": "requis",
|
||||
"save": "Enregistrer",
|
||||
"retry": "Réessayer",
|
||||
"next": "Suivant"
|
||||
},
|
||||
"app": {
|
||||
"file_sharing": "Partage de fichier",
|
||||
"folders": "Dossiers",
|
||||
"video": "Vidéo",
|
||||
"contact_details": "Détails du contact",
|
||||
"results_search": "Résultat(s) de votre recherche",
|
||||
"my_space": "Mon espace"
|
||||
},
|
||||
"login_s": {
|
||||
"username": "Identifiant",
|
||||
"password": "Mot de passe",
|
||||
"missing_users": "Utilisateurs introuvables"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "Aucun résultat"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Téléchargement",
|
||||
"update_completed": "Mise à jour effectuée",
|
||||
"updating_docs": "Mise à jour des documents",
|
||||
"updating_folders": "Mise à jour des dossiers",
|
||||
"sending_flyers": "Envoi des brochures",
|
||||
"updating_contacts": "Mise à jour des contacts",
|
||||
"user_install_completed": "Installation des utilisateurs effectuée",
|
||||
"updating_users": "Mise à jour des utilisateurs",
|
||||
"user_install": "Installation des utilisateurs",
|
||||
"start_sync": "LANCER LA SYNCHRONISATION",
|
||||
"new_app_version": "Une nouvelle version de l'application est disponible !",
|
||||
"open_store": "Ouvrir le store"
|
||||
},
|
||||
"contact_s": {
|
||||
"contact_transferred": "Contact transféré",
|
||||
"contact_will_be_sent_after_sync": "Le contact sera envoyé après synchronisation",
|
||||
"confirm_contact_delete": "Êtes-vous sûr de vouloir supprimer ce contact ?",
|
||||
"contact_deleted": "Contact supprimé",
|
||||
"contact_added": "Contact ajouté",
|
||||
"send_flyer": "Envoyer une brochure",
|
||||
"select_contact": "Sélectionnez le contact",
|
||||
"transfer": "Transférer",
|
||||
"contact_list": "Liste des contacts",
|
||||
"documents_list": "Liste des documents"
|
||||
},
|
||||
"contact_details_s": {
|
||||
"visits": "Visites",
|
||||
"notes": "Notes",
|
||||
"contact_saved": "Contact enregistré",
|
||||
"confirm_visit_delete": "Êtes-vous sûr de vouloir supprimer cette visite ?",
|
||||
"qrcode_not_vcard_format": "Ce QRCode n'est pas au format vCard",
|
||||
"customer": "Client",
|
||||
"prospect": "Prospect",
|
||||
"other": "Autre",
|
||||
"description": "Description",
|
||||
"no_visits": "Aucune visites",
|
||||
"visit_name": "Nom de la visite"
|
||||
},
|
||||
"error": {
|
||||
"error": "Erreur",
|
||||
"tablet_not_connected_internet": "La tablette n'est pas connectée à internet.",
|
||||
"tablet_not_synced_last_user": "La tablette n'as pas été synchronisée par l'utilisateur précédent.",
|
||||
"incorrect_credentials": "Identifiants incorrect.",
|
||||
"must_fill_login_fields": "Vous devez-remplir les champs de connexion.",
|
||||
"invalid_email_address": "Adresse email invalide",
|
||||
"error_has_occurred": "Une erreur est survenue",
|
||||
"must_be_connected_internet_sync": "Vous devez être connecté à internet pour lancer la synchronisation",
|
||||
"incomplete_form": "Formulaire incomplet",
|
||||
"fill_all_fields_and_1_doc_min": "Veuillez remplir tous les champs, 1 document minimum et une adresse email valide",
|
||||
"fill_other_field": "Vous devez remplir le champs description pour : Autre",
|
||||
"specify_type_contact": "Vous devez préciser le type de contact",
|
||||
"invalid_name": "Nom invalide",
|
||||
"invalid_firstname": "Prénom invalide",
|
||||
"camera_permission_denied": "Permission caméra refusée",
|
||||
"pending_camera_permission": "En attente de permission caméra"
|
||||
},
|
||||
"alert": {
|
||||
"error": "Erreur",
|
||||
"info": "Information"
|
||||
}
|
||||
}
|
||||
{
|
||||
"install": {
|
||||
"installation": "Installation",
|
||||
"install": "Installer",
|
||||
"enter_url": "Veuillez entrer le lien de votre back-office",
|
||||
"url_invalid": "Le lien saisi est invalide.",
|
||||
"resource_dl_error": "Une erreur est survenue lors du téléchargement de la ressource suivante : ",
|
||||
"install_complete": "Installation terminée !",
|
||||
"get_app_setting": "Récupération de la configuration de l'application",
|
||||
"get_content_setting": "Récupération de la configuration du contenu de l'application"
|
||||
},
|
||||
"global": {
|
||||
"change_lang": "Changer de langue",
|
||||
"sync": "Synchronisation",
|
||||
"logout": "Se déconnecter",
|
||||
"close": "Fermer",
|
||||
"yes": "Oui",
|
||||
"no": "Non",
|
||||
"home": "Accueil",
|
||||
"search": "Recherche",
|
||||
"login": "Connexion",
|
||||
"email": "Email",
|
||||
"message_sent": "Message envoyé",
|
||||
"message_will_be_sent_after_sync": "Le message sera envoyé après synchronisation",
|
||||
"warning": "Attention",
|
||||
"synchronization": "Synchronisation",
|
||||
"videos": "Vidéos",
|
||||
"contacts": "Contacts",
|
||||
"confirmation": "Confirmation",
|
||||
"lastname": "Nom",
|
||||
"firstname": "Prénom",
|
||||
"address": "Adresse",
|
||||
"phone": "Téléphone",
|
||||
"company": "Société",
|
||||
"add": "Ajouter",
|
||||
"cancel": "Annuler",
|
||||
"subject": "Objet",
|
||||
"message": "Message",
|
||||
"send": "Envoyer",
|
||||
"required": "requis",
|
||||
"save": "Enregistrer",
|
||||
"retry": "Réessayer",
|
||||
"next": "Suivant"
|
||||
},
|
||||
"app": {
|
||||
"file_sharing": "Partage de fichier",
|
||||
"folders": "Dossiers",
|
||||
"video": "Vidéo",
|
||||
"contact_details": "Détails du contact",
|
||||
"results_search": "Résultat(s) de votre recherche",
|
||||
"my_space": "Mon espace"
|
||||
},
|
||||
"login_s": {
|
||||
"username": "Identifiant",
|
||||
"password": "Mot de passe",
|
||||
"missing_users": "Utilisateurs introuvables"
|
||||
},
|
||||
"search_s": {
|
||||
"no_result": "Aucun résultat"
|
||||
},
|
||||
"sync_s": {
|
||||
"download": "Téléchargement",
|
||||
"update_completed": "Mise à jour effectuée",
|
||||
"updating_docs": "Mise à jour des documents",
|
||||
"updating_forms": "Mise à jour des formulaires",
|
||||
"updating_folders": "Mise à jour des dossiers",
|
||||
"sending_flyers": "Envoi des brochures",
|
||||
"updating_contacts": "Mise à jour des contacts",
|
||||
"user_install_completed": "Installation des utilisateurs effectuée",
|
||||
"updating_users": "Mise à jour des utilisateurs",
|
||||
"user_install": "Installation des utilisateurs",
|
||||
"start_sync": "LANCER LA SYNCHRONISATION",
|
||||
"new_app_version": "Une nouvelle version de l'application est disponible !",
|
||||
"open_store": "Ouvrir le store"
|
||||
},
|
||||
"contact_s": {
|
||||
"contact_transferred": "Contact transféré",
|
||||
"contact_will_be_sent_after_sync": "Le contact sera envoyé après synchronisation",
|
||||
"confirm_contact_delete": "Êtes-vous sûr de vouloir supprimer ce contact ?",
|
||||
"contact_deleted": "Contact supprimé",
|
||||
"contact_added": "Contact ajouté",
|
||||
"send_flyer": "Envoyer une brochure",
|
||||
"select_contact": "Sélectionnez un utilisateur",
|
||||
"transfer": "Transférer",
|
||||
"contact_list": "Liste des contacts",
|
||||
"documents_list": "Liste des documents"
|
||||
},
|
||||
"contact_details_s": {
|
||||
"visits": "Visites",
|
||||
"notes": "Notes",
|
||||
"contact_saved": "Contact enregistré",
|
||||
"confirm_visit_delete": "Êtes-vous sûr de vouloir supprimer cette visite ?",
|
||||
"qrcode_not_vcard_format": "Ce QRCode n'est pas au format vCard",
|
||||
"description": "Description",
|
||||
"no_visits": "Aucune visites",
|
||||
"visit_name": "Nom de la visite",
|
||||
"input_select_please_choose": "Selectionnez un élément",
|
||||
"input_select_multiple_search": "Recherche",
|
||||
"input_required": "Le champ %{placeholder} est obligatoire",
|
||||
"input_email": "Le champ %{placeholder} doit être un email valide"
|
||||
},
|
||||
"error": {
|
||||
"error": "Erreur",
|
||||
"tablet_not_connected_internet": "La tablette n'est pas connectée à internet.",
|
||||
"tablet_not_synced_last_user": "La tablette n'as pas été synchronisée par l'utilisateur précédent.",
|
||||
"incorrect_credentials": "Identifiants incorrect.",
|
||||
"must_fill_login_fields": "Vous devez-remplir les champs de connexion.",
|
||||
"invalid_email_address": "Adresse email invalide",
|
||||
"invalid_firstname": "Prénom invalide",
|
||||
"invalid_lastname": "Nom invalide",
|
||||
"invalid_phone": "Téléphone invalide",
|
||||
"field_required": "Le champ %{placeholder} est obligatoire",
|
||||
"error_has_occurred": "Une erreur est survenue",
|
||||
"must_be_connected_internet_sync": "Vous devez être connecté à internet pour lancer la synchronisation",
|
||||
"incomplete_form": "Formulaire incomplet",
|
||||
"fill_all_fields_and_1_doc_min": "Veuillez remplir tous les champs, 1 document minimum et une adresse email valide",
|
||||
"camera_permission_denied": "Permission caméra refusée",
|
||||
"pending_camera_permission": "En attente de permission caméra"
|
||||
},
|
||||
"alert": {
|
||||
"error": "Erreur",
|
||||
"info": "Information"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3378,7 +3378,7 @@
|
|||
"resolved" "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
|
||||
"version" "1.1.2"
|
||||
|
||||
"buffer@^5.5.0", "buffer@^5.6.0":
|
||||
"buffer@^5.5.0":
|
||||
"integrity" "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="
|
||||
"resolved" "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz"
|
||||
"version" "5.7.1"
|
||||
|
|
@ -3386,6 +3386,22 @@
|
|||
"base64-js" "^1.3.1"
|
||||
"ieee754" "^1.1.13"
|
||||
|
||||
"buffer@^5.6.0":
|
||||
"integrity" "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="
|
||||
"resolved" "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz"
|
||||
"version" "5.7.1"
|
||||
dependencies:
|
||||
"base64-js" "^1.3.1"
|
||||
"ieee754" "^1.1.13"
|
||||
|
||||
"buffer@^6.0.3":
|
||||
"integrity" "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="
|
||||
"resolved" "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz"
|
||||
"version" "6.0.3"
|
||||
dependencies:
|
||||
"base64-js" "^1.3.1"
|
||||
"ieee754" "^1.2.1"
|
||||
|
||||
"builtins@^1.0.3":
|
||||
"integrity" "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ=="
|
||||
"resolved" "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz"
|
||||
|
|
@ -5874,7 +5890,7 @@
|
|||
dependencies:
|
||||
"safer-buffer" ">= 2.1.2 < 3.0.0"
|
||||
|
||||
"ieee754@^1.1.13":
|
||||
"ieee754@^1.1.13", "ieee754@^1.2.1":
|
||||
"integrity" "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
||||
"resolved" "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz"
|
||||
"version" "1.2.1"
|
||||
|
|
@ -7317,6 +7333,11 @@
|
|||
"resolved" "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz"
|
||||
"version" "4.0.8"
|
||||
|
||||
"lodash.isequal@^4.5.0":
|
||||
"integrity" "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
|
||||
"resolved" "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz"
|
||||
"version" "4.5.0"
|
||||
|
||||
"lodash.merge@^4.6.2":
|
||||
"integrity" "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
||||
"resolved" "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
|
||||
|
|
@ -7477,6 +7498,11 @@
|
|||
"resolved" "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz"
|
||||
"version" "5.2.1"
|
||||
|
||||
"memoize-one@^6.0.0":
|
||||
"integrity" "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
|
||||
"resolved" "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz"
|
||||
"version" "6.0.0"
|
||||
|
||||
"memory-cache@~0.2.0":
|
||||
"integrity" "sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA=="
|
||||
"resolved" "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz"
|
||||
|
|
@ -9029,7 +9055,7 @@
|
|||
dependencies:
|
||||
"read" "1"
|
||||
|
||||
"prop-types@*", "prop-types@^15.6.2", "prop-types@^15.7.2", "prop-types@^15.8.1":
|
||||
"prop-types@*", "prop-types@^15.6.0", "prop-types@^15.6.2", "prop-types@^15.7.2", "prop-types@^15.8.1":
|
||||
"integrity" "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="
|
||||
"resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
|
||||
"version" "15.8.1"
|
||||
|
|
@ -9199,6 +9225,11 @@
|
|||
"jscodeshift" "^0.13.1"
|
||||
"nullthrows" "^1.1.1"
|
||||
|
||||
"react-native-email-link@^1.14.6":
|
||||
"integrity" "sha512-XsWgdSMgxutKrm6WJRLKd1DxQpFt2x6xLuIhmAE5CdMMjNKadsUM5Evub9+otTBhlphSerePAwzSaNoBXpisLg=="
|
||||
"resolved" "https://registry.npmjs.org/react-native-email-link/-/react-native-email-link-1.14.6.tgz"
|
||||
"version" "1.14.6"
|
||||
|
||||
"react-native-flash-message@^0.3.1":
|
||||
"integrity" "sha512-PswNvDdHBOavmIM7G4loLuEwML3oB8E8wVCuOPQ0Q6hRbExwTaF6gsTJvo5fQkyUsCi27ainSkL/F0ZijIkVig=="
|
||||
"resolved" "https://registry.npmjs.org/react-native-flash-message/-/react-native-flash-message-0.3.1.tgz"
|
||||
|
|
@ -9263,6 +9294,14 @@
|
|||
"react-freeze" "^1.0.0"
|
||||
"warn-once" "^0.1.0"
|
||||
|
||||
"react-native-sectioned-multi-select@^0.10.0":
|
||||
"integrity" "sha512-wD5USgM88cHNkgQLB94NxbubtYCLacgzk2vfFlF+HvOI7noDz1AZfzu2sVp1WKz4bFx20MFxM4mi1uZoyxAutg=="
|
||||
"resolved" "https://registry.npmjs.org/react-native-sectioned-multi-select/-/react-native-sectioned-multi-select-0.10.0.tgz"
|
||||
"version" "0.10.0"
|
||||
dependencies:
|
||||
"lodash.isequal" "^4.5.0"
|
||||
"memoize-one" "^6.0.0"
|
||||
|
||||
"react-native-size-matters@^0.4.0":
|
||||
"integrity" "sha512-8/C0htHrFWeUm9N8JegmadovUfgTWkGBkDPZ1N3YkXtDWb+98Ya2gThiKcu445r8c7YhcrBfnHz/mYsXIusaOQ=="
|
||||
"resolved" "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.4.0.tgz"
|
||||
|
|
@ -9276,6 +9315,11 @@
|
|||
"css-select" "^5.1.0"
|
||||
"css-tree" "^1.1.3"
|
||||
|
||||
"react-native-uuid@^2.0.1":
|
||||
"integrity" "sha512-cptnoIbL53GTCrWlb/+jrDC6tvb7ypIyzbXNJcpR3Vab0mkeaaVd5qnB3f0whXYzS+SMoSQLcUUB0gEWqkPC0g=="
|
||||
"resolved" "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.1.tgz"
|
||||
"version" "2.0.1"
|
||||
|
||||
"react-native-vector-icons@^9.2.0", "react-native-vector-icons@>7.0.0":
|
||||
"integrity" "sha512-wKYLaFuQST/chH3AJRjmOLoLy3JEs1JR6zMNgTaemFpNoXs0ztRnTxcxFD9xhX7cJe1/zoN5BpQYe7kL0m5yyA=="
|
||||
"resolved" "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz"
|
||||
|
|
@ -9284,7 +9328,7 @@
|
|||
"prop-types" "^15.7.2"
|
||||
"yargs" "^16.1.1"
|
||||
|
||||
"react-native@*", "react-native@^0.70.6", "react-native@>=0.42.0", "react-native@>=0.56.0", "react-native@>=0.57", "react-native@>=0.59", "react-native@>=0.70.0":
|
||||
"react-native@*", "react-native@^0.70.6", "react-native@>=0.40.0", "react-native@>=0.42.0", "react-native@>=0.56.0", "react-native@>=0.57", "react-native@>=0.59", "react-native@>=0.70.0":
|
||||
"integrity" "sha512-xtQdImPHnwgraEx3HIZFOF+D1hJ9bC5mfpIdUGoMHRws6OmvHAjmFpO6qfdnaQ29vwbmZRq7yf14sbury74R/w=="
|
||||
"resolved" "https://registry.npmjs.org/react-native/-/react-native-0.70.6.tgz"
|
||||
"version" "0.70.6"
|
||||
|
|
@ -9356,7 +9400,7 @@
|
|||
"react-shallow-renderer" "^16.15.0"
|
||||
"scheduler" "^0.22.0"
|
||||
|
||||
"react@*", "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^18.1.0", "react@>=16", "react@>=16.4.1", "react@>=17.0.0", "react@15.x || 16.x || 17.x || 18.x", "react@18.1.0":
|
||||
"react@*", "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^18.1.0", "react@>=16", "react@>=16.4.1", "react@>=16.8.0", "react@>=17.0.0", "react@15.x || 16.x || 17.x || 18.x", "react@18.1.0":
|
||||
"integrity" "sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ=="
|
||||
"resolved" "https://registry.npmjs.org/react/-/react-18.1.0.tgz"
|
||||
"version" "18.1.0"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue