@fto-consult/expo-ui 5.8.10 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/babel.config.alias.js +23 -0
- package/babel.config.js +0 -1
- package/package.json +2 -2
- package/src/App.js +5 -40
- package/src/components/Datagrid/Common/Common.js +16 -13
- package/src/components/Datagrid/SWRDatagrid.js +2 -2
- package/src/components/Form/Fields/Field.js +19 -6
- package/src/components/Form/Fields/SelectTableData/Component.js +4 -3
- package/src/components/Form/FormData/FormData.js +3 -0
- package/src/components/InlineIndicator/index.js +4 -4
- package/src/components/InlineIndicator/utils.js +15 -0
- package/src/components/PhoneInput/PhoneNumber.js +1 -0
- package/src/components/SimpleSelect/index.js +1 -1
- package/src/components/SplashScreen/index.js +122 -152
- package/src/index.js +69 -30
- package/src/layouts/DatabaseStatistics/index.js +1 -1
- package/src/layouts/Screen/FormData/List.js +0 -14
- package/src/layouts/Screen/TableData.js +6 -3
- package/src/layouts/Screen/utils.js +5 -2
- package/src/screens/Auth/PermProfile.js +2 -2
package/babel.config.alias.js
CHANGED
|
@@ -16,6 +16,29 @@ module.exports = (opts)=>{
|
|
|
16
16
|
const cpath = fs.existsSync(euCommon)? path.resolve(euCommon,"babel.config.alias") : "@fto-consult/common/babel.config.alias";
|
|
17
17
|
const r = require(`${cpath}`)(opts);
|
|
18
18
|
const expo = path.resolve(expoUI,"src");
|
|
19
|
+
|
|
20
|
+
/**** package json */
|
|
21
|
+
const packagePath = path.resolve(base,"package.json");
|
|
22
|
+
const configPath = path.resolve(expo,"app.config.json");
|
|
23
|
+
if(fs.existsSync(packagePath)){
|
|
24
|
+
try {
|
|
25
|
+
const packageObj = require(`${packagePath}`);
|
|
26
|
+
if(typeof packageObj.name =="string"){
|
|
27
|
+
packageObj.name = packageObj.name.toUpperCase();
|
|
28
|
+
}
|
|
29
|
+
if(packageObj){
|
|
30
|
+
["scripts","private","main","repository","keywords","bugs","dependencies","devDependencies"].map(v=>{
|
|
31
|
+
delete packageObj[v];
|
|
32
|
+
})
|
|
33
|
+
fs.writeFileSync(configPath,JSON.stringify(packageObj,null,"\t"));
|
|
34
|
+
}
|
|
35
|
+
} catch (e){
|
|
36
|
+
console.log(e," writing file sync on package JSON, file : $common/babel.config.alias")
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if(fs.existsSync(configPath)){
|
|
40
|
+
r["$package.json"] = r["$packageJSON"] = configPath;
|
|
41
|
+
}
|
|
19
42
|
r["$eauth"] = path.resolve(expo,"auth");
|
|
20
43
|
r["$ecomponents"] = r["$expo-components"] = path.resolve(expo,"components");
|
|
21
44
|
r["$etableLink"] = r["$eTableLink"] = path.resolve(r["$ecomponents"],"TableLink");
|
package/babel.config.js
CHANGED
|
@@ -14,7 +14,6 @@ module.exports = function(api,opts) {
|
|
|
14
14
|
inlineDovOptions.path ='./.env';
|
|
15
15
|
}
|
|
16
16
|
/*** par défaut, les variables d'environnements sont stockés dans le fichier .env situé à la racine du projet, référencée par la prop base */
|
|
17
|
-
|
|
18
17
|
const alias = require("./babel.config.alias")(options);
|
|
19
18
|
return {
|
|
20
19
|
presets: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fto-consult/expo-ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.9.0",
|
|
4
4
|
"description": "Bibliothèque de composants UI Expo,react-native",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@emotion/native": "^11.10.6",
|
|
62
62
|
"@expo/html-elements": "^0.2.0",
|
|
63
63
|
"@expo/vector-icons": "^13.0.0",
|
|
64
|
-
"@fto-consult/common": "^3.
|
|
64
|
+
"@fto-consult/common": "^3.13.16",
|
|
65
65
|
"@gorhom/portal": "^1.0.14",
|
|
66
66
|
"@react-native-async-storage/async-storage": "^1.17.11",
|
|
67
67
|
"@react-native-community/datetimepicker": "^6.7.3",
|
package/src/App.js
CHANGED
|
@@ -2,18 +2,11 @@ import '$session';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import {SWRConfig} from "$swr";
|
|
4
4
|
import {defaultObj} from "$cutils";
|
|
5
|
-
import {updateTheme,defaultTheme} from "$theme";
|
|
6
|
-
import {Provider as PaperProvider } from 'react-native-paper';
|
|
7
5
|
import Index from './index';
|
|
8
6
|
import notify from "$notify";
|
|
9
7
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
10
|
-
import { PreferencesContext } from './Preferences';
|
|
11
|
-
import {AuthProvider} from '$cauth';
|
|
12
|
-
import ErrorBoundary from "$ecomponents/ErrorBoundary";
|
|
13
8
|
import {GestureHandlerRootView} from "react-native-gesture-handler";
|
|
14
|
-
import StatusBar from "$ecomponents/StatusBar";
|
|
15
9
|
import APP from "$app";
|
|
16
|
-
import FontIcon from "$ecomponents/Icon/Font"
|
|
17
10
|
import {isMobileNative} from "$cplatform";
|
|
18
11
|
import {setDeviceIdRef} from "$capp";
|
|
19
12
|
import appConfig from "$capp/config";
|
|
@@ -30,7 +23,7 @@ Object.map(Utils,(v,i)=>{
|
|
|
30
23
|
window[i] = v;
|
|
31
24
|
}
|
|
32
25
|
});
|
|
33
|
-
export default function getIndex({onMount,onUnmount,swrConfig,
|
|
26
|
+
export default function getIndex({onMount,onUnmount,swrConfig,onRender,...rest}){
|
|
34
27
|
const isScreenFocusedRef = React.useRef(true);
|
|
35
28
|
///garde pour chaque écran sa date de dernière activité
|
|
36
29
|
const screensRef = React.useRef({});//la liste des écrans actifs
|
|
@@ -97,19 +90,7 @@ export default function getIndex({onMount,onUnmount,swrConfig,render,onRender,pr
|
|
|
97
90
|
}
|
|
98
91
|
}
|
|
99
92
|
},[])
|
|
100
|
-
|
|
101
|
-
const updatePreferenceTheme = (customTheme,persist)=>{
|
|
102
|
-
setTheme(updateTheme(customTheme));
|
|
103
|
-
};
|
|
104
|
-
const forceRender = React.useForceRender();
|
|
105
|
-
const pref = typeof appPreferences =='function'? appPreferences({setTheme,forceRender,updateTheme:updatePreferenceTheme}) : appPreferences;
|
|
106
|
-
const preferences = React.useMemo(()=>({
|
|
107
|
-
updateTheme:updatePreferenceTheme,
|
|
108
|
-
theme,
|
|
109
|
-
...defaultObj(pref),
|
|
110
|
-
}),[theme,pref]);
|
|
111
|
-
const child = <Index {...rest} theme={theme}/>;
|
|
112
|
-
const content = typeof render == 'function'? render({children:child,appConfig,config:appConfig}) : child;
|
|
93
|
+
|
|
113
94
|
return (
|
|
114
95
|
<SWRConfig
|
|
115
96
|
value={{
|
|
@@ -160,25 +141,9 @@ export default function getIndex({onMount,onUnmount,swrConfig,render,onRender,pr
|
|
|
160
141
|
}}
|
|
161
142
|
>
|
|
162
143
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
icon: (props) => {
|
|
167
|
-
return <FontIcon {...props}/>
|
|
168
|
-
},
|
|
169
|
-
}}
|
|
170
|
-
>
|
|
171
|
-
<SafeAreaProvider>
|
|
172
|
-
<AuthProvider>
|
|
173
|
-
<ErrorBoundary>
|
|
174
|
-
<StatusBar/>
|
|
175
|
-
<PreferencesContext.Provider value={preferences}>
|
|
176
|
-
{React.isValidElement(content) && content || child}
|
|
177
|
-
</PreferencesContext.Provider>
|
|
178
|
-
</ErrorBoundary>
|
|
179
|
-
</AuthProvider>
|
|
180
|
-
</SafeAreaProvider>
|
|
181
|
-
</PaperProvider>
|
|
144
|
+
<SafeAreaProvider>
|
|
145
|
+
<Index {...rest}/>
|
|
146
|
+
</SafeAreaProvider>
|
|
182
147
|
</GestureHandlerRootView>
|
|
183
148
|
</SWRConfig>
|
|
184
149
|
);
|
|
@@ -934,19 +934,22 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
934
934
|
})
|
|
935
935
|
if(size === 1 && canMakePhoneCall === true && canMakeCall()){
|
|
936
936
|
const rowKey = Object.keys(this.selectedRows)[0], rowData = defaultObj(this.selectedRows[rowKey]);
|
|
937
|
-
|
|
938
|
-
callProps =
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
937
|
+
const table = defaultStr(this.props.table,this.props.tableName).trim();
|
|
938
|
+
let callProps = typeof makePhoneCallProps == 'function'? makePhoneCallProps({rowData,rowKey,table,tableName:table,data:rowData,key:rowKey,context:this,props:this.props}) : makePhoneCallProps;
|
|
939
|
+
if(callProps !== false){
|
|
940
|
+
callProps = defaultObj(callProps);
|
|
941
|
+
r.push({
|
|
942
|
+
text : defaultStr(callProps.text,callProps.label,'Appeler'),
|
|
943
|
+
icon : defaultStr(callProps.icon,'phone'),
|
|
944
|
+
flat : true,
|
|
945
|
+
onPress : ()=>{
|
|
946
|
+
return makePhoneCall(
|
|
947
|
+
rowData,
|
|
948
|
+
callProps
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
})
|
|
952
|
+
}
|
|
950
953
|
}
|
|
951
954
|
if(isObj(this.props.columns) && size ===1){
|
|
952
955
|
r.push({
|
|
@@ -65,7 +65,7 @@ export const getSWROptions = ()=>{
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
const isValidMakePhoneCallProps = p=> isObj(p) && Object.size(p,true) || typeof p ==='function';
|
|
69
69
|
/****la fonction fetcher doit toujours retourner :
|
|
70
70
|
* 1. la liste des éléments fetchés dans la props data
|
|
71
71
|
* 2. le nombre total d'éléments de la liste obtenue en escluant les clause limit et offset correspondant à la même requête
|
|
@@ -118,7 +118,7 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
118
118
|
delete sort.column;
|
|
119
119
|
}
|
|
120
120
|
canMakePhoneCall = defaultBool(canMakePhoneCall,table.canMakePhoneCall);
|
|
121
|
-
makePhoneCallProps =
|
|
121
|
+
makePhoneCallProps = isValidMakePhoneCallProps(makePhoneCallProps) && makePhoneCallProps || isValidMakePhoneCallProps(rest.makePhoneCallProps) && rest.makePhoneCallProps || isValidMakePhoneCallProps(table.makePhoneCallProps) && table.makePhoneCallProps || {};
|
|
122
122
|
const isExportable = !!Auth.isTableDataAllowed({table:tableName,action:'export'});
|
|
123
123
|
rest.exportable = isExportable;
|
|
124
124
|
rowKey = defaultStr(rowKey,table.rowKey,table.primaryKeyColumnName);
|
|
@@ -3,9 +3,10 @@ import KeyboardEventHandler from "../KeyboardEventHandler";
|
|
|
3
3
|
const {getActions,getFormFields,Forms} = require("../utils")
|
|
4
4
|
import TextField,{parseDecimal} from "$ecomponents/TextField";
|
|
5
5
|
import Icon from "$ecomponents/Icon";
|
|
6
|
-
import {extendObj,isBool,isUndefined,uniqid,isValidDataFileName,defaultObj,isObj,defaultFunc,isFunction,isNumber,arrayValueExists,defaultVal,defaultStr,isNonNullString,defaultBool,defaultDecimal} from "$cutils";
|
|
6
|
+
import {extendObj,isBool,isUndefined,uniqid,isValidDataFileName,isValidEmail,defaultObj,isObj,defaultFunc,isFunction,isNumber,arrayValueExists,defaultVal,defaultStr,isNonNullString,defaultBool,defaultDecimal} from "$cutils";
|
|
7
7
|
import {Component as AppComponent} from "$react";
|
|
8
8
|
import {observable,addObserver} from "$observable";
|
|
9
|
+
import {isValidPhoneNumber} from "$ecomponents/PhoneInput";
|
|
9
10
|
import {Validator} from "$validator";
|
|
10
11
|
import theme,{grid} from "$theme";
|
|
11
12
|
import React from "$react";
|
|
@@ -285,11 +286,23 @@ export default class Field extends AppComponent {
|
|
|
285
286
|
});
|
|
286
287
|
}
|
|
287
288
|
onValidatorValid(args){
|
|
288
|
-
if(!this.isFilter()
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
if(value
|
|
292
|
-
|
|
289
|
+
if(!this.isFilter()){
|
|
290
|
+
const vRule =defaultStr(this.getValidRule()).toLowerCase();
|
|
291
|
+
const value = typeof args.value == "undefined" || args.value == null ? "" : String(args.value).replaceAll("/","").replaceAll("\\",'').trim();
|
|
292
|
+
if(value){
|
|
293
|
+
if(this.type ==='email' || vRule.contains('email')){
|
|
294
|
+
if(!isValidEmail(value)){
|
|
295
|
+
return "Veuillez saisir une addresse email valide";
|
|
296
|
+
}
|
|
297
|
+
} else if(this.type ==="tel" || this.type =="phone"){
|
|
298
|
+
if(!isValidPhoneNumber(value)){
|
|
299
|
+
return "Merci d'entrer un numéro de téléphone valide";
|
|
300
|
+
}
|
|
301
|
+
} else if(((this.props.allowWhiteSpaces === false) || ((this.type ==='id' || this.type =='piece') && this.props.allowWhiteSpaces !== true))){
|
|
302
|
+
if((value.contains(" ") || !isValidDataFileName(value.replaceAll("@","").replaceAll(".","")))){
|
|
303
|
+
return "Veuillez renseigner une valeur ne contenant pas d'espace ou de caractère accentués";
|
|
304
|
+
}
|
|
305
|
+
}
|
|
293
306
|
}
|
|
294
307
|
}
|
|
295
308
|
if(isFunction(this.props.onValidatorValid)){
|
|
@@ -33,7 +33,8 @@ const TableDataSelectField = React.forwardRef(({foreignKeyColumn,bindUpsert2Remo
|
|
|
33
33
|
}
|
|
34
34
|
convertFiltersToSQL = defaultVal(convertFiltersToSQL,willConvertFiltersToSQL());
|
|
35
35
|
getForeignKeyTable = getForeignKeyTable || appConfig.getTableData;
|
|
36
|
-
|
|
36
|
+
const foreignKeyTableStr = defaultStr(foreignKeyTable,props.table,props.tableName);
|
|
37
|
+
let fKeyTable = typeof getForeignKeyTable =='function' ? getForeignKeyTable(foreignKeyTableStr,props) : undefined;
|
|
37
38
|
fetchItemsPath = defaultStr(fetchItemsPath).trim();
|
|
38
39
|
|
|
39
40
|
if(!fetchItemsPath && (!isObj(fKeyTable) || !(defaultStr(fKeyTable.tableName,fKeyTable.table)))){
|
|
@@ -67,8 +68,8 @@ const TableDataSelectField = React.forwardRef(({foreignKeyColumn,bindUpsert2Remo
|
|
|
67
68
|
const defaultFields = Array.isArray(foreignKeyColumn)? foreignKeyColumn : [foreignKeyColumn];
|
|
68
69
|
if(Array.isArray(foreignKeyLabel)){
|
|
69
70
|
foreignKeyLabel.map(f=>{
|
|
70
|
-
if(isNonNullString(f)){
|
|
71
|
-
defaultFields.push(f);
|
|
71
|
+
if(isNonNullString(f) && !defaultFields.includes(f.trim())){
|
|
72
|
+
defaultFields.push(f.trim());
|
|
72
73
|
}
|
|
73
74
|
})
|
|
74
75
|
}
|
|
@@ -94,6 +94,9 @@ export default class FormDataComponent extends AppComponent{
|
|
|
94
94
|
savedArgs = {...savedArgs,data}
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
+
if(typeof saveDataMutator =='function'){
|
|
98
|
+
saveDataMutator(savedArgs);
|
|
99
|
+
}
|
|
97
100
|
return handleBeforeSaveCallback(this.beforeSave.bind(this),()=>{
|
|
98
101
|
return handleBeforeSaveCallback(beforeSave,()=>{
|
|
99
102
|
return handleBeforeSaveCallback(this.onSave.bind(this),()=>{
|
|
@@ -5,7 +5,7 @@ import {defaultObj,defaultVal} from "$cutils";
|
|
|
5
5
|
import {isMobileMedia} from "$cplatform/dimensions";
|
|
6
6
|
import TextFieldComponent from "$ecomponents/TextField";
|
|
7
7
|
import { StyleSheet } from "react-native";
|
|
8
|
-
|
|
8
|
+
import {METRICS_UNITS,WEIGHTS_UNITS} from "./utils";
|
|
9
9
|
|
|
10
10
|
export {Select};
|
|
11
11
|
|
|
@@ -45,7 +45,7 @@ export const MetricUnit = React.forwardRef((props,ref)=>{
|
|
|
45
45
|
inputProps.style = [styles.metricUnit,inputProps.style];
|
|
46
46
|
rest = defaultObj(rest);
|
|
47
47
|
return <Select
|
|
48
|
-
items = {
|
|
48
|
+
items = {METRICS_UNITS}
|
|
49
49
|
withCheckedIcon = {isMob}
|
|
50
50
|
{...rest}
|
|
51
51
|
inputProps = {inputProps}
|
|
@@ -67,7 +67,7 @@ export const WeightUnit = React.forwardRef((props,ref)=>{
|
|
|
67
67
|
inputProps.style = [styles.weightUnit,inputProps.style];
|
|
68
68
|
rest = defaultObj(rest);
|
|
69
69
|
return <Select
|
|
70
|
-
items = {
|
|
70
|
+
items = {WEIGHTS_UNITS}
|
|
71
71
|
renderItem = {({item,index})=>index}
|
|
72
72
|
withCheckedIcon = {isMob}
|
|
73
73
|
{...rest}
|
|
@@ -102,7 +102,7 @@ export const TextField = TextInput;
|
|
|
102
102
|
WeightUnit.displayName = "WeightUnitInlineIndicatorComponent";
|
|
103
103
|
|
|
104
104
|
export const Text = React.forwardRef((props,ref)=>{
|
|
105
|
-
return <LabelComponent.withRef ref={ref} {...props}
|
|
105
|
+
return <LabelComponent.withRef ref={ref} {...props} style={[styles.text,props.style]}/>
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
export const Label = Text;
|
|
@@ -322,7 +322,7 @@ const SimpleSelect = React.forwardRef((props,ref)=>{
|
|
|
322
322
|
paddingHorizontal : 10,
|
|
323
323
|
paddingVertical:0,
|
|
324
324
|
height : !isMob?contentContainerHeight:'90%',
|
|
325
|
-
width : !isMob ? layout.width : undefined,
|
|
325
|
+
width : !isMob ? Math.max(layout.width,150) : undefined,
|
|
326
326
|
},
|
|
327
327
|
isMob && {flex:1},
|
|
328
328
|
!isMob && {paddingRight : 0},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* @flow */
|
|
2
2
|
/*** fork of https://www.npmjs.com/package/react-native-animated-splash-screen */
|
|
3
3
|
import PropTypes from "prop-types"
|
|
4
|
-
import
|
|
4
|
+
import React from "$react"
|
|
5
5
|
import {Animated, StyleSheet } from "react-native";
|
|
6
6
|
import View from "$ecomponents/View";
|
|
7
7
|
import {isNativeMobile} from "$cplatform";
|
|
@@ -19,167 +19,136 @@ import styles, {
|
|
|
19
19
|
const isNative = isNativeMobile();
|
|
20
20
|
const Component = isNative? Animated.View : View;
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
state = {
|
|
22
|
+
const SplashScreenComponent = ({isLoaded,children , duration, delay,logoWidth,logoHeight,backgroundColor,imageBackgroundSource,imageBackgroundResizeMode,
|
|
23
|
+
testID,
|
|
24
|
+
disableAppScale,
|
|
25
|
+
disableImageBackgroundAnimation,preload})=>{
|
|
26
|
+
const [state,setState] = React.useState({
|
|
28
27
|
animationDone: false,
|
|
29
28
|
loadingProgress: new Animated.Value(0)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if(!isNativeMobile()){
|
|
38
|
-
this.setState({animationDone:true});
|
|
39
|
-
} else {
|
|
40
|
-
Animated.timing(loadingProgress, {
|
|
41
|
-
toValue: 100,
|
|
42
|
-
duration: duration || 1000,
|
|
43
|
-
delay: delay || 0,
|
|
44
|
-
useNativeDriver: true,
|
|
45
|
-
}).start(() => {
|
|
46
|
-
this.setState({
|
|
47
|
-
animationDone: true,
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
renderChildren() {
|
|
55
|
-
const { children, preload, isLoaded } = this.props
|
|
56
|
-
if (preload || preload == null) {
|
|
57
|
-
return children
|
|
29
|
+
});
|
|
30
|
+
const { loadingProgress, animationDone } = state;
|
|
31
|
+
const prevIsLoaded = React.usePrevious(isLoaded);
|
|
32
|
+
React.useEffect(()=>{
|
|
33
|
+
if(prevIsLoaded == isLoaded || !isLoaded) return;
|
|
34
|
+
if(!isNativeMobile()){
|
|
35
|
+
setState({...state,animationDone:true});
|
|
58
36
|
} else {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
37
|
+
Animated.timing(loadingProgress, {
|
|
38
|
+
toValue: 100,
|
|
39
|
+
duration: duration || 1000,
|
|
40
|
+
delay: delay || 0,
|
|
41
|
+
useNativeDriver: true,
|
|
42
|
+
}).start(() => {
|
|
43
|
+
setState({
|
|
44
|
+
...state,
|
|
45
|
+
animationDone: true,
|
|
46
|
+
})
|
|
47
|
+
})
|
|
62
48
|
}
|
|
63
|
-
|
|
64
|
-
|
|
49
|
+
},[isLoaded]);
|
|
50
|
+
testID = defaultStr(testID,"RN_SplashscreenComponent")
|
|
51
|
+
logoWidth = defaultDecimal(logoWidth,150);
|
|
52
|
+
logoHeight = defaultDecimal(logoHeight,250);
|
|
53
|
+
const opacityClearToVisible = {
|
|
54
|
+
opacity: loadingProgress.interpolate({
|
|
55
|
+
inputRange: [0, 15, 30],
|
|
56
|
+
outputRange: [0, 0, 1],
|
|
57
|
+
extrapolate: "clamp",
|
|
58
|
+
}),
|
|
59
|
+
}
|
|
60
|
+
const imageScale = {
|
|
61
|
+
transform: [
|
|
62
|
+
{
|
|
63
|
+
scale: loadingProgress.interpolate({
|
|
64
|
+
inputRange: [0, 10, 100],
|
|
65
|
+
outputRange: [1, 1, 65],
|
|
66
|
+
}),
|
|
67
|
+
},
|
|
68
|
+
],
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
disableAppScale,
|
|
78
|
-
disableImageBackgroundAnimation,
|
|
79
|
-
} = this.props
|
|
80
|
-
testID = defaultStr(testID,"RN_SplashscreenComponent")
|
|
81
|
-
logoWidth = defaultDecimal(logoWidth,150);
|
|
82
|
-
logoHeight = defaultDecimal(logoHeight,250);
|
|
83
|
-
const opacityClearToVisible = {
|
|
84
|
-
opacity: loadingProgress.interpolate({
|
|
85
|
-
inputRange: [0, 15, 30],
|
|
86
|
-
outputRange: [0, 0, 1],
|
|
87
|
-
extrapolate: "clamp",
|
|
88
|
-
}),
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const imageScale = {
|
|
92
|
-
transform: [
|
|
93
|
-
{
|
|
94
|
-
scale: loadingProgress.interpolate({
|
|
95
|
-
inputRange: [0, 10, 100],
|
|
96
|
-
outputRange: [1, 1, 65],
|
|
97
|
-
}),
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const logoScale = {
|
|
103
|
-
transform: [
|
|
104
|
-
{
|
|
105
|
-
scale: loadingProgress.interpolate({
|
|
106
|
-
inputRange: [0, 10, 100],
|
|
107
|
-
outputRange: [1, 0.8, 10],
|
|
108
|
-
}),
|
|
109
|
-
},
|
|
110
|
-
],
|
|
111
|
-
}
|
|
71
|
+
const logoScale = {
|
|
72
|
+
transform: [
|
|
73
|
+
{
|
|
74
|
+
scale: loadingProgress.interpolate({
|
|
75
|
+
inputRange: [0, 10, 100],
|
|
76
|
+
outputRange: [1, 0.8, 10],
|
|
77
|
+
}),
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
}
|
|
112
81
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
82
|
+
const logoOpacity = {
|
|
83
|
+
opacity: loadingProgress.interpolate({
|
|
84
|
+
inputRange: [0, 20, 100],
|
|
85
|
+
outputRange: [1, 0, 0],
|
|
86
|
+
extrapolate: "clamp",
|
|
87
|
+
}),
|
|
88
|
+
}
|
|
120
89
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return (
|
|
133
|
-
<View style={[styles.container]} testID={testID} nativeID={testID}>
|
|
134
|
-
{!animationDone && <View style={StyleSheet.absoluteFill} testID={testID+"_Animation"}/>}
|
|
135
|
-
<View style={styles.containerGlue}>
|
|
136
|
-
{!animationDone && (
|
|
137
|
-
<Animated.View
|
|
138
|
-
style={_staticBackground(logoOpacity, backgroundColor)}
|
|
139
|
-
testID={testID+"_AnimationDone"}
|
|
140
|
-
/>
|
|
141
|
-
)}
|
|
142
|
-
{(animationDone || isNative) && <Component style={[!disableAppScale && appScale, opacityClearToVisible, styles.flex]}>
|
|
143
|
-
{this.renderChildren()}
|
|
144
|
-
</Component>}
|
|
145
|
-
{!animationDone && (
|
|
146
|
-
<Animated.Image
|
|
147
|
-
testID={testID+"AnimateImage"}
|
|
148
|
-
resizeMode={imageBackgroundResizeMode || "cover"}
|
|
149
|
-
source={imageBackgroundSource}
|
|
150
|
-
style={[disableImageBackgroundAnimation && _staticBackground(
|
|
151
|
-
logoOpacity,
|
|
152
|
-
backgroundColor
|
|
153
|
-
), disableImageBackgroundAnimation && _dynamicImageBackground(
|
|
154
|
-
imageScale,
|
|
155
|
-
logoOpacity,
|
|
156
|
-
backgroundColor
|
|
157
|
-
)]}
|
|
158
|
-
/>
|
|
159
|
-
)}
|
|
160
|
-
{!animationDone && (
|
|
161
|
-
<View testID={testID+"_LogoContainer"} style={[StyleSheet.absoluteFill, styles.logoStyle]}>
|
|
162
|
-
{(
|
|
163
|
-
<Animated.View
|
|
164
|
-
testID={testID+"_Logo"}
|
|
165
|
-
style={_dynamicCustomComponentStyle(
|
|
166
|
-
logoScale,
|
|
167
|
-
logoOpacity,
|
|
168
|
-
logoWidth,
|
|
169
|
-
logoHeight
|
|
170
|
-
)}>
|
|
171
|
-
{<LogoProgress/>}
|
|
172
|
-
</Animated.View>
|
|
173
|
-
)}
|
|
174
|
-
</View>
|
|
175
|
-
)}
|
|
176
|
-
</View>
|
|
177
|
-
</View>
|
|
178
|
-
)
|
|
90
|
+
const appScale = {
|
|
91
|
+
transform: [
|
|
92
|
+
{
|
|
93
|
+
scale: loadingProgress.interpolate({
|
|
94
|
+
inputRange: [0, 7, 100],
|
|
95
|
+
outputRange: [1.1, 1.05, 1],
|
|
96
|
+
}),
|
|
97
|
+
},
|
|
98
|
+
],
|
|
179
99
|
}
|
|
100
|
+
const child = (animationDone && isLoaded)? React.isValidElement(children) && children : null;
|
|
101
|
+
return (
|
|
102
|
+
<View style={[styles.container]} testID={testID} nativeID={testID}>
|
|
103
|
+
{!animationDone && <View style={StyleSheet.absoluteFill} testID={testID+"_Animation"}/>}
|
|
104
|
+
<View style={styles.containerGlue}>
|
|
105
|
+
{!animationDone && (
|
|
106
|
+
<Animated.View
|
|
107
|
+
style={_staticBackground(logoOpacity, backgroundColor)}
|
|
108
|
+
testID={testID+"_AnimationDone"}
|
|
109
|
+
/>
|
|
110
|
+
)}
|
|
111
|
+
{(animationDone || isNative) && <Component style={[!disableAppScale && appScale, opacityClearToVisible, styles.flex]}>
|
|
112
|
+
{child}
|
|
113
|
+
</Component>}
|
|
114
|
+
{!animationDone && (
|
|
115
|
+
<Animated.Image
|
|
116
|
+
testID={testID+"AnimateImage"}
|
|
117
|
+
resizeMode={imageBackgroundResizeMode || "cover"}
|
|
118
|
+
source={imageBackgroundSource}
|
|
119
|
+
style={[disableImageBackgroundAnimation && _staticBackground(
|
|
120
|
+
logoOpacity,
|
|
121
|
+
backgroundColor
|
|
122
|
+
), disableImageBackgroundAnimation && _dynamicImageBackground(
|
|
123
|
+
imageScale,
|
|
124
|
+
logoOpacity,
|
|
125
|
+
backgroundColor
|
|
126
|
+
)]}
|
|
127
|
+
/>
|
|
128
|
+
)}
|
|
129
|
+
{!animationDone && (
|
|
130
|
+
<View testID={testID+"_LogoContainer"} style={[StyleSheet.absoluteFill, styles.logoStyle]}>
|
|
131
|
+
{(
|
|
132
|
+
<Animated.View
|
|
133
|
+
testID={testID+"_Logo"}
|
|
134
|
+
style={_dynamicCustomComponentStyle(
|
|
135
|
+
logoScale,
|
|
136
|
+
logoOpacity,
|
|
137
|
+
logoWidth,
|
|
138
|
+
logoHeight
|
|
139
|
+
)}>
|
|
140
|
+
{<LogoProgress/>}
|
|
141
|
+
</Animated.View>
|
|
142
|
+
)}
|
|
143
|
+
</View>
|
|
144
|
+
)}
|
|
145
|
+
</View>
|
|
146
|
+
</View>
|
|
147
|
+
)
|
|
180
148
|
}
|
|
181
149
|
|
|
182
|
-
|
|
150
|
+
|
|
151
|
+
SplashScreenComponent.propTypes = {
|
|
183
152
|
preload: PropTypes.bool,
|
|
184
153
|
logoWidth: PropTypes.number,
|
|
185
154
|
children: PropTypes.element,
|
|
@@ -197,4 +166,5 @@ AnimatedSplash.propTypes = {
|
|
|
197
166
|
delay: PropTypes.number,
|
|
198
167
|
}
|
|
199
168
|
|
|
200
|
-
|
|
169
|
+
SplashScreenComponent.displayName = "SplashScreenComponent";
|
|
170
|
+
export default SplashScreenComponent;
|
package/src/index.js
CHANGED
|
@@ -31,6 +31,13 @@ import {PortalProvider,PortalHost } from '$ecomponents/Portal';
|
|
|
31
31
|
import ErrorBoundaryProvider from "$ecomponents/ErrorBoundary/Provider";
|
|
32
32
|
import notify, {notificationRef} from "$notify";
|
|
33
33
|
import DropdownAlert from '$ecomponents/Dialog/DropdownAlert';
|
|
34
|
+
import {AuthProvider} from '$cauth';
|
|
35
|
+
import { PreferencesContext } from './Preferences';
|
|
36
|
+
import ErrorBoundary from "$ecomponents/ErrorBoundary";
|
|
37
|
+
import {updateTheme,defaultTheme} from "$theme";
|
|
38
|
+
import StatusBar from "$ecomponents/StatusBar";
|
|
39
|
+
import {Provider as PaperProvider } from 'react-native-paper';
|
|
40
|
+
import FontIcon from "$ecomponents/Icon/Font";
|
|
34
41
|
|
|
35
42
|
let MAX_BACK_COUNT = 1;
|
|
36
43
|
let countBack = 0;
|
|
@@ -48,13 +55,13 @@ const NAVIGATION_PERSISTENCE_KEY = 'NAVIGATION_STATE';
|
|
|
48
55
|
* initialRouteName : la route initiale par défaut
|
|
49
56
|
* getStartedRouteName : la route par défaut de getStarted lorsque l'application est en mode getStarted, c'est à dire lorsque la fonction init renvoie une erreur (reject)
|
|
50
57
|
*/
|
|
51
|
-
function App({init:initApp,initialRouteName:appInitialRouteName,getStartedRouteName}) {
|
|
58
|
+
function App({init:initApp,initialRouteName:appInitialRouteName,render,preferences:appPreferences,getStartedRouteName}) {
|
|
52
59
|
AppStateService.init();
|
|
53
60
|
const [initialState, setInitialState] = React.useState(undefined);
|
|
54
61
|
const appReadyRef = React.useRef(true);
|
|
55
62
|
const [state,setState] = React.useState({
|
|
56
63
|
isLoading : true,
|
|
57
|
-
isInitialized:
|
|
64
|
+
isInitialized:false,
|
|
58
65
|
});
|
|
59
66
|
React.useEffect(() => {
|
|
60
67
|
const loadResources = ()=>{
|
|
@@ -220,35 +227,67 @@ function App({init:initApp,initialRouteName:appInitialRouteName,getStartedRouteN
|
|
|
220
227
|
}
|
|
221
228
|
},[isInitialized]);
|
|
222
229
|
const hasGetStarted = state.hasGetStarted !== false? true : false;
|
|
230
|
+
|
|
231
|
+
const [theme,setTheme] = React.useState(updateTheme(defaultTheme));
|
|
232
|
+
const updatePreferenceTheme = (customTheme,persist)=>{
|
|
233
|
+
setTheme(updateTheme(customTheme));
|
|
234
|
+
};
|
|
235
|
+
const forceRender = React.useForceRender();
|
|
236
|
+
const pref = typeof appPreferences =='function'? appPreferences({setTheme,forceRender,updateTheme:updatePreferenceTheme}) : appPreferences;
|
|
237
|
+
const preferences = React.useMemo(()=>({
|
|
238
|
+
updateTheme:updatePreferenceTheme,
|
|
239
|
+
theme,
|
|
240
|
+
...defaultObj(pref),
|
|
241
|
+
}),[theme,pref]);
|
|
242
|
+
const isLoaded = !isLoading;
|
|
243
|
+
const child = isLoaded ? <NavigationContainer
|
|
244
|
+
ref={navigationRef}
|
|
245
|
+
initialState={initialState}
|
|
246
|
+
onStateChange={(state) =>{
|
|
247
|
+
setSession(NAVIGATION_PERSISTENCE_KEY,decycle(state),false);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
>
|
|
251
|
+
<PortalProvider>
|
|
252
|
+
<Portal.Host>
|
|
253
|
+
<PreloaderProvider/>
|
|
254
|
+
<DialogProvider responsive/>
|
|
255
|
+
<AlertProvider SimpleSelect={SimpleSelect}/>
|
|
256
|
+
<FormDataDialogProvider/>
|
|
257
|
+
<BottomSheetProvider/>
|
|
258
|
+
<DropdownAlert ref={notificationRef}/>
|
|
259
|
+
<ErrorBoundaryProvider/>
|
|
260
|
+
<Navigation
|
|
261
|
+
initialRouteName = {defaultStr(hasGetStarted ? appInitialRouteName : getStartedRouteName,"Home")}
|
|
262
|
+
state = {state}
|
|
263
|
+
hasGetStarted = {hasGetStarted}
|
|
264
|
+
isInitialized = {!isLoading}
|
|
265
|
+
onGetStart = {(e)=>{
|
|
266
|
+
setState({...state,hasGetStarted:true})
|
|
267
|
+
}}
|
|
268
|
+
/>
|
|
269
|
+
</Portal.Host>
|
|
270
|
+
</PortalProvider>
|
|
271
|
+
</NavigationContainer> : null;
|
|
272
|
+
const content = isLoaded ? typeof render == 'function'? render({children:child,appConfig,config:appConfig}) : child : null;
|
|
223
273
|
return (<SplashScreen isLoaded={!isLoading}>
|
|
224
|
-
<
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
<Navigation
|
|
242
|
-
initialRouteName = {defaultStr(hasGetStarted ? appInitialRouteName : getStartedRouteName,"Home")}
|
|
243
|
-
state = {state}
|
|
244
|
-
hasGetStarted = {hasGetStarted}
|
|
245
|
-
onGetStart = {(e)=>{
|
|
246
|
-
setState({...state,hasGetStarted:true})
|
|
247
|
-
}}
|
|
248
|
-
/>
|
|
249
|
-
</Portal.Host>
|
|
250
|
-
</PortalProvider>
|
|
251
|
-
</NavigationContainer>
|
|
274
|
+
<AuthProvider>
|
|
275
|
+
<PaperProvider
|
|
276
|
+
theme={theme}
|
|
277
|
+
settings={{
|
|
278
|
+
icon: (props) => {
|
|
279
|
+
return <FontIcon {...props}/>
|
|
280
|
+
},
|
|
281
|
+
}}
|
|
282
|
+
>
|
|
283
|
+
<ErrorBoundary>
|
|
284
|
+
<StatusBar/>
|
|
285
|
+
<PreferencesContext.Provider value={preferences}>
|
|
286
|
+
{React.isValidElement(content) && content || child}
|
|
287
|
+
</PreferencesContext.Provider>
|
|
288
|
+
</ErrorBoundary>
|
|
289
|
+
</PaperProvider>
|
|
290
|
+
</AuthProvider>
|
|
252
291
|
</SplashScreen>);
|
|
253
292
|
}
|
|
254
293
|
|
|
@@ -54,7 +54,7 @@ export default function DatabaseStatisticScreen ({withScreen,fetchDataProps,tabl
|
|
|
54
54
|
if(!content.length) {
|
|
55
55
|
return null;
|
|
56
56
|
}
|
|
57
|
-
content = <Component {...containerProps} style={[containerProps.style,theme.styles.mr1,theme.styles.ml1]}>
|
|
57
|
+
content = <Component {...containerProps} style={[containerProps.style,theme.styles.mr1,theme.styles.pv1,theme.styles.ml1]}>
|
|
58
58
|
{content}
|
|
59
59
|
</Component>;
|
|
60
60
|
return withScreen !== false ? <Screen containerProps={{style:[{flexGrow:0,flex:0}]}} withScrollView title={defaultVal(customTitle,title)} {...props}>{content}</Screen> : content;
|
|
@@ -33,30 +33,16 @@ export default class FormDataListScreen extends FormData{
|
|
|
33
33
|
if(typeof show =='function'){
|
|
34
34
|
show({...this.props,index:undefined,data:{}});
|
|
35
35
|
}
|
|
36
|
-
}
|
|
37
|
-
doSave(args){
|
|
38
|
-
|
|
39
36
|
}
|
|
40
37
|
doSave2New(args){
|
|
41
|
-
if(!this.__canSaveListData) return;
|
|
42
38
|
const {show} = this.props;
|
|
43
39
|
if(typeof show =='function'){
|
|
44
40
|
show({...args,index:undefined,data:{}});
|
|
45
41
|
}
|
|
46
42
|
}
|
|
47
43
|
doSave2Close(args){
|
|
48
|
-
if(!this.__canSaveListData) return;
|
|
49
44
|
return this.close();
|
|
50
45
|
}
|
|
51
|
-
onSave(args){
|
|
52
|
-
let {formDataProps} = this.props;
|
|
53
|
-
this.__canSaveListData = true;
|
|
54
|
-
formDataProps = defaultObj(formDataProps);
|
|
55
|
-
if(typeof formDataProps.onSave =='function' && formDataProps.onSave(args) === false){
|
|
56
|
-
this.__canSaveListData = false;
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
46
|
_render(content){
|
|
61
47
|
let {isAllowed} = this.props;
|
|
62
48
|
if(typeof isAllowed ==='function'){
|
|
@@ -755,11 +755,14 @@ export default class TableDataScreenComponent extends FormDataScreen{
|
|
|
755
755
|
getMakePhoneCallProps (){
|
|
756
756
|
const table = this.table;
|
|
757
757
|
const makePhoneCallProps = defaultVal(this.makePhoneCallProps,table.makePhoneCallProps);
|
|
758
|
-
|
|
758
|
+
const rowData = this.getCurrentData();
|
|
759
|
+
const mP = typeof makePhoneCallProps === 'function' ? makePhoneCallProps({rowData,data:rowData,isTableData:true,props:this.props,context:this,table,tableName:this.table}) : makePhoneCallProps;
|
|
760
|
+
return mP !== false ? defaultObj(mP) : null;
|
|
759
761
|
}
|
|
760
762
|
makePhoneCall(data){
|
|
761
|
-
|
|
762
|
-
|
|
763
|
+
const mP = this.getMakePhoneCallProps();
|
|
764
|
+
if(!this.canMakePhoneCall() || !canMakePhoneCall() || !isObj(mP)) return false;
|
|
765
|
+
makePCall(defaultObj(data || this.getCurrentData()),mP);
|
|
763
766
|
return false;
|
|
764
767
|
}
|
|
765
768
|
|
|
@@ -103,8 +103,11 @@ export function renderActions({context,isUpdate,newElementLabel,makePhoneCallPr
|
|
|
103
103
|
rest = defaultObj(rest);
|
|
104
104
|
newElementLabel = defaultStr(newElementLabel,"Nouveau");
|
|
105
105
|
let permsObj = checkPermsActions.call(self,{...defaultObj(perms),isUpdate})
|
|
106
|
-
makePhoneCallProps =
|
|
106
|
+
makePhoneCallProps = typeof makePhoneCallProps ==='function'? makePhoneCallProps({data,rowData:data,context:{},isTableDataActions:true,table,tableName:table}): makePhoneCallProps;
|
|
107
107
|
self.permsObj = permsObj;
|
|
108
|
+
if(makePhoneCallProps !== false){
|
|
109
|
+
makePhoneCallProps = defaultObj(makePhoneCallProps);
|
|
110
|
+
}
|
|
108
111
|
let save = (!readOnly && !permsObj.canSave || (saveAction === false))? null: {
|
|
109
112
|
text :hasManyData? 'Modifier': textSave,
|
|
110
113
|
title :hasManyData? 'Modifier': textSave,
|
|
@@ -197,7 +200,7 @@ export function renderActions({context,isUpdate,newElementLabel,makePhoneCallPr
|
|
|
197
200
|
flat : true,
|
|
198
201
|
onPress : createCallback({context:self,action:'new',callback:onPressToCreateNew})
|
|
199
202
|
} : null,
|
|
200
|
-
makePhoneCall : (canMakePhoneCall && isUpdate)?{
|
|
203
|
+
makePhoneCall : (canMakePhoneCall && isUpdate && isObj(makePhoneCallProps))?{
|
|
201
204
|
text : defaultStr(makePhoneCallProps.text,makePhoneCallProps.label,'Appeler'),
|
|
202
205
|
isAction : true,
|
|
203
206
|
icon : defaultStr(makePhoneCallProps.icon,'phone'),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import showConfirm from "$components/Dialog/confirm";
|
|
2
|
-
import notify from "$
|
|
2
|
+
import notify from "$notify";
|
|
3
3
|
import {defaultArray,arrayValueExists,defaultStr,uniqid} from "$cutils";
|
|
4
|
-
import userDbName from "$database/
|
|
4
|
+
import userDbName from "$database/tables/users/dbName";
|
|
5
5
|
import Auth from "$auth";
|
|
6
6
|
import getData from "$database/getData";
|
|
7
7
|
import getDB from "$database/getDB";
|