summaryrefslogtreecommitdiff
path: root/frontend/app/screens/messaging
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/app/screens/messaging')
-rw-r--r--frontend/app/screens/messaging/chat.js214
-rw-r--r--frontend/app/screens/messaging/chatList.js147
-rw-r--r--frontend/app/screens/messaging/comments.js98
-rw-r--r--frontend/app/screens/messaging/index.js3
4 files changed, 462 insertions, 0 deletions
diff --git a/frontend/app/screens/messaging/chat.js b/frontend/app/screens/messaging/chat.js
new file mode 100644
index 0000000..c6b0b5e
--- /dev/null
+++ b/frontend/app/screens/messaging/chat.js
@@ -0,0 +1,214 @@
+import React from 'react';
+import {
+ FlatList,
+ View,
+ Platform,
+ Image,
+ TouchableOpacity,
+ Keyboard,
+ InteractionManager,
+} from 'react-native';
+import {
+ RkButton,
+ RkText,
+ RkTextInput,
+ RkAvoidKeyboard,
+ RkStyleSheet,
+ RkTheme,
+} from 'react-native-ui-kitten';
+import _ from 'lodash';
+import { FontAwesome } from '../../assets/icons';
+import { data } from '../../data';
+import { Avatar } from '../../components/avatar';
+import { scale } from '../../utils/scale';
+import NavigationType from '../../config/navigation/propTypes';
+
+const moment = require('moment');
+
+export class Chat extends React.Component {
+ static propTypes = {
+ navigation: NavigationType.isRequired,
+ };
+ static navigationOptions = ({ navigation }) => {
+ const userId = navigation.state.params ? navigation.state.params.userId : undefined;
+ const user = data.getUser(userId);
+ return ({
+ headerTitle: Chat.renderNavigationTitle(navigation, user),
+ headerRight: Chat.renderNavigationAvatar(navigation, user),
+ });
+ };
+
+ constructor(props) {
+ super(props);
+ const userId = this.props.navigation.getParam('userId', undefined);
+ this.state = {
+ data: data.getConversation(userId),
+ };
+ }
+
+ componentDidMount() {
+ InteractionManager.runAfterInteractions(() => {
+ this.listRef.scrollToEnd();
+ });
+ }
+
+ setListRef = (ref) => {
+ this.listRef = ref;
+ };
+
+ extractItemKey = (item) => `${item.id}`;
+
+ scrollToEnd = () => {
+ if (Platform.OS === 'ios') {
+ this.listRef.scrollToEnd();
+ } else {
+ _.delay(this.listRef.scrollToEnd, 100);
+ }
+ };
+
+ onInputChanged = (text) => {
+ this.setState({ message: text });
+ };
+
+ onSendButtonPressed = () => {
+ if (!this.state.message) {
+ return;
+ }
+ this.state.data.messages.push({
+ id: this.state.data.messages.length, time: 0, type: 'out', text: this.state.message,
+ });
+ this.setState({ message: '' });
+ this.scrollToEnd(true);
+ };
+
+ static onNavigationTitlePressed = (navigation, user) => {
+ navigation.navigate('ProfileV1', { id: user.id });
+ };
+
+ static onNavigationAvatarPressed = (navigation, user) => {
+ navigation.navigate('ProfileV1', { id: user.id });
+ };
+
+ static renderNavigationTitle = (navigation, user) => (
+ <TouchableOpacity onPress={() => Chat.onNavigationTitlePressed(navigation, user)}>
+ <View style={styles.header}>
+ <RkText rkType='header5'>{`${user.firstName} ${user.lastName}`}</RkText>
+ <RkText rkType='secondary3 secondaryColor'>Online</RkText>
+ </View>
+ </TouchableOpacity>
+ );
+
+ static renderNavigationAvatar = (navigation, user) => (
+ <TouchableOpacity onPress={() => Chat.onNavigationAvatarPressed(navigation, user)}>
+ <Avatar style={styles.avatar} rkType='small' img={user.photo} />
+ </TouchableOpacity>
+ );
+
+ renderDate = (date) => (
+ <RkText style={styles.time} rkType='secondary7 hintColor'>
+ {moment().add(date, 'seconds').format('LT')}
+ </RkText>
+ );
+
+ renderItem = ({ item }) => {
+ const isIncoming = item.type === 'in';
+ const backgroundColor = isIncoming
+ ? RkTheme.current.colors.chat.messageInBackground
+ : RkTheme.current.colors.chat.messageOutBackground;
+ const itemStyle = isIncoming ? styles.itemIn : styles.itemOut;
+
+ return (
+ <View style={[styles.item, itemStyle]}>
+ {!isIncoming && this.renderDate(item.time)}
+ <View style={[styles.balloon, { backgroundColor }]}>
+ <RkText rkType='primary2 mediumLine chat' style={{ paddingTop: 5 }}>{item.text}</RkText>
+ </View>
+ {isIncoming && this.renderDate(item.time)}
+ </View>
+ );
+ };
+
+ render = () => (
+ <RkAvoidKeyboard
+ style={styles.container}
+ onResponderRelease={Keyboard.dismiss}>
+ <FlatList
+ ref={this.setListRef}
+ extraData={this.state}
+ style={styles.list}
+ data={this.state.data.messages}
+ keyExtractor={this.extractItemKey}
+ renderItem={this.renderItem}
+ />
+ <View style={styles.footer}>
+ <RkButton style={styles.plus} rkType='clear'>
+ <RkText rkType='awesome secondaryColor'>{FontAwesome.plus}</RkText>
+ </RkButton>
+ <RkTextInput
+ onFocus={this.scrollToEnd}
+ onBlur={this.scrollToEnd}
+ onChangeText={this.onInputChanged}
+ value={this.state.message}
+ rkType='row sticker'
+ placeholder="Add a comment..."
+ />
+ <RkButton onPress={this.onSendButtonPressed} style={styles.send} rkType='circle highlight'>
+ <Image source={require('../../assets/icons/sendIcon.png')} />
+ </RkButton>
+ </View>
+ </RkAvoidKeyboard>
+
+ )
+}
+
+const styles = RkStyleSheet.create(theme => ({
+ header: {
+ alignItems: 'center',
+ },
+ avatar: {
+ marginRight: 16,
+ },
+ container: {
+ flex: 1,
+ backgroundColor: theme.colors.screen.base,
+ },
+ list: {
+ paddingHorizontal: 17,
+ },
+ footer: {
+ flexDirection: 'row',
+ minHeight: 60,
+ padding: 10,
+ backgroundColor: theme.colors.screen.alter,
+ },
+ item: {
+ marginVertical: 14,
+ flex: 1,
+ flexDirection: 'row',
+ },
+ itemIn: {},
+ itemOut: {
+ alignSelf: 'flex-end',
+ },
+ balloon: {
+ maxWidth: scale(250),
+ paddingHorizontal: 15,
+ paddingTop: 10,
+ paddingBottom: 15,
+ borderRadius: 20,
+ },
+ time: {
+ alignSelf: 'flex-end',
+ margin: 15,
+ },
+ plus: {
+ paddingVertical: 10,
+ paddingHorizontal: 10,
+ marginRight: 7,
+ },
+ send: {
+ width: 40,
+ height: 40,
+ marginLeft: 10,
+ },
+}));
diff --git a/frontend/app/screens/messaging/chatList.js b/frontend/app/screens/messaging/chatList.js
new file mode 100644
index 0000000..36cde5c
--- /dev/null
+++ b/frontend/app/screens/messaging/chatList.js
@@ -0,0 +1,147 @@
+import React from 'react';
+import {
+ FlatList,
+ View,
+ StyleSheet,
+ TouchableOpacity,
+} from 'react-native';
+import _ from 'lodash';
+import {
+ RkStyleSheet,
+ RkText,
+ RkTextInput,
+} from 'react-native-ui-kitten';
+import { Avatar } from '../../components';
+import { FontAwesome } from '../../assets/icons';
+import { data } from '../../data';
+import NavigationType from '../../config/navigation/propTypes';
+
+const moment = require('moment');
+
+export class ChatList extends React.Component {
+ static propTypes = {
+ navigation: NavigationType.isRequired,
+ };
+ static navigationOptions = {
+ title: 'Chats List'.toUpperCase(),
+ };
+
+ state = {
+ data: {
+ original: data.getChatList(),
+ filtered: data.getChatList(),
+ },
+ };
+
+ extractItemKey = (item) => `${item.withUser.id}`;
+
+ onInputChanged = (event) => {
+ const pattern = new RegExp(event.nativeEvent.text, 'i');
+ const chats = _.filter(this.state.data.original, chat => {
+ const filterResult = {
+ firstName: chat.withUser.firstName.search(pattern),
+ lastName: chat.withUser.lastName.search(pattern),
+ };
+ return filterResult.firstName !== -1 || filterResult.lastName !== -1 ? chat : undefined;
+ });
+ this.setState({
+ data: {
+ original: this.state.data.original,
+ filtered: chats,
+ },
+ });
+ };
+
+ onItemPressed = (item) => {
+ const navigationParams = { userId: item.withUser.id };
+ this.props.navigation.navigate('Chat', navigationParams);
+ };
+
+ renderSeparator = () => (
+ <View style={styles.separator} />
+ );
+
+ renderInputLabel = () => (
+ <RkText rkType='awesome'>{FontAwesome.search}</RkText>
+ );
+
+ renderHeader = () => (
+ <View style={styles.searchContainer}>
+ <RkTextInput
+ autoCapitalize='none'
+ autoCorrect={false}
+ onChange={this.onInputChanged}
+ label={this.renderInputLabel()}
+ rkType='row'
+ placeholder='Search'
+ />
+ </View>
+ );
+
+ renderItem = ({ item }) => {
+ const last = item.messages[item.messages.length - 1];
+ return (
+ <TouchableOpacity onPress={() => this.onItemPressed(item)}>
+ <View style={styles.container}>
+ <Avatar rkType='circle' style={styles.avatar} img={item.withUser.photo} />
+ <View style={styles.content}>
+ <View style={styles.contentHeader}>
+ <RkText rkType='header5'>{`${item.withUser.firstName} ${item.withUser.lastName}`}</RkText>
+ <RkText rkType='secondary4 hintColor'>
+ {moment().add(last.time, 'seconds').format('LT')}
+ </RkText>
+ </View>
+ <RkText numberOfLines={2} rkType='primary3 mediumLine' style={{ paddingTop: 5 }}>
+ {last.text}
+ </RkText>
+ </View>
+ </View>
+ </TouchableOpacity>
+ );
+ };
+
+ render = () => (
+ <FlatList
+ style={styles.root}
+ data={this.state.data.filtered}
+ extraData={this.state}
+ ListHeaderComponent={this.renderHeader}
+ ItemSeparatorComponent={this.renderSeparator}
+ keyExtractor={this.extractItemKey}
+ renderItem={this.renderItem}
+ />
+ );
+}
+
+const styles = RkStyleSheet.create(theme => ({
+ root: {
+ backgroundColor: theme.colors.screen.base,
+ },
+ searchContainer: {
+ backgroundColor: theme.colors.screen.bold,
+ paddingHorizontal: 16,
+ paddingVertical: 10,
+ height: 60,
+ alignItems: 'center',
+ },
+ container: {
+ paddingLeft: 19,
+ paddingRight: 16,
+ paddingBottom: 12,
+ paddingTop: 7,
+ flexDirection: 'row',
+ },
+ content: {
+ marginLeft: 16,
+ flex: 1,
+ },
+ contentHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginBottom: 6,
+ },
+ separator: {
+ height: StyleSheet.hairlineWidth,
+ backgroundColor: theme.colors.border.base,
+ },
+}));
diff --git a/frontend/app/screens/messaging/comments.js b/frontend/app/screens/messaging/comments.js
new file mode 100644
index 0000000..3b772c5
--- /dev/null
+++ b/frontend/app/screens/messaging/comments.js
@@ -0,0 +1,98 @@
+import React from 'react';
+import {
+ FlatList,
+ View,
+ StyleSheet,
+ TouchableOpacity,
+} from 'react-native';
+import {
+ RkStyleSheet,
+ RkText,
+} from 'react-native-ui-kitten';
+import { Avatar } from '../../components';
+import { data } from '../../data';
+import NavigationType from '../../config/navigation/propTypes';
+
+const moment = require('moment');
+
+export class Comments extends React.Component {
+ static propTypes = {
+ navigation: NavigationType.isRequired,
+ };
+ static navigationOptions = {
+ title: 'Comments'.toUpperCase(),
+ };
+
+ constructor(props) {
+ super(props);
+ const postId = this.props.navigation.getParam('postId', undefined);
+ this.state = {
+ data: data.getComments(postId),
+ };
+ }
+
+ extractItemKey = (item) => `${item.id}`;
+
+ onItemPressed = (item) => {
+ const navigationParams = { id: item.user.id };
+ this.props.navigation.navigate('ProfileV1', navigationParams);
+ };
+
+ renderSeparator = () => (
+ <View style={styles.separator} />
+ );
+
+ renderItem = ({ item }) => (
+ <View style={styles.container}>
+ <TouchableOpacity onPress={() => this.onItemPressed(item)}>
+ <Avatar rkType='circle' style={styles.avatar} img={item.user.photo} />
+ </TouchableOpacity>
+ <View style={styles.content}>
+ <View style={styles.contentHeader}>
+ <RkText rkType='header5'>{`${item.user.firstName} ${item.user.lastName}`}</RkText>
+ <RkText rkType='secondary4 hintColor'>
+ {moment().add(item.time, 'seconds').format('LT')}
+ </RkText>
+ </View>
+ <RkText rkType='primary3 mediumLine'>{item.text}</RkText>
+ </View>
+ </View>
+ );
+
+ render = () => (
+ <FlatList
+ style={styles.root}
+ data={this.state.data}
+ extraData={this.state}
+ ItemSeparatorComponent={this.renderSeparator}
+ keyExtractor={this.extractItemKey}
+ renderItem={this.renderItem}
+ />
+ );
+}
+
+const styles = RkStyleSheet.create(theme => ({
+ root: {
+ backgroundColor: theme.colors.screen.base,
+ },
+ container: {
+ paddingLeft: 19,
+ paddingRight: 16,
+ paddingVertical: 12,
+ flexDirection: 'row',
+ alignItems: 'flex-start',
+ },
+ content: {
+ marginLeft: 16,
+ flex: 1,
+ },
+ contentHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginBottom: 6,
+ },
+ separator: {
+ height: StyleSheet.hairlineWidth,
+ backgroundColor: theme.colors.border.base,
+ },
+}));
diff --git a/frontend/app/screens/messaging/index.js b/frontend/app/screens/messaging/index.js
new file mode 100644
index 0000000..0d39244
--- /dev/null
+++ b/frontend/app/screens/messaging/index.js
@@ -0,0 +1,3 @@
+export * from './chat';
+export * from './chatList';
+export * from './comments';