Skip to content

Instantly share code, notes, and snippets.

@cms
Last active January 10, 2020 14:55
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/ad37110123b133426aeacd6f8ce6707c to your computer and use it in GitHub Desktop.
Save cms/ad37110123b133426aeacd6f8ce6707c 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: 0.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 * 0.9, height: width * 0.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={0.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={0.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={0.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={0.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