Skip to content

Commit

Permalink
1279 user profile UI changes for mvp (#1295)
Browse files Browse the repository at this point in the history
* Follow Button changes

* Change non pressable count icons to gray, removed onPress, hide post mvp sections of userprofile

* createRelationships api call, follow/unfollow functionality

* Unfollow and follow button functionality, refactoring
  • Loading branch information
angielt authored Mar 21, 2024
1 parent f510a46 commit 822909b
Show file tree
Hide file tree
Showing 11 changed files with 320 additions and 57 deletions.
4 changes: 2 additions & 2 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/yoga"

SPEC CHECKSUMS:
boost: 7dcd2de282d72e344012f7d6564d024930a6a440
boost: 57d2868c099736d80fcd648bf211b4431e51a558
BVLinearGradient: 880f91a7854faff2df62518f0281afb1c60d49a3
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: 9840513ec2766e31fb9e34c2dabb2c4671400fcd
Expand Down Expand Up @@ -810,4 +810,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 77ed9526d4011b245ce5afa1ea331dea4c67d753

COCOAPODS: 1.14.3
COCOAPODS: 1.14.2
12 changes: 10 additions & 2 deletions ios/iNaturalistReactNative.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,11 @@
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
OTHER_LDFLAGS = "$(inherited)";
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
};
Expand Down Expand Up @@ -1048,7 +1052,11 @@
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
OTHER_LDFLAGS = "$(inherited)";
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
Expand Down
10 changes: 10 additions & 0 deletions src/api/relationships.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ const fetchRelationships = async ( params: Object = {}, opts: Object = {} ): Pro
}
};

const createRelationships = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
try {
const response = await inatjs.relationships.create( { ...PARAMS, ...params }, opts );
return response;
} catch ( e ) {
return handleError( e );
}
};

const updateRelationships = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
try {
const response = await inatjs.relationships.update( { ...PARAMS, ...params }, opts );
Expand All @@ -36,6 +45,7 @@ const deleteRelationships = async ( params: Object = {}, opts: Object = {} ): Pr
};

