@fto-consult/expo-ui 1.2.3 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/babel.config.alias.js +7 -0
- package/package.json +102 -101
- package/src/auth/Login.js +19 -3
- package/src/auth/ThemeSelector/index.js +197 -0
- package/src/auth/ThemeSelector/utils.js +141 -0
- package/src/{navigation/Drawer/ProfilAvatar → auth/avatarProps}/defaultAvatar.js +0 -0
- package/src/auth/avatarProps/index.js +22 -0
- package/src/components/Dropdown/index.js +1 -0
- package/src/components/HeavyScreen/utils.js +1 -0
- package/src/components/List/Common.js +2 -2
- package/src/components/Menu/Menu.js +4 -4
- package/src/components/SimpleSelect/index.js +1 -0
- package/src/media/index.js +3 -7
- package/src/navigation/Drawer/ProfilAvatar/index.js +11 -11
- package/src/screens/Auth/Profile.js +97 -0
- package/src/screens/Auth/SignIn.js +29 -0
- package/src/screens/Auth/index.js +6 -28
- package/src/screens/index.js +1 -1
- package/src/screens/mainScreens.js +1 -1
package/babel.config.alias.js
CHANGED
|
@@ -17,8 +17,15 @@ module.exports = (opts)=>{
|
|
|
17
17
|
r["$emedia"] = path.resolve(expo,"media");
|
|
18
18
|
r["$enavigation"] = path.resolve(expo,"navigation");
|
|
19
19
|
r["$escreens"] = path.resolve(expo,"screens");
|
|
20
|
+
r["$emainScreens"] = path.resolve(expo,"screens","mainScreens");
|
|
21
|
+
///les screens principaux de l'application
|
|
22
|
+
r["$mainScreens"] = r["$mainScreens"] || r["$emainScreens"];
|
|
20
23
|
r["$escreen"] = path.resolve(expo,"layouts/Screen");
|
|
21
24
|
r["$eassets"] = path.resolve(dir,"assets");
|
|
25
|
+
r["$ethemeSelectorComponent"] = path.resolve(expo,"auth","ThemeSelector");
|
|
26
|
+
/*** le composant permettant de sélectionner un theme utilisateur */
|
|
27
|
+
r["$themeSelectorComponent"] = r["$themeSelectorComponent"] || r["$ethemeSelectorComponent"];
|
|
28
|
+
|
|
22
29
|
|
|
23
30
|
///pour personnaliser les écrans de l'application, il suffit de redefinir l'alis $screens, pointant vers le repertoire racine des écrans personnalisés
|
|
24
31
|
///cependant, ce repertoire doit contenir un fichier mainScreens.js qui contient la liste de tous les écrans de lapplicaiton
|
package/package.json
CHANGED
|
@@ -1,101 +1,102 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@fto-consult/expo-ui",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "Bibliothèque de composants UI Expo,react-native",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"publish1": "npm publish --access=public",
|
|
8
|
-
"unpublish": "npm -f unpublish @fto-consult/expo-ui",
|
|
9
|
-
"build-web": "",
|
|
10
|
-
"dev": "npx expo start -c --no-minify",
|
|
11
|
-
"start": "npx expo start --dev --no-minify",
|
|
12
|
-
"start-d": "npx expo start -c --no-dev --no-minify",
|
|
13
|
-
"start-p": "npm run start-d",
|
|
14
|
-
"expo-start-client": "npx expo start --dev --no-minify --dev-client",
|
|
15
|
-
"start-m": "npx expo start - c--dev--no -minify",
|
|
16
|
-
"android": "npx expo start --android -c",
|
|
17
|
-
"ios": "npx expo start --ios",
|
|
18
|
-
"web": "npx expo start --web",
|
|
19
|
-
"web-c": "npx expo start --web -c",
|
|
20
|
-
"eject": "expo eject",
|
|
21
|
-
"emulator": "npm run android-emulator",
|
|
22
|
-
"web-server": "npx serve web-build",
|
|
23
|
-
"build-android": "eas build --clear-cache -p android --profile preview",
|
|
24
|
-
"build-android-local": "eas build --platform android --local",
|
|
25
|
-
"build-android-dist": "eas build --clear-cache -p android",
|
|
26
|
-
"build-ios": "eas build --clear-cache -p ios --profile preview",
|
|
27
|
-
"build-ios-dist": "eas build --clear-cache -p ios",
|
|
28
|
-
"install-apk": "adb -s emulator-5554 install myapp.apk",
|
|
29
|
-
"android-emulator": "emulator -avd EMULATOR",
|
|
30
|
-
"flipper": "npx cross-env METRO_SERVER_PORT=19000 E:\\Studies\\react-native\\debugger\\Flipper-win\\Flipper.exe",
|
|
31
|
-
"build-electron": "electron-webpack && electron-builder --dir -c.compression=store",
|
|
32
|
-
"test:build": "electron-webpack && electron-builder --dir -c.compression=store -c.mac.identity=null",
|
|
33
|
-
"compile-electron": "webpack --config ./electron/webpack.config.js",
|
|
34
|
-
"compile-electron-p": "webpack --config ./electron/webpack.config.js --mode=production",
|
|
35
|
-
"electron": "electron ./electron",
|
|
36
|
-
"logcat": "adb -d logcat com.ftc.apps.salite1:E > errors.txt",
|
|
37
|
-
"logcat-export": "adb -d logcat com.ftc.apps.salite1 *:S > logcat.txt",
|
|
38
|
-
"electron-c": "npm run compile-electron && npm run electron",
|
|
39
|
-
"electron-p": "npm run compile-electron-p && npm run electron",
|
|
40
|
-
"update-app-version": "node ./update-app-version.js",
|
|
41
|
-
"find-licenses": "node ./find-licenses.js",
|
|
42
|
-
"fix-dependencies": "expo doctor --fix-dependencies"
|
|
43
|
-
},
|
|
44
|
-
"repository": {
|
|
45
|
-
"type": "git",
|
|
46
|
-
"url": "git+https://github.com/borispipo/expo-ui.git"
|
|
47
|
-
},
|
|
48
|
-
"keywords": [
|
|
49
|
-
"Expo",
|
|
50
|
-
"React-Native"
|
|
51
|
-
],
|
|
52
|
-
"author": "Boris Fouomene",
|
|
53
|
-
"license": "ISC",
|
|
54
|
-
"bugs": {
|
|
55
|
-
"url": "https://github.com/borispipo/expo-ui/issues"
|
|
56
|
-
},
|
|
57
|
-
"homepage": "https://github.com/borispipo/expo-ui#readme",
|
|
58
|
-
"dependencies": {
|
|
59
|
-
"@babel/preset-react": "^7.18.6",
|
|
60
|
-
"@emotion/native": "^11.10.0",
|
|
61
|
-
"@expo/html-elements": "^0.2.0",
|
|
62
|
-
"@expo/metro-config": "^0.4.0",
|
|
63
|
-
"@expo/webpack-config": "^0.17.2",
|
|
64
|
-
"@fto-consult/common": "^1.
|
|
65
|
-
"@gorhom/portal": "^1.0.14",
|
|
66
|
-
"@react-native-async-storage/async-storage": "~1.17.3",
|
|
67
|
-
"@react-native-community/datetimepicker": "6.2.0",
|
|
68
|
-
"@react-native-community/netinfo": "9.3.0",
|
|
69
|
-
"@react-navigation/native": "^6.0.13",
|
|
70
|
-
"@react-navigation/native-stack": "^6.9.1",
|
|
71
|
-
"@shopify/flash-list": "1.1.0",
|
|
72
|
-
"babel-plugin-inline-dotenv": "^1.7.0",
|
|
73
|
-
"babel-plugin-module-resolver": "^4.1.0",
|
|
74
|
-
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
|
|
75
|
-
"expo": "^46.0.15",
|
|
76
|
-
"expo-camera": "~12.3.0",
|
|
77
|
-
"expo-
|
|
78
|
-
"expo-
|
|
79
|
-
"expo-
|
|
80
|
-
"expo-
|
|
81
|
-
"expo-
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"react-
|
|
88
|
-
"react-
|
|
89
|
-
"react-
|
|
90
|
-
"react-native-
|
|
91
|
-
"react-native-
|
|
92
|
-
"react-native-paper
|
|
93
|
-
"react-native-
|
|
94
|
-
"react-native-
|
|
95
|
-
"react-native-
|
|
96
|
-
"react-native-
|
|
97
|
-
"react-native-
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
|
|
101
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@fto-consult/expo-ui",
|
|
3
|
+
"version": "1.2.5",
|
|
4
|
+
"description": "Bibliothèque de composants UI Expo,react-native",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"publish1": "npm publish --access=public",
|
|
8
|
+
"unpublish": "npm -f unpublish @fto-consult/expo-ui",
|
|
9
|
+
"build-web": "",
|
|
10
|
+
"dev": "npx expo start -c --no-minify",
|
|
11
|
+
"start": "npx expo start --dev --no-minify",
|
|
12
|
+
"start-d": "npx expo start -c --no-dev --no-minify",
|
|
13
|
+
"start-p": "npm run start-d",
|
|
14
|
+
"expo-start-client": "npx expo start --dev --no-minify --dev-client",
|
|
15
|
+
"start-m": "npx expo start - c--dev--no -minify",
|
|
16
|
+
"android": "npx expo start --android -c",
|
|
17
|
+
"ios": "npx expo start --ios",
|
|
18
|
+
"web": "npx expo start --web",
|
|
19
|
+
"web-c": "npx expo start --web -c",
|
|
20
|
+
"eject": "expo eject",
|
|
21
|
+
"emulator": "npm run android-emulator",
|
|
22
|
+
"web-server": "npx serve web-build",
|
|
23
|
+
"build-android": "eas build --clear-cache -p android --profile preview",
|
|
24
|
+
"build-android-local": "eas build --platform android --local",
|
|
25
|
+
"build-android-dist": "eas build --clear-cache -p android",
|
|
26
|
+
"build-ios": "eas build --clear-cache -p ios --profile preview",
|
|
27
|
+
"build-ios-dist": "eas build --clear-cache -p ios",
|
|
28
|
+
"install-apk": "adb -s emulator-5554 install myapp.apk",
|
|
29
|
+
"android-emulator": "emulator -avd EMULATOR",
|
|
30
|
+
"flipper": "npx cross-env METRO_SERVER_PORT=19000 E:\\Studies\\react-native\\debugger\\Flipper-win\\Flipper.exe",
|
|
31
|
+
"build-electron": "electron-webpack && electron-builder --dir -c.compression=store",
|
|
32
|
+
"test:build": "electron-webpack && electron-builder --dir -c.compression=store -c.mac.identity=null",
|
|
33
|
+
"compile-electron": "webpack --config ./electron/webpack.config.js",
|
|
34
|
+
"compile-electron-p": "webpack --config ./electron/webpack.config.js --mode=production",
|
|
35
|
+
"electron": "electron ./electron",
|
|
36
|
+
"logcat": "adb -d logcat com.ftc.apps.salite1:E > errors.txt",
|
|
37
|
+
"logcat-export": "adb -d logcat com.ftc.apps.salite1 *:S > logcat.txt",
|
|
38
|
+
"electron-c": "npm run compile-electron && npm run electron",
|
|
39
|
+
"electron-p": "npm run compile-electron-p && npm run electron",
|
|
40
|
+
"update-app-version": "node ./update-app-version.js",
|
|
41
|
+
"find-licenses": "node ./find-licenses.js",
|
|
42
|
+
"fix-dependencies": "expo doctor --fix-dependencies"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/borispipo/expo-ui.git"
|
|
47
|
+
},
|
|
48
|
+
"keywords": [
|
|
49
|
+
"Expo",
|
|
50
|
+
"React-Native"
|
|
51
|
+
],
|
|
52
|
+
"author": "Boris Fouomene",
|
|
53
|
+
"license": "ISC",
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/borispipo/expo-ui/issues"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/borispipo/expo-ui#readme",
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@babel/preset-react": "^7.18.6",
|
|
60
|
+
"@emotion/native": "^11.10.0",
|
|
61
|
+
"@expo/html-elements": "^0.2.0",
|
|
62
|
+
"@expo/metro-config": "^0.4.0",
|
|
63
|
+
"@expo/webpack-config": "^0.17.2",
|
|
64
|
+
"@fto-consult/common": "^1.4.3",
|
|
65
|
+
"@gorhom/portal": "^1.0.14",
|
|
66
|
+
"@react-native-async-storage/async-storage": "~1.17.3",
|
|
67
|
+
"@react-native-community/datetimepicker": "6.2.0",
|
|
68
|
+
"@react-native-community/netinfo": "9.3.0",
|
|
69
|
+
"@react-navigation/native": "^6.0.13",
|
|
70
|
+
"@react-navigation/native-stack": "^6.9.1",
|
|
71
|
+
"@shopify/flash-list": "1.1.0",
|
|
72
|
+
"babel-plugin-inline-dotenv": "^1.7.0",
|
|
73
|
+
"babel-plugin-module-resolver": "^4.1.0",
|
|
74
|
+
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
|
|
75
|
+
"expo": "^46.0.15",
|
|
76
|
+
"expo-camera": "~12.3.0",
|
|
77
|
+
"expo-image-picker": "~13.3.1",
|
|
78
|
+
"expo-linking": "~3.2.2",
|
|
79
|
+
"expo-sqlite": "~10.3.0",
|
|
80
|
+
"expo-status-bar": "~1.4.0",
|
|
81
|
+
"expo-system-ui": "~1.3.0",
|
|
82
|
+
"expo-web-browser": "~11.0.0",
|
|
83
|
+
"google-libphonenumber": "^3.2.31",
|
|
84
|
+
"htmlparser2-without-node-native": "^3.9.2",
|
|
85
|
+
"parent-package-json": "^2.0.1",
|
|
86
|
+
"prop-types": "^15.8.1",
|
|
87
|
+
"react-apexcharts": "^1.4.0",
|
|
88
|
+
"react-content-loader": "^6.2.0",
|
|
89
|
+
"react-dom": "18.0.0",
|
|
90
|
+
"react-native-big-list": "^1.5.5",
|
|
91
|
+
"react-native-gesture-handler": "~2.5.0",
|
|
92
|
+
"react-native-paper": "^4.12.5",
|
|
93
|
+
"react-native-paper-dates": "^0.9.2",
|
|
94
|
+
"react-native-reanimated": "~2.9.1",
|
|
95
|
+
"react-native-safe-area-context": "4.3.1",
|
|
96
|
+
"react-native-svg": "12.3.0",
|
|
97
|
+
"react-native-web": "~0.18.7",
|
|
98
|
+
"react-native-webview": "11.23.0",
|
|
99
|
+
"sharp-cli": "^2.1.0",
|
|
100
|
+
"tippy.js": "^6.3.7"
|
|
101
|
+
}
|
|
102
|
+
}
|
package/src/auth/Login.js
CHANGED
|
@@ -35,6 +35,7 @@ export default function LoginComponent(props){
|
|
|
35
35
|
const backgroundColor = theme.colors.surface;
|
|
36
36
|
const Wrapper = withPortal ? ScreenWithoutAuthContainer : View;
|
|
37
37
|
const _getForm = x=> getForm(formName);
|
|
38
|
+
const isMounted = React.useIsMounted();
|
|
38
39
|
|
|
39
40
|
const auth = useAuth();
|
|
40
41
|
const notifyUser = (message,title)=> {
|
|
@@ -43,10 +44,15 @@ export default function LoginComponent(props){
|
|
|
43
44
|
} else if(typeof message =='object') return false;
|
|
44
45
|
return notify.error({message,title,position:'top'});
|
|
45
46
|
}
|
|
46
|
-
const [state,
|
|
47
|
+
const [state,_setState] = React.useState({
|
|
47
48
|
step : defaultNumber(step,1),
|
|
48
49
|
data : defaultObj(props.data),
|
|
49
50
|
});
|
|
51
|
+
const setState = (state2)=>{
|
|
52
|
+
if(!isMounted()) return;
|
|
53
|
+
state2 = isObj(state2)? state2 : {};
|
|
54
|
+
return _setState({...state,...state2});
|
|
55
|
+
}
|
|
50
56
|
const getData = ()=>{
|
|
51
57
|
const form = _getForm();
|
|
52
58
|
if(form && form.getData){
|
|
@@ -79,8 +85,9 @@ export default function LoginComponent(props){
|
|
|
79
85
|
},1000)
|
|
80
86
|
}
|
|
81
87
|
},[withPortal])
|
|
82
|
-
const {header,children,data:loginData,canGoToNext,keyboardEvents,onSuccess:onLoginSuccess,canSubmit:canSubmitForm,onStepChange,...loginProps} = defaultObj(getProps({
|
|
88
|
+
const {header,children,initialize,data:loginData,canGoToNext,keyboardEvents,onSuccess:onLoginSuccess,canSubmit:canSubmitForm,onStepChange,...loginProps} = defaultObj(getProps({
|
|
83
89
|
...state,
|
|
90
|
+
setState,
|
|
84
91
|
state,
|
|
85
92
|
showError : notifyUser,
|
|
86
93
|
notifyUser,
|
|
@@ -93,6 +100,10 @@ export default function LoginComponent(props){
|
|
|
93
100
|
previousButtonRef,
|
|
94
101
|
}));
|
|
95
102
|
React.useEffect(()=>{
|
|
103
|
+
/*** pour initializer les cordonnées du composant login */
|
|
104
|
+
if(typeof initialize =='function'){
|
|
105
|
+
initialize();
|
|
106
|
+
}
|
|
96
107
|
Preloader.closeAll();
|
|
97
108
|
},[]);
|
|
98
109
|
const prevStep = React.usePrevious(state.step);
|
|
@@ -120,11 +131,16 @@ export default function LoginComponent(props){
|
|
|
120
131
|
}
|
|
121
132
|
if(typeof canGoToNext =='function'){
|
|
122
133
|
const s = canGoToNext(args);
|
|
123
|
-
if(s === false)
|
|
134
|
+
if(s === false) {
|
|
135
|
+
nextButtonRef.current?.disable();
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
124
138
|
if(isNonNullString(s)){
|
|
125
139
|
notifyUser(s);
|
|
140
|
+
nextButtonRef.current?.disable();
|
|
126
141
|
return
|
|
127
142
|
}
|
|
143
|
+
nextButtonRef.current?.enable();
|
|
128
144
|
}
|
|
129
145
|
if(step > 1){
|
|
130
146
|
if(!form.isValid()){
|
|
@@ -0,0 +1,197 @@
|
|
|
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
|
+
///permet de sélectionner un theme utilisateur
|
|
5
|
+
import React from "$react";
|
|
6
|
+
import Label from "$ecomponents/Label";
|
|
7
|
+
import Auth,{login} from "$cauth";
|
|
8
|
+
import View from "$ecomponents/View";
|
|
9
|
+
import { StyleSheet } from "react-native";
|
|
10
|
+
import {colors as defaultColors,defaultThemeName} from "$theme/defaultTheme";
|
|
11
|
+
import theme,{defaultDarkTheme,Colors,defaultLightTheme} from "$theme";
|
|
12
|
+
import Provider from "$ecomponents/Form/FormData/DialogProvider";
|
|
13
|
+
import Dropdown from "$ecomponents/Dropdown";
|
|
14
|
+
import {defaultObj} from "$utils";
|
|
15
|
+
import Icon from "$ecomponents/Icon";
|
|
16
|
+
import {open,close} from "$preloader";
|
|
17
|
+
import {fields,getThemeData} from "./utils";
|
|
18
|
+
|
|
19
|
+
const getStyle = (color)=>{
|
|
20
|
+
if(!Colors.isValid(color)) return {};
|
|
21
|
+
return {backgroundColor:color,paddingHorizontal:10,paddingVertical:5,color:Colors.getContrast(color)};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const ThemeSelectorComponent = React.forwardRef((props,ref)=>{
|
|
25
|
+
const innerRef = React.useRef(null);
|
|
26
|
+
return <Dropdown
|
|
27
|
+
{...getThemeFieldProps(props,innerRef)}
|
|
28
|
+
ref = {React.useMergeRefs(innerRef,ref)}
|
|
29
|
+
/>
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
const isDocEditing = ({data})=>{
|
|
34
|
+
return data && isNonNullString(data.name)? true : false;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const getThemeFieldProps = (props,ref)=>{
|
|
38
|
+
props = defaultObj(props);
|
|
39
|
+
let {user,showAdd,onValidate,onChange,onUpsert,...rest} = props;
|
|
40
|
+
const loggedUser = defaultObj(Auth.getLoggedUser());
|
|
41
|
+
user = defaultObj(user,loggedUser);
|
|
42
|
+
const isUserActive = loggedUser.code == user.code && user.code ? true : false;
|
|
43
|
+
const userTheme = defaultObj(user.theme);
|
|
44
|
+
const userThemeName = defaultStr(userTheme.name,defaultThemeName);
|
|
45
|
+
const isDark = theme.isDark() || theme.isDarkUI();
|
|
46
|
+
const defTheme = isDark ? {...defaultDarkTheme.colors,dark:true} : {...defaultLightTheme.colors,dark:false};
|
|
47
|
+
const itemsRef = React.useRef({...defaultObj(user.customThemes),...defaultColors});
|
|
48
|
+
const showThemeExplorer = (data)=>{
|
|
49
|
+
data = defaultObj(data,defTheme);
|
|
50
|
+
fields.name.disabled = ({data})=> data && isNonNullString(data.name);
|
|
51
|
+
const title = data && data.name ? ("Modifier ["+data.name+"]") : ('Nouv theme['+user.code+"]");
|
|
52
|
+
const isEditing = isDocEditing(data);
|
|
53
|
+
fields.textFieldMode.defaultValue = theme.textFieldMode;
|
|
54
|
+
Provider.open({
|
|
55
|
+
cancelButton : true,
|
|
56
|
+
dialogProps : {
|
|
57
|
+
withScrollView : true,
|
|
58
|
+
fullScreen : true,
|
|
59
|
+
},
|
|
60
|
+
data,
|
|
61
|
+
title,
|
|
62
|
+
isDocEditing,
|
|
63
|
+
actions : [{
|
|
64
|
+
text : 'Enregistrer',
|
|
65
|
+
primary : true,
|
|
66
|
+
icon : "check",
|
|
67
|
+
onPress : ({data,formName,...args})=>{
|
|
68
|
+
///un utilisateur doit avoir au max 10 Thème personnalisés
|
|
69
|
+
const customThemes = defaultObj(user.customThemes);
|
|
70
|
+
let cKeys = [];
|
|
71
|
+
Object.map(customThemes,(cT,i)=>{
|
|
72
|
+
if(!isObj(cT) || !cT.custom){
|
|
73
|
+
delete customThemes[i];
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
cKeys.push(i);
|
|
77
|
+
});
|
|
78
|
+
const counter = cKeys.length;
|
|
79
|
+
if(counter > 10){
|
|
80
|
+
delete customThemes[cKeys[0]]
|
|
81
|
+
}
|
|
82
|
+
data.custom = true;
|
|
83
|
+
customThemes[data.name] = data;
|
|
84
|
+
itemsRef.current = user.customThemes = customThemes;
|
|
85
|
+
open((isEditing?"Modification ":"Enregistrement ")+"du thème...");
|
|
86
|
+
Auth.upsertUser(user,false).then(()=>{
|
|
87
|
+
if(Auth.getLoggedUserCode() == user.code){
|
|
88
|
+
login(user,false);
|
|
89
|
+
}
|
|
90
|
+
if(ref && ref.current && ref.current.refresh){
|
|
91
|
+
ref.current.refresh(true);
|
|
92
|
+
}
|
|
93
|
+
if(typeof onUpsert =='function'){
|
|
94
|
+
onUpsert({data,theme:data,value:data});
|
|
95
|
+
}
|
|
96
|
+
}).finally(()=>{
|
|
97
|
+
Provider.close();
|
|
98
|
+
close();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}],
|
|
102
|
+
fields,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
rest = {
|
|
106
|
+
multiple : false,
|
|
107
|
+
...defaultObj(rest),
|
|
108
|
+
showAdd : typeof showAdd =='boolean'? showAdd : isUserActive || Auth.isTableDataAllowed({table:'users',action:'"changeTheme"'}),
|
|
109
|
+
addIconTooltip : "Cliquez pour ajouter un nouveau thème",
|
|
110
|
+
onAdd : ()=>{
|
|
111
|
+
showThemeExplorer();
|
|
112
|
+
},
|
|
113
|
+
onChange : (args)=>{
|
|
114
|
+
args = defaultObj(args);
|
|
115
|
+
const {value} = args
|
|
116
|
+
if(!value) return;
|
|
117
|
+
const {theme,value:validValue} = getThemeData(value);
|
|
118
|
+
args.theme = theme;
|
|
119
|
+
args.realValue = value;
|
|
120
|
+
args.value = validValue;
|
|
121
|
+
if(typeof onValidate =='function'){
|
|
122
|
+
onValidate(args);
|
|
123
|
+
}
|
|
124
|
+
if(typeof onChange =='function'){
|
|
125
|
+
onChange(args);
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
defaultValue : userThemeName,
|
|
129
|
+
items : x =>{
|
|
130
|
+
return itemsRef.current;
|
|
131
|
+
},
|
|
132
|
+
compare : (item,selected)=>{
|
|
133
|
+
if(isNonNullString(selected)){
|
|
134
|
+
if(isObj(item) && item.name == selected) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if(isNonNullString(item)) return item === selected ? true : false;
|
|
138
|
+
}
|
|
139
|
+
return isObj(item) && isObj(selected) && item.name == selected.name ? true : false;
|
|
140
|
+
},
|
|
141
|
+
itemValue : ({item})=>{return item;},
|
|
142
|
+
renderText : ({item,index}) =>{ return defaultStr(item?.name,index+"")},
|
|
143
|
+
renderItem : ({item,index}) =>{
|
|
144
|
+
let {primary,secondary,name,primaryName,secondaryName,dark} = item
|
|
145
|
+
let split = index.split("-")
|
|
146
|
+
let pText = defaultStr(item.custom?name:primaryName,split[0],name,primary)
|
|
147
|
+
let sText = defaultStr(secondaryName,split[1],secondary);
|
|
148
|
+
//<Icon icon={dark?'brightness-6':'brightness-4'} size={15} title={dark?'Sombre':'Clair'}/>
|
|
149
|
+
return <View style={[styles.buttonContainer]}>
|
|
150
|
+
<Label style={[getStyle(primary),{height:'100%',borderLeftWidth:10,borderLeftColor:dark?defaultDarkTheme.colors.surface:defaultLightTheme.colors.background}]}>
|
|
151
|
+
{pText}
|
|
152
|
+
</Label>
|
|
153
|
+
<View style={[styles.labelRight]}>
|
|
154
|
+
<Label style={[getStyle(secondary)]}>
|
|
155
|
+
{sText}
|
|
156
|
+
</Label>
|
|
157
|
+
{<Icon size={20}
|
|
158
|
+
name={item.custom?'pencil':'plus'}
|
|
159
|
+
title={(item.custom?'Cliquer pour modifier le thème': ' Ajouter un thème basé sur le thème')+' ['+item.name+"]"}
|
|
160
|
+
onPress = {(e)=>{
|
|
161
|
+
React.stopEventPropagation(e);
|
|
162
|
+
showThemeExplorer({...Object.clone(item),name:item.custom?item.name:undefined,primaryName:item.custom ? item.primaryName : undefined, secondaryName : item.custom ? item.secondaryName:undefined});
|
|
163
|
+
}}
|
|
164
|
+
/>}
|
|
165
|
+
</View>
|
|
166
|
+
</View>
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
rest.text = defaultStr(rest.text,rest.label,'Thème');
|
|
170
|
+
return rest;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
ThemeSelectorComponent.displayName = "ThemeSelectorComponent";
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
export default ThemeSelectorComponent;
|
|
177
|
+
|
|
178
|
+
const styles = StyleSheet.create({
|
|
179
|
+
theme : {
|
|
180
|
+
padding : 2,
|
|
181
|
+
marginBottom : 2,
|
|
182
|
+
},
|
|
183
|
+
itemContainer : {
|
|
184
|
+
width : '100%',
|
|
185
|
+
},
|
|
186
|
+
buttonContainer : {
|
|
187
|
+
width : '100%',
|
|
188
|
+
flexDirection :'row',
|
|
189
|
+
alignItems :'center',
|
|
190
|
+
},
|
|
191
|
+
labelRight : {
|
|
192
|
+
width : '100%',
|
|
193
|
+
flex : 1,
|
|
194
|
+
flexDirection :'row',
|
|
195
|
+
alignItems :'center',
|
|
196
|
+
}
|
|
197
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
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
|
+
|
|
5
|
+
import { lightColors,darkColors,primary as defaultPrimary,secondary as defaultSecondary} from "$theme/defaultTheme";
|
|
6
|
+
import {modesObject} from "$ecomponents/TextField/utils";
|
|
7
|
+
|
|
8
|
+
export const fields = {
|
|
9
|
+
name : {
|
|
10
|
+
type : 'text',
|
|
11
|
+
maxLength : 30,
|
|
12
|
+
text : 'Nom du thème',
|
|
13
|
+
required : true,
|
|
14
|
+
upper : true,
|
|
15
|
+
},
|
|
16
|
+
dark : {
|
|
17
|
+
type : 'switch',
|
|
18
|
+
checkedValue : true,
|
|
19
|
+
uncheckedValue : false,
|
|
20
|
+
label : 'Mode Sombre',
|
|
21
|
+
checkedTooltip : 'Mode sombre actif',
|
|
22
|
+
uncheckedTooltip : 'Mode sombre inactif',
|
|
23
|
+
onChange : ({value,checked,context})=>{
|
|
24
|
+
if(checked === undefined) return;
|
|
25
|
+
if(context && context.getField){
|
|
26
|
+
const darkFields = checked ? darkColors : lightColors;
|
|
27
|
+
Object.map(darkFields,(dF,i)=>{
|
|
28
|
+
const dFContext = context.getField(i);
|
|
29
|
+
if(dFContext && dFContext.setValue){
|
|
30
|
+
dFContext.validate({value:dF});
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
textFieldMode : {
|
|
37
|
+
type : 'select',
|
|
38
|
+
items : {...modesObject,none:{code:'',label:'Dynamique'}},
|
|
39
|
+
text : 'Mode d\'affichage des champs de texte'
|
|
40
|
+
},
|
|
41
|
+
primary : {
|
|
42
|
+
type : 'color',
|
|
43
|
+
text : 'Couleur principale [primary]',
|
|
44
|
+
required : true,
|
|
45
|
+
onChange : ({value,context})=>{
|
|
46
|
+
if(context && context.getField){
|
|
47
|
+
const pOnSurface = context.getField("primaryOnSurface");
|
|
48
|
+
if(pOnSurface){
|
|
49
|
+
pOnSurface.setValue(value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
primaryText : {
|
|
55
|
+
type :'color',
|
|
56
|
+
text :'Texte sur couleur principale [primaryText]',
|
|
57
|
+
required : true,
|
|
58
|
+
},
|
|
59
|
+
secondary : {
|
|
60
|
+
type : 'color',
|
|
61
|
+
text : ' Couleur secondaire [secondary]',
|
|
62
|
+
required : true,
|
|
63
|
+
onChange : ({value,context})=>{
|
|
64
|
+
if(context && context.getField){
|
|
65
|
+
const sOnSurface = context.getField("secondaryOnSurface");
|
|
66
|
+
if(sOnSurface){
|
|
67
|
+
sOnSurface.setValue(value);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
secondaryText : {
|
|
73
|
+
type :'color',
|
|
74
|
+
text :'Texte sur couleur secondaire [secondaryText]',
|
|
75
|
+
required : true,
|
|
76
|
+
},
|
|
77
|
+
text : {
|
|
78
|
+
type :'color',
|
|
79
|
+
text : 'Couleur de texte [text]',
|
|
80
|
+
required : true,
|
|
81
|
+
},
|
|
82
|
+
disabled : {
|
|
83
|
+
type :'color',
|
|
84
|
+
text :'Texte Inactif [disabeld]'
|
|
85
|
+
},
|
|
86
|
+
divider : {
|
|
87
|
+
type : 'color',
|
|
88
|
+
text : 'Couleur|Soulignement [divider]'
|
|
89
|
+
},
|
|
90
|
+
background : {
|
|
91
|
+
type : 'color',
|
|
92
|
+
text : 'Couleur d\'arrière plan [background]',
|
|
93
|
+
},
|
|
94
|
+
surface : {
|
|
95
|
+
type :'color',
|
|
96
|
+
text :'Couleur de surface [surface]',
|
|
97
|
+
},
|
|
98
|
+
surfaceText : {
|
|
99
|
+
type :'color',
|
|
100
|
+
text :'Texte sur surface [surfaceText]',
|
|
101
|
+
},
|
|
102
|
+
primaryOnSurface : {
|
|
103
|
+
type :'color',
|
|
104
|
+
text :'Couleur principale sur surface [primaryOnSurface]',
|
|
105
|
+
},
|
|
106
|
+
secondaryOnSurface : {
|
|
107
|
+
type :'color',
|
|
108
|
+
text :'Couleur secondaire sur surface [secondaryOnSurface]',
|
|
109
|
+
},
|
|
110
|
+
info : {
|
|
111
|
+
type :'color',
|
|
112
|
+
text :'Notification|info [info]'
|
|
113
|
+
},
|
|
114
|
+
success : {
|
|
115
|
+
type :'color',
|
|
116
|
+
text :'Notification|Succès [success]'
|
|
117
|
+
},
|
|
118
|
+
warning : {
|
|
119
|
+
type :'color',
|
|
120
|
+
text :'Notification|Alerte [warning]'
|
|
121
|
+
},
|
|
122
|
+
error : {
|
|
123
|
+
type :'color',
|
|
124
|
+
text :'Notification|Erreur [error]'
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
export const getThemeData = (value)=>{
|
|
128
|
+
const theme = {name:value.name,colors:{}};
|
|
129
|
+
const validValue = {};
|
|
130
|
+
Object.map(fields,(f,i)=>{
|
|
131
|
+
if(!f) return;
|
|
132
|
+
if(f.type =='color'){
|
|
133
|
+
const fText = i+"Color";
|
|
134
|
+
theme.colors[i] = value[i] || value[fText];
|
|
135
|
+
} else {
|
|
136
|
+
theme[i] = value[i];
|
|
137
|
+
}
|
|
138
|
+
validValue[i] = value[i];
|
|
139
|
+
});
|
|
140
|
+
return {theme,value:validValue};
|
|
141
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
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 {isNativeMobile} from "$platform";
|
|
5
|
+
import defaultSrc from "./defaultAvatar";
|
|
6
|
+
export default {
|
|
7
|
+
accordion:false,
|
|
8
|
+
editable : !isNativeMobile(),
|
|
9
|
+
text : 'Avatar',
|
|
10
|
+
type : 'image',
|
|
11
|
+
defaultSrc,
|
|
12
|
+
size : 100,
|
|
13
|
+
sortable : false,
|
|
14
|
+
datagrid : {
|
|
15
|
+
size : 50,
|
|
16
|
+
},
|
|
17
|
+
rounded : true,
|
|
18
|
+
cropProps : {
|
|
19
|
+
width : 100,
|
|
20
|
+
heigh : 100
|
|
21
|
+
},
|
|
22
|
+
}
|
|
@@ -1075,6 +1075,7 @@ class DropdownComponent extends AppComponent {
|
|
|
1075
1075
|
{...listProps}
|
|
1076
1076
|
ref = {this.listRef}
|
|
1077
1077
|
responsive = {false}
|
|
1078
|
+
contentContainerStyle = {[{backgroundColor:theme.colors.surface},listProps.contentContainerStyle]}
|
|
1078
1079
|
style = {[listProps.style]}
|
|
1079
1080
|
prepareItems = {false}
|
|
1080
1081
|
items = {renderingItems}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "$react";
|
|
2
2
|
import {InteractionManager} from "react-native";
|
|
3
3
|
/**** options, les options lié à la transition */
|
|
4
|
+
export const AFTER_INTERACTIONS_TIMEOUT = 10;
|
|
4
5
|
export const useAfterInteractions = (options) => {
|
|
5
6
|
const [areInteractionsComplete, setInteractionsComplete] = React.useState(false)
|
|
6
7
|
if(isNumber(options)){
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import React from "$react";
|
|
3
3
|
import { prepareItems as customPrepareItems,getBToTopRef } from "./utils";
|
|
4
|
-
import {grid,StylePropTypes} from "$theme";
|
|
4
|
+
import theme,{grid,StylePropTypes} from "$theme";
|
|
5
5
|
import PropTypes from "prop-types";
|
|
6
6
|
import {defaultObj,defaultDecimal,defaultArray,defaultFunc} from "$utils";
|
|
7
7
|
import {isMobileMedia} from "$cplatform/dimensions";
|
|
@@ -159,7 +159,7 @@ const CommonListComponent = React.forwardRef((props,ref)=>{
|
|
|
159
159
|
const restP = numColumns > 1 && isFlatList ? {
|
|
160
160
|
columnWrapperStyle : [styles.columnWrapperStyle,props.columnWrapperStyle]
|
|
161
161
|
} : {};
|
|
162
|
-
return <View {...containerProps} style={[styles.container,containerProps.style]}>
|
|
162
|
+
return <View {...containerProps} style={[{backgroundColor:theme.colors.surface},styles.container,containerProps.style]}>
|
|
163
163
|
<Component
|
|
164
164
|
onEndReachedThreshold={0}
|
|
165
165
|
scrollEventThrottle={16}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React,{BaseComponent as AppComponent} from '$react';
|
|
2
|
-
import View from "$
|
|
3
|
-
import ScrollView from "$
|
|
2
|
+
import View from "$components/View";
|
|
3
|
+
import ScrollView from "$components/ScrollView";
|
|
4
4
|
import {
|
|
5
5
|
Platform,
|
|
6
6
|
StyleSheet,
|
|
@@ -14,11 +14,11 @@ import {
|
|
|
14
14
|
} from 'react-native';
|
|
15
15
|
import PropTypes from "prop-types";
|
|
16
16
|
import { withTheme,Surface,Portal} from 'react-native-paper';
|
|
17
|
-
//import Surface from "$
|
|
17
|
+
//import Surface from "$components/Surface";
|
|
18
18
|
import { NativeModules} from 'react-native';
|
|
19
19
|
import {defaultDecimal,extendObj} from "$utils";
|
|
20
20
|
import theme,{StylePropTypes} from "$theme";
|
|
21
|
-
import APP from "$
|
|
21
|
+
import APP from "$app/instance";
|
|
22
22
|
import MenuItem from "./Item";
|
|
23
23
|
|
|
24
24
|
const RESIZE_PAGE = APP.EVENTS.RESIZE_PAGE;
|
|
@@ -361,6 +361,7 @@ const SimpleSelect = React.forwardRef((props,ref)=>{
|
|
|
361
361
|
{...listProps}
|
|
362
362
|
getItemLayout = {getItemLayout}
|
|
363
363
|
ref = {listRef}
|
|
364
|
+
contentContainerStyle = {[{backgroundColor:theme.colors.surface},listProps.contentContainerStyle]}
|
|
364
365
|
style = {[listProps.style]}
|
|
365
366
|
prepareItems = {false}
|
|
366
367
|
items = {renderingItems}
|
package/src/media/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {isObj} from "$utils";
|
|
2
|
-
import {notify} from "$
|
|
2
|
+
import {notify} from "$components/Dialog";
|
|
3
3
|
import Camera from "./camera";
|
|
4
|
-
import {isMobileNative} from "$
|
|
4
|
+
import {isMobileNative} from "$platform";
|
|
5
5
|
import React from "react";
|
|
6
6
|
|
|
7
7
|
let cameraRef = null;
|
|
@@ -16,11 +16,7 @@ export const createCameraRef = ()=>{
|
|
|
16
16
|
return ref;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
MediaTypeOptions : {},
|
|
21
|
-
mediaTypes : {},
|
|
22
|
-
};
|
|
23
|
-
///import * as ImagePicker from 'expo-image-picker';
|
|
19
|
+
import * as ImagePicker from 'expo-image-picker';
|
|
24
20
|
|
|
25
21
|
export const MEDIA_TYPES = {
|
|
26
22
|
ALL : ImagePicker.MediaTypeOptions.All,
|
|
@@ -3,10 +3,10 @@ import i18n from "$i18n"
|
|
|
3
3
|
import Auth from "$cauth";
|
|
4
4
|
import Menu from "$ecomponents/Menu";
|
|
5
5
|
import React from "$react";
|
|
6
|
-
import
|
|
6
|
+
import { screenName } from "$escreens/Auth/Profile";
|
|
7
7
|
import Image from "$ecomponents/Image";
|
|
8
8
|
import { StyleSheet,View} from "react-native";
|
|
9
|
-
import
|
|
9
|
+
import avatarProps from "$eauth/avatarProps";
|
|
10
10
|
import Button from "$ecomponents/Button";
|
|
11
11
|
import Label from "$ecomponents/Label";
|
|
12
12
|
import Icon from "$ecomponents/Icon";
|
|
@@ -32,7 +32,7 @@ const UserProfileAvatarComponent = React.forwardRef(({drawerRef,...props},ref)=>
|
|
|
32
32
|
onPress : (a)=>{
|
|
33
33
|
closeDrawer(()=>{
|
|
34
34
|
return navigate({
|
|
35
|
-
|
|
35
|
+
routeName : screenName,
|
|
36
36
|
params : {
|
|
37
37
|
user : u,
|
|
38
38
|
}
|
|
@@ -48,17 +48,16 @@ const UserProfileAvatarComponent = React.forwardRef(({drawerRef,...props},ref)=>
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
];
|
|
51
|
-
let pseudo = defaultStr(u.code,u.pseudo,u.email)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
pseudo = <Tooltip title={defaultStr(u.label)+" ["+pseudo+"]"}>{pT}</Tooltip>;
|
|
51
|
+
let pseudo = defaultStr(u.code,u.pseudo,u.email)
|
|
52
|
+
const label = defaultStr(u.label,u.name,u.fullName,u.userName)
|
|
53
|
+
//let pT = pseudo;
|
|
54
|
+
//pseudo = <Tooltip uppserCase={false} title={defaultStr(u.label)+" ["+pseudo+"]"}>{pT}</Tooltip>;
|
|
57
55
|
return <View ref ={ref}>
|
|
58
56
|
<Menu
|
|
59
57
|
anchor = { (aProps)=>{
|
|
60
58
|
return <Button
|
|
61
59
|
normal
|
|
60
|
+
upperCase = {false}
|
|
62
61
|
disableRipple
|
|
63
62
|
{...aProps}
|
|
64
63
|
style = {[styles.container]}
|
|
@@ -69,7 +68,7 @@ const UserProfileAvatarComponent = React.forwardRef(({drawerRef,...props},ref)=>
|
|
|
69
68
|
style = {styles.itemLeft}
|
|
70
69
|
testID = {"RN_ProfilAvatar_Avatar"}
|
|
71
70
|
editable
|
|
72
|
-
defaultSource ={
|
|
71
|
+
defaultSource ={avatarProps.defaultSrc}
|
|
73
72
|
onChange = {({dataURL})=>{
|
|
74
73
|
if(u.avatar === dataURL) {
|
|
75
74
|
return;
|
|
@@ -97,7 +96,7 @@ const UserProfileAvatarComponent = React.forwardRef(({drawerRef,...props},ref)=>
|
|
|
97
96
|
<View style={styles.labelContainer}>
|
|
98
97
|
<Label splitText style={{color:theme.colors.primaryOnSurface}}>{pseudo}</Label>
|
|
99
98
|
<Label splitText style={{fontSize:12,color:theme.colors.secondaryOnSurface,marginTop:6}}>
|
|
100
|
-
{
|
|
99
|
+
{label}
|
|
101
100
|
</Label>
|
|
102
101
|
</View>
|
|
103
102
|
</Button>
|
|
@@ -120,6 +119,7 @@ const styles = StyleSheet.create({
|
|
|
120
119
|
flexDirection : 'column',
|
|
121
120
|
paddingRight : 5,
|
|
122
121
|
maxWidth : 130,
|
|
122
|
+
minWidth : 100,
|
|
123
123
|
},
|
|
124
124
|
pseudo : {
|
|
125
125
|
flexDirection : "row",
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import FormDataScreen from "$elayouts/Screen/FormData";
|
|
2
|
+
import {defaultStr,defaultObj,isObjOrArray,isObj} from "$utils";
|
|
3
|
+
import Auth from "$auth";
|
|
4
|
+
import {getScreenProps,navigate} from "$cnavigation";
|
|
5
|
+
import SelectTheme from "$themeSelectorComponent";
|
|
6
|
+
import Preloader from "$epreloader";
|
|
7
|
+
import {SignIn2SignOut} from "$cauth";
|
|
8
|
+
import React from "$react";
|
|
9
|
+
import avatarProps from "$eauth/avatarProps";
|
|
10
|
+
|
|
11
|
+
export const screenName = "UserProfile";
|
|
12
|
+
|
|
13
|
+
export default function UserProfileScreen(prs){
|
|
14
|
+
const props = getScreenProps(prs);
|
|
15
|
+
const user = defaultObj(props.user,Auth.getLoggedUser());
|
|
16
|
+
const testID = defaultStr(props.testID,"RN_UserProfile_FormData");
|
|
17
|
+
const themeRef = React.useRef(defaultObj(user.theme));
|
|
18
|
+
const hasChangeRef = React.useRef(false);
|
|
19
|
+
const authProfileFields = typeof SignIn2SignOut.authProfileFields =='function'?SignIn2SignOut.authProfileFields(props) : SignIn2SignOut.authProfileFields;
|
|
20
|
+
const fields = isObj(authProfileFields)? authProfileFields : {};
|
|
21
|
+
const formFields = {
|
|
22
|
+
avatar : {
|
|
23
|
+
...avatarProps,
|
|
24
|
+
...(isObj(fields.avatar)?fields.avatar:{}),
|
|
25
|
+
text : undefined,
|
|
26
|
+
label : undefined,
|
|
27
|
+
responsive : false,
|
|
28
|
+
responsiveProps : {
|
|
29
|
+
style : {
|
|
30
|
+
width : '100%',
|
|
31
|
+
alignItems : 'center',
|
|
32
|
+
justifyContent : 'center',
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
Object.map(fields,(field,i)=>{
|
|
38
|
+
if(i !='avatar' && isObj(field)){
|
|
39
|
+
formFields[i] = field;
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
formFields.theme = {
|
|
43
|
+
type : 'html',
|
|
44
|
+
text : 'Theme',
|
|
45
|
+
onChange : ({value})=>{
|
|
46
|
+
if(isObj(value) && value.name && value.primary && value.name !== themeRef.current.name){
|
|
47
|
+
hasChangeRef.current = true;
|
|
48
|
+
themeRef.current = value;
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
onUpsert : ({value})=>{
|
|
52
|
+
if(value.name === themeRef.current.name){
|
|
53
|
+
hasChangeRef.current = true;
|
|
54
|
+
themeRef.current = value;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
render : (p)=>{
|
|
58
|
+
return <SelectTheme {...p} defaultValue = {themeRef.current.name}/>
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
formFields.avatar.onChange = (args)=>{
|
|
62
|
+
if(args.value === user.avatar) return;
|
|
63
|
+
hasChangeRef.current = true;
|
|
64
|
+
}
|
|
65
|
+
const onSaveProfile = ({data,goBack,...rest})=>{
|
|
66
|
+
data.theme = themeRef.current;
|
|
67
|
+
Preloader.open("Modification en cours...");
|
|
68
|
+
Auth.upsertUser(data,true).then(()=>{
|
|
69
|
+
if(typeof goBack =='function' && !hasChangeRef.current){
|
|
70
|
+
return goBack(true);
|
|
71
|
+
}
|
|
72
|
+
navigate('Home');
|
|
73
|
+
}).finally(()=>{
|
|
74
|
+
setTimeout(()=>{
|
|
75
|
+
Preloader.close();
|
|
76
|
+
},1000);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return <FormDataScreen
|
|
81
|
+
title = {(user.label?(user.label+" ["+user.code+"] | "):"")+"Profil : Modifier"}
|
|
82
|
+
{...props}
|
|
83
|
+
modal
|
|
84
|
+
withScrollView
|
|
85
|
+
fields = {formFields}
|
|
86
|
+
data = {user}
|
|
87
|
+
testID = {testID}
|
|
88
|
+
onSave = {onSaveProfile}
|
|
89
|
+
subtitle = {false}
|
|
90
|
+
/>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
UserProfileScreen.screenName = screenName;
|
|
94
|
+
|
|
95
|
+
UserProfileScreen.Modal = true;
|
|
96
|
+
|
|
97
|
+
UserProfileScreen.authRequired = true;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
import {SIGN_IN} from "$cauth/routes"
|
|
3
|
+
import Screen from "$escreen";
|
|
4
|
+
import Login from "$eauth/Login";
|
|
5
|
+
import {getScreenProps} from "$cnavigation";
|
|
6
|
+
import {getTitle} from "./utils";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
function AuthSignInScreen(_props){
|
|
10
|
+
const props = getScreenProps(_props);
|
|
11
|
+
const title = getTitle();
|
|
12
|
+
return <Screen
|
|
13
|
+
title = {title}
|
|
14
|
+
appBarProps = {{
|
|
15
|
+
title,backAction:false
|
|
16
|
+
}}
|
|
17
|
+
contentContainerStyle = {{justifyContent:'center',alignItems:'center'}}
|
|
18
|
+
>
|
|
19
|
+
<Login
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
</Screen>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
AuthSignInScreen.screenName = SIGN_IN;
|
|
26
|
+
AuthSignInScreen.authRequired = false;
|
|
27
|
+
AuthSignInScreen.modal = true;
|
|
28
|
+
AuthSignInScreen.allowDrawer = false;
|
|
29
|
+
export default AuthSignInScreen;
|
|
@@ -1,30 +1,8 @@
|
|
|
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.
|
|
1
4
|
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import Login from "$eauth/Login";
|
|
5
|
-
import {getScreenProps} from "$cnavigation";
|
|
6
|
-
import {getTitle} from "./utils";
|
|
5
|
+
import AuthSignInScreen from "./SignIn";
|
|
6
|
+
import UserProfileScreen from "./Profile";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
function AuthSignInScreen(_props){
|
|
10
|
-
const props = getScreenProps(_props);
|
|
11
|
-
const title = getTitle();
|
|
12
|
-
return <Screen
|
|
13
|
-
title = {title}
|
|
14
|
-
appBarProps = {{
|
|
15
|
-
title,backAction:false
|
|
16
|
-
}}
|
|
17
|
-
contentContainerStyle = {{justifyContent:'center',alignItems:'center'}}
|
|
18
|
-
>
|
|
19
|
-
<Login
|
|
20
|
-
{...props}
|
|
21
|
-
/>
|
|
22
|
-
</Screen>
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
AuthSignInScreen.screenName = SIGN_IN;
|
|
26
|
-
AuthSignInScreen.authRequired = false;
|
|
27
|
-
AuthSignInScreen.modal = true;
|
|
28
|
-
AuthSignInScreen.allowDrawer = false;
|
|
29
|
-
|
|
30
|
-
export default [AuthSignInScreen];
|
|
8
|
+
export default [AuthSignInScreen,UserProfileScreen];
|
package/src/screens/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {defaultBool,defaultArray,defaultVal,isObj,isNonNullString,defaultObj,isArray,defaultStr} from "$utils";
|
|
2
2
|
import {sanitizeName,GROUP_NAMES} from "./utils";
|
|
3
|
-
import mainScreens from "$
|
|
3
|
+
import mainScreens from "$mainScreens"
|
|
4
4
|
import React from "$react";
|
|
5
5
|
import { BackHandler } from "react-native";
|
|
6
6
|
import APP from "$capp";
|