|
@@ -45,7 +45,13 @@ import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
|
import Clipboard from '@react-native-clipboard/clipboard';
|
|
|
import { trigger } from 'react-native-haptic-feedback';
|
|
|
import ReactModal from 'react-native-modal';
|
|
|
-import { storage, StoreType } from 'src/storage';
|
|
|
+import {
|
|
|
+ editMessageInStorage,
|
|
|
+ sendMessageOffline,
|
|
|
+ checkAndSendSavedMessages,
|
|
|
+ storage,
|
|
|
+ StoreType
|
|
|
+} from 'src/storage';
|
|
|
import {
|
|
|
usePostGetGroupChatQuery,
|
|
|
usePostSendGroupMessageMutation,
|
|
@@ -80,12 +86,15 @@ import * as MediaLibrary from 'expo-media-library';
|
|
|
import BanIcon from 'assets/icons/messages/ban.svg';
|
|
|
import AttachmentsModal from '../Components/AttachmentsModal';
|
|
|
import RenderMessageVideo from '../Components/renderMessageVideo';
|
|
|
+import RenderMessageImage from '../Components/RenderMessageImage';
|
|
|
import MessageLocation from '../Components/MessageLocation';
|
|
|
import GroupIcon from 'assets/icons/messages/group-chat.svg';
|
|
|
import { CACHED_ATTACHMENTS_DIR } from 'src/constants/constants';
|
|
|
import GroupStatusModal from '../Components/GroupStatusModal';
|
|
|
import PinIcon from 'assets/icons/messages/pin.svg';
|
|
|
import MentionsList from '../Components/MentionsList';
|
|
|
+import { useConnection } from 'src/contexts/ConnectionContext';
|
|
|
+import moment from 'moment';
|
|
|
|
|
|
const options = {
|
|
|
enableVibrateFallback: true,
|
|
@@ -96,6 +105,9 @@ const reactionEmojis = ['👍', '❤️', '😂', '😮', '😭'];
|
|
|
|
|
|
const GroupChatScreen = ({ route }: { route: any }) => {
|
|
|
const token = storage.get('token', StoreType.STRING) as string;
|
|
|
+ const [isConnected, setIsConnected] = useState<boolean>(true);
|
|
|
+ const netInfo = useConnection();
|
|
|
+
|
|
|
const {
|
|
|
group_token,
|
|
|
name,
|
|
@@ -200,6 +212,16 @@ const GroupChatScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
const socket = useRef<WebSocket | null>(null);
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ if (netInfo && netInfo.isConnected !== null) {
|
|
|
+ setIsConnected(netInfo.isConnected);
|
|
|
+ if (netInfo.isConnected) {
|
|
|
+ checkAndSendSavedMessages();
|
|
|
+ refetch();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, [netInfo]);
|
|
|
+
|
|
|
const closeModal = () => {
|
|
|
setModalInfo({ ...modalInfo, visible: false });
|
|
|
};
|
|
@@ -981,7 +1003,7 @@ const GroupChatScreen = ({ route }: { route: any }) => {
|
|
|
received: message.status === 3,
|
|
|
deleted: message.status === 4,
|
|
|
edited: isMessageEdited(message.edits),
|
|
|
- isSending: false,
|
|
|
+ isSending: message?.isSending ? message.isSending : false,
|
|
|
video:
|
|
|
message.attachement !== -1 && message.attachement?.filetype?.startsWith('video')
|
|
|
? API_HOST + message.attachement?.attachment_link
|
|
@@ -1042,9 +1064,16 @@ const GroupChatScreen = ({ route }: { route: any }) => {
|
|
|
const newMessages = mappedMessages.filter(
|
|
|
(newMsg) => !previousMessages?.some((oldMsg) => oldMsg._id === newMsg._id)
|
|
|
);
|
|
|
+ let unsentMapped = [];
|
|
|
+ if (prevThenMessageId === -1) {
|
|
|
+ const unsentMessages = storage.get(`unsent_${group_token}`, StoreType.STRING)
|
|
|
+ ? JSON.parse(storage.get(`unsent_${group_token}`, StoreType.STRING) as string)
|
|
|
+ : [];
|
|
|
+ unsentMapped = unsentMessages.map(mapApiMessageToGiftedMessage);
|
|
|
+ }
|
|
|
return prevThenMessageId !== -1 && previousMessages
|
|
|
? GiftedChat.prepend(previousMessages, newMessages)
|
|
|
- : mappedMessages;
|
|
|
+ : [...unsentMapped, ...mappedMessages];
|
|
|
});
|
|
|
|
|
|
if (mappedMessages.length < 50) {
|
|
@@ -1520,6 +1549,8 @@ const GroupChatScreen = ({ route }: { route: any }) => {
|
|
|
},
|
|
|
{
|
|
|
onSuccess: () => {
|
|
|
+ editMessageInStorage(group_token, editingMessage._id, editedText, true);
|
|
|
+
|
|
|
const editedMessage = {
|
|
|
_id: editingMessage._id,
|
|
|
text: editedText
|
|
@@ -1563,6 +1594,29 @@ const GroupChatScreen = ({ route }: { route: any }) => {
|
|
|
])
|
|
|
);
|
|
|
|
|
|
+ if (!isConnected) {
|
|
|
+ const staticMessage = {
|
|
|
+ id: message._id,
|
|
|
+ text: transformMessageForServer(message.text),
|
|
|
+ isSending: true,
|
|
|
+ sender: +currentUserId,
|
|
|
+ status: 1,
|
|
|
+ sent_datetime: moment(message.createdAt).utc().format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ reply_to_id: message.replyMessage ? message.replyMessage.id : -1,
|
|
|
+ reactions: '{}',
|
|
|
+ edits: '{}',
|
|
|
+ attachement: -1,
|
|
|
+ encrypted: 0,
|
|
|
+ sender_avatar: null,
|
|
|
+ sender_name: 'Me'
|
|
|
+ };
|
|
|
+
|
|
|
+ sendMessageOffline(group_token, staticMessage as any);
|
|
|
+ clearReplyMessage();
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
sendMessage(
|
|
|
{
|
|
|
token,
|
|
@@ -1590,7 +1644,7 @@ const GroupChatScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
clearReplyMessage();
|
|
|
},
|
|
|
- [replyMessage, editingMessage]
|
|
|
+ [replyMessage, editingMessage, isConnected]
|
|
|
);
|
|
|
|
|
|
const addReaction = (messageId: number, reaction: string) => {
|
|
@@ -1749,78 +1803,6 @@ const GroupChatScreen = ({ route }: { route: any }) => {
|
|
|
}
|
|
|
}, [replyMessage]);
|
|
|
|
|
|
- const handleOpenImage = async (uri: string, fileName: string) => {
|
|
|
- const dirExist = await FileSystem.getInfoAsync(CACHED_ATTACHMENTS_DIR);
|
|
|
- if (!dirExist.exists) {
|
|
|
- await FileSystem.makeDirectoryAsync(CACHED_ATTACHMENTS_DIR, { intermediates: true });
|
|
|
- }
|
|
|
-
|
|
|
- const fileUri = `${CACHED_ATTACHMENTS_DIR}${fileName}`;
|
|
|
-
|
|
|
- const fileExists = await FileSystem.getInfoAsync(fileUri);
|
|
|
- if (fileExists.exists && fileExists.size > 1024) {
|
|
|
- setSelectedMedia(fileUri);
|
|
|
-
|
|
|
- return;
|
|
|
- }
|
|
|
- setSelectedMedia(uri);
|
|
|
-
|
|
|
- const { uri: localUri } = await FileSystem.downloadAsync(uri, fileUri, {
|
|
|
- headers: { Nmtoken: token, 'App-Version': APP_VERSION, Platform: Platform.OS }
|
|
|
- });
|
|
|
- };
|
|
|
-
|
|
|
- const renderMessageImage = (props: any) => {
|
|
|
- const { currentMessage } = props;
|
|
|
- const leftMessage = currentMessage?.user?._id !== +currentUserId;
|
|
|
-
|
|
|
- return (
|
|
|
- <TouchableOpacity
|
|
|
- onPress={() => {
|
|
|
- if (!currentMessage.attachment.attachment_full_url?.startsWith('/')) {
|
|
|
- setSelectedMedia(currentMessage.attachment.attachment_full_url);
|
|
|
- return;
|
|
|
- }
|
|
|
- handleOpenImage(
|
|
|
- API_HOST + currentMessage.attachment.attachment_full_url,
|
|
|
- currentMessage.attachment?.filename
|
|
|
- );
|
|
|
- }}
|
|
|
- onLongPress={() => handleLongPress(currentMessage, props)}
|
|
|
- style={styles.imageContainer}
|
|
|
- disabled={currentMessage.isSending}
|
|
|
- >
|
|
|
- <Image
|
|
|
- key={currentMessage.image}
|
|
|
- source={{
|
|
|
- uri: currentMessage.image,
|
|
|
- headers: { Nmtoken: token, 'App-Version': APP_VERSION, Platform: Platform.OS }
|
|
|
- }}
|
|
|
- style={styles.chatImage}
|
|
|
- resizeMode="cover"
|
|
|
- />
|
|
|
- {currentMessage.isSending && (
|
|
|
- <View
|
|
|
- style={{
|
|
|
- position: 'absolute',
|
|
|
- top: 0,
|
|
|
- left: 0,
|
|
|
- right: 0,
|
|
|
- bottom: 0,
|
|
|
- justifyContent: 'center',
|
|
|
- alignItems: 'center'
|
|
|
- }}
|
|
|
- >
|
|
|
- <ActivityIndicator
|
|
|
- size="large"
|
|
|
- color={leftMessage ? Colors.DARK_BLUE : Colors.FILL_LIGHT}
|
|
|
- />
|
|
|
- </View>
|
|
|
- )}
|
|
|
- </TouchableOpacity>
|
|
|
- );
|
|
|
- };
|
|
|
-
|
|
|
const renderTicks = (message: CustomMessage) => {
|
|
|
if (message.user._id !== +currentUserId) return null;
|
|
|
|
|
@@ -2176,7 +2158,8 @@ const GroupChatScreen = ({ route }: { route: any }) => {
|
|
|
(data &&
|
|
|
data.settings &&
|
|
|
data.settings.members_can_see_members === 0 &&
|
|
|
- data.settings.admin === 0)) ? (
|
|
|
+ data.settings.admin === 0) ||
|
|
|
+ !isConnected) ? (
|
|
|
<GiftedChat
|
|
|
messages={messages as CustomMessage[]}
|
|
|
text={text}
|
|
@@ -2201,7 +2184,15 @@ const GroupChatScreen = ({ route }: { route: any }) => {
|
|
|
onSend={(newMessages: CustomMessage[]) => onSend(newMessages)}
|
|
|
user={{ _id: +currentUserId, name: 'Me' }}
|
|
|
renderBubble={renderBubble}
|
|
|
- renderMessageImage={renderMessageImage}
|
|
|
+ renderMessageImage={(props) => (
|
|
|
+ <RenderMessageImage
|
|
|
+ props={props}
|
|
|
+ token={token}
|
|
|
+ currentUserId={+currentUserId}
|
|
|
+ onLongPress={handleLongPress}
|
|
|
+ setSelectedMedia={setSelectedMedia}
|
|
|
+ />
|
|
|
+ )}
|
|
|
showUserAvatar={true}
|
|
|
onPressAvatar={(user) => {
|
|
|
navigation.navigate(
|