export {
createRelationships,
deleteRelationships,
fetchRelationships,
updateRelationships
Expand Down
35 changes: 30 additions & 5 deletions src/components/SharedComponents/OverviewCounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,41 @@ type Props = {
}

type CountProps = {
count: number,
label: string,
icon: string
}

type CountPressableProps = {
count: number,
label: string,
icon: string,
onPress?: Function
}

const Count = ( {
count, label, icon, onPress
count, label, icon
}: CountProps ) => (
<View
className="w-1/4 items-center"
>
<View className="w-[32px] h-[32px] rounded-lg items-center justify-center">
<INatIcon
name={icon}
size={18}
color={colors.darkGray}
/>
</View>
{typeof count === "number"
? <Body2 className="mt-2">{t( "Intl-number", { val: count } )}</Body2>
: <ActivityIndicator size={25} />}
<Heading5 className="mt-2 text-center">{label}</Heading5>
</View>
);

const CountPressable = ( {
count, label, icon, onPress
}: CountPressableProps ) => (
<Pressable
onPress={onPress}
accessibilityRole="button"
Expand All @@ -48,13 +74,13 @@ const OverviewCounts = ( {
counts, onObservationPressed, onSpeciesPressed
}: Props ): React.Node => (
<View className="flex-row mt-6">
<Count
<CountPressable
count={counts.observations_count}
label={t( "OBSERVATIONS-WITHOUT-NUMBER", { count: counts.observations_count } )}
icon="binoculars"
onPress={onObservationPressed}
/>
<Count
<CountPressable
count={counts.species_count}
label={t( "SPECIES-WITHOUT-NUMBER", { count: counts.species_count } )}
icon="leaf"
Expand All @@ -64,8 +90,7 @@ const OverviewCounts = ( {
<Count
count={counts.identifications_count}
label={t( "IDENTIFICATIONS-WITHOUT-NUMBER", { count: counts.identifications_count } )}
icon="person"
onPress={onSpeciesPressed}
icon="label"
/>
)}
{typeof ( counts.members_count ) === "number" && (
Expand Down
44 changes: 44 additions & 0 deletions src/components/UserProfile/FollowButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// @flow

import {
Button
} from "components/SharedComponents";
import { t } from "i18next";
import type { Node } from "react";
import React from "react";

type Props = {
following: boolean,
follow: Function,
unfollow: Function,
loading: boolean
};

const FollowButton = ( {
following, follow, unfollow, loading
}: Props ): Node => {
if ( following ) {
return (
<Button
level="primary"
className="grow"
text={t( "UNFOLLOW" )}
onPress={unfollow}
testID="UserProfile.followButton"
/>
);
}
return (
<Button
level="primary"
className="grow"
loading={loading}
text={t( "FOLLOW" )}
onPress={follow}
testID="UserProfile.followButton"
/>

);
};

export default FollowButton;
110 changes: 110 additions & 0 deletions src/components/UserProfile/FollowButtonContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// @flow

import { createRelationships, updateRelationships } from "api/relationships";
import type { Node } from "react";
import React, { useEffect, useState } from "react";
import { Alert } from "react-native";
import { useAuthenticatedMutation } from "sharedHooks";

import FollowButton from "./FollowButton";

type Props = {
userId: number,
relationship: Object,
refetchRelationship: Function,
setShowLoginSheet: Function,
setShowUnfollowSheet: Function,
currentUser: Object
};

const FollowButtonContainer = ( {
userId, setShowLoginSheet, setShowUnfollowSheet,
currentUser, relationship, refetchRelationship
}: Props ): Node => {
const [loading, setLoading] = useState( false );
const [following, setFollowing] = useState( false );

useEffect( ( ) => {
if ( relationship?.following === true ) {
setFollowing( true );
return;
}
setFollowing( false );
}, [relationship, refetchRelationship] );

const createRelationshipsMutation = useAuthenticatedMutation(
( id, optsWithAuth ) => createRelationships( id, optsWithAuth )
);

const updateRelationshipsMutation = useAuthenticatedMutation(
( id, optsWithAuth ) => updateRelationships( id, optsWithAuth )
);

const createRelationshipsMutate = ( ) => createRelationshipsMutation.mutate( {
relationship: {
friend_id: userId,
following: true
}
}, {
onSuccess: () => {
refetchRelationship();
setLoading( false );
},
onError: error => {
setLoading( false );
Alert.alert( "Error Following/Unfollowing", error );
}
} );

const updateRelationshipsMutate = ( ) => updateRelationshipsMutation.mutate( {
id: relationship.id,
relationship: {
following: true
}
}, {
onSuccess: () => {
refetchRelationship();
setLoading( false );
},
onError: error => {
setLoading( false );
Alert.alert( "Error Following/Unfollowing", error );
}
} );

const follow = () => {
if ( relationship ) {
updateRelationshipsMutate();
} else {
createRelationshipsMutate();
}
};

const followUser = () => {
if ( !currentUser ) {
setShowLoginSheet( true );
return;
}
setLoading( true );
follow();
};

const unfollowUser = ( ) => {
if ( !currentUser ) {
setShowLoginSheet( true );
return;
}
setShowUnfollowSheet( true );
};

return (
<FollowButton
loading={loading}
following={following}
follow={followUser}
unfollow={unfollowUser}
/>
);
};

export default FollowButtonContainer;
56 changes: 56 additions & 0 deletions src/components/UserProfile/UnfollowSheet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// @flow
import { updateRelationships } from "api/relationships";
import WarningSheet from "components/SharedComponents/Sheets/WarningSheet";
import type { Node } from "react";
import React from "react";
import { Alert } from "react-native";
import { useAuthenticatedMutation, useTranslation } from "sharedHooks";

type Props = {
relationship: Object,
refetchRelationship: Function,
setShowUnfollowSheet: Function,
}

const UnfollowSheet = ( {
relationship,
setShowUnfollowSheet,
refetchRelationship
}: Props ): Node => {
const { t } = useTranslation( );

const updateRelationshipsMutation = useAuthenticatedMutation(
( id, optsWithAuth ) => updateRelationships( id, optsWithAuth )
);

const unfollowUser = ( ) => updateRelationshipsMutation.mutate( {
id: relationship.id,
relationship: {
following: false
}
}, {
onSuccess: () => {
setShowUnfollowSheet( false );
refetchRelationship();
},
onError: error => {
Alert.alert( "Error Following/Unfollowing", error );
}
} );

return (
<WarningSheet
handleClose={( ) => setShowUnfollowSheet( false )}
secondButtonText={t( "CANCEL" )}
buttonType="warning"
headerText={t( "UNFOLLOW-USER" )}
buttonText={t( "UNFOLLOW" )}
handleSecondButtonPress={( ) => setShowUnfollowSheet( false )}
confirm={( ) => {
if ( relationship ) unfollowUser();
}}
/>
);
};

export default UnfollowSheet;
Loading

0 comments on commit 822909b

Please sign in to comment.