@ethora/chat-component-rn 26.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +148 -0
- package/empty-shim.js +15 -0
- package/index.js +13 -0
- package/metro.js +72 -0
- package/package.json +99 -0
- package/src/api.config.ts +34 -0
- package/src/assets/BG.png +0 -0
- package/src/assets/BG.tsx +56 -0
- package/src/assets/File.svg +4 -0
- package/src/assets/ForzaCare.png +0 -0
- package/src/assets/ForzaCare.tsx +27 -0
- package/src/assets/icons.tsx +685 -0
- package/src/assets/images.tsx +41 -0
- package/src/assets/test.xml +243 -0
- package/src/components/AuthForms/Login.tsx +295 -0
- package/src/components/AuthForms/LoginAnonym.tsx +68 -0
- package/src/components/AuthForms/Register.tsx +8 -0
- package/src/components/ContextMenu/ContextMenuComponents.tsx +87 -0
- package/src/components/DropdownMenu/DropdownMenu.tsx +244 -0
- package/src/components/ExampleComponents/CustomMessage.tsx +92 -0
- package/src/components/ExampleComponents/CustomTypingIndicatorExamples.tsx +239 -0
- package/src/components/Header/HeaderRoomList.tsx +104 -0
- package/src/components/InputComponents/AudioInput.tsx +24 -0
- package/src/components/InputComponents/AudioRecorder.tsx +100 -0
- package/src/components/InputComponents/MediaInput.tsx +114 -0
- package/src/components/InputComponents/RecordingIndicator.tsx +77 -0
- package/src/components/InputComponents/Search.tsx +135 -0
- package/src/components/InputComponents/TextInput.tsx +66 -0
- package/src/components/MainComponents/ChatHeader.tsx +163 -0
- package/src/components/MainComponents/ChatRoom.tsx +392 -0
- package/src/components/MainComponents/ChatWrapper.tsx +318 -0
- package/src/components/MainComponents/ChooseChatMessage.tsx +44 -0
- package/src/components/MainComponents/ConnectionBanner.tsx +33 -0
- package/src/components/MainComponents/EditWrapper.tsx +72 -0
- package/src/components/MainComponents/LoginWrapper.tsx +134 -0
- package/src/components/MainComponents/MediaMessage.tsx +55 -0
- package/src/components/MainComponents/MessageContainer.tsx +122 -0
- package/src/components/MainComponents/MessageList.tsx +429 -0
- package/src/components/MainComponents/NoMessagesPlaceholder.tsx +49 -0
- package/src/components/MainComponents/ProfileImagePlaceholder.tsx +143 -0
- package/src/components/MainComponents/RNStyled.tsx +34 -0
- package/src/components/MainComponents/ReduxWrapper.tsx +40 -0
- package/src/components/MainComponents/RoomList.tsx +246 -0
- package/src/components/MainComponents/Select.tsx +165 -0
- package/src/components/MainComponents/Switch.tsx +73 -0
- package/src/components/MainComponents/SystemMessage.tsx +42 -0
- package/src/components/Menu/HeaderRoomListMenu.tsx +169 -0
- package/src/components/MenuRoom/MenuRoom.tsx +46 -0
- package/src/components/MessageBubble/Avatar.tsx +84 -0
- package/src/components/MessageBubble/BottomReplyContainer.tsx +117 -0
- package/src/components/MessageBubble/CustomDivider.tsx +10 -0
- package/src/components/MessageBubble/DeletedMessage.tsx +36 -0
- package/src/components/MessageBubble/Message.tsx +400 -0
- package/src/components/MessageBubble/MessageInteractions.tsx +247 -0
- package/src/components/MessageBubble/MessageReaction.tsx +149 -0
- package/src/components/MessageBubble/MessageReply.tsx +50 -0
- package/src/components/MessageBubble/MessageTranslations.tsx +30 -0
- package/src/components/Modals/AddMembersModal/AddMembersModal.tsx +142 -0
- package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +471 -0
- package/src/components/Modals/ChatProfileModal/DeleteChatModal.tsx +91 -0
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +298 -0
- package/src/components/Modals/Modal/Modal.tsx +52 -0
- package/src/components/Modals/ModalHeaderComponent.tsx +41 -0
- package/src/components/Modals/ModalSelectMedia/ModalSelectMedia.tsx +285 -0
- package/src/components/Modals/ModalWrapper/ModalWrapper.tsx +103 -0
- package/src/components/Modals/NewChatModal/ModalContent.tsx +151 -0
- package/src/components/Modals/NewChatModal/NewChatModal.tsx +391 -0
- package/src/components/Modals/NewChatModal/UpdNewChatModal.tsx +136 -0
- package/src/components/Modals/SelectUsersModal/SelectUsersModal.tsx +134 -0
- package/src/components/Modals/SettingsModals/BlockedUsers/BlockedUsersModal.tsx +63 -0
- package/src/components/Modals/SettingsModals/DocumentShares/DocumentSharesModal.tsx +115 -0
- package/src/components/Modals/SettingsModals/ManageDataModal/ManageDataModal.tsx +121 -0
- package/src/components/Modals/SettingsModals/ManageDataModal/StyledComponents.ts +0 -0
- package/src/components/Modals/SettingsModals/ProfileShares/ProfileShares.tsx +65 -0
- package/src/components/Modals/SettingsModals/Referrals/Referrals.tsx +90 -0
- package/src/components/Modals/SettingsModals/SharedStyledComponents.ts +74 -0
- package/src/components/Modals/SettingsModals/Visibility/RadioInput.tsx +59 -0
- package/src/components/Modals/SettingsModals/Visibility/StyledComponents.ts +32 -0
- package/src/components/Modals/SettingsModals/Visibility/VisibilityModal.tsx +146 -0
- package/src/components/Modals/UserProfileModal/EditUserModal.tsx +163 -0
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +410 -0
- package/src/components/Modals/UserSettingsModal/UserSettingsModal.tsx +85 -0
- package/src/components/Modals/styledModalComponents.tsx +181 -0
- package/src/components/OperationalModal/OperationalModal.tsx +78 -0
- package/src/components/RoomComponents/ChatRoomItem.tsx +219 -0
- package/src/components/RoomComponents/LastMessageItem.tsx +47 -0
- package/src/components/RoomComponents/styled/LastAudioMessage.tsx +62 -0
- package/src/components/RoomComponents/styled/LastMessageEmoji.tsx +26 -0
- package/src/components/RoomComponents/styled/LastMessageFile.tsx +54 -0
- package/src/components/RoomComponents/styled/LastMessagePhoto.tsx +54 -0
- package/src/components/RoomComponents/styled/LastMessageVideo.tsx +70 -0
- package/src/components/RoomComponents/styled/LastTextMessage.tsx +65 -0
- package/src/components/RoomComponents/styled/StyledRoomComponents.ts +53 -0
- package/src/components/SortDropDown/index.tsx +76 -0
- package/src/components/Thread/ThreadHeader.tsx +41 -0
- package/src/components/Thread/ThreadWrapper.tsx +270 -0
- package/src/components/Toast/Toast.tsx +128 -0
- package/src/components/Toast/index.ts +13 -0
- package/src/components/UsersList/StyledComponents.ts +30 -0
- package/src/components/UsersList/UsersList.tsx +112 -0
- package/src/components/styled/ActionButton.tsx +40 -0
- package/src/components/styled/AudioMessage.tsx +82 -0
- package/src/components/styled/Button.tsx +107 -0
- package/src/components/styled/ChatWrapperBox.tsx +9 -0
- package/src/components/styled/DateLabel.tsx +77 -0
- package/src/components/styled/Loader.tsx +65 -0
- package/src/components/styled/MediaFilePreview.tsx +42 -0
- package/src/components/styled/MediaModal.tsx +54 -0
- package/src/components/styled/MessageImage.tsx +54 -0
- package/src/components/styled/NewMessageLabel.tsx +50 -0
- package/src/components/styled/RoomListComponents/index.tsx +164 -0
- package/src/components/styled/SendInput.tsx +297 -0
- package/src/components/styled/StyledComponents.ts +320 -0
- package/src/components/styled/StyledInput.tsx +101 -0
- package/src/components/styled/StyledInputComponents/AudioComponents.tsx +1 -0
- package/src/components/styled/StyledInputComponents/Composing.tsx +97 -0
- package/src/components/styled/StyledInputComponents/CustomTypingIndicator.tsx +261 -0
- package/src/components/styled/StyledInputComponents/MediaComponents.tsx +90 -0
- package/src/components/styled/StyledInputComponents/StyledInputComponents.tsx +131 -0
- package/src/components/styled/StyledInputComponents/VideoComponents.tsx +49 -0
- package/src/components/styled/TreadLabel.tsx +50 -0
- package/src/components/styled/UnsupportedType.tsx +95 -0
- package/src/components/styled/VideoMessage.tsx +68 -0
- package/src/context/MessageNotificationContext.tsx +335 -0
- package/src/context/PushNotificationProvider.tsx +78 -0
- package/src/context/ToastContext.tsx +63 -0
- package/src/context/toastProvider.tsx +0 -0
- package/src/context/xmppProvider.tsx +364 -0
- package/src/helpers/block_scroll.ts +95 -0
- package/src/helpers/chatAutoEnterer.ts +46 -0
- package/src/helpers/checkUniqueUsers.tsx +31 -0
- package/src/helpers/constants/CHAT_TYPES.ts +6 -0
- package/src/helpers/constants/LANGUAGE_OPTIONS.ts +14 -0
- package/src/helpers/constants/LOCAL_STORAGE.ts +3 -0
- package/src/helpers/constants/MESSAGE_INTERACTIONS.ts +29 -0
- package/src/helpers/constants/MODAL_TYPES.ts +57 -0
- package/src/helpers/constants/PLATFORM_CONSTANTS.ts +3 -0
- package/src/helpers/createMainMessageForThread.ts +23 -0
- package/src/helpers/createMessageFromXml.ts +118 -0
- package/src/helpers/createRoomFromApi.tsx +27 -0
- package/src/helpers/createUserNameFromSetUser.ts +15 -0
- package/src/helpers/dateComparison.ts +12 -0
- package/src/helpers/debounce.ts +10 -0
- package/src/helpers/ensureScopedChatCache.ts +61 -0
- package/src/helpers/extractUniqueMembersFromRooms.ts +45 -0
- package/src/helpers/formatNumberWithCommas.ts +3 -0
- package/src/helpers/getBooleanFromString.ts +7 -0
- package/src/helpers/getDataFromXml.ts +80 -0
- package/src/helpers/getNumberFromString.ts +5 -0
- package/src/helpers/getRoomsWithRetry.ts +45 -0
- package/src/helpers/getTintedColor.ts +28 -0
- package/src/helpers/getUnnamedUsers.ts +39 -0
- package/src/helpers/handleCopyClick.ts +3 -0
- package/src/helpers/handleXmppError.ts +14 -0
- package/src/helpers/hashcolor.ts +34 -0
- package/src/helpers/historyPreloadScheduler.ts +264 -0
- package/src/helpers/initRoomsPresence.ts +32 -0
- package/src/helpers/initXmppRooms.tsx +71 -0
- package/src/helpers/insertMessageWithDelimiter.ts +96 -0
- package/src/helpers/isChatIdPresentInArray.ts +54 -0
- package/src/helpers/localStorageUser.ts +9 -0
- package/src/helpers/markdownParser.tsx +295 -0
- package/src/helpers/nanoToMs.ts +3 -0
- package/src/helpers/parseMessageBody.tsx +516 -0
- package/src/helpers/parseUrls.tsx +42 -0
- package/src/helpers/resolveInitBeforeLoadUser.ts +240 -0
- package/src/helpers/storeConsole.ts +26 -0
- package/src/helpers/transformTranslatations.ts +16 -0
- package/src/helpers/updateMessagesTillLast.tsx +104 -0
- package/src/helpers/updatedChatLastTimestamps.ts +29 -0
- package/src/helpers/validator.ts +20 -0
- package/src/helpers/walletUsername.ts +12 -0
- package/src/hooks/hooks.ts +6 -0
- package/src/hooks/useChatSettingState.tsx +38 -0
- package/src/hooks/useChatWrapperInit.ts +266 -0
- package/src/hooks/useComposing.tsx +59 -0
- package/src/hooks/useCustomTypingIndicator.tsx +193 -0
- package/src/hooks/useEventHandlers.tsx +81 -0
- package/src/hooks/useGetNewArchRoom.tsx +57 -0
- package/src/hooks/useHeapSender.tsx +88 -0
- package/src/hooks/useLocalStorage.tsx +53 -0
- package/src/hooks/useLogout.tsx +31 -0
- package/src/hooks/useMessageHeapState.tsx +11 -0
- package/src/hooks/useMessageLoaderQueue.tsx +90 -0
- package/src/hooks/useMessageQueue.ts +146 -0
- package/src/hooks/usePendingNotification.ts +49 -0
- package/src/hooks/usePrevious.tsx +15 -0
- package/src/hooks/usePushNotifications.ts +106 -0
- package/src/hooks/useQRCodeChatHandler.ts +58 -0
- package/src/hooks/useRoomInitialization.tsx +160 -0
- package/src/hooks/useRoomState.tsx +47 -0
- package/src/hooks/useRoomUrl.tsx +41 -0
- package/src/hooks/useSendMessage.tsx +306 -0
- package/src/hooks/useUnreadMessagesCounter.ts +55 -0
- package/src/hooks/useXmppInitialization.ts +148 -0
- package/src/main.ts +45 -0
- package/src/networking/api-requests/auth.api.ts +140 -0
- package/src/networking/api-requests/push.api.ts +55 -0
- package/src/networking/api-requests/roomMembers.api.ts +20 -0
- package/src/networking/api-requests/rooms.api.ts +142 -0
- package/src/networking/api-requests/user.api.ts +65 -0
- package/src/networking/apiClient.ts +149 -0
- package/src/networking/helpers/refreshChecker.ts +13 -0
- package/src/networking/stanzaHandlers.ts +418 -0
- package/src/networking/xmpp/actionSetTimestampToPrivateStore.xmpp.ts +37 -0
- package/src/networking/xmpp/allRoomPresences.xmpp.ts +10 -0
- package/src/networking/xmpp/createPrivateRoom.xmpp.ts +26 -0
- package/src/networking/xmpp/createRoom.xmpp.ts +35 -0
- package/src/networking/xmpp/createRoomPresence.xmpp.ts +74 -0
- package/src/networking/xmpp/createTimeoutPromise.xmpp.ts +15 -0
- package/src/networking/xmpp/deleteMessage.xmpp.ts +19 -0
- package/src/networking/xmpp/editMessage.xmpp.ts +46 -0
- package/src/networking/xmpp/getChatsPrivateStoreRequest.xmpp.ts +57 -0
- package/src/networking/xmpp/getHistory.xmpp.ts +140 -0
- package/src/networking/xmpp/getLastMessageArchive.xmpp.ts +24 -0
- package/src/networking/xmpp/getRoomInfo.xmpp.ts +15 -0
- package/src/networking/xmpp/getRoomMembers.xmpp.ts +13 -0
- package/src/networking/xmpp/getRooms.xmpp.ts +43 -0
- package/src/networking/xmpp/getRoomsPaged.xmpp.ts +59 -0
- package/src/networking/xmpp/handlePong.xmpp.ts +7 -0
- package/src/networking/xmpp/handleStanzas.xmpp.ts +55 -0
- package/src/networking/xmpp/inviteRoomRequest.xmpp.ts +25 -0
- package/src/networking/xmpp/leaveTheRoom.xmpp.ts +15 -0
- package/src/networking/xmpp/listenerManager.ts +116 -0
- package/src/networking/xmpp/presenceInRoom.xmpp.ts +57 -0
- package/src/networking/xmpp/roomConfig.xmpp.ts +71 -0
- package/src/networking/xmpp/sendMediaMessage.xmpp.ts +97 -0
- package/src/networking/xmpp/sendMessageReaction.xmpp.ts +41 -0
- package/src/networking/xmpp/sendPing.xmpp.ts +21 -0
- package/src/networking/xmpp/sendTextMessage.xmpp.ts +99 -0
- package/src/networking/xmpp/sendTextMessageWithTranslateTag.xmpp.ts +44 -0
- package/src/networking/xmpp/sendTypingRequest.xmpp.ts +26 -0
- package/src/networking/xmpp/setChatsPrivateStoreRequest.xmpp.ts +48 -0
- package/src/networking/xmpp/setMeAsOwner.xmpp.ts +52 -0
- package/src/networking/xmpp/setRoomImage.xmpp.ts +26 -0
- package/src/networking/xmpp/setVCard.xmpp.ts +19 -0
- package/src/networking/xmpp/subscribeToRoomMessages.xmpp.ts +75 -0
- package/src/networking/xmppClient.ts +603 -0
- package/src/roomStore/Middleware/logoutMiddleware.tsx +24 -0
- package/src/roomStore/Middleware/newMessageMidlleware.tsx +87 -0
- package/src/roomStore/Middleware/reactionsMiddleware.tsx +77 -0
- package/src/roomStore/Middleware/testMiddleware.tsx +20 -0
- package/src/roomStore/Middleware/unreadMidlleware.tsx +58 -0
- package/src/roomStore/chatSettingsSlice.ts +178 -0
- package/src/roomStore/index.ts +68 -0
- package/src/roomStore/persistence.ts +152 -0
- package/src/roomStore/roomHeapSlice.ts +37 -0
- package/src/roomStore/roomsSlice.ts +353 -0
- package/src/services/pushNotifications.ts +170 -0
- package/src/services/pushSubscriptionService.ts +145 -0
- package/src/types/messages.ts +61 -0
- package/src/types/models/action.model.ts +30 -0
- package/src/types/models/config.model.ts +16 -0
- package/src/types/models/customComponents.model.ts +53 -0
- package/src/types/models/language.model.ts +11 -0
- package/src/types/models/media.model.ts +5 -0
- package/src/types/models/message.model.ts +69 -0
- package/src/types/models/modal.model.ts +9 -0
- package/src/types/models/room.model.ts +120 -0
- package/src/types/models/user.model.ts +90 -0
- package/src/types/models/xmpp.model.ts +155 -0
- package/src/types/types.ts +505 -0
- package/src/utils/PriorityQueue.ts +47 -0
- package/src/utils/actionHelpers.ts +40 -0
- package/src/utils/actionLogger.ts +64 -0
- package/src/utils/clientRegistry.ts +80 -0
- package/src/utils/devLogger.ts +197 -0
- package/src/utils/messageNotificationManager.ts +108 -0
- package/src/utils/resendMessage.ts +87 -0
- package/src/utils/toastEmitter.ts +27 -0
- package/src/utils/xmppMemoryMonitor.ts +63 -0
- package/src/version.ts +1 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/rules-of-hooks -- pre-existing port artifacts; hooks called conditionally / inside helpers. TODO: refactor */
|
|
2
|
+
import React, { useMemo, useState } from 'react';
|
|
3
|
+
import styled from 'styled-components/native';
|
|
4
|
+
import {
|
|
5
|
+
CenterContainer,
|
|
6
|
+
ModalContainerFullScreen,
|
|
7
|
+
} from '../styledModalComponents';
|
|
8
|
+
import { SaveIcon } from '../../../assets/icons';
|
|
9
|
+
import ModalHeaderComponent from '../ModalHeaderComponent';
|
|
10
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
11
|
+
import Button from '../../styled/Button';
|
|
12
|
+
import { RootState } from '../../../roomStore';
|
|
13
|
+
import { FullScreenImage } from '../../styled/StyledInputComponents/MediaComponents';
|
|
14
|
+
import { setActiveFile } from '../../../roomStore/chatSettingsSlice';
|
|
15
|
+
import { Alert, Text, View, PermissionsAndroid, Platform } from 'react-native';
|
|
16
|
+
import Video from 'react-native-video';
|
|
17
|
+
import RNFS from 'react-native-fs';
|
|
18
|
+
import { CameraRoll } from '@react-native-camera-roll/camera-roll';
|
|
19
|
+
import { useToast } from '../../../context/ToastContext';
|
|
20
|
+
|
|
21
|
+
export const FullScreenVideo = styled.View`
|
|
22
|
+
width: 100%;
|
|
23
|
+
height: 100%;
|
|
24
|
+
object-fit: contain;
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
interface FilePreviewModalProps {
|
|
28
|
+
handleCloseModal: any;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const FilePreviewModal: React.FC<FilePreviewModalProps> = ({
|
|
32
|
+
handleCloseModal,
|
|
33
|
+
}) => {
|
|
34
|
+
const dispatch = useDispatch();
|
|
35
|
+
const { showToast } = useToast();
|
|
36
|
+
|
|
37
|
+
const { activeFile } = useSelector(
|
|
38
|
+
(state: RootState) => state.chatSettingStore
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
if (!activeFile) {return;}
|
|
42
|
+
|
|
43
|
+
const requestStoragePermission = async () => {
|
|
44
|
+
try {
|
|
45
|
+
if (Platform.OS === 'android') {
|
|
46
|
+
if (Platform.Version >= 33) {
|
|
47
|
+
const permissions = [
|
|
48
|
+
PermissionsAndroid.PERMISSIONS.READ_MEDIA_IMAGES,
|
|
49
|
+
PermissionsAndroid.PERMISSIONS.READ_MEDIA_VIDEO,
|
|
50
|
+
PermissionsAndroid.PERMISSIONS.READ_MEDIA_AUDIO,
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const granted = await PermissionsAndroid.requestMultiple(permissions);
|
|
54
|
+
|
|
55
|
+
if (
|
|
56
|
+
granted['android.permission.READ_MEDIA_IMAGES'] ===
|
|
57
|
+
PermissionsAndroid.RESULTS.GRANTED &&
|
|
58
|
+
granted['android.permission.READ_MEDIA_VIDEO'] ===
|
|
59
|
+
PermissionsAndroid.RESULTS.GRANTED &&
|
|
60
|
+
granted['android.permission.READ_MEDIA_AUDIO'] ===
|
|
61
|
+
PermissionsAndroid.RESULTS.GRANTED
|
|
62
|
+
) {
|
|
63
|
+
return true;
|
|
64
|
+
} else {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
} else if (Platform.Version >= 30) {
|
|
68
|
+
const granted = await PermissionsAndroid.request(
|
|
69
|
+
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
|
|
70
|
+
{
|
|
71
|
+
title: 'Storage Permission Required',
|
|
72
|
+
message:
|
|
73
|
+
'This app needs access to your storage to download and save files.',
|
|
74
|
+
buttonPositive: 'OK',
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
|
|
79
|
+
return true;
|
|
80
|
+
} else {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
const result = await CameraRoll.getPhotos({
|
|
85
|
+
first: 1,
|
|
86
|
+
})
|
|
87
|
+
.then(() => true)
|
|
88
|
+
.catch(() => false);
|
|
89
|
+
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return true;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('Error requesting permission:', error);
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const saveToGallery = async () => {
|
|
102
|
+
const hasPermission = await requestStoragePermission();
|
|
103
|
+
if (!hasPermission) {
|
|
104
|
+
Alert.alert(
|
|
105
|
+
'Permission Denied',
|
|
106
|
+
'Storage permission is required to save files to the gallery.'
|
|
107
|
+
);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
let galleryPath, filePath;
|
|
113
|
+
|
|
114
|
+
if (Platform.OS === 'android') {
|
|
115
|
+
galleryPath = activeFile.mimetype.startsWith('image/')
|
|
116
|
+
? `${RNFS.ExternalStorageDirectoryPath}/Pictures`
|
|
117
|
+
: `${RNFS.ExternalStorageDirectoryPath}/Movies`;
|
|
118
|
+
|
|
119
|
+
await RNFS.mkdir(galleryPath);
|
|
120
|
+
|
|
121
|
+
let fileName = activeFile.fileName;
|
|
122
|
+
if (!fileName.includes('.')) {
|
|
123
|
+
fileName += activeFile.mimetype.startsWith('image/')
|
|
124
|
+
? '.jpg'
|
|
125
|
+
: '.mp4';
|
|
126
|
+
}
|
|
127
|
+
filePath = `${galleryPath}/${fileName}`;
|
|
128
|
+
} else {
|
|
129
|
+
const documentsPath = RNFS.DocumentDirectoryPath;
|
|
130
|
+
let fileName = activeFile.fileName;
|
|
131
|
+
if (!fileName.includes('.')) {
|
|
132
|
+
fileName += activeFile.mimetype.startsWith('image/')
|
|
133
|
+
? '.jpg'
|
|
134
|
+
: '.mp4';
|
|
135
|
+
}
|
|
136
|
+
filePath = `${documentsPath}/${fileName}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const res = await RNFS.downloadFile({
|
|
140
|
+
fromUrl: activeFile.fileURL,
|
|
141
|
+
toFile: filePath,
|
|
142
|
+
}).promise;
|
|
143
|
+
|
|
144
|
+
if (res.statusCode === 200) {
|
|
145
|
+
if (Platform.OS === 'ios') {
|
|
146
|
+
await CameraRoll.save(filePath, {
|
|
147
|
+
type: activeFile.mimetype.startsWith('image/') ? 'photo' : 'video',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
showToast({
|
|
152
|
+
id: Date.now().toString(),
|
|
153
|
+
title: 'Success',
|
|
154
|
+
message: 'Save successful',
|
|
155
|
+
type: 'success',
|
|
156
|
+
});
|
|
157
|
+
} else {
|
|
158
|
+
Alert.alert('Error', 'Failed to save the file.');
|
|
159
|
+
}
|
|
160
|
+
} catch (err) {
|
|
161
|
+
Alert.alert('Error', `Failed to save the file: ${activeFile.fileName}`);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const saveFileToDownloads = async () => {
|
|
166
|
+
const hasPermission = await requestStoragePermission();
|
|
167
|
+
if (!hasPermission) {
|
|
168
|
+
Alert.alert(
|
|
169
|
+
'Permission Denied',
|
|
170
|
+
'Storage permission is required to save files.'
|
|
171
|
+
);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const downloadDest = `${RNFS.DownloadDirectoryPath}/${
|
|
177
|
+
activeFile.fileName || 'MEDIA-ETHORA'
|
|
178
|
+
}`;
|
|
179
|
+
|
|
180
|
+
const res = await RNFS.downloadFile({
|
|
181
|
+
fromUrl: activeFile.fileURL,
|
|
182
|
+
toFile: downloadDest,
|
|
183
|
+
}).promise;
|
|
184
|
+
|
|
185
|
+
if (res.statusCode === 200) {
|
|
186
|
+
showToast({
|
|
187
|
+
id: Date.now().toString(),
|
|
188
|
+
title: 'Success',
|
|
189
|
+
message: 'Save successful',
|
|
190
|
+
type: 'success',
|
|
191
|
+
});
|
|
192
|
+
} else {
|
|
193
|
+
Alert.alert('Error', 'Failed to save the file one.');
|
|
194
|
+
}
|
|
195
|
+
} catch (err) {
|
|
196
|
+
console.error('Error saving file:', err);
|
|
197
|
+
Alert.alert('Error', 'Failed to save the file two.');
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const saveClick = async () => {
|
|
202
|
+
if (
|
|
203
|
+
activeFile.mimetype.startsWith('image/') ||
|
|
204
|
+
activeFile.mimetype.startsWith('video/')
|
|
205
|
+
) {
|
|
206
|
+
await saveToGallery();
|
|
207
|
+
} else {
|
|
208
|
+
await saveFileToDownloads();
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const closeModal = () => {
|
|
213
|
+
dispatch(
|
|
214
|
+
setActiveFile({
|
|
215
|
+
fileName: '',
|
|
216
|
+
fileURL: '',
|
|
217
|
+
mimetype: '',
|
|
218
|
+
})
|
|
219
|
+
);
|
|
220
|
+
handleCloseModal?.();
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const getMediaComponent = useMemo(() => {
|
|
224
|
+
switch (true) {
|
|
225
|
+
case activeFile.mimetype.startsWith('image/'):
|
|
226
|
+
return (
|
|
227
|
+
<FullScreenImage
|
|
228
|
+
src={
|
|
229
|
+
activeFile.fileURL ||
|
|
230
|
+
'https://as2.ftcdn.net/v2/jpg/02/51/95/53/1000_F_251955356_FAQH0U1y1TZw3ZcdPGybwUkH90a3VAhb.jpg'
|
|
231
|
+
}
|
|
232
|
+
alt={activeFile.fileName}
|
|
233
|
+
/>
|
|
234
|
+
);
|
|
235
|
+
case activeFile.mimetype.startsWith('video/'):
|
|
236
|
+
return (
|
|
237
|
+
<Video
|
|
238
|
+
style={{
|
|
239
|
+
width: '100%',
|
|
240
|
+
height: '100%',
|
|
241
|
+
}}
|
|
242
|
+
source={{ uri: activeFile.fileURL }}
|
|
243
|
+
controls
|
|
244
|
+
resizeMode="contain"
|
|
245
|
+
paused={true}
|
|
246
|
+
/>
|
|
247
|
+
);
|
|
248
|
+
default:
|
|
249
|
+
return (
|
|
250
|
+
<View
|
|
251
|
+
style={{
|
|
252
|
+
backgroundColor: '#FFF8ED',
|
|
253
|
+
borderRadius: 16,
|
|
254
|
+
display: 'flex',
|
|
255
|
+
padding: 16,
|
|
256
|
+
}}
|
|
257
|
+
>
|
|
258
|
+
<Text>
|
|
259
|
+
Unable to open the uploaded document. The file format is not
|
|
260
|
+
supported by the system. Please upload a file in a compatible
|
|
261
|
+
format. You still can dowload this file.
|
|
262
|
+
</Text>
|
|
263
|
+
</View>
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}, [activeFile]);
|
|
267
|
+
|
|
268
|
+
return (
|
|
269
|
+
<ModalContainerFullScreen>
|
|
270
|
+
<ModalHeaderComponent
|
|
271
|
+
handleCloseModal={closeModal}
|
|
272
|
+
headerTitle={'File preview'}
|
|
273
|
+
rightMenu={
|
|
274
|
+
<>
|
|
275
|
+
<Button onPress={saveClick}>
|
|
276
|
+
<SaveIcon />
|
|
277
|
+
</Button>
|
|
278
|
+
</>
|
|
279
|
+
}
|
|
280
|
+
/>
|
|
281
|
+
|
|
282
|
+
<CenterContainer
|
|
283
|
+
style={{
|
|
284
|
+
display: 'flex',
|
|
285
|
+
height: '100%',
|
|
286
|
+
justifyContent: 'center',
|
|
287
|
+
overflow: 'hidden',
|
|
288
|
+
padding: 16,
|
|
289
|
+
}}
|
|
290
|
+
>
|
|
291
|
+
{getMediaComponent}
|
|
292
|
+
</CenterContainer>
|
|
293
|
+
|
|
294
|
+
</ModalContainerFullScreen>
|
|
295
|
+
);
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
export default FilePreviewModal;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ModalBackground } from '../styledModalComponents';
|
|
3
|
+
import { ModalType } from '../../../types/types';
|
|
4
|
+
import { useDispatch } from 'react-redux';
|
|
5
|
+
import { setActiveModal } from '../../../roomStore/chatSettingsSlice';
|
|
6
|
+
import {
|
|
7
|
+
MODAL_COMPONENTS,
|
|
8
|
+
MODAL_TYPES,
|
|
9
|
+
} from '../../../helpers/constants/MODAL_TYPES';
|
|
10
|
+
|
|
11
|
+
interface ModalProps {
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
modal?: string;
|
|
14
|
+
setOpenModal: (value?: ModalType) => any;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const Modal: React.FC<ModalProps> = ({ children, modal, setOpenModal }) => {
|
|
18
|
+
const dispatch = useDispatch();
|
|
19
|
+
const handleCloseModal = () => setOpenModal();
|
|
20
|
+
const handleBackButtonClick = () =>
|
|
21
|
+
dispatch(setActiveModal(MODAL_TYPES.SETTINGS));
|
|
22
|
+
|
|
23
|
+
const renderModalContent = () => {
|
|
24
|
+
if (!modal) {return null;}
|
|
25
|
+
|
|
26
|
+
const ModalComponent = MODAL_COMPONENTS[modal];
|
|
27
|
+
|
|
28
|
+
if (!ModalComponent) {return null;}
|
|
29
|
+
|
|
30
|
+
const handleClose =
|
|
31
|
+
modal === MODAL_TYPES.MANAGE_DATA ||
|
|
32
|
+
modal === MODAL_TYPES.VISIBILITY ||
|
|
33
|
+
modal === MODAL_TYPES.REFERRALS ||
|
|
34
|
+
modal === MODAL_TYPES.DOCUMENT_SHARES ||
|
|
35
|
+
modal === MODAL_TYPES.PROFILE_SHARES ||
|
|
36
|
+
modal === MODAL_TYPES.BLOCKED_USERS
|
|
37
|
+
? handleBackButtonClick
|
|
38
|
+
: handleCloseModal;
|
|
39
|
+
|
|
40
|
+
return <ModalComponent handleCloseModal={handleClose} />;
|
|
41
|
+
};
|
|
42
|
+
return (
|
|
43
|
+
modal && (
|
|
44
|
+
<ModalBackground id="modal-background" style={{ position: 'absolute' }}>
|
|
45
|
+
{renderModalContent()}
|
|
46
|
+
{children}
|
|
47
|
+
</ModalBackground>
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default Modal;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
HeaderContainer,
|
|
4
|
+
HeaderLeft,
|
|
5
|
+
HeaderRight,
|
|
6
|
+
} from './styledModalComponents';
|
|
7
|
+
import { BackIcon, MoreIcon, QrIcon } from '../../assets/icons';
|
|
8
|
+
import Button from '../styled/Button';
|
|
9
|
+
import { Text } from 'react-native';
|
|
10
|
+
|
|
11
|
+
interface ModalHeaderComponentProps {
|
|
12
|
+
handleCloseModal?: any;
|
|
13
|
+
headerTitle?: string;
|
|
14
|
+
rightMenu?: React.ReactNode;
|
|
15
|
+
leftMenu?: React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const ModalHeaderComponent: React.FC<ModalHeaderComponentProps> = ({
|
|
19
|
+
handleCloseModal,
|
|
20
|
+
headerTitle,
|
|
21
|
+
rightMenu,
|
|
22
|
+
leftMenu,
|
|
23
|
+
}) => {
|
|
24
|
+
return (
|
|
25
|
+
<HeaderContainer>
|
|
26
|
+
<HeaderLeft>
|
|
27
|
+
{leftMenu ? (
|
|
28
|
+
leftMenu
|
|
29
|
+
) : (
|
|
30
|
+
<>
|
|
31
|
+
<Button EndIcon={<BackIcon />} onPress={handleCloseModal} />
|
|
32
|
+
<Text>{headerTitle ?? 'Go back'}</Text>
|
|
33
|
+
</>
|
|
34
|
+
)}
|
|
35
|
+
</HeaderLeft>
|
|
36
|
+
<HeaderRight>{rightMenu}</HeaderRight>
|
|
37
|
+
</HeaderContainer>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default ModalHeaderComponent;
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import React, { FC, useMemo } from 'react';
|
|
2
|
+
import { Alert, Linking, Platform } from 'react-native';
|
|
3
|
+
import Button from '../../styled/Button';
|
|
4
|
+
import DropdownMenu from '../../DropdownMenu/DropdownMenu';
|
|
5
|
+
import DocumentPicker from 'react-native-document-picker';
|
|
6
|
+
import ImagePicker from 'react-native-image-crop-picker';
|
|
7
|
+
import {
|
|
8
|
+
check,
|
|
9
|
+
request,
|
|
10
|
+
PERMISSIONS,
|
|
11
|
+
RESULTS,
|
|
12
|
+
Permission,
|
|
13
|
+
} from 'react-native-permissions';
|
|
14
|
+
import {
|
|
15
|
+
AttachIcon,
|
|
16
|
+
CameraIcon,
|
|
17
|
+
DocumentIcon,
|
|
18
|
+
MediaIcon,
|
|
19
|
+
} from '../../../assets/icons';
|
|
20
|
+
import { MediaFile } from '../../../types/types';
|
|
21
|
+
|
|
22
|
+
interface ModalSelectMediaProps {
|
|
23
|
+
onFileSelect: (files: MediaFile[]) => void;
|
|
24
|
+
config?: any;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface Permissions {
|
|
28
|
+
UNAVAILABLE: 'unavailable';
|
|
29
|
+
BLOCKED: 'blocked';
|
|
30
|
+
DENIED: 'denied';
|
|
31
|
+
GRANTED: 'granted';
|
|
32
|
+
LIMITED: 'limited';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const ModalSelectMedia: FC<ModalSelectMediaProps> = ({
|
|
36
|
+
onFileSelect,
|
|
37
|
+
config,
|
|
38
|
+
}) => {
|
|
39
|
+
const checkPermission = async (permission: Permission) => {
|
|
40
|
+
const status = await check(permission);
|
|
41
|
+
|
|
42
|
+
if (status === RESULTS.GRANTED) {
|
|
43
|
+
return status;
|
|
44
|
+
} else if (status === RESULTS.DENIED) {
|
|
45
|
+
const requestStatus = await request(permission);
|
|
46
|
+
if (requestStatus === RESULTS.GRANTED) {
|
|
47
|
+
return requestStatus;
|
|
48
|
+
} else if (requestStatus === RESULTS.DENIED) {
|
|
49
|
+
return requestStatus;
|
|
50
|
+
}
|
|
51
|
+
} else if (status === RESULTS.UNAVAILABLE) {
|
|
52
|
+
return status;
|
|
53
|
+
} else {
|
|
54
|
+
return status;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const handleCameraSelection = async () => {
|
|
59
|
+
const permission =
|
|
60
|
+
Platform.OS === 'ios'
|
|
61
|
+
? PERMISSIONS.IOS.CAMERA
|
|
62
|
+
: PERMISSIONS.ANDROID.CAMERA;
|
|
63
|
+
const permissionStatus = await checkPermission(permission);
|
|
64
|
+
|
|
65
|
+
if (permissionStatus !== RESULTS.GRANTED) {
|
|
66
|
+
Alert.alert(
|
|
67
|
+
'Permission required',
|
|
68
|
+
'Camera permission is needed to take photos.',
|
|
69
|
+
[
|
|
70
|
+
{
|
|
71
|
+
text: 'Cancel',
|
|
72
|
+
onPress: () => console.log('Camera permission cancelled'),
|
|
73
|
+
style: 'cancel',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
text: 'Open Settings',
|
|
77
|
+
onPress: () => Linking.openSettings(),
|
|
78
|
+
},
|
|
79
|
+
]
|
|
80
|
+
);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const image = await ImagePicker.openCamera({
|
|
86
|
+
width: 300,
|
|
87
|
+
height: 400,
|
|
88
|
+
cropping: true,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const originalName = image.path.split('/').pop();
|
|
92
|
+
const file = {
|
|
93
|
+
uri: image.path,
|
|
94
|
+
type: image.mime,
|
|
95
|
+
name: originalName || `camera_${Date.now()}.jpg`,
|
|
96
|
+
};
|
|
97
|
+
onFileSelect([file]);
|
|
98
|
+
} catch (error: any) {
|
|
99
|
+
const errorMessage = error?.message || String(error);
|
|
100
|
+
const isSimulatorError =
|
|
101
|
+
errorMessage.includes('simulator') ||
|
|
102
|
+
errorMessage.includes('Cannot run camera') ||
|
|
103
|
+
errorMessage.includes('Camera not available');
|
|
104
|
+
|
|
105
|
+
if (isSimulatorError) {
|
|
106
|
+
Alert.alert(
|
|
107
|
+
'Camera unavailable',
|
|
108
|
+
'Camera is not available on iOS Simulator. Please test on a real device.',
|
|
109
|
+
[{ text: 'OK' }]
|
|
110
|
+
);
|
|
111
|
+
} else if (error?.code !== 'E_PICKER_CANCELLED') {
|
|
112
|
+
console.error('Camera error:', error);
|
|
113
|
+
Alert.alert(
|
|
114
|
+
'Camera error',
|
|
115
|
+
errorMessage || 'Failed to open camera. Please try again.',
|
|
116
|
+
[{ text: 'OK' }]
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const handleGallerySelection = async () => {
|
|
123
|
+
try {
|
|
124
|
+
let permission: Permission;
|
|
125
|
+
|
|
126
|
+
if (Platform.OS === 'ios') {
|
|
127
|
+
permission = PERMISSIONS.IOS.PHOTO_LIBRARY;
|
|
128
|
+
} else if (Number(Platform.Version) >= 33) {
|
|
129
|
+
permission = PERMISSIONS.ANDROID.READ_MEDIA_IMAGES;
|
|
130
|
+
} else {
|
|
131
|
+
permission = PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
console.log('handleGallerySelection - checking permission:', permission);
|
|
135
|
+
const permissionStatus = await checkPermission(permission);
|
|
136
|
+
console.log('handleGallerySelection - permission status:', permissionStatus);
|
|
137
|
+
|
|
138
|
+
if (permissionStatus !== RESULTS.GRANTED) {
|
|
139
|
+
console.log('handleGallerySelection - permission not granted, showing alert');
|
|
140
|
+
Alert.alert(
|
|
141
|
+
'Permission required',
|
|
142
|
+
'Gallery permission is needed to select photos.',
|
|
143
|
+
[
|
|
144
|
+
{
|
|
145
|
+
text: 'Cancel',
|
|
146
|
+
onPress: () => console.log('Gallery permission cancelled'),
|
|
147
|
+
style: 'cancel',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
text: 'Open Settings',
|
|
151
|
+
onPress: () => Linking.openSettings(),
|
|
152
|
+
},
|
|
153
|
+
]
|
|
154
|
+
);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
159
|
+
const image = await ImagePicker.openPicker({
|
|
160
|
+
multiple: false,
|
|
161
|
+
mediaType: 'any',
|
|
162
|
+
});
|
|
163
|
+
console.log('handleGallerySelection - image selected:', image);
|
|
164
|
+
|
|
165
|
+
const originalName = image.path.split('/').pop();
|
|
166
|
+
const file = {
|
|
167
|
+
uri: image.path,
|
|
168
|
+
type: image.mime,
|
|
169
|
+
name:
|
|
170
|
+
originalName ||
|
|
171
|
+
`gallery_${Date.now()}${
|
|
172
|
+
image.mime.includes('video') ? '.mp4' : '.jpg'
|
|
173
|
+
}`,
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
onFileSelect([file]);
|
|
177
|
+
} catch (error: any) {
|
|
178
|
+
if (error?.code === 'E_PICKER_CANCELLED') {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
console.error('Gallery error:', error);
|
|
183
|
+
console.error('Gallery error code:', error?.code);
|
|
184
|
+
console.error('Gallery error message:', error?.message);
|
|
185
|
+
|
|
186
|
+
const errorMessage = error?.message || String(error);
|
|
187
|
+
Alert.alert(
|
|
188
|
+
'Gallery error',
|
|
189
|
+
errorMessage || 'Failed to open gallery. Please try again.',
|
|
190
|
+
[{ text: 'OK' }]
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const handleFileSelection = async () => {
|
|
196
|
+
try {
|
|
197
|
+
const result = await DocumentPicker.pick({
|
|
198
|
+
type: [DocumentPicker.types.allFiles],
|
|
199
|
+
allowMultiSelection: false,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const files = result.map((file) => {
|
|
203
|
+
const originalName = file.name;
|
|
204
|
+
return {
|
|
205
|
+
uri: file.uri,
|
|
206
|
+
type: file.type || 'unknown',
|
|
207
|
+
name: originalName || `file_${Date.now()}`,
|
|
208
|
+
};
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
onFileSelect(files);
|
|
212
|
+
} catch (err: any) {
|
|
213
|
+
if (DocumentPicker.isCancel(err)) {
|
|
214
|
+
console.log('User cancelled file picker');
|
|
215
|
+
} else {
|
|
216
|
+
console.error('DocumentPicker Error:', err);
|
|
217
|
+
const errorMessage = err?.message || String(err);
|
|
218
|
+
Alert.alert(
|
|
219
|
+
'File selection error',
|
|
220
|
+
errorMessage || 'Failed to select file. Please try again.',
|
|
221
|
+
[{ text: 'OK' }]
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const menuOptions = useMemo(
|
|
228
|
+
() => [
|
|
229
|
+
{
|
|
230
|
+
label: 'Camera',
|
|
231
|
+
icon: <CameraIcon />,
|
|
232
|
+
onClick: async () => {
|
|
233
|
+
setTimeout(async () => {
|
|
234
|
+
await handleCameraSelection();
|
|
235
|
+
}, 500);
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
label: 'Media File',
|
|
240
|
+
icon: <MediaIcon />,
|
|
241
|
+
onClick: async () => {
|
|
242
|
+
await handleGallerySelection();
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
label: 'Document',
|
|
247
|
+
icon: <DocumentIcon />,
|
|
248
|
+
onClick: async () => {
|
|
249
|
+
setTimeout(async () => {
|
|
250
|
+
await handleFileSelection();
|
|
251
|
+
}, 500);
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
[]
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
return (
|
|
259
|
+
<DropdownMenu
|
|
260
|
+
position="leftBottom"
|
|
261
|
+
options={menuOptions}
|
|
262
|
+
openButton={(onPress) => {
|
|
263
|
+
console.log('🔵 [ModalSelectMedia] Rendering attach button');
|
|
264
|
+
return (
|
|
265
|
+
<Button
|
|
266
|
+
style={{
|
|
267
|
+
padding: 0,
|
|
268
|
+
height: 40,
|
|
269
|
+
width: 40,
|
|
270
|
+
justifyContent: 'center',
|
|
271
|
+
alignItems: 'center',
|
|
272
|
+
backgroundColor: 'transparent',
|
|
273
|
+
margin: 0,
|
|
274
|
+
}}
|
|
275
|
+
EndIcon={<AttachIcon color={config?.colors?.primary || '#0052CD'} />}
|
|
276
|
+
onPress={() => {
|
|
277
|
+
console.log('🔵 [ModalSelectMedia] Attach button pressed');
|
|
278
|
+
onPress();
|
|
279
|
+
}}
|
|
280
|
+
/>
|
|
281
|
+
);
|
|
282
|
+
}}
|
|
283
|
+
/>
|
|
284
|
+
);
|
|
285
|
+
};
|