Members
# setUserAgreementModalComponent
You can use this hook to customize the User Agreement modal. For example, you can add a checkbox at the bottom of the modal which will require users to scroll to the bottom to agree to the Terms of Service.
Example
//In custom_code/components/UserAgreementModal.js...
import React from "react";
import { View, Text, Platform } from "react-native";
import { wrapHtml } from "@src/utils";
import { DEVICE_HEIGHT, globalStyle } from "@src/styles/global";
import ScrollableModal from "@src/components/Modals/ScrollableModal";
import BottomSheetCloseButton from "@src/components/BottomSheet/BottomSheetCloseButton";
import ContentPlaceholder from "@src/components/ContentPlaceholder";
import ResizingWebView from "@src/components/ResizingWebView";
import { generateAssetsFontCss } from "@src/utils/jsUtils";
import { UserAgreementText } from "@src/components/Auth/UserAgreementText";
const UserAgreementModal = (props) => {
const {
config,
onClosed,
modalContent,
modalHeader,
hideModal,
refModal,
colors,
global,
t,
termsOfService,
privacyPolicy,
onPress,
onAgreementChecked,
agreementChecked,
} = props;
const {
htmlAdjustedCss,
htmlContentCss,
htmlStylesCss,
typography,
headerStyle
} = globalStyle(config.styles);
const renderModalHeader = () => (
<View
style={[
global.row,
global.panelHeader,
headerStyle,
{ borderColor: colors.borderColor, borderBottomWidth: 0.5 }
]}
>
{!!modalHeader && <Text style={global.filterTitle}>{modalHeader}</Text>}
<BottomSheetCloseButton onClose={hideModal} colors={colors} />
</View>
);
return (
<ScrollableModal
ref={refModal}
onClosed={onClosed}
HeaderComponent={renderModalHeader(global, colors)}
adjustToContentHeight={false}
scrollViewProps={{ backgroundColor: colors.bodyFrontBg }}
>
<View style={{flex: 1, padding: 20, borderRadius: 12}}>
<UserAgreementText
{...{
register: true,
colors,
global,
t,
termsOfService,
privacyPolicy,
withCheckbox: true,
onPress,
onAgreementChecked,
agreementChecked
}}
/>
<ResizingWebView
defaultHeight={DEVICE_HEIGHT}
width={"100%"}
startInLoadingState={true}
scrollEnabled={Platform.OS === "android"}
webViewStyle={Platform.OS === "android" ? { marginBottom: 150 } : {}}
nestedScrollEnabled
autoHeight={Platform.OS === "ios"}
fixAndroid={true}
contentId={"userAgreementContent"}
source={{
html: wrapHtml(
String(htmlStylesCss).replace(";overflow: hidden", "") +
htmlAdjustedCss +
htmlContentCss +
generateAssetsFontCss(
typography.bodyText.family,
typography.bodyText.type
)
)(modalContent)
}}
renderLoading={() => (
<View
style={{
position: "absolute",
top: 0,
left: 0,
bottom: 0,
right: 0,
zIndex: 1
}}
>
<ContentPlaceholder global={global} base={colors.headingsColor} />
</View>
)}
/>
</View>
</ScrollableModal>
);
};
export default UserAgreementModal;
//In custom_code/index.js...
...
import UserAgreeementModal from "./components/UserAgreementModal"
export const applyCustomCode = externalCodeSetup => {
externalCodeSetup.authApi.setUserAgreementModalComponent(props => <UserAgreeementModal {...props} />)
}
Methods
# setLoginButton(LoginButton)
You can use this hook to replace the Login Button on the login screen. You can also use this hook to change the behavior or styling of the login button on the login screen
Parameters:
Name | Type | Description |
---|---|---|
LoginButton |
React.ComponentType.<LoginButtonProps> |
Example
...
import {Alert} from "react-native"
import AppButton from "@src/components/AppButton";
export const applyCustomCode = externalCodeSetup => {
externalCodeSetup.authApi.setLoginButton(props => {
const {
t,
global,
colors,
doLogin,
stateUsername,
statePassword,
auth
} = props;
const customLoginAction = () => {
let isValid = false;
//Call an action to do extra validation such as an OTP request...
isValid = false;
//If successful, do default app login...
if (isValid) doLogin();
else Alert.alert("OTP is invalid");
};
return (
<AppButton
accessibilityLabel="login_button"
accessible
style={[{marginTop: 10}, global.authButtonContainer]}
onPress={() => customLoginAction()}
label={t("login:login")}
global={global}
loading={auth.isFetching}
labelStyle={global.authButtonLabel}
spinnerColor={colors.authButtonTextColor}
/>
);
});
}
# setLoginLogo(LoginLogo)
You can use this hook to replace the logo in the Login Screen. For example, you can change the logo's image, dimensions, or position.
Parameters:
Name | Type | Description |
---|---|---|
LoginLogo |
React.ComponentType.<LoginLogoProps> |
Example
...
import AppImage from "@src/components/AppImage";
export const applyCustomCode = (externalCodeSetup: ExternalCodeSetup) => {
externalCodeSetup.authApi.setLoginLogo(({
hideLogo,
headerStyle,
logoStyle,
source
}) => {
return !hideLogo && (
<View style={headerStyle}>
<AppImage
id="logo"
resizeMode={"contain"}
style={logoStyle}
source={source}
/>
</View>
)
})
}
# setRenderAuthInputs(renderAuthInput)
You can use this hook to modify the authentication fields on the login screen. For example, add a 'Phone' field along with the default email and password fields on the login screen.
Parameters:
Name | Type | Description |
---|---|---|
renderAuthInput |
React.ComponentType.<RenderAuthInputsProps> |
Examples
//In custom_code/LoginCustom.js...
import React, { useEffect, useState, useRef } from 'react';
import { Alert } from "react-native"
import AppButton from "@src/components/AppButton";
import TextInput from "@src/components/AppInput";
import { getExternalCodeSetup } from '../../src/externalCode/externalRepo';
const externalCodeSetup = getExternalCodeSetup();
const phoneIcon = require("../assets/img/phone.png");
const customLoginAction = (doLogin) => {
let isValid = false;
//Call an action to do extra validation such as an OTP request...
isValid = true;
//If successful, do default app login...
if (isValid)
doLogin()
else
Alert.alert("OTP is invalid")
}
const renderLoginButton = (phoneRef, usernameRef, passwordRef) => {
externalCodeSetup.authApi.setLoginButton(props => {
const {
t,
global,
stateUsername,
statePassword,
isSignUpEnabled,
privacyPolicy,
termsOfService,
withUserAgreementCheckbox,
stateAgreementChecked,
passwordInput,
usernameInput,
doLogin,
auth,
colors
} = props;
return <AppButton
accessibilityLabel="login_button"
accessible
style={[{ marginTop: 10 }, global.authButtonContainer]}
onPress={() => {
if (!!!stateUsername || !!!statePassword) {
return false;
}
if (
!isSignUpEnabled &&
withUserAgreementCheckbox &&
(privacyPolicy || termsOfService) &&
!stateAgreementChecked
) {
return Alert.alert(
t("login:user_agreement_title"),
t(
`login:user_agreement_message${privacyPolicy ? "_privacy" : ""
}${termsOfService ? "_terms" : ""}`
)
);
}
phoneRef.current.clear()
usernameRef.current.clear()
passwordRef.current.clear()
customLoginAction(doLogin);
}}
label="Get OTP"
global={global}
loading={auth.isFetching}
labelStyle={global.authButtonLabel}
spinnerColor={colors.authButtonTextColor}
/>
});
}
const AuthInputs = props => {
const {
t,
authBg,
global,
colors,
backgroundColor,
textColor,
userIcon,
setUsernameState,
stateUsername,
placeholderColor,
calcFontSize,
passwordIcon,
setPasswordState,
statePassword,
doLogin,
auth
} = props;
const [phone, setPhone] = useState('');
const phoneRef = useRef(null);
const usernameRef = useRef(null);
const passwordRef = useRef(null);
useEffect(() => {
renderLoginButton(phoneRef, usernameRef, passwordRef);
}, [])
return <>
<TextInput
accessibilityLabel="login_phone_input"
accessible
ref={phoneRef}
bodyColor={authBg}
inputWrapStyle={[global.formInput, { backgroundColor }]}
style={[
global.formInputText,
{ color: textColor, paddingLeft: 0 }
]}
keyboardType="numeric"
icon={phoneIcon}
webIcon={"IconUser"}
tintColor={textColor}
onChangeText={phone => setPhone({ phone })}
value={phone}
placeholderTextColor={placeholderColor}
placeholder="Phone"
autoCapitalize={"none"}
returnKeyType="next"
underlineColorAndroid="transparent"
autoCorrect={false}
calcFontSize={calcFontSize}
/>
<TextInput
accessibilityLabel="login_username_input"
accessible
ref={usernameRef}
bodyColor={authBg}
inputWrapStyle={[global.formInput, { backgroundColor }]}
style={[
global.formInputText,
{ color: textColor, paddingLeft: 0 }
]}
icon={userIcon}
webIcon={"IconUser"}
tintColor={textColor}
onChangeText={username => setUsernameState({ username })}
value={stateUsername}
placeholderTextColor={placeholderColor}
placeholder={t("login:username")}
autoCapitalize={"none"}
returnKeyType="next"
underlineColorAndroid="transparent"
autoCorrect={false}
calcFontSize={calcFontSize}
/>
<TextInput
accessibilityLabel="login_password_input"
accessible
bodyColor={authBg}
inputWrapStyle={global.inputWrap}
inputWrapStyle={[global.formInput, { backgroundColor }]}
style={[
global.formInputText,
{ color: textColor, width: "70%", paddingLeft: 0 }
]}
ref={passwordRef}
icon={passwordIcon}
webIcon={"IconLock"}
eyeTintColor={textColor}
tintColor={textColor}
onChangeText={password => setPasswordState({ password })}
value={statePassword}
placeholderTextColor={placeholderColor}
placeholder={t("login:password")}
secureTextEntry={true}
secureToggle={true}
returnKeyType={"done"}
autoCapitalize={"none"}
underlineColorAndroid="transparent"
autoCorrect={false}
onSubmitEditing={() =>
// done key should execute action
customLoginAction(doLogin)
}
calcFontSize={calcFontSize}
/>
</>
}
export default AuthInputs;
//In custom_code/index.js...
import LoginCustom from "./components/LoginCustom";
export const applyCustomCode = externalCodeSetup => {
externalCodeSetup.authApi.setRenderAuthInputs(props => <LoginCustom {...props} />)
}
export const applyCustomCode = externalCodeSetup => {
externalCodeSetup.authApi.setRenderAuthInputs((props) => {
const {
t,
authBg,
global,
colors,
backgroundColor,
textColor,
userIcon,
setUsernameState,
stateUsername,
placeholderColor,
calcFontSize,
passwordIcon,
setPasswordState,
statePassword,
doLogin,
setInputRef,
auth
} = props;
let passwordRef;
const setPasswordRef = (component) => {
//Set password ref for LoginScreen.js
setInputRef("password", component);
//Set password ref for this component
passwordRef = component;
}
return <>
<TextInput
accessibilityLabel="login_username_input"
accessible
ref={component => setInputRef("username", component)}
bodyColor={authBg}
inputWrapStyle={[global.formInput, { backgroundColor }]}
style={[
global.formInputText,
{ color: textColor, paddingLeft: 0 }
]}
tabIndex={1}
icon={userIcon}
webIcon={"IconUser"}
tintColor={textColor}
onChangeText={username => setUsernameState({ username })}
value={stateUsername}
placeholderTextColor={placeholderColor}
placeholder={t("login:username")}
autoCapitalize={"none"}
returnKeyType="next"
underlineColorAndroid="transparent"
autoCorrect={false}
onSubmitEditing={() => {
// next key should focus on next input by default
passwordRef.focus()
}}
calcFontSize={calcFontSize}
/>
<TextInput
accessibilityLabel="login_password_input"
accessible
bodyColor={authBg}
inputWrapStyle={global.inputWrap}
inputWrapStyle={[global.formInput, { backgroundColor }]}
style={[
global.formInputText,
{ color: textColor, width: "70%", paddingLeft: 0 }
]}
ref={component => setPasswordRef(component) }
tabIndex={2}
icon={passwordIcon}
webIcon={"IconLock"}
eyeTintColor={textColor}
tintColor={textColor}
onChangeText={password => setPasswordState({ password })}
value={statePassword}
placeholderTextColor={placeholderColor}
placeholder={t("login:password")}
secureTextEntry={true}
secureToggle={true}
returnKeyType={"done"}
autoCapitalize={"none"}
underlineColorAndroid="transparent"
autoCorrect={false}
onSubmitEditing={() =>
// done key should execute action
doLogin()
}
calcFontSize={calcFontSize}
/>
</>
})
}
# setSignupButton(SignupButton)
You can use this hook to replace the Signup Button on the Signup screen. You can also use this hook to change the behavior or styling of the signup button on the login screen.
Parameters:
Name | Type | Description |
---|---|---|
SignupButton |
React.ComponentType.<SignupButtonProps> |
Example
...
import { Alert } from "react-native"
import AppButton from "@src/components/AppButton";
export const applyCustomCode = externalCodeSetup => {
externalCodeSetup.authApi.setSignupButton(props => {
const {
disabled,
global,
doSignup,
label,
loading,
spinnerColor,
visibleFields,
profileType,
fieldValues,
formState,
getValues
} = props;
const signupAction = () => {
Alert.alert("OTP", `We will send an OTP to ${getValues.field_1}. Do you want to proceed?`, [
{
text: "Cancel",
onPress: () => console.log("Cancel Pressed"),
style: "cancel"
},
{ text: "OK", onPress: () => console.log("OK Pressed") }
])
}
return <AppButton
disabled={disabled}
style={[{ marginTop: 17 }, global.regButtonContainer]}
// onPress={doSignup}
onPress={signupAction}
label={label}
global={global}
loading={loading}
labelStyle={[
global.buttonLabel,
global.regButtonLabel,
disabled && { opacity: 0.4 }
]}
spinnerColor={spinnerColor}
/>
});
}
# setSignUpInputComponent(SignUpInputComponent)
You can use this hook to replace input components in the sign-up form.
Parameters:
Name | Type | Description |
---|---|---|
SignUpInputComponent |
React.ComponentType.<SignUpInputComponentProps> |
Example
//In custom_code/index.js...
...
import MyTextInput from "./components/MyTextInput";
export const applyCustomCode = (externalCodeSetup: any) => {
externalCodeSetup.authApi.setSignUpInputComponent(props => {
const {DefaultComponent, label} = props;
if (label === "Email") {
return <MyTextInput {...props}/>
}
return DefaultComponent;
});
}
//In custom_code/components/MyTextInput.js...
import React, {useState} from "react";
import {View, TextInput, ActivityIndicator, Text} from "react-native";
import axios from "axios";
const MyTextInput = props => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState(null);
const fetchData = async text => {
const search = text && text.toLowerCase();
try {
setLoading(true);
const response = await axios.get(`https://example.api/${search}`);
setData(response.data);
setLoading(false);
} catch (error) {
console.error(error);
}
};
const handleTextChange = text => {
fetchData(text);
props.setValue(props.field.id, text);
};
return (
<View>
<TextInput
onChangeText={handleTextChange}
placeholder="Type something..."
/>
{loading && <ActivityIndicator />}
{data && (
<Text>
Result: {data.name} | {data.abilities[0].ability.name}
</Text>
)}
</View>
);
};
export default MyTextInput;
# setSignUpInputsFilter(func)
You can use it to set the function that can filter the input fields to modify the signup process based on your app needs.
Parameters:
Name | Type | Description |
---|---|---|
func |
SignupFieldsFilterCallback |
Example
externalCodeSetup.authApi.setSignUpInputsFilter(props => {
props.shift()
return props;
})
# setSignUpInputsValidation(SignUpInputsValidationCallback)
You can use this hook to set the validation rules for the sign-up form. For example, you can exempt a field so that it will not be required when submitting the form.
Parameters:
Name | Type | Description |
---|---|---|
SignUpInputsValidationCallback |
SignUpInputsValidationCallback |
Example
authApi.setSignUpInputsValidation(props => {
const {doValidation, fieldName, field, register, t} = props;
const changeLabel = false;
const exemptField = false;
if (changeLabel) {
return register(fieldName, {
required:
field.required &&
field.required &&
`Custom - ${field.label}` + t("signup:validateFeildModal"),
validate: value => {
const {message} = getFieldError(field, value, t);
return message ?? true;
}
});
}
if (exemptField) {
if (fieldName === "signup_email") {
return;
}
}
return doValidation()
});
# setSignUpLink(SignUpLinkProps)
You can use this hook to replace the sign up link component in the Login Screen.
Parameters:
Name | Type | Description |
---|---|---|
SignUpLinkProps |
React.ComponentType.<SignUpLinkProps> |
Example
import React from "react";
import {View, Text} from "react-native";
import Icon from "@src/components/Icon";
import AppTouchableOpacity from "@src/components/AppTouchableOpacity";
export const applyCustomCode = externalCodeSetup => {
externalCodeSetup.authApi.setSignUpLink(props => {
const {isSignUpEnabled, footerRef, onPress, styles, t, colors} = props;
return (
isSignUpEnabled && (
<AppTouchableOpacity
ref={footerRef}
onPress={onPress}
style={styles.buttonContainer}
hitSlop={{top: 15, right: 15, bottom: 15, left: 15}}
>
<View style={styles.viewContainer}>
<Text style={styles.text}>
<Text>{t("login:haveAccount")}</Text>
<Text> </Text>
<Text style={styles.signUpText}>{t("login:signup")}</Text>
</Text>
<Icon
icon={{fontIconName: "arrow-right", weight: 300}}
webIcon={"IconArrowBack"}
tintColor={colors.authTextColor}
styles={{height: 15}}
/>
</View>
</AppTouchableOpacity>
)
);
});
};
# setUserAgreementTextComponent(UserAgreementTextComponent)
You can use this hook to customize the User Agreement text component located before the "Create Account" button.
Parameters:
Name | Type | Description |
---|---|---|
UserAgreementTextComponent |
React.ComponentType.<UserAgreementTextComponentProps> |
Example
//In custom_code/components/UserAgreementText.js...
import React from "react";
import {Text, View, Alert} from "react-native";
import AppCheckbox from "@src/components/AppCheckbox";
import {Check} from "@src/components/AppCheckbox";
import {getAuthFormTheme, getRegFormTheme} from "@src/components/Forms/utils";
const confirmAgreement = (onAgreementChecked) => {
Alert.alert(
"Confirmation",
"Have you read the Terms of Service?",
[
{
text: "No",
onPress: () => onAgreementChecked(false),
},
{ text: "Yes", onPress: () => onAgreementChecked(true) }
]
);
}
const UserAgreementText = props => {
const {
register,
t,
termsOfService,
privacyPolicy,
withCheckbox,
global,
colors,
onPress,
agreementChecked,
onAgreementChecked,
style = {}
} = props;
if (!termsOfService?.content && !privacyPolicy?.content) return null;
const theme = register ? getRegFormTheme(colors) : getAuthFormTheme(colors);
const {tint, inactiveTint, textColor, labelColor} = theme;
const tColor = withCheckbox ? textColor : labelColor;
const containerStyle = withCheckbox && {
borderRadius: 10,
backgroundColor: theme.backgroundColor,
paddingVertical: 14,
paddingHorizontal: 16,
marginBottom: 15,
...style
};
return (
<View
style={[
global.row,
{alignItems: "center", justifyContent: "center"},
containerStyle
]}
>
<Text
style={[
global.text,
{
textAlign: withCheckbox ? "left" : "center",
marginTop: withCheckbox ? 0 : 16,
paddingRight: 4,
paddingLeft: withCheckbox ? 0 : 4,
color: tColor,
flex: 1
},
withCheckbox && {
marginRight: 5
}
]}
>
{withCheckbox ? t(`signup:agreementStartingTextWithCheckbox`) : null}
{!!termsOfService?.content ? (
<Text
style={[global.boldText, {color: tColor}]}
onPress={() =>
onPress("termsOfService", termsOfService.content.rendered)
}
>
{t("signup:termsOfService")}
</Text>
) : (
""
)}
{!!termsOfService?.content && privacyPolicy?.content
? t("signup:and")
: ""}
{!!privacyPolicy?.content ? (
<Text
style={[global.boldText, {color: tColor}]}
onPress={() =>
onPress("privacyPolicy", privacyPolicy.content.rendered)
}
>
{t("signup:privacyPolicy")}
</Text>
) : (
""
)}
{withCheckbox ? t("signup:agreementEndingText") : null}
</Text>
{withCheckbox && (
<Check
inactiveTint={inactiveTint}
tintColor={tint}
isChecked={agreementChecked}
onPress={() => confirmAgreement(onAgreementChecked)}
// onPress={() => onAgreementChecked(!agreementChecked)}
/>
)}
</View>
);
};
export default UserAgreementText;
//In custom_code/index.js...
import UserAgreementText from "./components/UserAgreementText";
export const applyCustomCode = externalCodeSetup => {
externalCodeSetup.authApi.setUserAgreementTextComponent(props => <UserAgreementText {...props} />);
}