@iterable/react-native-sdk
Version:
Iterable SDK for React Native.
309 lines (304 loc) • 8.79 kB
JavaScript
"use strict";
import { useRef } from 'react';
import { Animated, Image, PanResponder, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { ITERABLE_INBOX_COLORS } from "../constants/index.js";
/**
* Renders a default layout for a message list item in the inbox.
*
* TODO: Change to component
*
* @param last - Indicates if this is the last item in the list.
* @param dataModel - The data model containing the message data.
* @param rowViewModel - The view model for the current row.
* @param customizations - Custom styles and configurations.
* @param isPortrait - Indicates if the device is in portrait mode.
*/
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
function defaultMessageListLayout(last, dataModel, rowViewModel, customizations, isPortrait) {
const messageTitle = rowViewModel.inAppMessage.inboxMetadata?.title ?? '';
const messageBody = rowViewModel.inAppMessage.inboxMetadata?.subtitle ?? '';
const messageCreatedAt = dataModel.getFormattedDate(rowViewModel.inAppMessage) ?? '';
const thumbnailURL = rowViewModel.imageUrl;
const styles = StyleSheet.create({
body: {
color: ITERABLE_INBOX_COLORS.TEXT_MUTED,
flexWrap: 'wrap',
fontSize: 15,
paddingBottom: 10,
width: '85%'
},
createdAt: {
color: ITERABLE_INBOX_COLORS.TEXT_MUTED,
fontSize: 12
},
messageContainer: {
flexDirection: 'column',
justifyContent: 'center',
paddingLeft: 10,
width: '75%'
},
messageRow: {
backgroundColor: ITERABLE_INBOX_COLORS.CONTAINER_BACKGROUND_LIGHT,
borderColor: ITERABLE_INBOX_COLORS.BORDER,
borderStyle: 'solid',
borderTopWidth: 1,
flexDirection: 'row',
height: 150,
paddingBottom: 10,
paddingTop: 10,
width: '100%'
},
readMessageThumbnailContainer: {
flexDirection: 'column',
justifyContent: 'center',
paddingLeft: 30
},
title: {
fontSize: 22,
paddingBottom: 10,
width: '85%'
},
unreadIndicator: {
backgroundColor: ITERABLE_INBOX_COLORS.UNREAD,
borderRadius: 15 / 2,
height: 15,
marginLeft: 10,
marginRight: 5,
marginTop: 10,
width: 15
},
unreadIndicatorContainer: {
flexDirection: 'column',
height: '100%',
justifyContent: 'flex-start'
},
unreadMessageThumbnailContainer: {
flexDirection: 'column',
justifyContent: 'center',
paddingLeft: 10
}
});
const resolvedStyles = {
...styles,
...customizations
};
const {
unreadIndicatorContainer,
unreadMessageThumbnailContainer,
title,
body,
createdAt,
messageRow
} = resolvedStyles;
let {
unreadIndicator,
readMessageThumbnailContainer,
messageContainer
} = resolvedStyles;
unreadIndicator = !isPortrait ? {
...unreadIndicator,
marginLeft: 40
} : unreadIndicator;
readMessageThumbnailContainer = !isPortrait ? {
...readMessageThumbnailContainer,
paddingLeft: 65
} : readMessageThumbnailContainer;
messageContainer = !isPortrait ? {
...messageContainer,
width: '90%'
} : messageContainer;
function messageRowStyle(_rowViewModel) {
return last ? {
...messageRow,
borderBottomWidth: 1
} : messageRow;
}
return /*#__PURE__*/_jsxs(View, {
style: messageRowStyle(rowViewModel),
children: [/*#__PURE__*/_jsx(View, {
style: unreadIndicatorContainer,
children: rowViewModel.read ? null : /*#__PURE__*/_jsx(View, {
style: unreadIndicator
})
}), /*#__PURE__*/_jsx(View, {
style: rowViewModel.read ? readMessageThumbnailContainer : unreadMessageThumbnailContainer,
children: thumbnailURL ? /*#__PURE__*/_jsx(Image
// MOB-10429: Use stylesheet according to best practices
// eslint-disable-next-line react-native/no-inline-styles
, {
style: {
height: 80,
width: 80
},
source: {
uri: thumbnailURL
}
}) : null
}), /*#__PURE__*/_jsxs(View, {
style: messageContainer,
children: [/*#__PURE__*/_jsx(Text, {
numberOfLines: 1,
ellipsizeMode: "tail",
style: title,
children: messageTitle
}), /*#__PURE__*/_jsx(Text, {
numberOfLines: 3,
ellipsizeMode: "tail",
style: body,
children: messageBody
}), /*#__PURE__*/_jsx(Text, {
style: createdAt,
children: messageCreatedAt
})]
})]
});
}
/**
* Props for the IterableInboxMessageCell component.
*/
/**
* Component which renders a single message cell in the Iterable inbox.
*/
export const IterableInboxMessageCell = ({
index,
last,
dataModel,
rowViewModel,
customizations,
swipingCheck,
messageListItemLayout,
deleteRow,
handleMessageSelect,
contentWidth,
isPortrait
}) => {
const position = useRef(new Animated.ValueXY()).current;
let deleteSliderHeight = customizations.messageRow?.height ? customizations.messageRow.height : 150;
if (messageListItemLayout(last, rowViewModel)) {
deleteSliderHeight = messageListItemLayout(last, rowViewModel)?.[1] ?? deleteSliderHeight;
}
const styles = StyleSheet.create({
deleteSlider: {
alignItems: 'center',
backgroundColor: ITERABLE_INBOX_COLORS.DESTRUCTIVE,
elevation: 1,
flexDirection: 'row',
height: deleteSliderHeight,
justifyContent: 'flex-end',
paddingRight: 10,
position: 'absolute',
width: '100%',
...(isPortrait ? {} : {
paddingRight: 40
})
},
textContainer: {
elevation: 2,
width: '100%'
},
textStyle: {
color: ITERABLE_INBOX_COLORS.TEXT_INVERSE,
fontSize: 15,
fontWeight: 'bold'
}
});
const scrollThreshold = contentWidth / 15;
const FORCING_DURATION = 350;
//If user swipes, either complete swipe or reset
function userSwipedLeft(gesture) {
if (gesture.dx < -0.6 * contentWidth) {
completeSwipe();
} else {
resetPosition();
}
}
function completeSwipe() {
const x = -2000;
Animated.timing(position, {
toValue: {
x,
y: 0
},
duration: FORCING_DURATION,
useNativeDriver: false
}).start(() => deleteRow(rowViewModel.inAppMessage.messageId));
}
function resetPosition() {
Animated.timing(position, {
toValue: {
x: 0,
y: 0
},
duration: 200,
useNativeDriver: false
}).start();
}
const panResponder = useRef(PanResponder.create({
onStartShouldSetPanResponder: () => false,
onMoveShouldSetPanResponder: (_event, gestureState) => {
const {
dx,
dy
} = gestureState;
// return true if user is swiping, return false if it's a single click
return Math.abs(dx) !== 0 && Math.abs(dy) !== 0;
},
onMoveShouldSetPanResponderCapture: (_event, gestureState) => {
const {
dx,
dy
} = gestureState;
// return true if user is swiping, return false if it's a single click
return Math.abs(dx) !== 0 && Math.abs(dy) !== 0;
},
onPanResponderTerminationRequest: () => false,
onPanResponderGrant: () => {
position.setValue({
x: 0,
y: 0
});
},
onPanResponderMove: (_event, gesture) => {
if (gesture.dx <= -scrollThreshold) {
//enables swipeing when threshold is reached
swipingCheck(true);
//threshold value is deleted from movement
const x = gesture.dx;
//position is set to the new value
position.setValue({
x,
y: 0
});
}
},
onPanResponderRelease: (_event, gesture) => {
position.flattenOffset();
if (gesture.dx < 0) {
userSwipedLeft(gesture);
} else {
resetPosition();
}
swipingCheck(false);
}
})).current;
return /*#__PURE__*/_jsxs(_Fragment, {
children: [/*#__PURE__*/_jsx(View, {
style: styles.deleteSlider,
children: /*#__PURE__*/_jsx(Text, {
style: styles.textStyle,
children: "DELETE"
})
}), /*#__PURE__*/_jsx(Animated.View, {
style: [styles.textContainer, position.getLayout()],
...panResponder.panHandlers,
children: /*#__PURE__*/_jsx(TouchableOpacity, {
activeOpacity: 1,
onPress: () => {
handleMessageSelect(rowViewModel.inAppMessage.messageId, index);
},
children: messageListItemLayout(last, rowViewModel) ? messageListItemLayout(last, rowViewModel)?.[0] : defaultMessageListLayout(last, dataModel, rowViewModel, customizations, isPortrait)
})
})]
});
};
//# sourceMappingURL=IterableInboxMessageCell.js.map