@fto-consult/expo-ui 8.6.1 → 8.7.1

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.
@@ -11,6 +11,7 @@ module.exports = {
11
11
  "@react-navigation/stack": "^6.3.20",
12
12
  "@shopify/flash-list": "1.6.3",
13
13
  "expo": "^50.0.2",
14
+ "expo-barcode-scanner": "~12.9.2",
14
15
  "expo-camera": "~14.0.1",
15
16
  "expo-clipboard": "~5.0.1",
16
17
  "expo-font": "~11.10.2",
package/bin/create-app.js CHANGED
@@ -116,10 +116,13 @@ const createAPPJSONFile = (projectRoot,{name,version})=>{
116
116
  "cameraPermission" : `Autoriser $(PRODUCT_NAME) à accéder à votre camera`
117
117
  }, cameraPluginsOptions = {
118
118
  "cameraPermission" : `Autoriser $(PRODUCT_NAME) à accéder à votre camera`
119
+ }, barCodePermission = {
120
+ "cameraPermission": "Autoriser $(PRODUCT_NAME) à accéder à la caméra."
119
121
  };
120
122
  const plugins = [
121
123
  ["expo-image-picker",imagePluginOptions],
122
- ["expo-camera",cameraPluginsOptions]
124
+ ["expo-camera",cameraPluginsOptions],
125
+ ["expo-barcode-scanner",barCodePermission]
123
126
  ];
124
127
  appSheme = name? sanitizeFileName(name).replace(/ /g, '') : null;
125
128
  const appJSONPath = path.join(projectRoot,"app.json");
@@ -176,14 +179,16 @@ const createAPPJSONFile = (projectRoot,{name,version})=>{
176
179
  if(!Array.isArray(appPlugins)){
177
180
  appPlugins = plugins;
178
181
  } else {
179
- let hasFoundCamera = false, hasFoundImagePicker = false;
182
+ let hasFoundCamera = false, hasFoundImagePicker = false,hasFoundBarCode = false;
180
183
  appPlugins.map(pl=>{
181
184
  if(Array.isArray(pl)){
182
185
  if(typeof pl[0] ==="expo-image-picker"){
183
186
  hasFoundImagePicker = true;
184
187
  } else if(pl[0] === "expo-camera"){
185
188
  hasFoundCamera = true;
186
- }
189
+ } else if(pl[0] =="expo-barcode-scanner"){
190
+ hasFoundBarCode = true;
191
+ }
187
192
  }
188
193
  });
189
194
  if(!hasFoundImagePicker){
@@ -192,6 +197,9 @@ const createAPPJSONFile = (projectRoot,{name,version})=>{
192
197
  if(!hasFoundCamera){
193
198
  appPlugins.push(plugins[1]);
194
199
  }
200
+ if(!hasFoundBarCode){
201
+ appPlugins.push(plugins[2]);
202
+ }
195
203
  }
196
204
  appJSONManager.set({
197
205
  expo : {plugins:appPlugins}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "8.6.1",
3
+ "version": "8.7.1",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "scripts": {
6
6
  "clear-npx-cache": "npx clear-npx-cache",
@@ -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.11.1",
73
+ "@fto-consult/common": "^4.11.2",
74
74
  "@fto-consult/node-utils": "^1.4.7",
75
75
  "apexcharts": "^3.45.2",
76
76
  "commander": "^11.1.0",
@@ -0,0 +1,148 @@
1
+ import React, { useState, useEffect,useMemo } from '$react';
2
+ import { View, StyleSheet} from 'react-native';
3
+ import { BarCodeScanner } from 'expo-barcode-scanner';
4
+ import theme from "$theme";
5
+ import ActivityIndicator from "$ecomponents/ActivityIndicator";
6
+ import Label from "$ecomponents/Label";
7
+ import PropTypes from "prop-types";
8
+ import { isNonNullString,defaultStr } from '$cutils';
9
+ import Button from "$ecomponents/Button";
10
+ import Dialog from "$ecomponents/Dialog";
11
+
12
+ export const scannerTypes = {back:"back",front:"front"};
13
+
14
+ /***@see : https://docs.expo.dev/versions/latest/sdk/bar-code-scanner/ */
15
+ export default function App({onScan,onGrantAccess,testID,onDenyAccess,scannerProps,onCancel,dialogProps}) {
16
+ testID = defaultStr(testID,"RN_BarCodeScanner");
17
+ const [hasPermission, setHasPermission] = useState(null);
18
+ const [visible,setVisible] = useState(true);
19
+ dialogProps = Object.assign({},dialogProps);
20
+ scannerProps = Object.assign({},scannerProps);
21
+ const prevVisible = React.usePrevious(visible);
22
+ const cancelRef = React.useRef(false);
23
+ const cancel = ()=>{
24
+ cancelRef.current = true;
25
+ setVisible(false);
26
+ }
27
+ const getCameraType = ()=>{
28
+ let {type} = scannerProps;
29
+ if(isNonNullString(type)){
30
+ type = type.toLowerCase().trim();
31
+ } else type = scannerTypes.back;
32
+ if(!scannerTypes[type]){
33
+ type = scannerTypes.back;
34
+ }
35
+ return type;
36
+ }
37
+ const sType = useMemo(()=>{
38
+ return getCameraType();
39
+ },[scannerProps.type]);
40
+ const [scannerType,setScannerType] = useState(sType);
41
+ useEffect(()=>{
42
+ const type = getCameraType();
43
+ if(type !== scannerType){
44
+ setScannerType(type);
45
+ }
46
+ },scannerProps.type)
47
+ const isBack = scannerType === scannerTypes.back;
48
+ useEffect(() => {
49
+ const getBarCodeScannerPermissions = async () => {
50
+ const { status } = await BarCodeScanner.requestPermissionsAsync();
51
+ setHasPermission(status === 'granted');
52
+ };
53
+
54
+ getBarCodeScannerPermissions();
55
+ }, []);
56
+
57
+ const handleBarCodeScanned = ({ type, data,...rest }) => {
58
+ //setScanned(true);
59
+ if(typeof onScan =="function"){
60
+ onScan({type,data,code:data,barCode:data,...rest});
61
+ }
62
+ setVisible(false);
63
+ };
64
+ useEffect(()=>{
65
+ if(hasPermission ===false){
66
+ if(typeof onDenyAccess =="function"){
67
+ return onDenyAccess();
68
+ }
69
+ } else if(hasPermission !== null){
70
+ if(typeof onGrantAccess =="function"){
71
+ onGrantAccess();
72
+ }
73
+ }
74
+ },[hasPermission]);
75
+ useEffect(()=>{
76
+ if(prevVisible === visible) return;
77
+ if(prevVisible && !visible && cancelRef.current && typeof onCancel =="function"){
78
+ onCancel();
79
+ }
80
+ cancelRef.current = false;
81
+ },[visible]);
82
+ const switchCameraBtn = {
83
+ text : "Pivoter la camera",
84
+ icon : "camera-flip",
85
+ tooltip : `Cliquez pour basculer à la camera ${isBack ? "frontable":"arrière"}`,
86
+ onPress : ()=>{
87
+ setScannerType(isBack ? scannerTypes.front : scannerTypes.back);
88
+ }
89
+ };
90
+ return <Dialog
91
+ fullPage
92
+ actions={[switchCameraBtn]}
93
+ title = {`Scanner un code barre`}
94
+ {...dialogProps}
95
+ onBackActionPress={cancel}
96
+ visible = {visible}
97
+ >
98
+ {hasPermission === null || hasPermission === false ? <View style={[styles.center]}>
99
+ {hasPermission === false ? <Label fontSize={18} error textBold>Accès à la camera refusée. Vous devez autoriser l'accès à la camera.</Label> :
100
+ <View style={[styles.row]}>
101
+ <Label fontSize={18} warning textBold>Demande d'autorisation pour l'accès à la camera...</Label>
102
+ <ActivityIndicator size={'large'}/>
103
+ </View>}
104
+ </View> : <View style={[theme.styles.flex1]} testID={testID}>
105
+ <BarCodeScanner
106
+ ratio='16:9'
107
+ testID={testID+"_ScannerContent"}
108
+ {...scannerProps}
109
+ type={scannerType}
110
+ style={[theme.styles.flex1,{width:"100%",height:"100%"},scannerProps.style]}
111
+ onBarCodeScanned={handleBarCodeScanned}
112
+ />
113
+ <View style={[styles.row,theme.styles.w100]}>
114
+ <Button
115
+ primary
116
+ {...switchCameraBtn}
117
+ style={[theme.styles.p1]}
118
+ />
119
+ <Button
120
+ error
121
+ children = {"Annuler"}
122
+ icon = "camera-off"
123
+ title = {"Cliquez pour annuler l'opération"}
124
+ onPress = {cancel}
125
+ />
126
+ </View>
127
+ </View>}
128
+ </Dialog>;
129
+ }
130
+ const styles = StyleSheet.create({
131
+ center : {
132
+ justifyContent : "center",
133
+ alignItems : "center",
134
+ flexDirection : "column",
135
+ flex : 1,
136
+ },
137
+ row : {
138
+ flexDirection : "row",
139
+ justifyContent : "center",
140
+ alignItems : "center",
141
+ flexWrap :"wrap",
142
+ }
143
+ });
144
+ BarCodeScanner.propTypes = {
145
+ onScan : PropTypes.func,
146
+ onGrantAccess : PropTypes.func, //lorsque la permission est allouée
147
+ onDenyAccess : PropTypes.func, //lorsque la permission est refusée
148
+ }
@@ -0,0 +1,3 @@
1
+ export default function BarCodeScanner(){
2
+ return null;
3
+ }