diff --git a/MaharaMobile/App.tsx b/MaharaMobile/App.tsx
index ce5e8d0355825e5b5a040b83ce2098d515096a62..c9f37dd90978dda590b8f288eca58aaf10eef119 100644
--- a/MaharaMobile/App.tsx
+++ b/MaharaMobile/App.tsx
@@ -1,27 +1,9 @@
 import React from 'react';
-import { Platform } from 'react-native';
 import { Provider } from 'react-redux';
-import { createAppContainer, createSwitchNavigator } from 'react-navigation';
-import { createStackNavigator } from 'react-navigation-stack';
-import { createBottomTabNavigator } from 'react-navigation-tabs';
-import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
-import {
-  faUser,
-  faPlusCircle,
-  faHistory
-} from '@fortawesome/free-solid-svg-icons';
-import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs';
 import { I18nProvider } from '@lingui/react';
 
-import styles from './assets/styles/variables';
 import configureStore from './store/store';
-import SiteCheckScreen from './screens/SiteCheckScreen/SiteCheckScreen';
-import LoginScreen from './screens/LoginScreen/LoginScreen';
-import ProfileScreen from './screens/ProfileScreen/ProfileScreen';
-import PendingScreen from './screens/PendingScreen/PendingScreen';
-import AddScreen from './screens/AddScreen/AddScreen';
-import AddFileScreen from './screens/AddFileScreen/AddFileScreen';
-import DetailsScreen from './screens/DetailsScreen/DetailsScreen';
+import AppNavigator from './navigations/app-navigator';
 
 const App = () => {
   const store = configureStore();
@@ -30,91 +12,10 @@ const App = () => {
   return (
     <Provider store={store}>
       <I18nProvider language="en">
-        <NavigationContainer />
+        <AppNavigator />
       </I18nProvider>
     </Provider>
   );
 };
 
-const NavigationContainer = () => {
-  const AddItemsNavigator = createStackNavigator({
-    Add: AddScreen,
-    AddFile: AddFileScreen,
-  });
-
-  const PendingItemsNavigator = createStackNavigator({
-    Pending: PendingScreen,
-    Details: {
-      screen: DetailsScreen,
-      navigationOptions: {
-        headerTitle: 'Back to Pending Items'
-      }
-    }
-  });
-
-  const tabScreenConfig = {
-    Profile: {
-      screen: ProfileScreen,
-      navigationOptions: {
-        tabBarIcon: () => (
-          <FontAwesomeIcon icon={faUser} color={styles.colors.light} />
-        ),
-        tabBarAccessibilityLabel: 'Profile page'
-      }
-    },
-    Add: {
-      screen: AddItemsNavigator,
-      navigationOptions: {
-        tabBarLabel: 'Add',
-        tabBarIcon: () => (
-          <FontAwesomeIcon icon={faPlusCircle} color={styles.colors.light} />
-        ),
-        tabBarAccessibilityLabel: 'Add item to Mahara'
-      }
-    },
-    PendingScreen: {
-      screen: PendingItemsNavigator,
-      navigationOptions: {
-        tabBarLabel: 'Pending ',
-        tabBarIcon: () => (
-          <FontAwesomeIcon icon={faHistory} color={styles.colors.light} />
-        ),
-        tabBarAccessibilityLabel: 'Pending uploads page'
-      }
-    }
-  };
-
-  // Check the OS system for correct styles
-  const AppTabNavigator = Platform.OS === 'android'
-    ? createMaterialBottomTabNavigator(tabScreenConfig, {
-      activeColor: styles.colors.light,
-      // shifting: true,
-      barStyle: {
-        backgroundColor: styles.colors.secondary,
-      },
-    })
-    : createBottomTabNavigator(tabScreenConfig, {
-      tabBarOptions: {
-        activeBackgroundColor: styles.colors.secondary,
-        activeTintColor: styles.colors.light,
-      },
-    });
-
-  // Navigator with only LoginScreen
-  const AuthNavigator = createStackNavigator({
-    Auth: SiteCheckScreen,
-    Login: LoginScreen
-  });
-
-  // Main navigator, with route to AppNavigator once authenticated
-  const MainNavigator = createSwitchNavigator({
-    Auth: AuthNavigator,
-    App: AppTabNavigator
-  });
-  const Navigation = createAppContainer(MainNavigator);
-
-
-  return <Navigation />;
-};
-
 export default App;
diff --git a/MaharaMobile/actions/actions.ts b/MaharaMobile/actions/actions.ts
index 29fa6894bb7ae921a2af545589abd1696f06a1a0..0630bd213c6bf798991ba01543b0fe3eaea136c4 100644
--- a/MaharaMobile/actions/actions.ts
+++ b/MaharaMobile/actions/actions.ts
@@ -1,55 +1,173 @@
-import { MaharaPendingFile, PendingJournalEntry, RequestErrorPayload } from '../models/models';
-import { UPDATE_SERVER_URL, UPDATE_USERNAME, UPDATE_USER_TAGS, UPDATE_USER_BLOGS, UPDATE_USER_FOLDERS, ADD_TOKEN, ADD_UPLOAD_FILE, ADD_UPLOAD_JOURNAL_ENTRY, REMOVE_UPLOAD_FILE, REMOVE_UPLOAD_JOURNAL_ENTRY } from '../utils/constants';
+import AsyncStorage from '@react-native-community/async-storage';
+import { MaharaPendingFile, PendingJournalEntry, RequestErrorPayload, UserBlog, UserFolder } from '../models/models';
+import {
+  UPDATE_USERNAME,
+  UPDATE_USER_TAGS,
+  UPDATE_USER_BLOGS,
+  UPDATE_USER_FOLDERS,
+  ADD_TOKEN,
+  ADD_UPLOAD_FILE,
+  ADD_UPLOAD_JOURNAL_ENTRY,
+  REMOVE_UPLOAD_FILE,
+  REMOVE_UPLOAD_JOURNAL_ENTRY,
+  CLEAR_USER_TAGS,
+  CLEAR_LOGIN_INFO,
+  CLEAR_UPLOAD_FILES,
+  CLEAR_UPLOAD_J_ENTRIES,
+  CLEAR_USER_BLOGS,
+  CLEAR_USER_FOLDERS,
+  UPDATE_J_ENTRIES_ON_LOGIN,
+  UPDATE_UPLOAD_FILES_ON_LOGIN,
+  UPDATE_LOGIN_TYPES,
+  UPDATE_URL,
+  UPDATE_PROFILE_ICON,
+  UPDATE_GUEST_STATUS
+} from '../utils/constants';
 
 // action creators - functions that create actions
 
-export function loginTypes(url: string, response: any) {
-  const tokenLogin = response.logintypes.includes('manual') ? true : false;
-  const localLogin = response.logintypes.includes('basic') ? true : false;
-  const ssoLogin = response.logintypes.includes('sso') ? true : false;
+// userTagsReducer
+export function updateUserTags(tags: any) {
+  AsyncStorage.setItem('userTags', JSON.stringify(tags));
+  return { type: UPDATE_USER_TAGS, userTags: tags };
+}
+
+export function clearUserTags() {
+  return { type: CLEAR_USER_TAGS };
+}
+
+// loginInfoReducer
+export function updateGuestStatus(isGuest: boolean) {
+  return { type: UPDATE_GUEST_STATUS, isGuest };
+}
+
+export function addToken(token: string) {
+  AsyncStorage.setItem('userToken', token);
+  return { type: ADD_TOKEN, token };
+}
+
+export function updateUserName(username: any) {
+  AsyncStorage.setItem('username', username);
+  return { type: UPDATE_USERNAME, userName: username };
+}
+
+export function updateUrl(url: string) {
+  AsyncStorage.setItem('url', url);
   return {
-    type: UPDATE_SERVER_URL,
-    url: url,
-    tokenLogin: tokenLogin,
-    localLogin: localLogin,
-    ssoLogin: ssoLogin
+    type: UPDATE_URL,
+    url: url
+  };
+}
+
+export function updateProfilePic(filepath: string) {
+  AsyncStorage.setItem('profileIcon', filepath);
+  return {
+    type: UPDATE_PROFILE_ICON,
+    profileIcon: filepath
   }
 }
 
-export function addToken(token: string) {
-  return { type: ADD_TOKEN, token }
+/**
+ * Update stored boolean login types
+ *  - response retrieved when users login the first time
+ *  - localL, tokenL, and ssoL are retrieved from AsyncStorage
+ */
+export function updateLoginTypes(
+  response: any,
+  localL = false,
+  tokenL = false,
+  ssoL = false
+) {
+  let tokenLogin;
+  let localLogin;
+  let ssoLogin;
+  if (response) {
+    tokenLogin = response.logintypes.includes('manual');
+    localLogin = response.logintypes.includes('basic');
+    ssoLogin = response.logintypes.includes('sso');
+  } else {
+    tokenLogin = tokenL;
+    localLogin = localL;
+    ssoLogin = ssoL;
+  }
+
+  AsyncStorage.setItem('tokenLogin', JSON.stringify(tokenLogin));
+  AsyncStorage.setItem('localLogin', JSON.stringify(localLogin));
+  AsyncStorage.setItem('ssoLogin', JSON.stringify(ssoLogin));
+
+  return {
+    type: UPDATE_LOGIN_TYPES,
+    tokenLogin,
+    localLogin,
+    ssoLogin
+  }
+}
+
+export function clearLoginInfo() {
+  return { type: CLEAR_LOGIN_INFO };
 }
 
+// uploadFilesReducer
 export function addFileToUploadList(file: MaharaPendingFile) {
   return { type: ADD_UPLOAD_FILE, file }
 }
 
+export function removeUploadFile(id: string) {
+  return { type: REMOVE_UPLOAD_FILE, id }
+}
+
+export function clearUploadFiles() {
+  return { type: CLEAR_UPLOAD_FILES };
+}
+
+export function updateUploadFilesOnLogin(
+  token: string,
+  urlDomain: string,
+  userFolders: Array<UserFolder>,
+) {
+  return { type: UPDATE_UPLOAD_FILES_ON_LOGIN, token, urlDomain, userFolders };
+}
+
+// uploadJEntriesReducer
 export function addJournalEntryToUploadList(journalEntry: PendingJournalEntry) {
-  return { type: ADD_UPLOAD_JOURNAL_ENTRY, journalEntry }
+  return { type: ADD_UPLOAD_JOURNAL_ENTRY, journalEntry };
 }
 
-export function updateUserName(json: any) {
-  return { type: UPDATE_USERNAME, userName: json.userprofile.myname }
+export function removeUploadJEntry(id: string) {
+  return { type: REMOVE_UPLOAD_JOURNAL_ENTRY, id };
 }
 
-export function updateUserTags(json: any) {
-  return { type: UPDATE_USER_TAGS, userTags: json.tags.tags }
+export function clearUploadJEntires() {
+  return { type: CLEAR_UPLOAD_J_ENTRIES };
 }
 
-export function updateUserBlogs(json: any) {
-  return { type: UPDATE_USER_BLOGS, userBlogs: json.blogs.blogs }
+export function updateJEntriesOnLogin(
+  token: string,
+  urlDomain: string,
+  userBlogs: Array<UserBlog>,
+) {
+  return { type: UPDATE_J_ENTRIES_ON_LOGIN, token, urlDomain, userBlogs };
 }
 
-export function updateUserFolders(json: any) {
-  return { type: UPDATE_USER_FOLDERS, userFolders: json.folders.folders }
+// userArtefactsReducer
+export function updateUserBlogs(blogs: any) {
+  AsyncStorage.setItem('userBlogs', JSON.stringify(blogs));
+  return { type: UPDATE_USER_BLOGS, userBlogs: blogs };
 }
 
-export function removeUploadFile(id: string) {
-  return { type: REMOVE_UPLOAD_FILE, id }
+export function updateUserFolders(folders: any) {
+  AsyncStorage.setItem('userFolders', JSON.stringify(folders));
+  return { type: UPDATE_USER_FOLDERS, userFolders: folders };
 }
 
-export function removeUploadJEntry(id: string) {
-  return { type: REMOVE_UPLOAD_JOURNAL_ENTRY, id }
+export function clearUserBlogs() {
+  AsyncStorage.removeItem('userBlogs');
+  return { type: CLEAR_USER_BLOGS };
+}
+
+export function clearUserFolders() {
+  AsyncStorage.removeItem('userFolders');
+  return { type: CLEAR_USER_FOLDERS };
 }
 
 export class RequestError extends Error {
@@ -85,7 +203,7 @@ const postJSON = (url: string, body: any) => {
   return requestJSON(url, {
     method: 'POST',
     body: body,
-  })
+  });
 };
 
 const requestJSON = async (url: any, config: any) => {
@@ -102,7 +220,7 @@ const requestJSON = async (url: any, config: any) => {
   } catch (error) {
     throw RequestError.createFromError(error);
   }
-}
+};
 
 export function checkLoginTypes(url: string) {
   const serverUrl = url + 'module/mobileapi/json/info.php';
@@ -110,22 +228,19 @@ export function checkLoginTypes(url: string) {
   return async function (dispatch: any) {
     try {
       // TODO: dispatch loading state for spinner
-
       const result: any = await getJSON(serverUrl);
-
       // check that there is a mahara version, and therefore a Mahara instance
       if (!result.maharaversion) {
         throw new Error('This is not a Mahara site');
       }
-
       // check that webservices is enabled on the Mahara instance
       if (!result.wsenabled) {
         throw new Error('Webservices is not enabled.');
       }
-
-      dispatch(loginTypes(url, result));
+      dispatch(updateLoginTypes(result));
+      dispatch(updateUrl(url));
     } catch (error) {
       throw error;
     }
   }
-}
\ No newline at end of file
+}
diff --git a/MaharaMobile/assets/styles/headings.ts b/MaharaMobile/assets/styles/headings.ts
index 6018a5703a8c74e7f7db055fb2556bdf3dce29df..70d038f7f6e00b08f01d6f9b0c134a336c8db807 100644
--- a/MaharaMobile/assets/styles/headings.ts
+++ b/MaharaMobile/assets/styles/headings.ts
@@ -1,7 +1,7 @@
 import { StyleSheet } from 'react-native';
 import styles from './variables';
 
-export const headings = StyleSheet.create({
+export const headingStyles = StyleSheet.create({
   mainHeading: {
     fontSize: styles.font.lg,
     color: styles.colors.secondary,
diff --git a/MaharaMobile/components/LoginType/LoginType.tsx b/MaharaMobile/components/LoginType/LoginType.tsx
index 600425ba8690cd057a9bb7786dccfbbac941e09d..582dceb70091ced9d968ddbb74b88dc0aef8a079 100644
--- a/MaharaMobile/components/LoginType/LoginType.tsx
+++ b/MaharaMobile/components/LoginType/LoginType.tsx
@@ -3,9 +3,9 @@ import { Text, View, TouchableOpacity, TextInput } from 'react-native';
 import { Trans, t } from '@lingui/macro';
 import { I18n } from "@lingui/react";
 import styles from './LoginType.style';
-import { headings } from '../../assets/styles/headings';
 import { forms } from '../../assets/styles/forms';
 import { buttons } from '../../assets/styles/buttons';
+import { headingStyles } from '../../assets/styles/headings';
 
 type Props = {
   url: string;
@@ -20,7 +20,8 @@ type Props = {
   serverPing: boolean;
   isInputHidden: boolean;
   enterUrlWarning: boolean;
-  skip: () => void;
+  navigation: any;
+  onSkip: () => void;
 };
 
 export default function LoginType(props: Props) {
@@ -28,16 +29,16 @@ export default function LoginType(props: Props) {
     <View style={styles.view}>
       {!props.isInputHidden ? (
         <View>
-          <Text style={headings.subHeading1}>
+          <Text style={headingStyles.subHeading1}>
             <Trans>What is the address of your Mahara?</Trans>
           </Text>
           <I18n>
             {({i18n}) => <TextInput
-                          style={forms.textInput}
-                          // placeholder={'https://yoursite.edu/'} TODO: put this back in and remove default value for go live
-                          defaultValue={i18n._(t `https://master.dev.mahara.org/`)}
-                          onChangeText={(url:string) => props.checkUrl(url)}
-                        />
+                style={forms.textInput}
+                // placeholder={'https://yoursite.edu/'} TODO: put this back in and remove default value for go live
+                defaultValue={i18n._(t`https://master.dev.mahara.org/`)}
+                onChangeText={(url: string) => props.checkUrl(url)}
+              />
             }
           </I18n>
         </View>
@@ -46,7 +47,7 @@ export default function LoginType(props: Props) {
       {props.errorMessage ? <Text>{props.errorMessage}</Text> : null}
       {props.serverPing && props.isInputHidden ? (
         <View>
-          <Text style={[headings.subHeading2, styles.url]}>{props.url}</Text>
+          <Text style={[headingStyles.subHeading2, styles.url]}>{props.url}</Text>
           <TouchableOpacity onPress={() => props.resetForm()}>
             <Text style={[buttons.md, styles.buttons]}>
               <Trans>Enter a different URL</Trans>
@@ -59,13 +60,13 @@ export default function LoginType(props: Props) {
           <TouchableOpacity onPress={() => props.checkServer()}>
             <Text style={[buttons.md, styles.buttons]}><Trans>Next</Trans></Text>
           </TouchableOpacity>
-          <TouchableOpacity onPress={props.skip}>
+          <TouchableOpacity onPress={() => props.onSkip()}>
             <Text style={[buttons.md, styles.buttons]}><Trans>Skip</Trans></Text>
           </TouchableOpacity>
         </View>
       ) : null}
       {props.serverPing ? (
-        <Text style={headings.mainHeading}><Trans>Select login type</Trans></Text>
+        <Text style={headingStyles.mainHeading}><Trans>Select login type</Trans></Text>
       ) : null}
       {props.serverPing && props.tokenLogin ? (
         <TouchableOpacity onPress={() => props.setLoginType('token')}>
diff --git a/MaharaMobile/components/MediumButton/MediumButton.style.ts b/MaharaMobile/components/MediumButton/MediumButton.style.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dffef8c1936a3390859d069a70bc10c490a47ee3
--- /dev/null
+++ b/MaharaMobile/components/MediumButton/MediumButton.style.ts
@@ -0,0 +1,10 @@
+import { StyleSheet } from 'react-native';
+import styles from '../../assets/styles/variables';
+
+const mdButtonStyles = StyleSheet.create({
+  buttons: {
+    marginBottom: styles.padding.md
+  }
+});
+
+export default mdButtonStyles;
diff --git a/MaharaMobile/components/MediumButton/MediumButton.tsx b/MaharaMobile/components/MediumButton/MediumButton.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..c4bc0db496bbc69fe5ff15ce7b6fbd692717ee96
--- /dev/null
+++ b/MaharaMobile/components/MediumButton/MediumButton.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import { TouchableOpacity } from 'react-native';
+import { Text } from 'react-native';
+import { Trans, I18n } from '@lingui/react';
+import { t } from '@lingui/macro';
+import mdButtonStyles from './MediumButton.style';
+import { buttons } from '../../assets/styles/buttons';
+
+type Props = {
+  onPress: () => void;
+  title: string;
+};
+
+const MediumButton = (props: Props) => (
+  <TouchableOpacity onPress={props.onPress}>
+    <I18n>
+      {({ i18n }) => (
+        <Text style={[buttons.md, mdButtonStyles.buttons]}>
+          {i18n._(t`${props.title}`)}
+        </Text>
+      )}
+    </I18n>
+  </TouchableOpacity>
+);
+
+export default MediumButton;
diff --git a/MaharaMobile/components/Profile/Profile.tsx b/MaharaMobile/components/Profile/Profile.tsx
index f474be37a8970233226ece12126b672a8ae6da21..5270a1e8bc57c8002c14ca9587d4fbee77bf9e9b 100644
--- a/MaharaMobile/components/Profile/Profile.tsx
+++ b/MaharaMobile/components/Profile/Profile.tsx
@@ -1,23 +1,25 @@
-import React, { Component } from 'react';
+import React from 'react';
 import { Text, View, Image } from 'react-native';
 import styles from './Profile.style';
 
 type Props = {
   name: string;
   profileIcon: string;
-}
+};
 
-export default class Profile extends Component<Props> {
-  render() {
-    const image: any = require('../../assets/images/no_userphoto.png');
-
-    return (
-      <View style={styles.view}>
-        <View style={styles.container}>
-          <Image source={this.props.profileIcon ? { uri: this.props.profileIcon } : image} style={styles.image} />
-        </View>
-        <Text style={styles.name}>Hi {this.props.name}</Text>
+const Profile = (props: Props) => {
+  const image: any = require('../../assets/images/no_userphoto.png');
+  return (
+    <View style={styles.view}>
+      <View style={styles.imageContainer}>
+        <Image
+          source={props.profileIcon ? { uri: props.profileIcon } : image}
+          style={styles.image}
+        />
+        <Text style={styles.name}>Hi {props.name ? props.name : 'Guest'}</Text>
       </View>
-    )
-  }
-}
+    </View>
+  );
+};
+
+export default Profile;
diff --git a/MaharaMobile/components/TokenInput/TokenInput.tsx b/MaharaMobile/components/TokenInput/TokenInput.tsx
index 9f0715fa2a1b01c4ea544653fd6c5df228669cc6..224596e83cdcee211d989ea564c41a09fa1544d8 100644
--- a/MaharaMobile/components/TokenInput/TokenInput.tsx
+++ b/MaharaMobile/components/TokenInput/TokenInput.tsx
@@ -1,29 +1,32 @@
+/* eslint-disable prettier/prettier */
 import React from 'react';
-import { Text, TextInput, View, TouchableOpacity } from 'react-native';
+import {
+  Text, TextInput, View, TouchableOpacity
+} from 'react-native';
 
 import styles from './TokenInput.style';
 import { forms } from '../../assets/styles/forms';
+import { headingStyles } from '../../assets/styles/headings';
 import { buttons } from '../../assets/styles/buttons';
-import { headings } from '../../assets/styles/headings';
 
 type Props = {
-  handleToken: Function;
-  setToken: Function;
-}
+  onVerifyToken: Function;
+  onUpdateToken: Function;
+};
 
 export default function TokenInput(props: Props) {
   return (
     <View style={styles.view}>
-      <Text style={headings.mainHeading}>Login via Token</Text>
-      <TextInput
+      <Text style={headingStyles.mainHeading}>Login via Token</Text>
+    <TextInput
         style={forms.textInput}
-        //TODO: remove default value for go live
-        defaultValue='c6f3d4fd4b997c96392deeb127ec983b'
-        onChangeText={(token) => props.setToken(token)}
+        // TODO: remove default value for go live
+        defaultValue="c6f3d4fd4b997c96392deeb127ec983b"
+        onChangeText={(token) => props.onUpdateToken(token)}
       />
-      <TouchableOpacity onPress={() => props.handleToken()}>
+      <TouchableOpacity onPress={() => props.onVerifyToken()}>
         <Text style={buttons.lg}>Verify Token</Text>
       </TouchableOpacity>
     </View>
-  )
+  );
 }
diff --git a/MaharaMobile/components/UploadForm/UploadForm.tsx b/MaharaMobile/components/UploadForm/UploadForm.tsx
index 635de759a094ece3775e800c5212818ab10c3a0c..4356322a783726913d01e2e6cd8999d1241b2d79 100644
--- a/MaharaMobile/components/UploadForm/UploadForm.tsx
+++ b/MaharaMobile/components/UploadForm/UploadForm.tsx
@@ -143,7 +143,7 @@ const UploadForm = (props: Props) => {
     // upon successful upload, remove the AddFile screen from the navigation stack
     props.navigation.dispatch(StackActions.popToTop());
     // then take user to PendingScreen
-    props.navigation.navigate({routeName: 'PendingScreen', params: { fileType: type }});
+    props.navigation.navigate({routeName: 'Pending', params: { fileType: type }});
   };
 
   return (
diff --git a/MaharaMobile/components/UploadItem/UploadItem.style.ts b/MaharaMobile/components/UploadItem/UploadItem.style.ts
index f8a1668963083b34052c67e9712b75656eb772b4..a9a8727715642f907ed55bed889be135ac27ff79 100644
--- a/MaharaMobile/components/UploadItem/UploadItem.style.ts
+++ b/MaharaMobile/components/UploadItem/UploadItem.style.ts
@@ -7,7 +7,7 @@ const uploadItemStyles = StyleSheet.create({
     flexDirection: 'row',
     padding: 3,
     marginVertical: 3,
-    height: 120,
+    height: 110,
   },
   pendingCard: {
     flexDirection: 'row',
diff --git a/MaharaMobile/navigations/app-navigator.tsx b/MaharaMobile/navigations/app-navigator.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..d1b523c15a58f0795c723020ed70007bb4363e1a
--- /dev/null
+++ b/MaharaMobile/navigations/app-navigator.tsx
@@ -0,0 +1,110 @@
+import React from 'react';
+import { createStackNavigator } from 'react-navigation-stack';
+import {
+  faUser,
+  faPlusCircle,
+  faHistory
+} from '@fortawesome/free-solid-svg-icons';
+import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs';
+import { createBottomTabNavigator } from 'react-navigation-tabs';
+import { Platform } from 'react-native';
+import {createSwitchNavigator, createAppContainer } from 'react-navigation';
+import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
+import AddScreen from '../screens/AddScreen/AddScreen';
+import AddFileScreen from '../screens/AddFileScreen/AddFileScreen';
+import PendingScreen from '../screens/PendingScreen/PendingScreen';
+import DetailsScreen from '../screens/DetailsScreen/DetailsScreen';
+import ProfileScreen from '../screens/ProfileScreen/ProfileScreen';
+import styles from '../assets/styles/variables';
+import SiteCheckScreen from '../screens/SiteCheckScreen/SiteCheckScreen';
+import LoginScreen from '../screens/LoginScreen/LoginScreen';
+import AuthLoadingScreen from '../screens/AuthLoadingScreen/AuthLoadingScreen';
+
+const AppNavigator = () => {
+  const AddItemsNavigator = createStackNavigator({
+    AddItems: AddScreen,
+    AddFile: AddFileScreen
+  });
+
+  const PendingItemsNavigator = createStackNavigator({
+    Pending: PendingScreen,
+    Details: {
+      screen: DetailsScreen,
+      navigationOptions: {
+        headerTitle: 'Back to Pending Items'
+      }
+    }
+  });
+
+  const tabScreenConfig = {
+    ProfileTab: {
+      screen: ProfileScreen,
+      navigationOptions: {
+        tabBarLabel: 'Profile',
+        tabBarIcon: () => (
+          <FontAwesomeIcon icon={faUser} color={styles.colors.light} />
+        ),
+        tabBarAccessibilityLabel: 'Profile page'
+      }
+    },
+    AddItemsTab: {
+      screen: AddItemsNavigator,
+      navigationOptions: {
+        tabBarLabel: 'Add',
+        tabBarIcon: () => (
+          <FontAwesomeIcon icon={faPlusCircle} color={styles.colors.light} />
+        ),
+        tabBarAccessibilityLabel: 'Add item to Mahara'
+      }
+    },
+    PendingTab: {
+      screen: PendingItemsNavigator,
+      navigationOptions: {
+        tabBarLabel: 'Pending ',
+        tabBarIcon: () => (
+          <FontAwesomeIcon icon={faHistory} color={styles.colors.light} />
+        ),
+        tabBarAccessibilityLabel: 'Pending uploads page'
+      }
+    }
+  };
+
+  const androidTabConfig = createMaterialBottomTabNavigator(tabScreenConfig, {
+    activeColor: styles.colors.light,
+    barStyle: {
+      backgroundColor: styles.colors.secondary
+    }
+  });
+
+  const iOSTabConfig = createBottomTabNavigator(tabScreenConfig, {
+    tabBarOptions: {
+      activeBackgroundColor: styles.colors.secondary,
+      activeTintColor: styles.colors.light
+    }
+  });
+
+  const AppTabNavigator = Platform.OS === 'android' ? androidTabConfig : iOSTabConfig;
+
+  // Navigator with only LoginScreen
+  const AuthNavigator = createStackNavigator({
+    SiteCheck: SiteCheckScreen,
+    Login: LoginScreen
+  });
+
+  // Main navigator, with route to AppNavigator once authenticated
+  const MainNavigator = createSwitchNavigator(
+    {
+      AuthLoading: AuthLoadingScreen,
+      App: AppTabNavigator,
+      Auth: AuthNavigator
+    },
+    {
+      initialRouteName: 'AuthLoading'
+    }
+  );
+
+  const Navigation = createAppContainer(MainNavigator);
+  return <Navigation />;
+};
+
+export default AppNavigator;
diff --git a/MaharaMobile/reducers/loginInfoReducer.ts b/MaharaMobile/reducers/loginInfoReducer.ts
index c217334a7b60b530a34b625dbf108c0e6a413b39..264aececd967a27bfa9922e0a5cfd8daf2bcc00c 100644
--- a/MaharaMobile/reducers/loginInfoReducer.ts
+++ b/MaharaMobile/reducers/loginInfoReducer.ts
@@ -2,13 +2,20 @@ import {
   UPDATE_SERVER_URL,
   ADD_TOKEN,
   UPDATE_USERNAME,
+  CLEAR_LOGIN_INFO,
+  UPDATE_LOGIN_TYPES,
+  UPDATE_URL,
+  UPDATE_PROFILE_ICON,
+  UPDATE_GUEST_STATUS
 } from '../utils/constants';
-import { RootState } from './reducers';
+import { RootState } from './rootReducer';
 
 type LoginInfoState = {
   url: string;
   token: string;
   userName: string;
+  isGuest: boolean;
+  profileIcon: string;
   // available login methods
   tokenLogin: boolean;
   ssoLogin: boolean;
@@ -22,27 +29,53 @@ const initialState: LoginInfoState = {
   localLogin: false,
   token: '',
   userName: '',
+  isGuest: false,
+  profileIcon: ''
 };
 
-export const loginInfoReducer = (state = initialState, action: any) => {
+export const loginInfoReducer = (
+  state = initialState,
+  action: any
+): LoginInfoState => {
   switch (action.type) {
     case UPDATE_SERVER_URL:
       return {
         ...state,
-        url: action.url,
-        tokenLogin: action.tokenLogin,
-        ssoLogin: action.ssoLogin,
-        localLogin: action.localLogin,
+        url: action.url
       };
     case ADD_TOKEN:
       return {
         ...state,
-        token: action.token,
+        token: action.token
       };
     case UPDATE_USERNAME:
       return {
         ...state,
-        userName: action.userName,
+        userName: action.userName
+      };
+    case CLEAR_LOGIN_INFO:
+      return initialState;
+    case UPDATE_LOGIN_TYPES:
+      return {
+        ...state,
+        localLogin: action.localLogin,
+        ssoLogin: action.ssoLogin,
+        tokenLogin: action.tokenLogin
+      };
+    case UPDATE_URL:
+      return {
+        ...state,
+        url: action.url
+      };
+    case UPDATE_PROFILE_ICON:
+      return {
+        ...state,
+        profileIcon: action.profileIcon
+      };
+    case UPDATE_GUEST_STATUS:
+      return {
+        ...state,
+        isGuest: action.isGuest
       };
     default:
       return state;
@@ -52,8 +85,10 @@ export const loginInfoReducer = (state = initialState, action: any) => {
 // Selector
 export const selectUrl = (state: RootState) => state.domainData.loginInfo.url;
 export const selectTokenLogin = (state: RootState) => state.domainData.loginInfo.tokenLogin;
-export const selectSsoLogin = (state: RootState) => state.domainData.loginInfo.ssoLogin;
-export const selectLocalLogin = (state: RootState) => state.domainData.loginInfo.localLogin;
-export const selectToken = (state: RootState) => state.domainData.loginInfo.token;
-export const selectUserName = (state: RootState) => state.domainData.loginInfo.userName;
-export const selectLoginState = (state: RootState) => (state.domainData.loginInfo.userName !=='' ? true : false);
+export const selectSsoLogin = (state: RootState) =>  state.domainData.loginInfo.ssoLogin;
+export const selectLocalLogin = (state: RootState) =>  state.domainData.loginInfo.localLogin;
+export const selectToken = (state: RootState) =>  state.domainData.loginInfo.token;
+export const selectUserName = (state: RootState) =>  state.domainData.loginInfo.userName;
+export const selectAllLoginInfo = (state: RootState) =>  state.domainData.loginInfo;
+export const selectProfileIcon = (state: RootState) =>  state.domainData.loginInfo.profileIcon;
+export const selectIsGuestStatus = (state: RootState) =>  state.domainData.loginInfo.isGuest;
diff --git a/MaharaMobile/reducers/rootReducer.ts b/MaharaMobile/reducers/rootReducer.ts
index f429d2068dc501616b3b88508d74ad1b076937a5..f2a37e21c1655050e3c4489a6cdd4bce8d88463e 100644
--- a/MaharaMobile/reducers/rootReducer.ts
+++ b/MaharaMobile/reducers/rootReducer.ts
@@ -11,7 +11,7 @@ export const rootReducer = combineReducers({
     loginInfo: loginInfoReducer,
     userTags: userTagsReducer,
     userFolders: userFoldersReducer,
-    userBlogs: userBlogsReducer,
+    userBlogs: userBlogsReducer
   }),
   appState: combineReducers({
     uploadFiles: uploadFilesReducer,
@@ -19,4 +19,4 @@ export const rootReducer = combineReducers({
   })
 });
 
-export type RootState = ReturnType<typeof rootReducer>;
\ No newline at end of file
+export type RootState = ReturnType<typeof rootReducer>;
diff --git a/MaharaMobile/reducers/uploadFilesReducer.ts b/MaharaMobile/reducers/uploadFilesReducer.ts
index 55c3dbdaba00384b9a007cd4a4d1502f4eacfb32..278910bb6e717a6519fe2bcfe6e18bc9f6b8c8da 100644
--- a/MaharaMobile/reducers/uploadFilesReducer.ts
+++ b/MaharaMobile/reducers/uploadFilesReducer.ts
@@ -1,6 +1,13 @@
-import { MaharaPendingFile } from '../models/models';
-import { RootState } from './reducers';
-import { ADD_UPLOAD_FILE, REMOVE_UPLOAD_FILE } from '../utils/constants';
+import AsyncStorage from '@react-native-community/async-storage';
+import {MaharaPendingFile, UserFolder} from '../models/models';
+import { RootState } from './rootReducer';
+import {
+  ADD_UPLOAD_FILE,
+  REMOVE_UPLOAD_FILE,
+  CLEAR_UPLOAD_FILES,
+  UPDATE_UPLOAD_FILES_ON_LOGIN
+} from '../utils/constants';
+import { arrayToObject } from '../utils/authHelperFunctions';
 
 type UploadFilesState = {
   uploadFiles: Record<string, MaharaPendingFile>;
@@ -9,48 +16,88 @@ type UploadFilesState = {
 
 const initialState: UploadFilesState = {
   uploadFiles: {},
-  uploadFilesIds: [],
+  uploadFilesIds: []
 };
 
 // Helper functions
+const getFiles = (ids: string[], arr: any) => ids.map((id: string) => arr[id]);
+
+const updateAsyncStorageUploadFiles = (uploadFiles: MaharaPendingFile[]) => {
+  AsyncStorage.setItem('uploadFiles', JSON.stringify(uploadFiles));
+};
+
 const addFileToUploadList = (
   state: UploadFilesState,
-  file: MaharaPendingFile,
+  file: MaharaPendingFile
 ) => {
-  const updatedUploadFilesIds = new Set([
-    ...state.uploadFilesIds,
-    file.id,
-  ])
-  const updatedUploadFiles = {
+  const updatedFilesIdsSet = new Set([...state.uploadFilesIds, file.id]);
+  const updatedFiles = {
     ...state.uploadFiles,
-    [file.id]: file,
+    [file.id]: file
   };
 
+  const updatedFileIds = Array.from(updatedFilesIdsSet);
+  updateAsyncStorageUploadFiles(getFiles(updatedFileIds, updatedFiles));
   return {
-    uploadFiles: updatedUploadFiles,
-    uploadFilesIds: Array.from(updatedUploadFilesIds)
+    uploadFiles: updatedFiles,
+    uploadFilesIds: updatedFileIds
   };
 };
 
 const removeUploadFile = (
   state: UploadFilesState,
-  id: string,
+  id: string
 ): UploadFilesState => {
   // Filter out given id from state
   const updatedFileIds = state.uploadFilesIds.filter(
-    (uploadFilesId: string) => uploadFilesId !== id,
+    (uploadFilesId: string) => uploadFilesId !== id
   );
 
   // Delete the file matching id
-  const updatedUploadFiles = { ...state.uploadFiles };
-  delete updatedUploadFiles[id];
+  const updatedFiles = { ...state.uploadFiles };
+  delete updatedFiles[id];
 
+  updateAsyncStorageUploadFiles(getFiles(updatedFileIds, updatedFiles));
   return {
-    uploadFiles: updatedUploadFiles,
-    uploadFilesIds: updatedFileIds,
+    uploadFiles: updatedFiles,
+    uploadFilesIds: updatedFileIds
   };
 };
 
+const updateUploadFilesOnLogin = (
+  state: UploadFilesState,
+  token: string,
+  urlDomain: string,
+  userFolders: Array<UserFolder>
+): UploadFilesState => {
+  const uploadJEntries = {
+    ...state.uploadFiles
+  };
+
+  const updatedFiles: Array<MaharaPendingFile> = [];
+  const filesArray = Object.values(uploadJEntries);
+  filesArray.forEach((file: MaharaPendingFile) => {
+    const newFile: MaharaPendingFile = {
+      ...file,
+      maharaFormData: {
+        ...file.maharaFormData,
+        wstoken: token,
+        foldername: userFolders[0].title
+      },
+      url: urlDomain + file.url
+    };
+    updatedFiles.push(newFile);
+  });
+
+  const updatedFilesObj = arrayToObject(updatedFiles);
+  const newState: UploadFilesState = {
+    ...state,
+    uploadFiles: updatedFilesObj
+  };
+  updateAsyncStorageUploadFiles(updatedFiles);
+  return newState;
+};
+
 // REDUCER
 export const uploadFilesReducer = (state = initialState, action: any) => {
   switch (action.type) {
@@ -58,6 +105,15 @@ export const uploadFilesReducer = (state = initialState, action: any) => {
       return addFileToUploadList(state, action.file);
     case REMOVE_UPLOAD_FILE:
       return removeUploadFile(state, action.id);
+    case CLEAR_UPLOAD_FILES:
+      return initialState;
+    case UPDATE_UPLOAD_FILES_ON_LOGIN:
+      return updateUploadFilesOnLogin(
+        state,
+        action.token,
+        action.urlDomain,
+        action.userFolders
+      );
     default:
       return state;
   }
@@ -67,19 +123,21 @@ const uploadFilesState = (state: RootState) => state.appState.uploadFiles;
 
 // Selectors
 export const selectAllUploadFiles = (
-  state: RootState,
+  state: RootState
 ): Array<MaharaPendingFile> => {
   const { uploadFiles } = uploadFilesState(state);
   const { uploadFilesIds } = uploadFilesState(state);
-  const files = uploadFilesIds.map((id: string) => uploadFiles[id]);
-  return files;
+  return getFiles(uploadFilesIds, uploadFiles);
 };
 
 export const selectAllUploadFilesIds = (state: RootState) => [
-  ...state.appState.uploadFiles.uploadFilesIds,
+  ...state.appState.uploadFiles.uploadFilesIds
 ];
 
-export const selectUploadFileById = (state: RootState, { id }: { id: string }): MaharaPendingFile => {
+export const selectUploadFileById = (
+  state: RootState,
+  { id }: {id: string}
+): MaharaPendingFile => {
   const { uploadFiles } = uploadFilesState(state);
   return uploadFiles[id];
 };
diff --git a/MaharaMobile/reducers/uploadJEntriesReducer.ts b/MaharaMobile/reducers/uploadJEntriesReducer.ts
index f23301813f6b3cd5bb99734dc965b2b280de22d6..5178916b4f565ba01bcc0f1ead0daa209c2a3cac 100644
--- a/MaharaMobile/reducers/uploadJEntriesReducer.ts
+++ b/MaharaMobile/reducers/uploadJEntriesReducer.ts
@@ -1,9 +1,13 @@
-import { PendingJournalEntry } from '../models/models';
-import { RootState } from './reducers';
+import { PendingJournalEntry, UserBlog, UserFolder, JournalEntry } from '../models/models';
+import { RootState } from './rootReducer';
 import {
   ADD_UPLOAD_JOURNAL_ENTRY,
   REMOVE_UPLOAD_JOURNAL_ENTRY,
+  CLEAR_UPLOAD_J_ENTRIES,
+  UPDATE_J_ENTRIES_ON_LOGIN
 } from '../utils/constants';
+import { arrayToObject } from '../utils/authHelperFunctions';
+import AsyncStorage from '@react-native-community/async-storage';
 
 type UploadJEntriesState = {
   uploadJEntries: Record<string, PendingJournalEntry>;
@@ -12,30 +16,35 @@ type UploadJEntriesState = {
 
 const initialState: UploadJEntriesState = {
   uploadJEntries: {},
-  uploadJEntriesIds: [],
+  uploadJEntriesIds: []
+};
+
+// Helper functions
+const getJEntries = (ids: string[], arr: any) => ids.map((id: string) => arr[id]);
+
+const updateAsyncStorageJEntries = (jEntries: PendingJournalEntry[]) => {
+  AsyncStorage.setItem('uploadJEntries', JSON.stringify(jEntries));
 };
 
-// HELPER FUNCTIONS
 const addJEntryToUploadList = (
   state: UploadJEntriesState,
-  journalEntry: PendingJournalEntry,
+  journalEntry: PendingJournalEntry
 ) => {
-  const uploadJEntries = {
+  const updatedJEntries = {
     ...state.uploadJEntries,
-    [journalEntry.id]: journalEntry,
+    [journalEntry.id]: journalEntry
   };
-  const uploadJEntriesIdsSet = new Set([
+  const updatedJEntriesIdsSet = new Set([
     ...state.uploadJEntriesIds,
-    journalEntry.id,
+    journalEntry.id
   ]);
 
-  const uploadJEntriesIds = Array.from(uploadJEntriesIdsSet)
-  const newState: UploadJEntriesState = {
-    uploadJEntries,
-    uploadJEntriesIds
+  const updatedJEntriesIds = Array.from(updatedJEntriesIdsSet);
+  updateAsyncStorageJEntries(getJEntries(updatedJEntriesIds, updatedJEntries));
+  return {
+    uploadJEntries: updatedJEntries,
+    uploadJEntriesIds: updatedJEntriesIds
   };
-
-  return newState;
 };
 
 /**
@@ -43,19 +52,55 @@ const addJEntryToUploadList = (
  */
 const removeUploadJEntry = (
   state: UploadJEntriesState,
-  id: string,
+  id: string
 ): UploadJEntriesState => {
   const updatedJEntriesIds = state.uploadJEntriesIds.filter(
-    (uploadJEntriesId: string) => uploadJEntriesId !== id,
+    (uploadJEntriesId: string) => uploadJEntriesId !== id
   );
 
   const updatedJEntries = { ...state.uploadJEntries };
   delete updatedJEntries[id];
 
+  updateAsyncStorageJEntries(getJEntries(updatedJEntriesIds, updatedJEntries));
   return {
     uploadJEntries: updatedJEntries,
-    uploadJEntriesIds: updatedJEntriesIds,
+    uploadJEntriesIds: updatedJEntriesIds
+  };
+};
+
+const updateJEntriesOnLogin = (
+  state: UploadJEntriesState,
+  token: string,
+  urlDomain: string,
+  userBlogs: Array<UserBlog>
+): UploadJEntriesState => {
+  const uploadJEntries = {
+    ...state.uploadJEntries
   };
+
+  const newJournalEntries: Array<PendingJournalEntry> = [];
+  const journalEntriesArr = Object.values(uploadJEntries);
+  journalEntriesArr.forEach((pendingJEntry: PendingJournalEntry) => {
+    const newPendingJEntry: PendingJournalEntry = {
+      id: pendingJEntry.id,
+      journalEntry: {
+        ...pendingJEntry.journalEntry,
+        blogid: userBlogs[1].id,
+        wstoken: token
+      },
+      url: urlDomain + pendingJEntry.url
+    };
+    newJournalEntries.push(newPendingJEntry);
+  });
+
+  const updatedJEntries = arrayToObject(newJournalEntries);
+
+  const newState: UploadJEntriesState = {
+    ...state,
+    uploadJEntries: updatedJEntries
+  };
+  updateAsyncStorageJEntries(newJournalEntries);
+  return newState;
 };
 
 // REDUCER
@@ -65,6 +110,10 @@ export const uploadJEntriesReducer = (state = initialState, action: any) => {
       return addJEntryToUploadList(state, action.journalEntry);
     case REMOVE_UPLOAD_JOURNAL_ENTRY:
       return removeUploadJEntry(state, action.id);
+    case CLEAR_UPLOAD_J_ENTRIES:
+      return initialState;
+    case UPDATE_J_ENTRIES_ON_LOGIN:
+      return updateJEntriesOnLogin(state, action.token, action.urlDomain, action.userBlogs);
     default:
       return state;
   }
@@ -74,7 +123,7 @@ export const uploadJEntriesReducer = (state = initialState, action: any) => {
 const uploadJEntriesState = (state: RootState) => state.appState.uploadJEntries;
 
 export const selectAllJEntries = (
-  state: RootState,
+  state: RootState
 ): Array<PendingJournalEntry> => {
   const { uploadJEntries } = uploadJEntriesState(state);
   const { uploadJEntriesIds } = uploadJEntriesState(state);
@@ -83,12 +132,12 @@ export const selectAllJEntries = (
 };
 
 export const selectAllJEntriesIds = (state: RootState) => [
-  ...state.appState.uploadJEntries.uploadJEntriesIds,
+  ...state.appState.uploadJEntries.uploadJEntriesIds
 ];
 
 export const selectJEntryById = (
   state: RootState,
-  { id }: { id: string },
+  { id }: { id: string }
 ): PendingJournalEntry => {
   const { uploadJEntries } = uploadJEntriesState(state);
   return uploadJEntries[id];
diff --git a/MaharaMobile/reducers/userArtefactsReducer.ts b/MaharaMobile/reducers/userArtefactsReducer.ts
index a10b966154c728a2c6c51183e976d2107e154065..7950d5a871c8279545a1bc0a38a29e76d6c4e262 100644
--- a/MaharaMobile/reducers/userArtefactsReducer.ts
+++ b/MaharaMobile/reducers/userArtefactsReducer.ts
@@ -1,10 +1,15 @@
 import { UserFolder, UserBlog } from '../models/models';
-import { RootState } from './reducers';
-import { UPDATE_USER_FOLDERS, UPDATE_USER_BLOGS } from '../utils/constants';
+import { RootState } from './rootReducer';
+import {
+  UPDATE_USER_FOLDERS,
+  UPDATE_USER_BLOGS,
+  CLEAR_USER_BLOGS,
+  CLEAR_USER_FOLDERS,
+} from '../utils/constants';
 
 // UserFolders
 type UserFoldersState = Array<UserFolder>;
-const initialUserFoldersState: UserFoldersState = [];
+const initialUserFoldersState: UserFoldersState = [{title: 'images'}];
 
 export const userFoldersReducer = (
   state = initialUserFoldersState,
@@ -12,15 +17,17 @@ export const userFoldersReducer = (
 ) => {
   switch (action.type) {
     case UPDATE_USER_FOLDERS:
+      if (action.userFolders.includes('images') && action.userFolders.length === 1) return state;
       return [...state, ...action.userFolders];
+    case CLEAR_USER_FOLDERS:
+      return initialUserFoldersState;
     default:
       return state;
   }
 };
 
 // UserFolders Selectors
-export const selectUserFolders = (state: RootState) =>
-  state.domainData.userFolders;
+export const selectUserFolders = (state: RootState) => state.domainData.userFolders;
 
 // UserBlogs
 type UserBlogsState = Array<UserBlog>;
@@ -33,6 +40,8 @@ export const userBlogsReducer = (
   switch (action.type) {
     case UPDATE_USER_BLOGS:
       return [...state, ...action.userBlogs];
+    case CLEAR_USER_BLOGS:
+      return initialUserBlogsState;
     default:
       return state;
   }
diff --git a/MaharaMobile/reducers/userTagsReducer.ts b/MaharaMobile/reducers/userTagsReducer.ts
index a8bc6ff140c1cccc739b9ec9b7c5c18a7d9da8fe..60d1730d97f5486dd3769659df71b5e8595a712f 100644
--- a/MaharaMobile/reducers/userTagsReducer.ts
+++ b/MaharaMobile/reducers/userTagsReducer.ts
@@ -1,33 +1,37 @@
 import { UserTag } from '../models/models';
-import { RootState } from './reducers';
-import { UPDATE_USER_TAGS, ADD_TAG, REMOVE_TAG } from '../utils/constants';
+import {
+  UPDATE_USER_TAGS,
+  ADD_TAG,
+  REMOVE_TAG,
+  CLEAR_USER_TAGS,
+} from '../utils/constants';
+import { RootState } from './rootReducer';
 
 const initialState: Array<UserTag> = [];
 
 // Reducer
-const addTag = (state: any, tag: UserTag) => {
-  return [...state.concat(tag)];
-}
+const addTag = (state: any, tag: UserTag) => [...state.concat(tag)];
 
 const removeTag = (state: any, tag: UserTag) => {
   const newState = { ...state };
   delete newState[tag.id];
   return newState;
-}
+};
 
 export const userTagsReducer = (state = initialState, action: any) => {
-
   switch (action.type) {
     case ADD_TAG:
       return addTag(state, action.payload);
     case REMOVE_TAG:
       return removeTag(state, action.payload);
     case UPDATE_USER_TAGS:
-      return [...state.concat(action.userTags)]
+      return [...state.concat(action.userTags)];
+    case CLEAR_USER_TAGS:
+      return initialState;
     default:
       return state;
   }
-}
+};
 
 // Selector
 export const selectUserTags = (state: RootState) => state.domainData.userTags;
diff --git a/MaharaMobile/screens/AuthLoadingScreen/AuthLoadingScreen.tsx b/MaharaMobile/screens/AuthLoadingScreen/AuthLoadingScreen.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..a15d0416ebf4aeb61929f9d2b1a297e1be830aff
--- /dev/null
+++ b/MaharaMobile/screens/AuthLoadingScreen/AuthLoadingScreen.tsx
@@ -0,0 +1,138 @@
+import React, {Component} from 'react';
+import AsyncStorage from '@react-native-community/async-storage';
+import { View, ActivityIndicator, StatusBar, StyleSheet } from 'react-native';
+import {connect} from 'react-redux';
+import {
+  updateUserBlogs,
+  updateUserFolders,
+  updateUserName,
+  updateUserTags,
+  addToken,
+  updateLoginTypes,
+  updateUrl,
+  addFileToUploadList,
+  addJournalEntryToUploadList,
+  updateProfilePic
+} from '../../actions/actions';
+import {setUpGuest} from '../../utils/authHelperFunctions';
+import {MaharaPendingFile, PendingJournalEntry} from '../../models/models';
+
+type Props = {
+  navigation: any;
+  dispatch: any;
+};
+
+type State = {};
+
+class AuthLoadingScreen extends Component<Props, State> {
+  componentDidMount() {
+    this.bootstrapAsync();
+  }
+
+  // Fetch userToken from storage then navigate to our appropriate place
+  bootstrapAsync = async () => {
+    const userToken = await AsyncStorage.getItem('userToken');
+    // This will switch to the App screen or Auth screen and this loading
+    // screen will be unmounted and thrown away.
+    if (userToken !== null) {
+      this.retrieveAsync().then(this.props.navigation.navigate('App'));
+    } else this.props.navigation.navigate('Auth');
+  };
+
+  retrieveAsync = async () => {
+    try {
+      // Sort data strings
+      await AsyncStorage.getItem('username').then(async (result: any) => {
+        await this.props.dispatch(updateUserName(result));
+      });
+
+      let localLogin = false;
+      let tokenLogin = false;
+      let ssoLogin = false;
+      await AsyncStorage.getItem('localLogin').then(async (result: any) => {
+        if (result) localLogin = JSON.parse(result);
+      });
+      await AsyncStorage.getItem('tokenLogin').then(async (result: any) => {
+        if (result) tokenLogin = JSON.parse(result);
+      });
+
+      await AsyncStorage.getItem('ssoLogin').then(async (result: any) => {
+        if (result) ssoLogin = JSON.parse(result);
+      });
+      this.props.dispatch(
+        updateLoginTypes(null, localLogin, tokenLogin, ssoLogin)
+      );
+
+      await AsyncStorage.getItem('url').then(async (result: any) => {
+        await this.props.dispatch(updateUrl(result));
+      });
+
+      await AsyncStorage.getItem('userToken').then(async (result: any) => {
+        await this.props.dispatch(addToken(result));
+      });
+      await AsyncStorage.getItem('profileIcon').then(async (result: any) => {
+        await this.props.dispatch(updateProfilePic(result));
+      });
+
+      // Sort data objects
+      await AsyncStorage.getItem('userTags').then(async (result: any) => {
+        if (result) {
+          this.props.dispatch(updateUserTags(this.parseJSON(result)));
+        }
+      });
+
+      await AsyncStorage.getItem('userFolders').then(async (result: any) => {
+        if (result) {
+          await this.props.dispatch(updateUserFolders(this.parseJSON(result)));
+        }
+      });
+
+      await AsyncStorage.getItem('userBlogs').then(async (result: any) => {
+        if (result) {
+          await this.props.dispatch(updateUserBlogs(this.parseJSON(result)));
+        }
+      });
+
+      await AsyncStorage.getItem('uploadFiles').then(async (result: any) => {
+        if (result) {
+          const uploadFilesList = this.parseJSON(result);
+          uploadFilesList.forEach((uploadFile: MaharaPendingFile) =>
+            this.props.dispatch(addFileToUploadList(uploadFile))
+          );
+        }
+      });
+
+      await AsyncStorage.getItem('uploadJEntries').then(async (result: any) => {
+        if (result) {
+          const uploadJEntries = this.parseJSON(result);
+          uploadJEntries.forEach((jEntry: PendingJournalEntry) =>
+            this.props.dispatch(addJournalEntryToUploadList(jEntry))
+          );
+        }
+      });
+    } catch (error) {
+      console.log(`Error getting items from AsyncStorage: ${error}`);
+    }
+  };
+
+  parseJSON = (jsonString: string) => JSON.parse(jsonString);
+
+  render() {
+    return (
+      <View style={styles.container}>
+        <ActivityIndicator />
+        <StatusBar barStyle="default" />
+      </View>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    alignItems: 'center',
+    justifyContent: 'center'
+  }
+});
+
+export default connect()(AuthLoadingScreen);
diff --git a/MaharaMobile/screens/LoginScreen/LoginScreen.tsx b/MaharaMobile/screens/LoginScreen/LoginScreen.tsx
index 3868c43f7e45fe49d2428fd63b6c8fd4c060d83a..64991ab5ea172357b31dcf5b6442906ef222918d 100644
--- a/MaharaMobile/screens/LoginScreen/LoginScreen.tsx
+++ b/MaharaMobile/screens/LoginScreen/LoginScreen.tsx
@@ -1,19 +1,27 @@
-/* eslint-disable import/extensions */
 import React, { Component } from 'react';
-import { View } from 'react-native';
+import { View, Alert } from 'react-native';
 import { connect } from 'react-redux';
-import { addToken } from '../../actions/actions';
+import AsyncStorage from '@react-native-community/async-storage';
+import { addToken, updateGuestStatus } from '../../actions/actions';
 import TokenInput from '../../components/TokenInput/TokenInput';
-import { sendTokenLogin } from '../../utils/helperFunctions';
 import generic from '../../assets/styles/generic';
 import {
   selectUrl,
   selectTokenLogin,
   selectSsoLogin,
   selectLocalLogin,
-  selectLoginState,
+  selectIsGuestStatus
 } from '../../reducers/loginInfoReducer';
 import { RootState } from '../../reducers/reducers';
+import {
+  selectUserBlogs,
+  selectUserFolders
+} from '../../reducers/userArtefactsReducer';
+import { UserFolder, UserBlog } from '../../models/models';
+import {
+  updatePendingItemsOnLogin,
+  fetchUserOnTokenLogin
+} from '../../utils/authHelperFunctions';
 
 type Props = {
   dispatch: any;
@@ -23,7 +31,9 @@ type Props = {
   ssoLogin: boolean;
   localLogin: boolean;
   loginType: boolean;
-  isLoggedIn: boolean;
+  userFolders: Array<UserFolder>;
+  userBlogs: Array<UserBlog>;
+  isGuest: boolean;
 };
 
 type State = {
@@ -35,12 +45,12 @@ export class LoginScreen extends Component<Props, State> {
     super(props);
 
     this.state = {
-      token: '',
+      token: ''
     };
   }
 
   login = () => {
-    const {url} = this.props;
+    const { url } = this.props;
     const serverUrl = `${url}webservice/rest/server.php?alt=json`;
 
     const body = {
@@ -56,42 +66,64 @@ export class LoginScreen extends Component<Props, State> {
     const requestOptions = {
       method: 'POST',
       headers: {
-        'Content-Type': 'application/json',
+        'Content-Type': 'application/json'
       },
-      body: JSON.stringify(body),
+      body: JSON.stringify(body)
     };
 
-    this.props
-      .dispatch(sendTokenLogin(serverUrl, requestOptions))
-      .then(() => this.props.navigation.navigate('Add'));
+    this.props.dispatch(fetchUserOnTokenLogin(serverUrl, requestOptions))
+      .then(() => {
+        this.props.dispatch(addToken(this.state.token));
+        this.signInAsync();
+      })
+      .then(() => this.props.navigation.navigate('App'));
   };
 
-  setToken = (input: string) => {
-    const token = input.trim();
-
+  updateToken = (input: string) => {
+    const newToken = input.trim();
     this.setState({
-      token,
+      token: newToken
     });
   };
 
-  handleToken = () => {
-    const {token} = this.state;
+  verifyToken = () => {
     this.login();
-    this.props.dispatch(addToken(token));
+  };
+
+  /**
+   * Save user token to async storage
+   */
+  signInAsync = async () => {
+    if (this.state.token.length < 1) {
+      Alert.alert('Nothing entered in field');
+    } else if (this.props.isGuest) {
+      await this.props.dispatch(updateGuestStatus(false));
+      updatePendingItemsOnLogin(
+        this.props.dispatch,
+        this.props.userBlogs,
+        this.props.userFolders,
+        this.state.token,
+        this.props.url
+      );
+      await AsyncStorage.setItem('userToken', this.state.token);
+    }
   };
 
   static navigationOptions = {
-    header: null,
+    header: null
   };
 
   render() {
-    const {params} = this.props.navigation.state;
-    const {loginType} = params;
+    const { params } = this.props.navigation.state;
+    const { loginType } = params;
 
     return (
       <View style={generic.view}>
         {loginType === 'token' ? (
-          <TokenInput handleToken={this.handleToken} setToken={this.setToken} />
+          <TokenInput
+            onVerifyToken={this.verifyToken}
+            onUpdateToken={this.updateToken}
+          />
         ) : null}
       </View>
     );
@@ -103,7 +135,9 @@ const mapStateToProps = (state: RootState) => ({
   tokenLogin: selectTokenLogin(state),
   ssoLogin: selectSsoLogin(state),
   localLogin: selectLocalLogin(state),
-  isLoggedIn: selectLoginState(state),
+  userBlogs: selectUserBlogs(state),
+  userFolders: selectUserFolders(state),
+  isGuest: selectIsGuestStatus(state)
 });
 
 export default connect(mapStateToProps)(LoginScreen);
diff --git a/MaharaMobile/screens/PendingScreen/PendingScreen.tsx b/MaharaMobile/screens/PendingScreen/PendingScreen.tsx
index ec4e9663165b7a28c2466594c516dfed7eb1657e..ee6de71ba2c4ed5a89b916978ad272e9071f105c 100644
--- a/MaharaMobile/screens/PendingScreen/PendingScreen.tsx
+++ b/MaharaMobile/screens/PendingScreen/PendingScreen.tsx
@@ -3,7 +3,6 @@ import { Text, View, TouchableOpacity } from 'react-native';
 import { connect } from 'react-redux';
 
 import styles from './PendingScreen.style';
-import { buttons } from '../../assets/styles/buttons';
 import { removeUploadFile, removeUploadJEntry } from '../../actions/actions'
 import { MaharaPendingFile, PendingJournalEntry } from '../../models/models';
 import Spinner from '../../components/Spinner/Spinner'
@@ -12,27 +11,25 @@ import { uploadItemToMahara } from '../../utils/helperFunctions';
 import { RootState } from '../../reducers/reducers';
 import { selectAllUploadFiles, selectAllUploadFilesIds } from '../../reducers/uploadFilesReducer';
 import { selectAllJEntriesIds, selectAllJEntries } from '../../reducers/uploadJEntriesReducer';
-import Header from '../../components/Header/Header';
-
-type Props =
-  {
-    uploadFiles: Array<MaharaPendingFile>;
-    uploadJEntries: Array<PendingJournalEntry>;
-    uploadFilesIds: Array<string>;
-    uploadJEntriesIds: Array<string>;
-    dispatch: any;
-    navigation: any;
-  }
+import { selectUserName } from '../../reducers/loginInfoReducer';
+import { buttons } from '../../assets/styles/buttons';
 
-type State =
-  {
-    uploadRequestPending: boolean;
-    uploadRequestReceived: boolean;
-    successMessage: string;
-    selectedFiles: Array<any>;
-    uploadItemsExist: boolean;
-  }
+type Props = {
+  uploadFiles: Array<MaharaPendingFile>;
+  uploadJEntries: Array<PendingJournalEntry>;
+  uploadFilesIds: Array<string>;
+  uploadJEntriesIds: Array<string>;
+  dispatch: any;
+  navigation: any;
+  userName: string;
+}
 
+type State = {
+  uploadRequestPending: boolean;
+  uploadRequestReceived: boolean;
+  successMessage: string;
+  uploadItemsExist: boolean;
+}
 
 export class PendingScreen extends Component<Props, State> {
   constructor(props: Props) {
@@ -42,37 +39,48 @@ export class PendingScreen extends Component<Props, State> {
       uploadRequestPending: false,
       uploadRequestReceived: false,
       successMessage: '',
-      selectedFiles: [],
       uploadItemsExist: (this.props.uploadFiles.length + this.props.uploadJEntries.length > 0 ? true : false),
-    }
+    };
   }
 
-  static navigationOptions = {
-    // header: null
-  };
-
   pendingDisplay = () => {
-    const { uploadRequestPending, uploadRequestReceived, successMessage } = this.state;
-    // there are items to upload
+    const { uploadRequestPending, uploadRequestReceived, successMessage } = this.state
     let list: Array<any> = [];
 
     if (this.props.uploadFilesIds.length > 0) list = list.concat(this.props.uploadFiles);
     if (this.props.uploadJEntriesIds.length > 0) list = list.concat(this.props.uploadJEntries)
 
     if (this.state.uploadItemsExist) {
-      return (
-        <View>
-          {this.renderPendingList(list)}
-        </View>
-      )
-      // no items to upload
-    } else {
-      if (uploadRequestPending) return <Spinner />
-      else if (!uploadRequestPending && uploadRequestReceived) return <Text>{successMessage}</Text>
-      else return <Text>No pending uploads</Text>
+      return <View>{this.renderPendingList(list)}</View>;
     }
+    if (uploadRequestPending) return <Spinner />;
+    if (!uploadRequestPending && uploadRequestReceived) return <Text>{successMessage}</Text>;
+    return <Text>No pending uploads</Text>;
+  };
+
+  /**
+   * When 'Remove' is pressed, filter out the item with the given id and update the UploadList.
+   */
+  onRemove = (itemId: string) => {
+    this.props.dispatch(removeUploadFile(itemId));
+    this.props.dispatch(removeUploadJEntry(itemId));
   }
 
+  onUploadClick = () => {
+    try {
+      this.props.uploadFiles.forEach(file => this.props.dispatch(uploadItemToMahara(file.url, file.maharaFormData)));
+      this.props.uploadJEntries.forEach(journalEntry => this.props.dispatch(uploadItemToMahara(journalEntry.url, journalEntry.journalEntry)));
+      this.props.uploadFiles.forEach(file => this.props.dispatch(removeUploadFile(file.id)))
+      this.props.uploadJEntries.forEach(journalEntry => this.props.dispatch(removeUploadJEntry(journalEntry.id)))
+    } catch (error) {
+      console.log('onUploadClick error', error);
+    }
+  };
+
+  static navigationOptions = {
+    headerTitle: 'Pending items'
+  };
+
   /**
    * Renders a PendingList
    * @param dataList array of files and journal entries
@@ -85,53 +93,42 @@ export class PendingScreen extends Component<Props, State> {
         onEdit={this.onEdit}
         navigation={this.props.navigation}
       />
-    )
-  }
-
-  onUploadClick = () => {
-    this.props.uploadFiles.forEach(file => this.props.dispatch(uploadItemToMahara(file.url, file.maharaFormData)));
-    this.props.uploadJEntries.forEach(journalEntry => this.props.dispatch(uploadItemToMahara(journalEntry.url, journalEntry.journalEntry)));
-    this.props.uploadFiles.forEach(file => this.props.dispatch(removeUploadFile(file.id)));
-    this.props.uploadJEntries.forEach(journalEntry => this.props.dispatch(removeUploadJEntry(journalEntry.id)));
-  }
-
-  /**
-   * When 'Remove' is pressed, filter out the item with the given id and update the UploadList.
-   */
-  onRemove = (itemId: string) => {
-    this.props.dispatch(removeUploadFile(itemId));
-    this.props.dispatch(removeUploadJEntry(itemId));
+    );
   }
 
   onEdit = (item: MaharaPendingFile | PendingJournalEntry) => {
-    this.props.navigation.navigate({routeName: 'AddFile', params: { item: item }});
+    this.props.navigation.navigate({ routeName: 'AddFile', params: { item: item } });
   }
 
   render() {
     return (
-      <View style={styles.app} >
-        <Header navigation={this.props.navigation} />
-        <Text>Pending Uploads</Text>
-        <View style={styles.listContainer}>
-          {this.pendingDisplay()}
-        </View>
+      <View style={styles.app}>
+        <View style={styles.listContainer}>{this.pendingDisplay()}</View>
         <View style={styles.buttonContainer}>
-          <TouchableOpacity onPress={this.onUploadClick}>
-            <Text style={buttons.lg}>Upload to your Mahara</Text>
-          </TouchableOpacity>
+          {this.props.userName !== 'guest' ? (
+            <TouchableOpacity onPress={this.onUploadClick}>
+              <Text style={buttons.lg}>Upload to your Mahara</Text>
+            </TouchableOpacity>
+          ) : (
+              <TouchableOpacity
+                onPress={() => this.props.navigation.navigate('Auth')}>
+                <Text style={buttons.lg}>Please login</Text>
+              </TouchableOpacity>)
+          }
         </View>
       </View>
     );
   }
-};
+}
 
 const mapStateToProps = (state: RootState) => {
   return {
     uploadFiles: selectAllUploadFiles(state),
     uploadFilesIds: selectAllUploadFilesIds(state),
     uploadJEntries: selectAllJEntries(state),
-    uploadJEntriesIds: selectAllJEntriesIds(state)
+    uploadJEntriesIds: selectAllJEntriesIds(state),
+    userName: selectUserName(state)
   };
-}
+};
 
 export default connect(mapStateToProps)(PendingScreen);
diff --git a/MaharaMobile/screens/ProfileScreen/ProfileScreen.tsx b/MaharaMobile/screens/ProfileScreen/ProfileScreen.tsx
index 70a7eb7250ef42a8384eb342699ae40162c8c3e8..bdb3692729fa0a4e10619a96d9fae4ec24930b7c 100644
--- a/MaharaMobile/screens/ProfileScreen/ProfileScreen.tsx
+++ b/MaharaMobile/screens/ProfileScreen/ProfileScreen.tsx
@@ -1,8 +1,7 @@
 import React, { Component } from 'react';
-import { View, TouchableOpacity, Text } from 'react-native';
+import { View } from 'react-native';
 import { connect } from 'react-redux';
-import RNFetchBlob from 'rn-fetch-blob';
-
+import AsyncStorage from '@react-native-community/async-storage';
 import Header from '../../components/Header/Header';
 import Profile from '../../components/Profile/Profile';
 import styles from './ProfileScreen.style';
@@ -10,15 +9,23 @@ import {
   selectUrl,
   selectToken,
   selectUserName,
+  selectProfileIcon
 } from '../../reducers/loginInfoReducer';
-import { RootState } from '../../reducers/reducers';
-import { buttons } from '../../assets/styles/buttons';
+import MediumButton from '../../components/MediumButton/MediumButton';
+import { clearReduxData, fetchProfilePic } from '../../utils/authHelperFunctions';
+import { selectAllJEntriesIds } from '../../reducers/uploadJEntriesReducer';
+import { selectAllUploadFilesIds } from '../../reducers/uploadFilesReducer';
+import { RootState } from '../../reducers/rootReducer';
 
 type Props = {
   navigation: any; // need to double check type for this
   token: string;
   userName: string;
   url: string;
+  profileIcon: string;
+  jEntriesIds: string[];
+  fileIds: string[];
+  dispatch: any;
 };
 
 type State = {
@@ -29,62 +36,73 @@ export class ProfileScreen extends Component<Props, State> {
   constructor(props: Props) {
     super(props);
     this.state = {
-      profileIcon: '',
+      profileIcon: ''
     };
   }
 
   componentDidMount() {
-    this.receiveProfilePic();
+    this.getProfilePic();
   }
 
-  receiveProfilePic = async () => {
-    const api = 'module_mobileapi_get_user_profileicon&height=100&width=100';
-    const wstoken = this.props.token;
-    const serverUrl =
-      'https://master.dev.mahara.org/module/mobileapi/download.php?wsfunction=' +
-      api +
-      '&wstoken=' +
-      wstoken;
+  getProfilePic = async () => {
+    if (!this.props.token || this.props.token === 'guest') return;
+    fetchProfilePic(this.props.dispatch, this.props.token);
+  };
 
-    RNFetchBlob.config({
-      fileCache: true,
-    })
-      .fetch('GET', serverUrl)
-      .then(res => {
-        const image = `file://${res.path()}`;
-        this.setState({
-          profileIcon: image,
-        });
-      })
-      .catch(error => {
-        // error handling
-        console.log(error);
-      });
+  signOutAsync = async () => {
+    await AsyncStorage.clear();
+    clearReduxData(this.props.dispatch);
+    this.props.navigation.navigate('Auth');
+  };
+
+  generateProfileScreen = () => {
+    if (this.props.token !== 'guest') {
+      return (
+        <View>
+          <View style={styles.container}>
+            <Profile
+              name={this.props.userName}
+              profileIcon={this.props.profileIcon}
+            />
+          </View>
+          <View style={{ marginTop: 450 }}>
+            <MediumButton title="Logout" onPress={this.signOutAsync} />
+          </View>
+        </View>
+      );
+    }
+
+    return (
+      <View>
+        <View style={styles.container}>
+          <Profile
+            name={this.props.userName}
+            profileIcon={this.state.profileIcon || this.props.profileIcon}
+          />
+        </View>
+        <View style={styles.buttons}>
+          <MediumButton
+            title="Logout as Guest"
+            onPress={() => this.signOutAsync()}
+          />
+          <MediumButton
+            title="Login"
+            onPress={() => this.props.navigation.navigate('Auth')}
+          />
+        </View>
+      </View>
+    );
   };
 
   static navigationOptions = {
-    header: null,
+    header: null
   };
 
   render() {
     return (
       <View style={styles.app}>
         <Header navigation={this.props.navigation} />
-        <View style={styles.container}>
-          {this.props.userName !== '' ? (
-            <Profile
-              name={this.props.userName}
-              profileIcon={this.state.profileIcon}
-            />
-          ) : (
-            <View style={styles.buttons}>
-              <TouchableOpacity
-                onPress={() => this.props.navigation.navigate('Auth')}>
-                <Text style={[buttons.md, styles.buttons]}>Login</Text>
-              </TouchableOpacity>
-            </View>
-          )}
-        </View>
+        <View style={styles.container}>{this.generateProfileScreen()}</View>
       </View>
     );
   }
@@ -94,6 +112,9 @@ const mapStateToProps = (state: RootState) => ({
   url: selectUrl(state),
   token: selectToken(state),
   userName: selectUserName(state),
+  profileIcon: selectProfileIcon(state),
+  jEntryIds: selectAllJEntriesIds(state),
+  fileIds: selectAllUploadFilesIds(state)
 });
 
 export default connect(mapStateToProps)(ProfileScreen);
diff --git a/MaharaMobile/screens/SiteCheckScreen/SiteCheckScreen.tsx b/MaharaMobile/screens/SiteCheckScreen/SiteCheckScreen.tsx
index e9e1fbbea681776a44b873e9b66c4101711c42d5..539f9973444a12d773231eda049e6d538f4bafc8 100644
--- a/MaharaMobile/screens/SiteCheckScreen/SiteCheckScreen.tsx
+++ b/MaharaMobile/screens/SiteCheckScreen/SiteCheckScreen.tsx
@@ -4,8 +4,14 @@ import { connect } from 'react-redux';
 import { checkLoginTypes } from '../../actions/actions';
 import LoginType from '../../components/LoginType/LoginType';
 import generic from '../../assets/styles/generic';
-import { RootState } from '../../reducers/reducers';
-import { selectUrl, selectTokenLogin, selectSsoLogin, selectLocalLogin } from '../../reducers/loginInfoReducer';
+import {
+  selectUrl,
+  selectTokenLogin,
+  selectSsoLogin,
+  selectLocalLogin
+} from '../../reducers/loginInfoReducer';
+import { setUpGuest } from '../../utils/authHelperFunctions';
+import { RootState } from '../../reducers/rootReducer';
 
 type Props = {
   dispatch: any;
@@ -31,7 +37,7 @@ const initialState: State = {
   loginType: '',
   serverPing: false,
   isInputHidden: false,
-  enterUrlWarning: false,
+  enterUrlWarning: false
 };
 
 export class SiteCheckScreen extends Component<Props, State> {
@@ -43,7 +49,7 @@ export class SiteCheckScreen extends Component<Props, State> {
 
   setLoginType = (loginType: string) => {
     this.props.navigation.navigate('Login', {
-      loginType,
+      loginType
     });
   };
 
@@ -53,12 +59,12 @@ export class SiteCheckScreen extends Component<Props, State> {
     if (serverUrl.length === 0) {
       this.setState({
         enterUrlWarning: true,
-        url: '',
+        url: ''
       });
       return;
     }
     this.setState({
-      enterUrlWarning: false,
+      enterUrlWarning: false
     });
 
     if (serverUrl.slice(-1) !== '/') {
@@ -79,34 +85,30 @@ export class SiteCheckScreen extends Component<Props, State> {
 
     try {
       await this.props.dispatch(checkLoginTypes(serverUrl));
-      if (
-        this.props.tokenLogin || this.props.localLogin || this.props.ssoLogin ) {
+      if (this.props.tokenLogin || this.props.localLogin || this.props.ssoLogin) {
         this.setState({
           serverPing: true,
           isInputHidden: true,
-          errorMessage: '',
+          errorMessage: ''
         });
       }
     } catch (error) {
       this.setState({ errorMessage: error.message });
-      console.log(error);
+      console.error(error);
     }
   };
 
-  resetForm = () => {
-    this.setState(initialState);
-  };
-
-  skip = () => {
-    this.props.navigation.navigate('Add');
+  skipLogin = () => {
+    setUpGuest(this.props.dispatch);
+    this.props.navigation.navigate('App');
   };
 
-  static navigationOptions = {
-    header: null,
+  resetForm = () => {
+    this.setState(initialState);
   };
 
   static navigationOptions = {
-    header: null,
+    header: null
   };
 
   render() {
@@ -125,7 +127,8 @@ export class SiteCheckScreen extends Component<Props, State> {
           ssoLogin={this.props.ssoLogin}
           tokenLogin={this.props.tokenLogin}
           errorMessage={this.state.errorMessage}
-          skip={this.skip}
+          navigation={this.props.navigation}
+          onSkip={this.skipLogin}
         />
       </View>
     );
@@ -136,7 +139,7 @@ const mapStateToProps = (state: RootState) => ({
   url: selectUrl(state),
   tokenLogin: selectTokenLogin(state),
   ssoLogin: selectSsoLogin(state),
-  localLogin: selectLocalLogin(state),
+  localLogin: selectLocalLogin(state)
 });
 
 export default connect(mapStateToProps)(SiteCheckScreen);
diff --git a/MaharaMobile/utils/authHelperFunctions.ts b/MaharaMobile/utils/authHelperFunctions.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cbe4d82c06f80d26aa3a31da4d35aa6f0fcc3120
--- /dev/null
+++ b/MaharaMobile/utils/authHelperFunctions.ts
@@ -0,0 +1,141 @@
+import AsyncStorage from '@react-native-community/async-storage';
+import RNFetchBlob from 'rn-fetch-blob';
+import {
+  UserBlog,
+  UserFolder,
+  MaharaPendingFile,
+  PendingJournalEntry
+} from '../models/models';
+import {
+  clearLoginInfo,
+  clearUploadFiles,
+  clearUploadJEntires,
+  clearUserFolders,
+  clearUserTags,
+  clearUserBlogs,
+  addToken,
+  updateUserName,
+  updateUserFolders,
+  updateUserBlogs,
+  updateJEntriesOnLogin,
+  updateUploadFilesOnLogin,
+  updateUserTags,
+  updateGuestStatus,
+  addJournalEntryToUploadList,
+  addFileToUploadList,
+  updateProfilePic
+} from '../actions/actions';
+
+export function fetchUserOnTokenLogin(serverUrl: string, requestOptions: any) {
+  return async function(dispatch: any) {
+    try {
+      const response = await fetch(serverUrl, requestOptions);
+      const json = await response.json();
+      dispatch(updateUserName(json.userprofile.myname));
+      dispatch(updateUserTags(json.tags.tags));
+      dispatch(updateUserBlogs(json.blogs.blogs));
+      dispatch(updateUserFolders(json.folders.folders));
+    } catch (error) {
+      // errorHandle(error);
+    }
+  };
+}
+
+export const clearReduxData = async (dispatch: any) => {
+  try {
+    dispatch(clearLoginInfo());
+    dispatch(clearUploadFiles());
+    dispatch(clearUploadJEntires());
+    dispatch(clearUserBlogs());
+    dispatch(clearUserFolders());
+    dispatch(clearUserTags());
+  } catch (error) {
+    console.log('clearReduxData$', error);
+  }
+};
+
+export const setUpGuest = async (dispatch: any) => {
+  await dispatch(addToken('guest'));
+  await dispatch(updateUserName('guest'));
+  await dispatch(updateUserFolders([{id: -1, title: 'images'}]));
+  await dispatch(
+    updateUserBlogs([
+      {
+        id: -1,
+        title: 'Guest Blog',
+        description: null,
+        locked: false,
+        numblogposts: -1
+      }
+    ])
+  );
+  await AsyncStorage.getItem('uploadFiles').then(async (result: any) => {
+    if (result) {
+      const uploadFilesList = parseJSON(result);
+      uploadFilesList.forEach((uploadFile: MaharaPendingFile) =>
+        dispatch(addFileToUploadList(uploadFile))
+      );
+    }
+  });
+
+  await AsyncStorage.getItem('uploadJEntries').then(async (result: any) => {
+    if (result) {
+      const uploadJEntries = parseJSON(result);
+      uploadJEntries.forEach((jEntry: PendingJournalEntry) =>
+        dispatch(addJournalEntryToUploadList(jEntry))
+      );
+    }
+  });
+  await dispatch(updateGuestStatus(true));
+};
+
+const parseJSON = (jsonString: string) => JSON.parse(jsonString);
+
+export const arrayToObject = (array: Array<any>) => {
+  const arrayCopy = [...array];
+  return arrayCopy.reduce((obj, item) => {
+    const objCopy = {...obj};
+    objCopy[item.id] = item;
+    return objCopy;
+  }, {});
+};
+
+/**
+ * Updates default guest data to user info once logged in.
+ * - Tokens, blogs, folders as well as their respective ids need to be updated
+ * - Existing pending uploadFiles and uploadJEntries once users login
+ * - Rerieved Mahara data to replace guest data be able to upload items.
+ */
+export const updatePendingItemsOnLogin = async (
+  dispatch: any,
+  userBlogs: Array<UserBlog>,
+  userFolders: Array<UserFolder>,
+  token: string,
+  urlDomain: string
+) => {
+  await dispatch(updateJEntriesOnLogin(token, urlDomain, userBlogs));
+  await dispatch(updateUploadFilesOnLogin(token, urlDomain, userFolders));
+};
+
+export const fetchProfilePic = async (dispatch: any, token: string) => {
+  const api = 'module_mobileapi_get_user_profileicon&height=100&width=100';
+  const wstoken = token;
+  const serverUrl = `https://master.dev.mahara.org/module/mobileapi/download.php?wsfunction=${api}&wstoken=${wstoken}`;
+
+  let profilePic = '';
+
+  RNFetchBlob.config({
+    fileCache: true
+  })
+    .fetch('GET', serverUrl)
+    .then((res) => {
+      profilePic = `file://${res.path()}`;
+      dispatch(updateProfilePic(profilePic));
+    })
+    .catch((error) => {
+      // error handling
+      console.log(error);
+    });
+
+  return profilePic;
+};
diff --git a/MaharaMobile/utils/constants.ts b/MaharaMobile/utils/constants.ts
index 62fb4cf9c4c01200041845604ff41f624d713358..e73a9a23a348cb0aeea1ac78abed5d24c12dcd9e 100644
--- a/MaharaMobile/utils/constants.ts
+++ b/MaharaMobile/utils/constants.ts
@@ -1,18 +1,34 @@
 // action types - payloads of information that send data from your application to your store
 
 // DOMAIN DATA
+// userTagsReducer
 export const ADD_TAG = 'ADD_TAG';
-export const ADD_USER = 'ADD_USER';
+export const REMOVE_TAG = 'REMOVE_TAG';
+export const UPDATE_USER_TAGS = 'UPDATE_USER_TAGS';
+export const CLEAR_USER_TAGS = 'CLEAR_USER_TAGS';
+// loginInfoReducer
 export const ADD_TOKEN = 'ADD_TOKEN';
 export const UPDATE_USERNAME = 'UPDATE_USERNAME';
+export const UPDATE_SERVER_URL = 'UPDATE_SERVER_URL';
+export const CLEAR_LOGIN_INFO = 'CLEAR_LOGIN_INFO';
+export const UPDATE_LOGIN_TYPES = 'UPDATE_LOGIN_TYPES';
+export const UPDATE_URL = 'UPDATE_URL';
+export const UPDATE_PROFILE_ICON = 'UPDATE_PROFILE_ICON';
+export const UPDATE_GUEST_STATUS = 'UPDATE_GUEST_STATUS';
+// userArtefactsReducer
 export const UPDATE_USER_BLOGS = 'UPDATE_USER_BLOGS';
 export const UPDATE_USER_FOLDERS = 'UPDATE_USER_FOLDERS';
-export const UPDATE_USER_TAGS = 'UPDATE_USER_TAGS';
-export const UPDATE_SERVER_URL = 'UPDATE_SERVER_URL';
-export const REMOVE_TAG = 'REMOVE_TAG';
+export const CLEAR_USER_BLOGS = 'CLEAR_USER_BLOGS';
+export const CLEAR_USER_FOLDERS = 'CLEAR_USER_FOLDERS';
 
 // APP STATE
+// uploadFilesReducer
 export const ADD_UPLOAD_FILE = 'ADD_FILE_TO_UPLOAD_LIST';
-export const ADD_UPLOAD_JOURNAL_ENTRY = 'ADD_JOURNAL_ENTRY_TO_UPLOAD_LIST';
 export const REMOVE_UPLOAD_FILE = 'REMOVE_UPLOAD_FILE';
+export const CLEAR_UPLOAD_FILES = 'CLEAR_UPLOAD_FILES';
+export const UPDATE_UPLOAD_FILES_ON_LOGIN = 'UPDATE_UPLOAD_FILES_ON_LOGIN';
+// uploadJEntriesReducer
+export const ADD_UPLOAD_JOURNAL_ENTRY = 'ADD_JOURNAL_ENTRY_TO_UPLOAD_LIST';
 export const REMOVE_UPLOAD_JOURNAL_ENTRY = 'REMOVE_UPLOAD_JOURNAL_ENTRY';
+export const CLEAR_UPLOAD_J_ENTRIES = 'CLEAR_UPLOAD_J_ENTRIES';
+export const UPDATE_J_ENTRIES_ON_LOGIN = 'UPDATE_J_ENTRIES_ON_LOGIN';