react-native upgrade to 0.71.1
parent
8b7f244812
commit
15f779a13b
|
@ -1,4 +1,5 @@
|
||||||
apply plugin: "com.android.application"
|
apply plugin: "com.android.application"
|
||||||
|
apply plugin: "com.facebook.react"
|
||||||
|
|
||||||
import com.android.build.OutputFile
|
import com.android.build.OutputFile
|
||||||
import org.apache.tools.ant.taskdefs.condition.Os
|
import org.apache.tools.ant.taskdefs.condition.Os
|
||||||
|
@ -316,4 +317,4 @@ project.ext.vectoricons = [
|
||||||
iconFontNames: [ 'MaterialIcons.ttf', 'MaterialCommunityIcons.ttf', 'FontAwesome.ttf', 'Ionicons.ttf' ] // Name of the font files you want to copy
|
iconFontNames: [ 'MaterialIcons.ttf', 'MaterialCommunityIcons.ttf', 'FontAwesome.ttf', 'Ionicons.ttf' ] // Name of the font files you want to copy
|
||||||
]
|
]
|
||||||
|
|
||||||
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
|
||||||
|
|
|
@ -2,18 +2,13 @@
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
buildToolsVersion = "31.0.0"
|
buildToolsVersion = "33.0.0"
|
||||||
minSdkVersion = 21
|
minSdkVersion = 21
|
||||||
compileSdkVersion = 31
|
compileSdkVersion = 33
|
||||||
targetSdkVersion = 31
|
targetSdkVersion = 33
|
||||||
|
|
||||||
if (System.properties['os.arch'] == "aarch64") {
|
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
|
||||||
// For M1 Users we need to use the NDK 24 which added support for aarch64
|
ndkVersion = "23.1.7779620"
|
||||||
ndkVersion = "24.0.8215888"
|
|
||||||
} else {
|
|
||||||
// Otherwise we default to the side-by-side NDK version from AGP.
|
|
||||||
ndkVersion = "21.4.7075529"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
|
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
|
@ -23,13 +23,14 @@
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"babel-preset-esnext": "^1.1.3",
|
"babel-preset-esnext": "^1.1.3",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
|
"idb": "^7.1.1",
|
||||||
"native-base": "^3.4.23",
|
"native-base": "^3.4.23",
|
||||||
|
"password-quality-calculator": "^1.0.4",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-dom": "18.1.0",
|
"react-dom": "18.1.0",
|
||||||
"react-native": "0.70.6",
|
"react-native": "0.71.1",
|
||||||
"react-native-encrypted-storage": "^4.0.3",
|
"react-native-encrypted-storage": "^4.0.3",
|
||||||
"react-native-gesture-handler": "^2.8.0",
|
"react-native-gesture-handler": "^2.8.0",
|
||||||
"react-native-reanimated": "^2.13.0",
|
|
||||||
"react-native-safe-area-context": "^4.4.1",
|
"react-native-safe-area-context": "^4.4.1",
|
||||||
"react-native-screens": "^3.18.2",
|
"react-native-screens": "^3.18.2",
|
||||||
"react-native-svg": "^13.6.0",
|
"react-native-svg": "^13.6.0",
|
||||||
|
@ -37,7 +38,8 @@
|
||||||
"react-native-vector-icons": "^9.2.0",
|
"react-native-vector-icons": "^9.2.0",
|
||||||
"react-native-web": "^0.18.10",
|
"react-native-web": "^0.18.10",
|
||||||
"react-redux": "^8.0.5",
|
"react-redux": "^8.0.5",
|
||||||
"react-string-replace": "^1.1.0"
|
"react-string-replace": "^1.1.0",
|
||||||
|
"realm": "^11.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.9",
|
"@babel/core": "^7.12.9",
|
||||||
|
@ -97,7 +99,7 @@
|
||||||
"<rootDir>"
|
"<rootDir>"
|
||||||
],
|
],
|
||||||
"setupFiles": [
|
"setupFiles": [
|
||||||
"./tests/setup.js"
|
"./mock.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"browser": [
|
"browser": [
|
||||||
|
|
|
@ -15,15 +15,25 @@ import {useEffect} from 'react';
|
||||||
import {initAppData} from '@caj/helper/appData';
|
import {initAppData} from '@caj/helper/appData';
|
||||||
import {appStatus} from '@caj/configs/appNonSaveVar';
|
import {appStatus} from '@caj/configs/appNonSaveVar';
|
||||||
import {appNonSaveVarActions} from '@caj/configs/appNonSaveVarReducer';
|
import {appNonSaveVarActions} from '@caj/configs/appNonSaveVarReducer';
|
||||||
|
import BigDataManager from '@caj/helper/storage/BigDataManager';
|
||||||
|
|
||||||
const AnimationView = animated(View);
|
const AnimationView = animated(View);
|
||||||
|
|
||||||
function onAppStart() {
|
function onAppStart() {
|
||||||
initAppData().then(() => {
|
initAppData().then(() => {
|
||||||
console.log('finish');
|
BigDataManager.initDatabase()
|
||||||
setTimeout(() => {
|
.then(() => {
|
||||||
store.dispatch(appNonSaveVarActions.setAppStatus(appStatus.APP_RUNNING));
|
console.log('finish');
|
||||||
}, 250);
|
setTimeout(() => {
|
||||||
|
store.dispatch(
|
||||||
|
appNonSaveVarActions.setAppStatus(appStatus.APP_RUNNING),
|
||||||
|
);
|
||||||
|
}, 250);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error("Database Error! Can't start App :(");
|
||||||
|
});
|
||||||
|
|
||||||
//store.dispatch(actions.loadPreferences(appVar));
|
//store.dispatch(actions.loadPreferences(appVar));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
import React, {useState, useEffect} from 'react';
|
|
||||||
|
|
||||||
import {StyleSheet, Appearance} from 'react-native';
|
|
||||||
import {SafeAreaProvider, SafeAreaView} from 'react-native-safe-area-context';
|
|
||||||
|
|
||||||
import {useSelector, useDispatch} from 'react-redux';
|
|
||||||
import {RootState} from '@caj/redux/store';
|
|
||||||
import {appVarActions} from '@caj/configs/appVarReducer';
|
|
||||||
|
|
||||||
import imgSrc from '@caj/img/maimg.png';
|
|
||||||
import {placeholder} from '@caj/lang/default';
|
|
||||||
import {getBackgroundColor} from '@caj/configs/colors';
|
|
||||||
import {saveVarChanges} from '@caj/helper/appData';
|
|
||||||
|
|
||||||
import {Box, Input, VStack, Center, Avatar, Text, Button} from 'native-base';
|
|
||||||
import {View} from 'react-native';
|
|
||||||
|
|
||||||
import {
|
|
||||||
LinkingOptions,
|
|
||||||
NavigationContainer,
|
|
||||||
useNavigation,
|
|
||||||
} from '@react-navigation/native';
|
|
||||||
import {
|
|
||||||
createNativeStackNavigator,
|
|
||||||
NativeStackNavigationProp,
|
|
||||||
} from '@react-navigation/native-stack';
|
|
||||||
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
height: '100%',
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const linking: LinkingOptions<{
|
|
||||||
Maps: string;
|
|
||||||
Home: string;
|
|
||||||
Chat: string;
|
|
||||||
Settings: string;
|
|
||||||
}> = {
|
|
||||||
prefixes: ['http://'],
|
|
||||||
config: {
|
|
||||||
screens: {
|
|
||||||
Maps: 'mapss',
|
|
||||||
Home: 'account',
|
|
||||||
Chat: 'chats',
|
|
||||||
Settings: 'settingss',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export type HomeStackNavigatorParamList = {
|
|
||||||
Account: undefined;
|
|
||||||
Maps: undefined;
|
|
||||||
Chat: undefined;
|
|
||||||
Test: undefined;
|
|
||||||
Settings: undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type HomeScreenNavigationProp =
|
|
||||||
NativeStackNavigationProp<HomeStackNavigatorParamList>;
|
|
||||||
|
|
||||||
export default function Navigation() {
|
|
||||||
const theme = useSelector(
|
|
||||||
(state: RootState) => state.appVariables.preferences.theme,
|
|
||||||
);
|
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tab.Navigator screenOptions={{headerShown: false}}>
|
|
||||||
<Tab.Screen name="Home" component={HomeStackScreen} />
|
|
||||||
<Tab.Screen name="Settings" component={SettingsScreen} />
|
|
||||||
<Tab.Screen
|
|
||||||
name="Chat"
|
|
||||||
options={{headerShown: true, tabBarStyle: {display: 'none'}}}
|
|
||||||
component={ChatScreen}
|
|
||||||
/>
|
|
||||||
</Tab.Navigator>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ChatScreen() {
|
|
||||||
return (
|
|
||||||
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
|
|
||||||
<Text>Chat!</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function HomeScreen() {
|
|
||||||
const navigation = useNavigation<HomeScreenNavigationProp>();
|
|
||||||
return (
|
|
||||||
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
|
|
||||||
<Text>Home screen</Text>
|
|
||||||
<Button onPress={() => navigation.navigate('Test')}>Go to Test</Button>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SettingsStackNavigatorParamList = {
|
|
||||||
Chat: undefined;
|
|
||||||
Settings: undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type SettingsScreenNavigationProp =
|
|
||||||
NativeStackNavigationProp<SettingsStackNavigatorParamList>;
|
|
||||||
|
|
||||||
function SettingsScreen() {
|
|
||||||
const navigation = useNavigation<SettingsScreenNavigationProp>();
|
|
||||||
const navigation2 = useNavigation<HomeScreenNavigationProp>();
|
|
||||||
return (
|
|
||||||
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
|
|
||||||
<Text>Settings screen</Text>
|
|
||||||
<Button onPress={() => navigation2.navigate('Maps')}>Go to Chat</Button>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const HomeStack = createNativeStackNavigator<HomeStackNavigatorParamList>();
|
|
||||||
|
|
||||||
function HomeStackScreen() {
|
|
||||||
return (
|
|
||||||
<HomeStack.Navigator>
|
|
||||||
<HomeStack.Screen
|
|
||||||
name="Maps"
|
|
||||||
options={{headerShown: false}}
|
|
||||||
component={HomeScreen}
|
|
||||||
/>
|
|
||||||
<HomeStack.Screen name="Test" component={ChatScreen} />
|
|
||||||
</HomeStack.Navigator>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const SettingsStack = createNativeStackNavigator<HomeStackNavigatorParamList>();
|
|
||||||
|
|
||||||
function SettingsStackScreen() {
|
|
||||||
return (
|
|
||||||
<SettingsStack.Navigator>
|
|
||||||
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
|
|
||||||
<SettingsStack.Screen name="Chat" component={ChatScreen} />
|
|
||||||
</SettingsStack.Navigator>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Tab = createBottomTabNavigator();
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import {AccountName, Username} from '@caj/helper/types';
|
||||||
|
import {RootState} from '@caj/redux/store';
|
||||||
|
import {HStack, Text} from 'native-base';
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
|
export default function NameDisplay(props: {
|
||||||
|
UserName: Username;
|
||||||
|
AccountName: AccountName;
|
||||||
|
fontSize?: number;
|
||||||
|
}) {
|
||||||
|
const theme = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.preferences.theme,
|
||||||
|
);
|
||||||
|
const fontSize = props.fontSize || 15;
|
||||||
|
const lineHeight = fontSize * 1.25;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HStack space={fontSize / 30} alignItems={'flex-end'}>
|
||||||
|
<Text fontSize={fontSize} color="primary.400">
|
||||||
|
{props.UserName !== '' ? props.UserName : '----'}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
fontSize={fontSize / 1.5}
|
||||||
|
fontFamily={'Outfit-Light'}
|
||||||
|
color="light.400">
|
||||||
|
{props.AccountName !== '' ? props.AccountName : '----'}
|
||||||
|
</Text>
|
||||||
|
</HStack>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import {AccountName, Username} from '@caj/helper/types';
|
import {AccountName, Username} from '@caj/configs/types';
|
||||||
import {RootState} from '@caj/redux/store';
|
import {RootState} from '@caj/redux/store';
|
||||||
import {HStack, Text} from 'native-base';
|
import {HStack, Text} from 'native-base';
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
|
|
|
@ -0,0 +1,960 @@
|
||||||
|
import {RegisterProcess, ThemeMode} from '@caj/configs/appVar';
|
||||||
|
import {appVarActions} from '@caj/configs/appVarReducer';
|
||||||
|
import {defaultHeaderStyle} from '@caj/configs/colors';
|
||||||
|
import {SlideFromLeftView} from '@caj/helper/animations';
|
||||||
|
import {saveVarChanges} from '@caj/helper/appData';
|
||||||
|
import {apiBackendRequest, makeRequest} from '@caj/helper/request';
|
||||||
|
import {
|
||||||
|
accountNameOptions,
|
||||||
|
EMail,
|
||||||
|
emailOptions,
|
||||||
|
passwordOptions,
|
||||||
|
userNameOptions,
|
||||||
|
XToken,
|
||||||
|
} from '@caj/helper/types';
|
||||||
|
import {RootScreenNavigationProp} from '@caj/Navigation';
|
||||||
|
import {RootState, store} from '@caj/redux/store';
|
||||||
|
import {useNavigation} from '@react-navigation/native';
|
||||||
|
import {
|
||||||
|
createNativeStackNavigator,
|
||||||
|
NativeStackNavigationProp,
|
||||||
|
} from '@react-navigation/native-stack';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Center,
|
||||||
|
Container,
|
||||||
|
FormControl,
|
||||||
|
Heading,
|
||||||
|
HStack,
|
||||||
|
Icon,
|
||||||
|
IconButton,
|
||||||
|
Input,
|
||||||
|
Pressable,
|
||||||
|
ScrollView,
|
||||||
|
Spinner,
|
||||||
|
Text,
|
||||||
|
useColorModeValue,
|
||||||
|
useTheme,
|
||||||
|
useToast,
|
||||||
|
VStack,
|
||||||
|
WarningOutlineIcon,
|
||||||
|
} from 'native-base';
|
||||||
|
|
||||||
|
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||||
|
|
||||||
|
import {baseFontSize} from 'native-base/lib/typescript/theme/tools';
|
||||||
|
import {useEffect, useRef, useState} from 'react';
|
||||||
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
|
import reactStringReplace from 'react-string-replace';
|
||||||
|
import ConfirmationCodeField from './ConfirmationCodeField';
|
||||||
|
import NameDisplay from './NameDisplay';
|
||||||
|
import showToast from './Toast';
|
||||||
|
import {NativeSyntheticEvent, TextInputFocusEventData} from 'react-native';
|
||||||
|
|
||||||
|
const validateEmail = (email: EMail) => {
|
||||||
|
return emailOptions.isAllowed(email);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function NotLoggedIn() {
|
||||||
|
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||||
|
const theme = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.preferences.theme,
|
||||||
|
);
|
||||||
|
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box alignItems="center" mt={5}>
|
||||||
|
<Text color="primary.400">{lang.appName}</Text>
|
||||||
|
<Text color="white.100">{lang.appNameDesc}</Text>
|
||||||
|
<VStack mt={5} space={4} alignItems="center">
|
||||||
|
<Button
|
||||||
|
w="72"
|
||||||
|
colorScheme="primary"
|
||||||
|
rounded="xl"
|
||||||
|
_text={{fontSize: 'xl'}}
|
||||||
|
onPress={() => {
|
||||||
|
navigation.navigate('Register', {screen: 'RegStepOne'});
|
||||||
|
}}>
|
||||||
|
Sign up
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
w="72"
|
||||||
|
colorScheme="black"
|
||||||
|
variant={theme === ThemeMode.Darkest ? 'outline' : 'subtle'}
|
||||||
|
rounded="xl"
|
||||||
|
_text={{fontSize: 'xl', color: 'white.900'}}>
|
||||||
|
Log in
|
||||||
|
</Button>
|
||||||
|
</VStack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RegisterScreenAnim(props: any) {
|
||||||
|
return (
|
||||||
|
<SlideFromLeftView>
|
||||||
|
<RegisterScreen {...props} />
|
||||||
|
</SlideFromLeftView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LoginStackNavigatorParamList = {
|
||||||
|
RegStepOne: undefined;
|
||||||
|
RegStepTwo: undefined;
|
||||||
|
RegStepFinal: undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const LoginStack = createNativeStackNavigator<LoginStackNavigatorParamList>();
|
||||||
|
|
||||||
|
export type LoginScreenNavigationProp =
|
||||||
|
NativeStackNavigationProp<LoginStackNavigatorParamList>;
|
||||||
|
|
||||||
|
function RegisterScreen() {
|
||||||
|
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||||
|
const theme = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.preferences.theme,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoginStack.Navigator>
|
||||||
|
<LoginStack.Screen
|
||||||
|
name="RegStepOne"
|
||||||
|
options={{
|
||||||
|
animation: 'slide_from_left',
|
||||||
|
title: lang.account.registration.registration,
|
||||||
|
headerShown: true,
|
||||||
|
...defaultHeaderStyle(theme, 'registration'),
|
||||||
|
}}
|
||||||
|
component={StepOne}
|
||||||
|
/>
|
||||||
|
<LoginStack.Screen
|
||||||
|
name="RegStepTwo"
|
||||||
|
options={{
|
||||||
|
animation: 'slide_from_right',
|
||||||
|
title: lang.account.registration.registration,
|
||||||
|
headerShown: true,
|
||||||
|
...defaultHeaderStyle(theme, 'registration'),
|
||||||
|
}}
|
||||||
|
component={StepTwo}
|
||||||
|
/>
|
||||||
|
<LoginStack.Screen
|
||||||
|
name="RegStepFinal"
|
||||||
|
options={{
|
||||||
|
animation: 'slide_from_right',
|
||||||
|
title: lang.account.registration.registration,
|
||||||
|
headerShown: true,
|
||||||
|
...defaultHeaderStyle(theme, 'registration'),
|
||||||
|
}}
|
||||||
|
component={StepFinal}
|
||||||
|
/>
|
||||||
|
</LoginStack.Navigator>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Agreement() {
|
||||||
|
const toast = useToast();
|
||||||
|
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||||
|
|
||||||
|
const textColor = useColorModeValue('blue.700', 'cyan.400');
|
||||||
|
|
||||||
|
let replacedText = reactStringReplace(
|
||||||
|
lang.account.registration.info,
|
||||||
|
'${TermsOfUse}',
|
||||||
|
(match, i) => (
|
||||||
|
<Text
|
||||||
|
key={match + i}
|
||||||
|
color={textColor}
|
||||||
|
bold
|
||||||
|
onPress={() => {
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.account.registration.termsOfUse,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'info',
|
||||||
|
description: undefined,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {colorScheme: 'primary'},
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
{lang.account.registration.termsOfUse}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
replacedText = reactStringReplace(
|
||||||
|
replacedText,
|
||||||
|
'${privacyPolicy}',
|
||||||
|
(match, i) => (
|
||||||
|
<Text
|
||||||
|
key={match + i}
|
||||||
|
color={textColor}
|
||||||
|
bold
|
||||||
|
onPress={() => {
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.account.registration.privacyPolicy,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'info',
|
||||||
|
description: undefined,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {colorScheme: 'primary'},
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
{lang.account.registration.privacyPolicy}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Text textAlign={'justify'} color={'white.900'}>
|
||||||
|
{replacedText}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resendMail(email: EMail, toast: any): Promise<XToken> {
|
||||||
|
return new Promise<XToken>((resolve, reject) => {
|
||||||
|
makeRequest({
|
||||||
|
path: apiBackendRequest.REGISTER_RESEND_MAIL,
|
||||||
|
|
||||||
|
requestHeader: {},
|
||||||
|
request: {
|
||||||
|
Email: email,
|
||||||
|
},
|
||||||
|
//response: {
|
||||||
|
// XToken: undefined,
|
||||||
|
//},
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
console.log(1);
|
||||||
|
let token =
|
||||||
|
store.getState().appVariables.preferences.RegisterProcess.XToken;
|
||||||
|
if (token !== undefined /*resp.response.XToken !== undefined*/) {
|
||||||
|
showToast(toast, {
|
||||||
|
title: store.getState().appVariables.lang.info,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'info',
|
||||||
|
description:
|
||||||
|
store.getState().appVariables.lang.account.registration.stepTwo
|
||||||
|
.resend[2],
|
||||||
|
isClosable: true,
|
||||||
|
rest: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
resolve(token);
|
||||||
|
} else {
|
||||||
|
reject(500);
|
||||||
|
showToast(toast, {
|
||||||
|
title: store.getState().appVariables.lang.error,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'error',
|
||||||
|
description: 'XToken is undefined',
|
||||||
|
isClosable: true,
|
||||||
|
rest: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(resp => {
|
||||||
|
let text = 'unknown error ' + resp.status;
|
||||||
|
if (resp.status !== undefined) {
|
||||||
|
const _text =
|
||||||
|
store.getState().appVariables.lang.account.registration.stepTwo
|
||||||
|
.resendError[resp.status as number];
|
||||||
|
if (_text !== undefined) text = _text;
|
||||||
|
}
|
||||||
|
|
||||||
|
showToast(toast, {
|
||||||
|
title: store.getState().appVariables.lang.error,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'error',
|
||||||
|
description: text,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
reject(resp.status);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function StepOne() {
|
||||||
|
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||||
|
const regPro = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.preferences.RegisterProcess,
|
||||||
|
);
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
const initNoErrors = {
|
||||||
|
wrongFormat: false,
|
||||||
|
alreadyExists: false,
|
||||||
|
noEntered: false,
|
||||||
|
unknown: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [errors, setErrors] = useState(initNoErrors);
|
||||||
|
|
||||||
|
const isError =
|
||||||
|
errors.wrongFormat ||
|
||||||
|
errors.alreadyExists ||
|
||||||
|
errors.noEntered ||
|
||||||
|
errors.unknown !== undefined;
|
||||||
|
|
||||||
|
const errorText = () => {
|
||||||
|
if (errors.wrongFormat) {
|
||||||
|
return lang.account.registration.stepOne.addressInvalid;
|
||||||
|
}
|
||||||
|
if (errors.alreadyExists) {
|
||||||
|
return lang.account.registration.stepOne.addressExists;
|
||||||
|
}
|
||||||
|
if (errors.noEntered) {
|
||||||
|
return lang.account.registration.stepOne.noMailEntered;
|
||||||
|
}
|
||||||
|
if (errors.unknown !== undefined) {
|
||||||
|
return errors.unknown;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const [isLoading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const [values, setValues] = useState({email: regPro.EMail});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (regPro.isRegistering === 'stepTwo') {
|
||||||
|
setLoading(true);
|
||||||
|
setErrors(initNoErrors);
|
||||||
|
|
||||||
|
setTimeout(nextStep, 500);
|
||||||
|
} else if (regPro.isRegistering === 'stepFinal') {
|
||||||
|
setLoading(true);
|
||||||
|
setErrors(initNoErrors);
|
||||||
|
|
||||||
|
setTimeout(nextStep, 500);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const nextStep = () => {
|
||||||
|
setLoading(true);
|
||||||
|
setErrors(initNoErrors);
|
||||||
|
|
||||||
|
makeRequest({
|
||||||
|
path: apiBackendRequest.REGISTER_STEP_1,
|
||||||
|
requestHeader: {},
|
||||||
|
request: {
|
||||||
|
Email: values.email,
|
||||||
|
},
|
||||||
|
response: {
|
||||||
|
XToken: undefined,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
let rp = {...regPro};
|
||||||
|
rp.isRegistering = 'stepTwo';
|
||||||
|
rp.EMail = values.email;
|
||||||
|
rp.XToken = resp.response.XToken;
|
||||||
|
|
||||||
|
dispatch(appVarActions.setRegisterProcess(rp));
|
||||||
|
saveVarChanges();
|
||||||
|
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.account.registration.stepOne.success,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'success',
|
||||||
|
description: undefined,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {colorScheme: 'primary'},
|
||||||
|
});
|
||||||
|
|
||||||
|
navigation.navigate('Register', {screen: 'RegStepTwo'});
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(resp => {
|
||||||
|
if (resp.status === 401 || resp.status === 204) {
|
||||||
|
if (regPro.XToken !== undefined) {
|
||||||
|
let rp = {...regPro};
|
||||||
|
|
||||||
|
if (resp.status === 401) {
|
||||||
|
rp.isRegistering = 'stepTwo';
|
||||||
|
rp.EMail = values.email;
|
||||||
|
|
||||||
|
dispatch(appVarActions.setRegisterProcess(rp));
|
||||||
|
saveVarChanges();
|
||||||
|
|
||||||
|
navigation.navigate('Register', {screen: 'RegStepTwo'});
|
||||||
|
} else if (resp.status === 204) {
|
||||||
|
rp.isRegistering = 'stepFinal';
|
||||||
|
rp.EMail = values.email;
|
||||||
|
|
||||||
|
dispatch(appVarActions.setRegisterProcess(rp));
|
||||||
|
saveVarChanges();
|
||||||
|
|
||||||
|
navigation.navigate('Register', {screen: 'RegStepFinal'});
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
} else {
|
||||||
|
resendMail(values.email, toast)
|
||||||
|
.then(() => {
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showToast(toast, {
|
||||||
|
title: 'Error',
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'error',
|
||||||
|
description: resp.status,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {colorScheme: 'primary'},
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView keyboardShouldPersistTaps="handled">
|
||||||
|
<Box alignItems="center" mt={5}>
|
||||||
|
<FormControl
|
||||||
|
w="75%"
|
||||||
|
maxW="350px"
|
||||||
|
isRequired
|
||||||
|
isDisabled={isLoading}
|
||||||
|
isInvalid={isError}>
|
||||||
|
<FormControl.Label>
|
||||||
|
{lang.account.registration.stepOne.title}
|
||||||
|
</FormControl.Label>
|
||||||
|
<Input
|
||||||
|
autoFocus
|
||||||
|
placeholder={lang.account.registration.stepOne.title}
|
||||||
|
value={values.email}
|
||||||
|
autoCapitalize={'none'}
|
||||||
|
maxLength={emailOptions.maxLength}
|
||||||
|
keyboardType={'email-address'}
|
||||||
|
onChangeText={text => {
|
||||||
|
const mail = text.replaceAll(' ', '');
|
||||||
|
setValues({email: mail});
|
||||||
|
|
||||||
|
if (errors.noEntered && mail !== '') {
|
||||||
|
let err = errors;
|
||||||
|
err.noEntered = false;
|
||||||
|
setErrors({...err});
|
||||||
|
}
|
||||||
|
if (errors.wrongFormat && validateEmail(mail)) {
|
||||||
|
let err = errors;
|
||||||
|
err.wrongFormat = false;
|
||||||
|
setErrors({...err});
|
||||||
|
}
|
||||||
|
if (errors.alreadyExists) {
|
||||||
|
let err = errors;
|
||||||
|
err.alreadyExists = false;
|
||||||
|
setErrors({...err});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
|
||||||
|
{errorText()}
|
||||||
|
</FormControl.ErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
<Container marginY={5}>
|
||||||
|
<Agreement />
|
||||||
|
</Container>
|
||||||
|
<Button
|
||||||
|
w="75%"
|
||||||
|
maxW="350px"
|
||||||
|
colorScheme="primary"
|
||||||
|
rounded="xl"
|
||||||
|
_text={{fontSize: 'xl'}}
|
||||||
|
isLoading={isLoading}
|
||||||
|
onPress={() => {
|
||||||
|
if (values.email === '') {
|
||||||
|
let err = errors;
|
||||||
|
err.noEntered = true;
|
||||||
|
setErrors({...err});
|
||||||
|
} else if (validateEmail(values.email)) {
|
||||||
|
nextStep();
|
||||||
|
} else {
|
||||||
|
let err = errors;
|
||||||
|
err.wrongFormat = true;
|
||||||
|
setErrors({...err});
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{lang.account.registration.stepOne.button}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function StepTwo() {
|
||||||
|
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||||
|
const regPro = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.preferences.RegisterProcess,
|
||||||
|
);
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const cellCount = 6;
|
||||||
|
const {colors} = useTheme();
|
||||||
|
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
const initNoErrors = {
|
||||||
|
noEntered: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [errors, setErrors] = useState(initNoErrors);
|
||||||
|
|
||||||
|
const [isLoading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const [values, setValues] = useState({code: ''});
|
||||||
|
|
||||||
|
const headerText = () => {
|
||||||
|
return reactStringReplace(
|
||||||
|
lang.account.registration.stepTwo.title,
|
||||||
|
'${EMail}',
|
||||||
|
(match, i) => (
|
||||||
|
<Text key={match + i} color={'primary.400'}>
|
||||||
|
{regPro.EMail}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const resendText = () => {
|
||||||
|
return reactStringReplace(
|
||||||
|
lang.account.registration.stepTwo.resend[0],
|
||||||
|
'${resend}',
|
||||||
|
(match, i) => (
|
||||||
|
<Text
|
||||||
|
key={match + i}
|
||||||
|
color={'primary.400'}
|
||||||
|
onPress={() => {
|
||||||
|
setLoading(true);
|
||||||
|
resendMail(
|
||||||
|
store.getState().appVariables.preferences.RegisterProcess.EMail,
|
||||||
|
toast,
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
{lang.account.registration.stepTwo.resend[1]}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const validate = (text: string) => {
|
||||||
|
setLoading(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
makeRequest({
|
||||||
|
path: apiBackendRequest.REGISTER_STEP_2,
|
||||||
|
|
||||||
|
requestHeader: {},
|
||||||
|
requestGET: {':verifyId': text, ':xToken': regPro.XToken || ''},
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
let rp = {...regPro};
|
||||||
|
rp.isRegistering = 'stepFinal';
|
||||||
|
|
||||||
|
dispatch(appVarActions.setRegisterProcess(rp));
|
||||||
|
saveVarChanges();
|
||||||
|
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.account.registration.stepTwo.success,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'success',
|
||||||
|
description: undefined,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {colorScheme: 'primary'},
|
||||||
|
});
|
||||||
|
|
||||||
|
navigation.navigate('Register', {screen: 'RegStepFinal'});
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(resp => {
|
||||||
|
let text = 'unknown error ' + resp.status;
|
||||||
|
if (resp.status !== undefined) {
|
||||||
|
const _text =
|
||||||
|
lang.account.registration.stepTwo.verificationError[
|
||||||
|
resp.status as number
|
||||||
|
];
|
||||||
|
if (_text !== undefined) text = _text;
|
||||||
|
}
|
||||||
|
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.error,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'error',
|
||||||
|
description: text,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
if (resp.status === 422) {
|
||||||
|
let rp = {...regPro};
|
||||||
|
rp.isRegistering = false;
|
||||||
|
|
||||||
|
dispatch(appVarActions.setRegisterProcess(rp));
|
||||||
|
saveVarChanges();
|
||||||
|
navigation.navigate('Register', {screen: 'RegStepOne'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView keyboardShouldPersistTaps="handled">
|
||||||
|
<Box alignItems="center" mt={5}>
|
||||||
|
<Center w="75%" maxW="1000px">
|
||||||
|
<Text>{headerText()}</Text>
|
||||||
|
<Box>
|
||||||
|
<FormControl isDisabled={isLoading} isInvalid={errors.noEntered}>
|
||||||
|
<ConfirmationCodeField
|
||||||
|
cellCount={cellCount}
|
||||||
|
charType="number"
|
||||||
|
disabled={isLoading}
|
||||||
|
rest={{mt: 5}}
|
||||||
|
onChange={(text: string) => {
|
||||||
|
setValues({code: text});
|
||||||
|
setErrors(initNoErrors);
|
||||||
|
}}
|
||||||
|
onFinish={(text: string) => validate(text)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormControl.ErrorMessage
|
||||||
|
leftIcon={<WarningOutlineIcon size="xs" />}>
|
||||||
|
{lang.account.registration.stepTwo.noCodeEntered}
|
||||||
|
</FormControl.ErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
</Center>
|
||||||
|
<Container marginY={5}>
|
||||||
|
<Agreement />
|
||||||
|
</Container>
|
||||||
|
<Button
|
||||||
|
w="75%"
|
||||||
|
maxW="350px"
|
||||||
|
colorScheme="primary"
|
||||||
|
rounded="xl"
|
||||||
|
_text={{fontSize: 'xl'}}
|
||||||
|
isLoading={isLoading}
|
||||||
|
onPress={() => {
|
||||||
|
if (values.code.length === cellCount) {
|
||||||
|
validate(values.code);
|
||||||
|
} else {
|
||||||
|
let err = {...errors};
|
||||||
|
err.noEntered = true;
|
||||||
|
setErrors(err);
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{lang.account.registration.stepTwo.button}
|
||||||
|
</Button>
|
||||||
|
<Container marginY={5}>
|
||||||
|
<Text textAlign={'justify'} color={'white.900'}>
|
||||||
|
{resendText()}
|
||||||
|
</Text>
|
||||||
|
</Container>
|
||||||
|
</Box>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function StepFinal() {
|
||||||
|
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||||
|
const regPro = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.preferences.RegisterProcess,
|
||||||
|
);
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const {colors} = useTheme();
|
||||||
|
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
const [isLoading, setLoading] = useState(false);
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
|
||||||
|
interface inputElementType {
|
||||||
|
label: string;
|
||||||
|
input: string;
|
||||||
|
autoCapitalize: 'none' | 'words';
|
||||||
|
errorIndex: 'none' | string;
|
||||||
|
errorTextObject: any;
|
||||||
|
isPassword: boolean | 'passwordRepeat';
|
||||||
|
minLength: number;
|
||||||
|
maxLength: number;
|
||||||
|
onTextChange: any;
|
||||||
|
textChangeTimeout: number;
|
||||||
|
isAllowed: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const accountNameRef = useRef(setTimeout(() => {}));
|
||||||
|
const accountNameFetchRef = useRef(setTimeout(() => {}));
|
||||||
|
|
||||||
|
const accountName = {
|
||||||
|
label: lang.account.registration.stepFinal.accountName,
|
||||||
|
input: '',
|
||||||
|
errorIndex: 'none',
|
||||||
|
errorTextObject: lang.account.registration.stepFinal.accountNameError,
|
||||||
|
minLength: accountNameOptions.minLength,
|
||||||
|
maxLength: accountNameOptions.maxLength,
|
||||||
|
isAllowed: accountNameOptions.isAllowed,
|
||||||
|
isPassword: false,
|
||||||
|
onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||||
|
let text = e.nativeEvent.text;
|
||||||
|
let self = accountName;
|
||||||
|
|
||||||
|
clearTimeout(accountNameRef.current);
|
||||||
|
|
||||||
|
let obj = {...valuesAccountName};
|
||||||
|
accountNameRef.current = setTimeout(() => {
|
||||||
|
obj.input = text;
|
||||||
|
|
||||||
|
if (text.length < self.minLength) obj.errorIndex = 'tooShort';
|
||||||
|
else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
|
||||||
|
else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
|
||||||
|
else obj.errorIndex = 'none';
|
||||||
|
|
||||||
|
setValuesAccountName(obj);
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
clearTimeout(accountNameFetchRef.current);
|
||||||
|
accountNameFetchRef.current = setTimeout(() => {
|
||||||
|
console.log(obj);
|
||||||
|
|
||||||
|
if (obj.errorIndex === 'none') {
|
||||||
|
makeRequest({
|
||||||
|
path: apiBackendRequest.REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK,
|
||||||
|
request: {AccountName: obj.input},
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
console.log('OK');
|
||||||
|
})
|
||||||
|
.catch(resp => {
|
||||||
|
if (resp.status !== undefined) {
|
||||||
|
obj.errorIndex = resp.status;
|
||||||
|
setValuesAccountName(obj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 750);
|
||||||
|
},
|
||||||
|
} as inputElementType;
|
||||||
|
const [valuesAccountName, setValuesAccountName] = useState(accountName);
|
||||||
|
|
||||||
|
const userNameRef = useRef(setTimeout(() => {}));
|
||||||
|
|
||||||
|
const userName = {
|
||||||
|
label: lang.account.registration.stepFinal.userName,
|
||||||
|
input: '',
|
||||||
|
errorIndex: 'none',
|
||||||
|
errorTextObject: lang.account.registration.stepFinal.userNameError,
|
||||||
|
minLength: userNameOptions.minLength,
|
||||||
|
maxLength: userNameOptions.maxLength,
|
||||||
|
isAllowed: userNameOptions.isAllowed,
|
||||||
|
isPassword: false,
|
||||||
|
onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||||
|
let text = e.nativeEvent.text;
|
||||||
|
let self = userName;
|
||||||
|
|
||||||
|
clearTimeout(userNameRef.current);
|
||||||
|
|
||||||
|
userNameRef.current = setTimeout(() => {
|
||||||
|
let obj = {...valuesUserName};
|
||||||
|
obj.input = text;
|
||||||
|
|
||||||
|
if (text.length < self.minLength) obj.errorIndex = 'tooShort';
|
||||||
|
else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
|
||||||
|
else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
|
||||||
|
else obj.errorIndex = 'none';
|
||||||
|
|
||||||
|
setValuesUserName(obj);
|
||||||
|
}, 50);
|
||||||
|
},
|
||||||
|
} as inputElementType;
|
||||||
|
const [valuesUserName, setValuesUserName] = useState(userName);
|
||||||
|
|
||||||
|
const passwordRef = useRef(setTimeout(() => {}));
|
||||||
|
|
||||||
|
const password = {
|
||||||
|
label: lang.account.registration.stepFinal.password,
|
||||||
|
input: '',
|
||||||
|
errorIndex: 'none',
|
||||||
|
errorTextObject: lang.account.registration.stepFinal.passwordError,
|
||||||
|
minLength: passwordOptions.minLength,
|
||||||
|
maxLength: passwordOptions.maxLength,
|
||||||
|
isAllowed: passwordOptions.isAllowed,
|
||||||
|
isPassword: true,
|
||||||
|
onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||||
|
let text = e.nativeEvent.text;
|
||||||
|
let self = password;
|
||||||
|
|
||||||
|
clearTimeout(passwordRef.current);
|
||||||
|
|
||||||
|
passwordRef.current = setTimeout(() => {
|
||||||
|
let obj = {...valuesPassword};
|
||||||
|
obj.input = text;
|
||||||
|
|
||||||
|
if (text.length < self.minLength) obj.errorIndex = 'tooShort';
|
||||||
|
else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
|
||||||
|
else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
|
||||||
|
else obj.errorIndex = 'none';
|
||||||
|
|
||||||
|
setValuesPassword(obj);
|
||||||
|
|
||||||
|
let objRe = {...valuesPasswordRe};
|
||||||
|
if (text !== valuesPasswordRe.input) objRe.errorIndex = 'noMatch';
|
||||||
|
else objRe.errorIndex = 'none';
|
||||||
|
|
||||||
|
setValuesPasswordRe(objRe);
|
||||||
|
}, 50);
|
||||||
|
},
|
||||||
|
} as inputElementType;
|
||||||
|
const [valuesPassword, setValuesPassword] = useState(password);
|
||||||
|
|
||||||
|
const passwordReRef = useRef(setTimeout(() => {}));
|
||||||
|
|
||||||
|
const passwordRe = {
|
||||||
|
label: lang.account.registration.stepFinal.passwordRepeat,
|
||||||
|
input: '',
|
||||||
|
errorIndex: 'none',
|
||||||
|
errorTextObject: lang.account.registration.stepFinal.passwordError,
|
||||||
|
minLength: passwordOptions.minLength,
|
||||||
|
maxLength: passwordOptions.maxLength,
|
||||||
|
isAllowed: passwordOptions.isAllowed,
|
||||||
|
isPassword: 'passwordRepeat',
|
||||||
|
onTextChange: (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||||
|
let text = e.nativeEvent.text;
|
||||||
|
let self = passwordRe;
|
||||||
|
|
||||||
|
clearTimeout(passwordReRef.current);
|
||||||
|
|
||||||
|
passwordReRef.current = setTimeout(() => {
|
||||||
|
let obj = {...valuesPasswordRe};
|
||||||
|
obj.input = text;
|
||||||
|
console.log(text, valuesPassword.input);
|
||||||
|
|
||||||
|
if (text !== valuesPassword.input) obj.errorIndex = 'noMatch';
|
||||||
|
else obj.errorIndex = 'none';
|
||||||
|
|
||||||
|
setValuesPasswordRe(obj);
|
||||||
|
}, 50);
|
||||||
|
},
|
||||||
|
} as inputElementType;
|
||||||
|
const [valuesPasswordRe, setValuesPasswordRe] = useState(passwordRe);
|
||||||
|
|
||||||
|
const inputElement = (
|
||||||
|
val: inputElementType,
|
||||||
|
set: React.Dispatch<React.SetStateAction<inputElementType>>,
|
||||||
|
valConst: inputElementType,
|
||||||
|
autofocus?: boolean,
|
||||||
|
) => {
|
||||||
|
const isPassword =
|
||||||
|
val.isPassword === true || val.isPassword === 'passwordRepeat';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl
|
||||||
|
w="75%"
|
||||||
|
maxW="350px"
|
||||||
|
isRequired
|
||||||
|
isDisabled={isLoading}
|
||||||
|
isInvalid={val.errorIndex !== 'none'}>
|
||||||
|
<FormControl.Label>{val.label}</FormControl.Label>
|
||||||
|
<Input
|
||||||
|
autoFocus={autofocus}
|
||||||
|
type={isPassword && showPassword === false ? 'password' : 'text'}
|
||||||
|
placeholder={''}
|
||||||
|
keyboardType={'default'}
|
||||||
|
onChange={valConst.onTextChange}
|
||||||
|
InputRightElement={
|
||||||
|
isPassword ? (
|
||||||
|
<IconButton
|
||||||
|
mr="2"
|
||||||
|
onPress={() => setShowPassword(!showPassword)}
|
||||||
|
icon={
|
||||||
|
<MaterialIcons
|
||||||
|
size={20}
|
||||||
|
name={showPassword ? 'visibility' : 'visibility-off'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
borderRadius="full"
|
||||||
|
/>
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
|
||||||
|
{val.errorTextObject[val.errorIndex] !== undefined
|
||||||
|
? val.errorTextObject[val.errorIndex]
|
||||||
|
.replaceAll('$(minLength)', val.minLength)
|
||||||
|
.replaceAll('$(maxLength)', val.maxLength)
|
||||||
|
: val.errorTextObject[val.errorIndex] !== 'none'
|
||||||
|
? lang.error
|
||||||
|
: null}
|
||||||
|
</FormControl.ErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView keyboardShouldPersistTaps="handled">
|
||||||
|
<VStack space={3} alignItems="center" mt={5}>
|
||||||
|
<Container maxWidth={'100%'} alignItems={'center'}>
|
||||||
|
<Center>
|
||||||
|
<Text>{lang.account.registration.stepFinal.displayName}</Text>
|
||||||
|
<NameDisplay
|
||||||
|
UserName={
|
||||||
|
valuesUserName.input !== ''
|
||||||
|
? valuesUserName.input
|
||||||
|
: lang.account.registration.stepFinal.userName
|
||||||
|
}
|
||||||
|
AccountName={
|
||||||
|
valuesAccountName.input !== ''
|
||||||
|
? valuesAccountName.input
|
||||||
|
: lang.account.registration.stepFinal.accountName
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Container>
|
||||||
|
{inputElement(valuesUserName, setValuesUserName, userName)}
|
||||||
|
{inputElement(valuesAccountName, setValuesAccountName, accountName)}
|
||||||
|
{inputElement(valuesPassword, setValuesPassword, password)}
|
||||||
|
{inputElement(valuesPasswordRe, setValuesPasswordRe, passwordRe)}
|
||||||
|
</VStack>
|
||||||
|
<Center>
|
||||||
|
<Container mt={5}>
|
||||||
|
<Agreement />
|
||||||
|
</Container>
|
||||||
|
<Button
|
||||||
|
marginY={5}
|
||||||
|
w="75%"
|
||||||
|
maxW="350px"
|
||||||
|
colorScheme="primary"
|
||||||
|
rounded="xl"
|
||||||
|
_text={{fontSize: 'xl'}}
|
||||||
|
isLoading={isLoading}
|
||||||
|
onPress={() => {}}>
|
||||||
|
{lang.account.registration.stepFinal.button}
|
||||||
|
</Button>
|
||||||
|
</Center>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ import {
|
||||||
passwordOptions,
|
passwordOptions,
|
||||||
userNameOptions,
|
userNameOptions,
|
||||||
XToken,
|
XToken,
|
||||||
} from '@caj/helper/types';
|
} from '@caj/configs/types';
|
||||||
import {RootScreenNavigationProp} from '@caj/Navigation';
|
import {RootScreenNavigationProp} from '@caj/Navigation';
|
||||||
import {RootState, store} from '@caj/redux/store';
|
import {RootState, store} from '@caj/redux/store';
|
||||||
import {useNavigation} from '@react-navigation/native';
|
import {useNavigation} from '@react-navigation/native';
|
||||||
|
@ -25,25 +25,20 @@ import {
|
||||||
Center,
|
Center,
|
||||||
Container,
|
Container,
|
||||||
FormControl,
|
FormControl,
|
||||||
Heading,
|
|
||||||
HStack,
|
|
||||||
Icon,
|
|
||||||
IconButton,
|
IconButton,
|
||||||
Input,
|
Input,
|
||||||
Pressable,
|
|
||||||
ScrollView,
|
ScrollView,
|
||||||
Spinner,
|
|
||||||
Text,
|
Text,
|
||||||
useColorModeValue,
|
useColorModeValue,
|
||||||
useTheme,
|
useTheme,
|
||||||
useToast,
|
useToast,
|
||||||
VStack,
|
VStack,
|
||||||
WarningOutlineIcon,
|
WarningOutlineIcon,
|
||||||
|
Progress,
|
||||||
} from 'native-base';
|
} from 'native-base';
|
||||||
|
|
||||||
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||||
|
|
||||||
import {baseFontSize} from 'native-base/lib/typescript/theme/tools';
|
|
||||||
import {useEffect, useRef, useState} from 'react';
|
import {useEffect, useRef, useState} from 'react';
|
||||||
import {useDispatch, useSelector} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
import reactStringReplace from 'react-string-replace';
|
import reactStringReplace from 'react-string-replace';
|
||||||
|
@ -52,6 +47,17 @@ import NameDisplay from './NameDisplay';
|
||||||
import showToast from './Toast';
|
import showToast from './Toast';
|
||||||
import {NativeSyntheticEvent, TextInputFocusEventData} from 'react-native';
|
import {NativeSyntheticEvent, TextInputFocusEventData} from 'react-native';
|
||||||
|
|
||||||
|
import PasswordQualityCalculator from '@caj/helper/password-quality-calculator/PasswordQualityCalculator';
|
||||||
|
|
||||||
|
// [ optional ] list of about 10000 most common passwords, 86kb (gzip 32kb)
|
||||||
|
import MostPopularPasswords from '@caj/helper/password-quality-calculator/MostPopularPasswords';
|
||||||
|
import MyUserManager from '@caj/user/MyUserManager';
|
||||||
|
|
||||||
|
const Buffer = require('buffer').Buffer;
|
||||||
|
|
||||||
|
// Load the popular passwords list
|
||||||
|
PasswordQualityCalculator.PopularPasswords.load(MostPopularPasswords);
|
||||||
|
|
||||||
const validateEmail = (email: EMail) => {
|
const validateEmail = (email: EMail) => {
|
||||||
return emailOptions.isAllowed(email);
|
return emailOptions.isAllowed(email);
|
||||||
};
|
};
|
||||||
|
@ -86,7 +92,10 @@ export default function NotLoggedIn() {
|
||||||
colorScheme="black"
|
colorScheme="black"
|
||||||
variant={theme === ThemeMode.Darkest ? 'outline' : 'subtle'}
|
variant={theme === ThemeMode.Darkest ? 'outline' : 'subtle'}
|
||||||
rounded="xl"
|
rounded="xl"
|
||||||
_text={{fontSize: 'xl', color: 'white.900'}}>
|
_text={{fontSize: 'xl', color: 'white.900'}}
|
||||||
|
onPress={() => {
|
||||||
|
navigation.navigate('Register', {screen: 'Login'});
|
||||||
|
}}>
|
||||||
Log in
|
Log in
|
||||||
</Button>
|
</Button>
|
||||||
</VStack>
|
</VStack>
|
||||||
|
@ -106,6 +115,7 @@ export type LoginStackNavigatorParamList = {
|
||||||
RegStepOne: undefined;
|
RegStepOne: undefined;
|
||||||
RegStepTwo: undefined;
|
RegStepTwo: undefined;
|
||||||
RegStepFinal: undefined;
|
RegStepFinal: undefined;
|
||||||
|
Login: undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoginStack = createNativeStackNavigator<LoginStackNavigatorParamList>();
|
const LoginStack = createNativeStackNavigator<LoginStackNavigatorParamList>();
|
||||||
|
@ -151,6 +161,16 @@ function RegisterScreen() {
|
||||||
}}
|
}}
|
||||||
component={StepFinal}
|
component={StepFinal}
|
||||||
/>
|
/>
|
||||||
|
<LoginStack.Screen
|
||||||
|
name="Login"
|
||||||
|
options={{
|
||||||
|
animation: 'slide_from_right',
|
||||||
|
title: lang.account.login.title,
|
||||||
|
headerShown: true,
|
||||||
|
...defaultHeaderStyle(theme, 'registration'),
|
||||||
|
}}
|
||||||
|
component={Login}
|
||||||
|
/>
|
||||||
</LoginStack.Navigator>
|
</LoginStack.Navigator>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -218,20 +238,35 @@ function resendMail(email: EMail, toast: any): Promise<XToken> {
|
||||||
return new Promise<XToken>((resolve, reject) => {
|
return new Promise<XToken>((resolve, reject) => {
|
||||||
makeRequest({
|
makeRequest({
|
||||||
path: apiBackendRequest.REGISTER_RESEND_MAIL,
|
path: apiBackendRequest.REGISTER_RESEND_MAIL,
|
||||||
|
requestHeader: {
|
||||||
requestHeader: {},
|
'X-Token':
|
||||||
|
store.getState().appVariables.preferences.RegisterProcess.XToken,
|
||||||
|
},
|
||||||
request: {
|
request: {
|
||||||
Email: email,
|
Email: email,
|
||||||
},
|
},
|
||||||
//response: {
|
response: {
|
||||||
// XToken: undefined,
|
XToken: undefined,
|
||||||
//},
|
},
|
||||||
})
|
})
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
console.log(1);
|
|
||||||
let token =
|
let token =
|
||||||
store.getState().appVariables.preferences.RegisterProcess.XToken;
|
store.getState().appVariables.preferences.RegisterProcess.XToken;
|
||||||
if (token !== undefined /*resp.response.XToken !== undefined*/) {
|
if (token === undefined) token = '';
|
||||||
|
|
||||||
|
if (resp.response.XToken !== undefined || token !== undefined) {
|
||||||
|
if (resp.response.XToken !== undefined) {
|
||||||
|
token = resp.response.XToken;
|
||||||
|
|
||||||
|
let regPro = {
|
||||||
|
...store.getState().appVariables.preferences.RegisterProcess,
|
||||||
|
};
|
||||||
|
regPro.XToken = token;
|
||||||
|
store.dispatch(appVarActions.setRegisterProcess(regPro));
|
||||||
|
|
||||||
|
saveVarChanges();
|
||||||
|
}
|
||||||
|
|
||||||
showToast(toast, {
|
showToast(toast, {
|
||||||
title: store.getState().appVariables.lang.info,
|
title: store.getState().appVariables.lang.info,
|
||||||
variant: 'solid',
|
variant: 'solid',
|
||||||
|
@ -257,7 +292,7 @@ function resendMail(email: EMail, toast: any): Promise<XToken> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(resp => {
|
.catch(resp => {
|
||||||
let text = 'unknown error ' + resp.status;
|
let text = 'Error ' + resp.status;
|
||||||
if (resp.status !== undefined) {
|
if (resp.status !== undefined) {
|
||||||
const _text =
|
const _text =
|
||||||
store.getState().appVariables.lang.account.registration.stepTwo
|
store.getState().appVariables.lang.account.registration.stepTwo
|
||||||
|
@ -342,6 +377,12 @@ function StepOne() {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setErrors(initNoErrors);
|
setErrors(initNoErrors);
|
||||||
|
|
||||||
|
let rp = {...regPro};
|
||||||
|
|
||||||
|
if (rp.EMail !== values.email) {
|
||||||
|
rp.XToken = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
makeRequest({
|
makeRequest({
|
||||||
path: apiBackendRequest.REGISTER_STEP_1,
|
path: apiBackendRequest.REGISTER_STEP_1,
|
||||||
requestHeader: {},
|
requestHeader: {},
|
||||||
|
@ -353,7 +394,6 @@ function StepOne() {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
let rp = {...regPro};
|
|
||||||
rp.isRegistering = 'stepTwo';
|
rp.isRegistering = 'stepTwo';
|
||||||
rp.EMail = values.email;
|
rp.EMail = values.email;
|
||||||
rp.XToken = resp.response.XToken;
|
rp.XToken = resp.response.XToken;
|
||||||
|
@ -376,8 +416,6 @@ function StepOne() {
|
||||||
.catch(resp => {
|
.catch(resp => {
|
||||||
if (resp.status === 401 || resp.status === 204) {
|
if (resp.status === 401 || resp.status === 204) {
|
||||||
if (regPro.XToken !== undefined) {
|
if (regPro.XToken !== undefined) {
|
||||||
let rp = {...regPro};
|
|
||||||
|
|
||||||
if (resp.status === 401) {
|
if (resp.status === 401) {
|
||||||
rp.isRegistering = 'stepTwo';
|
rp.isRegistering = 'stepTwo';
|
||||||
rp.EMail = values.email;
|
rp.EMail = values.email;
|
||||||
|
@ -400,26 +438,51 @@ function StepOne() {
|
||||||
} else {
|
} else {
|
||||||
resendMail(values.email, toast)
|
resendMail(values.email, toast)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
navigation.navigate('Register', {screen: 'RegStepTwo'});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
} else if (resp.status === 422) {
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.error,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'error',
|
||||||
|
description: lang.account.registration.stepOne.addressExists,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {colorScheme: 'primary'},
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
showToast(toast, {
|
showToast(toast, {
|
||||||
title: 'Error',
|
title: lang.error,
|
||||||
variant: 'solid',
|
variant: 'solid',
|
||||||
status: 'error',
|
status: 'error',
|
||||||
description: resp.status,
|
description: resp.status,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
rest: {colorScheme: 'primary'},
|
rest: {colorScheme: 'primary'},
|
||||||
});
|
});
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
|
setLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onButtonPress = () => {
|
||||||
|
if (values.email === '') {
|
||||||
|
let err = errors;
|
||||||
|
err.noEntered = true;
|
||||||
|
setErrors({...err});
|
||||||
|
} else if (validateEmail(values.email)) {
|
||||||
|
nextStep();
|
||||||
|
} else {
|
||||||
|
let err = errors;
|
||||||
|
err.wrongFormat = true;
|
||||||
|
setErrors({...err});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView keyboardShouldPersistTaps="handled">
|
<ScrollView keyboardShouldPersistTaps="handled">
|
||||||
<Box alignItems="center" mt={5}>
|
<Box alignItems="center" mt={5}>
|
||||||
|
@ -434,8 +497,10 @@ function StepOne() {
|
||||||
</FormControl.Label>
|
</FormControl.Label>
|
||||||
<Input
|
<Input
|
||||||
autoFocus
|
autoFocus
|
||||||
|
autoComplete="email"
|
||||||
placeholder={lang.account.registration.stepOne.title}
|
placeholder={lang.account.registration.stepOne.title}
|
||||||
value={values.email}
|
value={values.email}
|
||||||
|
onSubmitEditing={onButtonPress}
|
||||||
autoCapitalize={'none'}
|
autoCapitalize={'none'}
|
||||||
maxLength={emailOptions.maxLength}
|
maxLength={emailOptions.maxLength}
|
||||||
keyboardType={'email-address'}
|
keyboardType={'email-address'}
|
||||||
|
@ -475,19 +540,7 @@ function StepOne() {
|
||||||
rounded="xl"
|
rounded="xl"
|
||||||
_text={{fontSize: 'xl'}}
|
_text={{fontSize: 'xl'}}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
onPress={() => {
|
onPress={onButtonPress}>
|
||||||
if (values.email === '') {
|
|
||||||
let err = errors;
|
|
||||||
err.noEntered = true;
|
|
||||||
setErrors({...err});
|
|
||||||
} else if (validateEmail(values.email)) {
|
|
||||||
nextStep();
|
|
||||||
} else {
|
|
||||||
let err = errors;
|
|
||||||
err.wrongFormat = true;
|
|
||||||
setErrors({...err});
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
{lang.account.registration.stepOne.button}
|
{lang.account.registration.stepOne.button}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -588,7 +641,7 @@ function StepTwo() {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
.catch(resp => {
|
.catch(resp => {
|
||||||
let text = 'unknown error ' + resp.status;
|
let text = 'Error ' + resp.status;
|
||||||
if (resp.status !== undefined) {
|
if (resp.status !== undefined) {
|
||||||
const _text =
|
const _text =
|
||||||
lang.account.registration.stepTwo.verificationError[
|
lang.account.registration.stepTwo.verificationError[
|
||||||
|
@ -704,6 +757,7 @@ function StepFinal() {
|
||||||
onTextChange: any;
|
onTextChange: any;
|
||||||
textChangeTimeout: number;
|
textChangeTimeout: number;
|
||||||
isAllowed: any;
|
isAllowed: any;
|
||||||
|
autoComplete?: 'name' | 'username-new' | 'password-new';
|
||||||
}
|
}
|
||||||
|
|
||||||
const accountNameRef = useRef(setTimeout(() => {}));
|
const accountNameRef = useRef(setTimeout(() => {}));
|
||||||
|
@ -712,6 +766,7 @@ function StepFinal() {
|
||||||
const accountName = {
|
const accountName = {
|
||||||
label: lang.account.registration.stepFinal.accountName,
|
label: lang.account.registration.stepFinal.accountName,
|
||||||
input: '',
|
input: '',
|
||||||
|
autoComplete: 'username-new',
|
||||||
errorIndex: 'none',
|
errorIndex: 'none',
|
||||||
errorTextObject: lang.account.registration.stepFinal.accountNameError,
|
errorTextObject: lang.account.registration.stepFinal.accountNameError,
|
||||||
minLength: accountNameOptions.minLength,
|
minLength: accountNameOptions.minLength,
|
||||||
|
@ -734,28 +789,25 @@ function StepFinal() {
|
||||||
else obj.errorIndex = 'none';
|
else obj.errorIndex = 'none';
|
||||||
|
|
||||||
setValuesAccountName(obj);
|
setValuesAccountName(obj);
|
||||||
|
|
||||||
|
accountNameFetchRef.current = setTimeout(() => {
|
||||||
|
if (obj.errorIndex === 'none') {
|
||||||
|
makeRequest({
|
||||||
|
path: apiBackendRequest.REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK,
|
||||||
|
request: {AccountName: obj.input},
|
||||||
|
})
|
||||||
|
.then(resp => {})
|
||||||
|
.catch(resp => {
|
||||||
|
if (resp.status !== undefined) {
|
||||||
|
obj.errorIndex = resp.status;
|
||||||
|
setValuesAccountName({...obj});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 750);
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
clearTimeout(accountNameFetchRef.current);
|
clearTimeout(accountNameFetchRef.current);
|
||||||
accountNameFetchRef.current = setTimeout(() => {
|
|
||||||
console.log(obj);
|
|
||||||
|
|
||||||
if (obj.errorIndex === 'none') {
|
|
||||||
makeRequest({
|
|
||||||
path: apiBackendRequest.REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK,
|
|
||||||
request: {AccountName: obj.input},
|
|
||||||
})
|
|
||||||
.then(resp => {
|
|
||||||
console.log('OK');
|
|
||||||
})
|
|
||||||
.catch(resp => {
|
|
||||||
if (resp.status !== undefined) {
|
|
||||||
obj.errorIndex = resp.status;
|
|
||||||
setValuesAccountName(obj);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 750);
|
|
||||||
},
|
},
|
||||||
} as inputElementType;
|
} as inputElementType;
|
||||||
const [valuesAccountName, setValuesAccountName] = useState(accountName);
|
const [valuesAccountName, setValuesAccountName] = useState(accountName);
|
||||||
|
@ -765,6 +817,7 @@ function StepFinal() {
|
||||||
const userName = {
|
const userName = {
|
||||||
label: lang.account.registration.stepFinal.userName,
|
label: lang.account.registration.stepFinal.userName,
|
||||||
input: '',
|
input: '',
|
||||||
|
autoComplete: 'name',
|
||||||
errorIndex: 'none',
|
errorIndex: 'none',
|
||||||
errorTextObject: lang.account.registration.stepFinal.userNameError,
|
errorTextObject: lang.account.registration.stepFinal.userNameError,
|
||||||
minLength: userNameOptions.minLength,
|
minLength: userNameOptions.minLength,
|
||||||
|
@ -797,6 +850,7 @@ function StepFinal() {
|
||||||
const password = {
|
const password = {
|
||||||
label: lang.account.registration.stepFinal.password,
|
label: lang.account.registration.stepFinal.password,
|
||||||
input: '',
|
input: '',
|
||||||
|
autoComplete: 'password-new',
|
||||||
errorIndex: 'none',
|
errorIndex: 'none',
|
||||||
errorTextObject: lang.account.registration.stepFinal.passwordError,
|
errorTextObject: lang.account.registration.stepFinal.passwordError,
|
||||||
minLength: passwordOptions.minLength,
|
minLength: passwordOptions.minLength,
|
||||||
|
@ -813,28 +867,56 @@ function StepFinal() {
|
||||||
let obj = {...valuesPassword};
|
let obj = {...valuesPassword};
|
||||||
obj.input = text;
|
obj.input = text;
|
||||||
|
|
||||||
|
let PasswordQuality = PasswordQualityCalculator(text);
|
||||||
|
setPasswordQuality(PasswordQuality);
|
||||||
|
|
||||||
if (text.length < self.minLength) obj.errorIndex = 'tooShort';
|
if (text.length < self.minLength) obj.errorIndex = 'tooShort';
|
||||||
else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
|
else if (text.length > self.maxLength) obj.errorIndex = 'tooLong';
|
||||||
else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
|
else if (self.isAllowed(text) === false) obj.errorIndex = 'invalid';
|
||||||
|
else if (passwordOptions.minBits >= PasswordQuality)
|
||||||
|
obj.errorIndex = 'weak';
|
||||||
else obj.errorIndex = 'none';
|
else obj.errorIndex = 'none';
|
||||||
|
|
||||||
setValuesPassword(obj);
|
setValuesPassword(obj);
|
||||||
|
|
||||||
let objRe = {...valuesPasswordRe};
|
let objRe = {...valuesPasswordRe};
|
||||||
if (text !== valuesPasswordRe.input) objRe.errorIndex = 'noMatch';
|
if (valuesPasswordRe.input !== '') {
|
||||||
else objRe.errorIndex = 'none';
|
if (text !== valuesPasswordRe.input) objRe.errorIndex = 'noMatch';
|
||||||
|
else objRe.errorIndex = 'none';
|
||||||
|
|
||||||
setValuesPasswordRe(objRe);
|
setValuesPasswordRe(objRe);
|
||||||
|
}
|
||||||
}, 50);
|
}, 50);
|
||||||
},
|
},
|
||||||
} as inputElementType;
|
} as inputElementType;
|
||||||
const [valuesPassword, setValuesPassword] = useState(password);
|
const [valuesPassword, setValuesPassword] = useState(password);
|
||||||
|
const [passwordQuality, setPasswordQuality] = useState(0);
|
||||||
|
|
||||||
|
let passwordQualityIndex = 0;
|
||||||
|
if (passwordQuality >= 128) passwordQualityIndex = 4;
|
||||||
|
else if (passwordQuality >= 100) passwordQualityIndex = 3;
|
||||||
|
else if (passwordQuality >= 80) passwordQualityIndex = 2;
|
||||||
|
else if (passwordQuality >= 50) passwordQualityIndex = 1;
|
||||||
|
let passwordQualityPercent = (passwordQuality / 128.0) * 100;
|
||||||
|
passwordQualityPercent =
|
||||||
|
passwordQualityPercent >= 100.0 ? 100 : passwordQualityPercent;
|
||||||
|
|
||||||
|
const passwordQualityColor = 'hsl(' + passwordQualityPercent + ', 100%, 50%)';
|
||||||
|
|
||||||
|
const passwordQualityText =
|
||||||
|
lang.account.registration.stepFinal.passwordQuality.replace(
|
||||||
|
'${quality}',
|
||||||
|
lang.account.registration.stepFinal.passwordQualityList[
|
||||||
|
passwordQualityIndex
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
const passwordReRef = useRef(setTimeout(() => {}));
|
const passwordReRef = useRef(setTimeout(() => {}));
|
||||||
|
|
||||||
const passwordRe = {
|
const passwordRe = {
|
||||||
label: lang.account.registration.stepFinal.passwordRepeat,
|
label: lang.account.registration.stepFinal.passwordRepeat,
|
||||||
input: '',
|
input: '',
|
||||||
|
autoComplete: 'password-new',
|
||||||
errorIndex: 'none',
|
errorIndex: 'none',
|
||||||
errorTextObject: lang.account.registration.stepFinal.passwordError,
|
errorTextObject: lang.account.registration.stepFinal.passwordError,
|
||||||
minLength: passwordOptions.minLength,
|
minLength: passwordOptions.minLength,
|
||||||
|
@ -850,7 +932,6 @@ function StepFinal() {
|
||||||
passwordReRef.current = setTimeout(() => {
|
passwordReRef.current = setTimeout(() => {
|
||||||
let obj = {...valuesPasswordRe};
|
let obj = {...valuesPasswordRe};
|
||||||
obj.input = text;
|
obj.input = text;
|
||||||
console.log(text, valuesPassword.input);
|
|
||||||
|
|
||||||
if (text !== valuesPassword.input) obj.errorIndex = 'noMatch';
|
if (text !== valuesPassword.input) obj.errorIndex = 'noMatch';
|
||||||
else obj.errorIndex = 'none';
|
else obj.errorIndex = 'none';
|
||||||
|
@ -873,12 +954,13 @@ function StepFinal() {
|
||||||
return (
|
return (
|
||||||
<FormControl
|
<FormControl
|
||||||
w="75%"
|
w="75%"
|
||||||
maxW="350px"
|
maxW={350}
|
||||||
isRequired
|
isRequired
|
||||||
isDisabled={isLoading}
|
isDisabled={isLoading}
|
||||||
isInvalid={val.errorIndex !== 'none'}>
|
isInvalid={val.errorIndex !== 'none'}>
|
||||||
<FormControl.Label>{val.label}</FormControl.Label>
|
<FormControl.Label>{val.label}</FormControl.Label>
|
||||||
<Input
|
<Input
|
||||||
|
autoComplete={val.autoComplete}
|
||||||
autoFocus={autofocus}
|
autoFocus={autofocus}
|
||||||
type={isPassword && showPassword === false ? 'password' : 'text'}
|
type={isPassword && showPassword === false ? 'password' : 'text'}
|
||||||
placeholder={''}
|
placeholder={''}
|
||||||
|
@ -888,10 +970,12 @@ function StepFinal() {
|
||||||
isPassword ? (
|
isPassword ? (
|
||||||
<IconButton
|
<IconButton
|
||||||
mr="2"
|
mr="2"
|
||||||
|
focusable={false}
|
||||||
onPress={() => setShowPassword(!showPassword)}
|
onPress={() => setShowPassword(!showPassword)}
|
||||||
icon={
|
icon={
|
||||||
<MaterialIcons
|
<MaterialIcons
|
||||||
size={20}
|
size={20}
|
||||||
|
color={colors.white[200]}
|
||||||
name={showPassword ? 'visibility' : 'visibility-off'}
|
name={showPassword ? 'visibility' : 'visibility-off'}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
@ -904,8 +988,8 @@ function StepFinal() {
|
||||||
<FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
|
<FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
|
||||||
{val.errorTextObject[val.errorIndex] !== undefined
|
{val.errorTextObject[val.errorIndex] !== undefined
|
||||||
? val.errorTextObject[val.errorIndex]
|
? val.errorTextObject[val.errorIndex]
|
||||||
.replaceAll('$(minLength)', val.minLength)
|
.replaceAll('${minLength}', val.minLength)
|
||||||
.replaceAll('$(maxLength)', val.maxLength)
|
.replaceAll('${maxLength}', val.maxLength)
|
||||||
: val.errorTextObject[val.errorIndex] !== 'none'
|
: val.errorTextObject[val.errorIndex] !== 'none'
|
||||||
? lang.error
|
? lang.error
|
||||||
: null}
|
: null}
|
||||||
|
@ -937,6 +1021,20 @@ function StepFinal() {
|
||||||
{inputElement(valuesUserName, setValuesUserName, userName)}
|
{inputElement(valuesUserName, setValuesUserName, userName)}
|
||||||
{inputElement(valuesAccountName, setValuesAccountName, accountName)}
|
{inputElement(valuesAccountName, setValuesAccountName, accountName)}
|
||||||
{inputElement(valuesPassword, setValuesPassword, password)}
|
{inputElement(valuesPassword, setValuesPassword, password)}
|
||||||
|
|
||||||
|
<Box w="75%" maxW={350}>
|
||||||
|
<Text mx={4} mb={1} fontSize={13} color="light.400">
|
||||||
|
{passwordQualityText}
|
||||||
|
</Text>
|
||||||
|
<Progress
|
||||||
|
value={passwordQualityPercent}
|
||||||
|
mx={4}
|
||||||
|
_filledTrack={{
|
||||||
|
bg: passwordQualityColor,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
{inputElement(valuesPasswordRe, setValuesPasswordRe, passwordRe)}
|
{inputElement(valuesPasswordRe, setValuesPasswordRe, passwordRe)}
|
||||||
</VStack>
|
</VStack>
|
||||||
<Center>
|
<Center>
|
||||||
|
@ -951,10 +1049,400 @@ function StepFinal() {
|
||||||
rounded="xl"
|
rounded="xl"
|
||||||
_text={{fontSize: 'xl'}}
|
_text={{fontSize: 'xl'}}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
onPress={() => {}}>
|
onPress={() => {
|
||||||
|
function showToastNow(text: string) {
|
||||||
|
showToast(toast, {
|
||||||
|
title: text,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'error',
|
||||||
|
description: undefined,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
valuesUserName.onTextChange({
|
||||||
|
nativeEvent: {text: valuesUserName.input},
|
||||||
|
});
|
||||||
|
|
||||||
|
valuesAccountName.onTextChange({
|
||||||
|
nativeEvent: {text: valuesAccountName.input},
|
||||||
|
});
|
||||||
|
|
||||||
|
valuesPassword.onTextChange({
|
||||||
|
nativeEvent: {text: valuesPassword.input},
|
||||||
|
});
|
||||||
|
|
||||||
|
let obj = {...valuesPasswordRe};
|
||||||
|
if (obj.input !== valuesPassword.input) obj.errorIndex = 'noMatch';
|
||||||
|
else obj.errorIndex = 'none';
|
||||||
|
setValuesPasswordRe(obj);
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (
|
||||||
|
valuesAccountName.input === '' ||
|
||||||
|
valuesUserName.input === '' ||
|
||||||
|
valuesPassword.input === '' ||
|
||||||
|
valuesPasswordRe.input === '' ||
|
||||||
|
valuesUserName.errorIndex !== 'none' ||
|
||||||
|
valuesAccountName.errorIndex !== 'none' ||
|
||||||
|
valuesPassword.errorIndex !== 'none' ||
|
||||||
|
valuesPasswordRe.errorIndex !== 'none'
|
||||||
|
) {
|
||||||
|
/*showToastNow(
|
||||||
|
lang.account.registration.stepFinal.noAllFieldsEntered,
|
||||||
|
);*/
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let base64PW = new Buffer(valuesPassword.input).toString(
|
||||||
|
'base64',
|
||||||
|
);
|
||||||
|
|
||||||
|
let xToken =
|
||||||
|
store.getState().appVariables.preferences.RegisterProcess
|
||||||
|
.XToken;
|
||||||
|
|
||||||
|
if (xToken === undefined) xToken = '';
|
||||||
|
|
||||||
|
makeRequest({
|
||||||
|
path: apiBackendRequest.REGISTER_STEP_FINAL,
|
||||||
|
requestHeader: {
|
||||||
|
'X-Token': xToken,
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
AccountName: valuesAccountName.input,
|
||||||
|
Username: valuesUserName.input,
|
||||||
|
Password: base64PW,
|
||||||
|
},
|
||||||
|
response: {
|
||||||
|
XAuthorization: '',
|
||||||
|
UserId: '',
|
||||||
|
WebSocketSessionId: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
if (
|
||||||
|
resp.response.XAuthorization !== '' &&
|
||||||
|
resp.response.UserId !== '' &&
|
||||||
|
resp.response.WebSocketSessionId !== ''
|
||||||
|
) {
|
||||||
|
let regPro = {
|
||||||
|
...store.getState().appVariables.preferences
|
||||||
|
.RegisterProcess,
|
||||||
|
};
|
||||||
|
regPro.isRegistering = false;
|
||||||
|
store.dispatch(appVarActions.setRegisterProcess(regPro));
|
||||||
|
|
||||||
|
MyUserManager.createNewMyUser(
|
||||||
|
resp.response.UserId,
|
||||||
|
valuesAccountName.input,
|
||||||
|
valuesUserName.input,
|
||||||
|
store.getState().appVariables.preferences.RegisterProcess
|
||||||
|
.EMail,
|
||||||
|
resp.response.XAuthorization,
|
||||||
|
resp.response.WebSocketSessionId,
|
||||||
|
);
|
||||||
|
navigation.popToTop();
|
||||||
|
navigation.goBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(resp => {
|
||||||
|
let errorText =
|
||||||
|
lang.account.registration.stepFinal.registerError[
|
||||||
|
resp.status
|
||||||
|
] || 'Error ' + resp.status;
|
||||||
|
showToastNow(errorText);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, 300);
|
||||||
|
}}>
|
||||||
{lang.account.registration.stepFinal.button}
|
{lang.account.registration.stepFinal.button}
|
||||||
</Button>
|
</Button>
|
||||||
</Center>
|
</Center>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Login() {
|
||||||
|
const lang = useSelector((state: RootState) => state.appVariables.lang);
|
||||||
|
const regPro = useSelector(
|
||||||
|
(state: RootState) => state.appVariables.preferences.RegisterProcess,
|
||||||
|
);
|
||||||
|
|
||||||
|
const {colors} = useTheme();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const navigation = useNavigation<RootScreenNavigationProp>();
|
||||||
|
|
||||||
|
const initNoErrors = {
|
||||||
|
wrongFormat: false,
|
||||||
|
alreadyExists: false,
|
||||||
|
noEntered: false,
|
||||||
|
unknown: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [errorsMail, setErrorsMail] = useState(initNoErrors);
|
||||||
|
const [errorsPassword, setErrorsPassword] = useState(initNoErrors);
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
|
||||||
|
const isErrorMail =
|
||||||
|
errorsMail.wrongFormat || errorsMail.alreadyExists || errorsMail.noEntered;
|
||||||
|
|
||||||
|
const isErrorPassword = errorsPassword.noEntered;
|
||||||
|
|
||||||
|
const errorTextMail = () => {
|
||||||
|
if (errorsMail.wrongFormat) {
|
||||||
|
return lang.account.registration.stepOne.addressInvalid;
|
||||||
|
}
|
||||||
|
if (errorsMail.noEntered) {
|
||||||
|
return lang.account.registration.stepOne.noMailEntered;
|
||||||
|
}
|
||||||
|
if (errorsMail.unknown !== undefined) {
|
||||||
|
return errorsMail.unknown;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const errorTextPassword = () => {
|
||||||
|
if (errorsPassword.noEntered) {
|
||||||
|
return lang.account.registration.stepFinal.passwordError.required;
|
||||||
|
}
|
||||||
|
if (errorsPassword.unknown !== undefined) {
|
||||||
|
return errorsPassword.unknown;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const [isLoading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const [values, setValues] = useState({email: regPro.EMail, password: ''});
|
||||||
|
|
||||||
|
const onButtonPress = () => {
|
||||||
|
if (values.email === '') {
|
||||||
|
let err = {...errorsMail};
|
||||||
|
err.noEntered = true;
|
||||||
|
setErrorsMail({...err});
|
||||||
|
}
|
||||||
|
if (values.password === '') {
|
||||||
|
let err = {...errorsPassword};
|
||||||
|
err.noEntered = true;
|
||||||
|
setErrorsPassword({...err});
|
||||||
|
} else if (validateEmail(values.email)) {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
if (values.password.length < passwordOptions.minLength) {
|
||||||
|
setTimeout(() => {
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.account.login.wrongEmPw,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'error',
|
||||||
|
description: undefined,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {},
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let base64PW = new Buffer(values.password).toString('base64');
|
||||||
|
|
||||||
|
makeRequest({
|
||||||
|
path: apiBackendRequest.LOGIN,
|
||||||
|
requestHeader: {},
|
||||||
|
request: {
|
||||||
|
Email: values.email,
|
||||||
|
Password: base64PW,
|
||||||
|
},
|
||||||
|
response: {
|
||||||
|
XAuthorization: '',
|
||||||
|
UserId: '',
|
||||||
|
WebSocketSessionId: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
let accName = 'ga';
|
||||||
|
let userName = 'ga';
|
||||||
|
MyUserManager.createNewMyUser(
|
||||||
|
resp.response.UserId,
|
||||||
|
accName,
|
||||||
|
userName,
|
||||||
|
values.email,
|
||||||
|
resp.response.XAuthorization,
|
||||||
|
resp.response.WebSocketSessionId,
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.account.login.success,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'success',
|
||||||
|
description: undefined,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
navigation.goBack();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.account.login.failed,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'error',
|
||||||
|
description: undefined,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(resp => {
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
if (resp.status === 422) {
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.account.login.wrongEmPw,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'error',
|
||||||
|
description: undefined,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showToast(toast, {
|
||||||
|
title: lang.error + ' ' + resp.status,
|
||||||
|
variant: 'solid',
|
||||||
|
status: 'error',
|
||||||
|
description: undefined,
|
||||||
|
isClosable: true,
|
||||||
|
rest: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let err = {...errorsMail};
|
||||||
|
err.wrongFormat = true;
|
||||||
|
setErrorsMail({...err});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView keyboardShouldPersistTaps="handled">
|
||||||
|
<Box alignItems="center" mt={5}>
|
||||||
|
<FormControl
|
||||||
|
w="75%"
|
||||||
|
maxW="350px"
|
||||||
|
isRequired
|
||||||
|
isDisabled={isLoading}
|
||||||
|
isInvalid={isErrorMail}>
|
||||||
|
<FormControl.Label>
|
||||||
|
{lang.account.registration.stepOne.title}
|
||||||
|
</FormControl.Label>
|
||||||
|
<Input
|
||||||
|
autoFocus
|
||||||
|
autoComplete="email"
|
||||||
|
placeholder={lang.account.registration.stepOne.title}
|
||||||
|
value={values.email}
|
||||||
|
onSubmitEditing={onButtonPress}
|
||||||
|
autoCapitalize={'none'}
|
||||||
|
maxLength={emailOptions.maxLength}
|
||||||
|
keyboardType={'email-address'}
|
||||||
|
onChangeText={text => {
|
||||||
|
const mail = text.replaceAll(' ', '');
|
||||||
|
let val = {...values};
|
||||||
|
val.email = mail;
|
||||||
|
setValues(val);
|
||||||
|
|
||||||
|
if (errorsMail.noEntered && mail !== '') {
|
||||||
|
let err = errorsMail;
|
||||||
|
err.noEntered = false;
|
||||||
|
setErrorsMail({...err});
|
||||||
|
}
|
||||||
|
if (errorsMail.wrongFormat && validateEmail(mail)) {
|
||||||
|
let err = errorsMail;
|
||||||
|
err.wrongFormat = false;
|
||||||
|
setErrorsMail({...err});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
|
||||||
|
{errorTextMail()}
|
||||||
|
</FormControl.ErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
<FormControl
|
||||||
|
marginBottom={5}
|
||||||
|
w="75%"
|
||||||
|
maxW="350px"
|
||||||
|
isRequired
|
||||||
|
isDisabled={isLoading}
|
||||||
|
isInvalid={isErrorPassword}>
|
||||||
|
<FormControl.Label>
|
||||||
|
{lang.account.registration.stepFinal.password}
|
||||||
|
</FormControl.Label>
|
||||||
|
<Input
|
||||||
|
autoFocus
|
||||||
|
autoComplete="password"
|
||||||
|
placeholder={lang.account.registration.stepFinal.password}
|
||||||
|
value={values.password}
|
||||||
|
onSubmitEditing={onButtonPress}
|
||||||
|
autoCapitalize={'none'}
|
||||||
|
maxLength={emailOptions.maxLength}
|
||||||
|
type={showPassword === false ? 'password' : 'text'}
|
||||||
|
keyboardType={
|
||||||
|
showPassword === true ? 'visible-password' : undefined
|
||||||
|
}
|
||||||
|
InputRightElement={
|
||||||
|
<IconButton
|
||||||
|
mr="2"
|
||||||
|
focusable={false}
|
||||||
|
onPress={() => setShowPassword(!showPassword)}
|
||||||
|
icon={
|
||||||
|
<MaterialIcons
|
||||||
|
size={20}
|
||||||
|
color={colors.white[200]}
|
||||||
|
name={showPassword ? 'visibility' : 'visibility-off'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
borderRadius="full"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onChangeText={password => {
|
||||||
|
let val = {...values};
|
||||||
|
val.password = password;
|
||||||
|
setValues(val);
|
||||||
|
|
||||||
|
if (errorsPassword.noEntered && password !== '') {
|
||||||
|
let err = errorsPassword;
|
||||||
|
err.noEntered = false;
|
||||||
|
setErrorsMail({...err});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormControl.ErrorMessage leftIcon={<WarningOutlineIcon size="xs" />}>
|
||||||
|
{errorTextPassword()}
|
||||||
|
</FormControl.ErrorMessage>
|
||||||
|
</FormControl>
|
||||||
|
<Button
|
||||||
|
w="75%"
|
||||||
|
maxW="350px"
|
||||||
|
colorScheme="primary"
|
||||||
|
rounded="xl"
|
||||||
|
_text={{fontSize: 'xl'}}
|
||||||
|
isLoading={isLoading}
|
||||||
|
onPress={onButtonPress}>
|
||||||
|
{lang.account.login.title}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {EMail, XToken} from '@caj/helper/types';
|
import {EMail, UserId, XToken} from '@caj/configs/types';
|
||||||
import {VersionType} from '@caj/helper/version';
|
import {VersionType} from '@caj/helper/version';
|
||||||
|
import { MyUserAccount } from '@caj/user/types';
|
||||||
import {APP_VERSION} from './appNonSaveVar';
|
import {APP_VERSION} from './appNonSaveVar';
|
||||||
|
|
||||||
export enum ThemeMode {
|
export enum ThemeMode {
|
||||||
|
@ -54,6 +55,8 @@ export interface PREFERENCES_VARS {
|
||||||
version: VersionType;
|
version: VersionType;
|
||||||
theme: ThemeMode;
|
theme: ThemeMode;
|
||||||
RegisterProcess: RegisterProcess;
|
RegisterProcess: RegisterProcess;
|
||||||
|
selectedAccount: UserId | "none";
|
||||||
|
accounts: {[key: UserId]: MyUserAccount};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const preferences_vars_default: PREFERENCES_VARS = {
|
export const preferences_vars_default: PREFERENCES_VARS = {
|
||||||
|
@ -64,4 +67,6 @@ export const preferences_vars_default: PREFERENCES_VARS = {
|
||||||
XToken: undefined,
|
XToken: undefined,
|
||||||
EMail: '',
|
EMail: '',
|
||||||
},
|
},
|
||||||
|
selectedAccount: "none",
|
||||||
|
accounts: {},
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,8 @@ import {
|
||||||
import {non_save_vars, NON_SAVE_VARS} from './appNonSaveVar';
|
import {non_save_vars, NON_SAVE_VARS} from './appNonSaveVar';
|
||||||
import LangFormat from '@caj/lang/default';
|
import LangFormat from '@caj/lang/default';
|
||||||
import {lang as defaultLang} from '@caj/lang/en';
|
import {lang as defaultLang} from '@caj/lang/en';
|
||||||
|
import { UserId } from './types';
|
||||||
|
import { MyUserAccount } from '@caj/user/types';
|
||||||
|
|
||||||
export interface appVariablesState {
|
export interface appVariablesState {
|
||||||
preferences: PREFERENCES_VARS;
|
preferences: PREFERENCES_VARS;
|
||||||
|
@ -37,6 +39,12 @@ export const appVariablesSlice = createSlice({
|
||||||
setRegisterProcess: (state, action: PayloadAction<RegisterProcess>) => {
|
setRegisterProcess: (state, action: PayloadAction<RegisterProcess>) => {
|
||||||
state.preferences.RegisterProcess = action.payload;
|
state.preferences.RegisterProcess = action.payload;
|
||||||
},
|
},
|
||||||
|
setCurrentAccount:(state, action: PayloadAction<UserId>) => {
|
||||||
|
state.preferences.selectedAccount = action.payload;
|
||||||
|
},
|
||||||
|
setAccount:(state, action: PayloadAction<MyUserAccount>) => {
|
||||||
|
state.preferences.accounts[action.payload.UserId] = action.payload;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
|
import {ThemeMode} from './appVar';
|
||||||
|
|
||||||
export type EMail = string;
|
export type EMail = string;
|
||||||
|
|
||||||
|
export type langCode = 'en' | string;
|
||||||
|
|
||||||
|
export type timestamp = number;
|
||||||
|
|
||||||
export type AccountName = string;
|
export type AccountName = string;
|
||||||
export type Username = string;
|
export type Username = string | undefined;
|
||||||
export type Password = string;
|
export type Password = string;
|
||||||
export type UserAgent = string;
|
export type UserAgent = string;
|
||||||
export type XToken = string;
|
export type XToken = string;
|
||||||
export type verifyId = string;
|
export type verifyId = string;
|
||||||
|
|
||||||
export type SessionId = string;
|
export type XAuthorization = string;
|
||||||
export type UserId = string;
|
export type UserId = string;
|
||||||
export type WebSocketSessionId = string;
|
export type WebSocketSessionId = string;
|
||||||
|
|
||||||
|
@ -18,6 +24,7 @@ export const accountNameOptions = {
|
||||||
return text.match('^[a-zA-Z0-9_.]+$') !== null;
|
return text.match('^[a-zA-Z0-9_.]+$') !== null;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userNameOptions = {
|
export const userNameOptions = {
|
||||||
minLength: 2,
|
minLength: 2,
|
||||||
maxLength: 24,
|
maxLength: 24,
|
||||||
|
@ -29,8 +36,9 @@ export const userNameOptions = {
|
||||||
export const passwordOptions = {
|
export const passwordOptions = {
|
||||||
minLength: 6,
|
minLength: 6,
|
||||||
maxLength: 64,
|
maxLength: 64,
|
||||||
|
minBits: 50,
|
||||||
isAllowed: (text: string): boolean => {
|
isAllowed: (text: string): boolean => {
|
||||||
return true;
|
return /\W/.test(text) && /[a-zA-Z]/.test(text) && /[a-zA-Z]/.test(text);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import {createSlice} from '@reduxjs/toolkit';
|
||||||
|
import type {PayloadAction} from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
import LangFormat from '@caj/lang/default';
|
||||||
|
import {lang as defaultLang} from '@caj/lang/en';
|
||||||
|
import {UserId} from './types';
|
||||||
|
import {MyUserAccount} from '@caj/user/types';
|
||||||
|
|
||||||
|
export interface userList {
|
||||||
|
myUserList: {[key: UserId]: MyUserAccount};
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: userList = {
|
||||||
|
myUserList: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usersSlice = createSlice({
|
||||||
|
name: 'users',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
setAccount: (state, action: PayloadAction<MyUserAccount>) => {
|
||||||
|
state.myUserList[action.payload.UserId] = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Action creators are generated for each case reducer function
|
||||||
|
const {actions} = usersSlice;
|
||||||
|
export const usersActions = actions;
|
||||||
|
|
||||||
|
export default usersSlice.reducer;
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,638 @@
|
||||||
|
import * as PopularPasswords from './PopularPasswords.js';
|
||||||
|
|
||||||
|
const PatternID = {
|
||||||
|
LowerAlpha: 'L',
|
||||||
|
UpperAlpha: 'U',
|
||||||
|
Digit: 'D',
|
||||||
|
Special: 'S',
|
||||||
|
High: 'H',
|
||||||
|
Other: 'X',
|
||||||
|
|
||||||
|
Dictionary: 'W',
|
||||||
|
Repetition: 'R',
|
||||||
|
Number: 'N',
|
||||||
|
DiffSeq: 'C',
|
||||||
|
|
||||||
|
All: "LUDSHXWRNC"
|
||||||
|
};
|
||||||
|
const PrintableAsciiSpecial = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
|
||||||
|
const UpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
const LowerCase = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
const Digits = "0123456789";
|
||||||
|
const HighAnsiChars = (() => {
|
||||||
|
let sbHighAnsi = [], ch;
|
||||||
|
for(ch = 0x00A1; ch <= 0x00AC; ++ch)
|
||||||
|
sbHighAnsi.push(ch);
|
||||||
|
for(ch = 0x00AE; ch < 0x00FF; ++ch)
|
||||||
|
sbHighAnsi.push(ch);
|
||||||
|
sbHighAnsi.push(0x00FF);
|
||||||
|
return String.fromCharCode.apply(null, sbHighAnsi);
|
||||||
|
})();
|
||||||
|
|
||||||
|
function Assert(ok, msg) {
|
||||||
|
if (!ok) {
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class QeCharType {
|
||||||
|
constructor(chTypeID, strAlphabet, bIsConsecutive) {
|
||||||
|
let nChars;
|
||||||
|
if (typeof strAlphabet === 'string') {
|
||||||
|
if(strAlphabet.length === 0) throw new Error();
|
||||||
|
} else if (typeof strAlphabet === 'number') {
|
||||||
|
if(nChars <= 0) throw new RangeError();
|
||||||
|
nChars = strAlphabet;
|
||||||
|
strAlphabet = null;
|
||||||
|
bIsConsecutive = false;
|
||||||
|
} else {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.TypeID = chTypeID;
|
||||||
|
this.Alphabet = strAlphabet;
|
||||||
|
this.CharCount = nChars || this.Alphabet.length;
|
||||||
|
this.m_chFirst = (bIsConsecutive ? this.Alphabet.charCodeAt(0) : null);
|
||||||
|
this.m_chLast = (bIsConsecutive ? this.Alphabet.charCodeAt(this.CharCount - 1) : null);
|
||||||
|
|
||||||
|
this.CharSize = Math.log2(this.CharCount);
|
||||||
|
nChars || Assert((this.m_chLast - this.m_chFirst) == (this.CharCount - 1) || !bIsConsecutive);
|
||||||
|
}
|
||||||
|
|
||||||
|
Contains(ch)
|
||||||
|
{
|
||||||
|
if(this.m_chLast !== null)
|
||||||
|
return ((ch >= this.m_chFirst) && (ch <= this.m_chLast));
|
||||||
|
|
||||||
|
if (this.Alphabet.length === 0) throw new Error('Don\'t call for catch-none set')
|
||||||
|
return (this.Alphabet.indexOf(String.fromCharCode(ch)) >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EntropyEncoder {
|
||||||
|
constructor(strAlphabet, uBaseWeight,
|
||||||
|
uCharWeight, uOccExclThreshold)
|
||||||
|
{
|
||||||
|
if(strAlphabet === null || strAlphabet.length === 0) throw new Error();
|
||||||
|
|
||||||
|
this.m_strAlph = strAlphabet;
|
||||||
|
this.m_uBaseWeight = uBaseWeight;
|
||||||
|
this.m_uCharWeight = uCharWeight;
|
||||||
|
this.m_uOccExclThreshold = uOccExclThreshold;
|
||||||
|
|
||||||
|
this.m_dHisto = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reset()
|
||||||
|
{
|
||||||
|
this.m_dHisto = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Write(ch)
|
||||||
|
{
|
||||||
|
Assert(this.m_strAlph.indexOf(ch) >= 0);
|
||||||
|
|
||||||
|
let uOcc = this.m_dHisto[ch] || 0;
|
||||||
|
Assert(ch in this.m_dHisto || uOcc === 0);
|
||||||
|
this.m_dHisto[ch] = uOcc + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetOutputSize()
|
||||||
|
{
|
||||||
|
let uTotalWeight = this.m_uBaseWeight * this.m_strAlph.length;
|
||||||
|
for (let u of Object.values(this.m_dHisto))
|
||||||
|
{
|
||||||
|
Assert(u >= 1);
|
||||||
|
if(u > this.m_uOccExclThreshold)
|
||||||
|
uTotalWeight += (u - this.m_uOccExclThreshold) * this.m_uCharWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dSize = 0.0, dTotalWeight = uTotalWeight;
|
||||||
|
for (let u of Object.values(this.m_dHisto))
|
||||||
|
{
|
||||||
|
let uWeight = this.m_uBaseWeight;
|
||||||
|
if(u > this.m_uOccExclThreshold)
|
||||||
|
uWeight += (u - this.m_uOccExclThreshold) * this.m_uCharWeight;
|
||||||
|
|
||||||
|
dSize -= u * Math.log2(uWeight / dTotalWeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MultiEntropyEncoder {
|
||||||
|
constructor() {
|
||||||
|
this.m_dEncs = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
AddEncoder(chTypeID, ec)
|
||||||
|
{
|
||||||
|
Assert(ec);
|
||||||
|
|
||||||
|
Assert(!(chTypeID in this.m_dEncs));
|
||||||
|
this.m_dEncs[chTypeID] = ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reset()
|
||||||
|
{
|
||||||
|
for(let ec of Object.values(this.m_dEncs)) {
|
||||||
|
ec.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write(chTypeID, chData)
|
||||||
|
{
|
||||||
|
let ec = this.m_dEncs[chTypeID];
|
||||||
|
if(!ec)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ec.Write(chData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetOutputSize()
|
||||||
|
{
|
||||||
|
let d = 0.0;
|
||||||
|
|
||||||
|
for (let ec of Object.values(this.m_dEncs))
|
||||||
|
{
|
||||||
|
d += ec.GetOutputSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class QePatternInstance
|
||||||
|
{
|
||||||
|
constructor(iPosition, nLength, chPatternID, dblCost) {
|
||||||
|
let ctSingle;
|
||||||
|
if (typeof dblCost === 'number') {
|
||||||
|
this.Position = iPosition;
|
||||||
|
this.Length = nLength;
|
||||||
|
this.PatternID = chPatternID;
|
||||||
|
this.Cost = dblCost;
|
||||||
|
this.SingleCharType = null;
|
||||||
|
} else {
|
||||||
|
ctSingle = chPatternID;
|
||||||
|
|
||||||
|
this.Position = iPosition;
|
||||||
|
this.Length = nLength;
|
||||||
|
this.PatternID = ctSingle.TypeID;
|
||||||
|
this.Cost = ctSingle.CharSize;
|
||||||
|
this.SingleCharType = ctSingle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class QePathState {
|
||||||
|
constructor(iPosition, lPath) {
|
||||||
|
this.Position = iPosition;
|
||||||
|
this.Path = lPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let m_objSyncInit;
|
||||||
|
let m_lCharTypes;
|
||||||
|
|
||||||
|
function EnsureInitialized() {
|
||||||
|
if(m_lCharTypes == null)
|
||||||
|
{
|
||||||
|
let strSpecial = PrintableAsciiSpecial;
|
||||||
|
strSpecial = strSpecial + " ";
|
||||||
|
|
||||||
|
let nSp = strSpecial.length;
|
||||||
|
let nHi = HighAnsiChars.length;
|
||||||
|
|
||||||
|
m_lCharTypes = [];
|
||||||
|
|
||||||
|
m_lCharTypes.push(new QeCharType(PatternID.LowerAlpha,
|
||||||
|
LowerCase, true));
|
||||||
|
m_lCharTypes.push(new QeCharType(PatternID.UpperAlpha,
|
||||||
|
UpperCase, true));
|
||||||
|
m_lCharTypes.push(new QeCharType(PatternID.Digit,
|
||||||
|
Digits, true));
|
||||||
|
m_lCharTypes.push(new QeCharType(PatternID.Special,
|
||||||
|
strSpecial, false));
|
||||||
|
m_lCharTypes.push(new QeCharType(PatternID.High,
|
||||||
|
HighAnsiChars, false));
|
||||||
|
m_lCharTypes.push(new QeCharType(PatternID.Other,
|
||||||
|
0x10000 - (2 * 26) - 10 - nSp - nHi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetCharType(ch) {
|
||||||
|
let nTypes = m_lCharTypes.length;
|
||||||
|
Assert((nTypes > 0) && (m_lCharTypes[nTypes - 1].CharCount > 256));
|
||||||
|
|
||||||
|
for(let i = 0; i < (nTypes - 1); ++i)
|
||||||
|
{
|
||||||
|
if(m_lCharTypes[i].Contains(ch))
|
||||||
|
return m_lCharTypes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_lCharTypes[nTypes - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function ComputePathCost(l, vPassword, ecPattern, mcData)
|
||||||
|
{
|
||||||
|
ecPattern.Reset();
|
||||||
|
for(let i = 0; i < l.length; ++i)
|
||||||
|
ecPattern.Write(l[i].PatternID);
|
||||||
|
let dblPatternCost = ecPattern.GetOutputSize();
|
||||||
|
|
||||||
|
mcData.Reset();
|
||||||
|
let dblDataCost = 0.0;
|
||||||
|
for(let pi of l)
|
||||||
|
{
|
||||||
|
let tChar = pi.SingleCharType;
|
||||||
|
if(tChar != null)
|
||||||
|
{
|
||||||
|
let ch = vPassword[pi.Position];
|
||||||
|
if(!mcData.Write(tChar.TypeID, ch))
|
||||||
|
dblDataCost += pi.Cost;
|
||||||
|
}
|
||||||
|
else dblDataCost += pi.Cost;
|
||||||
|
}
|
||||||
|
dblDataCost += mcData.GetOutputSize();
|
||||||
|
|
||||||
|
return (dblPatternCost + dblDataCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
function FindRepetitions(vPassword, vPatterns)
|
||||||
|
{
|
||||||
|
let v = stringToArray(vPassword);
|
||||||
|
let n = vPassword.length;
|
||||||
|
|
||||||
|
let chErased = 0xffff;
|
||||||
|
for(let m = (n / 2); m >= 3; --m)
|
||||||
|
{
|
||||||
|
for(let x1 = 0; x1 <= (n - (2 * m)); ++x1)
|
||||||
|
{
|
||||||
|
let bFoundRep = false;
|
||||||
|
|
||||||
|
for(let x2 = (x1 + m); x2 <= (n - m); ++x2)
|
||||||
|
{
|
||||||
|
if(PartsEqual(v, x1, x2, m))
|
||||||
|
{
|
||||||
|
let dblCost = Math.log2(x1 + 1) + Math.log2(m);
|
||||||
|
vPatterns[x2].push(new QePatternInstance(x2, m,
|
||||||
|
PatternID.Repetition, dblCost));
|
||||||
|
|
||||||
|
chErased = ErasePart(v, x2, m, chErased);
|
||||||
|
|
||||||
|
bFoundRep = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bFoundRep) chErased = ErasePart(v, x1, m, chErased);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function PartsEqual(v, x1, x2, nLength)
|
||||||
|
{
|
||||||
|
for(let i = 0; i < nLength; ++i)
|
||||||
|
{
|
||||||
|
if(v[x1 + i] != v[x2 + i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ErasePart(v, i, n, chErased)
|
||||||
|
{
|
||||||
|
for(let j = 0; j < n; ++j) {
|
||||||
|
v[i + j] = chErased;
|
||||||
|
--chErased;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chErased;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringToArray(string) {
|
||||||
|
let array = [];
|
||||||
|
for (let i = 0; i < string.length; i++) {
|
||||||
|
array.push(string.charCodeAt(i));
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
function FindNumbers(vPassword, vPatterns)
|
||||||
|
{
|
||||||
|
let n = vPassword.length;
|
||||||
|
let sb = [];
|
||||||
|
|
||||||
|
for(let i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
let ch = vPassword.charCodeAt(i);
|
||||||
|
if((ch >= 0x30) && (ch <= 0x39)) sb.push(ch);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddNumberPattern(vPatterns, sb, i - sb.length);
|
||||||
|
sb = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AddNumberPattern(vPatterns, sb, n - sb.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AddNumberPattern(vPatterns, sb, i)
|
||||||
|
{
|
||||||
|
if(sb.length <= 2) return;
|
||||||
|
let strNumber = String.fromCharCode.apply(null,sb);
|
||||||
|
|
||||||
|
let nZeros = 0;
|
||||||
|
for(let j = 0; j < strNumber.length; ++j)
|
||||||
|
{
|
||||||
|
if(strNumber.charCodeAt(j) != 0x30) break;
|
||||||
|
++nZeros;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dblCost = Math.log2(nZeros + 1);
|
||||||
|
if(nZeros < strNumber.length)
|
||||||
|
{
|
||||||
|
let strNonZero = strNumber.substring(nZeros);
|
||||||
|
|
||||||
|
dblCost += Math.log2(parseFloat(strNonZero));
|
||||||
|
}
|
||||||
|
|
||||||
|
vPatterns[i].push(new QePatternInstance(i, strNumber.length,
|
||||||
|
PatternID.Number, dblCost));
|
||||||
|
}
|
||||||
|
|
||||||
|
function FindDiffSeqs(vPassword, vPatterns) {
|
||||||
|
let n = vPassword.length;
|
||||||
|
let d = Infinity, p = 0;
|
||||||
|
|
||||||
|
for(let i = 1; i <= n; ++i)
|
||||||
|
{
|
||||||
|
let dCur = ((i == n) ? Infinity :
|
||||||
|
(vPassword.charCodeAt(i) - vPassword.charCodeAt(i - 1)));
|
||||||
|
if(dCur != d)
|
||||||
|
{
|
||||||
|
if((i - p) >= 3) // At least 3 chars involved
|
||||||
|
{
|
||||||
|
let ct = GetCharType(vPassword.charCodeAt(p));
|
||||||
|
let dblCost = ct.CharSize + Math.log2(i - p - 1);
|
||||||
|
|
||||||
|
vPatterns[p].push(new QePatternInstance(p,
|
||||||
|
i - p, PatternID.DiffSeq, dblCost));
|
||||||
|
}
|
||||||
|
|
||||||
|
d = dCur;
|
||||||
|
p = i - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function DecodeLeet(str) {
|
||||||
|
let newstr = '';
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
let char = str.charAt(i);
|
||||||
|
let decoded = DecodeLeetChar(char);
|
||||||
|
newstr += decoded;
|
||||||
|
}
|
||||||
|
return newstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function FindPopularPasswords(vPassword, vPatterns) {
|
||||||
|
let n = vPassword.length;
|
||||||
|
|
||||||
|
let vLower = vPassword.toLowerCase();
|
||||||
|
let vLeet = DecodeLeet(vLower);
|
||||||
|
|
||||||
|
for(let nSubLen = Math.min(n, PopularPasswords.getMaxLength()); nSubLen >= 3; --nSubLen) {
|
||||||
|
if (!PopularPasswords.ContainsLength(nSubLen)) continue;
|
||||||
|
|
||||||
|
for(let i = 0; i <= (n - nSubLen); ++i)
|
||||||
|
{
|
||||||
|
let vSub = vLower.substring(i, i + nSubLen);
|
||||||
|
|
||||||
|
if (!vSub || vSub.indexOf('\u0000') !== -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!EvalAddPopularPasswordPattern(vPatterns, vPassword,
|
||||||
|
i, vSub, 0.0))
|
||||||
|
{
|
||||||
|
let vLeetSub = vLeet.substring(i, nSubLen);
|
||||||
|
if(EvalAddPopularPasswordPattern(vPatterns, vPassword,
|
||||||
|
i, vLeetSub, 1.5))
|
||||||
|
{
|
||||||
|
vLower = StringClear(vLower, i, nSubLen); // Not vLeet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vLower = StringClear(vLower, i, nSubLen); // Not vLeet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function StringClear(str, pos, count) {
|
||||||
|
let erased = ''
|
||||||
|
for (let i = 0;i < count;i++) {
|
||||||
|
erased += '\u0000'
|
||||||
|
}
|
||||||
|
return str.substring(0, pos) + erased + str.substring(pos + count);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DecodeLeetChar(chLeet) {
|
||||||
|
if((chLeet.charCodeAt(0) >= 0x00C0) && (chLeet.charCodeAt(0) <= 0x00C6)) return 'a';
|
||||||
|
if((chLeet.charCodeAt(0) >= 0x00C8) && (chLeet.charCodeAt(0) <= 0x00CB)) return 'e';
|
||||||
|
if((chLeet.charCodeAt(0) >= 0x00CC) && (chLeet.charCodeAt(0) <= 0x00CF)) return 'i';
|
||||||
|
if((chLeet.charCodeAt(0) >= 0x00D2) && (chLeet.charCodeAt(0) <= 0x00D6)) return 'o';
|
||||||
|
if((chLeet.charCodeAt(0) >= 0x00D9) && (chLeet.charCodeAt(0) <= 0x00DC)) return 'u';
|
||||||
|
if((chLeet.charCodeAt(0) >= 0x00E0) && (chLeet.charCodeAt(0) <= 0x00E6)) return 'a';
|
||||||
|
if((chLeet.charCodeAt(0) >= 0x00E8) && (chLeet.charCodeAt(0) <= 0x00EB)) return 'e';
|
||||||
|
if((chLeet.charCodeAt(0) >= 0x00EC) && (chLeet.charCodeAt(0) <= 0x00EF)) return 'i';
|
||||||
|
if((chLeet.charCodeAt(0) >= 0x00F2) && (chLeet.charCodeAt(0) <= 0x00F6)) return 'o';
|
||||||
|
if((chLeet.charCodeAt(0) >= 0x00F9) && (chLeet.charCodeAt(0) <= 0x00FC)) return 'u';
|
||||||
|
|
||||||
|
switch(chLeet)
|
||||||
|
{
|
||||||
|
case '4':
|
||||||
|
case '@':
|
||||||
|
case '?':
|
||||||
|
case '^':
|
||||||
|
case '\u00AA': return 'a';
|
||||||
|
case '8':
|
||||||
|
case '\u00DF': return 'b';
|
||||||
|
case '(':
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
case '<':
|
||||||
|
case '\u00A2':
|
||||||
|
case '\u00A9':
|
||||||
|
case '\u00C7':
|
||||||
|
case '\u00E7': return 'c';
|
||||||
|
case '\u00D0':
|
||||||
|
case '\u00F0': return 'd';
|
||||||
|
case '3':
|
||||||
|
case '\u20AC':
|
||||||
|
case '&':
|
||||||
|
case '\u00A3': return 'e';
|
||||||
|
case '6':
|
||||||
|
case '9': return 'g';
|
||||||
|
case '#': return 'h';
|
||||||
|
case '1':
|
||||||
|
case '!':
|
||||||
|
case '|':
|
||||||
|
case '\u00A1':
|
||||||
|
case '\u00A6': return 'i';
|
||||||
|
case '\u00D1':
|
||||||
|
case '\u00F1': return 'n';
|
||||||
|
case '0':
|
||||||
|
case '*':
|
||||||
|
case '\u00A4': // Currency
|
||||||
|
case '\u00B0': // Degree
|
||||||
|
case '\u00D8':
|
||||||
|
case '\u00F8': return 'o';
|
||||||
|
case '\u00AE': return 'r';
|
||||||
|
case '$':
|
||||||
|
case '5':
|
||||||
|
case '\u00A7': return 's';
|
||||||
|
case '+':
|
||||||
|
case '7': return 't';
|
||||||
|
case '\u00B5': return 'u';
|
||||||
|
case '%':
|
||||||
|
case '\u00D7': return 'x';
|
||||||
|
case '\u00A5':
|
||||||
|
case '\u00DD':
|
||||||
|
case '\u00FD':
|
||||||
|
case '\u00FF': return 'y';
|
||||||
|
case '2': return 'z';
|
||||||
|
default: return chLeet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function EvalAddPopularPasswordPattern(vPatterns, vPassword, i, sub, dblCostPerMod)
|
||||||
|
{
|
||||||
|
let IsPopularPassword = PopularPasswords.IsPopularPassword(sub);
|
||||||
|
let uDictSize = PopularPasswords.GetDictSize(sub.length);
|
||||||
|
if(!IsPopularPassword)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let n = sub.length;
|
||||||
|
let d = HammingDist(sub, 0, vPassword, i, n);
|
||||||
|
|
||||||
|
let dblCost = Math.log2(uDictSize);
|
||||||
|
|
||||||
|
// dblCost += Math.log2(n binom d)
|
||||||
|
let k = Math.min(d, n - d);
|
||||||
|
for(let j = n; j > (n - k); --j)
|
||||||
|
dblCost += Math.log2(j);
|
||||||
|
for(let j = k; j >= 2; --j)
|
||||||
|
dblCost -= Math.log2(j);
|
||||||
|
|
||||||
|
dblCost += dblCostPerMod * d;
|
||||||
|
|
||||||
|
vPatterns[i].push(new QePatternInstance(i, n, PatternID.Dictionary,
|
||||||
|
dblCost));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function HammingDist(v1, iOffset1, v2, iOffset2, nLength)
|
||||||
|
{
|
||||||
|
let nDist = 0;
|
||||||
|
for(let i = 0; i < nLength; ++i)
|
||||||
|
{
|
||||||
|
if(v1.charCodeAt(iOffset1 + i) !== v2.charCodeAt(iOffset2 + i)) ++nDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PasswordQualityCalculator(vPassword)
|
||||||
|
{
|
||||||
|
if (typeof vPassword !== 'string' || vPassword.length === 0) return 0;
|
||||||
|
|
||||||
|
EnsureInitialized();
|
||||||
|
|
||||||
|
let n = vPassword.length;
|
||||||
|
let vPatterns = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
vPatterns[i] = [
|
||||||
|
new QePatternInstance(i, 1, GetCharType(vPassword.charCodeAt(i)))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
FindRepetitions(vPassword, vPatterns);
|
||||||
|
FindNumbers(vPassword, vPatterns);
|
||||||
|
FindDiffSeqs(vPassword, vPatterns);
|
||||||
|
FindPopularPasswords(vPassword, vPatterns);
|
||||||
|
|
||||||
|
// Encoders must not be static, because the entropy estimation
|
||||||
|
// may run concurrently in multiple threads and the encoders are
|
||||||
|
// not read-only
|
||||||
|
let ecPattern = new EntropyEncoder(PatternID.All, 0, 1, 0);
|
||||||
|
let mcData = new MultiEntropyEncoder();
|
||||||
|
|
||||||
|
for(let i = 0; i < (m_lCharTypes.length - 1); ++i)
|
||||||
|
{
|
||||||
|
// Let m be the alphabet size. In order to ensure that two same
|
||||||
|
// characters cost at least as much as a single character, for
|
||||||
|
// the probability p and weight w of the character it must hold:
|
||||||
|
// -log(1/m) >= -2*log(p)
|
||||||
|
// <=> log(1/m) <= log(p^2) <=> 1/m <= p^2 <=> p >= sqrt(1/m);
|
||||||
|
// sqrt(1/m) = (1+w)/(m+w)
|
||||||
|
// <=> m+w = (1+w)*sqrt(m) <=> m+w = sqrt(m) + w*sqrt(m)
|
||||||
|
// <=> w*(1-sqrt(m)) = sqrt(m) - m <=> w = (sqrt(m)-m)/(1-sqrt(m))
|
||||||
|
// <=> w = (sqrt(m)-m)*(1+sqrt(m))/(1-m)
|
||||||
|
// <=> w = (sqrt(m)-m+m-m*sqrt(m))/(1-m) <=> w = sqrt(m)
|
||||||
|
let uw = Math.sqrt(m_lCharTypes[i].CharCount) | 0;
|
||||||
|
|
||||||
|
mcData.AddEncoder(m_lCharTypes[i].TypeID, new EntropyEncoder(
|
||||||
|
m_lCharTypes[i].Alphabet, 1, uw, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
let dblMinCost = Infinity;
|
||||||
|
let tStart = Date.now();
|
||||||
|
|
||||||
|
let sRec = [];
|
||||||
|
sRec.push(new QePathState(0, []));
|
||||||
|
|
||||||
|
|
||||||
|
while(sRec.length > 0)
|
||||||
|
{
|
||||||
|
let tDiff = Date.now() - tStart;
|
||||||
|
if(tDiff > 500) break;
|
||||||
|
|
||||||
|
let s = sRec.pop();
|
||||||
|
|
||||||
|
if(s.Position >= n)
|
||||||
|
{
|
||||||
|
Assert(s.Position === n);
|
||||||
|
|
||||||
|
let dblCost = ComputePathCost(s.Path, vPassword,
|
||||||
|
ecPattern, mcData);
|
||||||
|
if(dblCost < dblMinCost) dblMinCost = dblCost;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let lSubs = vPatterns[s.Position];
|
||||||
|
for(let i = lSubs.length - 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
let pi = lSubs[i];
|
||||||
|
Assert(pi.Position == s.Position);
|
||||||
|
Assert(pi.Length >= 1);
|
||||||
|
|
||||||
|
let lNewPath = [];
|
||||||
|
lNewPath.push(...s.Path);
|
||||||
|
lNewPath.push(pi);
|
||||||
|
|
||||||
|
let sNew = new QePathState(s.Position +
|
||||||
|
pi.Length, lNewPath);
|
||||||
|
sRec.push(sNew);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.ceil(dblMinCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
PasswordQualityCalculator.PopularPasswords = PopularPasswords;
|
|
@ -0,0 +1,47 @@
|
||||||
|
const m_dicts = {};
|
||||||
|
|
||||||
|
export function getMaxLength() {
|
||||||
|
let iMaxLen = 0;
|
||||||
|
for (let iLen of Object.keys(m_dicts)) {
|
||||||
|
if (parseInt(iLen) > iMaxLen) iMaxLen = parseInt(iLen);
|
||||||
|
}
|
||||||
|
return iMaxLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ContainsLength(nLength) {
|
||||||
|
return nLength in m_dicts;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function IsPopularPassword(password) {
|
||||||
|
if (password == null) throw new Error();
|
||||||
|
if (password.length == 0) { return false; }
|
||||||
|
|
||||||
|
if (!(password.length in m_dicts)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_dicts[password.length].includes(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GetDictSize(length) {
|
||||||
|
|
||||||
|
if (!(length in m_dicts)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_dicts[length].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function load(passwordList) {
|
||||||
|
for (let pw of passwordList) {
|
||||||
|
if (pw.length in m_dicts) {
|
||||||
|
m_dicts[pw.length].push(pw);
|
||||||
|
} else {
|
||||||
|
m_dicts[pw.length] = [pw];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function reset() {
|
||||||
|
m_dicts = {}
|
||||||
|
}
|
|
@ -10,13 +10,14 @@ import {
|
||||||
AccountName,
|
AccountName,
|
||||||
EMail,
|
EMail,
|
||||||
Password,
|
Password,
|
||||||
SessionId,
|
XAuthorization,
|
||||||
UserId,
|
UserId,
|
||||||
Username,
|
Username,
|
||||||
verifyId,
|
verifyId,
|
||||||
WebSocketSessionId,
|
WebSocketSessionId,
|
||||||
XToken,
|
XToken,
|
||||||
} from './types';
|
} from '../configs/types';
|
||||||
|
import MyUserManager from '@caj/user/MyUserManager';
|
||||||
|
|
||||||
export const apiPath = {
|
export const apiPath = {
|
||||||
backend: {
|
backend: {
|
||||||
|
@ -30,19 +31,24 @@ export enum apiBackendRequest {
|
||||||
REGISTER_STEP_2 = '/verify/email/:xToken/:verifyId',
|
REGISTER_STEP_2 = '/verify/email/:xToken/:verifyId',
|
||||||
REGISTER_STEP_FINAL = '/admin/users',
|
REGISTER_STEP_FINAL = '/admin/users',
|
||||||
REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK = '/admin/users/validation/accountname',
|
REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK = '/admin/users/validation/accountname',
|
||||||
|
LOGIN = '/user',
|
||||||
|
GET_USER_PROFILE = '/users/:userId',
|
||||||
|
APP_START = '/appstart',
|
||||||
}
|
}
|
||||||
|
|
||||||
type requestGET = {[key: string]: string};
|
type requestGET = {[key: string]: string};
|
||||||
|
type requestHeader = {[key: string]: string | undefined};
|
||||||
|
|
||||||
export interface defaultRequest {
|
export interface defaultRequest {
|
||||||
status?: 200 | 400 | 422 | 500;
|
status?: 200 | 400 | 422 | 500;
|
||||||
error?: string;
|
error?: string;
|
||||||
requestGET?: requestGET;
|
requestGET?: requestGET;
|
||||||
|
requestHeader?: requestHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface REGISTER_STEP_1 extends defaultRequest {
|
interface REGISTER_STEP_1 extends defaultRequest {
|
||||||
path: apiBackendRequest.REGISTER_STEP_1;
|
path: apiBackendRequest.REGISTER_STEP_1;
|
||||||
requestHeader: {};
|
|
||||||
request: {
|
request: {
|
||||||
Email: EMail;
|
Email: EMail;
|
||||||
};
|
};
|
||||||
|
@ -52,18 +58,20 @@ interface REGISTER_STEP_1 extends defaultRequest {
|
||||||
}
|
}
|
||||||
interface REGISTER_RESEND_MAIL extends defaultRequest {
|
interface REGISTER_RESEND_MAIL extends defaultRequest {
|
||||||
path: apiBackendRequest.REGISTER_RESEND_MAIL;
|
path: apiBackendRequest.REGISTER_RESEND_MAIL;
|
||||||
requestHeader: {};
|
requestHeader: {
|
||||||
|
'X-Token': XToken | undefined;
|
||||||
|
};
|
||||||
request: {
|
request: {
|
||||||
Email: EMail;
|
Email: EMail;
|
||||||
};
|
};
|
||||||
// response: {
|
response: {
|
||||||
// XToken: XToken | undefined;
|
XToken: XToken | undefined;
|
||||||
//};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface REGISTER_STEP_2 extends defaultRequest {
|
interface REGISTER_STEP_2 extends defaultRequest {
|
||||||
path: apiBackendRequest.REGISTER_STEP_2;
|
path: apiBackendRequest.REGISTER_STEP_2;
|
||||||
requestHeader: {};
|
|
||||||
requestGET: {
|
requestGET: {
|
||||||
':xToken': XToken;
|
':xToken': XToken;
|
||||||
':verifyId': verifyId;
|
':verifyId': verifyId;
|
||||||
|
@ -84,7 +92,7 @@ interface REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK extends defaultRequest {
|
||||||
interface REGISTER_STEP_FINAL extends defaultRequest {
|
interface REGISTER_STEP_FINAL extends defaultRequest {
|
||||||
path: apiBackendRequest.REGISTER_STEP_FINAL;
|
path: apiBackendRequest.REGISTER_STEP_FINAL;
|
||||||
requestHeader: {
|
requestHeader: {
|
||||||
XToken: XToken;
|
'X-Token': XToken;
|
||||||
};
|
};
|
||||||
request: {
|
request: {
|
||||||
AccountName: AccountName;
|
AccountName: AccountName;
|
||||||
|
@ -92,18 +100,70 @@ interface REGISTER_STEP_FINAL extends defaultRequest {
|
||||||
Password: Password;
|
Password: Password;
|
||||||
};
|
};
|
||||||
response?: {
|
response?: {
|
||||||
SessionId: SessionId;
|
XAuthorization: XAuthorization;
|
||||||
UserId: UserId;
|
UserId: UserId;
|
||||||
WebSocketSessionId: WebSocketSessionId;
|
WebSocketSessionId: WebSocketSessionId;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LOGIN extends defaultRequest {
|
||||||
|
path: apiBackendRequest.LOGIN;
|
||||||
|
request: {
|
||||||
|
Email: EMail;
|
||||||
|
Password: Password;
|
||||||
|
};
|
||||||
|
response?: {
|
||||||
|
XAuthorization: XAuthorization;
|
||||||
|
UserId: UserId;
|
||||||
|
WebSocketSessionId: WebSocketSessionId;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GET_USER_PROFILE extends defaultRequest {
|
||||||
|
path: apiBackendRequest.GET_USER_PROFILE;
|
||||||
|
|
||||||
|
requestGET: {
|
||||||
|
':userId': UserId;
|
||||||
|
};
|
||||||
|
response: {
|
||||||
|
AccountName: AccountName;
|
||||||
|
Username: Username;
|
||||||
|
Description: string;
|
||||||
|
FollowersCount: number;
|
||||||
|
FollowingCount: number;
|
||||||
|
XpLevel: number;
|
||||||
|
XpPoints: number;
|
||||||
|
AvatarUrl: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface APP_START extends defaultRequest {
|
||||||
|
path: apiBackendRequest.APP_START;
|
||||||
|
|
||||||
|
response: {
|
||||||
|
TokenValid: boolean;
|
||||||
|
AccountName: AccountName;
|
||||||
|
Username: Username;
|
||||||
|
Description: string;
|
||||||
|
FollowersCount: number;
|
||||||
|
FollowingCount: number;
|
||||||
|
XpLevel: number;
|
||||||
|
XpPoints: number;
|
||||||
|
AccountStatus: number;
|
||||||
|
AvatarUrl: string;
|
||||||
|
Events: any;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
type FetchTypes =
|
type FetchTypes =
|
||||||
| REGISTER_STEP_1
|
| REGISTER_STEP_1
|
||||||
| REGISTER_RESEND_MAIL
|
| REGISTER_RESEND_MAIL
|
||||||
| REGISTER_STEP_2
|
| REGISTER_STEP_2
|
||||||
| REGISTER_STEP_FINAL
|
| REGISTER_STEP_FINAL
|
||||||
| REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK;
|
| REGISTER_STEP_FINAL_ACCOUNT_NAME_CHECK
|
||||||
|
| LOGIN
|
||||||
|
| GET_USER_PROFILE
|
||||||
|
| APP_START;
|
||||||
|
|
||||||
function isA(obj: any): obj is REGISTER_STEP_1 {
|
function isA(obj: any): obj is REGISTER_STEP_1 {
|
||||||
return obj.request !== undefined;
|
return obj.request !== undefined;
|
||||||
|
@ -130,9 +190,20 @@ export function makeRequest<T1 extends FetchTypes>(type: T1): Promise<T1> {
|
||||||
'X-Language': store.getState().appVariables.lang.details.langCode,
|
'X-Language': store.getState().appVariables.lang.details.langCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (type.requestHeader !== undefined) {
|
||||||
|
for (let key in type.requestHeader) {
|
||||||
|
let val = (type.requestHeader as requestHeader)[key];
|
||||||
|
|
||||||
|
if (val !== undefined) headers[key] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Platform.OS === 'android' || Platform.OS === 'ios')
|
if (Platform.OS === 'android' || Platform.OS === 'ios')
|
||||||
headers['User-Agent'] = getUserAgent();
|
headers['User-Agent'] = getUserAgent();
|
||||||
|
|
||||||
|
const SessionId = MyUserManager.getSessionId();
|
||||||
|
if (SessionId !== undefined) headers['X-Authorization'] = SessionId;
|
||||||
|
|
||||||
const requestOptions: RequestInit = {
|
const requestOptions: RequestInit = {
|
||||||
method: makeRequestObj.request !== undefined ? 'POST' : 'GET',
|
method: makeRequestObj.request !== undefined ? 'POST' : 'GET',
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
import {initDatabase} from './bdm/init';
|
||||||
|
|
||||||
|
const BigDataManager = {initDatabase};
|
||||||
|
export default BigDataManager;
|
|
@ -0,0 +1,18 @@
|
||||||
|
import Realm from 'realm';
|
||||||
|
import DBSchemas from './schemas';
|
||||||
|
|
||||||
|
export const initDatabase = (): Promise<void> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
for (const key in DBSchemas) {
|
||||||
|
const Schema = DBSchemas[key as keyof typeof DBSchemas];
|
||||||
|
Realm.open({
|
||||||
|
schema: [Schema.details],
|
||||||
|
schemaVersion: Schema.version,
|
||||||
|
path: Schema.filePath,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,16 @@
|
||||||
|
import {openDB, deleteDB, wrap, unwrap} from 'idb';
|
||||||
|
import DBSchemas from './schemas';
|
||||||
|
|
||||||
|
export const initDatabase = (): Promise<void> => {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
setTimeout(async () => {
|
||||||
|
for (const key in DBSchemas) {
|
||||||
|
const Schema = DBSchemas[key as keyof typeof DBSchemas];
|
||||||
|
await openDB(Schema.details.name, Schema.version, {
|
||||||
|
upgrade: Schema.migration,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,15 @@
|
||||||
|
import {MigrationCallback} from 'realm';
|
||||||
|
|
||||||
|
export const usersDBMigration: MigrationCallback = (oldRealm, newRealm) => {
|
||||||
|
/*// only apply this change if upgrading to schemaVersion 2
|
||||||
|
if (oldRealm.schemaVersion < 2) {
|
||||||
|
const oldObjects = oldRealm.objects('Person');
|
||||||
|
const newObjects = newRealm.objects('Person');
|
||||||
|
// loop through all objects and set the fullName property in the new schema
|
||||||
|
for (const objectIndex in oldObjects) {
|
||||||
|
const oldObject = oldObjects[objectIndex];
|
||||||
|
const newObject = newObjects[objectIndex];
|
||||||
|
newObject.fullName = `${oldObject.firstName} ${oldObject.lastName}`;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
};
|
|
@ -0,0 +1,68 @@
|
||||||
|
import {IDBPDatabase, IDBPTransaction, StoreNames} from 'idb';
|
||||||
|
import DBSchemas from './schemas';
|
||||||
|
|
||||||
|
interface migrationArguments {
|
||||||
|
db: IDBPDatabase<unknown>;
|
||||||
|
oldVersion: number;
|
||||||
|
newVersion: number | null;
|
||||||
|
transaction: IDBPTransaction<unknown, StoreNames<unknown>[], 'versionchange'>;
|
||||||
|
event: IDBVersionChangeEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
type upgradeFunc = (
|
||||||
|
database: IDBPDatabase<unknown>,
|
||||||
|
oldVersion: number,
|
||||||
|
newVersion: number | null,
|
||||||
|
transaction: IDBPTransaction<unknown, StoreNames<unknown>[], 'versionchange'>,
|
||||||
|
event: IDBVersionChangeEvent,
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
export const usersDBMigration: upgradeFunc = (
|
||||||
|
db,
|
||||||
|
oldVersion,
|
||||||
|
newVersion,
|
||||||
|
transaction,
|
||||||
|
event,
|
||||||
|
) => {
|
||||||
|
const Schema = DBSchemas['users'];
|
||||||
|
|
||||||
|
if (oldVersion == 0) {
|
||||||
|
// perform the initialization
|
||||||
|
db.createObjectStore(Schema.details.name, {
|
||||||
|
keyPath: Schema.details.primaryKey,
|
||||||
|
});
|
||||||
|
} else if (newVersion !== null) {
|
||||||
|
let ver = oldVersion;
|
||||||
|
|
||||||
|
while (ver < newVersion) {
|
||||||
|
console.log('upgrade from v', ver, ' to v', ver + 1);
|
||||||
|
|
||||||
|
ver++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const chatDBMigration: upgradeFunc = (
|
||||||
|
db,
|
||||||
|
oldVersion,
|
||||||
|
newVersion,
|
||||||
|
transaction,
|
||||||
|
event,
|
||||||
|
) => {
|
||||||
|
const Schema = DBSchemas['chat'];
|
||||||
|
|
||||||
|
if (oldVersion == 0) {
|
||||||
|
// perform the initialization
|
||||||
|
db.createObjectStore(Schema.details.name, {
|
||||||
|
keyPath: Schema.details.primaryKey,
|
||||||
|
});
|
||||||
|
} else if (newVersion !== null) {
|
||||||
|
let ver = oldVersion;
|
||||||
|
|
||||||
|
while (ver < newVersion) {
|
||||||
|
console.log('upgrade from v', ver, ' to v', ver + 1);
|
||||||
|
|
||||||
|
ver++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,47 @@
|
||||||
|
import {usersDBMigration} from './migration';
|
||||||
|
import {chatDBMigration} from './migration.web';
|
||||||
|
|
||||||
|
type databaseNames = 'users' | 'chat';
|
||||||
|
|
||||||
|
interface databaseConf {
|
||||||
|
filePath: string;
|
||||||
|
version: number;
|
||||||
|
migration?: any;
|
||||||
|
details: {
|
||||||
|
name: databaseNames;
|
||||||
|
properties: any;
|
||||||
|
primaryKey: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const users: databaseConf = {
|
||||||
|
filePath: 'users',
|
||||||
|
version: 1,
|
||||||
|
migration: usersDBMigration,
|
||||||
|
details: {
|
||||||
|
name: 'users',
|
||||||
|
properties: {
|
||||||
|
UserId: 'string',
|
||||||
|
AccountName: 'string',
|
||||||
|
Username: 'string',
|
||||||
|
},
|
||||||
|
primaryKey: 'UserId',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const chat: databaseConf = {
|
||||||
|
filePath: 'chat',
|
||||||
|
version: 1,
|
||||||
|
migration: chatDBMigration,
|
||||||
|
details: {
|
||||||
|
name: 'chat',
|
||||||
|
properties: {
|
||||||
|
UserId: 'string',
|
||||||
|
msg: 'string',
|
||||||
|
},
|
||||||
|
primaryKey: 'UserId',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const DBSchemas = {users, chat};
|
||||||
|
export default DBSchemas;
|
|
@ -22,8 +22,15 @@ export default interface LangFormat {
|
||||||
error: string;
|
error: string;
|
||||||
success: string;
|
success: string;
|
||||||
account: {
|
account: {
|
||||||
|
login: {
|
||||||
|
title: string;
|
||||||
|
wrongEmPw: string;
|
||||||
|
failed: string;
|
||||||
|
success: string;
|
||||||
|
};
|
||||||
registration: {
|
registration: {
|
||||||
registration: string;
|
registration: string;
|
||||||
|
|
||||||
info: string;
|
info: string;
|
||||||
privacyPolicy: string;
|
privacyPolicy: string;
|
||||||
termsOfUse: string;
|
termsOfUse: string;
|
||||||
|
@ -55,7 +62,11 @@ export default interface LangFormat {
|
||||||
accountNameError: {[key: string]: string};
|
accountNameError: {[key: string]: string};
|
||||||
userNameError: {[key: string]: string};
|
userNameError: {[key: string]: string};
|
||||||
passwordError: {[key: string]: string};
|
passwordError: {[key: string]: string};
|
||||||
|
passwordQuality: string;
|
||||||
|
passwordQualityList: {[key: string]: string};
|
||||||
|
noAllFieldsEntered: string;
|
||||||
button: string;
|
button: string;
|
||||||
|
registerError: {[key: string]: string};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,13 +21,20 @@ export const lang: LangFormat = {
|
||||||
error: 'Error',
|
error: 'Error',
|
||||||
success: 'Success',
|
success: 'Success',
|
||||||
account: {
|
account: {
|
||||||
|
login: {
|
||||||
|
title: 'Log in',
|
||||||
|
wrongEmPw: 'Wrong E-Mail or password',
|
||||||
|
failed: 'Login failed. Try again or contact support.',
|
||||||
|
success: 'Successfully logged in!',
|
||||||
|
},
|
||||||
registration: {
|
registration: {
|
||||||
registration: 'Registration',
|
registration: 'Registration',
|
||||||
|
|
||||||
info: 'By registering, you agree to our ${TermsOfUse}. You can find out how we collect and use your data in our ${privacyPolicy}.',
|
info: 'By registering, you agree to our ${TermsOfUse}. You can find out how we collect and use your data in our ${privacyPolicy}.',
|
||||||
privacyPolicy: 'privacy policy',
|
privacyPolicy: 'privacy policy',
|
||||||
termsOfUse: 'Terms of Use',
|
termsOfUse: 'Terms of Use',
|
||||||
stepOne: {
|
stepOne: {
|
||||||
title: 'Enter E-Mail',
|
title: 'E-Mail',
|
||||||
success: 'A verification has sent to your E-Mail!',
|
success: 'A verification has sent to your E-Mail!',
|
||||||
addressExists: 'The E-Mail you entered is already in use.',
|
addressExists: 'The E-Mail you entered is already in use.',
|
||||||
addressInvalid: 'The address you entered has an invalid format.',
|
addressInvalid: 'The address you entered has an invalid format.',
|
||||||
|
@ -44,7 +51,7 @@ export const lang: LangFormat = {
|
||||||
'E-Mail verification has resent',
|
'E-Mail verification has resent',
|
||||||
],
|
],
|
||||||
resendError: {
|
resendError: {
|
||||||
400: 'The E-Mail is already verified!',
|
400: 'Email is already in the registration process by another user!',
|
||||||
401: 'Your device have changed. Please use another E-Mail address.',
|
401: 'Your device have changed. Please use another E-Mail address.',
|
||||||
429: 'Too many requests in a too small period of time in a row',
|
429: 'Too many requests in a too small period of time in a row',
|
||||||
},
|
},
|
||||||
|
@ -63,29 +70,44 @@ export const lang: LangFormat = {
|
||||||
accountName: 'AccountName',
|
accountName: 'AccountName',
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
passwordRepeat: 'Repeat password',
|
passwordRepeat: 'Repeat password',
|
||||||
displayName: 'Other users see you like this:',
|
displayName: 'Other users will see you like this:',
|
||||||
accountNameError: {
|
accountNameError: {
|
||||||
tooLong: 'Too long. Max length are $(maxLength) character.',
|
tooLong: 'Too long. Max length are ${maxLength} character.',
|
||||||
tooShort: 'Too short. Min length are $(minLength) character.',
|
tooShort: 'Too short. Min length are ${minLength} character.',
|
||||||
required: 'This field is required',
|
required: 'This field is required',
|
||||||
invalid:
|
invalid:
|
||||||
'Account names can only contain letters, numbers, underscores (_) and dots (.)',
|
'Account names can only contain letters, numbers, underscores (_) and dots (.)',
|
||||||
exists: 'The account name you entered already exists.',
|
exists: 'The account name you entered already exists.',
|
||||||
|
422: 'This name is already in use :(',
|
||||||
},
|
},
|
||||||
userNameError: {
|
userNameError: {
|
||||||
tooLong: 'Too long. Max length are $(maxLength) character.',
|
tooLong: 'Too long. Max length are ${maxLength} character.',
|
||||||
tooShort: 'Too short. Min length are $(minLength) character.',
|
tooShort: 'Too short. Min length are ${minLength} character.',
|
||||||
required: 'This field is required',
|
required: 'This field is required',
|
||||||
},
|
},
|
||||||
passwordError: {
|
passwordError: {
|
||||||
noMatch: 'Passwords do not match',
|
noMatch: 'Passwords do not match',
|
||||||
tooLong: 'Too long. Max length are $(maxLength) character.',
|
tooLong: 'Too long. Max length are ${maxLength} character.',
|
||||||
tooShort: 'Too short. Min length are $(minLength) character.',
|
tooShort: 'Too short. Min length are ${minLength} character.',
|
||||||
required: 'This field is required',
|
required: 'This field is required',
|
||||||
weak: 'Password is too weak',
|
weak: 'Password is too weak',
|
||||||
|
invalid:
|
||||||
|
"Passwords must have at least one letter, one number, and one special character. It's for your security. :)",
|
||||||
},
|
},
|
||||||
|
passwordQuality: 'Password quality: ${quality}',
|
||||||
|
passwordQualityList: {
|
||||||
|
0: 'Very weak',
|
||||||
|
1: 'Weak',
|
||||||
|
2: 'Moderate',
|
||||||
|
3: 'Strong',
|
||||||
|
4: 'Very strong',
|
||||||
|
},
|
||||||
|
noAllFieldsEntered: 'Please fill all fields',
|
||||||
button: 'Finish registration',
|
button: 'Finish registration',
|
||||||
|
registerError: {
|
||||||
|
400: 'Sign up process expired please try again',
|
||||||
|
401: 'User agent and/or IP has changed',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import appNonSaveVarReducer from '@caj/configs/appNonSaveVarReducer';
|
import appNonSaveVarReducer from '@caj/configs/appNonSaveVarReducer';
|
||||||
import {configureStore} from '@reduxjs/toolkit';
|
import {configureStore} from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import appVariablesReducer from '../configs/appVarReducer';
|
import appVariablesReducer from '@caj/configs/appVarReducer';
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
import {appVarActions} from '@caj/configs/appVarReducer';
|
||||||
|
import {
|
||||||
|
AccountName,
|
||||||
|
EMail,
|
||||||
|
XAuthorization,
|
||||||
|
UserId,
|
||||||
|
Username,
|
||||||
|
WebSocketSessionId,
|
||||||
|
} from '@caj/configs/types';
|
||||||
|
import {saveVarChanges} from '@caj/helper/appData';
|
||||||
|
import {apiBackendRequest, makeRequest} from '@caj/helper/request';
|
||||||
|
import {store} from '@caj/redux/store';
|
||||||
|
import {MyUserAccount, createUserProp, SourceProp} from './types';
|
||||||
|
|
||||||
|
function createNewMyUser(
|
||||||
|
UserId: UserId,
|
||||||
|
AccountName: AccountName,
|
||||||
|
Username: Username,
|
||||||
|
EMail: EMail,
|
||||||
|
SessionId: XAuthorization,
|
||||||
|
WebSocketSessionId: WebSocketSessionId,
|
||||||
|
): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let user: MyUserAccount = {
|
||||||
|
UserId,
|
||||||
|
AccountName: createUserProp(SourceProp.offline, AccountName),
|
||||||
|
Username: createUserProp(SourceProp.offline, Username),
|
||||||
|
Description: createUserProp(SourceProp.online),
|
||||||
|
FollowersCount: createUserProp(SourceProp.online),
|
||||||
|
FollowingCount: createUserProp(SourceProp.online),
|
||||||
|
XpLevel: createUserProp(SourceProp.online),
|
||||||
|
XpPoints: createUserProp(SourceProp.online),
|
||||||
|
EMail,
|
||||||
|
SessionId,
|
||||||
|
WebSocketSessionId,
|
||||||
|
lastUpdateTimestamp: createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
Math.floor(new Date().getTime() / 1000),
|
||||||
|
),
|
||||||
|
ProfilePicture: {
|
||||||
|
hq: createUserProp(SourceProp.offline),
|
||||||
|
lq: createUserProp(SourceProp.offline),
|
||||||
|
},
|
||||||
|
userSettings: {
|
||||||
|
lang: store.getState().appVariables.lang.details.langCode,
|
||||||
|
theme: store.getState().appVariables.preferences.theme,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('SessionId', SessionId);
|
||||||
|
|
||||||
|
createMyUser(user);
|
||||||
|
|
||||||
|
makeRequest({
|
||||||
|
path: apiBackendRequest.APP_START,
|
||||||
|
requestGET: {':userId': UserId},
|
||||||
|
response: {
|
||||||
|
AccountName: '',
|
||||||
|
Description: '',
|
||||||
|
FollowersCount: 0,
|
||||||
|
FollowingCount: 0,
|
||||||
|
Username: '',
|
||||||
|
XpLevel: 0,
|
||||||
|
XpPoints: 0,
|
||||||
|
AvatarUrl: '',
|
||||||
|
AccountStatus: 0,
|
||||||
|
Events: {},
|
||||||
|
TokenValid: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
let user = {...getMyUser(UserId)};
|
||||||
|
console.log(user);
|
||||||
|
user.AccountName = createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
resp.response.AccountName,
|
||||||
|
);
|
||||||
|
user.Username = createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
resp.response.Username,
|
||||||
|
);
|
||||||
|
user.Description = createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
resp.response.Description,
|
||||||
|
);
|
||||||
|
user.FollowersCount = createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
resp.response.FollowersCount,
|
||||||
|
);
|
||||||
|
user.FollowingCount = createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
resp.response.FollowingCount,
|
||||||
|
);
|
||||||
|
user.XpLevel = createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
resp.response.XpLevel,
|
||||||
|
);
|
||||||
|
user.XpPoints = createUserProp(
|
||||||
|
SourceProp.offline,
|
||||||
|
resp.response.XpPoints,
|
||||||
|
);
|
||||||
|
|
||||||
|
setMyUser(user);
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch(resp => {
|
||||||
|
console.error(resp.status);
|
||||||
|
reject();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMyUser(user: MyUserAccount) {
|
||||||
|
store.dispatch(appVarActions.setAccount(user));
|
||||||
|
store.dispatch(appVarActions.setCurrentAccount(user.UserId));
|
||||||
|
saveVarChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMyUser(userId: UserId): MyUserAccount {
|
||||||
|
return store.getState().appVariables.preferences.accounts[userId];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setMyUser(user: MyUserAccount) {
|
||||||
|
store.dispatch(appVarActions.setAccount(user));
|
||||||
|
saveVarChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSessionId(userId?: UserId): XAuthorization | undefined {
|
||||||
|
const preferences = store.getState().appVariables.preferences;
|
||||||
|
let user = preferences.accounts[userId || preferences.selectedAccount];
|
||||||
|
|
||||||
|
if (user === undefined) return undefined;
|
||||||
|
|
||||||
|
let SessionId = user.SessionId;
|
||||||
|
|
||||||
|
console.log(userId || preferences.selectedAccount);
|
||||||
|
console.log(preferences.accounts[userId || preferences.selectedAccount]);
|
||||||
|
|
||||||
|
return SessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MyUserManager = {createNewMyUser, getSessionId};
|
||||||
|
export default MyUserManager;
|
|
@ -0,0 +1,5 @@
|
||||||
|
import {UserId, XAuthorization} from '@caj/configs/types';
|
||||||
|
import {store} from '@caj/redux/store';
|
||||||
|
|
||||||
|
const UserManager = {};
|
||||||
|
export default UserManager;
|
|
@ -0,0 +1,62 @@
|
||||||
|
import {ThemeMode} from '@caj/configs/appVar';
|
||||||
|
import {
|
||||||
|
AccountName,
|
||||||
|
EMail,
|
||||||
|
langCode,
|
||||||
|
XAuthorization,
|
||||||
|
timestamp,
|
||||||
|
UserId,
|
||||||
|
Username,
|
||||||
|
WebSocketSessionId,
|
||||||
|
} from '@caj/configs/types';
|
||||||
|
|
||||||
|
export enum SourceProp {
|
||||||
|
online = -1,
|
||||||
|
offline = 0,
|
||||||
|
cached = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BasicUserProp<T1> {
|
||||||
|
source: SourceProp;
|
||||||
|
url?: string;
|
||||||
|
data?: T1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProfilePicture {
|
||||||
|
lq: BasicUserProp<string>;
|
||||||
|
hq: BasicUserProp<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface User {
|
||||||
|
UserId: UserId;
|
||||||
|
|
||||||
|
ProfilePicture: ProfilePicture;
|
||||||
|
lastUpdateTimestamp: BasicUserProp<timestamp>;
|
||||||
|
AccountName: BasicUserProp<AccountName>;
|
||||||
|
Username: BasicUserProp<Username>;
|
||||||
|
Description: BasicUserProp<string>;
|
||||||
|
FollowersCount: BasicUserProp<number>;
|
||||||
|
FollowingCount: BasicUserProp<number>;
|
||||||
|
XpLevel: BasicUserProp<number>;
|
||||||
|
XpPoints: BasicUserProp<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MyUserAccount extends User {
|
||||||
|
EMail: EMail;
|
||||||
|
SessionId: XAuthorization;
|
||||||
|
WebSocketSessionId: WebSocketSessionId;
|
||||||
|
userSettings: userSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface userSettings {
|
||||||
|
theme: ThemeMode;
|
||||||
|
lang: langCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createUserProp<T1>(
|
||||||
|
source: SourceProp,
|
||||||
|
data?: T1,
|
||||||
|
url?: string,
|
||||||
|
): BasicUserProp<T1> {
|
||||||
|
return {source, data, url};
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
},
|
},
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"allowJs": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"jsx": "react-native",
|
"jsx": "react-native",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
|
Loading…
Reference in New Issue