Untitled
unknown
json
2 years ago
17 kB
17
Indexable
import React, {
useCallback,
useEffect,
useLayoutEffect,
useMemo,
useState,
} from 'react';
import {
ActivityIndicator,
Image,
ImageBackground,
SafeAreaView,
Text,
TouchableOpacity,
View,
} from 'react-native';
import {useHeaderHeight} from '@react-navigation/stack';
import {useAuth} from '@squantumengine/react-native-sqeid';
import axios from 'axios';
import Config from 'react-native-config';
import PhoneImage from '@assets/illustration/phone.webp';
import SinarmasSSOImage from '@assets/login/sinarmas-sso.webp';
import {SvgIcon} from '@assets/svg';
import {ToggleSwitch} from '@components/Atom';
import Button from '@components/Atom/Button';
import DevModeButton from '@components/Atom/DevModeButton';
import If from '@components/Atom/If';
import KeyboardAdjustedView from '@components/Atom/KeyboardAjustedView';
import TextField from '@components/Atom/TextField';
import {NanoModal} from '@components/Organism';
import HelpModal from '@components/Organism/HelpModal';
import RemoteAccessCheck from '@components/Organism/RemoteAccessCheck';
import {colors as staticColors} from '@design-system';
import {useLocale} from '@hooks/global/useLocale';
import useModal from '@hooks/global/useModal';
import useRemoteAccessApps from '@hooks/global/useRemoteAccessApps';
import {useTheme} from '@hooks/global/useTheme';
import useUserInfo from '@hooks/global/useUserInfo';
import useAnimation from '@hooks/local/useAnimation';
import useFirebaseRemoteState from '@hooks/local/useFirebaseRemoteState';
import useHelpCenter from '@hooks/local/useHelpCenter';
import useLogin from '@hooks/local/useLogin';
import useSegmentAnalytics from '@hooks/local/useSegmentAnalytics';
import {Translation} from '@hooks/local/useSegmentAnalytics/AnalyticPropertyEnum';
import {LoginScreenTestId} from '@models/ScreenTestId';
import {AuthStackProps} from '@navigator/AuthParamList';
import {removeAllSpace} from '@utils/formatUtils';
import {resolveImageSource} from '@utils/imageUtils';
import {isIphoneX} from '@utils/iPhoneXHelpers';
import {formatPhoneNumber, parsePhoneNumber} from '@utils/phoneNumHelper';
import {
isValidPhoneNumber,
isValidStartPhoneNumber,
} from '@utils/validators/inputValidator';
import getStyles from './style';
const LoginScreen = ({navigation}: AuthStackProps<'Login'>) => {
const {
login: loginSSOSinarmas,
credentialsCallback,
saveCredentials,
renewCredentialsAfterPhoneNumberChanged,
} = useAuth();
const [isValid, setIsValid] = useState<boolean>(false);
const [isInputError, setInputError] = useState<boolean>(false);
const [phoneNumber, setPhoneNumber] = useState<string | undefined>(undefined);
const countryCode = '62';
const {translate: t, changeLocale, locale} = useLocale();
const [, hideModal] = useModal(
_ => undefined,
action => action.hideModal,
);
const [, showSelectorModal] = useModal(
_ => undefined,
action => action.showSelectorModal,
);
const [, useUserInfoAPI] = useUserInfo(
_ => undefined,
action => action.useUserInfoAPI,
);
const {removeLocalData, updateLanguage, isLoadingPutUserInfo} =
useUserInfoAPI();
const {hapticEffect} = useAnimation();
const {trackEvent, trackScreen} = useSegmentAnalytics('VerifyPhoneNumber');
const [modalVisible, setModalVisible] = useState(false);
const [isShowModalSSOSinarmas, setIsShowModalSSOSinarmas] = useState(false);
const {
checkAvailability,
isCheckingPhoneAvailability,
postSQEToken,
isSSOSinarmasActivated,
} = useLogin();
const {showHelpCenter} = useHelpCenter();
const {firebaseAppConfig, getFirebaseAppConfig} =
useFirebaseRemoteState.AppConfig();
const {
colors: colorTheme,
images: imagesTheme,
theme,
changeTheme,
} = useTheme();
const styles = useMemo(() => getStyles(colorTheme), [colorTheme]);
// Language
const languagesData = useMemo(() => {
return ['English', 'Bahasa Indonesia'];
}, []);
const handleTextChanged = useCallback(
(text: string) => {
hapticEffect();
text = text.replace(/\s|\D/g, '');
if (removeAllSpace(text) === Config.STATIC_PHONE_NUMBER) {
setIsValid(true);
setInputError(false);
} else {
setIsValid(isValidPhoneNumber(parsePhoneNumber(text)));
setInputError(!isValidStartPhoneNumber(parsePhoneNumber(text)));
}
if (text !== null) {
setPhoneNumber(formatPhoneNumber(text));
if (text.length >= 8) {
trackEvent('VerifyPhoneNumberCheck');
}
}
},
[hapticEffect, trackEvent],
);
const handleCallbackResult = credentials => {
if (credentials) {
postSQEToken({requestBody: {sqeToken: credentials.accessToken}});
saveCredentials(credentials);
}
};
const handleSubmitNumber = useCallback(async () => {
removeLocalData();
if (phoneNumber) {
// Overriding the baseURL if app detects below number are being used
// Basically we forced the app to points to UAT env for this number
// This number are used ONLY for Apple & Playstore QAs
// For them to test main functionality of the App
if (removeAllSpace(phoneNumber) === Config.STATIC_PHONE_NUMBER) {
axios.defaults.baseURL = Config.STATIC_URL_BASE_PATH;
} else {
axios.defaults.baseURL = Config.BFF_WALLET_BASE_PATH;
}
const parsedNo = parsePhoneNumber(phoneNumber);
checkAvailability({countryCode, phoneNumber: parsedNo});
trackEvent('VerifyPhoneNumberNextTapped');
}
}, [phoneNumber, removeLocalData, checkAvailability, trackEvent]);
const onSelectLanguage = useCallback(
(value: string, index: number) => {
const selectedLanguage = value === 'English' ? 'en' : 'id';
trackEvent('VerifyPhoneNumberChooseLanguageTapped', {
language_selected:
selectedLanguage === 'en' ? Translation.EN : Translation.ID,
});
changeLocale(selectedLanguage);
hideModal();
},
[changeLocale, hideModal, trackEvent],
);
const closeModalLanguage = useCallback(() => {
trackEvent('VerifyPhoneNumberCloseLanguage');
hideModal();
}, [hideModal, trackEvent]);
const handlePressLanguage = useCallback(() => {
trackEvent('VerifyPhoneNumberChangeLanguageTapped');
showSelectorModal({
visible: true,
data: languagesData,
onSelectItem: onSelectLanguage,
title: t('languages'),
onClose: closeModalLanguage,
onDismiss: closeModalLanguage,
testID: LoginScreenTestId.LOGIN_LANGUAGE_SWITCH,
});
}, [
closeModalLanguage,
languagesData,
onSelectLanguage,
showSelectorModal,
t,
trackEvent,
]);
const onChangeTheme = useCallback(() => {
changeTheme(theme === 'DARK' ? 'LIGHT' : 'DARK');
}, [changeTheme, theme]);
const [remoteAppDeatils] = useRemoteAccessApps(
state => state.remoteAppDeatils,
);
const onLanguageToggle = useCallback(
(newMode: boolean) => {
if (newMode) {
setTimeout(() => {
changeLocale('id');
}, 150);
} else {
setTimeout(() => {
changeLocale('en');
}, 100);
}
},
[changeLocale, updateLanguage],
);
const customSwitchLanguage = useMemo(() => {
if (isLoadingPutUserInfo) {
return <ActivityIndicator color={staticColors.primary.white} />;
}
return locale === 'en' ? (
<Text style={styles.textLanguangeToggle}>EN</Text>
) : (
<Text style={styles.textLanguangeToggle}>ID</Text>
);
}, [locale, styles.textLanguangeToggle, isLoadingPutUserInfo]);
const TextInActiveComponent = useMemo(() => {
return (
<Text
style={[
styles.textInActive,
locale === 'en' ? styles.isEnglish : styles.isIndonesia,
]}>
{locale === 'en' ? 'ID' : 'EN'}
</Text>
);
}, [locale, styles.isEnglish, styles.isIndonesia, styles.textInActive]);
useLayoutEffect(() => {
navigation.setOptions({
headerTransparent: true,
headerRight: () => (
<If condition={!remoteAppDeatils?.isRemoteAccessAppsInstalled}>
<ToggleSwitch
switchStatus={locale === 'id'}
onChange={onLanguageToggle}
switchInactiveColor={colorTheme.shade.grey2}
switchActiveColor={colorTheme.shade.grey2}
customInputRangeAnimation={[0, 1.2]}
customSwitchComponent={customSwitchLanguage}
switchIndicatorStyle={styles.languageToggle}
switchContainerStyle={styles.containerToggleStyle}
customTextInactiveComponent={TextInActiveComponent}
/>
</If>
),
headerLeft: () => (
<If
condition={
firebaseAppConfig.isDarkmodeToggleEnabled &&
!remoteAppDeatils?.isRemoteAccessAppsInstalled
}>
<TouchableOpacity
onPress={onChangeTheme}
activeOpacity={0.7}
style={styles.notifWrapper}
testID={LoginScreenTestId.LOGIN_THEME_SWITCH + 'pressable'}
accessibilityLabel={
LoginScreenTestId.LOGIN_THEME_SWITCH + 'pressable'
}
accessible>
<Image
source={resolveImageSource(imagesTheme.homepage.toggle)}
style={styles.notiIcon}
testID={LoginScreenTestId.LOGIN_THEME_SWITCH + 'image'}
accessibilityLabel={
LoginScreenTestId.LOGIN_THEME_SWITCH + 'image'
}
accessible
/>
</TouchableOpacity>
</If>
),
});
}, [
firebaseAppConfig,
handlePressLanguage,
imagesTheme.homepage.toggle,
locale,
navigation,
onChangeTheme,
remoteAppDeatils?.isRemoteAccessAppsInstalled,
styles,
]);
useEffect(() => {
getFirebaseAppConfig();
trackScreen();
}, [trackScreen, getFirebaseAppConfig]);
const _onOpenHelp = useCallback(() => {
setModalVisible(true);
trackEvent('VerifyPhoneNumberQuestionMarkTapped');
}, [trackEvent]);
const _closeRbSheet = useCallback(() => {
setModalVisible(false);
}, []);
const _bsContent: () =>
| {title: string; contents: {label: string; uri: string}[]}
| undefined = useCallback(() => {
return {
title: t('button.need_help'),
contents: [
{
label: t('help_list_number_inactive'),
uri: '/requests/new?ticket_form_id=360000205478&tf_360011144817=This+is+another+value+for+the+text+field+from+the+config&tf_360025038718=dropdown_value_2',
},
{
label: t('help_list_number_unused'),
uri: '/requests/new?ticket_form_id=360000205478&tf_360011144817=This+is+another+value+for+the+text+field+from+the+config&tf_360025038718=dropdown_value_2',
},
],
};
}, [t]);
const LeftButtonTextInput = useCallback(
() => (
<TouchableOpacity
style={styles.iconHelp}
activeOpacity={0.75}
onPress={_onOpenHelp}
testID={LoginScreenTestId.LOGIN_PHONE_HELP + '-pressable'}
accessibilityLabel={LoginScreenTestId.LOGIN_PHONE_HELP + '-pressable'}
accessible>
<SvgIcon.Question />
</TouchableOpacity>
),
[_onOpenHelp, styles.iconHelp],
);
const _onPress = useCallback(
item => {
showHelpCenter({
uri: item.uri,
beforeOpenHC: _closeRbSheet,
});
},
[_closeRbSheet, showHelpCenter],
);
const _renderItemBsContent = useCallback(
(item: {label: string; uri: string}, index: number = 0) => {
return (
<TouchableOpacity
onPress={() => _onPress(item)}
key={`${index}`}
style={styles.contentContainerBs}
testID={LoginScreenTestId.LOGIN_PHONE_HELP + '-itemList-' + index}
accessibilityLabel={
LoginScreenTestId.LOGIN_PHONE_HELP + '-itemList-' + index
}
accessible>
<Text
style={styles.contentTextBs}
testID={LoginScreenTestId.LOGIN_PHONE_HELP + '-text-' + index}
accessibilityLabel={
LoginScreenTestId.LOGIN_PHONE_HELP + '-text-' + index
}
accessible>
{item.label}
</Text>
</TouchableOpacity>
);
},
[_onPress, styles.contentContainerBs, styles.contentTextBs],
);
const marginTop = useHeaderHeight();
if (remoteAppDeatils?.isRemoteAccessAppsInstalled) {
return <RemoteAccessCheck remoteApps={remoteAppDeatils?.installedApps} />;
}
const hideSSOModal = () => {
setIsShowModalSSOSinarmas(false);
};
credentialsCallback(handleCallbackResult);
const doLoginSSOSinarmas = () => {
hideSSOModal();
setTimeout(() => {
loginSSOSinarmas();
}, 250);
};
return (
<ImageBackground
source={imagesTheme.bgAccount.background}
style={styles.background}>
<SafeAreaView style={styles.container}>
<KeyboardAdjustedView
keyboardMargin={isIphoneX() ? 0 : 24}
style={[styles.container, styles.keyboardView]}>
<DevModeButton phoneNumber={phoneNumber?.replace(/\s/g, '') ?? ''}>
<Image
style={[styles.headerIcon, {marginTop}]}
source={PhoneImage}
/>
</DevModeButton>
<View style={styles.textContainer}>
<Text
style={styles.contentTitle}
testID={LoginScreenTestId.LOGIN_GREETING + '-text'}
accessibilityLabel={LoginScreenTestId.LOGIN_GREETING + '-text'}
accessible>
{t('auth.login.greeting')}
</Text>
<Text
style={styles.contentDesc}
testID={LoginScreenTestId.LOGIN_ENTER_PHONE_NUMBER + '-text'}
accessibilityLabel={
LoginScreenTestId.LOGIN_ENTER_PHONE_NUMBER + '-text'
}
accessible>
{t('auth.login.enter_phone_number')}
</Text>
</View>
<TextField
startText={`+${countryCode}`}
placeholder={'821 001 00'}
onChangeText={handleTextChanged}
value={phoneNumber}
maxLength={15}
editable={!isCheckingPhoneAvailability}
status={isInputError ? 'error' : 'normal'}
errorText={t('auth.login.error_start_number')}
leftButton={LeftButtonTextInput}
testID={LoginScreenTestId.LOGIN_PHONE_INPUT_FIELD}
accessibilityLabel={LoginScreenTestId.LOGIN_PHONE_INPUT_FIELD}
/>
<View style={styles.buttonContainer}>
<Button
type="primary"
disabled={!isValid}
loading={isCheckingPhoneAvailability}
text={t('button.next')}
onPress={handleSubmitNumber}
testID={LoginScreenTestId.LOGIN_GO_TO_NEXT}
textStyle={styles.actionText}
/>
</View>
<If condition={isSSOSinarmasActivated}>
<Text
style={styles.otherOptionDesc}
onPress={() => setIsShowModalSSOSinarmas(true)}>
{t('auth.login.other_method')}
</Text>
</If>
</KeyboardAdjustedView>
<HelpModal
visible={modalVisible}
onClose={_closeRbSheet}
testID={LoginScreenTestId.LOGIN_PHONE_HELP}
title={_bsContent()?.title ?? ''}>
{_bsContent()?.contents.map(_renderItemBsContent)}
</HelpModal>
<NanoModal
onBackdropPress={hideSSOModal}
onBackPress={hideSSOModal}
visible={isShowModalSSOSinarmas}>
<View style={styles.containerTempLockModal}>
<Text style={styles.titleModalLock}>
{t('auth.login.other_method_modal_title')}
</Text>
<View style={styles.containerButtonSSO}>
<Button
onPress={() =>
renewCredentialsAfterPhoneNumberChanged('+6285129999', {})
}
text={t('auth.login.sso_sinarmas')}
type={'custom'}
iconLeft={() => <Image source={SinarmasSSOImage} />}
textColor={staticColors.primary.black}
textStyle={styles.buttonTextSSO}
containerStyle={styles.containerButtonSSO}
/>
</View>
</View>
</NanoModal>
</SafeAreaView>
</ImageBackground>
);
};
export default LoginScreen;
Editor is loading...
Leave a Comment