@fto-consult/expo-ui 5.7.10 → 5.7.12
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/package.json +1 -1
- package/src/App.js +7 -28
- package/src/components/Datagrid/Common/Common.js +4 -3
- package/src/components/Drawer/index.js +5 -2
- package/src/components/Dropdown/index.js +1 -1
- package/src/components/Form/Fields/SelectTableData/Component.js +5 -3
- package/src/components/Form/FormData/FormData.js +10 -5
- package/src/components/Form/FormData/index.js +3 -1
- package/src/components/Form/FormData/utils.js +3 -2
- package/src/components/Form/utils/index.js +3 -1
- package/src/components/Form/utils/isDocEditing.js +44 -0
- package/src/components/SplashScreen/index.js +9 -3
- package/src/index.js +30 -9
- package/src/layouts/Screen/ScreenWithOrWithoutAuthContainer.js +42 -39
- package/src/layouts/Screen/TableData.js +5 -37
- package/src/layouts/Screen/utils.js +2 -1
package/package.json
CHANGED
package/src/App.js
CHANGED
|
@@ -5,23 +5,13 @@ import {defaultObj} from "$cutils";
|
|
|
5
5
|
import {updateTheme,defaultTheme} from "$theme";
|
|
6
6
|
import {Provider as PaperProvider } from 'react-native-paper';
|
|
7
7
|
import Index from './index';
|
|
8
|
-
import
|
|
9
|
-
import {PreloaderProvider} from "$epreloader";
|
|
10
|
-
import DropdownAlert from '$ecomponents/Dialog/DropdownAlert';
|
|
11
|
-
import notify, {notificationRef} from "$notify";
|
|
12
|
-
import BottomSheetProvider from "$ecomponents/BottomSheet/Provider";
|
|
13
|
-
import DialogProvider from "$ecomponents/Dialog/Provider";
|
|
14
|
-
import { DialogProvider as FormDataDialogProvider } from '$eform/FormData';
|
|
8
|
+
import notify from "$notify";
|
|
15
9
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
16
10
|
import { PreferencesContext } from './Preferences';
|
|
17
11
|
import {AuthProvider} from '$cauth';
|
|
18
|
-
import {PortalProvider } from '$ecomponents/Portal';
|
|
19
12
|
import ErrorBoundary from "$ecomponents/ErrorBoundary";
|
|
20
|
-
import ErrorBoundaryProvider from "$ecomponents/ErrorBoundary/Provider";
|
|
21
13
|
import {GestureHandlerRootView} from "react-native-gesture-handler";
|
|
22
14
|
import StatusBar from "$ecomponents/StatusBar";
|
|
23
|
-
import SimpleSelect from '$ecomponents/SimpleSelect';
|
|
24
|
-
import {Provider as AlertProvider} from '$ecomponents/Dialog/confirm/Alert';
|
|
25
15
|
import APP from "$app";
|
|
26
16
|
import FontIcon from "$ecomponents/Icon/Font"
|
|
27
17
|
import {isMobileNative} from "$cplatform";
|
|
@@ -178,23 +168,12 @@ export default function getIndex({onMount,onUnmount,swrConfig,onRender,preferenc
|
|
|
178
168
|
>
|
|
179
169
|
<SafeAreaProvider>
|
|
180
170
|
<AuthProvider>
|
|
181
|
-
<
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
<PreloaderProvider/>
|
|
188
|
-
<DialogProvider responsive/>
|
|
189
|
-
<AlertProvider SimpleSelect={SimpleSelect}/>
|
|
190
|
-
<FormDataDialogProvider/>
|
|
191
|
-
{<Index {...rest} theme={theme}/>}
|
|
192
|
-
<ErrorBoundaryProvider/>
|
|
193
|
-
<BottomSheetProvider/>
|
|
194
|
-
</PreferencesContext.Provider>
|
|
195
|
-
</ErrorBoundary>
|
|
196
|
-
</Portal.Host>
|
|
197
|
-
</PortalProvider>
|
|
171
|
+
<ErrorBoundary>
|
|
172
|
+
<StatusBar/>
|
|
173
|
+
<PreferencesContext.Provider value={preferences}>
|
|
174
|
+
{<Index {...rest} theme={theme}/>}
|
|
175
|
+
</PreferencesContext.Provider>
|
|
176
|
+
</ErrorBoundary>
|
|
198
177
|
</AuthProvider>
|
|
199
178
|
</SafeAreaProvider>
|
|
200
179
|
</PaperProvider>
|
|
@@ -2459,6 +2459,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
2459
2459
|
render,
|
|
2460
2460
|
readOnly,
|
|
2461
2461
|
disabled,
|
|
2462
|
+
editable,
|
|
2462
2463
|
visible,
|
|
2463
2464
|
defaultValue,
|
|
2464
2465
|
id,
|
|
@@ -2469,7 +2470,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
2469
2470
|
} = header;
|
|
2470
2471
|
restCol = Object.clone(defaultObj(restCol));
|
|
2471
2472
|
let colFilter = defaultVal(restCol.filter,true);
|
|
2472
|
-
field = header.field = defaultStr(header.field,field,headerIndex);
|
|
2473
|
+
field = header.field = restCol.field = defaultStr(header.field,field,headerIndex);
|
|
2473
2474
|
delete restCol.filter;
|
|
2474
2475
|
|
|
2475
2476
|
const type = defaultStr(header.jsType,header.type,"text").toLowerCase();
|
|
@@ -2617,14 +2618,14 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
2617
2618
|
this.sectionListColumnsSize.current++;
|
|
2618
2619
|
}
|
|
2619
2620
|
const mItem = {
|
|
2620
|
-
...
|
|
2621
|
+
...restCol,
|
|
2621
2622
|
field,
|
|
2622
2623
|
type,
|
|
2623
2624
|
onPress : ()=>{
|
|
2624
2625
|
this.toggleColumnInSectionList(field);
|
|
2625
2626
|
return false;
|
|
2626
2627
|
},
|
|
2627
|
-
title
|
|
2628
|
+
title,
|
|
2628
2629
|
icon : isInSectionListHeader?CHECKED_ICON_NAME : null,
|
|
2629
2630
|
};
|
|
2630
2631
|
if(this.isSectionListColumnConfigurable(mItem)){
|
|
@@ -35,8 +35,10 @@ const DrawerComponent = React.forwardRef((props,ref)=>{
|
|
|
35
35
|
permanentToggleIcon,minimizedToggleIcon,temporaryToggleIcon,withMinimizedIcon,
|
|
36
36
|
isItemActive,onPageResize,navigationViewRef,
|
|
37
37
|
children,
|
|
38
|
+
testID,
|
|
38
39
|
drawerType} = props;
|
|
39
40
|
sessionName = defaultStr(sessionName);
|
|
41
|
+
testID = defaultStr(testID,"RN_DrawerComponent")
|
|
40
42
|
const sessionRef = React.useRef({});
|
|
41
43
|
const session = React.useMemo(()=>{
|
|
42
44
|
if(sessionName){
|
|
@@ -251,8 +253,9 @@ const DrawerComponent = React.forwardRef((props,ref)=>{
|
|
|
251
253
|
}
|
|
252
254
|
return false;
|
|
253
255
|
},getState:getDrawerState,getDrawerRef}}>
|
|
254
|
-
<View style={styles.container}>
|
|
256
|
+
<View style={styles.container} testID={`${testID}_Container`}>
|
|
255
257
|
<DrawerLayout
|
|
258
|
+
testID = {`${testID}_DrawerLayout`}
|
|
256
259
|
{...restP}
|
|
257
260
|
permanent = {isPermanent}
|
|
258
261
|
onDrawerSlide={onDrawerSlide}
|
|
@@ -339,7 +342,7 @@ const DrawerComponent = React.forwardRef((props,ref)=>{
|
|
|
339
342
|
{paddingBottom:30},
|
|
340
343
|
contentContainerStyle
|
|
341
344
|
]
|
|
342
|
-
|
|
345
|
+
}>
|
|
343
346
|
{children}
|
|
344
347
|
</DrawerLayout>
|
|
345
348
|
</View>
|
|
@@ -991,7 +991,7 @@ class DropdownComponent extends AppComponent {
|
|
|
991
991
|
{...restProps}
|
|
992
992
|
testID = {testID+"_ModalComponent"}
|
|
993
993
|
withScrollView = {false}
|
|
994
|
-
visible={visible
|
|
994
|
+
visible={visible}
|
|
995
995
|
onDismiss={this.hide.bind(this)}
|
|
996
996
|
contentStyle = {[{paddingVertical:0},restProps.contentStyle]}
|
|
997
997
|
anchor={anchor}
|
|
@@ -21,6 +21,9 @@ import appConfig from "$appConfig";
|
|
|
21
21
|
*/
|
|
22
22
|
const TableDataSelectField = React.forwardRef(({foreignKeyColumn,bindUpsert2RemoveEvents,onAdd,showAdd:customShowAdd,canShowAdd,foreignKeyTable,fetchItemsPath,foreignKeyLabel,foreignKeyLabelIndex,dropdownActions,fields,fetchItems:customFetchItem,convertFiltersToSQL,mutateFetchedItems,getForeignKeyTable,onFetchItems,isFilter,isUpdate,isDocEditing,items,onAddProps,fetchOptions,...props},ref)=>{
|
|
23
23
|
props.data = defaultObj(props.data);
|
|
24
|
+
if(!foreignKeyColumn && isNonNullString(props.field)){
|
|
25
|
+
foreignKeyColumn = props.field;
|
|
26
|
+
}
|
|
24
27
|
if(isNonNullString(foreignKeyColumn)){
|
|
25
28
|
foreignKeyColumn = foreignKeyColumn.trim();
|
|
26
29
|
}
|
|
@@ -34,7 +37,7 @@ const TableDataSelectField = React.forwardRef(({foreignKeyColumn,bindUpsert2Remo
|
|
|
34
37
|
fetchItemsPath = defaultStr(fetchItemsPath).trim();
|
|
35
38
|
|
|
36
39
|
if(!fetchItemsPath && (!isObj(fKeyTable) || !(defaultStr(fKeyTable.tableName,fKeyTable.table)))){
|
|
37
|
-
console.error("type de données invalide pour la foreignKeyTable ",fKeyTable," composant SelectTableData",foreignKeyColumn,foreignKeyTable,props);
|
|
40
|
+
console.error("type de données invalide pour la foreignKeyTable ",foreignKeyTable," label : ",foreignKeyLabel,fKeyTable," composant SelectTableData",foreignKeyColumn,foreignKeyTable,props);
|
|
38
41
|
return null;
|
|
39
42
|
}
|
|
40
43
|
fKeyTable = defaultObj(fKeyTable);
|
|
@@ -280,13 +283,12 @@ const TableDataSelectField = React.forwardRef(({foreignKeyColumn,bindUpsert2Remo
|
|
|
280
283
|
}
|
|
281
284
|
return rItem(p);
|
|
282
285
|
}}
|
|
283
|
-
hideOnAdd
|
|
284
286
|
onAdd = {(args)=>{
|
|
285
287
|
onAddProps = defaultObj(isFunction(onAddProps)? onAddProps.call(context,{context,foreignKeyTable,dbName,props}) : onAddProps);
|
|
286
288
|
if(typeof onAdd =='function'){
|
|
287
289
|
return onAdd({...args,...onAddProps});
|
|
288
290
|
}
|
|
289
|
-
return navigateToTableData({...onAddProps,foreignKeyTable,table:foreignKeyTable,foreignKeyColumn,tableName : foreignKeyTable
|
|
291
|
+
return navigateToTableData(foreignKeyTable,{routeParams:{...onAddProps,foreignKeyTable,table:foreignKeyTable,foreignKeyColumn,tableName : foreignKeyTable}});
|
|
290
292
|
}}
|
|
291
293
|
/>
|
|
292
294
|
});
|
|
@@ -8,10 +8,10 @@ import Form from "../Form";
|
|
|
8
8
|
import theme,{flattenStyle} from "$theme";
|
|
9
9
|
import PropTypes from "prop-types";
|
|
10
10
|
import {renderActions} from "$ecomponents/Dialog/utils";
|
|
11
|
-
//import {isDocUpdate} from "$database/utils";
|
|
12
11
|
import {handleBeforeSaveCallback} from "./utils";
|
|
12
|
+
import isDbDocEditing,{checkPrimaryKey} from "../utils/isDocEditing";
|
|
13
13
|
import getComponentFromType from "./componentsTypes";
|
|
14
|
-
import
|
|
14
|
+
import keyboardShortcuts from "../utils/keyboardShortcuts";
|
|
15
15
|
import appConfig from "$capp/config";
|
|
16
16
|
|
|
17
17
|
export default class FormDataComponent extends AppComponent{
|
|
@@ -84,11 +84,10 @@ export default class FormDataComponent extends AppComponent{
|
|
|
84
84
|
return "Impossible d'enregister les données à cause l'erreur suivante : "+errorText;
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
-
const isDocEditing = this.isDocEditing(args.data);
|
|
88
87
|
const isUpdated = this.isDocEditing(args.data);
|
|
89
88
|
const currentIndex = this.getCurrentIndex();
|
|
90
89
|
const action = typeof this.clickedAction =='string' ? this.clickedAction.toLowerCase() : '';
|
|
91
|
-
const savedArgs = {...args,
|
|
90
|
+
const savedArgs = {...args,isUpdated,context:this,action,currentIndex,index:currentIndex,isUpdate:isUpdated,isUpdated,props:this.props,context:this};
|
|
92
91
|
if(beforeSaveArgumentsMutator){
|
|
93
92
|
savedArgs = beforeSaveArgumentsMutator(savedArgs);
|
|
94
93
|
if(!isObj(savedArgs)){
|
|
@@ -149,7 +148,9 @@ export default class FormDataComponent extends AppComponent{
|
|
|
149
148
|
} else if(typeof this.props.isDocUpdate =='function'){
|
|
150
149
|
return this.props.isDocUpdate(data,{context:this}) ? true : false;
|
|
151
150
|
}
|
|
152
|
-
return
|
|
151
|
+
return isObj(this.formDataPrimaryKeyFields) && Object.size(this.formDataPrimaryKeyFields,true) ? isDbDocEditing(data,this.formDataPrimaryKeyFields,({index:field,data})=>{
|
|
152
|
+
return checkPrimaryKey(data,field);
|
|
153
|
+
}) : false;
|
|
153
154
|
}
|
|
154
155
|
canBindResizeEvents(){
|
|
155
156
|
return false;
|
|
@@ -180,6 +181,7 @@ export default class FormDataComponent extends AppComponent{
|
|
|
180
181
|
formProps = defaultObj(formProps);
|
|
181
182
|
const fieldProps = defaultObj(formProps.fieldProps,this.props.fieldProps);
|
|
182
183
|
formProps.style = flattenStyle(formProps.style);
|
|
184
|
+
this.formDataPrimaryKeyFields = {};
|
|
183
185
|
const content = [];
|
|
184
186
|
const fields = defaultObj(formProps.fields,this.props.fields);
|
|
185
187
|
const data = isObj(formProps.data) ? formProps.data : typeof this.props.data =='object' && this.props.data ? this.props.data : {};
|
|
@@ -198,6 +200,9 @@ export default class FormDataComponent extends AppComponent{
|
|
|
198
200
|
rest = Object.assign({},rest);
|
|
199
201
|
delete rest.import;
|
|
200
202
|
delete rest.export;
|
|
203
|
+
if(primaryKey === true && name && !field.filter){
|
|
204
|
+
this.formDataPrimaryKeyFields[name] = field;
|
|
205
|
+
}
|
|
201
206
|
if(form === false || ignore || (isNonNullString(perm) && !Auth.isAllowedFromStr(perm))){
|
|
202
207
|
return null;
|
|
203
208
|
}
|
|
@@ -2,7 +2,7 @@ import {isNonNullString,isObj,defaultObj,isPromise,isFunction,defaultStr,isObjOr
|
|
|
2
2
|
import notify from "$notify";
|
|
3
3
|
import { getFormData } from "../utils/FormsManager";
|
|
4
4
|
import {isMobileBrowser,isMobileNative} from "$cplatform";
|
|
5
|
-
import
|
|
5
|
+
import KeyboardShorts from "../utils/keyboardShortcuts";
|
|
6
6
|
|
|
7
7
|
export const keyboardShortcuts = {};
|
|
8
8
|
Object.map(KeyboardShorts,(st,i)=>{
|
|
@@ -100,4 +100,5 @@ export const handleBeforeSaveCallback = (beforeSaveCallback,successCb,arg)=>{
|
|
|
100
100
|
}
|
|
101
101
|
successCb(arg);
|
|
102
102
|
return bF;
|
|
103
|
-
}
|
|
103
|
+
}
|
|
104
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {isObj,defaultStr} from "$cutils";
|
|
2
|
+
export const checkPrimaryKey = (data,f)=>{
|
|
3
|
+
return !(!(f in data) || (data[f] == null) || (!data[f] && typeof data !=='number'));
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/*** vérifie si le document passé en paramètre est éditable
|
|
7
|
+
* @param {object} data la données à vérifier
|
|
8
|
+
* @param {object| array} les champs sur lesquels se baser pour vérifier si la donénes est une mise à jour
|
|
9
|
+
* @param {func} checkPrimaryKey la foncition permettant de vérifier s'il s'agit d'une clé primaire pour la données courante
|
|
10
|
+
*/
|
|
11
|
+
const isDocEditing = (data,fields,checkPrimaryKey)=>{
|
|
12
|
+
if(!isObj(data) || !isObjOrArray(fields)) return false;
|
|
13
|
+
let hasPrimaryFields = false;
|
|
14
|
+
let hasValidated = true;
|
|
15
|
+
for(let i in fields){
|
|
16
|
+
const field = fields[i];
|
|
17
|
+
if(typeof checkPrimaryKey =='function') {
|
|
18
|
+
hasPrimaryFields = true;
|
|
19
|
+
if(checkPrimaryKey({field,i,index:i,data}) === false){
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if(!isObj(field)) continue;
|
|
25
|
+
hasPrimaryFields = true;
|
|
26
|
+
const f = defaultStr(field.field,i);
|
|
27
|
+
if(field.primaryKey === true){
|
|
28
|
+
if(!checkPrimaryKey(data,f)){
|
|
29
|
+
if(hasPrimaryFields){
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
hasValidated = false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if(hasPrimaryFields){
|
|
37
|
+
return hasValidated;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default isDocEditing;
|
|
43
|
+
|
|
44
|
+
export const isDocUpdate = isDocEditing;
|
|
@@ -7,6 +7,7 @@ import View from "$ecomponents/View";
|
|
|
7
7
|
import {isNativeMobile} from "$cplatform";
|
|
8
8
|
import {defaultDecimal} from "$cutils";
|
|
9
9
|
import {LogoProgress} from "$ecomponents/Logo";
|
|
10
|
+
import {defaultStr} from "$cutils";
|
|
10
11
|
import styles, {
|
|
11
12
|
_solidBackground,
|
|
12
13
|
_staticBackground,
|
|
@@ -72,9 +73,11 @@ class AnimatedSplash extends React.Component {
|
|
|
72
73
|
backgroundColor,
|
|
73
74
|
imageBackgroundSource,
|
|
74
75
|
imageBackgroundResizeMode,
|
|
76
|
+
testID,
|
|
75
77
|
disableAppScale,
|
|
76
78
|
disableImageBackgroundAnimation,
|
|
77
79
|
} = this.props
|
|
80
|
+
testID = defaultStr(testID,"RN_SplashscreenComponent")
|
|
78
81
|
logoWidth = defaultDecimal(logoWidth,150);
|
|
79
82
|
logoHeight = defaultDecimal(logoHeight,250);
|
|
80
83
|
const opacityClearToVisible = {
|
|
@@ -127,12 +130,13 @@ class AnimatedSplash extends React.Component {
|
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
return (
|
|
130
|
-
<View style={[styles.container]}>
|
|
131
|
-
{!animationDone && <View style={StyleSheet.absoluteFill} />}
|
|
133
|
+
<View style={[styles.container]} testID={testID} nativeID={testID}>
|
|
134
|
+
{!animationDone && <View style={StyleSheet.absoluteFill} testID={testID+"_Animation"}/>}
|
|
132
135
|
<View style={styles.containerGlue}>
|
|
133
136
|
{!animationDone && (
|
|
134
137
|
<Animated.View
|
|
135
138
|
style={_staticBackground(logoOpacity, backgroundColor)}
|
|
139
|
+
testID={testID+"_AnimationDone"}
|
|
136
140
|
/>
|
|
137
141
|
)}
|
|
138
142
|
{(animationDone || isNative) && <Component style={[!disableAppScale && appScale, opacityClearToVisible, styles.flex]}>
|
|
@@ -140,6 +144,7 @@ class AnimatedSplash extends React.Component {
|
|
|
140
144
|
</Component>}
|
|
141
145
|
{!animationDone && (
|
|
142
146
|
<Animated.Image
|
|
147
|
+
testID={testID+"AnimateImage"}
|
|
143
148
|
resizeMode={imageBackgroundResizeMode || "cover"}
|
|
144
149
|
source={imageBackgroundSource}
|
|
145
150
|
style={[disableImageBackgroundAnimation && _staticBackground(
|
|
@@ -153,9 +158,10 @@ class AnimatedSplash extends React.Component {
|
|
|
153
158
|
/>
|
|
154
159
|
)}
|
|
155
160
|
{!animationDone && (
|
|
156
|
-
<View style={[StyleSheet.absoluteFill, styles.logoStyle]}>
|
|
161
|
+
<View testID={testID+"_LogoContainer"} style={[StyleSheet.absoluteFill, styles.logoStyle]}>
|
|
157
162
|
{(
|
|
158
163
|
<Animated.View
|
|
164
|
+
testID={testID+"_Logo"}
|
|
159
165
|
style={_dynamicCustomComponentStyle(
|
|
160
166
|
logoScale,
|
|
161
167
|
logoOpacity,
|
package/src/index.js
CHANGED
|
@@ -13,7 +13,6 @@ import {set as setSession,get as getSession} from "$session";
|
|
|
13
13
|
import { showConfirm } from "$ecomponents/Dialog";
|
|
14
14
|
import {close as closePreloader, isVisible as isPreloaderVisible} from "$epreloader";
|
|
15
15
|
import SplashScreen from "$ecomponents/SplashScreen";
|
|
16
|
-
import {notify} from "$ecomponents/Dialog";
|
|
17
16
|
import {decycle} from "$cutils/json";
|
|
18
17
|
import init from "$capp/init";
|
|
19
18
|
import { setIsInitialized} from "$capp/utils";
|
|
@@ -21,6 +20,17 @@ import {isObj,isNonNullString,isPromise,defaultObj,defaultStr} from "$cutils";
|
|
|
21
20
|
import {loadFonts} from "$ecomponents/Icon/Font";
|
|
22
21
|
import appConfig from "$capp/config";
|
|
23
22
|
import Preloader from "$preloader";
|
|
23
|
+
import {PreloaderProvider} from "$epreloader";
|
|
24
|
+
import BottomSheetProvider from "$ecomponents/BottomSheet/Provider";
|
|
25
|
+
import DialogProvider from "$ecomponents/Dialog/Provider";
|
|
26
|
+
import SimpleSelect from '$ecomponents/SimpleSelect';
|
|
27
|
+
import {Provider as AlertProvider} from '$ecomponents/Dialog/confirm/Alert';
|
|
28
|
+
import { DialogProvider as FormDataDialogProvider } from '$eform/FormData';
|
|
29
|
+
import {Portal } from 'react-native-paper';
|
|
30
|
+
import {PortalProvider,PortalHost } from '$ecomponents/Portal';
|
|
31
|
+
import ErrorBoundaryProvider from "$ecomponents/ErrorBoundary/Provider";
|
|
32
|
+
import notify, {notificationRef} from "$notify";
|
|
33
|
+
import DropdownAlert from '$ecomponents/Dialog/DropdownAlert';
|
|
24
34
|
|
|
25
35
|
let MAX_BACK_COUNT = 1;
|
|
26
36
|
let countBack = 0;
|
|
@@ -219,14 +229,25 @@ function App({init:initApp,initialRouteName:appInitialRouteName,getStartedRouteN
|
|
|
219
229
|
}
|
|
220
230
|
}
|
|
221
231
|
>
|
|
222
|
-
<
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
<PortalProvider>
|
|
233
|
+
<Portal.Host>
|
|
234
|
+
<PreloaderProvider/>
|
|
235
|
+
<DialogProvider responsive/>
|
|
236
|
+
<AlertProvider SimpleSelect={SimpleSelect}/>
|
|
237
|
+
<FormDataDialogProvider/>
|
|
238
|
+
<BottomSheetProvider/>
|
|
239
|
+
<DropdownAlert ref={notificationRef}/>
|
|
240
|
+
<ErrorBoundaryProvider/>
|
|
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>
|
|
230
251
|
</NavigationContainer>
|
|
231
252
|
</SplashScreen>);
|
|
232
253
|
}
|
|
@@ -2,14 +2,14 @@ import React from '$react';
|
|
|
2
2
|
import {StyleSheet} from 'react-native';
|
|
3
3
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
4
4
|
import PropTypes from "prop-types";
|
|
5
|
-
import {defaultObj,defaultStr,defaultNumber,defaultBool} from "$cutils";
|
|
5
|
+
import {defaultObj,defaultStr,defaultNumber,defaultBool,uniqid} from "$cutils";
|
|
6
6
|
import View from "$ecomponents/View";
|
|
7
7
|
import { useNavigation} from '$cnavigation';
|
|
8
8
|
import Fab from "$layouts/Fab";
|
|
9
9
|
import APP from "$capp";
|
|
10
10
|
import AppBar,{createAppBarRef} from "$elayouts/AppBar";
|
|
11
|
-
import ErrorBoundary from "$ecomponents/ErrorBoundary";
|
|
12
11
|
import Portal from "$ecomponents/Portal";
|
|
12
|
+
import { FullWindowOverlay } from 'react-native-screens';
|
|
13
13
|
import theme,{StyleProp} from "$theme";
|
|
14
14
|
import StatusBar from "$ecomponents/StatusBar";
|
|
15
15
|
import ScrollView from "$ecomponents/ScrollView";
|
|
@@ -108,57 +108,60 @@ export default function MainScreenScreenWithOrWithoutAuthContainer(props) {
|
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
110
|
}, [title,subtitle]);
|
|
111
|
-
const Wrapper = modal ?
|
|
111
|
+
const Wrapper = modal ? PortalCP : React.Fragment;
|
|
112
|
+
const WrapperProps = modal? {screenName} : {};
|
|
112
113
|
const fab = withFab ? <Fab
|
|
113
114
|
{...fabProps}
|
|
114
115
|
screenName={screenName}
|
|
115
116
|
/> : null;
|
|
116
117
|
const profilAvatar = typeof renderProfilAvatar =='function'? renderProfilAvatar(profilAvatarProps) : null;
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
<ErrorBoundary testID={testID+"_ScreenLayoutErrorBoundary"}>
|
|
120
|
-
<View testID={testID} {...containerProps} style={[styles.container,{backgroundColor},modal && styles.modal,containerProps.style]}>
|
|
121
|
-
{appBar === false ? null : React.isValidElement(appBar)? state.AppBar : <AppBar
|
|
122
|
-
testID={testID+'_AppBar'} {...appBarProps}
|
|
123
|
-
backAction = {defaultVal(appBarProps.backAction,backAction)}
|
|
124
|
-
elevation={defaultNumber(appBarProps.elevation,elevation)}
|
|
125
|
-
withDrawer={withDrawer} options={options}
|
|
126
|
-
ref={appBarRef} title={title}
|
|
127
|
-
subtitle={subtitle}
|
|
128
|
-
right = {withProfilAvatarOnAppBar && <View testID={testID+"_ProfilAvatar_Container"} {...profilAvatarContainerProps} style={[profilAvatarContainerProps.style,styles.profilAvatarContainer]} >
|
|
129
|
-
{React.isValidElement(profilAvatar) && profilAvatar || null}
|
|
130
|
-
</View> || null}
|
|
131
|
-
/>}
|
|
132
|
-
{withScrollView !== false ? (
|
|
133
|
-
<ScrollView
|
|
134
|
-
testID = {testID+'_ScreenContentScrollView'}
|
|
135
|
-
{...rest}
|
|
136
|
-
contentContainerStyle={[contentContainerStyle]}
|
|
137
|
-
style={[containerStyle,styles.container, style]}
|
|
138
|
-
>
|
|
139
|
-
{children}
|
|
140
|
-
{fab}
|
|
141
|
-
</ScrollView>
|
|
142
|
-
) : (
|
|
143
|
-
<View testID={testID+'_ScreenContent'} {...rest} style={[containerStyle,styles.wrapper,styles.container, style]}>
|
|
144
|
-
{children}
|
|
145
|
-
{fab}
|
|
146
|
-
</View>
|
|
147
|
-
)}
|
|
148
|
-
</View>
|
|
149
|
-
</ErrorBoundary>
|
|
150
|
-
</>
|
|
151
|
-
return <Wrapper>
|
|
118
|
+
const portalId = uniqid("screeen-container-"+screenName);
|
|
119
|
+
return <Wrapper {...WrapperProps}>
|
|
152
120
|
{renderChildren({
|
|
153
121
|
containerProps : {
|
|
154
122
|
...authProps,
|
|
155
123
|
required : authRequired,
|
|
156
124
|
},
|
|
157
|
-
|
|
125
|
+
children : <View testID={testID} nativeID={portalId} {...containerProps} style={[styles.container,{backgroundColor},modal && styles.modal,containerProps.style]}>
|
|
126
|
+
{withStatusBar !== false ? <StatusBar/> : null}
|
|
127
|
+
{appBar === false ? null : React.isValidElement(appBar)? state.AppBar : <AppBar
|
|
128
|
+
testID={testID+'_AppBar'} {...appBarProps}
|
|
129
|
+
backAction = {defaultVal(appBarProps.backAction,backAction)}
|
|
130
|
+
elevation={defaultNumber(appBarProps.elevation,elevation)}
|
|
131
|
+
withDrawer={withDrawer} options={options}
|
|
132
|
+
ref={appBarRef} title={title}
|
|
133
|
+
subtitle={subtitle}
|
|
134
|
+
right = {withProfilAvatarOnAppBar && <View testID={testID+"_ProfilAvatar_Container"} {...profilAvatarContainerProps} style={[profilAvatarContainerProps.style,styles.profilAvatarContainer]} >
|
|
135
|
+
{React.isValidElement(profilAvatar) && profilAvatar || null}
|
|
136
|
+
</View> || null}
|
|
137
|
+
/>}
|
|
138
|
+
{withScrollView !== false ? (
|
|
139
|
+
<ScrollView
|
|
140
|
+
testID = {testID+'_ScreenContentScrollView'}
|
|
141
|
+
{...rest}
|
|
142
|
+
contentContainerStyle={[contentContainerStyle]}
|
|
143
|
+
style={[containerStyle,styles.container, style]}
|
|
144
|
+
>
|
|
145
|
+
{children}
|
|
146
|
+
{fab}
|
|
147
|
+
</ScrollView>
|
|
148
|
+
) : (
|
|
149
|
+
<View testID={testID+'_ScreenContent'} {...rest} style={[containerStyle,styles.wrapper,styles.container, style]}>
|
|
150
|
+
{children}
|
|
151
|
+
{fab}
|
|
152
|
+
</View>
|
|
153
|
+
)}
|
|
154
|
+
</View>,
|
|
158
155
|
})}
|
|
159
156
|
</Wrapper>
|
|
160
157
|
}
|
|
161
158
|
|
|
159
|
+
const PortalCP = ({children,screenName})=>{
|
|
160
|
+
return <Portal>
|
|
161
|
+
{children}
|
|
162
|
+
</Portal>
|
|
163
|
+
}
|
|
164
|
+
|
|
162
165
|
const styles = StyleSheet.create({
|
|
163
166
|
container: {
|
|
164
167
|
flex: 1,
|
|
@@ -21,6 +21,7 @@ import theme from "$theme";
|
|
|
21
21
|
import cActions from "$cactions";
|
|
22
22
|
import APP from "$capp/instance";
|
|
23
23
|
import { generatedColumnsProperties } from "./utils";
|
|
24
|
+
import {isDocEditing,checkPrimaryKey} from "$ecomponents/Form";
|
|
24
25
|
import i18n from "$i18n";
|
|
25
26
|
import fetch from "$capi/fetch";
|
|
26
27
|
|
|
@@ -31,42 +32,6 @@ const DEFAULT_TABS_KEYS = "main-tabs";
|
|
|
31
32
|
|
|
32
33
|
const TIMEOUT = 50;
|
|
33
34
|
|
|
34
|
-
const checkPrimary = (data,f)=>{
|
|
35
|
-
return !(!(f in data) || (data[f] == null) || (!data[f] && typeof data !=='number'));
|
|
36
|
-
}
|
|
37
|
-
/*** vérifie si le document passé en paramètre est éditable
|
|
38
|
-
* @param {object} data la données à vérifier
|
|
39
|
-
* @param {object| array} les champs sur lesquels se baser pour vérifier si la donénes est une mise à jour
|
|
40
|
-
* @param {func} checkPrimaryKey la foncition permettant de vérifier s'il s'agit d'une clé primaire pour la données courante
|
|
41
|
-
*/
|
|
42
|
-
export const isDocEditing = (data,fields,checkPrimaryKey)=>{
|
|
43
|
-
if(!isObj(data) || !isObjOrArray(fields)) return false;
|
|
44
|
-
|
|
45
|
-
let hasPrimaryFields = false;
|
|
46
|
-
let hasValidated = true;
|
|
47
|
-
for(let i in fields){
|
|
48
|
-
const field = fields[i];
|
|
49
|
-
if(typeof checkPrimaryKey =='function') {
|
|
50
|
-
hasPrimaryFields = true;
|
|
51
|
-
if(checkPrimaryKey({field,i,index:i,data}) === false){
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
if(!isObj(field)) continue;
|
|
57
|
-
hasPrimaryFields = true;
|
|
58
|
-
const f = defaultStr(field.field,i);
|
|
59
|
-
if(field.primaryKey === true){
|
|
60
|
-
if(!checkPrimary(data,f)){
|
|
61
|
-
hasValidated = false;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
if(hasPrimaryFields){
|
|
66
|
-
return hasValidated;
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
35
|
|
|
71
36
|
export default class TableDataScreenComponent extends FormDataScreen{
|
|
72
37
|
constructor(props){
|
|
@@ -280,6 +245,9 @@ export default class TableDataScreenComponent extends FormDataScreen{
|
|
|
280
245
|
currentField.disabled = true;
|
|
281
246
|
}
|
|
282
247
|
}
|
|
248
|
+
if(field.primaryKey ===true){
|
|
249
|
+
this.primaryKeyFields[columnField] = true;
|
|
250
|
+
}
|
|
283
251
|
const isPrimary = this.primaryKeyFields[columnField] && true || false;
|
|
284
252
|
const f = prepareCb(cArgs);
|
|
285
253
|
if(f === false) {
|
|
@@ -536,7 +504,7 @@ export default class TableDataScreenComponent extends FormDataScreen{
|
|
|
536
504
|
const isDocEditingCb = typeof this.props.isDocEditing =='function'? this.props.isDocEditing : typeof this.props.isDocUpdate =='function'? this.props.isDocUpdate : undefined;
|
|
537
505
|
if(!isDocEditingCb){
|
|
538
506
|
if(isDocEditing(data,this.primaryKeyFields,({index:field,data})=>{
|
|
539
|
-
return
|
|
507
|
+
return checkPrimaryKey(data,field);
|
|
540
508
|
})) return true;
|
|
541
509
|
} else {
|
|
542
510
|
return isDocEditingCb(data,{context:this});
|