diff --git a/assets/info-icon.png b/assets/info-icon.png
new file mode 100644
index 0000000..d670537
Binary files /dev/null and b/assets/info-icon.png differ
diff --git a/components/ChannelList/ChannelList.jsx b/components/ChannelList/ChannelList.jsx
index 64ab873..3196413 100644
--- a/components/ChannelList/ChannelList.jsx
+++ b/components/ChannelList/ChannelList.jsx
@@ -38,6 +38,10 @@ export default class ChannelList extends React.Component {
if (this.props.onPressChannel) this.props.onPressChannel(id, name);
}
+ onLongPressChannel = (id, name) => {
+ if (this.props.onLongPressChannel) this.props.onLongPressChannel(id, name);
+ }
+
updateSubscription = (id, index) => {
if (['all', 'subs', 'myPosts'].includes(id)) return;
@@ -105,7 +109,9 @@ export default class ChannelList extends React.Component {
- this.onPressChannel(channel.id, channel.name)}>
+ this.onPressChannel(channel.id, channel.name)}
+ onLongPress={() => this.onLongPressChannel(channel.id, channel.name)}>
{channel.name}
@@ -147,5 +153,6 @@ export default class ChannelList extends React.Component {
ChannelList.propTypes = {
onPressChannel: PropTypes.func,
+ onLongPressChannel: PropTypes.func,
channels: PropTypes.array,
}
diff --git a/components/ChannelProfile/ChannelProfile.jsx b/components/ChannelProfile/ChannelProfile.jsx
new file mode 100644
index 0000000..d13041b
--- /dev/null
+++ b/components/ChannelProfile/ChannelProfile.jsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import { Modal, View, TouchableOpacity } from 'react-native';
+import { Text, Icon } from 'native-base';
+
+import styles from '../../components/ChannelProfile/ChannelProfileStyle';
+
+export default class ChannelProfile extends React.Component {
+
+ onClose = () => {
+ const { onClose } = this.props;
+ onClose();
+ }
+
+ render() {
+ const {
+ channel: channelData,
+ isModalOpen,
+ } = this.props;
+
+ if (!channelData) return null;
+ if (!channelData.description) return null;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {`${channelData.name}`}
+
+
+
+ {channelData.description && {`${channelData.description}`}}
+
+
+
+
+
+ )
+ }
+}
\ No newline at end of file
diff --git a/components/ChannelProfile/ChannelProfileStyle.js b/components/ChannelProfile/ChannelProfileStyle.js
new file mode 100644
index 0000000..a53ebe9
--- /dev/null
+++ b/components/ChannelProfile/ChannelProfileStyle.js
@@ -0,0 +1,30 @@
+import { StyleSheet, Dimensions } from 'react-native';
+
+import userProfileStyles from '../../components/UserProfile/UserProfileStyle'
+
+export default (styles = StyleSheet.create({
+ modal: {
+ ...userProfileStyles.modal
+ },
+ card: {
+ ...userProfileStyles.card
+ },
+ cancelRow: {
+ ...userProfileStyles.cancelRow
+ },
+ cancelIcon: {
+ ...userProfileStyles.cancelIcon
+ },
+ name: {
+ ...userProfileStyles.name
+ },
+ infoBlock: {
+ ...userProfileStyles.infoBlock,
+ },
+ cardChannelDescription: {
+ height: 200
+ },
+ channelInfoText: {
+ textAlign: 'center'
+ }
+}));
\ No newline at end of file
diff --git a/components/Comment/Comment.jsx b/components/Comment/Comment.jsx
index e4941a1..febc8a8 100644
--- a/components/Comment/Comment.jsx
+++ b/components/Comment/Comment.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import Autolink from 'react-native-autolink';
-import { Dimensions, TouchableOpacity, View, Modal } from 'react-native';
+import { ScrollView, TouchableOpacity, View, Modal } from 'react-native';
import {
Text, Thumbnail, ListItem, Card, CardItem,
Container, Content, Left, Icon, Button
@@ -10,6 +10,7 @@ import _ from 'lodash';
import { AppLoading } from "expo";
import * as Font from 'expo-font';
import date from 'date-fns';
+import Popover from 'react-native-popover-view';
import styles from "./CommentStyle";
import {getProfilePicture} from "../../helpers/imageCache"
@@ -25,6 +26,7 @@ export default class Comment extends React.Component {
profilePicture: null,
showEditButtons: false,
editing: false,
+ showLikedList: false
}
}
@@ -85,10 +87,58 @@ export default class Comment extends React.Component {
updateComment && updateComment(commentId, {}, "deleteComment");
}
+ toggleLike = () => {
+ const {
+ data,
+ loggedInUser,
+ updateComment
+ } = this.props;
+
+ if (data.usersLiked.find((user) => user._id === loggedInUser._id)) {
+ data.usersLiked = data.usersLiked.filter(user => user._id !== loggedInUser._id);
+ } else {
+ console.log("pushing")
+ data.usersLiked.push({
+ _id: loggedInUser._id,
+ firstname: loggedInUser.firstName,
+ lastName: loggedInUser.lastName
+ });
+ }
+
+ if (data.likes < 0) data.likes = 0; // (Grebel's a positive community, come on!)
+ console.log("Updating resource")
+ updateComment && updateComment(data._id, data, 'toggleCommentLike');
+ console.log("Updating resource")
+ }
+
+ generateLikesList = () => {
+ let {
+ usersLiked
+ } = this.props.data;
+
+ if (usersLiked.filter(e => e._id == this.props.loggedInUser._id).length) {
+ usersLiked = usersLiked.filter(user => user._id !== this.props.loggedInUser._id);
+ usersLiked.unshift({ firstName: 'You' }); // a wee hack
+ }
+
+ return (
+
+
+
+ {usersLiked.map((user, i) => {
+ return (
+ {user.firstName} {user.lastName || ''}
+ )
+ })}
+
+ )
+ }
+
render() {
const {
showEditButtons,
- editing
+ editing,
+ showLikedList
} = this.state;
const {
@@ -101,6 +151,7 @@ export default class Comment extends React.Component {
author,
content,
createdAt,
+ usersLiked,
} = data;
var authorName;
@@ -125,6 +176,11 @@ export default class Comment extends React.Component {
)
}
+ const isLiked = usersLiked.filter(e => e._id == this.props.loggedInUser._id).length > 0;
+
+ var likeIcon = isLiked ? require('../../assets/liked-cookie.png') : require('../../assets/cookie-icon.png');
+ var likesDialog = usersLiked.length > 0 ? usersLiked.length : '';
+
return (
@@ -146,10 +202,31 @@ export default class Comment extends React.Component {
{`${createdAt} `}
-
+
+
+
+ this.setState({ showLikedList: true })}
+ ref={ref => this.dialogRef = ref}
+ hitSlop={{ top: 40, bottom: 10, left: 30, right: 40 }}
+ >
+ {`${likesDialog}`}
+
+
+
+
+
+
+ this.setState({ showLikedList: false })}
+ >
+ {this.generateLikesList()}
+
diff --git a/components/Comment/CommentStyle.js b/components/Comment/CommentStyle.js
index c15cfd4..b114694 100644
--- a/components/Comment/CommentStyle.js
+++ b/components/Comment/CommentStyle.js
@@ -27,18 +27,21 @@ export default (styles = StyleSheet.create({
justifyContent: 'flex-start',
alignItems: 'flex-start'
},
+
textAuthor: {
paddingLeft: 5,
fontWeight: 'bold'
},
textContent: {
- paddingLeft: 5
+ paddingLeft: 5,
+ fontSize: 16,
+ flex: 1
},
editButtonsContainer: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
- alignItems: 'center',
+ alignItems: 'bottom',
backgroundColor: '#00000050'
},
view: {
@@ -66,5 +69,47 @@ export default (styles = StyleSheet.create({
flexDirection: 'row',
justifyContent: 'space-between',
paddingBottom: 5
- }
+ },
+ icon: {
+ width: 25,
+ height: 25,
+ marginRight: 0,
+ paddingRight: 0
+ },
+ iconContainer: {
+ flexDirection: 'column',
+ padding: 5,
+ flex: 0
+ },
+ likesDialog: {
+ fontSize: 12,
+ paddingBottom: 3,
+ flex: 1,
+ textAlignVertical: 'bottom',
+ alignSelf: 'center'
+ },
+
+ likedList: {
+ padding: 20,
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'flex-start',
+ alignItems: 'flex-start',
+ },
+ likedListIcon: {
+ width: 25,
+ height: 25,
+ marginBottom: 10,
+ alignSelf: 'center'
+ },
+ line: {
+ width: '100%',
+ borderBottomWidth: 1,
+ borderBottomColor: '#C0C0C0',
+ paddingLeft: 20,
+ paddingRight: 20
+ },
+ likedListItem: {
+ padding: 5
+ }
}));
diff --git a/components/CommentEditor/CommentEditor.jsx b/components/CommentEditor/CommentEditor.jsx
index 0ecb302..77b6430 100644
--- a/components/CommentEditor/CommentEditor.jsx
+++ b/components/CommentEditor/CommentEditor.jsx
@@ -52,10 +52,6 @@ export default class CommentEditor extends React.Component {
}
render() {
- const {
- showEditButtons,
- editing
- } = this.state;
const {
author
@@ -90,6 +86,7 @@ export default class CommentEditor extends React.Component {
onChangeText={this.textUpdate}
value={this.state.commentText}
multiline = {true}
+ scrollEnabled = {false}
/>
{this.state.commentText ?
diff --git a/components/CommentEditor/CommentEditorStyle.js b/components/CommentEditor/CommentEditorStyle.js
index 09b4639..42bb932 100644
--- a/components/CommentEditor/CommentEditorStyle.js
+++ b/components/CommentEditor/CommentEditorStyle.js
@@ -34,9 +34,10 @@ export default (styles = StyleSheet.create({
},
textContent: {
paddingLeft: 5,
- height: 38,
flexGrow: 1,
- flexShrink: 1
+ flexShrink: 1,
+ minHeight:38,
+ fontSize: 16
},
editButtonsContainer: {
flex: 1,
diff --git a/components/Post/Post.jsx b/components/Post/Post.jsx
index 7748fc8..4fb81e6 100644
--- a/components/Post/Post.jsx
+++ b/components/Post/Post.jsx
@@ -375,7 +375,7 @@ export default class Post extends React.Component {
-
+
{poll ?
(this.props.onPressPost ?
diff --git a/components/Post/PostStyle.js b/components/Post/PostStyle.js
index 11276cb..dd8328e 100644
--- a/components/Post/PostStyle.js
+++ b/components/Post/PostStyle.js
@@ -18,6 +18,9 @@ export default (styles = StyleSheet.create({
paddingTop: 0,
paddingBottom: 0,
},
+ autolinkContent: {
+ fontSize: 16
+ },
postFooter: {
marginTop: 3,
marginBottom: 3
diff --git a/components/UserProfile/UserProfileStyle.js b/components/UserProfile/UserProfileStyle.js
index 9543e72..4e27d7d 100644
--- a/components/UserProfile/UserProfileStyle.js
+++ b/components/UserProfile/UserProfileStyle.js
@@ -48,7 +48,8 @@ export default (styles = StyleSheet.create({
fontWeight: "400",
fontSize: 26,
marginTop: 10,
- marginBottom: 15
+ marginBottom: 15,
+ textAlign: 'center'
},
infoBlock: {
alignSelf: 'flex-start',
diff --git a/views/Comments/Comments.jsx b/views/Comments/Comments.jsx
index 90c2093..7d008ec 100644
--- a/views/Comments/Comments.jsx
+++ b/views/Comments/Comments.jsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { Container, Content, Text } from 'native-base';
+import { Container, Content, Text} from 'native-base';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'
import * as Font from 'expo-font';
@@ -12,6 +12,7 @@ import defaultStyles from "../../styles/styles";
import _ from 'lodash'
import CommentEditor from '../../components/CommentEditor/CommentEditor';
import Spinner from '../../components/Spinner/Spinner'
+import { ScrollView, KeyboardAvoidingView, } from 'react-native';
export default class CommentsView extends React.Component {
@@ -80,7 +81,7 @@ export default class CommentsView extends React.Component {
}
updateResource = async (id, data, type) => {
-
+ console.log(type)
const {
navigation,
} = this.props;
@@ -104,6 +105,22 @@ export default class CommentsView extends React.Component {
console.error(err);
alert("Error updating post. Sorry about that!");
});
+ } else if (['toggleCommentLike'].includes(type)) {
+ const addLike = data.usersLiked.some(user => user._id === loggedInUser._id);
+ console.log(addLike)
+ ApiClient.post(`/posts/${postData._id}/comment/${id}/like`, { addLike }, {authorized: true})
+ .then(() => {
+ postData.comments.forEach((comment) =>{
+ if(comment._id === id){
+ comment = data;
+ }
+ });
+ this.setState({ postData});
+ })
+ .catch(err => {
+ console.error(err);
+ alert("Error updating post. Sorry about that!");
+ });
}
else if (type === 'editPoll') {
@@ -242,7 +259,7 @@ export default class CommentsView extends React.Component {
showFullDate={true}
navigation={this.props.navigation}
/>
-
+
{_.map(_.orderBy(comments, comment => comment.createdAt.valueOf()),
(comment, key) => {
var enableCommentEditing = comment.author._id === loggedInUser._id;
@@ -255,13 +272,15 @@ export default class CommentsView extends React.Component {
enableEditing={enableCommentEditing}
enableDeleting={ loggedInUser.role && loggedInUser.role.includes("admin")}
showUserProfile={this.showUserProfile}
+ loggedInUser={loggedInUser}
/>
)
})}
-
-
+
+
+
-
diff --git a/views/CreatePost/CreatePostStyle.js b/views/CreatePost/CreatePostStyle.js
index 08f8d15..86b180f 100644
--- a/views/CreatePost/CreatePostStyle.js
+++ b/views/CreatePost/CreatePostStyle.js
@@ -52,6 +52,7 @@ export default (styles = StyleSheet.create({
borderColor: '#d6d7da',
marginLeft: 5,
marginRight: 5,
+ minHeight: 80,
},
buttonGroup: {
height: 100,
diff --git a/views/EditProfile/EditProfile.jsx b/views/EditProfile/EditProfile.jsx
index bc3efe8..1332424 100644
--- a/views/EditProfile/EditProfile.jsx
+++ b/views/EditProfile/EditProfile.jsx
@@ -65,6 +65,7 @@ export default class EditProfile extends React.Component {
affiliation: _.get(user, 'info.affiliation', undefined),
phone: _.get(user, 'info.phone', undefined),
bio: _.get(user, 'info.bio', undefined),
+ email: _.get(user, 'info.email', undefined),
avoidKeyboard: false,
}
}
@@ -102,6 +103,7 @@ export default class EditProfile extends React.Component {
address,
affiliation,
phone,
+ email,
bio
} = this.state;
@@ -118,6 +120,7 @@ export default class EditProfile extends React.Component {
if (address) user.info.address = address;
if (affiliation) user.info.affiliation = affiliation;
if (phone) user.info.phone = phone;
+ if (email) user.info.email = email;
if (bio) user.info.bio = bio;
return user;
@@ -180,7 +183,6 @@ export default class EditProfile extends React.Component {
@@ -193,6 +195,7 @@ export default class EditProfile extends React.Component {
{this.generateFieldJSX('address', 'Room Number / Address', 'Where can you be found?')}
{this.generateFieldJSX('affiliation', 'Affiliation with Grebel', 'i.e. Resident')}
{this.generateFieldJSX('phone', 'Phone Number', 'Let others contact you')}
+ {this.generateFieldJSX('email', 'Email', 'This won\'t be shared with anyone')}
{this.generateFieldJSX('bio', 'Bio', 'Share something about yourself')}
diff --git a/views/Feed/Feed.jsx b/views/Feed/Feed.jsx
index aa31c94..c4b28a4 100644
--- a/views/Feed/Feed.jsx
+++ b/views/Feed/Feed.jsx
@@ -4,10 +4,11 @@
import React from 'react';
import _ from 'lodash';
-import { FlatList} from 'react-native';
+import { FlatList, TouchableOpacity, Image} from 'react-native';
import { Container, Content, Text, Button, View } from 'native-base';
import * as Font from 'expo-font';
import UserProfile from '../../components/UserProfile/UserProfile.jsx';
+import ChannelProfile from '../../components/ChannelProfile/ChannelProfile.jsx';
import Post from '../../components/Post/Post';
import ApiClient from '../../ApiClient';
import styles from './FeedStyle';
@@ -22,6 +23,14 @@ export default class FeedView extends React.Component {
else title = 'Feed';
return {
+ get headerRight() {
+ if (!channel.description) return null;
+ return (
+
+
+
+ )
+ },
title: title,
headerTitle: null,
};
@@ -37,7 +46,9 @@ export default class FeedView extends React.Component {
page: 1,
loadedLastPage: false,
userDataToShow: undefined,
- showProfileModal: false
+ channelDataToShow: undefined,
+ showUserModal: false,
+ showChannelModal: false
}
}
@@ -52,13 +63,9 @@ export default class FeedView extends React.Component {
this.setState({ loading: false });
- //refresh data when returning from CreatePost
- this.props.navigation.addListener(
- 'willFocus',
- payload => {
- this.loadData()
- }
- );
+ this.props.navigation.setParams({
+ showChannelProfile: this.showChannelProfile
+ });
}
getUri() {
@@ -170,14 +177,29 @@ export default class FeedView extends React.Component {
showUserProfile = (user) => {
this.setState({
userDataToShow: user,
- showProfileModal: true
+ showUserModal: true
})
}
- closeProfileModal = () => {
+ closeUserModal = () => {
this.setState({
userDataToShow: undefined,
- showProfileModal: false
+ showUserModal: false
+ })
+ }
+
+ showChannelProfile = () => {
+ var channel = this.props.navigation.getParam('channel');
+ this.setState({
+ channelDataToShow: channel,
+ showChannelModal: true
+ })
+ }
+
+ closeChannelModal = () => {
+ this.setState({
+ channelDataToShow: undefined,
+ showChannelModal: false
})
}
@@ -216,6 +238,7 @@ export default class FeedView extends React.Component {
enableEditing={enableEditing}
enableDeleting={loggedInUser.role && loggedInUser.role.includes("admin")}
showUserProfile={this.showUserProfile}
+ showChannelProfile={this.showChannelProfile}
showFullDate={false}
navigation={this.props.navigation}
updatePost={this.updatePost}
@@ -291,7 +314,9 @@ export default class FeedView extends React.Component {
const {
loading,
userDataToShow,
- showProfileModal
+ channelDataToShow,
+ showUserModal: showUserModal,
+ showChannelModal: showChannelModal
} = this.state;
if (loading) {
@@ -312,8 +337,13 @@ export default class FeedView extends React.Component {
+
diff --git a/views/Feed/FeedStyle.js b/views/Feed/FeedStyle.js
index 8c3e622..7ad8e6a 100644
--- a/views/Feed/FeedStyle.js
+++ b/views/Feed/FeedStyle.js
@@ -15,15 +15,21 @@ export default (styles = StyleSheet.create({
bottom:40,
right:20,
...defaultStyles.primaryColor},
- noDataView: {
+ noDataView: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
alignItems: 'center',
marginTop: height / 3
},
- noDataText: {
+ noDataText: {
fontSize: 18,
fontStyle: 'italic',
- }
+ },
+ infoIcon: {
+ width: 25,
+ height: 25,
+ marginRight: 15,
+ marginBottom: 0
+ }
}));
diff --git a/views/Home/Home.jsx b/views/Home/Home.jsx
index 8e31a84..67a732d 100644
--- a/views/Home/Home.jsx
+++ b/views/Home/Home.jsx
@@ -3,6 +3,7 @@ import { StatusBar, TouchableOpacity, Image } from 'react-native';
import { Container, Content, Footer, Thumbnail} from 'native-base';
import ChannelList from "../../components/ChannelList/ChannelList";
import NotificationList from "../../components/NotificationList/NotificationList";
+import ChannelProfile from '../../components/ChannelProfile/ChannelProfile.jsx';
import HomeTabBar from "./HomeTabBar/HomeTabBar";
import styles from "./HomeStyle";
import ApiClient from '../../ApiClient';
@@ -49,7 +50,9 @@ export default class HomeView extends React.Component {
channels: [],
user: props.navigation.getParam('user'),
notifications: props.navigation.getParam('user').notifications,
- currentTab: 'channels'
+ currentTab: 'channels',
+ channelDataToShow: undefined,
+ showChannelModal: false
}
}
@@ -100,14 +103,27 @@ export default class HomeView extends React.Component {
onPressChannel = (channelId, channelName) => {
const { channels, user } = this.state;
- var channel;
+ let channel;
if (['all', 'subs', 'myPosts'].includes(channelId)) channel = { _id: channelId, name: channelName };
- else channel = _.head(_.filter(channels, { _id: channelId }));
+ else channel = channels.find(channel => channel._id === channelId);
this.props.navigation.navigate('Feed', { channel, loggedInUser: user });
}
+ onLongPressChannel = (channelId, channelName) => {
+ const { channels, user } = this.state;
+
+ let channel;
+ if (['all', 'subs', 'myPosts'].includes(channelId)) channel = { _id: channelId, name: channelName };
+ else channel = channels.find(channel => channel._id === channelId);
+
+ this.setState({
+ channelDataToShow: channel,
+ showChannelModal: true
+ })
+ }
+
onPressNotif = (notif) => {
this.updateNotificationState(notif);
this.props.navigation.navigate(
@@ -120,6 +136,13 @@ export default class HomeView extends React.Component {
);
}
+ closeChannelModal = () => {
+ this.setState({
+ channelDataToShow: undefined,
+ showChannelModal: false
+ })
+ }
+
updateNotificationState = (notif) => {
ApiClient.post(
`/notifications/${notif._id}/markSeen`, {}, {authorized: true}
@@ -160,8 +183,8 @@ export default class HomeView extends React.Component {
}
render() {
- const { channels, loading, user } = this.state;
-
+ const { channels, loading, user, channelDataToShow, showChannelModal } = this.state;
+
StatusBar.setBarStyle('dark-content', true);
if (loading) {
return (
@@ -180,6 +203,7 @@ export default class HomeView extends React.Component {
:
}
+
+
+