@fto-consult/expo-ui 2.11.2 → 2.11.3

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.
@@ -23,6 +23,8 @@ module.exports = (opts)=>{
23
23
  ///les screens principaux de l'application
24
24
  r["$mainScreens"] = r["$mainScreens"] || r["$emainScreens"];
25
25
  r["$escreen"] = r["$eScreen"] = path.resolve(expo,"layouts/Screen");
26
+ r["$eTableDataScreen"] = path.resolve(expo,"layouts","Screen","TableData");
27
+ r["$TableDataScreen"] = r["$TableDataScreen"] || r["$eTableDataScreen"]
26
28
  r["$eassets"] = path.resolve(dir,"assets");
27
29
  r["$ethemeSelectorComponent"] = path.resolve(expo,"auth","ThemeSelector");
28
30
  /*** le composant permettant de sélectionner un theme utilisateur */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "2.11.2",
3
+ "version": "2.11.3",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -65,7 +65,7 @@
65
65
  "@expo/metro-config": "^0.4.0",
66
66
  "@expo/vector-icons": "^13.0.0",
67
67
  "@expo/webpack-config": "^0.17.2",
68
- "@fto-consult/common": "^1.19.8",
68
+ "@fto-consult/common": "^1.20.0",
69
69
  "@gorhom/portal": "^1.0.14",
70
70
  "@react-native-async-storage/async-storage": "~1.17.3",
71
71
  "@react-native-community/datetimepicker": "6.5.2",
@@ -96,7 +96,7 @@
96
96
  "react-content-loader": "^6.2.0",
97
97
  "react-dom": "18.1.0",
98
98
  "react-native": "0.70.5",
99
- "react-native-big-list": "^1.5.5",
99
+ "react-native-big-list": "^1.6.0",
100
100
  "react-native-gesture-handler": "~2.8.0",
101
101
  "react-native-paper": "^4.12.5",
102
102
  "react-native-paper-dates": "^0.9.2",
@@ -79,7 +79,7 @@ class DropdownComponent extends AppComponent {
79
79
  override : false, writable : false,
80
80
  },
81
81
  isBigList : {
82
- value : multiple || this.props.dynamicContent ? true : false,
82
+ value : true,//multiple || this.props.dynamicContent ? true : false,
83
83
  override : false,
84
84
  },
85
85
  });
