|
@@ -9,7 +9,9 @@ import {
|
|
Dimensions,
|
|
Dimensions,
|
|
Alert,
|
|
Alert,
|
|
ScrollView,
|
|
ScrollView,
|
|
- Linking
|
|
|
|
|
|
+ Linking,
|
|
|
|
+ Platform,
|
|
|
|
+ ActivityIndicator
|
|
} from 'react-native';
|
|
} from 'react-native';
|
|
import {
|
|
import {
|
|
GiftedChat,
|
|
GiftedChat,
|
|
@@ -31,7 +33,7 @@ import {
|
|
LongPressGestureHandler,
|
|
LongPressGestureHandler,
|
|
Swipeable
|
|
Swipeable
|
|
} from 'react-native-gesture-handler';
|
|
} from 'react-native-gesture-handler';
|
|
-import { AvatarWithInitials, Header } from 'src/components';
|
|
|
|
|
|
+import { AvatarWithInitials, Header, WarningModal } from 'src/components';
|
|
import { Colors } from 'src/theme';
|
|
import { Colors } from 'src/theme';
|
|
import { useFocusEffect, useNavigation } from '@react-navigation/native';
|
|
import { useFocusEffect, useNavigation } from '@react-navigation/native';
|
|
import { Video } from 'expo-av';
|
|
import { Video } from 'expo-av';
|
|
@@ -62,6 +64,8 @@ import { styles } from './styles';
|
|
import SendIcon from 'assets/icons/messages/send.svg';
|
|
import SendIcon from 'assets/icons/messages/send.svg';
|
|
import { SheetManager } from 'react-native-actions-sheet';
|
|
import { SheetManager } from 'react-native-actions-sheet';
|
|
import { NAVIGATION_PAGES } from 'src/types';
|
|
import { NAVIGATION_PAGES } from 'src/types';
|
|
|
|
+import * as Notifications from 'expo-notifications';
|
|
|
|
+import { usePushNotification } from 'src/contexts/PushNotificationContext';
|
|
|
|
|
|
const options = {
|
|
const options = {
|
|
enableVibrateFallback: true,
|
|
enableVibrateFallback: true,
|
|
@@ -75,7 +79,7 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
const currentUserId = storage.get('uid', StoreType.STRING) as number;
|
|
const currentUserId = storage.get('uid', StoreType.STRING) as number;
|
|
const token = storage.get('token', StoreType.STRING) as string;
|
|
const token = storage.get('token', StoreType.STRING) as string;
|
|
const insets = useSafeAreaInsets();
|
|
const insets = useSafeAreaInsets();
|
|
- const [messages, setMessages] = useState<CustomMessage[]>([]);
|
|
|
|
|
|
+ const [messages, setMessages] = useState<CustomMessage[] | null>();
|
|
const { showActionSheetWithOptions } = useActionSheet();
|
|
const { showActionSheetWithOptions } = useActionSheet();
|
|
const navigation = useNavigation();
|
|
const navigation = useNavigation();
|
|
const { data: chatData, isFetching, refetch } = usePostGetChatWithQuery(token, id, -1, -1, true);
|
|
const { data: chatData, isFetching, refetch } = usePostGetChatWithQuery(token, id, -1, -1, true);
|
|
@@ -86,6 +90,12 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
const [selectedMedia, setSelectedMedia] = useState<any>(null);
|
|
const [selectedMedia, setSelectedMedia] = useState<any>(null);
|
|
|
|
|
|
const [replyMessage, setReplyMessage] = useState<CustomMessage | null>(null);
|
|
const [replyMessage, setReplyMessage] = useState<CustomMessage | null>(null);
|
|
|
|
+ const [modalInfo, setModalInfo] = useState({
|
|
|
|
+ visible: false,
|
|
|
|
+ type: 'confirm',
|
|
|
|
+ message: '',
|
|
|
|
+ action: () => {}
|
|
|
|
+ });
|
|
|
|
|
|
const [selectedMessage, setSelectedMessage] = useState<BubbleProps<CustomMessage> | null>(null);
|
|
const [selectedMessage, setSelectedMessage] = useState<BubbleProps<CustomMessage> | null>(null);
|
|
const [emojiSelectorVisible, setEmojiSelectorVisible] = useState(false);
|
|
const [emojiSelectorVisible, setEmojiSelectorVisible] = useState(false);
|
|
@@ -111,9 +121,61 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
const messageRefs = useRef<{ [key: string]: any }>({});
|
|
const messageRefs = useRef<{ [key: string]: any }>({});
|
|
const flatList = useRef<FlatList | null>(null);
|
|
const flatList = useRef<FlatList | null>(null);
|
|
const scrollY = useSharedValue(0);
|
|
const scrollY = useSharedValue(0);
|
|
|
|
+ const { isSubscribed } = usePushNotification();
|
|
|
|
|
|
const socket = useRef<WebSocket | null>(null);
|
|
const socket = useRef<WebSocket | null>(null);
|
|
|
|
|
|
|
|
+ const closeModal = () => {
|
|
|
|
+ setModalInfo({ ...modalInfo, visible: false });
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const dismissChatNotifications = async (chatWithUserId: number) => {
|
|
|
|
+ const { status } = await Notifications.getPermissionsAsync();
|
|
|
|
+ if (status !== 'granted' || !isSubscribed) {
|
|
|
|
+ setModalInfo({
|
|
|
|
+ visible: true,
|
|
|
|
+ type: 'success',
|
|
|
|
+ message:
|
|
|
|
+ 'To use this feature we need your permission to access your notifications. You will be redirected to the notification settings screen where you need to enable them.',
|
|
|
|
+ action: () =>
|
|
|
|
+ // @ts-ignore
|
|
|
|
+ navigation.navigate(NAVIGATION_PAGES.MENU_DRAWER, {
|
|
|
|
+ screen: NAVIGATION_PAGES.NOTIFICATIONS
|
|
|
|
+ })
|
|
|
|
+ });
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ const subscription = Notifications.addNotificationReceivedListener((notification) => {
|
|
|
|
+ let conversation_with_user = 0;
|
|
|
|
+ if (Platform.OS === 'android') {
|
|
|
|
+ const data = notification.request.content.data;
|
|
|
|
+ if (data?.params) {
|
|
|
|
+ const parsedParams = JSON.parse(data.params) ?? {};
|
|
|
|
+ conversation_with_user = parsedParams?.id;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ const data = (notification.request.trigger as Notifications.PushNotificationTrigger)
|
|
|
|
+ ?.payload;
|
|
|
|
+ if (data?.params) {
|
|
|
|
+ const parsedParams = JSON.parse(data.params as string) ?? {};
|
|
|
|
+ conversation_with_user = parsedParams?.id;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (conversation_with_user === chatWithUserId) {
|
|
|
|
+ Notifications.dismissNotificationAsync(notification.request.identifier);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ return () => {
|
|
|
|
+ subscription.remove();
|
|
|
|
+ };
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ dismissChatNotifications(id);
|
|
|
|
+ }, [id]);
|
|
|
|
+
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
socket.current = new WebSocket(WEBSOCKET_URL);
|
|
socket.current = new WebSocket(WEBSOCKET_URL);
|
|
|
|
|
|
@@ -347,8 +409,11 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
},
|
|
},
|
|
{
|
|
{
|
|
onSuccess: () => {
|
|
onSuccess: () => {
|
|
- setMessages((prevMessages) => prevMessages.filter((msg) => msg._id !== messageId));
|
|
|
|
|
|
+ setMessages((prevMessages) =>
|
|
|
|
+ prevMessages ? prevMessages.filter((msg) => msg._id !== messageId) : []
|
|
|
|
+ );
|
|
// sendWebSocketMessage('message_deleted');
|
|
// sendWebSocketMessage('message_deleted');
|
|
|
|
+ refetch();
|
|
sendWebSocketMessage('new_message');
|
|
sendWebSocketMessage('new_message');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -372,10 +437,6 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
handleDeleteMessage(selectedMessage.currentMessage?._id);
|
|
handleDeleteMessage(selectedMessage.currentMessage?._id);
|
|
setIsModalVisible(false);
|
|
setIsModalVisible(false);
|
|
break;
|
|
break;
|
|
- // case 'pin':
|
|
|
|
- // setIsModalVisible(false);
|
|
|
|
- // Alert.alert(option);
|
|
|
|
- // break;
|
|
|
|
default:
|
|
default:
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -392,7 +453,7 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
{
|
|
{
|
|
onSuccess: () => {
|
|
onSuccess: () => {
|
|
setMessages((prevMessages) =>
|
|
setMessages((prevMessages) =>
|
|
- prevMessages.map((msg) => {
|
|
|
|
|
|
+ prevMessages?.map((msg) => {
|
|
if (msg._id === messageId) {
|
|
if (msg._id === messageId) {
|
|
return {
|
|
return {
|
|
...msg,
|
|
...msg,
|
|
@@ -583,7 +644,7 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
}
|
|
}
|
|
);
|
|
);
|
|
|
|
|
|
- setMessages((previousMessages) => GiftedChat.append(previousMessages, [message]));
|
|
|
|
|
|
+ setMessages((previousMessages) => GiftedChat.append(previousMessages ?? [], [message]));
|
|
clearReplyMessage();
|
|
clearReplyMessage();
|
|
},
|
|
},
|
|
[replyMessage]
|
|
[replyMessage]
|
|
@@ -630,7 +691,9 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
image: result.assets[0].type === 'image' ? result.assets[0].uri : null,
|
|
image: result.assets[0].type === 'image' ? result.assets[0].uri : null,
|
|
video: result.assets[0].type === 'video' ? result.assets[0].uri : null
|
|
video: result.assets[0].type === 'video' ? result.assets[0].uri : null
|
|
};
|
|
};
|
|
- setMessages((previousMessages) => GiftedChat.append(previousMessages, [newMedia as any]));
|
|
|
|
|
|
+ setMessages((previousMessages) =>
|
|
|
|
+ GiftedChat.append(previousMessages ?? [], [newMedia as any])
|
|
|
|
+ );
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
@@ -658,7 +721,7 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
}));
|
|
}));
|
|
|
|
|
|
setMessages((previousMessages) =>
|
|
setMessages((previousMessages) =>
|
|
- GiftedChat.append(previousMessages, imageMessages as any[])
|
|
|
|
|
|
+ GiftedChat.append(previousMessages ?? [], imageMessages as any[])
|
|
);
|
|
);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
@@ -689,6 +752,8 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
};
|
|
};
|
|
|
|
|
|
const addReaction = (messageId: number, reaction: string) => {
|
|
const addReaction = (messageId: number, reaction: string) => {
|
|
|
|
+ if (!messages) return;
|
|
|
|
+
|
|
const updatedMessages = messages.map((msg: any) => {
|
|
const updatedMessages = messages.map((msg: any) => {
|
|
if (msg._id === messageId) {
|
|
if (msg._id === messageId) {
|
|
const updatedReactions: Reaction[] = [
|
|
const updatedReactions: Reaction[] = [
|
|
@@ -783,6 +848,8 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
};
|
|
};
|
|
|
|
|
|
const scrollToMessage = (messageId: number) => {
|
|
const scrollToMessage = (messageId: number) => {
|
|
|
|
+ if (!messages) return;
|
|
|
|
+
|
|
const messageIndex = messages.findIndex((message) => message._id === messageId);
|
|
const messageIndex = messages.findIndex((message) => message._id === messageId);
|
|
|
|
|
|
if (messageIndex !== -1 && flatList.current) {
|
|
if (messageIndex !== -1 && flatList.current) {
|
|
@@ -933,12 +1000,13 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
const renderInputToolbar = (props: any) => (
|
|
const renderInputToolbar = (props: any) => (
|
|
<InputToolbar
|
|
<InputToolbar
|
|
{...props}
|
|
{...props}
|
|
- renderActions={() => (
|
|
|
|
- <Actions
|
|
|
|
- icon={() => <MaterialCommunityIcons name="plus" size={28} color={Colors.DARK_BLUE} />}
|
|
|
|
- // onPressActionButton={openActionSheet}
|
|
|
|
- />
|
|
|
|
- )}
|
|
|
|
|
|
+ renderActions={() =>
|
|
|
|
+ // <Actions
|
|
|
|
+ // icon={() => <MaterialCommunityIcons name="plus" size={28} color={Colors.DARK_BLUE} />}
|
|
|
|
+ // // onPressActionButton={openActionSheet}
|
|
|
|
+ // />
|
|
|
|
+ null
|
|
|
|
+ }
|
|
containerStyle={{
|
|
containerStyle={{
|
|
backgroundColor: Colors.FILL_LIGHT
|
|
backgroundColor: Colors.FILL_LIGHT
|
|
}}
|
|
}}
|
|
@@ -1015,101 +1083,105 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
</View>
|
|
</View>
|
|
|
|
|
|
<GestureHandlerRootView style={styles.container}>
|
|
<GestureHandlerRootView style={styles.container}>
|
|
- <GiftedChat
|
|
|
|
- messages={messages}
|
|
|
|
- listViewProps={{
|
|
|
|
- ref: flatList,
|
|
|
|
- showsVerticalScrollIndicator: false,
|
|
|
|
- initialNumToRender: 30,
|
|
|
|
- onViewableItemsChanged: handleViewableItemsChanged,
|
|
|
|
- viewabilityConfig: { itemVisiblePercentThreshold: 50 },
|
|
|
|
- initialScrollIndex: unreadMessageIndex ?? 0,
|
|
|
|
- onScrollToIndexFailed: (info: any) => {
|
|
|
|
- const wait = new Promise((resolve) => setTimeout(resolve, 300));
|
|
|
|
- wait.then(() => {
|
|
|
|
- flatList.current?.scrollToIndex({
|
|
|
|
- index: info.index,
|
|
|
|
- animated: true,
|
|
|
|
- viewPosition: 0.5
|
|
|
|
|
|
+ {messages ? (
|
|
|
|
+ <GiftedChat
|
|
|
|
+ messages={messages as CustomMessage[]}
|
|
|
|
+ listViewProps={{
|
|
|
|
+ ref: flatList,
|
|
|
|
+ showsVerticalScrollIndicator: false,
|
|
|
|
+ initialNumToRender: 30,
|
|
|
|
+ onViewableItemsChanged: handleViewableItemsChanged,
|
|
|
|
+ viewabilityConfig: { itemVisiblePercentThreshold: 50 },
|
|
|
|
+ initialScrollIndex: unreadMessageIndex ?? 0,
|
|
|
|
+ onScrollToIndexFailed: (info: any) => {
|
|
|
|
+ const wait = new Promise((resolve) => setTimeout(resolve, 300));
|
|
|
|
+ wait.then(() => {
|
|
|
|
+ flatList.current?.scrollToIndex({
|
|
|
|
+ index: info.index,
|
|
|
|
+ animated: true,
|
|
|
|
+ viewPosition: 0.5
|
|
|
|
+ });
|
|
});
|
|
});
|
|
- });
|
|
|
|
- }
|
|
|
|
- }}
|
|
|
|
- renderSystemMessage={renderSystemMessage}
|
|
|
|
- onSend={(newMessages: CustomMessage[]) => onSend(newMessages)}
|
|
|
|
- user={{ _id: +currentUserId, name: 'Me' }}
|
|
|
|
- renderBubble={renderBubble}
|
|
|
|
- renderMessageImage={renderMessageImage}
|
|
|
|
- renderInputToolbar={renderInputToolbar}
|
|
|
|
- renderCustomView={renderReplyMessageView}
|
|
|
|
- isCustomViewBottom={false}
|
|
|
|
- messageContainerRef={messageContainerRef}
|
|
|
|
- minComposerHeight={34}
|
|
|
|
- onInputTextChanged={(text) => handleTyping(text.length > 0)}
|
|
|
|
- isTyping={isTyping}
|
|
|
|
- renderSend={(props) => (
|
|
|
|
- <View
|
|
|
|
- style={{
|
|
|
|
- flexDirection: 'row',
|
|
|
|
- height: '100%',
|
|
|
|
- alignItems: 'center',
|
|
|
|
- justifyContent: 'center',
|
|
|
|
- paddingHorizontal: 14
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- {props.text?.trim() && (
|
|
|
|
- <Send
|
|
|
|
- {...props}
|
|
|
|
- containerStyle={{
|
|
|
|
- justifyContent: 'center'
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <SendIcon fill={Colors.DARK_BLUE} />
|
|
|
|
- </Send>
|
|
|
|
- )}
|
|
|
|
- {!props.text?.trim() && <SendIcon fill={Colors.LIGHT_GRAY} />}
|
|
|
|
- </View>
|
|
|
|
- )}
|
|
|
|
- textInputProps={{ ...styles.composer, selectionColor: Colors.LIGHT_GRAY }}
|
|
|
|
- placeholder=""
|
|
|
|
- renderMessage={(props) => (
|
|
|
|
- <ChatMessageBox
|
|
|
|
- {...(props as MessageProps<CustomMessage>)}
|
|
|
|
- updateRowRef={updateRowRef}
|
|
|
|
- setReplyOnSwipeOpen={setReplyMessage}
|
|
|
|
- />
|
|
|
|
- )}
|
|
|
|
- renderChatFooter={() => (
|
|
|
|
- <ReplyMessageBar clearReply={clearReplyMessage} message={replyMessage} />
|
|
|
|
- )}
|
|
|
|
- // renderMessageVideo={renderMessageVideo}
|
|
|
|
- renderAvatar={null}
|
|
|
|
- maxComposerHeight={100}
|
|
|
|
- renderComposer={(props) => <Composer {...props} />}
|
|
|
|
- keyboardShouldPersistTaps="handled"
|
|
|
|
- renderChatEmpty={() => (
|
|
|
|
- <View style={styles.emptyChat}>
|
|
|
|
- <Text
|
|
|
|
- style={styles.emptyChatText}
|
|
|
|
- >{`No messages yet.\nFeel free to start the conversation.`}</Text>
|
|
|
|
- </View>
|
|
|
|
- )}
|
|
|
|
- shouldUpdateMessage={shouldUpdateMessage}
|
|
|
|
- scrollToBottom={true}
|
|
|
|
- scrollToBottomComponent={renderScrollToBottom}
|
|
|
|
- scrollToBottomStyle={{ backgroundColor: 'transparent' }}
|
|
|
|
- parsePatterns={(linkStyle) => [
|
|
|
|
- {
|
|
|
|
- type: 'url',
|
|
|
|
- style: { color: Colors.ORANGE, textDecorationLine: 'underline' },
|
|
|
|
- onPress: (url: string) => Linking.openURL(url),
|
|
|
|
- onLongPress: (url: string) => {
|
|
|
|
- Clipboard.setString(url ?? '');
|
|
|
|
- Alert.alert('Link copied');
|
|
|
|
}
|
|
}
|
|
- }
|
|
|
|
- ]}
|
|
|
|
- />
|
|
|
|
|
|
+ }}
|
|
|
|
+ renderSystemMessage={renderSystemMessage}
|
|
|
|
+ onSend={(newMessages: CustomMessage[]) => onSend(newMessages)}
|
|
|
|
+ user={{ _id: +currentUserId, name: 'Me' }}
|
|
|
|
+ renderBubble={renderBubble}
|
|
|
|
+ renderMessageImage={renderMessageImage}
|
|
|
|
+ renderInputToolbar={renderInputToolbar}
|
|
|
|
+ renderCustomView={renderReplyMessageView}
|
|
|
|
+ isCustomViewBottom={false}
|
|
|
|
+ messageContainerRef={messageContainerRef}
|
|
|
|
+ minComposerHeight={34}
|
|
|
|
+ onInputTextChanged={(text) => handleTyping(text.length > 0)}
|
|
|
|
+ isTyping={isTyping}
|
|
|
|
+ renderSend={(props) => (
|
|
|
|
+ <View
|
|
|
|
+ style={{
|
|
|
|
+ flexDirection: 'row',
|
|
|
|
+ height: '100%',
|
|
|
|
+ alignItems: 'center',
|
|
|
|
+ justifyContent: 'center',
|
|
|
|
+ paddingHorizontal: 14
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ {props.text?.trim() && (
|
|
|
|
+ <Send
|
|
|
|
+ {...props}
|
|
|
|
+ containerStyle={{
|
|
|
|
+ justifyContent: 'center'
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ <SendIcon fill={Colors.DARK_BLUE} />
|
|
|
|
+ </Send>
|
|
|
|
+ )}
|
|
|
|
+ {!props.text?.trim() && <SendIcon fill={Colors.LIGHT_GRAY} />}
|
|
|
|
+ </View>
|
|
|
|
+ )}
|
|
|
|
+ textInputProps={{ ...styles.composer, selectionColor: Colors.LIGHT_GRAY }}
|
|
|
|
+ placeholder=""
|
|
|
|
+ renderMessage={(props) => (
|
|
|
|
+ <ChatMessageBox
|
|
|
|
+ {...(props as MessageProps<CustomMessage>)}
|
|
|
|
+ updateRowRef={updateRowRef}
|
|
|
|
+ setReplyOnSwipeOpen={setReplyMessage}
|
|
|
|
+ />
|
|
|
|
+ )}
|
|
|
|
+ renderChatFooter={() => (
|
|
|
|
+ <ReplyMessageBar clearReply={clearReplyMessage} message={replyMessage} />
|
|
|
|
+ )}
|
|
|
|
+ // renderMessageVideo={renderMessageVideo}
|
|
|
|
+ renderAvatar={null}
|
|
|
|
+ maxComposerHeight={100}
|
|
|
|
+ renderComposer={(props) => <Composer {...props} />}
|
|
|
|
+ keyboardShouldPersistTaps="handled"
|
|
|
|
+ renderChatEmpty={() => (
|
|
|
|
+ <View style={styles.emptyChat}>
|
|
|
|
+ <Text
|
|
|
|
+ style={styles.emptyChatText}
|
|
|
|
+ >{`No messages yet.\nFeel free to start the conversation.`}</Text>
|
|
|
|
+ </View>
|
|
|
|
+ )}
|
|
|
|
+ shouldUpdateMessage={shouldUpdateMessage}
|
|
|
|
+ scrollToBottom={true}
|
|
|
|
+ scrollToBottomComponent={renderScrollToBottom}
|
|
|
|
+ scrollToBottomStyle={{ backgroundColor: 'transparent' }}
|
|
|
|
+ parsePatterns={(linkStyle) => [
|
|
|
|
+ {
|
|
|
|
+ type: 'url',
|
|
|
|
+ style: { color: Colors.ORANGE, textDecorationLine: 'underline' },
|
|
|
|
+ onPress: (url: string) => Linking.openURL(url),
|
|
|
|
+ onLongPress: (url: string) => {
|
|
|
|
+ Clipboard.setString(url ?? '');
|
|
|
|
+ Alert.alert('Link copied');
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ ]}
|
|
|
|
+ />
|
|
|
|
+ ) : (
|
|
|
|
+ <ActivityIndicator size="large" color={Colors.DARK_BLUE} />
|
|
|
|
+ )}
|
|
|
|
|
|
<Modal visible={!!selectedMedia} transparent={true}>
|
|
<Modal visible={!!selectedMedia} transparent={true}>
|
|
<View style={styles.modalContainer}>
|
|
<View style={styles.modalContainer}>
|
|
@@ -1169,6 +1241,17 @@ const ChatScreen = ({ route }: { route: any }) => {
|
|
</TouchableOpacity>
|
|
</TouchableOpacity>
|
|
</BlurView>
|
|
</BlurView>
|
|
</ReactModal>
|
|
</ReactModal>
|
|
|
|
+
|
|
|
|
+ <WarningModal
|
|
|
|
+ isVisible={modalInfo.visible}
|
|
|
|
+ onClose={closeModal}
|
|
|
|
+ type={modalInfo.type}
|
|
|
|
+ message={modalInfo.message}
|
|
|
|
+ action={() => {
|
|
|
|
+ modalInfo.action();
|
|
|
|
+ closeModal();
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
</GestureHandlerRootView>
|
|
</GestureHandlerRootView>
|
|
<View
|
|
<View
|
|
style={{
|
|
style={{
|