isometrik-chat 0.1.0

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.
Files changed (188) hide show
  1. package/README.md +74 -0
  2. package/babel.config.js +6 -0
  3. package/dist/index.js +684 -0
  4. package/package.json +59 -0
  5. package/public/Logo-192x192.png +0 -0
  6. package/public/Logo-512x512.png +0 -0
  7. package/public/favicon.ico +0 -0
  8. package/public/fonts/BenjaminVictoria.ttf +0 -0
  9. package/public/icons/arrow_logo.svg +9 -0
  10. package/public/icons/assets/ic_placeholder_banner.svg +1 -0
  11. package/public/icons/attach-file.svg +9 -0
  12. package/public/icons/audio_pause.svg +1 -0
  13. package/public/icons/audio_play.svg +6 -0
  14. package/public/icons/back.svg +3 -0
  15. package/public/icons/bell.svg +1 -0
  16. package/public/icons/block.svg +1 -0
  17. package/public/icons/bottom-arrow.svg +1 -0
  18. package/public/icons/camera-switch.svg +12 -0
  19. package/public/icons/camera.svg +4 -0
  20. package/public/icons/cancel.svg +1 -0
  21. package/public/icons/chat empty placeholder.svg +58 -0
  22. package/public/icons/chat_audio_pause.png +0 -0
  23. package/public/icons/chat_audio_play.png +0 -0
  24. package/public/icons/close.svg +5 -0
  25. package/public/icons/crossCarousel.svg +3 -0
  26. package/public/icons/delete.svg +3 -0
  27. package/public/icons/disappear.svg +24 -0
  28. package/public/icons/document.png +0 -0
  29. package/public/icons/document.svg +1 -0
  30. package/public/icons/downloadCarousel.svg +6 -0
  31. package/public/icons/edit-pencil.svg +6 -0
  32. package/public/icons/emoji.svg +8 -0
  33. package/public/icons/emojiCarousel.svg +3 -0
  34. package/public/icons/filter.svg +1 -0
  35. package/public/icons/forwardCarousel.svg +3 -0
  36. package/public/icons/gallery.svg +1 -0
  37. package/public/icons/goToMessageCarousel.svg +3 -0
  38. package/public/icons/ic_uil_arrow-left.svg +1 -0
  39. package/public/icons/ic_uil_eye-slash.svg +1 -0
  40. package/public/icons/ic_uil_eye.svg +1 -0
  41. package/public/icons/leftArrowCarousel.svg +6 -0
  42. package/public/icons/light-mode.svg +14 -0
  43. package/public/icons/lock.svg +1 -0
  44. package/public/icons/login_background.png +0 -0
  45. package/public/icons/menu .svg +5 -0
  46. package/public/icons/menuCarousel.svg +5 -0
  47. package/public/icons/message.svg +3 -0
  48. package/public/icons/placeholder.svg +958 -0
  49. package/public/icons/poll.svg +1 -0
  50. package/public/icons/retake.png +0 -0
  51. package/public/icons/right-arrow.svg +3 -0
  52. package/public/icons/right.svg +3 -0
  53. package/public/icons/round-star.svg +1 -0
  54. package/public/icons/search.svg +3 -0
  55. package/public/icons/send.svg +10 -0
  56. package/public/icons/starCarousel.svg +3 -0
  57. package/public/icons/status.svg +1 -0
  58. package/public/icons/sticker.svg +1 -0
  59. package/public/icons/thumb-down.svg +1 -0
  60. package/public/icons/user.svg +1 -0
  61. package/public/icons/users.svg +1 -0
  62. package/public/icons/voice.png +0 -0
  63. package/public/index.html +38 -0
  64. package/public/logo192.png +0 -0
  65. package/public/logo512.png +0 -0
  66. package/public/manifest.json +25 -0
  67. package/public/offline.html +12 -0
  68. package/public/robots.txt +3 -0
  69. package/public/service-worker.js +81 -0
  70. package/src/App.js +15 -0
  71. package/src/App.test.js +8 -0
  72. package/src/Authpage.js +16 -0
  73. package/src/ChatContext.js +172 -0
  74. package/src/Data/index.js +110 -0
  75. package/src/assets/icons.js +49 -0
  76. package/src/assets/images/WhatsApp.html +258 -0
  77. package/src/assets/images/WhatsApp_files/301446776_522918349234681_1974693392291574064_n.jpg +0 -0
  78. package/src/assets/images/WhatsApp_files/app-bf223f825866ee433b07.css +242 -0
  79. package/src/assets/images/WhatsApp_files/app.77ee8aa7a4c593101105.js +77 -0
  80. package/src/assets/images/WhatsApp_files/lazy_loaded_high_priority_components.85a06e74a0a4ade1640b.css +16 -0
  81. package/src/assets/images/WhatsApp_files/lazy_loaded_low_priority_components.8621270bc215a9298a97.css +47 -0
  82. package/src/assets/images/WhatsApp_files/libsignal-protocol-ee5b8ba.min.js +21 -0
  83. package/src/assets/images/WhatsApp_files/main.48b845d68e066fb27a75.css +161 -0
  84. package/src/assets/images/WhatsApp_files/runtime.e6018f3c1e255e8f4dc7.js +2 -0
  85. package/src/assets/images/WhatsApp_files/stylex-d50abd61e6cf7eab2afd855adccf14e5.css +2841 -0
  86. package/src/assets/images/WhatsApp_files/vendor1_app.58a51d93a250f83ab555.js +79 -0
  87. package/src/assets/images/bg.jpeg +0 -0
  88. package/src/assets/images/drkbg.jpg +0 -0
  89. package/src/assets/images/notFound.jpeg +0 -0
  90. package/src/assets/images/watsapp.jpg +0 -0
  91. package/src/assets/images/watsappbg.png +0 -0
  92. package/src/assets/images/wb.jpg +0 -0
  93. package/src/assets/images/whatsapp.jpeg +0 -0
  94. package/src/components/ChatBox/AudioBubble.js +162 -0
  95. package/src/components/ChatBox/ChatBubble.js +232 -0
  96. package/src/components/ChatBox/DocumentBubble.js +87 -0
  97. package/src/components/ChatBox/MessagesBox.js +533 -0
  98. package/src/components/CustomModal.js +60 -0
  99. package/src/components/Icon.js +10 -0
  100. package/src/components/ImageComponent.js +24 -0
  101. package/src/components/MediaDocs.js +155 -0
  102. package/src/components/MediaDocumentContainer.js +55 -0
  103. package/src/components/MessageInfoDropdown.js +124 -0
  104. package/src/components/Modal/AllowMicPermissionModal.js +63 -0
  105. package/src/components/Modal/BlockUnblockChatModal.js +78 -0
  106. package/src/components/Modal/CameraPermissionBlockedModal.js +61 -0
  107. package/src/components/Modal/CameraPermissionRequestModal.js +60 -0
  108. package/src/components/Modal/ClearChatModal.js +78 -0
  109. package/src/components/Modal/DeleteChatModal.js +79 -0
  110. package/src/components/Modal/MicPermissionDisableModal.js +63 -0
  111. package/src/components/Modal/Modal.js +103 -0
  112. package/src/components/Modal/ModalDialog.js +103 -0
  113. package/src/components/Modal/ProfilePictureUploadPreview.js +160 -0
  114. package/src/components/OutsideAlerter/OutsideAlerter.js +38 -0
  115. package/src/components/ProfilePicture/ProfilePicture.js +127 -0
  116. package/src/components/Registration/Login.js +265 -0
  117. package/src/components/Registration/SignUp.js +322 -0
  118. package/src/components/SnackBar.js +42 -0
  119. package/src/components/common/Modal/useDetectOutsideClick.js +23 -0
  120. package/src/components/common/styled/PageWrapper.js +25 -0
  121. package/src/components/formcontrol/CustomButton.js +38 -0
  122. package/src/components/formcontrol/InputText.js +60 -0
  123. package/src/global-styles.js +42 -0
  124. package/src/hooks/useDeviceType.js +28 -0
  125. package/src/hooks/useThrottle.js +29 -0
  126. package/src/index.css +225 -0
  127. package/src/index.js +23 -0
  128. package/src/lib/constant.js +21 -0
  129. package/src/lib/functionality.js +13 -0
  130. package/src/lib/helpers.js +320 -0
  131. package/src/lib/mockData/index.js +76 -0
  132. package/src/lib/session/index.js +31 -0
  133. package/src/lib/validation.js +4 -0
  134. package/src/logo.svg +1 -0
  135. package/src/pages/WhatsappMainBox/index.js +574 -0
  136. package/src/reportWebVitals.js +13 -0
  137. package/src/services/deliveryStatus.js +27 -0
  138. package/src/setupTests.js +5 -0
  139. package/src/utils/chatSdk.js +14 -0
  140. package/src/utils/global.js +57 -0
  141. package/src/utils/media.js +79 -0
  142. package/src/view/component/BlockedContactSlide.js +134 -0
  143. package/src/view/component/Carousle/UpperMenuBar.js +106 -0
  144. package/src/view/component/Carousle/index.js +204 -0
  145. package/src/view/component/Chatbox.js/AudioRecorder.js +311 -0
  146. package/src/view/component/Chatbox.js/ChatBubbleReply.js +27 -0
  147. package/src/view/component/Chatbox.js/TakePhoto.js +363 -0
  148. package/src/view/component/Chatbox.js/index.js +856 -0
  149. package/src/view/component/Chatbox.js/styles.css +231 -0
  150. package/src/view/component/Contact/index.js +56 -0
  151. package/src/view/component/Contact/styles.css +208 -0
  152. package/src/view/component/ContactInfo/index.js +543 -0
  153. package/src/view/component/ContactInfo/styles.css +289 -0
  154. package/src/view/component/Context/index.js +3 -0
  155. package/src/view/component/DialogBox.js +15 -0
  156. package/src/view/component/ImageCropper/ImageCropper.js +128 -0
  157. package/src/view/component/Loader/Loader.js +52 -0
  158. package/src/view/component/Loader/UserPagingLoader.js +62 -0
  159. package/src/view/component/MainChatBox/index.js +819 -0
  160. package/src/view/component/MainChatBox/styles.css +124 -0
  161. package/src/view/component/Menu/index.js +261 -0
  162. package/src/view/component/Menu/styles.css +68 -0
  163. package/src/view/component/Profile/ProfileInfoContainer.js +112 -0
  164. package/src/view/component/Profile/ProfileUpdate.js +178 -0
  165. package/src/view/component/Profile/TakeProfilePhoto.js +391 -0
  166. package/src/view/component/Profile/index.js +550 -0
  167. package/src/view/component/Profile/styles.css +370 -0
  168. package/src/view/component/ReplyChatMessage/ReplyChatMessage.js +48 -0
  169. package/src/view/component/SeachBar/index.js +106 -0
  170. package/src/view/component/SeachBar/styles.css +53 -0
  171. package/src/view/component/Siderbar/index.js +512 -0
  172. package/src/view/component/Siderbar/styles.css +138 -0
  173. package/src/view/component/Toaster/Toaster.js +117 -0
  174. package/src/view/component/UserDetailsCard/UserDetailCard.js +337 -0
  175. package/src/view/component/deleteMessageMoal.js +80 -0
  176. package/src/view/component/emoji/index.js +22 -0
  177. package/src/view/component/emoji/sstyles.css +0 -0
  178. package/src/view/component/forwardData/index.js +327 -0
  179. package/src/view/component/forwardData/styles.css +112 -0
  180. package/src/view/component/forwardPopup/index.js +55 -0
  181. package/src/view/component/forwardPopup/styles.css +144 -0
  182. package/src/view/component/mediaList/index.js +92 -0
  183. package/src/view/component/menuDialog/index.js +71 -0
  184. package/src/view/component/menuDialog/styles.css +24 -0
  185. package/src/view/component/pagination/pagination.js +52 -0
  186. package/src/view/component/pagination/paginationForMsg.js +43 -0
  187. package/src/view/component/sidebarChat/index.js +321 -0
  188. package/src/view/component/sidebarChat/styles.css +109 -0
