diff options
Diffstat (limited to 'src/components')
-rw-r--r-- | src/components/common/TaggRadioButton.tsx | 53 | ||||
-rw-r--r-- | src/components/common/TaggUserSelectionCell.tsx | 73 | ||||
-rw-r--r-- | src/components/common/index.ts | 1 | ||||
-rw-r--r-- | src/components/moments/TagFriendsFoooter.tsx | 132 | ||||
-rw-r--r-- | src/components/moments/index.ts | 1 | ||||
-rw-r--r-- | src/components/profile/ProfilePreview.tsx | 44 | ||||
-rw-r--r-- | src/components/search/SearchBar.tsx | 24 |
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> ); }; |