Skip to content

Instantly share code, notes, and snippets.

@cms
Created January 10, 2020 14:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cms/ab0ca4f591d194c33009981e10e09d29 to your computer and use it in GitHub Desktop.
Save cms/ab0ca4f591d194c33009981e10e09d29 to your computer and use it in GitHub Desktop.
import _ from "lodash";
import React from 'react';
import moment from 'moment';
import { connect } from 'react-redux';
import API from '@Services/Api/profile';
import { ApiManager } from "../../api/apiManager";
import ParsedText from 'react-native-parsed-text';
import { NavigationEvents } from "react-navigation";
import { DateToWordsFromNow } from '../../helpers/helper';
import { ACTIVITY_NOTIFICATION } from "../../api/constants";
import EmptyState from "../../components/empty_state/emptyState";
import { Feather, MaterialCommunityIcons, AntDesign, Entypo } from '@expo/vector-icons';
import { scale, blumerMainColor, blumerSixthColor, MAIN_FONT_FAMILY, blumerSecondaryColor} from "@Styles/style";
import {
Text,
View,
Alert,
Image,
FlatList,
Dimensions,
TouchableOpacity,
ActivityIndicator,
DeviceEventEmitter,
} from 'react-native';
import { notification } from "expo-haptics";
const { height, width } = Dimensions.get('window');
function firstCap(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
const Thumbnail = ({ onLoad, notification, icon }) => (
<View style={{
borderWidth: .5,
width: scale(60),
height: scale(60),
alignItems: 'center',
borderColor: '#CDCDCD',
borderRadius: scale(30),
justifyContent: 'center',
marginRight: 10,
}}>
<View style={{
width: scale(55),
height: scale(55),
borderRadius: scale(55 / 2),
}}>
<Image
onLoad={onLoad}
source={{ uri: notification.photo }}
style={{
width: '100%',
height: '100%',
borderRadius: scale(55 / 2),
}}
/>
</View>
<View style={{
right: 2.5,
bottom: -5,
width: scale(25),
height: scale(25),
position: 'absolute',
alignItems: 'center',
justifyContent: 'center',
borderRadius: scale(25 / 2),
backgroundColor: blumerSecondaryColor
}}>
{icon}
</View>
</View>
);
const NoNotifications = () => {
return (
<View style={{
flex: 1,
height: height - scale(150)
}}>
<View style={{
marginTop: 8,
flexDirection: 'row',
marginHorizontal: 70,
}}>
<View style={{
flex: 1,
width: scale(240),
alignItems: 'center',
justifyContent: 'center',
}}>
<Text style={{
color: '#a9c4fc',
textAlign: 'center',
fontSize: scale(15),
}}>
Agrega amigos para que comiences a interactuar
</Text>
</View>
<Image
style={{ width: scale(43), height: scale(43) }}
source={require('@Assets/images/arrow-up.png')}
/>
</View>
<View style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Image
style={{ width: width * .9, height: width * .9 }}
source={require('@Assets/images/notifications.png')}
/>
<Text style={{
marginTop: 15,
color: '#a9c4fc',
fontSize: scale(22),
}}>
… Aún no tienes notificaciones …
</Text>
</View>
</View>
)
}
const FRIEND_RELATIONSHIP_STATUS = {
IS_FRIEND: 1,
IN_PROCESS: 2,
BLOCKED_USER: 4,
IS_NOT_FRIEND: 0,
FRIENDSHIP_REQUESTED: 3,
};
const FRIENDSHIP_STATUS = {
DENY: 3, // Reject/Cancel friendship request
DELETE: 4, // Delete friend
UNBLOCK: 6, // Unblock friend
BLOCKED: 5, // Block friend
ACCEPTED: 2, // <= Acept friend request
REQUESTED: 1, // <= Friendship request
};
class ProfileNotifications extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
refreshing: false,
notifications: [],
loadingFriendshipProcess: false,
friendshipStatus: FRIEND_RELATIONSHIP_STATUS.IS_NOT_FRIEND,
}
this.page = 0;
this.lastPage = -1;
}
async componentDidMount() {
await this.getNotifications();
}
async getNotifications() {
this.setState({ loading: true });
const res = await ApiManager.getNotifications(this.props.token, this.page);
this.setState({ loading: false });
console.log('NOTIFICACIONES:', res)
this.lastPage = this.page;
if (!res.error) {
const _notifications = this.page == 0 ? res.message.data : [...this.state.notifications, ...res.message.data]
let notifications = [];
for (let i = 0; i < _notifications.length; i++) {
const notification = _notifications[i];
if (_.findIndex(notifications, { id: notification.id, type_notification: notification.type_notification }) == -1) {
notifications.push(notification);
}
}
this.setState({ notifications })
if (res.message.data.length > 0) {
this.page++;
}
}
else {
Alert.alert('Atención', 'No se pudo obtener el listado de notificaciones.');
}
}
async setNotificationAsRead(postId, typeOfNotification, typeOfNotificationId, ownerProfileId = '', ...props) {
DeviceEventEmitter.emit('onLoadingEvent', { loading: true })
let notificationAsReadBody = {
friendShipId: typeOfNotificationId,
notificationId: typeOfNotificationId,
typeOfNotification: typeOfNotification
}
if (typeOfNotification == ACTIVITY_NOTIFICATION.FRIENDSHIP) {
delete notificationAsReadBody.notificationId;
}
else {
delete notificationAsReadBody.friendShipId;
}
let res = await ApiManager.sendReadStatus(this.props.token, notificationAsReadBody);
DeviceEventEmitter.emit('onLoadingEvent', { loading: false })
if (!res.error) {
if (typeOfNotification == ACTIVITY_NOTIFICATION.FRIENDSHIP) {
this.props.navigation.navigate('PersonProfile', { token: this.props.token, userId: ownerProfileId })
} else {
this.props.navigation.navigate('PostDetails', { token: this.props.token, postId: postId })
}
}
else {
Alert.alert('Atención', 'Se ha producido un error, por favor vuelve a intentarlo.');
}
}
onFriendRequestAction = (allow = true, notification_id) => {
this.setState({ loadingFriendshipProcess: true });
const { userId } = this.props;
return API.cancelFriendRequest({
notification: 1,
follow_id: userId,
status_id: allow ? FRIENDSHIP_STATUS.ACCEPTED : FRIENDSHIP_STATUS.DENY,
}).then(({ response, rawResponse, error }) => {
if (!error && !response.error && [200, 201].indexOf(rawResponse.status) !== -1) {
return API.notificationFriendRequest({
notification_id
}).then(({ error: error2, rawResponse: rawResponse2, }) => {
if (!error2 && [200, 201].indexOf(rawResponse2.status) !== -1) {
if (allow) {
const notifications = _.cloneDeep(this.state.notifications);
const _notification = _.find(notifications, { id: notification_id });
if (!!_notification) {
_notification.by_read = true;
}
this.setState({ notifications });
} else {
this.setState({
notifications: _.filter(({ id }) => id !== notification_id)
});
}
} else {
console.log('Error Al leer la notificacion')
}
})
} else {
this.setState({ loadingFriendshipProcess: false });
Alert.alert('Lo sentimos', 'Ha ocurrido un error intentando procesar su solicitud');
}
});
}
renderFriendRequestNotification(notificationElement) {
return (
<TouchableOpacity
style={{
flex: 1,
// width: width - 20,
padding: 10,
marginVertical: 1,
alignItems: 'center',
flexDirection: 'row',
backgroundColor: '#FFF',
justifyContent: 'space-between',
paddingHorizontal: 20,
}}
onPress={() => {
this.setNotificationAsRead(
notificationElement.post_id,
notificationElement.type_notification,
notificationElement.id,
notificationElement.id_profile_owner,
notificationElement.by_read
)
}}
activeOpacity={.9}
>
<View style={{
flexDirection: 'row',
backgroundColor: '#FFF',
}}>
<Thumbnail
onLoad={() => { }}
notification={notificationElement}
icon={(
<Feather name="user-plus" size={14} color="#FFF" />
)}
/>
<View style={{ flex: 1 }}>
{
this.state.friendshipStatus === FRIEND_RELATIONSHIP_STATUS.IS_FRIEND ?
<View style={{}}>
<Text style={{
color: '#000000',
fontSize: scale(13),
fontFamily: MAIN_FONT_FAMILY,
}}>
{ `${_.startCase(_.lowerCase(notificationElement.first_name))} ${_.startCase(_.lowerCase(notificationElement.last_name))} y tu` }
</Text>
<Text style={{
marginTop: 2.5,
color: '#808080',
fontSize: scale(12),
fontFamily: MAIN_FONT_FAMILY,
}}>
Ahora son amigos en Blumer!
</Text>
</View>
: <View>
<Text style={{
color: '#000000',
fontSize: scale(13),
fontFamily: MAIN_FONT_FAMILY,
}}>
{ _.startCase(_.lowerCase(`${notificationElement.first_name} ${notificationElement.last_name}`)) }
</Text>
<Text style={{
marginTop: 2.5,
color: '#808080',
fontSize: scale(12),
fontFamily: MAIN_FONT_FAMILY,
}}>
Te ha enviado una solicitud de amistad.
</Text>
<View style={{
marginTop: 10,
flexDirection: 'row',
}}>
<TouchableOpacity
activeOpacity={.9}
onPress={() => this.onFriendRequestAction(true, notification_id = notificationElement.by_read)}
disabled={this.state.loadingFriendshipProcess}
style={{
flex: 1,
marginRight: 5,
borderRadius: 8,
height: scale(25),
flexDirection: 'row',
alignItems: 'center',
borderColor: '#D1D1D1',
justifyContent: 'center',
backgroundColor: blumerSecondaryColor,
}}
>
<Text style={{
color: '#FFF',
fontSize: scale(12),
textAlign: 'center',
fontFamily: MAIN_FONT_FAMILY,
}}>
Confirmar
</Text>
{
this.state.loadingFriendshipProcess && <View style={{
marginLeft: 10
}}>
<ActivityIndicator color="#FFF" />
</View>
}
</TouchableOpacity>
<TouchableOpacity
activeOpacity={.9}
onPress={() => this.onFriendRequestAction(false, notification_id = notificationElement.by_read)}
disabled={this.state.loadingFriendshipProcess}
style={{
flex: 1,
marginRight: 5,
borderRadius: 8,
height: scale(25),
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#E3E3E3',
}}
>
<Text style={{
color: '#979797',
fontSize: scale(12),
textAlign: 'center',
fontFamily: MAIN_FONT_FAMILY,
}}>
Eliminar
</Text>
{
this.state.loadingFriendshipProcess && <View style={{
marginLeft: 10
}}>
<ActivityIndicator color="red" />
</View>
}
</TouchableOpacity>
</View>
</View>
}
<Text style={{
marginTop: 10,
color: '#808080',
fontSize: scale(12),
fontFamily: MAIN_FONT_FAMILY
}}>
{ firstCap(moment(notificationElement.date).startOf('hour').fromNow()) }
</Text>
</View>
{
this.state.friendshipStatus === FRIEND_RELATIONSHIP_STATUS.IS_FRIEND ?
<View style={{
borderRadius: 8,
width: scale(65),
height: scale(65),
}}>
<Image
resizeMode="cover"
source={require('@Assets/images/friend-blumer.png')}
style={{ width: '100%', height: '100%', alignSelf: "center", borderRadius: 8 }}
/>
</View> : null
}
</View>
</TouchableOpacity>
)
}
renderActivityNotification(notificationElement) {
// let message = `${notificationElement.first_name}`;
let message = `__name__`;
if ('listado_actores' in notificationElement) {
if (notificationElement.listado_actores.length > 0) {
for (let index = 0; index < notificationElement.listado_actores.length; index++) {
const actor = notificationElement.listado_actores[index];
if (index == notificationElement.listado_actores.length - 1) {
if (notificationElement.count > 0) {
message += `, ${actor} y ${(notificationElement.count > 1 ? `otras ${notificationElement.count} personas` : `una persona más`)}`;
}
else {
message += ` y ${actor}`;
}
}
else {
message += `, ${actor}`;
}
}
}
}
switch (notificationElement.type_notification) {
case ACTIVITY_NOTIFICATION.LIKE:
notificationIcon = <AntDesign name="like2" size={15} color="#FFF" />;
message += (`${notificationElement.listado_actores} Le gusta tu publicación`);
break;
case ACTIVITY_NOTIFICATION.COMMENT:
notificationIcon = <MaterialCommunityIcons name="comment-multiple-outline" size={15} color="#FFF" />;
message += (`${notificationElement.listado_actores} Comentó en tu publicación`);
break;
case ACTIVITY_NOTIFICATION.SHARED:
notificationIcon = <Entypo name="share" size={15} color="#FFF" />;
message += (`${notificationElement.listado_actores} Compartió tu publicación`);
break;
case ACTIVITY_NOTIFICATION.MENTION:
notificationIcon = null;
message += " te ha mencionado en una publicación."
break;
}
return (
<TouchableOpacity
style={{
padding: 10,
marginVertical: 1,
flexDirection: 'row',
backgroundColor: '#FFF',
paddingHorizontal: 20,
}}
onPress={() => {
this.setNotificationAsRead(
notificationElement.post_id,
notificationElement.type_notification,
notificationElement.id
)
}}
activeOpacity={.9}
>
<Thumbnail
onLoad={() => { }}
icon={notificationIcon}
notification={notificationElement}
/>
<View style={{ flex: 1 }}>
<ParsedText
style={{
color: '#808080',
fontSize: scale(12),
fontFamily: MAIN_FONT_FAMILY
}}
parse={[
{
pattern: /__name__/,
onPress: (name) => { },
renderText: (string) => `${notificationElement.first_name} ${notificationElement.last_name}`,
style: {
color: '#000',
fontSize: scale(13),
fontFamily: MAIN_FONT_FAMILY,
},
},
]}
>
{message}
</ParsedText>
<Text style={{
marginTop: 10,
color: '#808080',
fontSize: scale(12),
fontFamily: MAIN_FONT_FAMILY
}}>
{ firstCap(moment(notificationElement.date).startOf('hour').fromNow()) }
</Text>
</View>
<View style={{
width: scale(65),
height: scale(65),
backgroundColor: '#F4F4F4F4',
borderRadius: 8,
}}>
<Image
resizeMode="cover"
source={{ uri: notificationElement.cover }}
style={{ width: '100%', height: '100%', alignSelf: "center", borderRadius: 8 }}
onLoad={() => this.setState({ ['loadingImage' + notificationElement.id]: true })}
/>
</View>
</TouchableOpacity>
);
}
_onRefresh = async () => {
this.setState({ refreshing: true });
this.page = 0;
await this.getNotifications();
this.setState({ refreshing: false });
}
_handleLoadMore = async () => {
if (!this.state.loading && this.lastPage !== this.page)
await this.getNotifications();
}
_renderFooter = () => {
if (!this.state.loading || this.lastPage === this.page) return null;
return (
<View style={{ width: '100%', alignItems: 'center', padding: 15 }}>
<ActivityIndicator size="large" color={blumerMainColor} />
</View>
)
}
render() {
return (
<View style={{ flex: 1, backgroundColor: blumerSixthColor, }}>
{/* <NavigationEvents onDidFocus={payload => this._onNavigationDidFocus(payload)}/> */}
<View style={{ flex: 1, }}>
<FlatList
keyExtractor={(item, index) => index.toString()}
ListEmptyComponent={(
this.state.notifications.length == 0 && !this.state.loading &&
<NoNotifications />
)}
data={this.state.notifications}
onRefresh={this._onRefresh}
refreshing={this.state.refreshing}
onEndReached={this._handleLoadMore}
onEndReachedThreshold={0.8}
extraData={this.state}
ListFooterComponent={this._renderFooter}
renderItem={({ item, index }) => (
<View key={index}>
{
item.type_notification == ACTIVITY_NOTIFICATION.FRIENDSHIP &&
this.renderFriendRequestNotification(item)
}
{
item.type_notification != ACTIVITY_NOTIFICATION.FRIENDSHIP &&
this.renderActivityNotification(item)
}
</View>
)}
/>
</View>
</View>
)
}
}
/**
* Function to map the global state into component props
*
* @param {Object} param0 The object global state
*/
const mapStateToProps = ({ session }) => ({
token: session.token,
userId: session.userId,
});
export default connect(mapStateToProps)(ProfileNotifications);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment