@fto-consult/expo-ui 8.76.8 → 8.77.2

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.
@@ -1,38 +1,38 @@
1
-
2
- module.exports = {
3
- "@emotion/native": "^11.11.0",
4
- "@expo/html-elements": "^0.5.1",
5
- "@expo/vector-icons": "^14.0.0",
6
- "@pchmn/expo-material3-theme": "^1.3.2",
7
- "@react-native-community/netinfo": "11.1.0",
8
- "@react-native/assets-registry": "^0.72.0",
9
- "react-native-get-random-values": "~1.8.0",
10
- "@react-navigation/native": "^6.1.17",
11
- "@react-navigation/native-stack": "^6.9.26",
12
- "@react-navigation/stack": "^6.3.29",
13
- "@shopify/flash-list": "1.6.3",
14
- "expo": "^50.0.17",
15
- "expo-camera": "~14.1.3",
16
- "expo-clipboard": "~5.0.1",
17
- "expo-font": "~11.10.3",
18
- "expo-image-picker": "~14.7.1",
19
- "expo-linking": "~6.2.2",
20
- "expo-sharing": "~11.10.0",
21
- "expo-sqlite": "~13.4.0",
22
- "expo-status-bar": "~1.11.1",
23
- "expo-system-ui": "~2.9.4",
24
- "expo-web-browser": "~12.8.2",
25
- "react": "18.2.0",
26
- "react-native": "0.73.6",
27
- "react-native-safe-area-context": "4.8.2",
28
- "react-native-screens": "~3.29.0",
29
- "react-native-svg": "14.1.0",
30
- "react-native-webview": "13.6.4",
31
- "react-native-gesture-handler": "~2.14.0",
32
- "react-native-reanimated": "~3.6.2",
33
- "react-native-view-shot": "3.8.0",
34
- "expo-intent-launcher": "~10.11.0",
35
- "expo-image-manipulator": "~11.8.0",
36
- "expo-document-picker": "~11.10.1"
37
- };
1
+
2
+ module.exports = {
3
+ "@emotion/native": "^11.11.0",
4
+ "@expo/html-elements": "^0.5.1",
5
+ "@expo/vector-icons": "^14.0.0",
6
+ "@pchmn/expo-material3-theme": "^1.3.2",
7
+ "@react-native-community/netinfo": "11.1.0",
8
+ "@react-native/assets-registry": "^0.72.0",
9
+ "react-native-get-random-values": "~1.8.0",
10
+ "@react-navigation/native": "^6.1.17",
11
+ "@react-navigation/native-stack": "^6.9.26",
12
+ "@react-navigation/stack": "^6.3.29",
13
+ "@shopify/flash-list": "1.6.3",
14
+ "expo": "^50.0.17",
15
+ "expo-camera": "~14.1.3",
16
+ "expo-clipboard": "~5.0.1",
17
+ "expo-font": "~11.10.3",
18
+ "expo-image-picker": "~14.7.1",
19
+ "expo-linking": "~6.2.2",
20
+ "expo-sharing": "~11.10.0",
21
+ "expo-sqlite": "~13.4.0",
22
+ "expo-status-bar": "~1.11.1",
23
+ "expo-system-ui": "~2.9.4",
24
+ "expo-web-browser": "~12.8.2",
25
+ "react": "18.2.0",
26
+ "react-native": "0.73.6",
27
+ "react-native-safe-area-context": "4.8.2",
28
+ "react-native-screens": "~3.29.0",
29
+ "react-native-svg": "14.1.0",
30
+ "react-native-webview": "13.6.4",
31
+ "react-native-gesture-handler": "~2.14.0",
32
+ "react-native-reanimated": "~3.6.2",
33
+ "react-native-view-shot": "3.8.0",
34
+ "expo-intent-launcher": "~10.11.0",
35
+ "expo-image-manipulator": "~11.8.0",
36
+ "expo-document-picker": "~11.10.1"
37
+ };
38
38
 
