diff --git a/src/app/config.js b/src/app/config.js index c2fdbd8f..7a900ba5 100644 --- a/src/app/config.js +++ b/src/app/config.js @@ -18,6 +18,10 @@ export const firebaseConfig = { appId: "1:418687074928:web:753286adbf239f5af9eab5", measurementId: "G-XV476KEC8P", }; +export const ChatPrefixs = { + channel: "#", + user: "@", +}; export const vapidKey = `BGXCn-5YRXSFw38Q9lUKJ5bibL212-yIQn1pCvthGhp6_KwA29FO1Ax_d_7if1vfC2a5wTSVO8AcZrc-Hm1aS0Y`; // "840319286941-6ds7lbvk55eq8mjortf68cb2ll65lprt.apps.googleusercontent.com"; export const tokenHeader = "X-API-Key"; diff --git a/src/common/component/Contact.js b/src/common/component/Contact.js index b2684ee4..8474e34f 100644 --- a/src/common/component/Contact.js +++ b/src/common/component/Contact.js @@ -63,6 +63,7 @@ const StyledWrapper = styled.div` } `; export default function Contact({ + cid = null, owner = false, dm = false, interactive = true, @@ -84,7 +85,7 @@ export default function Contact({ disabled={!popover} placement="left" trigger="click" - content={} + content={} > { - if (copied) { - toast.success("Emial Copied!"); - } - }, [copied]); useEffect(() => { if (removeMemberSuccess) { toast.success("Remove Member successfully"); diff --git a/src/common/component/Message/Mention.js b/src/common/component/Message/Mention.js index 6680f4d9..d622b79a 100644 --- a/src/common/component/Message/Mention.js +++ b/src/common/component/Message/Mention.js @@ -10,7 +10,7 @@ const Styled = styled.span` cursor: pointer; } `; -export default function Mention({ uid, popover = true }) { +export default function Mention({ uid, popover = true, cid }) { const contactsData = useSelector((store) => store.contacts.byId); const user = contactsData[uid]; if (!user) return null; @@ -20,7 +20,7 @@ export default function Mention({ uid, popover = true }) { interactive placement="top" trigger="click" - content={} + content={} > {`@${user.name}`} diff --git a/src/common/component/Message/index.js b/src/common/component/Message/index.js index b770dcdb..9d3116ec 100644 --- a/src/common/component/Message/index.js +++ b/src/common/component/Message/index.js @@ -99,7 +99,7 @@ function Message({ interactive placement="left" trigger="click" - content={} + content={} >
diff --git a/src/common/component/Message/renderContent.js b/src/common/component/Message/renderContent.js index cd9fb59d..da797ef9 100644 --- a/src/common/component/Message/renderContent.js +++ b/src/common/component/Message/renderContent.js @@ -51,7 +51,7 @@ const renderContent = ({ (match, idx) => { console.log("match", match); const uid = match.trim().slice(1); - return ; + return ; } )} {/* {content.replace(/\s{1}\@[1-9]+\s{1}/g,)} */} diff --git a/src/common/component/Message/useMessageOperation.js b/src/common/component/Message/useMessageOperation.js index 0a4af20b..b9ee9c7f 100644 --- a/src/common/component/Message/useMessageOperation.js +++ b/src/common/component/Message/useMessageOperation.js @@ -9,7 +9,7 @@ import useCopy from "../../hook/useCopy"; import usePinMessage from "../../hook/usePinMessage"; export default function useMessageOperation({ mid, context, contextId }) { - const [copied, copy] = useCopy(); + const { copy } = useCopy(); const { content_type, properties, currUid, from_uid, content } = useSelector( (store) => { return { @@ -64,11 +64,6 @@ export default function useMessageOperation({ mid, context, contextId }) { toast.success("Unpin Message Successfully!"); } }, [isUnpinSuccess]); - useEffect(() => { - if (copied) { - toast.success("Copied"); - } - }, [copied]); const enablePin = context == "channel" && canPin; // const enableReply = currUid != from_uid; const isImage = @@ -83,7 +78,9 @@ export default function useMessageOperation({ mid, context, contextId }) { [ContentTypes.text, ContentTypes.markdown].includes(content_type) || isImage; return { - copyContent: isImage ? copyContent.bind(null, true) : copyContent, + copyContent: isImage + ? copyContent.bind(null, true) + : copyContent.bind(null, false), canCopy, isImage, isMarkdown: content_type == ContentTypes.markdown, diff --git a/src/common/component/Profile.js b/src/common/component/Profile.js deleted file mode 100644 index 997f309d..00000000 --- a/src/common/component/Profile.js +++ /dev/null @@ -1,134 +0,0 @@ -// import React from "react"; -import { useSelector } from 'react-redux'; -import { NavLink } from 'react-router-dom'; -import styled from 'styled-components'; -import IconMessage from '../../assets/icons/message.svg'; -import IconCall from '../../assets/icons/call.svg'; -import IconMore from '../../assets/icons/more.svg'; -import Avatar from '../../common/component/Avatar'; -import toast from 'react-hot-toast'; - -const StyledWrapper = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin-top: 80px; - width: 432px; - gap: 4px; - .avatar { - width: 80px; - height: 80px; - border-radius: 50%; - } - .name { - user-select: text; - font-weight: bold; - font-size: 18px; - line-height: 100%; - color: #1c1c1e; - } - .email { - user-select: text; - font-weight: normal; - font-size: 14px; - line-height: 20px; - color: #98a2b3; - } - .intro { - color: #344054; - font-style: normal; - font-weight: 400; - font-size: 14px; - line-height: 20px; - } - .icons { - margin-top: 24px; - display: flex; - align-items: center; - gap: 8px; - .icon { - cursor: pointer; - font-weight: 500; - font-size: 14px; - line-height: 20px; - color: #22ccee; - display: flex; - align-items: center; - flex-direction: column; - gap: 4px; - background: #f9fafb; - border-radius: 8px; - width: 128px; - padding: 14px 0 12px 0; - &:hover { - background: #f2f4f7; - } - &.call, - &.more { - svg path { - fill: #22ccee; - } - } - } - } - .line { - width: 100%; - height: 1px; - border: none; - background-color: rgba(0, 0, 0, 0.1); - } - &.card { - padding: 16px; - width: 280px; - background: #ffffff; - box-shadow: 0px 20px 25px 20px rgba(31, 41, 55, 0.1), 0px 10px 10px rgba(31, 41, 55, 0.04); - border-radius: 6px; - .icons { - padding-bottom: 2px; - } - } -`; -export default function Profile({ uid = null, type = 'embed' }) { - const data = useSelector((store) => store.contacts.byId[uid]); - if (!data) return null; - // console.log("profile", data); - const { - name, - email, - avatar - // introduction = "This guy has nothing to introduce", - } = data; - const handleClick = () => { - toast.success('cooming soon...'); - }; - return ( - - -

{name}

- {email} - {/*

{introduction}

*/} -
    - -
  • - - Message -
  • -
    - {/* */} - {type !== 'card' && ( -
  • - - Call -
  • - )} - {/*
    */} -
  • - - More -
  • -
- {/* {type == "embed" &&
} */} -
- ); -} diff --git a/src/common/component/Profile/index.js b/src/common/component/Profile/index.js new file mode 100644 index 00000000..1e5ea694 --- /dev/null +++ b/src/common/component/Profile/index.js @@ -0,0 +1,116 @@ +import { useEffect } from "react"; +import { useSelector } from "react-redux"; +import { NavLink } from "react-router-dom"; +import toast from "react-hot-toast"; +import Tippy from "@tippyjs/react"; +import { hideAll } from "tippy.js"; +import IconMessage from "../../../assets/icons/message.svg"; +import IconCall from "../../../assets/icons/call.svg"; +import IconMore from "../../../assets/icons/more.svg"; +import Avatar from "../Avatar"; +import StyledWrapper from "./styled"; +import StyledMenu from "../styled/Menu"; +import useCopy from "../../hook/useCopy"; +import { useRemoveMembersMutation } from "../../../app/services/channel"; + +export default function Profile({ uid = null, type = "embed", cid = null }) { + const [ + removeFromChannel, + { isSuccess: removeSuccess }, + ] = useRemoveMembersMutation(); + const { copy } = useCopy(); + const { data, channel, loginUid, isAdmin } = useSelector((store) => { + return { + data: store.contacts.byId[uid], + channel: store.channels.byId[cid], + loginUid: store.authData.uid, + isAdmin: store.contacts.byId[store.authData.uid]?.is_admin, + }; + }); + useEffect(() => { + if (removeSuccess) { + toast.success("Remove Successfully"); + } + }, [removeSuccess]); + + if (!data) return null; + // console.log("profile", data); + const { + name, + email, + avatar, + // introduction = "This guy has nothing to introduce", + } = data; + const handleClick = () => { + toast.success("cooming soon..."); + }; + const handlCopyEmail = () => { + copy(email); + hideAll(); + }; + const handleRemove = (uid) => { + removeFromChannel({ id: +cid, members: [+uid] }); + hideAll(); + }; + const canCall = type !== "card" && loginUid != uid; + const canRemoveFromChannel = + cid && + !channel?.is_public && + (isAdmin || channel?.owner == loginUid) && + channel?.owner != uid; + const hasMore = canCall || email || canRemoveFromChannel; + return ( + + +

{name}

+ {email} + {/*

{introduction}

*/} +
    + +
  • + + Message +
  • +
    + {/* */} + {canCall && ( +
  • + + Call +
  • + )} + {/*
    */} + + {canCall &&
  • Call
  • } + {email && ( +
  • + Copy Email +
  • + )} + {canRemoveFromChannel && ( +
  • + Remove from Channel +
  • + )} + + } + > +
  • + + More +
  • +
    +
