diff --git a/src/components/pages/authenticate.js b/src/components/pages/authenticate.js
index 5a665cf..1d4817a 100644
--- a/src/components/pages/authenticate.js
+++ b/src/components/pages/authenticate.js
@@ -14,33 +14,7 @@ import * as Linking from "expo-linking";
import * as WebBrowser from "expo-web-browser";
import Constants from "expo-constants";
-async function postForm(url, data, token = false) {
- // Send a POST request with data formatted with FormData returning JSON
- let form = new FormData();
- for (let key in data) {
- form.append(key, data[key]);
- }
-
- const response = await fetch(url, {
- method: "POST",
- body: form,
- headers: token
- ? { "Authorization": `Bearer ${token}`, }
- : {},
- });
-
- return response.json();
-}
-
-async function get(url, token = false) {
- const response = await fetch(url, {
- method: "GET",
- headers: token
- ? { "Authorization": `Bearer ${token}`, }
- : {},
- });
- return response.json();
-}
+import * as requests from "src/requests";
const AuthenticateJsx = ({navigation}) => {
const REDIRECT_URI = Linking.makeUrl("authenticate");
@@ -76,15 +50,17 @@ const AuthenticateJsx = ({navigation}) => {
scope: "read write follow push",
};
- const token = await postForm(`${api}/oauth/token`, tokenRequestBody);
+ const token = await requests
+ .postForm(`${api}/oauth/token`, tokenRequestBody)
+ .then(resp => resp.json());
// Store the token
AsyncStorage.setItem("@user_token", JSON.stringify(token));
- const profile = await get(
+ const profile = await requests.get(
`${api}/api/v1/accounts/verify_credentials`,
token.access_token
- );
+ ).then(resp => resp.json());
await AsyncStorage.multiSet([
[ "@user_profile", JSON.stringify(profile), ],
@@ -122,12 +98,12 @@ const AuthenticateJsx = ({navigation}) => {
// Ensure the app has been created
if (appJSON == null) {
// Register app: https://docs.joinmastodon.org/methods/apps/#create-an-application
- app = await postForm(`${url}/api/v1/apps`, {
+ app = await requests.postForm(`${url}/api/v1/apps`, {
client_name: "Resin",
redirect_uris: REDIRECT_URI,
scopes: "read write follow push",
website: "https://github.com/natjms/resin",
- });
+ }).then(resp => resp.json());
await AsyncStorage
.setItem("@app_object", JSON.stringify(app))
diff --git a/src/components/pages/profile.js b/src/components/pages/profile.js
index 8c89d1c..d0171a9 100644
--- a/src/components/pages/profile.js
+++ b/src/components/pages/profile.js
@@ -13,6 +13,7 @@ import AsyncStorage from "@react-native-async-storage/async-storage";
import { activeOrNot } from "src/interface/interactions";
import { withoutHTML } from "src/interface/rendering";
+import * as requests from "src/requests";
import GridViewJsx from "src/components/posts/grid-view";
import {
@@ -89,13 +90,15 @@ const TEST_THEIR_FOLLOWERS = [
{ id: 6 },
];
-function getMutuals(yours, theirs) {
- // Where yours and theirs are arrays of followers, as returned by the oAPI
+function getMutuals(yourFollowing, theirFollowers) {
+ // Where yours and theirs are arrays of followers, as returned by the API
+ // Returns a list of people you are following that are following some other
+ // account
- const idify = ({id}) => id;
- const asIDs = new Set(theirs.map(idify));
+ const acctsArray = ({acct}) => acct;
+ const asIDs = new Set(theirFollowers.map(acctArray));
- return yours.filter(x => asIDs.has(idify(x)));
+ return yourFollowing.filter(x => asIDs.has(idify(x)));
}
const HTMLLink = ({link}) => {
@@ -118,62 +121,143 @@ const HTMLLink = ({link}) => {
}
}
-const ProfileJsx = ({navigation}) => {
- return (
-
-
-
- );
-};
-
const ViewProfileJsx = ({navigation}) => {
+ // As rendered when opened from somewhere other than the tab bar
+ const [state, setState] = useState({
+ loaded: false,
+ profile: navigation.getParam("profile"),
+ });
+
+ useEffect(() => {
+ AsyncStorage
+ .multiGet(["@user_profile", "@user_instance", "@user_token"])
+ .then(([ownProfilePair, ownDomainPair, tokenPair]) =>
+ [
+ JSON.parse(ownProfilePair[1]),
+ ownDomainPair[1],
+ JSON.parse(tokenPair[1]).access_token,
+ ]
+ )
+ .then(([ ownProfile, ownDomain, accessToken ]) => {
+ const parsedAcct = state.profile.acct.split("@");
+ const domain = parsedAcct.length == 1
+ ? ownDomain // There's no @ in the acct, thus it's a local user
+ : parsedAcct [1] // The part of profile.acct after the @
+
+ return Promise.all([
+ requests.fetchFollowing(
+ ownDomain,
+ ownProfile.id,
+ accessToken
+ ),
+ requests.fetchFollowers(
+ domain,
+ state.profile.id,
+ accessToken
+ ),
+ ]);
+ })
+ .then(([ ownFollowing, theirFollowers ]) =>
+ setState({...state,
+ mutuals: getMutuals(ownFollowing, theirFollowers),
+ loaded: true,
+ })
+ );
+ }, []);
return (
-
-
-
+ <>
+ { state.loaded
+ ?
+
+
+ : <>>
+ }
+ >
);
}
-const ProfileDisplayJsx = ({navigation}) => {
- const accountName = navigation.getParam("acct", "");
- let [state, setState] = useState({
+const ProfileJsx = ({ navigation }) => {
+ const [state, setState] = useState({
loaded: false,
});
+ useEffect(() => {
+ let profile;
+ let notifs;
+ let domain;
+ let accessToken;
+
+ AsyncStorage
+ .multiGet([
+ "@user_profile",
+ "@user_notifications",
+ "@user_instance",
+ ])
+ .then(([profilePair, notifPair, domainPair]) => {
+ profile = JSON.parse(profilePair[1]);
+ notifs = JSON.parse(notifPair[1]);
+ domain = domainPair[1];
+
+ return requests.fetchProfile(domain, profile.id);
+ })
+ .then(latestProfile => {
+ if(JSON.stringify(latestProfile) != JSON.stringify(profile)) {
+ profile = latestProfile
+ }
+
+ setState({...state,
+ profile: profile,
+ notifs: notifs,
+ loaded: true,
+ });
+ });
+ }, []);
+ return (
+ <>
+ { state.loaded
+ ?
+
+
+ : <>>
+ }
+ >
+ )
+};
+
+const RawProfileJsx = (props) => {
+ let [state, setState] = useState({
+ own: props.own,
+ profile: props.profile,
+ notifs: props.notifs,
+ });
+
const notif_pack = {
active: require("assets/eva-icons/bell-unread.png"),
inactive: require("assets/eva-icons/bell-black.png")
}
- useEffect(() => {
- AsyncStorage.multiGet(["@user_profile", "@user_notifications"])
- .then(values => {
- const [profileJSON, notificationsJSON] = values;
-
- const profile = JSON.parse(profileJSON[1]);
- const notifications = JSON.parse(notificationsJSON[1]);
- setState({
- profile: profile,
- unreadNotifications: notifications.unread,
- mutuals: getMutuals(TEST_YOUR_FOLLOWERS, TEST_THEIR_FOLLOWERS),
- own: true,
- loaded: true,
- });
- });
- }, []);
+ const _handleFollow = () => {};
let profileButton;
- if (state.own) {
+ if (props.own) {
profileButton = (
{
- navigation.navigate("Settings");
+ props.navigation.navigate("Settings");
}
}>
@@ -183,7 +267,7 @@ const ProfileDisplayJsx = ({navigation}) => {
);
} else {
profileButton = (
-
+
Follow
@@ -193,107 +277,101 @@ const ProfileDisplayJsx = ({navigation}) => {
return (
- { state.loaded ?
- <>
-
-
-
-
-
- {state.profile.display_name}
-
-
- @{state.profile.username }
-
-
- {
- state.own ?
-
- {
- navigation.navigate("Notifications");
- }
- }>
-
-
-
- :
- }
-
-
- { state.profile.statuses_count } posts •
- {
- const context = state.own ?
- "People following you"
- : "Your mutual followers with " + state.profile.display_name;
- navigation.navigate("UserList", {
- data: [/*Some array of users*/],
- context: context
- });
- }
- }>
- {
- state.own ?
- <>View followers>
- : <>{state.mutuals.length + " mutuals"}>
- }
-
-
+
+
+
+
+
+ { props.profile.display_name}
-
- {state.profile.note}
+
+ @{ props.profile.acct }
-
- { state.profile.fields
- ? state.profile.fields.map((field, index) => (
-
-
-
- { field.name }
-
-
-
-
-
-
- ))
- : <>>
- }
-
- {profileButton}
-
- {
- navigation.navigate("ViewPost", {
- id: id,
- originTab: "Profile"
+ {
+ state.own ?
+
+ {
+ props.navigation.navigate("Notifications");
+ }
+ }>
+
+
+
+ :
+ }
+
+
+ { props.profile.statuses_count } posts •
+ {
+ const context = props.own ?
+ "People following you"
+ : "Your mutual followers with " + props.profile.display_name;
+ props.navigation.navigate("UserList", {
+ context: context,
});
}
- } />
- >
- :
- }
+ }>
+ {
+ state.own ?
+ <>View followers>
+ : <>{ props.mutuals + " mutuals" }>
+ }
+
+
+
+
+ {props.profile.note}
+
+
+ { props.profile.fields
+ ? props.profile.fields.map((field, index) => (
+
+
+
+ { field.name }
+
+
+
+
+
+
+ ))
+ : <>>
+ }
+
+ {profileButton}
+
+
+ {
+ props.navigation.navigate("ViewPost", {
+ id: id,
+ originTab: "Profile"
+ });
+ }
+ } />
);
};
@@ -371,5 +449,4 @@ const styles = {
},
};
-export { ViewProfileJsx, ProfileDisplayJsx };
-export default ProfileJsx;
+export { ViewProfileJsx, ProfileJsx as default };
diff --git a/src/requests.js b/src/requests.js
index 9e8349a..3147c0a 100644
--- a/src/requests.js
+++ b/src/requests.js
@@ -28,3 +28,45 @@ export async function checkUnreadNotifications() {
return isUnread;
}
}
+
+export async function postForm(url, data, token = false) {
+ // Send a POST request with data formatted with FormData returning JSON
+ let form = new FormData();
+ for (let key in data) {
+ form.append(key, data[key]);
+ }
+
+ const resp = await fetch(url, {
+ method: "POST",
+ body: form,
+ headers: token
+ ? { "Authorization": `Bearer ${token}`, }
+ : {},
+ });
+
+ return resp;
+}
+
+export function get(url, token = false) {
+ return fetch(url, {
+ method: "GET",
+ headers: token
+ ? { "Authorization": `Bearer ${token}`, }
+ : {},
+ });
+}
+
+export async function fetchProfile(domain, id) {
+ const resp = await get(`https://${domain}/api/v1/accounts/${id}`);
+ return resp.json();
+}
+
+export async function fetchFollowing(domain, id, token) {
+ const resp = await get(`https://${domain}/api/v1/accounts/${id}/following`, token);
+ return resp.json();
+}
+
+export async function fetchFollowers(domain, id, token) {
+ const resp = await get(`https://${domain}/api/v1/accounts/${id}/followers`, token);
+ return resp.json();
+}