aboutsummaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/common/TaggRadioButton.tsx53
-rw-r--r--src/components/common/TaggUserSelectionCell.tsx73
-rw-r--r--src/components/common/index.ts1
-rw-r--r--src/components/moments/TagFriendsFoooter.tsx132
-rw-r--r--src/components/moments/index.ts1
-rw-r--r--src/components/profile/ProfilePreview.tsx44
-rw-r--r--src/components/search/SearchBar.tsx24
7 files changed, 313 insertions, 15 deletions
diff --git a/src/components/common/TaggRadioButton.tsx b/src/components/common/TaggRadioButton.tsx
new file mode 100644
index 00000000..3cc2780c
--- /dev/null
+++ b/src/components/common/TaggRadioButton.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import {
+ GestureResponderEvent,
+ StyleSheet,
+ TouchableOpacity,
+ View,
+} from 'react-native';
+import {RADIO_BUTTON_GREY, TAGG_LIGHT_BLUE_2} from '../../constants/constants';
+
+interface TaggRadioButtonProps {
+ pressed: boolean;
+ onPress: (event: GestureResponderEvent) => void;
+}
+const TaggRadioButton: React.FC<TaggRadioButtonProps> = ({
+ pressed,
+ onPress,
+}) => {
+ const activeOuterStyle = {
+ borderColor: pressed ? TAGG_LIGHT_BLUE_2 : RADIO_BUTTON_GREY,
+ };
+
+ const activeInnerStyle = {
+ backgroundColor: pressed ? TAGG_LIGHT_BLUE_2 : 'white',
+ };
+ return (
+ <TouchableOpacity
+ style={[styles.outer, activeOuterStyle]}
+ onPress={onPress}>
+ {pressed && <View style={[styles.inner, activeInnerStyle]} />}
+ </TouchableOpacity>
+ );
+};
+
+const styles = StyleSheet.create({
+ outer: {
+ width: 20,
+ height: 20,
+ borderWidth: 1.5,
+ borderRadius: 20,
+
+ backgroundColor: 'white',
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ inner: {
+ width: 14,
+ height: 14,
+ borderRadius: 8,
+ },
+});
+
+export default TaggRadioButton;
diff --git a/src/components/common/TaggUserSelectionCell.tsx b/src/components/common/TaggUserSelectionCell.tsx
new file mode 100644
index 00000000..2ea1e4ce
--- /dev/null
+++ b/src/components/common/TaggUserSelectionCell.tsx
@@ -0,0 +1,73 @@
+import React, {useEffect, useState} from 'react';
+import {StyleSheet, View} from 'react-native';
+import {ProfilePreview} from '..';
+import {ProfilePreviewType, ScreenType} from '../../types';
+import {SCREEN_WIDTH} from '../../utils';
+import TaggRadioButton from './TaggRadioButton';
+
+interface TaggUserSelectionCellProps {
+ item: ProfilePreviewType;
+ selectedUsers: ProfilePreviewType[];
+ setSelectedUsers: Function;
+}
+const TaggUserSelectionCell: React.FC<TaggUserSelectionCellProps> = ({
+ item,
+ selectedUsers,
+ setSelectedUsers,
+}) => {
+ const [pressed, setPressed] = useState<boolean>(false);
+
+ /*
+ * To update state of radio button on initial render and subsequent re-renders
+ */
+ useEffect(() => {
+ const updatePressed = () => {
+ const userSelected = selectedUsers.findIndex(
+ (selectedUser) => item.id === selectedUser.id,
+ );
+ setPressed(userSelected !== -1);
+ };
+ updatePressed();
+ });
+
+ /*
+ * Handles on press on radio button
+ * Adds/removes user from selected list of users
+ */
+ const handlePress = () => {
+ // Add to selected list of users
+ if (pressed === false) {
+ setSelectedUsers([...selectedUsers, item]);
+ }
+ // Remove item from selected list of users
+ else {
+ const filteredSelection = selectedUsers.filter(
+ (user) => user.id !== item.id,
+ );
+ setSelectedUsers(filteredSelection);
+ }
+ };
+ return (
+ <View style={styles.container}>
+ <View style={{width: SCREEN_WIDTH * 0.8}}>
+ <ProfilePreview
+ profilePreview={item}
+ previewType={'Search'}
+ screenType={ScreenType.Profile}
+ />
+ </View>
+ <TaggRadioButton pressed={pressed} onPress={handlePress} />
+ </View>
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ marginHorizontal: '3%',
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+});
+
+export default TaggUserSelectionCell;
diff --git a/src/components/common/index.ts b/src/components/common/index.ts
index 692c9f8a..4f5c0232 100644
--- a/src/components/common/index.ts
+++ b/src/components/common/index.ts
@@ -27,4 +27,5 @@ export {default as Avatar} from './Avatar';
export {default as TaggTypeahead} from './TaggTypeahead';
export {default as TaggUserRowCell} from './TaggUserRowCell';
export {default as LikeButton} from './LikeButton';
+export {default as TaggUserSelectionCell} from './TaggUserSelectionCell';
export {default as MomentTags} from './MomentTags';
diff --git a/src/components/moments/TagFriendsFoooter.tsx b/src/components/moments/TagFriendsFoooter.tsx
new file mode 100644
index 00000000..6b8fc62a
--- /dev/null
+++ b/src/components/moments/TagFriendsFoooter.tsx
@@ -0,0 +1,132 @@
+import {useNavigation} from '@react-navigation/native';
+import React, {Dispatch, SetStateAction} from 'react';
+import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
+import {ProfilePreview} from '..';
+import {ProfilePreviewType, ScreenType} from '../../types';
+import {normalize} from '../../utils/layouts';
+
+interface TagFriendsFooterProps {
+ taggedUsers: ProfilePreviewType[];
+ setTaggedUsers: Dispatch<SetStateAction<ProfilePreviewType[]>>;
+}
+const TagFriendsFooter: React.FC<TagFriendsFooterProps> = ({
+ taggedUsers,
+ setTaggedUsers,
+}) => {
+ const navigation = useNavigation();
+
+ const handleRemoveTag = (user: ProfilePreviewType) => {
+ const filteredSelection = taggedUsers.filter((item) => user.id !== item.id);
+ setTaggedUsers(filteredSelection);
+ };
+
+ const TaggMoreButton = () => (
+ <TouchableOpacity
+ onPress={() =>
+ navigation.navigate('TagSelectionScreen', {
+ selectedUsers: taggedUsers,
+ })
+ }
+ style={{
+ flexDirection: 'column',
+ alignItems: 'center',
+ }}>
+ <Image
+ source={require('../../assets/icons/tagging/white-plus-icon.png')}
+ style={{width: 38, height: 38, top: -2}}
+ />
+ <Text style={styles.taggMoreLabel}>{'Tagg More'}</Text>
+ </TouchableOpacity>
+ );
+
+ const TaggedUser = (user: ProfilePreviewType) => (
+ <View style={{flexDirection: 'row-reverse'}} key={user.id}>
+ <TouchableOpacity
+ style={styles.closeIconContainer}
+ onPress={() => handleRemoveTag(user)}>
+ <Image
+ source={require('../../assets/icons/tagging/x-icon.png')}
+ style={{
+ width: 20,
+ height: 20,
+ }}
+ />
+ </TouchableOpacity>
+ <ProfilePreview
+ profilePreview={user}
+ previewType={'Tag Selection'}
+ screenType={ScreenType.Profile}
+ />
+ </View>
+ );
+
+ /*
+ * Title/Button depending on the number of users inside taggedUsers list
+ * If taggUsers is empty, title acts as a button
+ * Else, gets disabled and TaggMore button appears
+ */
+ const TagFriendsTitle = () => (
+ <TouchableOpacity
+ style={{
+ flexDirection: 'row',
+ }}
+ disabled={taggedUsers.length !== 0}
+ onPress={() =>
+ navigation.navigate('TagSelectionScreen', {
+ selectedUsers: taggedUsers,
+ })
+ }>
+ <Image
+ source={require('../../assets/icons/tagging/tag-icon.png')}
+ style={styles.tagIcon}
+ />
+ <Text style={styles.tagFriendsTitle}>Tag Friends</Text>
+ </TouchableOpacity>
+ );
+
+ return (
+ <>
+ <TagFriendsTitle />
+ <View style={styles.tagFriendsContainer}>
+ {taggedUsers.map((user) => (
+ <TaggedUser {...user} />
+ ))}
+ {taggedUsers.length !== 0 && <TaggMoreButton />}
+ </View>
+ </>
+ );
+};
+
+const styles = StyleSheet.create({
+ tagIcon: {width: 20, height: 20, marginRight: '3%'},
+ tagFriendsTitle: {
+ color: 'white',
+ fontSize: normalize(12),
+ lineHeight: normalize(16.71),
+ letterSpacing: normalize(0.3),
+ fontWeight: '600',
+ },
+ tagFriendsContainer: {
+ flexDirection: 'row',
+ marginTop: '3%',
+ flexWrap: 'wrap',
+ justifyContent: 'flex-start',
+ },
+ taggMoreLabel: {
+ fontWeight: '500',
+ fontSize: normalize(9),
+ lineHeight: normalize(10),
+ letterSpacing: normalize(0.2),
+ color: 'white',
+ textAlign: 'center',
+ marginVertical: '5%',
+ },
+ closeIconContainer: {
+ width: 20,
+ height: 20,
+ right: -20,
+ zIndex: 1,
+ },
+});
+
+export default TagFriendsFooter;
diff --git a/src/components/moments/index.ts b/src/components/moments/index.ts
index 89fd689c..6af29bc5 100644
--- a/src/components/moments/index.ts
+++ b/src/components/moments/index.ts
@@ -3,3 +3,4 @@ export {default as CaptionScreenHeader} from './CaptionScreenHeader';
export {default as MomentPostHeader} from './MomentPostHeader';
export {default as MomentPostContent} from './MomentPostContent';
export {default as Moment} from './Moment';
+export {default as TagFriendsFooter} from './TagFriendsFoooter';
diff --git a/src/components/profile/ProfilePreview.tsx b/src/components/profile/ProfilePreview.tsx
index 66d68d8f..88c075e2 100644
--- a/src/components/profile/ProfilePreview.tsx
+++ b/src/components/profile/ProfilePreview.tsx
@@ -148,6 +148,14 @@ const ProfilePreview: React.FC<ProfilePreviewProps> = ({
usernameStyle = styles.discoverUsersUsername;
nameStyle = styles.discoverUsersName;
break;
+ case 'Tag Selection':
+ containerStyle = styles.tagSelectionContainer;
+ avatarStyle = styles.tagSelectionAvatar;
+ nameContainerStyle = styles.tagSelectionNameContainer;
+ usernameToDisplay = '@' + username;
+ usernameStyle = styles.tagSelectionUsername;
+ nameStyle = styles.tagSelectionName;
+ break;
case 'Comment':
containerStyle = styles.commentContainer;
avatarStyle = styles.commentAvatar;
@@ -195,10 +203,9 @@ const ProfilePreview: React.FC<ProfilePreviewProps> = ({
<Text style={nameStyle}>{first_name.concat(' ', last_name)}</Text>
</>
)}
- {previewType === 'Comment' && (
- <Text style={usernameStyle}>{usernameToDisplay}</Text>
- )}
- {previewType === 'Discover Users' && (
+ {(previewType === 'Discover Users' ||
+ previewType === 'Tag Selection' ||
+ previewType === 'Comment') && (
<>
<Text style={usernameStyle}>{usernameToDisplay}</Text>
</>
@@ -368,6 +375,35 @@ const styles = StyleSheet.create({
marginRight: 15,
borderRadius: 50,
},
+ tagSelectionContainer: {
+ width: 60,
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'flex-start',
+ margin: '1%',
+ },
+ tagSelectionAvatar: {
+ width: 34,
+ height: 34,
+ borderRadius: 20,
+ },
+ tagSelectionNameContainer: {
+ width: '100%',
+ marginVertical: '10%',
+ },
+ tagSelectionUsername: {
+ fontWeight: '500',
+ fontSize: normalize(9),
+ lineHeight: normalize(10),
+ letterSpacing: normalize(0.2),
+ color: 'white',
+ textAlign: 'center',
+ },
+ tagSelectionName: {
+ fontWeight: '500',
+ fontSize: 8,
+ color: 'white',
+ },
});
export default ProfilePreview;
diff --git a/src/components/search/SearchBar.tsx b/src/components/search/SearchBar.tsx
index 25ea3b59..a17d0695 100644
--- a/src/components/search/SearchBar.tsx
+++ b/src/components/search/SearchBar.tsx
@@ -21,10 +21,10 @@ import {getSearchSuggestions, normalize} from '../../utils';
const AnimatedIcon = Animated.createAnimatedComponent(Icon);
interface SearchBarProps extends TextInputProps {
- onCancel: () => void;
- animationProgress: Animated.SharedValue<number>;
- searching: boolean;
- onLayout: (e: LayoutChangeEvent) => void;
+ onCancel?: () => void;
+ animationProgress?: Animated.SharedValue<number>;
+ searching?: boolean;
+ onLayout?: (e: LayoutChangeEvent) => void;
}
const SearchBar: React.FC<SearchBarProps> = ({
onFocus,
@@ -113,8 +113,8 @@ const SearchBar: React.FC<SearchBarProps> = ({
* On-search marginRight style ("cancel" button slides and fades in).
*/
const animatedStyles = useAnimatedStyle<ViewStyle>(() => ({
- marginRight: animationProgress.value * 58,
- opacity: animationProgress.value,
+ marginRight: (animationProgress ? animationProgress.value : 0) * 58,
+ opacity: animationProgress ? animationProgress.value : 0,
}));
return (
@@ -136,11 +136,13 @@ const SearchBar: React.FC<SearchBarProps> = ({
{...{placeholder, value, onChangeText, onFocus, onBlur}}
/>
</Animated.View>
- <Animated.View style={animatedStyles}>
- <TouchableOpacity style={styles.cancelButton} onPress={onCancel}>
- <Text style={styles.cancelText}>Cancel</Text>
- </TouchableOpacity>
- </Animated.View>
+ {onCancel && (
+ <Animated.View style={animatedStyles}>
+ <TouchableOpacity style={styles.cancelButton} onPress={onCancel}>
+ <Text style={styles.cancelText}>Cancel</Text>
+ </TouchableOpacity>
+ </Animated.View>
+ )}
</View>
);
};