@@ -0,0 +1,311 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import styled, { css } from 'styled-components';
3
+ import ImageComponent from '../../../components/ImageComponent';
4
+ import { AUDIO_PAUSE, AUDIO_PLAY, CANCEl, CHAT_AUDIO_PAUSE, CHAT_AUDIO_PLAY, DELETEICON } from '../../../utils/global';
5
+ import { convertSecondsToMinutes, dataURLtoFile, generatedMessagePresignedUrls, getMediaUrl } from '../../../lib/helpers';
6
+ import CustomModal from '../../../components/CustomModal';
7
+ import MicPermissionDisableModal from '../../../components/Modal/MicPermissionDisableModal';
8
+ import { mobile } from '../../../utils/media';
9
+ import AllowMicPermissionModal from '../../../components/Modal/AllowMicPermissionModal';
10
+ import WaveSurfer from 'wavesurfer.js';
11
+
12
+ const AudioRecorderWrapper = styled.div`
13
+ width: 100%;
14
+ display: flex;
15
+ justify-content: flex-end;
16
+ align-items: center;
17
+ padding: 0.5rem 2rem;
18
+ gap: 1rem;
19
+ visibility: ${props => props.isVisible ? 'visible' : 'hidden'};
20
+
21
+ ${mobile(css`
22
+ width: 90%;
23
+ padding: 0 0.8rem;
24
+ `)}
25
+
26
+ .stop_recording_icon{
27
+ width: 30px;
28
+ height: 30px;
29
+ filter: ${props => props.theme ? 'invert(0)' : ''};
30
+ cursor: pointer;
31
+ }
32
+ `;
33
+
34
+ const AudioMicWrapper = styled.div`
35
+ height: 76px;
36
+ `;
37
+
38
+ const ShowRecordedAudioWrapper = styled.div`
39
+ position: relative;
40
+ display: flex;
41
+ align-items: center;
42
+ width: ${props => props.audioRecorded ? '50%' : 'fit-content'};
43
+
44
+
45
+ .wave_container{
46
+ width: 100%;
47
+
48
+ wave{
49
+ ::-webkit-scrollbar {
50
+ display: none;
51
+ }
52
+ -ms-overflow-style: none; /* IE and Edge */
53
+ scrollbar-width: none; /* Firefox */
54
+ }
55
+ }
56
+
57
+ .chat_audio_play_pause{
58
+ width: 16px;
59
+ height: 16px;
60
+ margin-right: 1rem;
61
+ filter: ${props => props.theme === true ? 'invert(1)' : 'unset'};
62
+ }
63
+ `;
64
+
65
+ const AudioTime = styled.p`
66
+ font-size: 14px;
67
+ color: var(--chat_timing);
68
+ margin-bottom: 0;
69
+ margin-left: 1rem;
70
+ `;
71
+
72
+ const AudioRecordDot = styled.div`
73
+ width: 16px;
74
+ height: 16px;
75
+ background-color: var(--profile-color);
76
+ border-radius: 50%;
77
+ animation: blink 1s infinite;
78
+
79
+ @keyframes blink {
80
+ 0% {
81
+ opacity: 1;
82
+ }
83
+ 50% {
84
+ opacity: 0;
85
+ }
86
+ 100% {
87
+ opacity: 1;
88
+ }
89
+ }
90
+ `;
91
+
92
+ const AudioRecorder = React.forwardRef((props, ref) => {
93
+ const { theme, onClose, conversationId, setRecordedStream, setMessageText, recordedStream, setAudioRecorderStatus, audioRecorderStatus } = props;
94
+ const [recording, setRecording] = useState(true);
95
+ const [recordingStream, setRecordingStream] = useState(null);
96
+ const [finalAudioLink, setFinalAudioLink] = useState('');
97
+ const mediaRecorderRef = useRef(null);
98
+ const audioRef = useRef(null);
99
+ const waveformRef = useRef(null);
100
+ const wavesurfer = useRef(null);
101
+ const [isMicPermissionDisable, setIsMicPermissionDisable] = useState(false);
102
+ const [isMicPermissionAllow, setIsMicPermissionAllow] = useState(true);
103
+ const [isPlaying, setIsPlaying] = useState(false);
104
+ const [audioDuration, setAudioDuration] = useState(0);
105
+ const [time, setTime] = useState(0);
106
+ // const [recordedChunks, setRecordedChunks] = useState({});
107
+ let recordedChunks = [];
108
+ let combinedChunks = [];
109
+
110
+ const startRecording = async (e) => {
111
+ try {
112
+ setMessageText(false);
113
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
114
+ setRecordingStream(stream);
115
+ startTimer();
116
+ setIsMicPermissionAllow(false);
117
+ mediaRecorderRef.current = new MediaRecorder(stream);
118
+ mediaRecorderRef.current.addEventListener("dataavailable", handleDataAvailable);
119
+ mediaRecorderRef.current.start();
120
+ setRecording(true);
121
+ } catch (error) {
122
+ console.error('error', error);
123
+ setIsMicPermissionDisable(true);
124
+ setIsMicPermissionAllow(true);
125
+ }
126
+ };
127
+
128
+ useEffect(() => {
129
+ try {
130
+ if (finalAudioLink?.length > 0) {
131
+ wavesurfer.current = WaveSurfer.create({
132
+ container: waveformRef.current,
133
+ waveColor: '#6f8171',
134
+ progressColor: '#6f8171',
135
+ height: 40,
136
+ barHeight: 1.5,
137
+ barWidth: 3,
138
+ barGap: 2,
139
+ });
140
+
141
+ wavesurfer.current.load(finalAudioLink);
142
+
143
+ wavesurfer.current.on('ready', () => {
144
+ const totalDuration = wavesurfer.current.getDuration();
145
+ const getSortedTime = convertSecondsToMinutes(Math.round(totalDuration));
146
+ setAudioDuration(getSortedTime);
147
+ });
148
+
149
+ wavesurfer.current.on('audioprocess', () => {
150
+ const totalDuration = wavesurfer.current.getCurrentTime();
151
+ const getSortedTime = convertSecondsToMinutes(Math.round(totalDuration));
152
+ setAudioDuration(getSortedTime);
153
+ });
154
+
155
+ wavesurfer.current.on('finish', () => {
156
+ setIsPlaying(false);
157
+ });
158
+ }
159
+ } catch (error) {
160
+ console.error('error', error);
161
+ }
162
+
163
+
164
+ return () => {
165
+ wavesurfer?.current?.destroy();
166
+ setIsPlaying(false);
167
+ };
168
+
169
+ }, [finalAudioLink]);
170
+
171
+
172
+ const audioHandler = () => {
173
+ if (!wavesurfer.current.isPlaying()) {
174
+ setIsPlaying(true);
175
+ wavesurfer.current.play();
176
+ } else {
177
+ setIsPlaying(false);
178
+ wavesurfer.current.pause();
179
+ }
180
+ };
181
+
182
+ const getPlayPauseIcon = () => {
183
+ if (isPlaying) {
184
+ return (
185
+ <ImageComponent className="chat_audio_play_pause pointer" src={AUDIO_PLAY } alt="chat_audio_pause" />
186
+ )
187
+ } else {
188
+ return (
189
+ <ImageComponent className="chat_audio_play_pause pointer" src={AUDIO_PAUSE} alt="chat_audio_play" />
190
+ )
191
+ }
192
+ }
193
+
194
+
195
+ useEffect(() => {
196
+ startRecording();
197
+ }, [])
198
+
199
+ const stopRecording = async (e) => {
200
+ if (recordingStream) {
201
+ recordingStream.getTracks().forEach((track) => {
202
+ track.stop();
203
+ });
204
+ }
205
+ setRecordingStream(null);
206
+ setRecording(false);
207
+ setMessageText(true);
208
+ };
209
+
210
+ const handleDataAvailable = async ({ data }) => {
211
+ setRecordedStream(data);
212
+ recordedChunks.push(data)
213
+ const audioURL = URL.createObjectURL(data);
214
+ setFinalAudioLink(audioURL);
215
+ };
216
+
217
+ const handleDeleteButtonClick = () => {
218
+ stopRecording();
219
+ onClose();
220
+ }
221
+
222
+ React.useImperativeHandle(ref, () => ({
223
+ handleDeleteButtonClick
224
+ }));
225
+
226
+ const handleMicPermissionModalClose = (e) => {
227
+ onClose();
228
+ setIsMicPermissionDisable(false);
229
+ setIsMicPermissionAllow(false);
230
+ };
231
+
232
+ const startTimer = () => {
233
+ try {
234
+ setInterval(() => {
235
+ setTime((prevTime) => prevTime + 1);
236
+ }, 1000);
237
+ } catch (error) {
238
+ console.error('error', error);
239
+ }
240
+
241
+ };
242
+
243
+ const formatTime = () => {
244
+ try {
245
+ const minutes = Math.floor(time / 60).toString().padStart(2, '0');
246
+ const seconds = (time % 60).toString().padStart(2, '0');
247
+ return `${minutes}:${seconds}`;
248
+ } catch (error) {
249
+ console.error('error', error);
250
+ }
251
+ };
252
+
253
+
254
+ return (
255
+ <>
256
+ <AudioRecorderWrapper isVisible={!isMicPermissionAllow && !isMicPermissionDisable} theme={theme}>
257
+ <ImageComponent className="pointer" onClick={handleDeleteButtonClick} src={DELETEICON} alt="delete_icon" />
258
+ <ShowRecordedAudioWrapper theme={theme} audioRecorded={finalAudioLink.length} >
259
+ {finalAudioLink.length > 0 &&
260
+ <div onClick={audioHandler}>{getPlayPauseIcon()}</div>
261
+ }
262
+ {
263
+ !finalAudioLink.length &&
264
+ <AudioRecordDot />
265
+ }
266
+ {
267
+ !finalAudioLink.length &&
268
+ <AudioTime>{formatTime()}</AudioTime>
269
+ }
270
+ {
271
+ finalAudioLink.length > 0 &&
272
+ <div className='wave_container' ref={waveformRef}></div>
273
+ }
274
+ {
275
+ finalAudioLink.length > 0 &&
276
+ <AudioTime>{audioDuration || ''}</AudioTime>
277
+ }
278
+ </ShowRecordedAudioWrapper>
279
+ {recording ?
280
+ <div onClick={stopRecording} className='stop_recording_icon'>
281
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><circle cx="16" cy="16" r="14.75" fill="none" stroke="currentColor" stroke-width="2.5" /><path fill="currentColor" d="M20.65 21.69V10.25h-3.34v11.44Zm-9.3-11.44v11.44h3.34V10.25Z" class="iwt3stqw s79hpmcy ksz6vod1" /></svg>
282
+ </div>
283
+ :
284
+ <></>
285
+ }
286
+ </AudioRecorderWrapper>
287
+ {
288
+ isMicPermissionDisable &&
289
+ <>
290
+ <AudioMicWrapper>
291
+ </AudioMicWrapper>
292
+ <CustomModal backDropClick={true} onClose={handleMicPermissionModalClose} open={isMicPermissionDisable}>
293
+ <MicPermissionDisableModal onClose={handleMicPermissionModalClose} />
294
+ </CustomModal>
295
+ </>
296
+ }
297
+ {
298
+ isMicPermissionAllow &&
299
+ <>
300
+ <AudioMicWrapper>
301
+ </AudioMicWrapper>
302
+ <CustomModal backDropClick={true} onClose={handleMicPermissionModalClose} open={isMicPermissionAllow}>
303
+ <AllowMicPermissionModal onClose={handleMicPermissionModalClose} />
304
+ </CustomModal>
305
+ </>
306
+ }
307
+ </>
308
+ );
309
+ })
310
+
311
+ export default AudioRecorder;
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import { decodeChatBody } from '../../../lib/helpers';
4
+ const ChatBubbleReplyWrapper = styled.div`
5
+ background: var(--reply-background-color);
6
+ padding: 0.5rem;
7
+ margin-bottom: 0.35rem;
8
+ `;
9
+ const SenderName = styled.h5`
10
+ color: var(--profile-color);
11
+ font-size: 0.7rem;
12
+ `;
13
+ const SenderText = styled.p`
14
+ color: var(--black);
15
+ margin-bottom: 0;
16
+ font-size: 0.8rem;
17
+ `;
18
+ const ChatBubbleReply = (props) => {
19
+ const { replyData, reply } = props;
20
+ return (
21
+ <ChatBubbleReplyWrapper>
22
+ <SenderName>{reply?.senderName}</SenderName>
23
+ <SenderText>{decodeChatBody(reply?.body)}</SenderText>
24
+ </ChatBubbleReplyWrapper>
25
+ );
26
+ }
27
+ export default ChatBubbleReply;
@@ -0,0 +1,363 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import styled, { css } from 'styled-components';
3
+ import { checkFileSize, dataURLtoFile, } from '../../../lib/helpers';
4
+ import { CAMERA_RETAKE, CAMERA_SWITCH, CLOSE_ICON, SENDICON } from '../../../utils/global';
5
+ import ImageComponent from '../../../components/ImageComponent';
6
+ import CustomModal from '../../../components/CustomModal';
7
+ import Loader from '../Loader/Loader';
8
+ import CameraPermissionBlockedModal from '../../../components/Modal/CameraPermissionBlockedModal';
9
+ import CameraPermissionRequestModal from '../../../components/Modal/CameraPermissionRequestModal';
10
+ import { mobile } from '../../../utils/media';
11
+ import useDeviceType from '../../../hooks/useDeviceType';
12
+
13
+ const TakeProfilePhotoWrapper = styled.div`
14
+ position: relative;
15
+ height: 100%;
16
+ width: 100%;
17
+ border: none;
18
+ cursor: default;
19
+ visibility: hidden;
20
+ background: var(--modal-backdrop);
21
+ display: flex;
22
+ justify-content: center;
23
+ align-items: center;
24
+ ${(props) =>
25
+ props.isActive &&
26
+ css`
27
+ visibility: visible;
28
+ opacity: 1;
29
+ transform: translateY(0);
30
+ `}
31
+
32
+ ${mobile(css`
33
+ width: 100%;
34
+ height: 100%;
35
+ `)}
36
+
37
+ .cross_icon{
38
+ width: 18px;
39
+ height: 18px;
40
+ }
41
+ `;
42
+
43
+ const ModalContainer = styled.div`
44
+ background-color: var(--modal_color);
45
+ color: var(--black);
46
+ padding: ${props => props.isPadding ? '0 2rem' : 'unset'};
47
+ padding-bottom: 3rem;
48
+ visibility: hidden;
49
+ width: 100%;
50
+ display: none;
51
+ ${(props) =>
52
+ props.isActive &&
53
+ css`
54
+ visibility: visible;
55
+ opacity: 1;
56
+ display: block;
57
+ `}
58
+
59
+ ${mobile(css`
60
+ width: 100%;
61
+ height: 100%;
62
+ `)}
63
+
64
+ .video_play{
65
+ width: 100%;
66
+ height: 80vh;
67
+ ${mobile(css`
68
+ height: 100%;
69
+ `)}
70
+ }
71
+
72
+ .user_clicked_pic{
73
+ width: 100%;
74
+ height: 80vh;
75
+ object-fit: cover;
76
+ border-radius: 0;
77
+ ${mobile(css`
78
+ width: 100%;
79
+ height: 400px;
80
+ `)}
81
+ }
82
+ `;
83
+
84
+ const CameraIconContainer = styled.div`
85
+ width: 60px;
86
+ height: 60px;
87
+ border-radius: 50%;
88
+ background-color: var(--profile-name);
89
+ display: ${props => !props.isActive ? 'flex' : 'none'};
90
+ justify-content: center;
91
+ align-items: center;
92
+ position: absolute;
93
+ left: 50%;
94
+ transform: translate(-50%, 0%);
95
+ bottom: -20px;
96
+ cursor: pointer;
97
+
98
+ .camera_icon{
99
+ width: 24px;
100
+ height: 24px;
101
+ }
102
+ `;
103
+
104
+ const ModalHeaderContainer = styled.div`
105
+ width: 100%;
106
+ display: flex;
107
+ justify-content: space-between;
108
+ padding: 1rem 2rem;
109
+ ${mobile(css`
110
+ padding: 1rem;
111
+ `)}
112
+ .header_wrapper{
113
+ display: flex;
114
+ }
115
+ `;
116
+
117
+ const ModalHeaderText = styled.p`
118
+ margin-bottom: 0;
119
+ color: var(--black);
120
+ margin-left: 1rem;
121
+ padding-top:${props => props.isPaddingTop ? '2rem' : 'unset'};
122
+ `;
123
+
124
+ const ClickedImageWrapper = styled.div`
125
+ position: relative;
126
+ ${mobile(css`
127
+ height: 90%;
128
+ display: flex;
129
+ align-items: center;
130
+ `)}
131
+ `;
132
+
133
+ const CorrectIconWrapper = styled.div`
134
+ width: 60px;
135
+ height: 60px;
136
+ border-radius: 50%;
137
+ background-color: var( --gray_color);
138
+ display: flex;
139
+ justify-content: center;
140
+ align-items: center;
141
+ position: absolute;
142
+ right: 50px;
143
+ bottom: -30px;
144
+
145
+ img{
146
+ width: 30px;
147
+ height: 30px;
148
+ }
149
+ `;
150
+
151
+ const VideoWrapper = styled.div`
152
+ display: ${props => !props.isActive ? 'block' : 'none'};
153
+ ${mobile(css`
154
+ height: 100%;
155
+ `)}
156
+ `
157
+
158
+ const LoaderVideoContainer = styled.div`
159
+ position: relative;
160
+ ${mobile(css`
161
+ height: 90%;
162
+ `)}
163
+ `;
164
+
165
+ const CameraSwitchContainer = styled.div`
166
+ display: flex;
167
+ align-items: center;
168
+
169
+ .camera_switch{
170
+ width: 20px;
171
+ height: 20px;
172
+ filter: ${props => props.theme ? ' invert(1) ': ''} ;
173
+ }
174
+ `;
175
+
176
+
177
+ const TakePhoto = (props) => {
178
+ const { isTakePhotoModal, onClose, updateProfileImageRequest, setIsTakePhotoModal, sendClickedImage, setConvertClickedImageToFileType, theme } = props;
179
+ const [getClickedPictureUrl, setGetClickedPictureUrl] = useState('');
180
+ const [takePhoto, setTakePhoto] = useState(true);
181
+ const [currentStream, setCurrentStream] = useState('');
182
+ const [loaderStatus, setLoaderStatus] = useState(true);
183
+ const [notAllowCameraPermission, setNotAllowCameraPermission] = useState('');
184
+ const [accessCamera, setAccessCamera] = useState(false);
185
+ const [cameraPermission, setCameraPermission] = useState(false);
186
+ const [isCameraSwitch, setIsCameraSwitch] = useState(false);
187
+ const [rotateCameraIcon, setRotateCameraIcon] = useState(true);
188
+ const isMobile = useDeviceType();
189
+
190
+
191
+ const closeStream = (stream) => {
192
+ const tracks = stream.getTracks();
193
+ tracks.forEach(function (track) {
194
+ track.stop();
195
+ });
196
+ }
197
+
198
+ const cameraClickedForPicture = (stream) => {
199
+ closeStream(stream);
200
+ setRotateCameraIcon(false);
201
+ }
202
+
203
+ useEffect(() => {
204
+ if (!takePhoto) return;
205
+ let newFacingMode;
206
+ if (isCameraSwitch) {
207
+ const videoTrack = currentStream.getVideoTracks()[0];
208
+ const currentFacingMode = videoTrack.getSettings().facingMode;
209
+ newFacingMode = currentFacingMode === 'user' ? 'environment' : 'user';
210
+ videoTrack.stop();
211
+ }
212
+ setLoaderStatus(true);
213
+ !cameraPermission && setAccessCamera(true);
214
+ const video = document.querySelector("video");
215
+ const canvas = document.createElement("canvas");
216
+ const ctx = canvas.getContext("2d");
217
+ const takePictureButton = document.querySelector("#take-picture");
218
+ navigator.mediaDevices
219
+ .getUserMedia({ video: isCameraSwitch ? { facingMode: newFacingMode } : true })
220
+ .then((stream) => {
221
+ setAccessCamera(false);
222
+ setLoaderStatus(false);
223
+ setCameraPermission(true);
224
+ video.srcObject = stream;
225
+ video.play();
226
+ setCurrentStream(stream);
227
+ takePictureButton.addEventListener('click', () => cameraClickedForPicture(stream));
228
+ })
229
+ .catch((err) => {
230
+ setAccessCamera(false);
231
+ setCameraPermission(false);
232
+ setNotAllowCameraPermission(true);
233
+ console.error(err);
234
+ });
235
+
236
+ const showCameraPicture = () => {
237
+ try {
238
+ // Set the canvas dimensions to match the video dimensions
239
+ canvas.width = video.videoWidth;
240
+ canvas.height = video.videoHeight;
241
+
242
+ // Draw the current video frame onto the canvas
243
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
244
+
245
+ // Convert the canvas image data to a base64-encoded URL
246
+ const imageDataUrl = canvas.toDataURL();
247
+ setTakePhoto(false);
248
+ setGetClickedPictureUrl(imageDataUrl);
249
+ const file = dataURLtoFile(imageDataUrl, 'myimage.png');
250
+ setConvertClickedImageToFileType(file);
251
+ } catch (error) {
252
+ console.log('error', error);
253
+ }
254
+ }
255
+
256
+ takePictureButton.addEventListener("click", showCameraPicture);
257
+
258
+ setTimeout(() => {
259
+ setLoaderStatus(false);
260
+ }, 900);
261
+
262
+ return () => {
263
+ takePictureButton.removeEventListener('click', showCameraPicture);
264
+ }
265
+ }, [takePhoto, isCameraSwitch]);
266
+
267
+
268
+ const closeModalCameraAccessHandler = () => {
269
+ currentStream && closeStream(currentStream);
270
+ onClose();
271
+ }
272
+
273
+ const allowCameraModalHandler = () => {
274
+ currentStream && closeStream(currentStream);
275
+ onClose();
276
+ }
277
+
278
+ return (
279
+ <>
280
+ <TakeProfilePhotoWrapper isActive={isTakePhotoModal} className="App">
281
+ {
282
+ <ModalContainer isActive={!notAllowCameraPermission && !accessCamera}>
283
+ <ModalHeaderContainer>
284
+ <div className='header_wrapper'>
285
+ <ImageComponent
286
+ id="takePhotoModal"
287
+ onClick={closeModalCameraAccessHandler}
288
+ src={CLOSE_ICON}
289
+ className={`${props?.theme ? "darkicons" : "lighticons"} cross_icon`}
290
+ />
291
+ <ModalHeaderText>{'Take Photo'}</ModalHeaderText>
292
+ </div>
293
+ {
294
+ getClickedPictureUrl.length > 0 &&
295
+ <div onClick={() => {
296
+ setGetClickedPictureUrl('');
297
+ setTakePhoto(true);
298
+ setRotateCameraIcon(true);
299
+ }} className='header_wrapper pointer'>
300
+ <ImageComponent
301
+ src={CAMERA_RETAKE}
302
+ className={`${props?.theme ? "darkicons" : "lighticons"} cross_icon`}
303
+ />
304
+ <ModalHeaderText>{'Retake'}</ModalHeaderText>
305
+ </div>
306
+ }
307
+ {
308
+ rotateCameraIcon && isMobile &&
309
+ <CameraSwitchContainer theme={theme}>
310
+ <ImageComponent className="camera_switch" src={CAMERA_SWITCH} alt="camera_switch" />
311
+ <ModalHeaderText onClick={() => setIsCameraSwitch(!isCameraSwitch)}>{'Rotate camera'}</ModalHeaderText>
312
+ </CameraSwitchContainer>
313
+ }
314
+ </ModalHeaderContainer>
315
+ <>
316
+ {
317
+ getClickedPictureUrl?.length > 0 &&
318
+ <>
319
+ <ClickedImageWrapper onClick={sendClickedImage}>
320
+ <ImageComponent className={'user_clicked_pic'} src={getClickedPictureUrl} alt="user_picture" />
321
+ <CorrectIconWrapper>
322
+ <ImageComponent className={`darkicons`} src={SENDICON} alt={"correct_icon"} />
323
+ </CorrectIconWrapper>
324
+
325
+ </ClickedImageWrapper>
326
+
327
+ </>
328
+ }
329
+ <LoaderVideoContainer>
330
+ <VideoWrapper isActive={getClickedPictureUrl}>
331
+ <video className='video_play'></video>
332
+ <CameraIconContainer isActive={getClickedPictureUrl} id='take-picture'>
333
+ <ImageComponent className={'camera_icon'} src={'https://www.shutterstock.com/image-vector/photo-camera-lens-button3d-vector-600w-2087249068.jpg'} alt={'camera_icon'} />
334
+ </CameraIconContainer>
335
+ </VideoWrapper>
336
+ </LoaderVideoContainer>
337
+ </>
338
+ </ModalContainer>
339
+ }
340
+ {
341
+ cameraPermission && loaderStatus &&
342
+ <Loader theme={theme} top={'75px'} width={'100%'} height={'80%'} />
343
+ }
344
+ </TakeProfilePhotoWrapper>
345
+ <>
346
+ {
347
+ accessCamera &&
348
+ <CustomModal open={accessCamera} backDropClick={true} modelWidth={'60vw'} onClose={allowCameraModalHandler}>
349
+ <CameraPermissionRequestModal onClick={allowCameraModalHandler} />
350
+ </CustomModal>
351
+ }
352
+ {
353
+ notAllowCameraPermission &&
354
+ <CustomModal open={notAllowCameraPermission} backDropClick={true} modelWidth={'60vw'} onClose={allowCameraModalHandler}>
355
+ <CameraPermissionBlockedModal onClick={allowCameraModalHandler} />
356
+ </CustomModal>
357
+ }
358
+ </>
359
+ </>
360
+ );
361
+ }
362
+
363
+ export default TakePhoto;