@@ -215,6 +215,9 @@ export default class FormDataComponent extends AppComponent{
215
215
  if(hidden){
216
216
  rest.style = flattenStyle([rest.style,theme.styles.hidden]);
217
217
  }
218
+ if(rest.defaultValue === null){
219
+ rest.defaultValue = undefined;
220
+ }
218
221
  customResponsiveProps = defaultObj(customResponsiveProps);
219
222
  content.push(<Component
220
223
  data = {data}
@@ -4,8 +4,6 @@ import Dimensions from "$cplatform/dimensions";
4
4
  import {defaultStr,isObj,defaultObj,isNonNullString,defaultVal,defaultFunc} from "$utils";
5
5
  import React from "$react";
6
6
  import {isWeb} from "$cplatform";
7
- import PropTypes from "prop-types";
8
-
9
7
 
10
8
  export default class FormDataActionComponent extends FormData {
11
9
  isFullScreen(){
@@ -47,13 +47,13 @@ export const getUri = (src,onlySting)=>{
47
47
  }
48
48
 
49
49
  export default function ImageComponent(props){
50
- const [src,setSrc] = React.useStateIfMounted(defaultVal(props.src));
50
+ const [src,setSrc] = React.useState(defaultVal(props.src));
51
51
  const prevSrc = React.usePrevious(src);
52
- /*const [editorProps,setEditorProps] = React.useStateIfMounted({
52
+ /*const [editorProps,setEditorProps] = React.useState({
53
53
  visible : false,
54
54
  options : {}
55
55
  })*/
56
- const [isDrawing,setIsDrawing] = React.useStateIfMounted(false);
56
+ const [isDrawing,setIsDrawing] = React.useState(false);
57
57
  let {disabled,onMount,defaultSource,onUnmount,label,text,labelProps,readOnly,beforeRemove,
58
58
  onChange,draw,round,drawText,drawLabel,rounded,editable,defaultSrc,
59
59
  createSignatureOnly,pickImageProps,width,height,cropProps,size,resizeProps,containerProps,
@@ -7,7 +7,7 @@ import Expandable from "$ecomponents/Expandable";
7
7
  import {cursorPointer} from "$theme";
8
8
  import Item from "./Item";
9
9
 
10
- export const MIN_WIDTH = 150;
10
+ export const MIN_WIDTH = 160;
11
11
 
12
12
  export const renderItems = (props)=>{
13
13
  let _items = [];
@@ -13,8 +13,6 @@ import theme,{StyleProp} from "$theme";
13
13
  import OpacityAnimation from "$ecomponents/Animations/OpacityAnimation";
14
14
  import { Surface } from "react-native-paper";
15
15
  import { Platform } from "react-native";
16
- import {isWeb} from "$cplatform";
17
- import {isAndroid} from "$cplatform";
18
16
  import Portal from "$ecomponents/Portal";
19
17
  import {
20
18
  getStatusBarHeight,
@@ -7,7 +7,7 @@ import View from "$ecomponents/View";
7
7
  import Divider from "$ecomponents/Divider";
8
8
  import Menu from "$ecomponents/Menu/Menu";
9
9
  import theme,{Colors,StylePropTypes} from "$theme";
10
- import List,{MIN_HEIGHT} from "$ecomponents/List";
10
+ import List,{MIN_HEIGHT,BigList} from "$ecomponents/List";
11
11
  import Label from "$ecomponents/Label";
12
12
  import PropTypes from "prop-types";
13
13
  import Icon from "$ecomponents/Icon";
@@ -371,7 +371,7 @@ const SimpleSelect = React.forwardRef((props,ref)=>{
371
371
  />
372
372
  <Divider />
373
373
  </>}
374
- <List
374
+ <BigList
375
375
  testID = {testID+"_List"}
376
376
  {...listProps}
377
377
  getItemLayout = {getItemLayout}
@@ -0,0 +1,743 @@
1
+ import {defaultStr,isNumber,isPromise,defaultVal,extendObj,defaultObj,uniqid,isObj,isObjOrArray} from "$utils";
2
+ import {FormData} from "$ecomponents/Form";
3
+ import FormDataScreen from "./FormData";
4
+ import ScreenContainer from "$screen";
5
+ import React from "$react";
6
+ import { StyleSheet} from "react-native";
7
+ import ScrollView from "$ecomponents/ScrollView";
8
+ import PropTypes from "prop-types";
9
+ import notify from "$notify";
10
+ import Auth from "$cauth";
11
+ import {open as showPreloader,close as hidePreloader} from "$preloader";
12
+ import {canMakePhoneCall, makePhoneCall as makePCall} from "$app/MakePhoneCall";
13
+ import copyToClipboard from "$app/clipboard";
14
+ import {isMobileOrTabletMedia} from "$platform/dimensions";
15
+ import Tab from "$ecomponents/Tab";
16
+ import Surface from "$ecomponents/Surface";
17
+ import View from "$ecomponents/View";
18
+ import {getScreenProps,goBack as navGoBack} from "$cnavigation";
19
+ import {renderTabsContent,renderActions} from "./utils";
20
+ import theme from "$theme";
21
+ import cActions from "$cactions";
22
+ import APP from "$capp/instance";
23
+
24
+ const HIDE_PRELOADER_TIMEOUT = 300;
25
+
26
+ const DEFAULT_TABS_KEYS = "main-tabs";
27
+
28
+ const TIMEOUT = 50;
29
+
30
+ export default class TableDataScreenComponent extends FormDataScreen{
31
+ constructor(props){
32
+ super(props);
33
+ let cDatas = [];
34
+ const mainProps = getScreenProps(props);
35
+ const hasManyData = isObjOrArray(mainProps.datas) && Object.size(mainProps.datas,true) > 0 ? true : false;
36
+ if(hasManyData){
37
+ cDatas = Object.toArray(mainProps.datas);
38
+ }
39
+ extendObj(this.state,{
40
+ hasManyData,
41
+ datas : cDatas,
42
+ currentIndex : 0,
43
+ data : hasManyData ? defaultObj(cDatas[0]) : isObj(mainProps.data)? mainProps.data : {}
44
+ });
45
+ const table = defaultObj(mainProps.table);
46
+ const fields = {};
47
+ Object.map(table.fields,(field,i)=>{
48
+ if(isObj(field) && field.form !== false){
49
+ fields[i] = Object.clone(field);
50
+ } else {
51
+ fields[i] = field;
52
+ }
53
+ });
54
+ Object.defineProperties(this,{
55
+ INITIAL_STATE : {value : {}},
56
+ tableName : { value : defaultStr(table.table,table.tableName)},
57
+ fields : {value : fields},
58
+ table : {value : table},
59
+ validateDataBeforeSave : {value : mainProps.validateData},
60
+ upsertDataToDB : {value : mainProps.upsertToDB},
61
+ makePhoneCallProps : {value : mainProps.makePhoneCallProps},
62
+ onSaveProp : {value : mainProps.onSave},
63
+ titleProp : {value : mainProps.title},
64
+ closeOnSaveProp : {value : mainProps.closeOnSave || mainProps.closeAfterSave },
65
+ newActionProp : {value : mainProps.newAction},
66
+
67
+ });
68
+ this.hidePreloader = this.hidePreloader.bind(this);
69
+ this.showPreloader = this.showPreloader.bind(this);
70
+ };
71
+ resetState(){
72
+ Object.map(this.INITIAL_STATE,(s,k)=>{
73
+ delete this.INITIAL_STATE[k];
74
+ })
75
+ }
76
+ getDatas(){
77
+ return this.state.datas;
78
+ }
79
+ hasManyData (){
80
+ return this.state.hasManyData;
81
+ }
82
+ getCurrentData(){
83
+ return defaultObj(this.state.data);
84
+ }
85
+ /**** retourne les props en cours d'édition */
86
+ getCurrentEditingProps (){
87
+ return defaultObj(this.INITIAL_STATE.props);
88
+ }
89
+ /* Attention, cette méthode est appélée dans la méthode getComponentProps de la classe parente.
90
+ * Tenir de cette information capitale pour bien négocier l'appel de la dite méthode. Elle permet de retourner
91
+ * les permissions particulière qu'aura l'utilisateur sur les actions de la tableData
92
+ * cette fonction est appelée, pour retourner les permissions qu'à l'utilisateur sur les ressource
93
+ * Elle doit retourner un objet de la forme :
94
+ * {
95
+ * create || write : boolean
96
+ * edit || update : boolean
97
+ * }
98
+ * @param {
99
+ * perm {string} : la chaine de caractère traduisant la permission et pouvant être passée en paramètre
100
+ * isUpdate : booléan spécifiant s'il s'agit d'une mise à jour du document actuel
101
+ * tableName : chaine de caractère contenenant le nom de la table associée à la tableData
102
+ * context || le context qui execute la fonction courante
103
+ * datas: la liste des données passées à la TableData
104
+ * }
105
+ */
106
+ getActionsPerms({perm,action,tableName}){
107
+ return (isNonNullString(perm)? Auth.isAllowed({resource:perm.split(':')[0],action}):Auth.isTableDataAllowed({table:tableName,action}));
108
+ }
109
+ getRenderedActionPrefix (){}
110
+ renderActions(){
111
+ return null;
112
+ }
113
+ getComponentProps(props){
114
+ this.resetState();
115
+ const {
116
+ actions,
117
+ fields:customFields,
118
+ onKeyEvent,
119
+ canMakePhoneCall : customCanMakePhoneCall,
120
+ makePhoneCallProps : customMakePhoneCallProps,
121
+ beforeSave,
122
+ closeOnSave,closeAfterSave,
123
+ table : cTable,
124
+ onSave,
125
+ onSaveTableData,
126
+ clone,
127
+ isArchivable,clonable,isPrintable,print,data:customData,getRowKey,
128
+ save2newAction,
129
+ saveAction,
130
+ save2closeAction,
131
+ cloneAction,
132
+ children,
133
+ Component,
134
+ tabs : customTabs,
135
+ firstTabProps,
136
+ sessionName : customSessionName,
137
+ contentProps : customContentProps,
138
+ elevation,
139
+ appBarProps : customAppBarProps,
140
+ containerProps : customContainerProps,
141
+ formProps : customFormProps,
142
+ newElementLabel,
143
+ ...rest
144
+ } = getScreenProps(props);
145
+ const table = this.table;
146
+ const {datas,currentIndex,data} = this.state;
147
+ const tableName = this.tableName;
148
+ const sessionName = this.INITIAL_STATE.sessionName = defaultStr(customSessionName,"table-form-data"+tableName);
149
+ const isUpdated = this.isDocEditing(data);
150
+ const isMobOrTab = isMobileOrTabletMedia();
151
+ let archived = this.isArchived();
152
+ this.INITIAL_STATE.archived = archived;
153
+ this.INITIAL_STATE.tableName = tableName;
154
+ const fields = {};
155
+ Object.map(this.fields,(field,i)=>{
156
+ if(isObj(field)){
157
+ fields[i] = Object.clone(field);
158
+ if(isUpdated){
159
+ //la props readOnlyOnEditing permet de rendre le champ readOnly en cas de mise à jour de la tableData
160
+ if((field.readOnlyOnEditing === true)){
161
+ fields[i].readOnly = true;
162
+ }
163
+ if((field.disabledOnEditing === true)){
164
+ fields[i].disabled = true;
165
+ }
166
+ }
167
+ } else {
168
+ fields[i] = field;
169
+ }
170
+ })
171
+ if(isObj(customFields)){
172
+ extendObj(true,fields,customFields);
173
+ }
174
+ const context = this;
175
+ const formProps = ({
176
+ ...defaultObj(customFormProps),
177
+ archived,
178
+ data,
179
+ isUpdate : isUpdated,
180
+ isUpdated,
181
+ fields,
182
+ });
183
+ const rActionsArg = this.INITIAL_STATE.props = {
184
+ ...rest,
185
+ ...formProps,
186
+ context,
187
+ save2newAction : this.canCreateNew() && save2newAction !== false ? true : false,
188
+ isMobile : isMobOrTab,
189
+ saveAction,
190
+ save2closeAction,
191
+ cloneAction : this.isClonable() && clonable !== false ? cloneAction : false,
192
+ tableName,
193
+ sessionName,
194
+ table,
195
+ newElementLabel : this.getNewElementLabel(),
196
+ printable : this.isPrintable(),///si la table data est imprimable,
197
+ canMakePhoneCall : this.canMakePhoneCall(),
198
+ makePhoneCallProps:this.getMakePhoneCallProps(),
199
+ onPressToMakePhoneCall : this.makePhoneCall.bind(this),
200
+ archivable : this.isArchivable(),
201
+ saveButton : isUpdated?'Modifier':'Enregistrer',
202
+ currentData:data,
203
+ hasManyData : this.hasManyData(),
204
+ //onPressToPrint : this.print.bind(this),
205
+ datas,
206
+ currentDataIndex:currentIndex,
207
+ onPressToPrevious:this.goToPreviousData.bind(this),
208
+ onPressToArchive : this.doSave.bind(this),
209
+ onSave : undefined,
210
+ onPressToCreateNew : this.createNew.bind(this),
211
+ onPressToNext:this.goToNextData.bind(this),
212
+ archivedPermsFilter : this.archivedPermsFilter.bind(this),
213
+ onPressCopyToClipboard : this.copyToClipboard.bind(this)
214
+ }
215
+ ///modifie le container par défaut de fasson à définir la bonne date pour les champs de type date
216
+ if(isObj(fields.date)){
217
+ fields.date.defaultValue = new Date();
218
+ }
219
+ if(isUpdated){
220
+ fields.approved = this.isApprovable()? {
221
+ text : 'Approuvé',
222
+ type : 'switch',
223
+ defaultValue : 0,
224
+ checkedTooltip: 'Oui',
225
+ disabled : Auth.isTableDataAllowed({table:tableName,action:'updateapproved'})? false:true,
226
+ uncheckedTooltip : 'Non'
227
+ } : null;
228
+ }
229
+ rActionsArg.contentProps = Object.assign({},customContentProps);
230
+ rActionsArg.containerProps = Object.assign({},customContainerProps);
231
+ formProps.onKeyEvent = this.onKeyEvent.bind(this);
232
+ rActionsArg.elevation = typeof rActionsArg.contentProps.elevation ==="number"? contentProps.elevation : typeof elevation == 'number' ? elevation : 5;
233
+ rActionsArg.formProps = formProps;
234
+ return rActionsArg;
235
+ }
236
+ renderTabs(){
237
+ return null;
238
+ }
239
+ handleCustomRender(){
240
+ return true;
241
+ }
242
+ componentWillRender(rActionsArg){
243
+ const rActions = renderActions.call(this,rActionsArg);
244
+ const renderedActs = this.renderActions(rActionsArg);
245
+ if(!rActionsArg.archived){
246
+ const customActionKeyPrefix = this.getRenderedActionPrefix();
247
+ const iPrefix = customActionKeyPrefix === false ? "" : defaultStr(customActionKeyPrefix,"zact")
248
+ Object.map(renderedActs,(a,i)=>{
249
+ rActions[iPrefix+i] = a;
250
+ });
251
+ }
252
+ rActionsArg.actions = rActions;
253
+ return rActionsArg;
254
+ }
255
+ _render ({header,content,context}){
256
+ const restProps = this.getCurrentEditingProps();
257
+ delete restProps.tabs;
258
+ let {tabProps,firstTabProps,tabsProps,withScrollView} = restProps;
259
+ let testID = defaultStr(this.props.testID);
260
+ tabsProps = defaultObj(tabsProps);
261
+ tabsProps.tabItemsProps = defaultObj(tabsProps.tabItemsProps);
262
+ if(typeof withScrollView =='boolean' && typeof tabsProps.withScrollView !=='boolean'){
263
+ tabsProps.withScrollView = withScrollView;
264
+ }
265
+ restProps.tabsProps = tabsProps;
266
+ restProps.tabProps = tabProps = defaultObj(tabProps);
267
+ const tabs = this.renderTabs(restProps);
268
+ const tabKey = this.getTabsKey();
269
+ const isMobile = isMobileOrTabletMedia();
270
+ const contentProps = restProps.contentProps;
271
+ const elevation = restProps.elevation;
272
+ const renderingTabsProps = {tabs,data:this.getCurrentData(),isMobile,sessionName:this.INITIAL_STATE.sessionName,props:restProps,tabProps,tabsProps,context,tabKey};
273
+ const hasTabs = Object.size(tabs,true);
274
+ let mainContent = undefined;
275
+ testID = defaultStr(testID,"RN_TableDataScreenItem_"+restProps.tableName);
276
+ const isMobOrTab = isMobileOrTabletMedia();
277
+ firstTabProps = extendObj({},tabProps,firstTabProps);
278
+ if(hasTabs){
279
+ if(isMobOrTab){
280
+ renderingTabsProps.firstTab = <Tab.Item testID={testID+"_MainTab"} label={"Principal"} {...firstTabProps} key={tabKey}>
281
+ <Surface testID={testID+"_MainTab_Content"} elevation={5} {...contentProps} style={[styles.noMarging,contentProps.style,styles.h100,styles.noPadding]}>
282
+ {header}
283
+ {content}
284
+ </Surface>
285
+ </Tab.Item>
286
+ } else {
287
+ //tabsProps.tabItemsProps.elevation = 0;
288
+ }
289
+ const ct = renderTabsContent(renderingTabsProps);
290
+ if(isMobOrTab && ct){
291
+ contentProps.style = [contentProps.style,styles.noMarging,styles.noPadding,styles.content]
292
+ mainContent = ct;
293
+ } else {
294
+ mainContent = <View {...contentProps} testID={testID+"_ContentContainer"} style={[styles.container,styles.noPadding]}>
295
+ <ScrollView virtualized testID={testID+"_MainContentScrollView"} contentProps={{style:theme.styles.p1}}>
296
+ <Surface elevation={elevation} testID={testID+"_ContentHeader"} style={[styles.screenContent,theme.styles.p1,header?styles.screenContentWithHeader:null]}>
297
+ {header}
298
+ {content}
299
+ </Surface>
300
+ {ct ? <Surface {...contentProps} testID={testID+"_DesktopContentTabs"} elevation={elevation} style={[contentProps.style]}>
301
+ {ct}
302
+ </Surface> : null}
303
+ </ScrollView>
304
+ </View>
305
+ }
306
+ } else {
307
+ mainContent = <Surface {...contentProps} testID={testID+"_MainContentContainer"} elevation={elevation} style={[styles.container,styles.noPadding,{paddingTop:0,marginTop:0}]}>
308
+ <ScrollView virtualized testID={testID+"_MainContentScrollView"}>
309
+ <View testID={testID+"_MainContent"} style={[styles.screenContent,!isMobOrTab && theme.styles.p1,header?styles.screenContentWithHeader:null]}>
310
+ {header}
311
+ {content}
312
+ </View>
313
+ </ScrollView>
314
+ </Surface>
315
+ }
316
+ const appBarProps = this.getAppBarActionsProps(restProps);
317
+ if(hasTabs && isMobOrTab){
318
+ appBarProps.elevation = 0;
319
+ restProps.elevation = 0;
320
+ }
321
+ return <ScreenContainer {...restProps} appBarProps = {appBarProps} testID={testID}>
322
+ {this.wrapRenderingContent(mainContent,{testID})}
323
+ </ScreenContainer>
324
+ }
325
+ wasTransferred(data){
326
+ data = defaultObj(data,this.state.data);
327
+ return !!data.wasTransferred;
328
+ }
329
+ getCurrentIndex (){
330
+ return this.state.currentIndex;
331
+ }
332
+ isArchivable(){
333
+ return false;
334
+ }
335
+ isArchived(data){
336
+ data = defaultObj(data,this.state.data);
337
+ return this.isArchivable() && this.isDocEditing(data) && (!!data.archived || !!data.wasTransferred)? true : !!this.INITIAL_STATE.archived || false;
338
+ }
339
+ goToPreviousData(){
340
+ const currentIndex = this.getCurrentIndex(),datas = this.state.datas;
341
+ if(!this._isMounted() || !this.hasManyData() || currentIndex <= 0) return;
342
+ clearTimeout(this.timeoutCallback);
343
+ this.timeoutCallback = setTimeout(()=>{
344
+ const cIndex = currentIndex -1;
345
+ if(isObj(datas[cIndex])){
346
+ this.showPreloader();
347
+ this.setState({currentIndex:cIndex,data:datas[cIndex]},this.hidePreloader);
348
+ }
349
+ },TIMEOUT);
350
+ }
351
+ goToNextData = ()=>{
352
+ const currentIndex = this.getCurrentIndex(),datas = this.state.datas;
353
+ if(!this._isMounted() || !this.hasManyData() || currentIndex >= this.state.datas.length-1) return;
354
+ clearTimeout(this.timeoutCallback);
355
+ this.timeoutCallback = setTimeout(()=>{
356
+ const cIndex = currentIndex +1;
357
+ if(isObj(datas[cIndex])){
358
+ this.showPreloader();
359
+ this.setState({currentIndex:cIndex,data:datas[cIndex]},this.hidePreloader);
360
+ }
361
+ },TIMEOUT);
362
+ }
363
+ getTabsKey(k){
364
+ let key = DEFAULT_TABS_KEYS;
365
+ k = isNumber(k) ? k : 0;
366
+ if(this.hasManyData()){
367
+ return this.getCurrentIndex()+k;
368
+ }
369
+ return key+k;
370
+ }
371
+ isApprovable(){
372
+ return false;
373
+ }
374
+ getCurrentEditingData(data){
375
+ return this.isDocEditing(data)? data : this.getCurrentData();
376
+ }
377
+ approve (data){
378
+ if(!this.isApprovable()) return;
379
+ data = this.getCurrentEditingData(data);
380
+ data.approved = 1;
381
+ this.clickedEl = "save";
382
+ this.doSave({data});
383
+ return true;
384
+ }
385
+ isPrintable(){
386
+ return false;
387
+ }
388
+ print(data){
389
+ if(!this.isPrintable() && typeof this.props.print!=='function') return;
390
+ data = this.isDocEditing(data)? data : isObj(data) && this.isDocEditing(data.data)? data.data : {};
391
+ return this.props.print(data,this);
392
+ }
393
+ isClonable(){
394
+ return true;
395
+ }
396
+ clone (data){
397
+ if(!this._isMounted() || !this.isClonable())return data;
398
+ data = {...this.getCurrentEditingData(data)};
399
+ if(typeof this.props.clone =='function' && this.props.clone(data,this) === false) return data;
400
+ this.showPreloader();
401
+ delete data.approved;
402
+ Object.map(['_rev','_id','code','updatedBy','updatedDate','createdBy','updatedHour','createdHour','createdDate'],(idx)=>{
403
+ data[idx] = undefined;
404
+ delete data[idx];
405
+ });
406
+ this.setState({data,hasManyData:false,datas:[],currentIndex:0},this.hidePreloader);
407
+ return data;
408
+ }
409
+ showPreloader(content){
410
+ return showPreloader(content||'traitement en cours...');
411
+ }
412
+ hidePreloader(timeoutCallback){
413
+ clearTimeout(this.hidePreloaderTimeout);
414
+ this.hidePreloaderTimeout = setTimeout(()=>{
415
+ clearTimeout(this.hidePreloaderTimeout);
416
+ hidePreloader();
417
+ },typeof timeoutCallback =='number'? timeoutCallback : HIDE_PRELOADER_TIMEOUT);
418
+ return this.hidePreloaderTimeout;
419
+ }
420
+ reset (args,cb){
421
+ if(!this._isMounted()) return;
422
+ clearTimeout(this.timeoutCallback);
423
+ this.showPreloader();
424
+ this.timeoutCallback = setTimeout(()=>{
425
+ args = defaultObj(args);
426
+ args.data = defaultObj(args.data)
427
+ const currentIndex = this.getCurrentIndex();
428
+ if(args.reset !== true && this.hasManyData() && Object.size(args.data,true)){
429
+ const cData = [...this.state.datas]
430
+ cData[currentIndex] = args.data;
431
+ this.setState({data:args.data,datas:cData,currentIndex},this.hidePreloader);
432
+ } else {
433
+ this.setState({data:args.data,datas:[],hasManyData:false,currentIndex:0},this.hidePreloader);
434
+ }
435
+ },TIMEOUT);
436
+ }
437
+
438
+ /**** si l'on peut appeler la props onSuccess après vouloir cliquer sur le bouton enregistrer les données depuis la formData*/
439
+ canCallOnSuccess(){
440
+ return true;
441
+ }
442
+ upsertToDB(args){
443
+ if(typeof this.upsertDataToDB ==='function'){
444
+ return this.upsertDataToDB(args);
445
+ }
446
+ return Promise.resolve({});
447
+ }
448
+ getDataProp(){
449
+ return Object.assign({},this.getCurrentData());
450
+ }
451
+ getAppBarActionsProps(props){
452
+ return super.getAppBarActionsProps({...props,data:this.getCurrentData()})
453
+ }
454
+ /**** cette fonction est appelée immédiatement lorsque l'on clique sur le bouton enregistrer de l'un des actions du formulaire */
455
+ onPressToSaveFormData(args){
456
+ return this.doSave(args);
457
+ }
458
+ canCreateNew(){
459
+ return this.newActionProp !== false ? true : false;
460
+ }
461
+ createNew(){
462
+ return this.reset();
463
+ }
464
+ archive(){}
465
+ validateData(args){
466
+ if(typeof this.validateDataBeforeSave =='function'){
467
+ return this.validateDataBeforeSave(args);
468
+ }
469
+ return true;
470
+ }
471
+ onSaveTableData(){}
472
+ doSave ({goBack,data,action}){
473
+ const cb = ()=>{
474
+ if(action === 'new'){
475
+ this.reset();
476
+ return false;
477
+ }
478
+ if(action =='makePhoneCall'){
479
+ this.makePhoneCall(data);
480
+ return false;
481
+ }
482
+ if(action === 'print'){
483
+ this.print(data);
484
+ return false;
485
+ }
486
+ if(action === 'archive'){
487
+ this.archive(data);
488
+ return false;
489
+ }
490
+ if(action === 'clone'){
491
+ this.clone({...data});
492
+ return false;
493
+ }
494
+ const isUpdated = this.isDocEditing(data);
495
+ let isPOpened = true;
496
+ const closePreloader = ()=>{
497
+ if(isPOpened){
498
+ hidePreloader();
499
+ }
500
+ isPOpened = false;
501
+ }
502
+ const close = ()=>{
503
+ closePreloader();
504
+ goBack = typeof goBack =='function'? goBack : navGoBack;
505
+ if(typeof goBack =='function'){
506
+ goBack(true);
507
+ }
508
+ }
509
+ showPreloader(this.getConfirmTitle()+"\n"+(isUpdated?'Modification':'Enregistrement')+" en cours...");
510
+ const hasManyData = this.hasManyData();
511
+ const context = this;
512
+ const tableName = this.tableName;
513
+ const upToDB = this.upsertToDB({data,table:this.table,tableName,context});
514
+ if(isPromise(upToDB)){
515
+ upToDB.then((upserted)=>{
516
+ const willCloseAfterSave = action === 'save2close' || !hasManyData;
517
+ let savedData = this.isDocEditing(upserted)? upserted : data;
518
+ const newArgs = {tableName,actionName:action,action,table:this.table,data:savedData,result:upserted,context};
519
+ APP.trigger(cActions.upsert(tableName),newArgs);
520
+ if(this.onSaveTableData(newArgs) === false || (isFunction(this.onSaveProp)&& this.onSaveProp(newArgs) === false)){
521
+ closePreloader();
522
+ return;
523
+ }
524
+ const isSave2Print = action =="save2print";
525
+ let forceClose = this.closeOnSaveProp || isSave2Print;
526
+ if(forceClose){
527
+ close();
528
+ if(isSave2Print){
529
+ setTimeout(()=>{
530
+ this.print(savedData);
531
+ },TIMEOUT);
532
+ }
533
+ }
534
+ if(action == 'save2new'){
535
+ this.reset();
536
+ closePreloader();
537
+ } else if(action === 'save'){
538
+ this.reset({data:savedData});
539
+ closePreloader();
540
+ } else if(willCloseAfterSave) {
541
+ close();
542
+ } else {
543
+ notify('Données modifiée avec succès!!','success');
544
+ closePreloader();
545
+ }
546
+ }).catch((e)=>{
547
+ console.log('error on saving table data ',e);
548
+ closePreloader();
549
+ });
550
+ } else {
551
+ closePreloader();
552
+ }
553
+ }
554
+ action = defaultStr(action,this.clickedEl);
555
+ const isValid = this.validateData({data,action,context:this});
556
+ if(isNonNullString(isValid)){
557
+ return notify.error(isValid);
558
+ }
559
+ if(isValid === false) return;
560
+ if(isPromise(isValid)){
561
+ isValid.then((r)=>{
562
+ if(isNonNullString(r)){
563
+ return notify.error(r);
564
+ } else if(r === false) return;
565
+ cb();
566
+ }).catch(notify.error);
567
+ } else {
568
+ cb();
569
+ }
570
+ return false;
571
+ }
572
+ onKeyEvent(event){
573
+ event = super.onKeyEvent(event);
574
+ if(!isObj(event)) return;
575
+ if(isObj(this.buttonsActions) && isObj(event.formKeyEventAction) && isNonNullString(event.formKeyEventAction.action)){
576
+ let fke = event.formKeyEventAction;
577
+ let button = this.buttonsActions[fke.action];
578
+ this.clickedEl = fke.action;
579
+ if(isObj(button)){
580
+ if(fke.action == 'previous'){
581
+ this.goToPreviousData();
582
+ } else if(fke.action =="next"){
583
+ this.goToNextData();
584
+ } else {
585
+ let f = this.getForm();
586
+ if(isObj(f) && f.isValid && f.isValid()){
587
+ const data = f.getData();
588
+ switch(fke.action){
589
+ case 'print':
590
+ this.print(data);
591
+ break;
592
+ default :
593
+ this.clickedEl = fke.action;
594
+ this.doSave({data});
595
+ break;
596
+ }
597
+ } else {
598
+ notify.warning("Impossible d'enregistrer le document. Rassurez vous de remplir les champs nécesaires afin qu'il soit valide.");
599
+ }
600
+ }
601
+ }
602
+ }
603
+ }
604
+ canMakePhoneCall(){
605
+ if(!canMakePhoneCall()) return false;
606
+ const table = this.table;
607
+ if(table.canMakePhoneCall) return true;
608
+ return isObj(table.datagrid) ? !!table.datagrid.canMakePhoneCall : false;
609
+ }
610
+ getTableName(){
611
+ return this.tableName;
612
+ }
613
+ getMakePhoneCallProps (){
614
+ const table = this.table;
615
+ const makePhoneCallProps = defaultVal(this.makePhoneCallProps,table.makePhoneCallProps);
616
+ return defaultObj(typeof makePhoneCallProps === 'function' ? makePhoneCallProps(this.getCurrentData()) : makePhoneCallProps);
617
+ }
618
+ makePhoneCall(data){
619
+ if(!this.canMakePhoneCall() || !canMakePhoneCall()) return false;
620
+ makePCall(defaultObj(data || this.getCurrentData()),this.getMakePhoneCallProps());
621
+ return false;
622
+ }
623
+
624
+ /*** archivedPermsFilter est la fonction permettant de filtres les permissions qui par défaut ne figurent pas parmis les permissions en readOnly
625
+ * si archivedPermFilter retourne true pour une permission données alors cette permission sera ignorée
626
+ */
627
+ archivedPermsFilter (perm,perms){
628
+ return true;
629
+ };
630
+ copyToClipboard(){
631
+ return copyToClipboard({
632
+ data : this.getCurrentData(),
633
+ fields : this.INITIAL_STATE.fields,
634
+ sessionName : this.INITIAL_STATE.sessionName,
635
+ })
636
+ }
637
+ renderDatagridActions(args){
638
+ args = defaultObj(args);
639
+ let {datagrid,filterAction} = args
640
+ let ret = [];
641
+ if(this.isDocEditing(args.data) && isObj(datagrid) && typeof (datagrid.selectedRowsActions) ==='function'){
642
+ filterAction = defaultFunc(filterAction,(x)=>true);
643
+ Object.map(datagrid.selectedRowsActions({selectedRows : {[args.data._id]:args.data},Auth}),(v,i)=>{
644
+ if(isObj(v) && filterAction(v,i)){
645
+ ret.push({...v},i);
646
+ }
647
+ })
648
+ }
649
+ return ret;
650
+ }
651
+ getAppBarTitle (){
652
+ return defaultStr(this.titleProp,this.table.text,this.table.label);
653
+ }
654
+ getMainProps(){
655
+ if(isObj(this.INITIAL_STATE.props) && Object.size(this.INITIAL_STATE.props,true)) {
656
+ this.INITIAL_STATE.props
657
+ }
658
+ return getScreenProps(this.props);
659
+ }
660
+ getAppBarProps(a){
661
+ const r = super.getAppBarProps(a);
662
+ r.title = this.getAppBarTitle();
663
+ if(this.hasManyData()){
664
+ r.title +=" ["+(this.state.currentIndex+1)+"/"+this.state.datas.length+"]";
665
+ }
666
+ return r;
667
+ }
668
+ }
669
+
670
+
671
+
672
+
673
+ TableDataScreenComponent.propTypes = {
674
+ ...defaultObj(FormData.propTypes),
675
+ table : PropTypes.shape({
676
+ tableName : PropTypes.string,
677
+ table : PropTypes.string,
678
+ fields : PropTypes.object,
679
+ }),
680
+ validateData : PropTypes.func,// la fonction permettant de valider les données à enregistrer
681
+ archivedPermsFilter : PropTypes.func,///le filtre des permissions archivées
682
+ newElementLabel : PropTypes.string,//le titre du bouton nouveau pour l'ajout d'un nouvel élément
683
+ customActionKeyPrefix : PropTypes.oneOfType([
684
+ PropTypes.string,
685
+ PropTypes.bool,
686
+ ]), //le préfix par défaut à utiliser pour préfixer les actions supplémentaires du FormDataScreen. important pour un ordre personalisé des actions du composant
687
+ formName : PropTypes.string,//le nom de la formnanem qui rend le contenu du table data
688
+ onSave : PropTypes.func, ///lorsque la données est enregistrée
689
+ onSaveTableData : PropTypes.func,
690
+ closeOnSave : PropTypes.bool,
691
+ closeAfterSave : PropTypes.bool,
692
+ beforeSave : PropTypes.func,
693
+ canMakePhoneCall : PropTypes.bool,
694
+ makePhoneCallProps : PropTypes.oneOfType([
695
+ PropTypes.object,
696
+ PropTypes.func,
697
+ ]),
698
+ fields : PropTypes.objectOf(PropTypes.object),
699
+ tabs : PropTypes.oneOfType([
700
+ PropTypes.array,
701
+ PropTypes.object,
702
+ PropTypes.func,
703
+ ]),
704
+ children : PropTypes.oneOfType([
705
+ PropTypes.func,
706
+ PropTypes.node,
707
+ PropTypes.element,
708
+ ]),
709
+ }
710
+
711
+ const styles = StyleSheet.create({
712
+ noPadding : {
713
+ padding:0,
714
+ paddingTop : 0,
715
+ paddingBottom : 0,
716
+ paddingHorizontal : 0,
717
+ paddingVertical : 0,
718
+ },
719
+ noMarging : {
720
+ margin : 0,
721
+ marginVertical : 0,
722
+ marginHorizontal : 0,
723
+ },
724
+ container : {
725
+ paddingVertical : 10,
726
+ paddingHorizontal : 10,
727
+ },
728
+ content : {
729
+
730
+ },
731
+ screenContent : {
732
+ padding : 0,
733
+ paddingBottom : 50,
734
+ },
735
+ screenContentWithHeader : {
736
+ marginTop : 0,
737
+ paddingTop:0,
738
+ },
739
+ h100 : {
740
+ height:'100%'
741
+ }
742
+ });
743
+ TableDataScreenComponent.displayName = "TableDataScreenComponent"
@@ -0,0 +1,274 @@
1
+ import Tab from "$ecomponents/Tab";
2
+ import {isObjOrArray,defaultStr,defaultObj,isNonNullString,defaultArray,defaultFunc} from "$utils";
3
+ import React from "$react";
4
+ import {Colors} from "$theme";
5
+ import { COPY_ICON,PRINT_ICON} from "$ecomponents/Icon";
6
+ import {getTableDataRouteName} from "$enavigation/utils";
7
+
8
+
9
+ export const renderTabsContent = ({tabs,context,data,sessionName,isMobile,props,firstTab,tabKey,tabProps,tabsProps})=>{
10
+ let tabsArr = [],hasFirstTab = false;
11
+ if(React.isValidElement(firstTab)){
12
+ tabsArr.push(firstTab);
13
+ hasFirstTab = true;
14
+ }
15
+ tabsProps = Object.assign({},tabsProps);
16
+ tabsProps.centered = false;
17
+ tabKey = typeof tabKey =='string' || typeof tabKey =='number'? tabKey : 'first-tab-key';
18
+ let idx = tabsArr.length-1;
19
+ const testID = defaultStr(tabsProps.testID,"RN_TableDataScreenTab");
20
+ if(isObjOrArray(tabs) && Object.size(tabs,true)>0){
21
+ Object.map(tabs,(tab,index,i)=>{
22
+ if(!isObj(tab)) return null;
23
+ let key = index+(tabKey),label = null,children = null;
24
+ idx++;
25
+ const tabP = Object.assign({},tabProps);
26
+ tabP.index = idx;
27
+ if(React.isValidElement(tab)){
28
+ children = tab;
29
+ } else {
30
+ let {text,render,...rest} = tab;
31
+ extendObj(tabP,rest);
32
+ label = defaultVal(tab.label,text)
33
+ children = tab.children;
34
+ delete tab.children;
35
+ tabP.label = label;
36
+ key = (key+defaultStr(tab.key,tab._id)).replaceAll(" ",);
37
+ if(typeof (render) =='function'){
38
+ children = render.call(context,{context,sessionName,isMobile,data,index,tab,props,key});
39
+ } else if(!React.isValidElement(children) && React.isValidElement(render)){
40
+ children = render;
41
+ }
42
+ }
43
+ if(React.isValidElement(children)){
44
+ tabsArr.push(
45
+ <Tab.Item testID={testID+"_Item_"+key} label={label} {...tabP} key={key}>
46
+ {children}
47
+ </Tab.Item>
48
+ )
49
+ }
50
+ })
51
+ }
52
+ if(tabsArr.length> (hasFirstTab ? 1 : 0)){
53
+ return <Tab testID={testID}
54
+ {...tabsProps}
55
+ onChange={(args)=>{
56
+ if(typeof tabsProps.onChange =='function'){
57
+ tabsProps.onChange(args)
58
+ }
59
+ context.activeTabIndex = args.activeIndex;
60
+ }}
61
+ sessionName = {sessionName}
62
+ activeIndex = {typeof context.activeTabIndex =='number'? context.activeTabIndex : tabsProps.activeIndex}
63
+ >
64
+ {tabsArr}
65
+ </Tab>
66
+ }
67
+ return null;
68
+ }
69
+
70
+
71
+ export function renderActions({context,isUpdate,newElementLabel,makePhoneCallProps,hasManyData,onPressCopyToClipboard,archived,archivedPermsFilter,canMakePhoneCall,onPressToMakePhoneCall,saveAction,save2newAction,save2closeAction,cloneAction,readOnly,printable,archivable,data,table,perm,tableName,saveButton,datas,rows,currentData,currentDataIndex,onPressToSave,onPressToCreateNew,onPressToPrint,onPressToPrevious,onPressToNext,onPressToArchive,...rest}){
72
+ let textSave = defaultStr(saveButton)
73
+ archivedPermsFilter = defaultFunc(archivedPermsFilter,x=>true);
74
+ table = defaultStr(tableName,table);
75
+ datas = defaultArray(datas,rows);
76
+ const self = context || {}
77
+ let action = ['create','approve','updateapproved','update','delete','print','archive'];
78
+ const getActionsPerms = isFunction(self.getActionsPerms) ? self.getActionsPerms.bind(self) : undefined;
79
+ let perms = {};
80
+ readOnly = defaultBool(readOnly,false);
81
+ if(getActionsPerms){
82
+ /**** getAction perms est la fonction appelée parl'objet TableData, pour retourner les permission des actions de la tableData */
83
+ perms = getActionsPerms.call(self,{readOnly,perm,isUpdate,currentData,action,data,tableName:table,table,context,datas})
84
+ } else {
85
+ perms = (isNonNullString(perm)? Auth.isAllowed({resource:perm.split(':')[0],action}):Auth.isTableDataAllowed({table,action}));
86
+ }
87
+ if(!printable){
88
+ delete perms.print;
89
+ delete perms.printable;
90
+ }
91
+ if(!archivable){
92
+ delete perms.archive;
93
+ delete perms.archivable;
94
+ }
95
+ if(isUpdate && isObj(data) && (data.wasTransferred || (data.approved && !perms.updateapproved))){
96
+ archived = true;
97
+ }
98
+ rest = defaultObj(rest);
99
+ newElementLabel = defaultStr(newElementLabel,"Nouveau");
100
+ let permsObj = checkPermsActions.call(self,{...defaultObj(perms),isUpdate})
101
+ makePhoneCallProps = defaultObj(makePhoneCallProps);
102
+ self.permsObj = permsObj;
103
+ let save = (!readOnly && !permsObj.canSave || (saveAction === false))? null: {
104
+ text :hasManyData? 'Modifier': textSave,
105
+ title :hasManyData? 'Modifier': textSave,
106
+ isAction : true,
107
+ shortcut : 'save',
108
+ flat : true,
109
+ icon : 'content-save',
110
+ color: Colors.get('green500'),
111
+ onPress : createCallback({context:self,action:'save',callback:onPressToSave})
112
+ }, save2close = (readOnly || save2closeAction === false || (!permsObj.canSave) || (hasManyData && datas.length !== 1))?null:{
113
+ text : textSave+'+ Fermer',
114
+ title : textSave+'+ Fermer',
115
+ isAction : true,
116
+ shortcut : "save2close",
117
+ icon : 'content-save-all-outline',
118
+ flat : true,
119
+ onPress : createCallback({context:self,action:'save2close',callback:onPressToSave})
120
+ }, save2new = (save2newAction !== false && !readOnly && permsObj.canSave2New && !hasManyData)?{
121
+ text : textSave+'& '+newElementLabel,
122
+ title : textSave+'& '+newElementLabel,
123
+ isAction : true,
124
+ shortcut : "save2new",
125
+ icon : 'content-save-edit',
126
+ flat : true,
127
+ onPress : createCallback({context:self,action:'save2new',callback:onPressToSave})
128
+ } : null;
129
+ self.buttonsActions = {
130
+ print : (isUpdate && permsObj.canPrint)?{
131
+ text : 'Imprimer',
132
+ shortcut : 'print',
133
+ isAction : false,
134
+ icon : PRINT_ICON,
135
+ flat : true,
136
+ handleChange : false,
137
+ onPress : createCallback({context:self,action:'print',callback:onPressToPrint})
138
+ }:null,
139
+ save2print : (save || save2close) && permsObj.canPrint ? {
140
+ icon : 'printer-check',
141
+ text : 'Enregistrer + imprimer',
142
+ shortcut : 'save2print',
143
+ isAction : true,
144
+ flat : true,
145
+ title : 'Enregistrer, fermer puis imprimer',
146
+ onPress: createCallback({context:self,action:'save2print',callback:onPressToSave})
147
+ } : null,
148
+ save2close,
149
+ save2new,
150
+ save,
151
+ previous : (hasManyData && datas.length > 0 && currentDataIndex > 0)?{
152
+ icon : 'chevron-left',
153
+ text : 'Précédent',
154
+ shortcut : 'previous',
155
+ isAction : false,
156
+ flat : true,
157
+ title : 'Précédent',
158
+ onPress:onPressToPrevious
159
+ }:null,
160
+ next : (hasManyData && datas.length-1 > currentDataIndex)? {
161
+ icon : 'chevron-right',
162
+ text : 'Suivant',
163
+ shortcut : 'next',
164
+ title : 'Suivant',
165
+ flat : true,
166
+ isAction:false,
167
+ onPress :onPressToNext
168
+ } : null,
169
+ clone : (cloneAction !== false && !readOnly && isUpdate && permsObj.canCreate)?{
170
+ text : 'Dupliquer',
171
+ isAction : true,
172
+ shortcut : 'clone',
173
+ icon : 'content-duplicate',
174
+ flat : true,
175
+ onPress: createCallback({context:self,action:'clone',callback:onPressToSave})
176
+ } : null,
177
+ archive : (isUpdate && !archived && permsObj.canArchive) ?{
178
+ text : 'Archiver',
179
+ isAction : false,
180
+ shortcut : 'archive',
181
+ icon : 'archive',
182
+ handleChange : false,
183
+ flat : true,
184
+ onPress: createCallback({context:self,action:'archive',callback:onPressToArchive||onPressToSave})
185
+ } : null,
186
+ new : isUpdate && (save2new || (perms.create && save2newAction !== false)) ? {
187
+ text : newElementLabel,
188
+ title : newElementLabel,
189
+ isAction : false,
190
+ shortcut : "new",
191
+ icon : 'new-box',
192
+ flat : true,
193
+ onPress : createCallback({context:self,action:'new',callback:onPressToCreateNew})
194
+ } : null,
195
+ makePhoneCall : (canMakePhoneCall && isUpdate)?{
196
+ text : defaultStr(makePhoneCallProps.text,makePhoneCallProps.label,'Appeler'),
197
+ isAction : true,
198
+ icon : defaultStr(makePhoneCallProps.icon,'phone'),
199
+ handleChange : false,
200
+ flat : true,
201
+ onPress : createCallback({context:self,action:'makePhoneCall',force:true,callback:onPressToMakePhoneCall})
202
+ }:null,
203
+ copyToClipboard : (isUpdate)?{
204
+ text : 'Copier',
205
+ icon : COPY_ICON,
206
+ title : 'Copier',
207
+ flat : true,
208
+ isAction : false,
209
+ onPress: createCallback({context:self,action:'copyToClipboard',callback:onPressCopyToClipboard})
210
+ } : null,
211
+ }
212
+ return self.buttonsActions;
213
+ }
214
+
215
+
216
+
217
+
218
+ /*** vérifie les actions qu'à un utilisateur en fonction de ses permission en lecture, en écriture
219
+ * @param arg {object} : L'objet spécifiant les actions par défaut de l'utilisateur
220
+ * c'est objet est un objet de booléen de la forme :
221
+ * isDocUpdate : s'il d'ajit d'une mise à jour du document
222
+ * read : si l'utilisateur a accès en lecture
223
+ * write || create : si l'utilisateur a accès en écriture
224
+ * edit || update : si l'utilisateur a accès en modification
225
+ * remove || delete : si l'utilisateur peut supprimer
226
+ * print || printable : si l'utilisateur peut imprimer le document
227
+ *
228
+ * @return {object} retourne un objet de la forme :
229
+ * canSave : Si l'utilisateur peut enregistrer un élément
230
+ * canUpdate : si l'utilisateur peut modifier la resource
231
+ * canDelete : si l'utilisateur peut supprimer la resource,
232
+ * canSave2New : Si l'utilisateur peut enregistrer et créer un nouvel element
233
+ * canSave2Close : si l'utilisateur peut enregistrer et fermer,
234
+ * canPrint : si l'utilisateur peut imprimer la table data où pas
235
+ */
236
+ export const checkPermsActions = function (arg){
237
+ arg = defaultObj(arg);
238
+ let {isUpdate,print,printable,create,write,archive,archivable,read,remove,update,edit} = arg;
239
+ let canUpdate = isUpdate && defaultBool(update,edit,false);
240
+ let canCreate = defaultBool(create,write,false);
241
+ let canSave = ((canCreate && !isUpdate) || canUpdate );
242
+ let canDelete = defaultBool(remove,arg.delete,false)
243
+ let canPrint = defaultBool(print,printable,false);
244
+ let canArchive = defaultBool(archive,archivable,false)
245
+ return {
246
+ canArchive,
247
+ canPrint,
248
+ canSave,
249
+ canCreate,
250
+ canSave2Close:canSave,
251
+ canSave2New : canSave && canCreate,
252
+ canDelete,
253
+ canRemove : canDelete,
254
+ }
255
+ }
256
+
257
+ export const createCallback = ({context,action,callback,force}) =>{
258
+ if(force === true && isFunction(callback)) return callback;
259
+ return (a1,a2,a3,a4) =>{
260
+ context = context || {};
261
+ if(action && typeof action == "string"){
262
+ context.clickedEl = action;
263
+ }
264
+ if(isFunction(callback)) callback.call(context,a1,a2,a3,a4);
265
+ return true;
266
+ }
267
+ }
268
+
269
+ export const getScreenName = (screenName)=>{
270
+ if(isObj(screenName)){
271
+ screenName = defaultStr(screenName.table,screenName.tableName);
272
+ }
273
+ return getTableDataRouteName(screenName);
274
+ }
@@ -4,6 +4,8 @@ import {Stack,setInitialRouteName } from "$cnavigation";
4
4
  import React from "$react";
5
5
  import DrawerNavigator from "./Drawer";
6
6
 
7
+ export * from "./utils";
8
+
7
9
  export default function NavigationComponent (props){
8
10
  let {state,hasGetStarted,initialRouteName,extra} = props;
9
11
  const allScreens = initScreens({Factory:Stack,ModalFactory:Stack,filter:({name,Screen})=>{
@@ -0,0 +1,51 @@
1
+ // Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style
3
+ // license that can be found in the LICENSE file.
4
+ import {navigate,sanitizeName} from "$cnavigation";
5
+ import {routeName as tableDataRouteName} from "$screens/TableData/utils";
6
+ import {isNonNullString,defaultObj,isObj} from "$utils";
7
+
8
+ export const navigateToTableData = function(tableName,params,actionType){
9
+ if(isNonNullString(tableName)){
10
+ tableName = {tableName};
11
+ }
12
+ if(isObj(tableName)){
13
+ params = {...tableName,...defaultObj(params)};
14
+ }
15
+ params = defaultObj(params);
16
+ tableName = defaultStr(params.tableName,params.table).toUpperCase();
17
+ if(!tableName) return;
18
+ const {perm} = params;
19
+ let isAllowed = true;
20
+ const isTableData = actionType =='table_data';
21
+ if(isNonNullString(perm)){
22
+ isAllowed = Auth.isAllowedFromStr(perm)
23
+ } else if(actionType =='struct_data') {
24
+ isAllowed = Auth.isStructDataAllowed({table:tableName})
25
+ } else if(isTableData){
26
+ isAllowed = Auth.isTableDataAllowed({table:tableName});
27
+ }
28
+ if(!isAllowed){
29
+ return Auth.showError();
30
+ }
31
+ params.routeName = buildScreenRoute(tableName,tableDataRouteName);
32
+ return navigate(params)
33
+ }
34
+
35
+ export const buildScreenRoute = function(tableName,parent){
36
+ if(!isNonNullString(tableName)) return undefined;
37
+ parent = defaultStr(parent,tableDataRouteName);
38
+ if(parent){
39
+ parent= parent.rtrim("/")+"/";
40
+ }
41
+ return sanitizeName(parent+tableName);
42
+ }
43
+
44
+ export const getTableDataRouteName = function(tableName){
45
+ return buildScreenRoute(tableName,tableDataRouteName);
46
+ }
47
+
48
+ /*** permet d'obtenir le lien vers l'écran table data permettant de lister les données de la table data */
49
+ export const getTableDataListRouteName = function(tableName){
50
+ return buildScreenRoute(tableName,tableDataRouteName+"/LIST/");
51
+ }