index.tsx 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import { CbEvents, MessageType } from "@openim/wasm-client-sdk";
  2. import {
  3. GroupItem,
  4. MessageItem,
  5. RtcInvite,
  6. WSEvent,
  7. } from "@openim/wasm-client-sdk/lib/types/entity";
  8. import { Popover } from "antd";
  9. import i18n, { t } from "i18next";
  10. import { useCallback, useEffect, useRef, useState } from "react";
  11. import { getBusinessUserInfo } from "@/api/login";
  12. import add_friend from "@/assets/images/topSearchBar/add_friend.png";
  13. import add_group from "@/assets/images/topSearchBar/add_group.png";
  14. import create_group from "@/assets/images/topSearchBar/create_group.png";
  15. import search from "@/assets/images/topSearchBar/search.png";
  16. import show_more from "@/assets/images/topSearchBar/show_more.png";
  17. import WindowControlBar from "@/components/WindowControlBar";
  18. import { CustomType } from "@/constants";
  19. import { OverlayVisibleHandle } from "@/hooks/useOverlayVisible";
  20. import ChooseModal, { ChooseModalState } from "@/pages/common/ChooseModal";
  21. import GroupCardModal from "@/pages/common/GroupCardModal";
  22. import RtcCallModal from "@/pages/common/RtcCallModal";
  23. import { InviteData } from "@/pages/common/RtcCallModal/data";
  24. import UserCardModal, { CardInfo } from "@/pages/common/UserCardModal";
  25. import emitter, { OpenUserCardParams } from "@/utils/events";
  26. import { IMSDK } from "../MainContentWrap";
  27. import SearchUserOrGroup from "./SearchUserOrGroup";
  28. type UserCardState = OpenUserCardParams & {
  29. cardInfo?: CardInfo;
  30. };
  31. const TopSearchBar = () => {
  32. const userCardRef = useRef<OverlayVisibleHandle>(null);
  33. const groupCardRef = useRef<OverlayVisibleHandle>(null);
  34. const chooseModalRef = useRef<OverlayVisibleHandle>(null);
  35. const searchModalRef = useRef<OverlayVisibleHandle>(null);
  36. const rtcRef = useRef<OverlayVisibleHandle>(null);
  37. const [chooseModalState, setChooseModalState] = useState<ChooseModalState>({
  38. type: "CRATE_GROUP",
  39. });
  40. const [userCardState, setUserCardState] = useState<UserCardState>();
  41. const [groupCardData, setGroupCardData] = useState<GroupItem>();
  42. const [actionVisible, setActionVisible] = useState(false);
  43. const [isSearchGroup, setIsSearchGroup] = useState(false);
  44. const [inviteData, setInviteData] = useState<InviteData>({} as InviteData);
  45. useEffect(() => {
  46. const userCardHandler = (params: OpenUserCardParams) => {
  47. setUserCardState({ ...params });
  48. userCardRef.current?.openOverlay();
  49. };
  50. const chooseModalHandler = (params: ChooseModalState) => {
  51. setChooseModalState({ ...params });
  52. chooseModalRef.current?.openOverlay();
  53. };
  54. const callRtcHandler = (inviteData: InviteData) => {
  55. if (window.electronAPI?.ipcSend) {
  56. window.electronAPI?.ipcSend("calling-window", { data: "test" });
  57. return;
  58. }
  59. if (rtcRef.current?.isOverlayOpen) return;
  60. setInviteData(inviteData);
  61. rtcRef.current?.openOverlay();
  62. };
  63. const newMessageHandler = ({ data }: WSEvent<MessageItem[]>) => {
  64. if (rtcRef.current?.isOverlayOpen) return;
  65. let rtcInvite = undefined as undefined | RtcInvite;
  66. data.map((message) => {
  67. if (message.contentType === MessageType.CustomMessage) {
  68. const customData = JSON.parse(message.customElem!.data);
  69. if (customData.customType === CustomType.CallingInvite) {
  70. rtcInvite = customData.data;
  71. }
  72. }
  73. });
  74. if (rtcInvite) {
  75. getBusinessUserInfo([rtcInvite.inviterUserID]).then(({ data: { users } }) => {
  76. if (users.length === 0) return;
  77. setInviteData({
  78. invitation: rtcInvite,
  79. participant: {
  80. userInfo: {
  81. nickname: users[0].nickname,
  82. faceURL: users[0].faceURL,
  83. userID: users[0].userID,
  84. ex: "",
  85. },
  86. },
  87. });
  88. rtcRef.current?.openOverlay();
  89. });
  90. }
  91. };
  92. emitter.on("OPEN_USER_CARD", userCardHandler);
  93. emitter.on("OPEN_GROUP_CARD", openGroupCardWithData);
  94. emitter.on("OPEN_CHOOSE_MODAL", chooseModalHandler);
  95. emitter.on("OPEN_RTC_MODAL", callRtcHandler);
  96. IMSDK.on(CbEvents.OnRecvNewMessages, newMessageHandler);
  97. return () => {
  98. emitter.off("OPEN_USER_CARD", userCardHandler);
  99. emitter.off("OPEN_GROUP_CARD", openGroupCardWithData);
  100. emitter.off("OPEN_CHOOSE_MODAL", chooseModalHandler);
  101. emitter.off("OPEN_RTC_MODAL", callRtcHandler);
  102. IMSDK.off(CbEvents.OnRecvNewMessages, newMessageHandler);
  103. };
  104. }, []);
  105. const actionClick = (idx: number) => {
  106. switch (idx) {
  107. case 0:
  108. case 1:
  109. setIsSearchGroup(Boolean(idx));
  110. searchModalRef.current?.openOverlay();
  111. break;
  112. case 2:
  113. setChooseModalState({ type: "CRATE_GROUP" });
  114. chooseModalRef.current?.openOverlay();
  115. break;
  116. case 3:
  117. break;
  118. default:
  119. break;
  120. }
  121. setActionVisible(false);
  122. };
  123. const openUserCardWithData = useCallback((cardInfo: CardInfo) => {
  124. searchModalRef.current?.closeOverlay();
  125. setUserCardState({ userID: cardInfo.userID, cardInfo });
  126. userCardRef.current?.openOverlay();
  127. }, []);
  128. const openGroupCardWithData = useCallback((group: GroupItem) => {
  129. searchModalRef.current?.closeOverlay();
  130. setGroupCardData(group);
  131. groupCardRef.current?.openOverlay();
  132. }, []);
  133. return (
  134. <div className="no-mobile app-drag flex h-10 min-h-[40px] items-center bg-[var(--top-search-bar)] dark:bg-[#141414]">
  135. <div className="flex w-full items-center justify-center">
  136. <div className="app-no-drag flex h-[26px] w-1/3 cursor-pointer items-center justify-center rounded-md bg-[rgba(255,255,255,0.2)]">
  137. <img width={16} src={search} alt="" />
  138. <span className="ml-2 text-[#D2E3F8]">{t("placeholder.search")}</span>
  139. </div>
  140. <Popover
  141. content={<ActionPopContent actionClick={actionClick} />}
  142. arrow={false}
  143. title={null}
  144. trigger="click"
  145. placement="bottom"
  146. open={actionVisible}
  147. onOpenChange={(vis) => setActionVisible(vis)}
  148. >
  149. <img
  150. className="app-no-drag ml-8 cursor-pointer"
  151. width={20}
  152. src={show_more}
  153. alt=""
  154. />
  155. </Popover>
  156. </div>
  157. <WindowControlBar />
  158. <UserCardModal ref={userCardRef} {...userCardState} />
  159. <GroupCardModal ref={groupCardRef} groupData={groupCardData} />
  160. <ChooseModal ref={chooseModalRef} state={chooseModalState} />
  161. <SearchUserOrGroup
  162. ref={searchModalRef}
  163. isSearchGroup={isSearchGroup}
  164. openUserCardWithData={openUserCardWithData}
  165. openGroupCardWithData={openGroupCardWithData}
  166. />
  167. <RtcCallModal inviteData={inviteData} ref={rtcRef} />
  168. </div>
  169. );
  170. };
  171. export default TopSearchBar;
  172. const actionMenuList = [
  173. {
  174. idx: 0,
  175. title: t("placeholder.addFriends"),
  176. icon: add_friend,
  177. },
  178. {
  179. idx: 1,
  180. title: t("placeholder.addGroup"),
  181. icon: add_group,
  182. },
  183. {
  184. idx: 2,
  185. title: t("placeholder.createGroup"),
  186. icon: create_group,
  187. },
  188. ];
  189. i18n.on("languageChanged", () => {
  190. actionMenuList[0].title = t("placeholder.addFriends");
  191. actionMenuList[1].title = t("placeholder.addGroup");
  192. actionMenuList[2].title = t("placeholder.createGroup");
  193. });
  194. const ActionPopContent = ({ actionClick }: { actionClick: (idx: number) => void }) => {
  195. return (
  196. <div className="p-1">
  197. {actionMenuList.map((action) => (
  198. <div
  199. className="flex cursor-pointer items-center rounded px-3 py-2 text-xs hover:bg-[var(--primary-active)]"
  200. key={action.idx}
  201. onClick={() => actionClick?.(action.idx)}
  202. >
  203. <img width={20} src={action.icon} alt="call_video" />
  204. <div className="ml-3">{action.title}</div>
  205. </div>
  206. ))}
  207. </div>
  208. );
  209. };