Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import React, { useEffect, useMemo } from "react";
  2. import PropTypes from "prop-types";
  3. import { DirectChatContainer } from "./DirectChat.styled";
  4. import DirectChatHeaderTitle from "./DirectChatHeaderTitle/DirectChatHeaderTitle";
  5. import DirectChatHeader from "./DirectChatHeader/DirectChatHeader";
  6. import { useDispatch, useSelector } from "react-redux";
  7. import { useLocation, useRouteMatch } from "react-router-dom";
  8. import {
  9. addNewMessage,
  10. fetchChats,
  11. fetchOneChat,
  12. setOneChat,
  13. } from "../../store/actions/chat/chatActions";
  14. import {
  15. selectLatestChats,
  16. selectSelectedChat,
  17. } from "../../store/selectors/chatSelectors";
  18. import DirectChatContent from "./DirectChatContent/DirectChatContent";
  19. import { selectOffer } from "../../store/selectors/offersSelectors";
  20. import { fetchOneOffer } from "../../store/actions/offers/offersActions";
  21. import SkeletonDirectChat from "./SkeletonDirectChat/SkeletonDirectChat";
  22. import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
  23. import { CHAT_SCOPE } from "../../store/actions/chat/chatActionConstants";
  24. import { selectUserId } from "../../store/selectors/loginSelectors";
  25. import {
  26. acceptExchangeSocket,
  27. addMessageListener,
  28. removeMessageListener,
  29. } from "../../socket/socket";
  30. import { makeErrorToastMessage } from "../../store/utils/makeToastMessage";
  31. import { useTranslation } from "react-i18next";
  32. import {
  33. selectExchange,
  34. selectRequester,
  35. } from "../../store/selectors/exchangeSelector";
  36. import {
  37. acceptExchange,
  38. fetchExchange,
  39. setRequester,
  40. } from "../../store/actions/exchange/exchangeActions";
  41. import { convertLocalDateToUTCDate } from "../../util/helpers/dateHelpers";
  42. import requesterStatus from "../../constants/requesterStatus";
  43. import exchangeStatus from "../../constants/exchangeStatus";
  44. import { NEW_CHAT } from "../../constants/chatConstants";
  45. const DirectChat = () => {
  46. const chat = useSelector(selectSelectedChat);
  47. const allChats = useSelector(selectLatestChats);
  48. const offer = useSelector(selectOffer);
  49. const routeMatch = useRouteMatch();
  50. const location = useLocation();
  51. const dispatch = useDispatch();
  52. const { t } = useTranslation();
  53. const exchange = useSelector(selectExchange);
  54. const requester = useSelector(selectRequester);
  55. const userId = useSelector(selectUserId);
  56. const isLoadingDirectChat = useSelector(
  57. selectIsLoadingByActionType(CHAT_SCOPE)
  58. );
  59. const offerObject = useMemo(() => {
  60. if (location?.state?.offerId) {
  61. return offer;
  62. }
  63. return chat?.offer;
  64. }, [chat, location.state, offer]);
  65. const chatObject = useMemo(() => {
  66. if (location?.state?.offerId) {
  67. return {};
  68. }
  69. return chat;
  70. }, [chat, location.state]);
  71. const amIBuyer = useMemo(
  72. () => exchange.buyer?.user?._id === userId,
  73. [exchange, userId]
  74. );
  75. const exchangeState = useMemo(() => {
  76. if (exchange?.buyer) {
  77. let haveIAccepted = amIBuyer
  78. ? exchange.buyer?.accepted
  79. : exchange.seller?.accepted;
  80. let haveinterlocutorAccepted = amIBuyer
  81. ? exchange.seller?.accepted
  82. : exchange.buyer?.accepted;
  83. let haveIReviewed = amIBuyer
  84. ? exchange.buyer.givenReview
  85. : exchange.seller.givenReview;
  86. if (haveIAccepted) {
  87. if (haveinterlocutorAccepted) {
  88. if (haveIReviewed) {
  89. return exchangeStatus.REVIEWED;
  90. } else {
  91. return exchangeStatus.ACCEPTED;
  92. }
  93. } else {
  94. return exchangeStatus.I_OFFERED;
  95. }
  96. } else {
  97. if (haveinterlocutorAccepted) {
  98. return exchangeStatus.I_AM_OFFERED;
  99. } else {
  100. return exchangeStatus.INITIAL;
  101. }
  102. }
  103. }
  104. return exchangeStatus.INITIAL;
  105. }, [exchange, amIBuyer]);
  106. const interlocutorObject = useMemo(() => {
  107. if (location?.state?.offerId) {
  108. return offer?.user;
  109. }
  110. if (chat?.participants) {
  111. let interlocutor = userId === chat?.participants[0]._id ? 1 : 0;
  112. return chat?.participants[interlocutor];
  113. }
  114. return {};
  115. }, [chat, location.state, offer]);
  116. // Fetch chat after it is created
  117. // (renders after state of location changes)
  118. useEffect(() => {
  119. if (routeMatch.params?.chatId) {
  120. refreshChat();
  121. }
  122. }, [routeMatch.params?.chatId, location.state?.offerId]);
  123. // Listener to socket.IO chat
  124. useEffect(() => {
  125. addMessageListener(({ succeed, data }) => {
  126. if (succeed) {
  127. if (
  128. [...allChats].find((item) => {
  129. return item._id === data.chatId;
  130. })
  131. ) {
  132. dispatch(
  133. addNewMessage({
  134. _id: data.chatId,
  135. message: data.message,
  136. })
  137. );
  138. if (data.message?.isAcceptRequest) {
  139. dispatch(fetchExchange(exchange?._id));
  140. if (requester === requesterStatus.NOONE) {
  141. dispatch(setRequester(requesterStatus.interlocutor));
  142. }
  143. }
  144. } else {
  145. dispatch(fetchChats());
  146. }
  147. } else {
  148. dispatch(fetchChats());
  149. dispatch(fetchOneChat(routeMatch.params?.chatId));
  150. makeErrorToastMessage(t("apiErrors.somethingWentWrong"));
  151. }
  152. });
  153. return () => removeMessageListener();
  154. }, [allChats, routeMatch, requester]);
  155. const refreshChat = () => {
  156. if (routeMatch.params?.chatId === NEW_CHAT) {
  157. dispatch(fetchOneOffer(location.state.offerId));
  158. dispatch(setOneChat({}));
  159. } else {
  160. dispatch(fetchOneChat(routeMatch.params?.chatId));
  161. }
  162. };
  163. const handleAcceptExchangeSuccess = () => {
  164. let interlocutor = userId === chat?.participants[0]._id ? 1 : 0;
  165. acceptExchangeSocket(
  166. chat?._id,
  167. userId,
  168. chat?.participants[interlocutor]._id,
  169. () => {
  170. dispatch(
  171. addNewMessage({
  172. _id: chat?._id,
  173. message: {
  174. user: {
  175. _id: userId,
  176. },
  177. isAcceptRequest: true,
  178. text: "",
  179. _created: convertLocalDateToUTCDate(new Date()),
  180. },
  181. })
  182. );
  183. if (requester === requesterStatus.NOONE) {
  184. dispatch(setRequester(requesterStatus.ME));
  185. }
  186. }
  187. );
  188. };
  189. const handleAcceptExchange = () => {
  190. console.log("accept salje i prima 1 POZVANA FUNKCIJA")
  191. dispatch(
  192. acceptExchange({
  193. exchangeId: exchange._id,
  194. handleApiResponseSuccess: handleAcceptExchangeSuccess,
  195. })
  196. );
  197. };
  198. return (
  199. <DirectChatContainer>
  200. {isLoadingDirectChat || isLoadingDirectChat === undefined ? (
  201. <SkeletonDirectChat />
  202. ) : (
  203. <>
  204. <DirectChatHeaderTitle />
  205. <DirectChatHeader
  206. exchangeState={exchangeState}
  207. offer={offerObject}
  208. interlocutor={interlocutorObject}
  209. acceptExchange={handleAcceptExchange}
  210. />
  211. </>
  212. )}
  213. <DirectChatContent
  214. chat={chatObject}
  215. exchangeState={exchangeState}
  216. interlocutor={interlocutorObject}
  217. refreshChat={refreshChat}
  218. />
  219. </DirectChatContainer>
  220. );
  221. };
  222. DirectChat.propTypes = {
  223. children: PropTypes.node,
  224. };
  225. export default DirectChat;