Untitled
unknown
json
a year ago
17 kB
5
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