aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/assets/icons/tag_indicate.pngbin0 -> 101301 bytes
-rw-r--r--src/components/common/Draggable.tsx34
-rw-r--r--src/components/common/MomentTags.tsx100
-rw-r--r--src/components/common/TaggUserSelectionCell.tsx37
-rw-r--r--src/components/moments/MomentPostContent.tsx21
-rw-r--r--src/components/moments/TagFriendsFoooter.tsx130
-rw-r--r--src/components/profile/ProfilePreview.tsx4
-rw-r--r--src/components/suggestedPeople/BadgeIcon.tsx64
-rw-r--r--src/components/suggestedPeople/index.ts2
-rw-r--r--src/components/suggestedPeople/legacy/BadgesDropdown.tsx (renamed from src/components/suggestedPeople/BadgesDropdown.tsx)68
-rw-r--r--src/components/taggs/TaggDraggable.tsx17
-rw-r--r--src/routes/main/MainStackNavigator.tsx20
-rw-r--r--src/screens/moments/TagFriendsScreen.tsx33
-rw-r--r--src/screens/moments/TagSelectionScreen.tsx20
-rw-r--r--src/screens/profile/CaptionScreen.tsx27
-rw-r--r--src/screens/suggestedPeople/SPBody.tsx88
-rw-r--r--src/services/MomentService.ts16
-rw-r--r--src/services/SearchService.ts9
-rw-r--r--src/types/types.ts1
-rw-r--r--src/utils/search.ts2
20 files changed, 409 insertions, 284 deletions
diff --git a/src/assets/icons/tag_indicate.png b/src/assets/icons/tag_indicate.png
new file mode 100644
index 00000000..7947aef7
--- /dev/null
+++ b/src/assets/icons/tag_indicate.png
Binary files differ
diff --git a/src/components/common/Draggable.tsx b/src/components/common/Draggable.tsx
index edd29b78..15ba3325 100644
--- a/src/components/common/Draggable.tsx
+++ b/src/components/common/Draggable.tsx
@@ -59,7 +59,7 @@ interface IProps {
minY?: number;
maxX?: number;
maxY?: number;
- onDragStart?: () => void;
+ onDragStart?: () => number;
}
export default function Draggable(props: IProps) {
@@ -103,8 +103,8 @@ export default function Draggable(props: IProps) {
// Whether we're currently dragging or not
const isDragging = React.useRef(false);
- // const [zIndex, setZIndex] = React.useState(z);
- const zIndex = z;
+ const [zIndex, setZIndex] = React.useState(z);
+ // const zIndex = z;
const getBounds = React.useCallback(() => {
const left = x + offsetFromStart.current.x;
@@ -136,7 +136,9 @@ export default function Draggable(props: IProps) {
isDragging.current = false;
if (onDragRelease) {
onDragRelease(e, gestureState);
- onRelease(e, true);
+ }
+ if (onRelease) {
+ onRelease(e, gestureState);
}
if (!shouldReverse) {
pan.current.flattenOffset();
@@ -147,18 +149,17 @@ export default function Draggable(props: IProps) {
[onDragRelease, shouldReverse, onRelease, reversePosition],
);
- const onPanResponderGrant = React.useCallback(
- (_: GestureResponderEvent) => {
- startBounds.current = getBounds();
- isDragging.current = true;
- if (!shouldReverse) {
- pan.current.setOffset(offsetFromStart.current);
- pan.current.setValue({x: 0, y: 0});
- }
- onDragStart();
- },
- [getBounds, shouldReverse],
- );
+ const onPanResponderGrant = (_: GestureResponderEvent) => {
+ startBounds.current = getBounds();
+ isDragging.current = true;
+ if (!shouldReverse) {
+ pan.current.setOffset(offsetFromStart.current);
+ pan.current.setValue({x: 0, y: 0});
+ }
+ if (onDragStart) {
+ setZIndex(onDragStart());
+ }
+ };
const handleOnDrag = React.useCallback(
(e: GestureResponderEvent, gestureState: PanResponderGestureState) => {
@@ -194,6 +195,7 @@ export default function Draggable(props: IProps) {
listener: handleOnDrag,
useNativeDriver: false,
}),
+ onPanResponderRelease,
// onPanResponderRelease: (_) => {
// // console.log('end');
// // setZIndex(1);
diff --git a/src/components/common/MomentTags.tsx b/src/components/common/MomentTags.tsx
index defd4b4b..bdd1fbeb 100644
--- a/src/components/common/MomentTags.tsx
+++ b/src/components/common/MomentTags.tsx
@@ -1,4 +1,4 @@
-import React, {MutableRefObject, useEffect, useState} from 'react';
+import React, {createRef, MutableRefObject, useEffect, useState} from 'react';
import {MomentTagType, ProfilePreviewType} from '../../types';
import TaggDraggable from '../taggs/TaggDraggable';
import Draggable from './Draggable';
@@ -6,6 +6,7 @@ import Draggable from './Draggable';
interface MomentTagsProps {
editing: boolean;
tags: MomentTagType[];
+ setTags: (tag: MomentTagType[]) => void;
imageRef: MutableRefObject<null>;
deleteFromList?: (user: ProfilePreviewType) => void;
}
@@ -13,60 +14,127 @@ interface MomentTagsProps {
const MomentTags: React.FC<MomentTagsProps> = ({
editing,
tags,
+ setTags,
imageRef,
deleteFromList,
}) => {
const [offset, setOffset] = useState([0, 0]);
- const [curStart, setCurStart] = useState([0, 0]);
const [imageDimensions, setImageDimensions] = useState([0, 0]);
+ const [maxZIndex, setMaxZIndex] = useState(1);
+ const [draggableRefs, setDraggableRefs] = useState<
+ React.MutableRefObject<null>[]
+ >([]);
+
+ const updateTagPosition = (
+ ref: React.MutableRefObject<null>,
+ userId: string,
+ ) => {
+ if (ref !== null && ref.current !== null) {
+ ref.current.measure(
+ (
+ _fx: number, // location of ref relative to parent element
+ _fy: number,
+ _width: number,
+ _height: number,
+ px: number, // location of ref relative to entire screen
+ py: number,
+ ) => {
+ const x = ((px - offset[0]) / imageDimensions[0]) * 100;
+ const y = ((py - offset[1]) / imageDimensions[1]) * 100;
+ setTags(
+ tags.map((tag) =>
+ tag.user.id === userId
+ ? {
+ id: '',
+ x,
+ y,
+ z: maxZIndex - 1, // TODO: change this
+ user: tag.user,
+ }
+ : tag,
+ ),
+ );
+ },
+ );
+ }
+ };
+
+ useEffect(() => {
+ setDraggableRefs(tags.map((_) => createRef()));
+ }, [tags]);
useEffect(() => {
- imageRef.current.measure((fx, fy, width, height, px, py) => {
- setOffset([px, py]);
- setImageDimensions([width, height]);
- });
+ setTimeout(
+ () => {
+ imageRef.current.measure(
+ (
+ fx: number, // location of ref relative to parent element
+ fy: number,
+ width: number,
+ height: number,
+ _x: number, // location of ref relative to entire screen
+ _y: number,
+ ) => {
+ setOffset([fx, fy]);
+ setImageDimensions([width, height]);
+ },
+ );
+ },
+ editing ? 100 : 0,
+ );
}, []);
if (!tags) {
return null;
}
+
return editing && deleteFromList ? (
<>
- {tags.map((tag) => (
+ {tags.map((tag, index) => (
<Draggable
- x={imageDimensions[0] / 2 - curStart[0] / 2 + offset[0]}
- y={offset[1] + imageDimensions[1] / 2 - curStart[1] / 2}
+ key={tag.user.id + tag.x + tag.y}
+ x={(imageDimensions[0] * tag.x) / 100 + offset[0]}
+ y={(imageDimensions[1] * tag.y) / 100 + offset[1]}
+ z={tag.z}
minX={offset[0]}
minY={offset[1]}
maxX={imageDimensions[0] + offset[0]}
maxY={imageDimensions[1] + offset[1]}
- onDragStart={() => null}>
+ onDragStart={() => {
+ const currZIndex = maxZIndex;
+ setMaxZIndex(currZIndex + 1);
+ return currZIndex;
+ }}
+ onDragRelease={() =>
+ updateTagPosition(draggableRefs[index], tag.user.id)
+ }>
<TaggDraggable
+ draggableRef={draggableRefs[index]}
taggedUser={tag.user}
editingView={true}
deleteFromList={() => deleteFromList(tag.user)}
- setStart={setCurStart}
/>
</Draggable>
))}
</>
) : (
<>
- {tags.map((tag) => (
+ {tags.map((tag, index) => (
<Draggable
- x={imageDimensions[0] / 2 - curStart[0] / 2 + tag.x}
- y={imageDimensions[0] / 2 - curStart[0] / 2 + tag.y}
+ key={tag.user.id}
+ x={(imageDimensions[0] * tag.x) / 100 + offset[0]}
+ y={(imageDimensions[1] * tag.y) / 100 + offset[1]}
+ z={tag.z}
minX={offset[0]}
minY={offset[1]}
maxX={imageDimensions[0] + offset[0]}
maxY={imageDimensions[1] + offset[1]}
- onDragStart={() => null}
disabled={true}>
<TaggDraggable
+ draggableRef={draggableRefs[index]}
taggedUser={tag.user}
editingView={editing}
deleteFromList={() => null}
- setStart={setCurStart}
/>
</Draggable>
))}
diff --git a/src/components/common/TaggUserSelectionCell.tsx b/src/components/common/TaggUserSelectionCell.tsx
index 2ea1e4ce..72c98822 100644
--- a/src/components/common/TaggUserSelectionCell.tsx
+++ b/src/components/common/TaggUserSelectionCell.tsx
@@ -1,19 +1,20 @@
import React, {useEffect, useState} from 'react';
import {StyleSheet, View} from 'react-native';
+import {TouchableWithoutFeedback} from 'react-native-gesture-handler';
import {ProfilePreview} from '..';
-import {ProfilePreviewType, ScreenType} from '../../types';
+import {MomentTagType, ProfilePreviewType, ScreenType} from '../../types';
import {SCREEN_WIDTH} from '../../utils';
import TaggRadioButton from './TaggRadioButton';
interface TaggUserSelectionCellProps {
item: ProfilePreviewType;
- selectedUsers: ProfilePreviewType[];
- setSelectedUsers: Function;
+ tags: MomentTagType[];
+ setTags: (tags: MomentTagType[]) => void;
}
const TaggUserSelectionCell: React.FC<TaggUserSelectionCellProps> = ({
item,
- selectedUsers,
- setSelectedUsers,
+ tags,
+ setTags,
}) => {
const [pressed, setPressed] = useState<boolean>(false);
@@ -22,9 +23,7 @@ const TaggUserSelectionCell: React.FC<TaggUserSelectionCellProps> = ({
*/
useEffect(() => {
const updatePressed = () => {
- const userSelected = selectedUsers.findIndex(
- (selectedUser) => item.id === selectedUser.id,
- );
+ const userSelected = tags.findIndex((tag) => item.id === tag.user.id);
setPressed(userSelected !== -1);
};
updatePressed();
@@ -37,18 +36,24 @@ const TaggUserSelectionCell: React.FC<TaggUserSelectionCellProps> = ({
const handlePress = () => {
// Add to selected list of users
if (pressed === false) {
- setSelectedUsers([...selectedUsers, item]);
+ setTags([
+ ...tags,
+ {
+ id: '',
+ x: 50,
+ y: 50,
+ z: 1,
+ user: item,
+ },
+ ]);
}
// Remove item from selected list of users
else {
- const filteredSelection = selectedUsers.filter(
- (user) => user.id !== item.id,
- );
- setSelectedUsers(filteredSelection);
+ setTags(tags.filter((tag) => tag.user.id !== item.id));
}
};
return (
- <View style={styles.container}>
+ <TouchableWithoutFeedback onPress={handlePress} style={styles.container}>
<View style={{width: SCREEN_WIDTH * 0.8}}>
<ProfilePreview
profilePreview={item}
@@ -56,8 +61,8 @@ const TaggUserSelectionCell: React.FC<TaggUserSelectionCellProps> = ({
screenType={ScreenType.Profile}
/>
</View>
- <TaggRadioButton pressed={pressed} onPress={handlePress} />
- </View>
+ <TaggRadioButton pressed={pressed} onPress={() => null} />
+ </TouchableWithoutFeedback>
);
};
diff --git a/src/components/moments/MomentPostContent.tsx b/src/components/moments/MomentPostContent.tsx
index c3cb03f5..f485396f 100644
--- a/src/components/moments/MomentPostContent.tsx
+++ b/src/components/moments/MomentPostContent.tsx
@@ -43,6 +43,8 @@ const MomentPostContent: React.FC<MomentPostContentProps> = ({
const navigation = useNavigation();
const dispatch = useDispatch();
const imageRef = useRef(null);
+ const [fadeValue, setFadeValue] = useState(new Animated.Value(0));
+ const [visible, setVisible] = useState(false);
const [fadeValue, setFadeValue] = useState<Animated.Value<number>>(
new Animated.Value(0),
@@ -85,6 +87,12 @@ const MomentPostContent: React.FC<MomentPostContentProps> = ({
source={{uri: pathHash}}
resizeMode={'cover'}
/>
+ {tags.length > 0 && (
+ <Image
+ source={require('../../assets/icons/tag_indicate.png')}
+ style={[styles.tagIcon]}
+ />
+ )}
</TouchableWithoutFeedback>
{visible && (
<Animated.View style={[styles.tapTag, {opacity: fadeValue}]}>
@@ -119,9 +127,6 @@ const styles = StyleSheet.create({
aspectRatio: 1,
marginBottom: '3%',
},
- tapTag: {
- position: 'absolute',
- },
footerContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
@@ -150,5 +155,15 @@ const styles = StyleSheet.create({
lineHeight: normalize(15.51),
letterSpacing: normalize(0.6),
},
+ tapTag: {
+ position: 'absolute',
+ },
+ tagIcon: {
+ width: normalize(30),
+ height: normalize(30),
+ position: 'absolute',
+ bottom: '7%',
+ left: normalize(20),
+ },
});
export default MomentPostContent;
diff --git a/src/components/moments/TagFriendsFoooter.tsx b/src/components/moments/TagFriendsFoooter.tsx
index 7b109877..365d709d 100644
--- a/src/components/moments/TagFriendsFoooter.tsx
+++ b/src/components/moments/TagFriendsFoooter.tsx
@@ -1,39 +1,47 @@
import {useNavigation} from '@react-navigation/native';
-import React, {Dispatch, SetStateAction} from 'react';
-import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
+import React, {useMemo} from 'react';
+import {
+ Image,
+ ScrollView,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ View,
+} from 'react-native';
import {ProfilePreview} from '..';
-import {ProfilePreviewType, ScreenType} from '../../types';
-import {normalize} from '../../utils/layouts';
+import {MomentTagType, ProfilePreviewType, ScreenType} from '../../types';
+import {normalize, SCREEN_HEIGHT} from '../../utils/layouts';
interface TagFriendsFooterProps {
- taggedUsers: ProfilePreviewType[];
- setTaggedUsers: Dispatch<SetStateAction<ProfilePreviewType[]>>;
+ tags: MomentTagType[];
+ setTags: (tags: MomentTagType[]) => void;
}
-const TagFriendsFooter: React.FC<TagFriendsFooterProps> = ({
- taggedUsers,
- setTaggedUsers,
-}) => {
+const TagFriendsFooter: React.FC<TagFriendsFooterProps> = ({tags, setTags}) => {
const navigation = useNavigation();
const handleRemoveTag = (user: ProfilePreviewType) => {
- const filteredSelection = taggedUsers.filter((item) => user.id !== item.id);
- setTaggedUsers(filteredSelection);
+ setTags(tags.filter((tag) => tag.user.id !== user.id));
};
- const TaggMoreButton = () => (
- <TouchableOpacity
- onPress={() =>
- navigation.navigate('TagSelectionScreen', {
- selectedUsers: taggedUsers,
- })
- }
- style={styles.tagMoreContainer}>
- <Image
- source={require('../../assets/icons/tagging/white-plus-icon.png')}
- style={styles.tagMoreIcon}
- />
- <Text style={styles.tagMoreLabel}>{'Tagg More'}</Text>
- </TouchableOpacity>
+ const goToSelectionScreen = () => {
+ navigation.navigate('TagSelectionScreen', {
+ selectedTags: tags,
+ });
+ };
+
+ const taggMoreButton = useMemo(
+ () => (
+ <TouchableOpacity
+ onPress={goToSelectionScreen}
+ style={styles.tagMoreContainer}>
+ <Image
+ source={require('../../assets/icons/tagging/white-plus-icon.png')}
+ style={styles.tagMoreIcon}
+ />
+ <Text style={styles.tagMoreLabel}>{'Tagg More'}</Text>
+ </TouchableOpacity>
+ ),
+ [tags],
);
const TaggedUser = (user: ProfilePreviewType) => (
@@ -59,31 +67,36 @@ const TagFriendsFooter: React.FC<TagFriendsFooterProps> = ({
* If taggUsers is empty, title acts as a button
* Else, gets disabled and TaggMore button appears
*/
- const TagFriendsTitle = () => (
- <TouchableOpacity
- style={styles.tagFriendsTitleContainer}
- 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>
+ const tagFriendsTitle = useMemo(
+ () => (
+ <TouchableOpacity
+ style={styles.tagFriendsTitleContainer}
+ disabled={tags.length !== 0}
+ onPress={() =>
+ navigation.navigate('TagSelectionScreen', {
+ selectedTags: tags,
+ })
+ }>
+ <Image
+ source={require('../../assets/icons/tagging/tag-icon.png')}
+ style={styles.tagIcon}
+ />
+ <Text style={styles.tagFriendsTitle}>Tag Friends</Text>
+ </TouchableOpacity>
+ ),
+ [tags.length],
);
return (
<>
- <TagFriendsTitle />
+ {tagFriendsTitle}
<View style={styles.tagFriendsContainer}>
- {taggedUsers.map((user) => (
- <TaggedUser {...user} />
- ))}
- {taggedUsers.length !== 0 && <TaggMoreButton />}
+ <ScrollView horizontal>
+ {tags.map((tag) => (
+ <TaggedUser key={tag.user.id} {...tag.user} />
+ ))}
+ {tags.length !== 0 && taggMoreButton}
+ </ScrollView>
</View>
</>
);
@@ -99,10 +112,9 @@ const styles = StyleSheet.create({
fontWeight: '600',
},
tagFriendsContainer: {
- flexDirection: 'row',
- marginTop: '3%',
- flexWrap: 'wrap',
- justifyContent: 'flex-start',
+ height: SCREEN_HEIGHT * 0.1,
+ marginTop: 2,
+ marginBottom: 5,
},
tagMoreLabel: {
fontWeight: '500',
@@ -111,7 +123,6 @@ const styles = StyleSheet.create({
letterSpacing: normalize(0.2),
color: 'white',
textAlign: 'center',
- marginVertical: '5%',
},
closeIconContainer: {
width: 20,
@@ -120,14 +131,25 @@ const styles = StyleSheet.create({
zIndex: 1,
},
tagMoreContainer: {
- flexDirection: 'column',
+ width: 60,
alignItems: 'center',
+ justifyContent: 'flex-start',
+ marginTop: -12,
+ },
+ tagMoreIcon: {
+ width: 38,
+ height: 38,
+ marginTop: 13,
+ marginBottom: '10%',
+ },
+ taggedUserContainer: {
+ marginTop: -12,
},
- tagMoreIcon: {width: 38, height: 38, top: -2},
- taggedUserContainer: {flexDirection: 'row-reverse'},
closeIcon: {
width: 20,
height: 20,
+ left: 15,
+ top: 10,
},
tagFriendsTitleContainer: {
flexDirection: 'row',
diff --git a/src/components/profile/ProfilePreview.tsx b/src/components/profile/ProfilePreview.tsx
index 88c075e2..dd93a5fd 100644
--- a/src/components/profile/ProfilePreview.tsx
+++ b/src/components/profile/ProfilePreview.tsx
@@ -377,10 +377,8 @@ const styles = StyleSheet.create({
},
tagSelectionContainer: {
width: 60,
- flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
- margin: '1%',
},
tagSelectionAvatar: {
width: 34,
@@ -389,7 +387,7 @@ const styles = StyleSheet.create({
},
tagSelectionNameContainer: {
width: '100%',
- marginVertical: '10%',
+ marginVertical: normalize(5),
},
tagSelectionUsername: {
fontWeight: '500',
diff --git a/src/components/suggestedPeople/BadgeIcon.tsx b/src/components/suggestedPeople/BadgeIcon.tsx
new file mode 100644
index 00000000..8f576a43
--- /dev/null
+++ b/src/components/suggestedPeople/BadgeIcon.tsx
@@ -0,0 +1,64 @@
+import {useNavigation} from '@react-navigation/core';
+import React from 'react';
+import {
+ Image,
+ ImageSourcePropType,
+ StyleProp,
+ StyleSheet,
+ ViewStyle,
+} from 'react-native';
+import {TouchableOpacity} from 'react-native-gesture-handler';
+import LinearGradient from 'react-native-linear-gradient';
+import {UniversityBadge} from '../../types';
+import {normalize} from '../../utils';
+
+interface BadgeIconProps {
+ badge: UniversityBadge;
+ img: ImageSourcePropType;
+ style?: StyleProp<ViewStyle>;
+}
+
+const BadgeIcon: React.FC<BadgeIconProps> = ({badge, img, style}) => {
+ const navigation = useNavigation();
+ return (
+ <TouchableOpacity
+ style={[styles.badgeButton, style]}
+ onPress={() => {
+ navigation.navigate('MutualBadgeHolders', {
+ badge_id: badge.id,
+ badge_title: badge.name,
+ badge_img: img,
+ });
+ }}>
+ <LinearGradient
+ colors={['#4E3629', '#EC2027']}
+ useAngle={true}
+ angle={154.72}
+ angleCenter={{x: 0.5, y: 0.5}}
+ style={styles.badgeBackground}>
+ <Image source={img} style={styles.icon} />
+ </LinearGradient>
+ </TouchableOpacity>
+ );
+};
+
+const styles = StyleSheet.create({
+ badgeBackground: {
+ width: '100%',
+ height: '100%',
+ borderRadius: 50,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ badgeButton: {
+ width: normalize(30),
+ height: normalize(30),
+ borderRadius: 30,
+ },
+ icon: {
+ width: '60%',
+ height: '60%',
+ },
+});
+
+export default BadgeIcon;
diff --git a/src/components/suggestedPeople/index.ts b/src/components/suggestedPeople/index.ts
index 339c9ae0..34bb96d4 100644
--- a/src/components/suggestedPeople/index.ts
+++ b/src/components/suggestedPeople/index.ts
@@ -1,3 +1,3 @@
export {default as MutualFriends} from './MutualFriends';
-export {default as BadgesDropdown} from './BadgesDropdown';
export {default as SPTaggsBar} from './SPTaggsBar';
+export {default as BadgeIcon} from './BadgeIcon';
diff --git a/src/components/suggestedPeople/BadgesDropdown.tsx b/src/components/suggestedPeople/legacy/BadgesDropdown.tsx
index bc4e7a54..267355f3 100644
--- a/src/components/suggestedPeople/BadgesDropdown.tsx
+++ b/src/components/suggestedPeople/legacy/BadgesDropdown.tsx
@@ -1,39 +1,35 @@
-import {useNavigation} from '@react-navigation/native';
import React, {useEffect, useState} from 'react';
-import {Image, StyleSheet} from 'react-native';
+import {ImageSourcePropType, StyleSheet} from 'react-native';
import {TouchableOpacity} from 'react-native-gesture-handler';
-import LinearGradient from 'react-native-linear-gradient';
import Animated, {Easing} from 'react-native-reanimated';
-import {UniversityType, UniversityBadge} from '../../types';
-import {UniversityIcon} from '..';
-import {normalize, SCREEN_WIDTH} from '../../utils';
-import UniversityIconClicked from './UniversityIconClicked';
+import {BadgeIcon, UniversityIcon} from '../..';
+import {UniversityBadge, UniversityType} from '../../../types';
+import {normalize} from '../../../utils';
+import UniversityIconClicked from '../UniversityIconClicked';
+
interface BadgesDropdownProps {
university: UniversityType;
localBadges: {
badge: UniversityBadge;
- img: string;
+ img: ImageSourcePropType;
}[];
- badges: UniversityBadge[];
}
const BadgesDropdown: React.FC<BadgesDropdownProps> = ({
university,
localBadges,
- badges,
}) => {
// Used to toggle between dropdown being displayed and not
const [displayBadges, setDisplayBadges] = useState<boolean>(false);
// Determines the absolute position of the individual badges [0, i * 40]
let [top, setTop] = useState<Animated.Value<number>[]>([]);
- const navigation = useNavigation();
useEffect(() => {
// Initialize position of badges to 0
const defineBadgePositions = () => {
let localTop: Animated.Value<number>[] = [];
- badges.forEach(() => {
+ localBadges.forEach(() => {
localTop.push(new Animated.Value(0));
});
setTop(localTop);
@@ -43,7 +39,7 @@ const BadgesDropdown: React.FC<BadgesDropdownProps> = ({
// Displays badges dropdown by updating top [state] for every badge
const animate = () => {
- for (let i = 0; i < badges?.length; i++) {
+ for (let i = 0; i < localBadges?.length; i++) {
if (top) {
Animated.timing(top[i], {
toValue: i * 40 + 50,
@@ -56,7 +52,7 @@ const BadgesDropdown: React.FC<BadgesDropdownProps> = ({
// Draws back displayed badges by setting top [state] to 0 for every badge
const animateBack = () => {
- for (let i = 0; i < badges?.length; i++) {
+ for (let i = 0; i < localBadges?.length; i++) {
if (top) {
Animated.timing(top[i], {
toValue: 0,
@@ -106,30 +102,7 @@ const BadgesDropdown: React.FC<BadgesDropdownProps> = ({
zIndex: -1 * badge.id,
},
]}>
- <TouchableOpacity
- style={styles.badgeButton}
- onPress={() => {
- navigation.navigate('MutualBadgeHolders', {
- badge_id: badge.id,
- badge_title: badge.name,
- badge_img: img,
- });
- }}>
- <LinearGradient
- colors={['#4E3629', '#EC2027']}
- useAngle={true}
- angle={154.72}
- angleCenter={{x: 0.5, y: 0.5}}
- style={styles.badgeBackground}>
- <Image
- source={img}
- style={{
- width: SCREEN_WIDTH * 0.04,
- height: SCREEN_WIDTH * 0.04,
- }}
- />
- </LinearGradient>
- </TouchableOpacity>
+ <BadgeIcon badge={badge} img={img} />
</Animated.View>
))}
</Animated.View>
@@ -137,18 +110,6 @@ const BadgesDropdown: React.FC<BadgesDropdownProps> = ({
};
const styles = StyleSheet.create({
- badgeBackground: {
- position: 'absolute',
- width: '100%',
- height: '100%',
- borderRadius: 50,
- borderColor: 'transparent',
- borderWidth: 1,
- alignSelf: 'center',
- flexDirection: 'row',
- justifyContent: 'center',
- alignItems: 'center',
- },
badgesContainer: {
flexDirection: 'column',
justifyContent: 'space-between',
@@ -157,12 +118,9 @@ const styles = StyleSheet.create({
left: '5%',
paddingBottom: '2%',
},
- badgeButton: {
- width: 30,
- height: 30,
- borderRadius: 15,
+ animatedBadgeView: {
+ position: 'absolute',
},
- animatedBadgeView: {position: 'absolute'},
universityIconContainer: {
width: normalize(31),
height: normalize(38),
diff --git a/src/components/taggs/TaggDraggable.tsx b/src/components/taggs/TaggDraggable.tsx
index 12e8e1e1..d458fab6 100644
--- a/src/components/taggs/TaggDraggable.tsx
+++ b/src/components/taggs/TaggDraggable.tsx
@@ -1,5 +1,5 @@
import {useNavigation} from '@react-navigation/native';
-import React, {useEffect, useRef} from 'react';
+import React from 'react';
import {
Image,
StyleSheet,
@@ -7,6 +7,7 @@ import {
TouchableOpacity,
TouchableWithoutFeedback,
View,
+ ViewProps,
} from 'react-native';
import {useDispatch, useSelector} from 'react-redux';
import Avatar from '../../components/common/Avatar';
@@ -15,31 +16,23 @@ import {ProfilePreviewType, ScreenType, UserType} from '../../types';
import {normalize} from '../../utils';
import {navigateToProfile} from '../../utils/users';
-interface TaggDraggableProps {
+interface TaggDraggableProps extends ViewProps {
+ draggableRef: React.MutableRefObject<null>;
taggedUser: ProfilePreviewType;
editingView: boolean;
deleteFromList: () => void;
- setStart: Function;
}
const TaggDraggable: React.FC<TaggDraggableProps> = (
props: TaggDraggableProps,
) => {
+ const {draggableRef, taggedUser, editingView, deleteFromList} = props;
const navigation = useNavigation();
const dispatch = useDispatch();
const state = useSelector((rs: RootState) => rs);
- const {taggedUser, editingView, deleteFromList, setStart} = props;
let uriX = require('../../assets/images/draggableX.png');
let uriTip = require('../../assets/images/Tagg-Triangle.png');
- const draggableRef = useRef(null);
-
- useEffect(() => {
- draggableRef.current.measure((width: number, height: number) => {
- setStart([width, height]);
- });
- }, []);
-
const user: UserType = {
userId: taggedUser.id,
username: taggedUser.username,
diff --git a/src/routes/main/MainStackNavigator.tsx b/src/routes/main/MainStackNavigator.tsx
index aeead38d..d22c1874 100644
--- a/src/routes/main/MainStackNavigator.tsx
+++ b/src/routes/main/MainStackNavigator.tsx
@@ -5,8 +5,8 @@ import {createStackNavigator} from '@react-navigation/stack';
import {Image} from 'react-native-image-crop-picker';
import {
CommentBaseType,
+ MomentTagType,
MomentType,
- ProfilePreviewType,
ScreenType,
SearchCategoryType,
} from '../../types';
@@ -40,7 +40,15 @@ export type MainStackParams = {
title: string;
image: Image;
screenType: ScreenType;
- selectedUsers?: ProfilePreviewType[];
+ selectedTags?: MomentTagType[];
+ };
+ TagFriendsScreen: {
+ image: Image;
+ screenType: ScreenType;
+ selectedTags?: MomentTagType[];
+ };
+ TagSelectionScreen: {
+ selectedTags: MomentTagType[];
};
IndividualMoment: {
moment: MomentType;
@@ -99,14 +107,6 @@ export type MainStackParams = {
ChatList: undefined;
Chat: undefined;
NewChatModal: undefined;
- TagSelectionScreen: {
- selectedUsers: ProfilePreviewType[];
- };
- TagFriendsScreen: {
- image: Image;
- screenType: ScreenType;
- selectedUsers?: ProfilePreviewType[];
- };
};
export const MainStack = createStackNavigator<MainStackParams>();
diff --git a/src/screens/moments/TagFriendsScreen.tsx b/src/screens/moments/TagFriendsScreen.tsx
index b2a8586a..d960f3b9 100644
--- a/src/screens/moments/TagFriendsScreen.tsx
+++ b/src/screens/moments/TagFriendsScreen.tsx
@@ -19,7 +19,7 @@ import {
} from '../../components';
import {TagFriendsFooter} from '../../components/moments';
import {TAGG_LIGHT_BLUE_2} from '../../constants';
-import {ProfilePreviewType} from '../../types';
+import {MomentTagType} from '../../types';
import {SCREEN_WIDTH, StatusBarHeight} from '../../utils';
type TagFriendsScreenRouteProps = RouteProp<
@@ -30,19 +30,17 @@ interface TagFriendsScreenProps {
route: TagFriendsScreenRouteProps;
}
const TagFriendsScreen: React.FC<TagFriendsScreenProps> = ({route}) => {
- const {image, selectedUsers} = route.params;
+ const {image, selectedTags} = route.params;
const navigation = useNavigation();
const imageRef = useRef(null);
- const [taggedUsers, setTaggedUsers] = useState<ProfilePreviewType[]>([]);
+ const [tags, setTags] = useState<MomentTagType[]>([]);
/*
* Update list of tagged users from route params
*/
useEffect(() => {
- if (selectedUsers !== undefined) {
- setTaggedUsers(selectedUsers);
- }
- }, [selectedUsers]);
+ setTags(selectedTags ? selectedTags : []);
+ }, [selectedTags]);
/*
* Navigate back to Tag Users Screen, send selected users
@@ -50,7 +48,7 @@ const TagFriendsScreen: React.FC<TagFriendsScreenProps> = ({route}) => {
const handleDone = () => {
navigation.navigate('CaptionScreen', {
...route.params,
- selectedUsers: taggedUsers,
+ selectedTags: tags,
});
};
@@ -79,7 +77,7 @@ const TagFriendsScreen: React.FC<TagFriendsScreenProps> = ({route}) => {
title={'Tap on photo to Tag friends!'}
/>
<TouchableWithoutFeedback
- disabled={taggedUsers.length > 0}
+ disabled={tags.length > 0}
onPress={() =>
navigation.navigate('TagSelectionScreen', {
selectedUsers: [],
@@ -92,26 +90,19 @@ const TagFriendsScreen: React.FC<TagFriendsScreenProps> = ({route}) => {
resizeMode={'cover'}
/>
</TouchableWithoutFeedback>
- {taggedUsers.length !== 0 && (
+ {tags.length !== 0 && (
<MomentTags
+ tags={tags}
+ setTags={setTags}
editing={true}
- tags={taggedUsers.map((user) => ({
- id: '',
- x: 0,
- y: 0,
- user,
- }))}
imageRef={imageRef}
deleteFromList={(user) =>
- setTaggedUsers(taggedUsers.filter((u) => u.id !== user.id))
+ setTags(tags.filter((tag) => tag.user.id !== user.id))
}
/>
)}
<View style={styles.footerContainer}>
- <TagFriendsFooter
- taggedUsers={taggedUsers}
- setTaggedUsers={setTaggedUsers}
- />
+ <TagFriendsFooter tags={tags} setTags={setTags} />
</View>
</View>
</KeyboardAvoidingView>
diff --git a/src/screens/moments/TagSelectionScreen.tsx b/src/screens/moments/TagSelectionScreen.tsx
index a698a07b..3177b638 100644
--- a/src/screens/moments/TagSelectionScreen.tsx
+++ b/src/screens/moments/TagSelectionScreen.tsx
@@ -9,7 +9,7 @@ import {SearchBar, TaggUserSelectionCell} from '../../components';
import {SEARCH_ENDPOINT_MESSAGES} from '../../constants';
import {MainStackParams} from '../../routes';
import {loadSearchResults} from '../../services';
-import {ProfilePreviewType} from '../../types';
+import {MomentTagType, ProfilePreviewType} from '../../types';
import {
isIPhoneX,
loadTaggUserSuggestions,
@@ -30,9 +30,7 @@ interface TagSelectionScreenProps {
const TagSelectionScreen: React.FC<TagSelectionScreenProps> = ({route}) => {
const navigation = useNavigation();
const [users, setUsers] = useState<ProfilePreviewType[]>([]);
- const [selectedUsers, setSelectedUsers] = useState<ProfilePreviewType[]>(
- route.params.selectedUsers,
- );
+ const [tags, setTags] = useState<MomentTagType[]>(route.params.selectedTags);
const [searching, setSearching] = useState(false);
const [query, setQuery] = useState<string>('');
const [label, setLabel] = useState<string>('Recent');
@@ -48,7 +46,7 @@ const TagSelectionScreen: React.FC<TagSelectionScreenProps> = ({route}) => {
onPress={() => {
navigation.navigate('TagFriendsScreen', {
...route.params,
- selectedUsers: selectedUsers,
+ selectedTags: tags,
});
}}>
<BackIcon
@@ -67,12 +65,12 @@ const TagSelectionScreen: React.FC<TagSelectionScreenProps> = ({route}) => {
* that the loggedInUser might want to select
*/
const loadUsers = async () => {
- const data: ProfilePreviewType[] = await loadTaggUserSuggestions();
+ const data = await loadTaggUserSuggestions();
const filteredData: ProfilePreviewType[] = data.filter((user) => {
- const index = selectedUsers.findIndex((s) => s.id === user.id);
+ const index = tags.findIndex((tag) => tag.user.id === user.id);
return index === -1;
});
- setUsers([...filteredData, ...selectedUsers]);
+ setUsers([...filteredData, ...tags.map((tag) => tag.user)]);
};
/*
@@ -83,7 +81,7 @@ const TagSelectionScreen: React.FC<TagSelectionScreenProps> = ({route}) => {
const searchResults = await loadSearchResults(
`${SEARCH_ENDPOINT_MESSAGES}?query=${query}`,
);
- setUsers(searchResults?.users);
+ setUsers(searchResults ? searchResults.users : []);
} else {
setUsers([]);
}
@@ -130,8 +128,8 @@ const TagSelectionScreen: React.FC<TagSelectionScreenProps> = ({route}) => {
<TaggUserSelectionCell
key={item.item.id}
item={item.item}
- selectedUsers={selectedUsers}
- setSelectedUsers={setSelectedUsers}
+ tags={tags}
+ setTags={setTags}
/>
)}
/>
diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 43665428..8bffd82b 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -29,7 +29,7 @@ import {
updateProfileCompletionStage,
} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
-import {ProfilePreviewType} from '../../types';
+import {MomentTagType} from '../../types';
import {SCREEN_WIDTH, StatusBarHeight} from '../../utils';
import {mentionPartTypes} from '../../utils/comments';
@@ -47,26 +47,26 @@ interface CaptionScreenProps {
}
const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
- const {title, image, screenType, selectedUsers} = route.params;
+ const {title, image, screenType, selectedTags} = route.params;
const {
user: {userId},
} = useSelector((state: RootState) => state.user);
const dispatch = useDispatch();
const [caption, setCaption] = useState('');
const [loading, setLoading] = useState(false);
- const [taggedUsers, setTaggedUsers] = useState<ProfilePreviewType[]>([]);
+ const [tags, setTags] = useState<MomentTagType[]>([]);
const [taggedList, setTaggedList] = useState<string>('');
useEffect(() => {
- setTaggedUsers(selectedUsers ? selectedUsers : []);
- }, [route.params]);
+ setTags(selectedTags ? selectedTags : []);
+ }, [selectedTags]);
useEffect(() => {
const getTaggedUsersListString = () => {
let listString = '';
- for (let i = 0; i < taggedUsers.length; i++) {
+ for (let i = 0; i < tags.length; i++) {
if (listString.length < 21) {
- listString = listString.concat(`@${taggedUsers[i].username} `);
+ listString = listString.concat(`@${tags[i].user.username} `);
} else {
break;
}
@@ -74,7 +74,7 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
setTaggedList(listString);
};
getTaggedUsersListString();
- }, [taggedUsers]);
+ }, [tags]);
const navigateToProfile = () => {
//Since the logged In User is navigating to own profile, useXId is not required
@@ -115,10 +115,11 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
}
const momentTagResponse = await postMomentTags(
momentResponse.moment_id,
- taggedUsers.map((u, index) => ({
- x: index * 50 - 150,
- y: index * 50 - 150,
- user_id: u.id,
+ tags.map((tag) => ({
+ x: Math.floor(tag.x),
+ y: Math.floor(tag.y),
+ z: Math.floor(tag.z),
+ user_id: tag.user.id,
})),
);
if (!momentTagResponse) {
@@ -173,7 +174,7 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
navigation.navigate('TagFriendsScreen', {
image: image,
screenType: screenType,
- selectedUsers: taggedUsers,
+ selectedTags: tags,
})
}
style={styles.tagFriendsContainer}>
diff --git a/src/screens/suggestedPeople/SPBody.tsx b/src/screens/suggestedPeople/SPBody.tsx
index c22f8143..eb80da49 100644
--- a/src/screens/suggestedPeople/SPBody.tsx
+++ b/src/screens/suggestedPeople/SPBody.tsx
@@ -1,11 +1,11 @@
import {useNavigation} from '@react-navigation/native';
import React, {Fragment, useEffect, useMemo, useState} from 'react';
-import {StyleSheet, Text, View} from 'react-native';
+import {ImageSourcePropType, StyleSheet, Text, View} from 'react-native';
import {Image} from 'react-native-animatable';
import {TouchableOpacity} from 'react-native-gesture-handler';
import RequestedButton from '../../assets/ionicons/requested-button.svg';
-import {SPTaggsBar} from '../../components';
-import {BadgesDropdown, MutualFriends} from '../../components/suggestedPeople';
+import {UniversityIcon} from '../../components';
+import {BadgeIcon, MutualFriends} from '../../components/suggestedPeople';
import {BADGE_DATA} from '../../constants/badges';
import {
ProfilePreviewType,
@@ -28,7 +28,6 @@ const SPBody: React.FC<SPBodyProps> = ({
user,
university,
mutual_friends,
- social_links,
suggested_people_url,
friendship,
badges,
@@ -43,7 +42,7 @@ const SPBody: React.FC<SPBodyProps> = ({
const [localBadges, setLocalBadges] = useState<
{
badge: UniversityBadge;
- img: string;
+ img: ImageSourcePropType;
}[]
>([]);
const navigation = useNavigation();
@@ -116,21 +115,30 @@ const SPBody: React.FC<SPBodyProps> = ({
[suggested_people_url],
);
- const NamePlate = () => {
- return (
- <TouchableOpacity
- onPress={() => {
- navigation.navigate('Profile', {
- userXId: loggedInUserId === user.id ? undefined : user.id,
- screenType,
- });
- }}
- style={styles.nameInfoContainer}>
- <Text style={styles.firstName}>{user.first_name}</Text>
- <Text style={styles.username}>@{user.username}</Text>
- </TouchableOpacity>
- );
- };
+ const NamePlate = () => (
+ <TouchableOpacity
+ onPress={() => {
+ navigation.navigate('Profile', {
+ userXId: loggedInUserId === user.id ? undefined : user.id,
+ screenType,
+ });
+ }}>
+ <Text style={styles.firstName}>{user.first_name}</Text>
+ <Text style={styles.username}>@{user.username}</Text>
+ </TouchableOpacity>
+ );
+
+ const Badges = () => (
+ // Badges aligned left and spaced as if there are 5 items
+ <View style={styles.badgeContainer}>
+ {localBadges.map(({badge, img}, index) => (
+ <BadgeIcon key={index} badge={badge} img={img} style={styles.badge} />
+ ))}
+ {[0, 0, 0, 0, 0].splice(localBadges.length, 5).map((_, index) => (
+ <View key={index} style={styles.badge} />
+ ))}
+ </View>
+ );
return (
<View>
@@ -138,22 +146,20 @@ const SPBody: React.FC<SPBodyProps> = ({
<View style={styles.mainContainer}>
<View style={styles.topContainer}>
<Text style={styles.title}>{firstItem && 'Suggested People'}</Text>
- {localBadges && (
- <BadgesDropdown {...{university, localBadges, badges}} />
- )}
+ <UniversityIcon
+ university={university}
+ style={styles.universityIcon}
+ imageStyle={styles.universityIcon}
+ />
</View>
- <View style={styles.body}>
+ <View>
<View style={styles.marginManager}>
<View style={styles.addUserContainer}>
<NamePlate />
{user.id !== loggedInUserId && <FriendButton />}
</View>
</View>
- <SPTaggsBar
- userXId={user.id === loggedInUserId ? undefined : user.id}
- screenType={screenType}
- linkedSocials={social_links}
- />
+ {localBadges.length !== 0 && <Badges />}
<View style={styles.marginManager}>
<MutualFriends user={user} friends={mutual_friends} />
</View>
@@ -219,7 +225,6 @@ const styles = StyleSheet.create({
textShadowRadius: normalize(2),
letterSpacing: normalize(2),
},
- nameInfoContainer: {},
addButton: {
justifyContent: 'center',
alignItems: 'center',
@@ -267,17 +272,20 @@ const styles = StyleSheet.create({
shadowOffset: {width: 2, height: 2},
shadowOpacity: 0.5,
},
- body: {},
- button: {
- justifyContent: 'center',
+ universityIcon: {
+ left: '5%',
+ width: normalize(31),
+ height: normalize(38),
+ },
+ badgeContainer: {
+ flexDirection: 'row',
alignItems: 'center',
- width: SCREEN_WIDTH * 0.4,
- aspectRatio: 154 / 33,
- borderWidth: 2,
- borderColor: '#fff',
- borderRadius: 3,
- marginRight: '2%',
- marginLeft: '1%',
+ justifyContent: 'space-evenly',
+ marginBottom: 25,
+ },
+ badge: {
+ width: normalize(52),
+ height: normalize(52),
},
});
diff --git a/src/services/MomentService.ts b/src/services/MomentService.ts
index 7d141984..af602dc7 100644
--- a/src/services/MomentService.ts
+++ b/src/services/MomentService.ts
@@ -147,6 +147,7 @@ export const postMomentTags = async (
tags: {
x: number;
y: number;
+ z: number;
user_id: string;
}[],
) => {
@@ -155,16 +156,13 @@ export const postMomentTags = async (
const form = new FormData();
form.append('moment_id', moment_id);
form.append('tags', JSON.stringify(tags));
- const response = await fetch(
- MOMENTTAG_ENDPOINT + `?moment_id=${moment_id}`,
- {
- method: 'POST',
- headers: {
- Authorization: 'Token ' + token,
- },
- body: form,
+ const response = await fetch(MOMENTTAG_ENDPOINT, {
+ method: 'POST',
+ headers: {
+ Authorization: 'Token ' + token,
},
- );
+ body: form,
+ });
return response.status === 201 || response.status === 200;
} catch (error) {
console.error(error);
diff --git a/src/services/SearchService.ts b/src/services/SearchService.ts
index 7b97f9a7..672c1ec6 100644
--- a/src/services/SearchService.ts
+++ b/src/services/SearchService.ts
@@ -1,4 +1,5 @@
import AsyncStorage from '@react-native-community/async-storage';
+import {ProfilePreviewType} from '../types';
export const loadSearchResults = async (url: string) => {
try {
@@ -11,12 +12,14 @@ export const loadSearchResults = async (url: string) => {
});
const {status} = response;
if (status === 200) {
- const searchResults = await response.json();
+ const searchResults: {
+ users: ProfilePreviewType[];
+ } = await response.json();
return searchResults;
}
} catch (error) {
console.log(error);
- throw error;
+ return undefined;
}
- return {};
+ return undefined;
};
diff --git a/src/types/types.ts b/src/types/types.ts
index e957483b..b294e3f1 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -123,6 +123,7 @@ export interface MomentTagType {
user: ProfilePreviewType;
x: number;
y: number;
+ z: number;
}
export interface CommentBaseType {
diff --git a/src/utils/search.ts b/src/utils/search.ts
index 789acbc3..c3246c41 100644
--- a/src/utils/search.ts
+++ b/src/utils/search.ts
@@ -147,5 +147,5 @@ export const loadTaggUserSuggestions = async (): Promise<
ProfilePreviewType[]
> => {
const searchResults = await loadSearchResults(`${SEARCH_ENDPOINT_SUGGESTED}`);
- return searchResults?.users;
+ return searchResults ? searchResults.users : [];
};