client-reactnative/src/stores/loginStore.ts
import AsyncStorage from '@react-native-async-storage/async-storage';
import {makeAutoObservable, runInAction, action} from 'mobx';
import {LoginManager} from 'react-native-fbsdk-next';
import {deleteAllRealm} from '../components/realmModels/allSchemas';
import {httpPost, httpPut} from '../config/apiService';
import {
loginURL,
refreshTokenURL,
registerUserURL,
} from '../config/routesConstants';
import {asyncStorageSetItem} from '../helpers/cache/asyncStorageSetItem';
import {underscoreManipulation} from '../helpers/underscoreLogic';
import {rootStore, RootStore} from './context';
import {asyncStorageGetItem} from '../helpers/cache/asyncStorageGetItem';
import {regularLoginEmail} from '../../docs/config';
//interfaces and types
export interface InitialDataProps {
firstName: string;
lastName: string;
walletAddress: string;
photo: string;
username: string;
password: string;
desc: string;
xmppPassword: string;
xmppUsername: string;
_id: string;
referrerId: string;
isProfileOpen: boolean;
isAssetsOpen: boolean;
email: string;
cryptoKey?: string;
}
//interfaces and types
export class LoginStore {
isFetching: boolean = false;
loading: boolean = false;
error: boolean = false;
errorMessage: string = '';
initialData: InitialDataProps = {
firstName: '',
lastName: '',
walletAddress: '',
photo: '',
username: '',
password: '',
desc: '',
xmppPassword: '',
xmppUsername: '',
_id: '',
referrerId: '',
isProfileOpen: false,
isAssetsOpen: false,
email: '',
cryptoKey: '',
};
userDescription: string = '';
userAvatar: string = '';
anotherUserAvatar: string = '';
anotherUserDescription: string = '';
anotherUserFirstname: string = 'Loading';
anotherUserLastname: string = '...';
anotherUserLastSeen: any = {};
anotherUserWalletAddress: any = {};
isPreviousUser: boolean = false;
pushSubscriptionData: any = {
ok: false,
subscription_info: {
appId: '',
country: '',
createdAt: null,
deviceId: '',
deviceType: null,
environment: 'Development',
expiresAt: null,
externalId: '',
id: null,
isSubscribed: '0',
jid: null,
language: 'en',
lat: '',
long: '',
screenName: null,
timezone: 0,
updatedAt: 0,
},
};
skipForever: boolean = false;
stores: RootStore;
userToken: string = '';
refreshToken: string = '';
walletAddress: string = '';
xmppUsername: string = '';
constructor(stores: RootStore) {
makeAutoObservable(this);
this.stores = stores;
}
//initial state
setInitialState = () => {
runInAction(() => {
this.isFetching = false;
this.loading = false;
this.error = false;
this.errorMessage = '';
this.initialData = {
firstName: '',
lastName: '',
walletAddress: '',
photo: '',
username: '',
password: '',
desc: '',
xmppPassword: '',
xmppUsername: '',
email: '',
cryptoKey: '',
_id: '',
referrerId: '',
isProfileOpen: true,
isAssetsOpen: true,
};
this.userDescription = '';
this.userAvatar = '';
this.anotherUserAvatar = '';
this.anotherUserDescription = '';
this.anotherUserFirstname = 'Loading';
this.anotherUserLastname = '...';
this.anotherUserLastSeen = {};
this.anotherUserWalletAddress = {};
this.isPreviousUser = false;
this.pushSubscriptionData = {
ok: false,
subscription_info: {
appId: '',
country: '',
createdAt: null,
deviceId: '',
deviceType: null,
environment: 'Development',
expiresAt: null,
externalId: '',
id: null,
isSubscribed: '0',
jid: null,
language: 'en',
lat: '',
long: '',
screenName: null,
timezone: 0,
updatedAt: 0,
},
};
this.skipForever = false;
this.userToken = '';
this.refreshToken = '';
this.walletAddress = '';
this.xmppUsername = '';
});
};
//actions
//update user avatar and description
updateUserPhotoAndDescription(avatar: string, description: string) {
runInAction(() => {
this.userAvatar = avatar;
this.userDescription = description;
});
}
//update user name
updateUserName(name: string) {
runInAction(() => {
this.initialData.firstName = name.split(' ')[0];
this.initialData.lastName = name.split(' ')[1];
});
}
//set vcard details for another user.
setOtherUserVcard(data: any) {
runInAction(() => {
this.anotherUserAvatar = data.anotherUserAvatar;
this.anotherUserDescription = data.anotherUserDescription;
});
}
//set other user basic details
setOtherUserDetails(data: {
anotherUserFirstname: string;
anotherUserLastname: string;
anotherUserLastSeen?: any;
anotherUserWalletAddress?: string;
anotherUserAvatar?: string;
}) {
runInAction(() => {
this.anotherUserFirstname = data.anotherUserFirstname;
this.anotherUserLastname = data.anotherUserLastname;
this.anotherUserLastSeen = data.anotherUserLastSeen;
this.anotherUserWalletAddress = data.anotherUserWalletAddress;
this.anotherUserAvatar = data.anotherUserAvatar || '';
});
}
//function to initial log out process
async logOut() {
runInAction(() => {
this.isFetching = true;
});
try {
//logout of any of the social login
LoginManager.logOut();
try {
//clear all async store data
await AsyncStorage.clear();
} catch (e) {
// console.log(e)
}
//delete realm data
deleteAllRealm();
//reset mobx store
rootStore.resetStore();
} catch (error: any) {
runInAction(() => {
this.isFetching = false;
this.error = true;
this.errorMessage = error;
});
}
}
//handle to get refresh token to renew user session
getRefreshToken = async () => {
try {
const response = await httpPost(
refreshTokenURL,
{},
this.refreshToken,
);
runInAction(() => {
this.userToken = response.data.token;
this.refreshToken = response.data.refreshToken;
});
await asyncStorageSetItem('userToken', response.data.token);
await asyncStorageSetItem('refreshToken', response.data.refreshToken);
} catch (error) {
console.log(error);
}
};
//function to login using email and password
regularLogin = async ({username, password}:{username:string, password:string}) => {
const body = regularLoginEmail
? {email: username, password}
: {username, password};
const response = await httpPost(
loginURL,
body,
this.stores.apiStore.defaultToken,
);
if (response.data.success) {
this.loginHandler(response, '');
}
};
//login user handler
loginUser = async (
loginType: any,
authToken: any,
password: any,
ssoUserData: {photo: any},
) => {
const token = this.stores.apiStore.defaultToken;
let bodyData = {
loginType: loginType,
authToken: authToken,
};
runInAction(() => {
this.isFetching = true;
});
const url = loginURL;
try {
const response: any = await httpPost(url, bodyData, token);
if (response.data.success) {
this.loginHandler(response, ssoUserData.photo);
} else {
this.error = true;
this.errorMessage = response.data.msg;
}
} catch (error: any) {
this.error = true;
this.errorMessage = error.response;
}
};
loginHandler = async (response: any, photo: string) => {
await asyncStorageSetItem('userToken', response.data.token);
await asyncStorageSetItem('refreshToken', response.data.refreshToken);
runInAction(() => {
this.loading = false;
this.userToken = response.data.token;
this.refreshToken = response.data.refreshToken;
});
let {
firstName,
lastName,
username,
password,
xmppPassword,
_id,
isProfileOpen,
isAssetsOpen,
email,
cryptoKey,
} = response.data.user;
if (!lastName) {
lastName = firstName.split(' ')[1];
firstName = firstName.split(' ')[0];
}
const {walletAddress} = response.data.user.defaultWallet;
const xmppUsername = underscoreManipulation(walletAddress);
// save user login details received after login
const dataForStorage = {
firstName,
lastName,
walletAddress,
photo: photo,
username,
password,
xmppPassword,
xmppUsername,
_id,
referrerId: response.data.referrerId || '',
isProfileOpen: isProfileOpen,
isAssetsOpen: isAssetsOpen,
desc: '',
email,
cryptoKey,
};
await asyncStorageSetItem('initialLoginData', dataForStorage);
runInAction(() => {
this.initialData = dataForStorage;
this.isFetching = false;
});
};
//update details of current user
updateCurrentUser = async (user: any) => {
let {
firstName,
lastName,
username,
password,
xmppPassword,
_id,
isProfileOpen,
isAssetsOpen,
} = user;
const {walletAddress} = user.defaultWallet;
const xmppUsername = underscoreManipulation(walletAddress);
// save user login details received after login
const dataForStorage = {
...this.initialData,
firstName,
lastName,
walletAddress,
username,
password,
xmppPassword,
xmppUsername,
_id,
isProfileOpen: isProfileOpen,
isAssetsOpen: isAssetsOpen,
};
await asyncStorageSetItem('initialLoginData', dataForStorage);
runInAction(() => {
this.initialData = dataForStorage;
this.isFetching = false;
});
};
//handler to login using external wallets
loginExternalWallet = async (body: {
walletAddress: string;
signature: string;
msg: string;
loginType: string;
}) => {
const url = loginURL;
try {
const response = await httpPost(
url,
body,
this.stores.apiStore.defaultToken,
);
await this.loginHandler(response, '');
} catch (error) {
console.log(error);
}
};
//set initial data received from login response
updateInitialData = async (data: InitialDataProps) => {
try {
await asyncStorageSetItem('initialLoginData', data);
runInAction(() => {
this.initialData = data;
this.isFetching = false;
});
} catch (error) {
console.log(error);
}
};
//extract token from async store when app launches everytime
setTokenFromAsyncStorage = async () => {
runInAction(() => {
this.loading = true;
});
const userToken = await asyncStorageGetItem('userToken');
const refreshToken = await asyncStorageGetItem('refreshToken');
runInAction(() => {
this.userToken = userToken;
this.refreshToken = refreshToken;
this.loading = false;
});
};
//extract initial details from login
setInitialDetailsFromAsyncStorage = async () => {
this.isFetching = true;
await AsyncStorage.getItem('initialLoginData').then(
action((data: any) => {
if (data) {
this.initialData = JSON.parse(data);
}
this.isFetching = false;
}),
);
};
//handle to register a new user
registerUser = async (body: any, ssoUserData: any) => {
const token = this.stores.apiStore.defaultToken;
try {
const url = registerUserURL;
const response: any = await httpPost(url, body, token);
if (response.data.success) {
this.loginUser(
body.loginType,
body.authToken,
body.password,
ssoUserData,
);
} else {
runInAction(() => {
this.isFetching = false;
this.error = true;
this.errorMessage = response.data;
});
}
} catch (error: any) {
runInAction(() => {
this.isFetching = false;
this.error = true;
this.errorMessage = error;
});
}
};
//handle to register a new user using external wallet
registerExternalWalletUser = async (body: {
walletAddress: string;
firstName: string;
lastName: string;
loginType: string;
msg: string;
signature: string;
}) => {
const token = this.stores.apiStore.defaultToken;
try {
const url = registerUserURL;
const response: any = await httpPost(url, body, token);
if (response.data.success) {
this.loginHandler(response, '');
}
} catch (error: any) {
runInAction(() => {
this.isFetching = false;
this.error = true;
this.errorMessage = error;
});
}
};
//this will first hit dapp api to update user's display name
//will call updateInitialData which will store the updated data in async store and then in mobx store.
updateUserDisplayName = async (bodyData: {
firstName: string;
lastName: string;
}) => {
const fd = new FormData();
fd.append('firstName', bodyData.firstName);
fd.append('lastName', bodyData.lastName);
const url = registerUserURL;
const response: any = await httpPut(url, fd, this.userToken);
if (response.data.success) {
const updatedData = {
...this.initialData,
firstName: bodyData.firstName,
lastName: bodyData.lastName,
};
this.updateInitialData(updatedData);
}
};
}