@@ -1,18 +1,18 @@
1
- {
2
- "build": {
3
- "development": {
4
- "developmentClient": true,
5
- "distribution": "internal"
6
- },
7
- "preview": {
8
- "distribution": "internal",
9
- "android": {
10
- "buildType": "apk"
11
- }
12
- },
13
- "production": {}
14
- },
15
- "submit": {
16
- "production": {}
17
- }
18
- }
1
+ {
2
+ "build": {
3
+ "development": {
4
+ "developmentClient": true,
5
+ "distribution": "internal"
6
+ },
7
+ "preview": {
8
+ "distribution": "internal",
9
+ "android": {
10
+ "buildType": "apk"
11
+ }
12
+ },
13
+ "production": {}
14
+ },
15
+ "submit": {
16
+ "production": {}
17
+ }
18
+ }
@@ -47,9 +47,17 @@ export default {
47
47
  la fonction loginPropsMutator de muter les props du composant Login par défaut, prise en compte lorsque le composant de connexion n'est pas remplacer par celui définit dans la prop login,
48
48
  @param {object} props : les propriétés de la fonction login, les props ont des propriétés suivantes :
49
49
  {
50
+ signIn : ()=><any>, la fonction permettant de connecter l'utilisateur,
50
51
  onSuccess : ({object})=><Any>, la fonction appelée en cas de success
51
52
  setState : (newState)=>(...newState),//la fonction utilisée pour update le state du composant. elle doit remplacer le state du composant
52
- state : <Object: data,...rest>, le state actuel à l'instant t du composant
53
+ state : <Object: data,...rest>, le state actuel à l'instant t du composant,
54
+
55
+ //prend en paramètre une référence pointant sur le composant $ecomponents/Button et retourne les actions possible sur ledit button
56
+ getButtonAction : (buttonRef) => <{
57
+ enable : x=>typeof buttonRef?.current?.enable =="function" && buttonRef.current.enable(),
58
+ disable : x=> typeof buttonRef?.current?.disable =="function" && buttonRef?.current.disable(),
59
+ isDisabled : x=> typeof buttonRef?.current?.isDisabled ==="function" && buttonRef.current?.isDisabled(),
60
+ },
53
61
  nextButton : <Object :
54
62
  {
55
63
  ref : nextButtonRef, //la référence vers le bouton next (le boutn Suivant)
@@ -72,6 +80,7 @@ export default {
72
80
  formName <string>, //le nom du formulaire Form, passé à la formData
73
81
  nextButtonRef <{current:<any>}>, la référence vers le bouton next
74
82
  previousButtonRef <{current:<any>}, la référence vers le bouton previous
83
+ formProps : (object), //les props à passer au composant FormData
75
84
  }
76
85
  @return <{object}>, l'objet a retourné doit être de la forme :
77
86
  {
@@ -80,6 +89,13 @@ export default {
80
89
  containerProps : <object>, les props du composant <Surface/>, le composant qui est le wrapper du composant FormData en charge de récupérer les données de l'interface de connexion
81
90
  canSubmit : ({step,...rest})=> <boolean>, //si les donées du formulaire peuvent être submit
82
91
  beforeSubmit : ({step,data,...rest})=><void>, //la fonction appélée immédiatement avant le submit des donénes
92
+ renderNextButton : <boolean>, //si le bouton next sera rendu
93
+ renderPreviousButton : <boolean>, //si le bouton previous sera rendu
94
+ title : <string>, //le titre de l'interface de connexion, titre personnalisé s'il y a lieu
95
+ wrapperProps : <func({withScreen,withScrollView,state,...rest})=><object>,object>, //les props du composant wrapper,
96
+ containerProps : <object>, //les props du composant container, idem à ceux du composant $ecomponents/Surface
97
+ contentProps : <object>, //les props du composant parent direct à la form rendu par le composatn formData, idem à ceux du composant $ecomponents/Surface
98
+ onSuccess : (object)=><boolean | any>, la fonction de rappel appelée lorsque l'utilisateur a été connecté, via la fonction signIn. si onSuccess retourne false, alors l'action par défaut de redirection de l'utilisateur via l'interface de connexion ne sera pas appelée.
83
99
  ...loginProps {object}, les props Supplémentaires à passer au composant FormData utilisé pour le rendu du formulaire de connexion
84
100
  }
85
101
  */
package/expo-ui.json CHANGED
@@ -1,11 +1,11 @@
1
- {
2
- "name": "@fto-consult/expo-ui",
3
- "version": "6.44.4",
4
- "description": "Bibliothèque de composants UI Expo,react-native",
5
- "bin": {
6
- "expo-ui": "./bin/index.js"
7
- },
8
- "author": "Boris Fouomene",
9
- "license": "ISC",
10
- "homepage": "https://github.com/borispipo/expo-ui#readme"
1
+ {
2
+ "name": "@fto-consult/expo-ui",
3
+ "version": "6.44.4",
4
+ "description": "Bibliothèque de composants UI Expo,react-native",
5
+ "bin": {
6
+ "expo-ui": "./bin/index.js"
7
+ },
8
+ "author": "Boris Fouomene",
9
+ "license": "ISC",
10
+ "homepage": "https://github.com/borispipo/expo-ui#readme"
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "8.76.8",
3
+ "version": "8.77.2",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "react-native-paper-doc": "https://github.com/callstack/react-native-paper/tree/main/docs/docs/guides",
6
6
  "scripts": {
@@ -70,7 +70,7 @@
70
70
  "dependencies": {
71
71
  "@emotion/react": "^11.11.1",
72
72
  "@faker-js/faker": "^8.0.2",
73
- "@fto-consult/common": "^4.48.3",
73
+ "@fto-consult/common": "^4.50.8",
74
74
  "@fto-consult/expo-ui": "^8.73.1",
75
75
  "apexcharts": "^3.49.0",
76
76
  "file-saver": "^2.0.5",
package/src/auth/Login.js CHANGED
@@ -2,6 +2,7 @@ import React from "$react";
2
2
  import {isNonNullString,isObj,defaultNumber,defaultStr,uniqid,extendObj,isFunction} from "$cutils";
3
3
  import {navigate} from "$cnavigation";
4
4
  import FormData from "$ecomponents/Form/FormData/FormData";
5
+ import { Action } from "$ecomponents/Form";
5
6
  import {getForm} from "$ecomponents/Form/utils";
6
7
  import Button from "$ecomponents/Button";
7
8
  import notify from "$notify";
@@ -28,7 +29,7 @@ const WIDTH = 400;
28
29
  export default function LoginComponent(props){
29
30
  let {formName,step,appBarProps,onSuccess,withPortal,testID} = props;
30
31
  const {auth:{loginPropsMutator,Login}} = useContext();
31
- const loginTitle = getTitle();
32
+ let loginTitle = getTitle();
32
33
  testID = defaultStr(testID,"RN_Auth.LoginComponent");
33
34
  formName = React.useRef(uniqid(defaultStr(formName,"login-formname"))).current;
34
35
  const nextButtonRef = React.useRef(null);
@@ -106,23 +107,79 @@ export default function LoginComponent(props){
106
107
  onSuccess = {onSuccess}
107
108
  auth = {auth}
108
109
  />
109
- const getButtonAction = (buttonRef)=>{
110
- return {
111
- ref : buttonRef,
112
- isDisabled : x=> typeof buttonRef?.current?.isDisabled ==="function" && buttonRef.current?.isDisabled(),
113
- enable : x=>typeof buttonRef?.current?.enable =="function" && buttonRef.current.enable(),
114
- disable : x=> typeof buttonRef?.current?.disable =="function" && buttonRef?.current.disable(),
110
+ const getButtonAction = React.useMemo(()=>{
111
+ return (buttonRef)=>{
112
+ buttonRef = buttonRef || React.createRef();
113
+ return {
114
+ ref : buttonRef,
115
+ isDisabled : x=> typeof buttonRef?.current?.isDisabled ==="function" && buttonRef.current?.isDisabled(),
116
+ enable : x=>{
117
+ return typeof buttonRef?.current?.enable =="function" && buttonRef.current.enable();
118
+ },
119
+ disable : x=> {
120
+ return typeof buttonRef?.current?.disable =="function" && buttonRef?.current.disable()
121
+ },
122
+ }
115
123
  }
116
- }
124
+ },[]);
117
125
  const nextButton = getButtonAction(nextButtonRef),
118
126
  prevButton = getButtonAction(previousButtonRef);
119
- const {header,
127
+ const setIsLoading = (buttonRef,bool)=>{
128
+ if(typeof buttonRef?.current?.setIsLoading == 'function'){
129
+ return buttonRef.current?.setIsLoading(bool)
130
+ }
131
+ }
132
+ const beforeSubmitRef = React.useRef(null);
133
+ const canSubmitRef = React.useRef(null);
134
+ const onSuccesRef = React.useRef(null);
135
+ const signIn = ()=>{
136
+ const form = _getForm();
137
+ if(!form){
138
+ notifyUser("Impossible de valider le formulaire car celui-ci semble invalide")
139
+ return;
140
+ }
141
+ if(!form.isValid()){
142
+ notifyUser(form.getErrorText());
143
+ return;
144
+ }
145
+ const data = getData();
146
+ const canSubmit = typeof canSubmitRef.current == 'function'? canSubmitRef.current : w=>true;
147
+ const beforeSubmit = typeof beforeSubmitRef.current === 'function' ? beforeSubmitRef.current : ()=> true;
148
+ const args = {...state,data,form,state,setState,nextButtonRef,previousButtonRef};
149
+ const cS = canSubmit(args);
150
+ if(typeof cS === 'string' && cS){
151
+ return notifyUser(cS);
152
+ }
153
+ if(cS !== false && beforeSubmit(args) !== false){
154
+ Preloader.open("vérification ...");
155
+ setIsLoading(nextButtonRef,true);
156
+ return auth.signIn(data).then((a)=>{
157
+ if(typeof onSuccesRef.current =='function' && onSuccesRef.current(a)=== false) return;
158
+ if(isFunction(onSuccess)){
159
+ onSuccess(data);
160
+ } else {
161
+ navigate("Home");
162
+ }
163
+ }).finally(()=>{
164
+ Preloader.close();
165
+ setIsLoading(nextButtonRef,false);
166
+ })
167
+ }
168
+ }
169
+ const {header : Header,
120
170
  headerTopContent:HeaderTopContent,
121
171
  containerProps : customContainerProps,
122
172
  contentProps : customContentProps,
123
- withScrollView:customWithScrollView,children,initialize,contentTop,data:loginData,canGoToNext,keyboardEvents,onSuccess:onLoginSuccess,mutateData,beforeSubmit:beforeSubmitForm,canSubmit:canSubmitForm,onStepChange,...loginProps} = loginPropsMutator({
173
+ formProps,
174
+ wrapperProps : cWrapperProps,
175
+ title : customTitle,
176
+ withScrollView:customWithScrollView,children,initialize,contentTop,renderNextButton,renderPreviousButton,data:loginData,canGoToNext,keyboardEvents,onSuccess:onLoginSuccess,beforeSubmit:beforeSubmitForm,canSubmit:canSubmitForm,onStepChange,...loginProps} = loginPropsMutator({
124
177
  ...state,
178
+ getButtonAction,
179
+ data : getData(),
180
+ signIn,
125
181
  setState,
182
+ setIsLoading,
126
183
  state,
127
184
  nextButton,
128
185
  prevButton,
@@ -138,13 +195,18 @@ export default function LoginComponent(props){
138
195
  ProviderSelector,
139
196
  previousButtonRef,
140
197
  });
198
+ if(isNonNullString(customTitle)){
199
+ loginTitle = customTitle;
200
+ }
141
201
  const containerProps = defaultObj(customContainerProps);
142
202
  const contentProps = defaultObj(customContentProps);
143
203
  /****la fonction à utiliser pour vérifier si l'on peut envoyer les données pour connextion
144
204
  * par défaut, on envoie les données lorssqu'on est à l'étappe 2
145
205
  * **/
146
- const canSubmit = typeof canSubmitForm =='function'? canSubmitForm : ({step})=>step >= 2;
147
- const beforeSubmit = typeof beforeSubmitForm =='function'? beforeSubmitForm : x=> true;
206
+ canSubmitRef.current = typeof canSubmitForm =='function'? canSubmitForm : ({step})=>step >= 2;
207
+ beforeSubmitRef.current = typeof beforeSubmitForm =='function'? beforeSubmitForm : x=> true;
208
+ onSuccesRef.current = onLoginSuccess;
209
+
148
210
  const goToNext = ()=>{
149
211
  let step = state.step;
150
212
  const data = getData();
@@ -175,27 +237,7 @@ export default function LoginComponent(props){
175
237
  nextButtonRef.current?.enable();
176
238
  }
177
239
  if(step > 1){
178
- const cS = canSubmit(args);
179
- if(typeof cS === 'string' && cS){
180
- return notifyUser(cS);
181
- }
182
- if(cS && beforeSubmit(args) !== false){
183
- ///pour modifier automatiquement la données à mettre à jour
184
- if(typeof mutateData =='function'){
185
- mutateData(data);
186
- }
187
- Preloader.open("vérification ...");
188
- return auth.signIn(data).then((a)=>{
189
- if(typeof onLoginSuccess =='function' && onLoginSuccess(a)=== false) return;
190
- if(isFunction(onSuccess)){
191
- onSuccess(data);
192
- } else {
193
- navigate("Home");
194
- }
195
- }).finally(()=>{
196
- Preloader.close();
197
- })
198
- }
240
+ signIn();
199
241
  } else {
200
242
  setState({...state,step:step+1,data})
201
243
  }
@@ -219,8 +261,10 @@ export default function LoginComponent(props){
219
261
  const mediaQueryUpdateStyle = (a)=>{
220
262
  return StyleSheet.flatten([updateMediaQueryStyle(),contentProps.style]);
221
263
  };
222
- const wrapperProps = withPortal ? {appBarProps,authRequired:false,title:loginTitle,withScrollView} : { style:styles.wrapper};
264
+ const wProps = defaultObj(typeof cWrapperProps =="function"? cWrapperProps({...state,setState,formName,state,withPortal,withScreen:withPortal,withScrollView,state,formName}) : cWrapperProps);
265
+ const wrapperProps = withPortal ? {appBarProps,authRequired:false,title:loginTitle,withScrollView,...wProps} : { ...wProps,style:[styles.wrapper,wProps.style]};
223
266
  const sH = React.isComponent(HeaderTopContent)? <HeaderTopContent mediaQueryUpdateStyle = {mediaQueryUpdateStyle} /> : React.isValidElement(HeaderTopContent)? HeaderTopContent : null;
267
+ const header = React.isComponent(Header) ? <Header mediaQueryUpdateStyle = {mediaQueryUpdateStyle}/> : React.isValidElement(Header)? Header : null;
224
268
  return <Wrapper testID = {testID+"_Wrapper" }{...wrapperProps}>
225
269
  <DialogProvider ref={dialogProviderRef}/>
226
270
  {sH}
@@ -237,32 +281,34 @@ export default function LoginComponent(props){
237
281
  responsive = {false}
238
282
  {...loginProps}
239
283
  fields = {loginFields}
240
- formProps = {{
284
+ formProps = {extendObj(true,{},{
241
285
  keyboardEvents : {
242
- ...defaultObj(keyboardEvents),
243
286
  enter : ({formInstance})=>{
244
287
  goToNext();
245
- }
288
+ },
246
289
  }
247
- }}
290
+ },formProps)}
248
291
  data = {extendObj(state.data,loginData)}
249
292
  >
250
293
  <>
251
294
  {React.isValidElement(contentTop)? contentTop : null}
252
- {hasLoginFields?<View testID={testID+"_ButtonsContainer"} style={[styles.buttonWrapper]}>
253
- <Button
295
+ {renderNextButton !== false || renderPreviousButton !== false ? <>
296
+ {hasLoginFields?<View testID={testID+"_ButtonsContainer"} style={[styles.buttonWrapper]}>
297
+ {renderNextButton !== false ? <Action
254
298
  ref = {nextButtonRef}
255
299
  primary
300
+ formName={formName}
256
301
  mode = "contained"
257
302
  rounded
258
303
  style = {styles.button}
259
304
  onPress = {goToNext}
260
305
  icon = {state.step == 1? 'arrow-right':'login'}
261
306
  surface
307
+ testID = {testID+"_NextButton"}
262
308
  >
263
309
  {state.step == 1? 'Suivant' : 'Connexion' }
264
- </Button>
265
- {state.step>=2 ? <Button
310
+ </Action> : null}
311
+ {renderPreviousButton !== false && state.step>=2 ? <Button
266
312
  onPress = {goToFirstStep}
267
313
  ref = {previousButtonRef}
268
314
  mode = "contained"
@@ -272,10 +318,12 @@ export default function LoginComponent(props){
272
318
  secondary
273
319
  surface
274
320
  icon = {'arrow-left'}
321
+ testID = {testID+"_PrevButton"}
275
322
  >
276
323
  Précédent
277
324
  </Button> : null}
278
325
  </View> : null}
326
+ </> : null}
279
327
  </>
280
328
  </FormData>
281
329
  {React.isValidElement(children) ? children : null}
@@ -344,6 +392,25 @@ const styles = StyleSheet.create({
344
392
  });
345
393
 
346
394
  LoginComponent.propTypes = {
395
+ /****
396
+ les props du composant Wrapper, peut être une fonction où un objet
397
+ - s'il s'agit d'une fonction : elle est définie comme suit :
398
+ ({withScreen<boolean>,withPortal<boolean>,withScrolView<boolean>})=> <object>,
399
+
400
+ */
401
+ wrapperProps : PropTypes.oneOfType([
402
+ PropTypes.func,
403
+ PropTypes.object,
404
+ ]),
405
+ /***
406
+ les props du composant Container, enfant hiérachique au composant Wrapper
407
+ idem aux props du composant Surface
408
+ */
409
+ containerProps : PropTypes.shape(defaultObj(Surface.propTypes)),
410
+ //les props du composant Surface, parent direct du composant FormData utile pour le rendu du form
411
+ contentProps : PropTypes.shape(defaultObj(Surface.propTypes)),
412
+ //les props du form data, idem à ceux du composant FormData
413
+ formProps : PropTypes.object,
347
414
  headerTopContent : PropTypes.oneOfType([
348
415
  PropTypes.func,
349
416
  PropTypes.node,
@@ -352,12 +419,10 @@ LoginComponent.propTypes = {
352
419
  header : PropTypes.oneOfType([
353
420
  PropTypes.node,
354
421
  PropTypes.element,
422
+ PropTypes.func,
355
423
  ]),
424
+ onSuccess : PropTypes.func, //la fonctino appelée lorsque l'utilisateur a été connecté, lorsque l'action liée à la fonction signIn de auth s'est terminée correctement
425
+ renderNextButton : PropTypes.bool,//si le bouton next sera rendu
426
+ renderPreviousButton : PropTypes.bool,//si le bouton previous sera rendu
356
427
  }
357
428
 
358
- /*** les loginProps sont les porps à passer au composant FormData
359
- */
360
- const loginPropTypes = {
361
- containerProps : PropTypes.object, //les props à passer au container
362
- ...FormData.propTypes, //les props type du composant form data
363
- }