+
+ ); +} diff --git a/src/common/component/Profile/styled.js b/src/common/component/Profile/styled.js new file mode 100644 index 00000000..f3e69c2d --- /dev/null +++ b/src/common/component/Profile/styled.js @@ -0,0 +1,96 @@ +import styled from "styled-components"; + +const StyledWrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-top: 80px; + width: 432px; + gap: 4px; + .avatar { + width: 80px; + height: 80px; + border-radius: 50%; + } + .name { + user-select: text; + font-weight: bold; + font-size: 18px; + line-height: 100%; + color: #1c1c1e; + } + .email { + user-select: text; + font-weight: normal; + font-size: 14px; + line-height: 20px; + color: #98a2b3; + } + .intro { + color: #344054; + font-style: normal; + font-weight: 400; + font-size: 14px; + line-height: 20px; + } + .icons { + margin-top: 24px; + display: flex; + align-items: center; + gap: 8px; + .icon { + cursor: pointer; + font-weight: 500; + font-size: 14px; + line-height: 20px; + color: #22ccee; + display: flex; + align-items: center; + flex-direction: column; + gap: 4px; + background: #f9fafb; + border-radius: 8px; + width: 128px; + padding: 14px 0 12px 0; + + &:not(.disabled):hover { + background: #f2f4f7; + } + &.call, + &.more { + svg path { + fill: #22ccee; + } + } + &.disabled { + color: #ccc; + svg path { + fill: #ccc; + } + } + .txt { + user-select: none; + } + } + } + .line { + width: 100%; + height: 1px; + border: none; + background-color: rgba(0, 0, 0, 0.1); + } + &.card { + padding: 16px; + width: 280px; + background: #ffffff; + box-shadow: 0px 20px 25px 20px rgba(31, 41, 55, 0.1), + 0px 10px 10px rgba(31, 41, 55, 0.04); + border-radius: 6px; + .icons { + padding-bottom: 2px; + } + } +`; + +export default StyledWrapper; diff --git a/src/common/component/Send/index.js b/src/common/component/Send/index.js index 9195c224..1fa18850 100644 --- a/src/common/component/Send/index.js +++ b/src/common/component/Send/index.js @@ -3,7 +3,7 @@ import { useDispatch, useSelector } from "react-redux"; import useSendMessage from "../../hook/useSendMessage"; import useAddLocalFileMessage from "../../hook/useAddLocalFileMessage"; import { updateInputMode } from "../../../app/slices/ui"; -import { ContentTypes } from "../../../app/config"; +import { ContentTypes, ChatPrefixs } from "../../../app/config"; import StyledSend from "./styled"; import UploadFileList from "./UploadFileList"; @@ -15,10 +15,7 @@ import MarkdownEditor from "../MarkdownEditor"; import MixedInput, { useMixedEditor } from "../MixedInput"; import useDraft from "../../hook/useDraft"; import useUploadFile from "../../hook/useUploadFile"; -const Types = { - channel: "#", - user: "@", -}; + const Modes = { text: "text", markdown: "markdown", @@ -132,7 +129,7 @@ function Send({ }; const name = context == "channel" ? channelsData[id]?.name : contactsData[id]?.name; - const placeholder = `Send to ${Types[context]}${name} `; + const placeholder = `Send to ${ChatPrefixs[context]}${name} `; const members = context == "channel" ? channelsData[id]?.is_public diff --git a/src/common/hook/useInviteLink.js b/src/common/hook/useInviteLink.js index 0d221224..ccadf2f0 100644 --- a/src/common/hook/useInviteLink.js +++ b/src/common/hook/useInviteLink.js @@ -19,7 +19,7 @@ export default function useInviteLink(cid = null) { generateServerInviteLink, { data: serverInviteLink, isLoading: generatingServerLink }, ] = useCreateServerInviteLinkQuery(); - const [linkCopied, copy] = useCopy(); + const { copied, copy } = useCopy({ enableToast: false }); const copyLink = () => { copy(finalLink); }; @@ -50,7 +50,7 @@ export default function useInviteLink(cid = null) { ? generateChannelInviteLink.bind(null, cid) : genServerLink, link: finalLink, - linkCopied, + linkCopied: copied, copyLink, }; }