I've been out of work for a while, and a friend who owns a startup company tasked me with fixing the Facebook Login functionality of his app. Big opportunity for me.
None of the devs who built/worked on it are around anymore, and the app's code is written in such a confusing way. So I'm bringing it here in hopes that I can get help to resolve it.
The Issue
When you open the app there's an intro screen, you close that, and then it prompts you to login with Facebook.
When Login is clicked, it loads for a bit, and then just returns back to the initial intro screen.
The debugger console displays:
[CodePush] Reporting binary update (2.0.0)
[CodePush] Report status failed: {"appVersion":"2.0.0"}
Not really familiar with CodePush, and I've been investigating that on and off, unsure if that's even related to my issue or not. I went through their docs and made sure this project was configured right anyway.
Then I did the same with Facebook SDK. I checked the docs and compared the instructions to what was done in the app, to see if the previous devs configured it properly. Everything looks right.
Docs I'm referring to:
https://developers.facebook.com/docs/facebook-login/android/v2.2
NOTE I can't do steps 5 and beyond, because you need to log in to complete those, and my FB account is not connected to the app. Currently waiting to hear back from someone who worked on this. Likely not relevant anyway, as everything else was done correctly.
I found the code for the Login Button in the codebase, but there's a lot of files importing to each other, and I'm not sure what exactly does what. I will post the bread trail I followed below.
Here I track the Login button to find the source of the implemented feature.
I skip files that are unnecessary, such as the screen that displays the greeting along with the Login button. I followed the import statements until I reached the following:
LoginButtonContainer.js
// #flow
import { connect } from 'react-redux'
import { loginWithFbButtonPressed } from '../redux/actions'
import LoginWithFbButton, {
Props as LoginButtonComponentProps,
} from '../components/LoginWithFbButton' // <<<~~~ This file confused me, so next I checked here
type LoginButtonProps = {
onPress: any => void,
}
const mapDispatchToProps = (dispatch: any) => ({
login: () => dispatch(loginWithFbButtonPressed()),
})
const mergeProps = (
_,
dispatchProps: { login: () => void },
ownProps: LoginButtonProps
): LoginButtonComponentProps => {
const { login } = dispatchProps
const { onPress = () => null } = ownProps
return {
onPress: () => {
onPress()
login()
},
}
}
export default connect(null, mapDispatchToProps, mergeProps)(LoginWithFbButton)
LoginWithFbButton.js
// #flow
import * as React from 'react'
import { View, Text, Dimensions, StyleSheet } from 'react-native'
import Icon from 'react-native-vector-icons/FontAwesome'
import Entypo from 'react-native-vector-icons/Entypo'
import { heavyGray, lightGray, facebookColor } from '../constants/colors'
export type Props = {
onPress: () => void,
advisoryText: string,
}
/**
* #class LoginWithFbButton
* Facebook compliant component to login with FB, do not use any other medium to login with FB as to not break the TOS
*/
class LoginWithFbButton extends React.PureComponent<Props> {
render() {
const {
onPress,
advisoryText = `We don't post anything to Facebook`,
} = this.props
return (
<View style={styles.container}>
<Icon.Button
name="facebook"
backgroundColor={facebookColor}
onPress={onPress}
style={styles.facebookButton}
>
Login with Facebook
</Icon.Button>
<View style={styles.advisoryContainer}>
<Entypo
color={heavyGray}
name="info-with-circle"
style={styles.infoIcon}
/>
<Text style={styles.advisoryText}>{advisoryText}</Text>
</View>
</View>
)
}
}
export default LoginWithFbButton
This led me to search for <LoginWithFBButton> but I do not see that anywhere in the app.
Despite me not finding that tag anywhere, the Login button is displayed on the screen.
Lastly(maybe) there's a file called facebook.js
facebook.js
// #flow
import FBSDK from 'react-native-fbsdk';
const { LoginManager, AccessToken } = FBSDK;
export type OpenFBLoginResult =
| {
fbData: string,
}
| {
error: any,
};
export type FacebookDataState = {
accessToken: string,
applicationID: string,
declinedPermissions: Array<string>,
expirationTime: number,
lastRefreshTime: number,
permissions: Array<string>,
userID: string,
};
const getToken = (): Promise<?string> =>
AccessToken.getCurrentAccessToken().then(t => (t ? t.accessToken : null));
const openFBLogin = (): Promise<OpenFBLoginResult> =>
LoginManager.logInWithReadPermissions([
'public_profile',
'email',
]).then(result => {
if (result.isCancelled) {
return {
error: 'User cancelled Facebook login',
};
}
return AccessToken.getCurrentAccessToken().then(fbData => ({
...result,
fbData,
}));
});
const logOut = (): Promise<void> => LoginManager.logOut();
/**
* Dummies
*/
class GraphRequest {}
const GraphRequestManager = () => ({
addRequest: () => ({
start: () => null,
}),
});
const fetchUserImage = (facebookId: string) => {
return new Promise((resolve, reject) => {
const path = `/${facebookId}/picture`;
// Create a graph request asking for user information with a callback to handle the response.
const infoRequest = new GraphRequest(
path,
null,
(error: ?Object, result: ?Object) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}
);
// Start the graph request.
new GraphRequestManager().addRequest(infoRequest).start();
});
};
export default {
openFBLogin,
getToken,
logOut,
fetchUserImage,
};
// export function* openFBLogin(): OpenFBLoginResult {
// type openFBLoginResultType = { +type: string, +token: string }
// const response: openFBLoginResultType = yield call(Expo.Facebook.logInWithReadPermissionsAsync, FBAPP_ID, {
// permissions: FB_PERMISSIONS
// })
// let error: ?any = null
// switch (response.type) {
// case 'success':
// const { token } = response
// yield call(_setFBToken, token)
// yield put(actions.loginFb.success('', token))
// return { token }
// case 'cancel':
// error = CANCELLED_ERROR
// yield put(actions.loginFb.failure('', error))
// return { error }
// default:
// error = JSON.stringify(response)
// yield put(actions.loginFb.failure('', error))
// return { error }
// }
// }
This is probably not a great post, but a lot rides on this, and I'm hoping something obvious sticks out to someone more experienced than I.
If I've left anything out, I will update this post with whatever I can. Thanks all.
Related
The Need:
I am using RedwoodJS for making a Fullstack app. It provides us with hook useAuth() which gives a state isAuthenticated telling if user is logged in or not.
I want to make some Queries on Web side whenever user Logs in. Not whenever isAuthenticated from useAuth() is changed. (example: on page loads, isAuthenticated is set to false from undefined.. but this doesn't mean user logged out. What if I want to run certain function only on log out?
Tried Solution:
I wrote this custom hook:
export type CurrentUser = ReturnType<typeof useAuth>['currentUser']
interface HookProps {
// similarly for onLogout
onLogin?: (currentUser: CurrentUser) => void
}
export function useAuthenti(props: HookProps): CurrentUser | false {
const { onLogin } = props
const { isAuthenticated, currentUser } = useAuth()
const wasAuthenticated = usePrevious(isAuthenticated);
const [currentUserOrFalse, setCurrentUserOrFalse] = useState<CurrentUser | false>(false)
useEffect(() => {
console.log(`isAuthenticated CHANGED: ${wasAuthenticated} => ${isAuthenticated}`)
if (isAuthenticated) {
setCurrentUserOrFalse(currentUser)
if (wasAuthenticated === undefined) {
console.log(`false login 1`)
} else if (wasAuthenticated === false) {
console.log(`real login [MAKE API CALLS]`)
if (onLogin) {
console.log(`1. [inside] calling onlogin`)
onLogin?.(currentUser)
console.log(`4. [inside] called onLogin`)
}
} else if (wasAuthenticated === true) {
console.log(`false login 2`)
} else {
console.log(`false login 3`)
}
} else {
setCurrentUserOrFalse(false)
if (wasAuthenticated === undefined) {
console.log(`false logout 1`)
} else if (wasAuthenticated === false) {
console.log(`false logout 2`)
} else if (wasAuthenticated === true) {
console.log(`real logout [MAKE API CALLS]`)
} else {
console.log(`false logout 3`)
}
}
}, [isAuthenticated])
return currentUserOrFalse
}
and I am using this hook as follows:
export function Initialize({ children }: ComponentProps) {
const [getMyData, { loading: loading_MyData, data: data_MyData }] = useLazyQuery(MY_DATA_QUERY)
const [getAllPosts, { loading: loading_AllPosts, data: data_AllPosts }] = useLazyQuery(ALL_POSTS_QUERY)
useAuthenti({
onLogin: (currentUser: CurrentUser) => {
console.log(`2. [outside] onLogin start`)
getMyData()
getAllPosts()
console.log(`3. [outside] onLogin done`)
},
})
useEffect(() => {
if (data_MyData && data_AllPosts) {
console.log(data_MyData)
console.log(data_AllPosts)
}
}, [data_MyData, data_AllPosts])
return (
<>
{children}
</>
)
}
The Problem:
In the above usage, as you can see i am providing onLogin function prop to the useAuthenti custom hook. Because i want that function to run ON LOGIN and make the api calls in it.
However, the code isn't working as expected every time. sometimes it is working, other times it's not. (also weird.. seems like a race condition?)
When it's not working, I don't see any console logs (hinting the onLogin was never called), BUT, in networks tab I DO see calls being made by createHttpLink.js:100. it's failing also. During this case (when it doesn't work as expected), i see user login call succeeding BUT redwood js' getCurrentUser call isn't made. (you can ignore the redwoodjs part if you're unfamiliar with redwood js, just focus on the hook part) How are the apis that are inside onLogin running without any console logs surrounding it?
Networks Tab Debug
The red box shows attempt one at login (doesn't work)
The green box shows attempt two at login (works)
Additional Note:
Apparently, only passing the functions as arguments is causing them to run EVEN if I don't run them inside the hook. Why are the functions passed as arguments to hook running on their own?
Is the way I am making a custom React Hook wrong? What am I doing wrong here if anyone could please let me know.
Is there a race condition as sometimes it'w working and sometimes it's not?
How do I proceed?
I don't understand why, but writing a custom hook to replace useLazyQuery that returns a Promise fixed all the problems.
This Github thread helped: https://github.com/apollographql/react-apollo/issues/3499
Particularly this answer: https://github.com/apollographql/react-apollo/issues/3499#issuecomment-539346982
To which I extended to support Typescript and States like loading error and data. (his version is useLazyQuery, extended hook is useLazyQueryModded)
useLazyQueryModded.tsx
import { useState } from 'react';
import { DocumentNode, ApolloError, useApolloClient, OperationVariables } from '#apollo/client';
type QueryVariables = Record<string, any>;
type UseLazyQueryResult<TData, TVariables extends QueryVariables> = [
(variables?: TVariables) => void,
{ data: TData | undefined, error: ApolloError | undefined, loading: boolean }
];
function useLazyQuery<TData = any, TVariables = OperationVariables>(query: DocumentNode) {
const client = useApolloClient()
return React.useCallback(
(variables: TVariables) =>
client.query<TData, TVariables>({
query: query,
variables: variables,
fetchPolicy: 'cache-first'
}),
[client]
)
}
function useLazyQueryModded<TData = any, TVariables extends QueryVariables = QueryVariables>(
query: DocumentNode
): UseLazyQueryResult<TData, TVariables> {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<TData | undefined>(undefined);
const [error, setError] = useState<ApolloError | undefined>(undefined);
const runQuery = useLazyQuery<TData, TVariables>(query);
const executeQuery = async (variables?: TVariables) => {
setLoading(true);
setData(undefined);
setError(undefined);
try {
const result = await runQuery(variables);
setData(result.data);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
const result = { data, error, loading };
return [executeQuery, result];
}
export { useLazyQueryModded };
If anyone can explain why useLazyQuery wasn't returning a Promise or why even when it didn't code worked sometime, I'd be relieved of this itch.
My app has a test sheet, if a user passes the test he is shown a passing screen and then the state is saved using asyncstorage. But the problem here is, let's say i have user A and user B and user A is currently logged in, he passed the test and the app shows him passing screen and the state is saved. Now user A logs out and user B logs in, he is a completely new user he has never given test before but my app has still saved the state for the user A and keeps showing passing screen even to the user B rather it should not.Can someone help me with this issue?
code:
import React ,{useState, useEffect} from "react";
import {View, Alert, Image, StyleSheet, Text, Modal, TouchableOpacity, TouchableHighlight} from 'react-native';
import Voice from 'react-native-voice';
import auth from '#react-native-firebase/auth';
import AsyncStorage from '#react-native-async-storage/async-storage';
const key = auth().currentUser.uid + "hasPassed"
export const hasPassed = async () => {
return AsyncStorage.getItem(key).then(result => result != null ? JSON.parse(result) : undefined).catch(e => console.log(e))
}
export const setHasPassed = async (newPassed) => {
return AsyncStorage.setItem(key, JSON.stringify({hasPassed: newPassed})).catch(e => console.log(e))
}
export default alpht =({navigation}) => {
function Check() {
if (results.includes(words[index])){
Alert.alert('Correct!','You are learning so well!');
if(index==7) {
if(count<=5)
{
setHasPassed(true).then(() => setshowpass(true))
// setshowpass(true);
}
else{
console.log(count)
Alert.alert('fail','fail');
}
}
if (index==7){
setndis(true);
setdis(true);
setidis(true);
}
else{
setndis(false);
setdis(true);
setidis(true);
}
}
else{
Alert.alert('Ops!','Looks like you went wrong somewhere. Try again!');
setcount(count+1);
setdis(true);
setndis(true);
if(count==5){
Alert.alert('Restest', 'Looks like you had way too many mistakes!')
setind(0);
setcount(0);
setdis(true);
}
}
}
const words=['ceket', 'çilek', 'elma', 'fare', 'öğretmen', 'otobüs', 'şemsiye', 'uçak'];
const [show, setshow]=useState('');
const [showpass, setshowpass]=useState(false);
useEffect(() => {
//console.log(auth().currentUser.uid);
setshow(true);
}, []);
useEffect(() => {
const getState = async () => {
const result = await hasPassed()
setshowpass(result ? result.hasPassed : false)
}
getState()
}, []);
console.log(auth().currentUser.uid)
if (showpass === false) {
// setshow(true)
console.log('hey');
return null
}
return (
//... other code
)
}
my user logs out using auth().signOut() by the way!
It would be great if this issue gets solved i am dealing with it for the past 4,5 days now!
I think this is the problem:
const key = auth().currentUser.uid + "hasPassed"
export const hasPassed = async () => {
return AsyncStorage.getItem(key).then(result => result != null ? JSON.parse(result) : undefined).catch(e => console.log(e))
}
export const setHasPassed = async (newPassed) => {
return AsyncStorage.setItem(key, JSON.stringify({hasPassed: newPassed})).catch(e => console.log(e))
}
key is defined at the top level, outside of the react lifecycle, and thus is subject to having stale values. auth().currentUser may change, the value of key will not (I think). Instead of storing key as a string, try storing it as a function:
// every time getKey is called it will get a fresh instance of currentUser
const getKey = ()=>auth().currentUser.uid + "hasPassed"
export const hasPassed = async () => {
return AsyncStorage.getItem(getKey()).
then(result => result != null ? JSON.parse(result) : undefined).
catch(e => console.log(e))
}
export const setHasPassed = async (newPassed) => {
return AsyncStorage.setItem(
getKey(),
JSON.stringify({hasPassed: newPassed})
).catch(e => console.log(e))
}
I don't know exactly what's going wrong in your code, but I believe that the piece of code in your useEffect is fetching the state of user A no matter who is logged in ( state persistence). try testing with user C. check out firebase state persistence in their official documentation. I hope I gave you some hints to solve this issue.
I am building a web application in which i need to verify the user's email sent via the client side (React.js and Next.js) and i'm following this youtube tutorial. However, the mentor is using create-react-app CLI and React-Router-Dom for the routing system which doesn't really go with my current needs.
Moreover, I found this method online using HOC :
import React from 'react';
import Router from 'next/router';
const login = '/register?redirected=true'; // Define your login route address.
const checkUserAuthentication = () => {
return { auth: null }; // change null to { isAdmin: true } for test it.
};
export default WrappedComponent => {
const hocComponent = ({ ...props }) => <WrappedComponent {...props} />;
hocComponent.getInitialProps = async (context) => {
const userAuth = await checkUserAuthentication();
// Are you an authorized user or not?
if (!userAuth?.auth) {
// Handle server-side and client-side rendering.
if (context.res) {
context.res?.writeHead(302, {
Location: login,
});
context.res?.end();
} else {
Router.replace(login);
}
} else if (WrappedComponent.getInitialProps) {
const wrappedProps = await WrappedComponent.getInitialProps({...context, auth: userAuth});
return { ...wrappedProps, userAuth };
}
return { userAuth };
};
return hocComponent;
};
The code above helps me to have a private route that the user cannot access unless he's authenticated (currently no programming included), but on the other hand i still need a page in the following route :
'pages/user/activate/[token].js' // the link sent via email from express back end.
What i need now is to create this page using Next routing system in order to get the token and decode it to move forward with the back end and save the user into MongoDB, and in order to accomplish that, i have created my [token].js page with the following code :
import React, {useState, useEffect} from 'react'
import { ToastContainer, toast } from 'react-toastify';
import axios from 'axios';
import jwt from 'jsonwebtoken';
import { authenticate, isAuth } from '../helpers/auth';
import { Link, Redirect } from 'react-router-dom';
const Activate = ({ match }) => {
const [formData, setFormData] = useState({
email: '',
token: '',
show: true
});
const { email, token, show } = formData;
useEffect(() => {
let token = match.params.token;
let { email } = jwt.decode(token);
if (token) {
setFormData({ ...formData, email, token });
}
console.log(token, email);
}, [match.params.token]);
return (
<>
{isAuth() ? <Redirect to="/" /> : null}
<p>Account activated, please log in</p>
</>
)
};
export default Activate;
However, i keep getting this error :
TypeError: Cannot read property 'params' of undefined
at Activate (C:\Users\Hp\Desktop\SMP\client\.next\server\pages\user\activate\[token].js:245:13)
at processChild (C:\Users\Hp\Desktop\SMP\client\node_modules\react-dom\cjs\react-dom-
server.node.development.js:3353:14)
at resolve (C:\Users\Hp\Desktop\SMP\client\node_modules\react-dom\cjs\react-dom-
server.node.development.js:3270:5)
at ReactDOMServerRenderer.render (C:\Users\Hp\Desktop\SMP\client\node_modules\react-dom\cjs\react-
dom-server.node.development.js:3753:22)
at ReactDOMServerRenderer.read (C:\Users\Hp\Desktop\SMP\client\node_modules\react-dom\cjs\react-dom-
server.node.development.js:3690:29)
at renderToString (C:\Users\Hp\Desktop\SMP\client\node_modules\react-dom\cjs\react-dom-
server.node.development.js:4298:27)
at Object.renderPage (C:\Users\Hp\Desktop\SMP\client\node_modules\next\dist\next-
server\server\render.js:53:851)
at Function.getInitialProps (C:\Users\Hp\Desktop\SMP\client\.next\server\pages\_document.js:293:19)
at loadGetInitialProps (C:\Users\Hp\Desktop\SMP\client\node_modules\next\dist\next-
server\lib\utils.js:5:101)
at renderToHTML (C:\Users\Hp\Desktop\SMP\client\node_modules\next\dist\next-
server\server\render.js:53:1142)
I couldn't find a solution because i believe that i'm doing something wrong whether in my code or in the logic implemented.
Is there any way that i can do this properly ?
Thank you in advance !
I am trying to link a React Native <RefreshControl> component to my app in such a way that it triggers a new dispatch to my redux store. However upon scrolling down to trigger the refresh the loading wheel briefly spins before returning the following error: TypeError: undefined is not a function (near '...cards.map...')
My component code and redux functions are below:
Component Code
import React, {Component} from 'react';
import {Text, View, ScrollView, RefreshControl} from 'react-native';
import {connect} from 'react-redux';
import {fetchBalanceActionCreator, fetchPriceActionCreator} from './actions';
import ItemCard from './ItemCard';
class StoreItems extends Component {
render() {
return (
<View style={{flex: 1}}>
<ScrollView
scrollEventThrottle={16}
directionalLockEnabled={true}
refreshControl={
<RefreshControl
refreshing={this.props.refreshing}
onRefresh={() => {
console.log('+++ onRefresh');
this.props.fetchData(this.props.cards);
}}
/>
}
horizontal={false}>
{ITEMS.map(item => {
return (
<ItemCard name={item.name} price={item.price} qty={item.qty} />
);
})}
</ScrollView>
</View>
);
}
}
const mapStateToProps = state => {
console.log(
'Data +++ refreshing',
state.itemPrice.isFetching || state.cardBalance.isFetching,
);
return {
refreshing: state.itemPrice.isFetching || state.cardBalance.isFetching,
cards: state.cards,
};
};
const mapDispatchToProps = dispatch => {
return {
fetchData: cards => {
console.log('fetchData1');
dispatch(fetchBalanceActionCreator(cards));
dispatch(fetchPriceActionCreator(cards));
console.log('fetchData2');
},
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(StoreItems);
Redux Functions
function fetchPriceActionCreator(items) {
return function(dispatch) {
dispatch(requestItemPriceActionCreator());
const reqs = items.map(item => {
return getItemPrice(item.itemNumber);
});
return Promise.all(reqs).then(res => {
dispatch(receiveItemPriceActionCreator(res));
});
};
}
function fetchBalanceActionCreator(cards) {
return function(dispatch) {
dispatch(requestBalanceActionCreator());
const reqs = cards.map(card => {
const cardType = card.cardType.toLowerCase();
const cardNumber = card.cardNumber;
return getBalances(cardType, cardNumber);
});
return Promise.all(reqs)
.then(balances => {
dispatch(receiveBalanceActionCreator(balances));
})
.catch(err => {
console.error(err);
});
};
}
EDIT:
The getBalances and getPrices functions are both making API calls.
Most of the data fetched from these calls is displayed in child components/elsewhere in the app, but I want to be able to refresh on this particular screen.
I have added a number of console.logs throughout the code, the results are as follows:
+++ onRefresh displays in the console
fetchData1 follows immediately after
data +++ refreshing is then displayed, I have noticed occasionally
it shows a value of true, and occasionally a value of false
fetchData2 is never logged to the console.
The error screen in the app simulator references the line with dispatch(fetchBalanceActionCreator(cards)); from the StoreItems component, in addition to the return function(dispatch) {line from the Redux action creator file.
EDIT 2
Here is the getBalance function:
async function getBalances(cardType, card) {
cardType = cardType.toLowerCase();
const balance = await balanceRequestor[cardType](card);
return {
cardId: cardType,
card: card,
balance: balance,
};
}
Depending on the card type, getBalance will then trigger a function fetches data from an API and looks like so:
export async function getCard1Balance(card) {
const response = await fetch(`https://api.exampleapi.com/${card}`);
const data = await response.json();
return data;
}
All of these functions work fine upon loading and navigating the app, it only seems to be when using the RefreshControl that the undefined is not a function is shown.
I am wondering how I would refactor the following. Basically, after I get the user information from google, it is validated since a specific domain might be allowed. If it passes that one, we validate the token against a back end api.
Sonar is complaining on the use of return displayAlert('LoginFailed') three times. Given the methods have unique use, I am wondering what could be done to improve it?
import React, {useContext} from 'react';
import {View, Alert} from 'react-native';
import {LocalizationContext} from 'library/localization';
import ServiceAuth from 'services/ServiceAuth';
import {saveLoggedInDetails} from 'library/userInformation';
const MyComponent = (props) => {
const {translations} = useContext(LocalizationContext);
const displayAlert = (msg) =>{
//translations happen here
Alert.alert("Failed", msg)
return false;
}
const validateToken = async (userGoogleInfo) => {
const {idToken} = userGoogleInfo;
let serviceAuth = ServiceAuth.getInstance();
try {
return await serviceAuth.validateT(idToken);
} catch (error) {
//show alert here
return displayAlert('LoginFailed')
}
};
const authorize = async (userGoogleInfo) => {
const allowedDomains = [];
let reply = {ok: false};
//check if domain is allowed etc and set to true.
if (!reply['ok']) {
return displayAlert('InvalidDomain');
}
try {
const userInfo = await validateToken(userGoogleInfo);
if (userInfo) {
console.log("okay")
} else {
return displayAlert('LoginFailed')
}
} catch (error) {
return displayAlert('LoginFailed')
}
};
return (
<>
<View>
<Text>Hello</Text>
</View>
</>
);
};
export default MyComponent;
The message is a little bit confusing but sonar is complaining only about the LoginFailed string used three times as parameter.
Create a constant as, for example:
const LOGIN_FAILED = 'LoginFailed';
And then use it in all the three calls to displayAlert:
return displayAlert(LOGIN_FAILED);