diff --git a/src/common/component/ChannelInviteModal.js b/src/common/component/ChannelInviteModal.js deleted file mode 100644 index c7d1cd1d..00000000 --- a/src/common/component/ChannelInviteModal.js +++ /dev/null @@ -1,141 +0,0 @@ -// import React from 'react' -import styled from "styled-components"; -import useInviteLink from "../hook/useInviteLink"; -import CloseIcon from "../../assets/icons/close.svg"; -const Styled = styled.div` - display: flex; - flex-direction: column; - background: #fff; - box-shadow: 0px 25px 50px rgba(31, 41, 55, 0.25); - border-radius: var(--br); - padding: 0; - min-width: 408px; - > .title { - display: flex; - align-items: center; - justify-content: space-between; - font-style: normal; - font-weight: 600; - font-size: 18px; - line-height: 28px; - color: #374151; - padding: 16px; - .close { - cursor: pointer; - } - } - - .body { - padding: 16px; - box-shadow: 0px -1px 2px rgba(0, 0, 0, 0.06); - .input { - position: relative; - button { - position: absolute; - right: 4px; - top: 50%; - transform: translateY(-50%); - } - input { - padding-right: 80px; - } - } - > .invite { - display: flex; - flex-direction: column; - gap: 16px; - margin-bottom: 16px; - /* position: relative; */ - } - > .link { - display: flex; - flex-direction: column; - gap: 8px; - margin-bottom: 12px; - /* position: relative; */ - } - label { - color: #6b7280; - font-style: normal; - font-weight: 500; - font-size: 14px; - line-height: 20px; - } - > .tip { - color: #344054; - font-weight: 400; - font-size: 12px; - line-height: 18px; - button { - background: none; - border: none; - color: #22ccee; - } - } - } -`; -import Modal from "./Modal"; -import Button from "./styled/Button"; -import Input from "./styled/Input"; -export default function ChannelInviteModal({ cid = null, title, closeModal }) { - const { - enableSMTP, - linkCopied, - link, - copyLink, - generateNewLink, - generating, - } = useInviteLink(cid); - if (!cid) return null; - return ( - - - - Invite friends to #{title}{" "} - - - - - Invite by Email - - - - Invite - - - - - Or Send invite link to your friends - - - - {linkCopied ? `Copied` : `Copy`} - - - - - Invite link expires in 7 days.{" "} - - Generate New Link - - - - - - ); -} diff --git a/src/common/component/ChannelInviteModal/AddMembers.js b/src/common/component/ChannelInviteModal/AddMembers.js new file mode 100644 index 00000000..402a788d --- /dev/null +++ b/src/common/component/ChannelInviteModal/AddMembers.js @@ -0,0 +1,197 @@ +import { useState, useEffect } from "react"; +import styled from "styled-components"; +import { useSelector } from "react-redux"; +import Button from "../styled/Button"; +import Input from "../styled/Input"; +import Contact from "../Contact"; +import StyledCheckbox from "../styled/Checkbox"; +import { useAddMembersMutation } from "../../../app/services/channel"; +import CloseIcon from "../../../assets/icons/close.svg"; +import toast from "react-hot-toast"; +import useFilteredUsers from "../../../common/hook/useFilteredUsers"; + +const Styled = styled.div` + padding-top: 16px; + > .filter { + width: 376px; + min-height: 40px; + padding: 6px 8px; + display: flex; + align-items: center; + margin-bottom: 12px; + background: #ffffff; + border: 1px solid #e5e7eb; + box-shadow: 0px 1px 2px rgba(31, 41, 55, 0.08); + border-radius: 4px; + .selects { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 5px; + width: 100%; + overflow: scroll; + + /* white-space: nowrap; */ + &::-webkit-scrollbar { + width: 0; /* Remove scrollbar space */ + height: 0; /* Remove scrollbar space */ + background: transparent; /* Optional: just make scrollbar invisible */ + } + .select { + padding: 4px 6px; + background: #52edff; + border-radius: 4px; + font-weight: 600; + font-size: 14px; + line-height: 20px; + color: #ffffff; + display: flex; + justify-content: space-between; + align-items: center; + gap: 5px; + .close { + cursor: pointer; + width: 12px; + height: 12px; + path { + fill: #fff; + fill-opacity: 1; + } + /* filter: invert(1); */ + } + } + .input { + width: fit-content; + } + } + } + .users { + display: flex; + flex-direction: column; + /* height: 260px; */ + padding-bottom: 20px; + max-height: 364px; + overflow: scroll; + .user { + cursor: pointer; + display: flex; + align-items: center; + padding: 4px 8px; + /* margin: 0 4px; */ + width: -webkit-fill-available; + border-radius: 8px; + &:hover { + background: rgba(116, 127, 141, 0.1); + } + > div { + width: 100%; + } + } + } + > .btn { + width: 100%; + margin-top: 16px; + font-weight: 500; + font-size: 14px; + line-height: 20px; + } +`; +export default function AddMembers({ cid = null, closeModal }) { + const [ + addMembers, + { isLoading: isAdding, isSuccess }, + ] = useAddMembersMutation(); + const [selects, setSelects] = useState([]); + const { channel, contactData } = useSelector((store) => { + return { + channel: store.channels.byId[cid], + contactData: store.contacts.byId, + }; + }); + useEffect(() => { + if (isSuccess) { + toast.success("Add members successfully!"); + closeModal(); + } + }, [isSuccess]); + + const handleAddMembers = () => { + addMembers({ id: cid, members: selects }); + }; + const { input, updateInput, contacts = [] } = useFilteredUsers(); + const toggleCheckMember = ({ currentTarget }) => { + const { uid } = currentTarget.dataset; + if (selects.includes(+uid)) { + setSelects((prevs) => { + return prevs.filter((id) => id != uid); + }); + } else { + setSelects([...selects, +uid]); + } + }; + const handleFilterInput = (evt) => { + updateInput(evt.target.value); + }; + if (!channel) return null; + const { members: uids } = channel; + const contactIds = contacts.map(({ uid }) => uid); + console.log("selects", selects); + return ( + + + {/* {selects && selects.length > 0 && ( */} + + {selects.map((uid) => { + return ( + + {contactData[uid].name} + + + ); + })} + + + {/* )} */} + + + {contactIds.map((uid) => { + const added = uids.includes(uid); + return ( + + + + + ); + })} + + + {isAdding ? `Adding` : "Add"} to #{channel.name} + + + ); +} diff --git a/src/common/component/ChannelInviteModal/InviteByEmail.js b/src/common/component/ChannelInviteModal/InviteByEmail.js new file mode 100644 index 00000000..44d3924f --- /dev/null +++ b/src/common/component/ChannelInviteModal/InviteByEmail.js @@ -0,0 +1,112 @@ +// import React from 'react' +import styled from "styled-components"; +import useInviteLink from "../../hook/useInviteLink"; +const Styled = styled.div` + padding: 16px 0; + .input { + position: relative; + button { + position: absolute; + right: 4px; + top: 50%; + transform: translateY(-50%); + &.copy { + padding-right: 8px; + background: none; + font-weight: 500; + font-size: 14px; + line-height: 20px; + color: #22ccee; + } + } + input { + padding-right: 80px; + &.invite { + padding-right: 50px; + } + } + } + > .invite { + display: flex; + flex-direction: column; + gap: 16px; + margin-bottom: 16px; + /* position: relative; */ + } + > .link { + display: flex; + flex-direction: column; + gap: 8px; + margin-bottom: 12px; + /* position: relative; */ + } + label { + color: #6b7280; + font-style: normal; + font-weight: 500; + font-size: 14px; + line-height: 20px; + } + > .tip { + color: #344054; + font-weight: 400; + font-size: 12px; + line-height: 18px; + button { + background: none; + border: none; + color: #22ccee; + } + } +`; +import Button from "../styled/Button"; +import Input from "../styled/Input"; +export default function InviteByEmail({ cid = null }) { + const { + enableSMTP, + linkCopied, + link, + copyLink, + generateNewLink, + generating, + } = useInviteLink(cid); + return ( + + + Invite by Email + + + + Invite + + + + + Or Send invite link to your friends + + + + {linkCopied ? `Copied` : `Copy`} + + + + + Invite link expires in 7 days.{" "} + + Generate New Link + + + + ); +} diff --git a/src/common/component/ChannelInviteModal/index.js b/src/common/component/ChannelInviteModal/index.js new file mode 100644 index 00000000..8605e24f --- /dev/null +++ b/src/common/component/ChannelInviteModal/index.js @@ -0,0 +1,53 @@ +// import React from 'react' +import styled from "styled-components"; +import { useSelector } from "react-redux"; +import InviteByEmail from "./InviteByEmail"; +import AddMembers from "./AddMembers"; +import CloseIcon from "../../../assets/icons/close.svg"; +const Styled = styled.div` + display: flex; + flex-direction: column; + background: #fff; + box-shadow: 0px 25px 50px rgba(31, 41, 55, 0.25); + border-radius: var(--br); + padding: 16px; + min-width: 408px; + > .title { + display: flex; + align-items: center; + justify-content: space-between; + font-style: normal; + font-weight: 600; + font-size: 18px; + line-height: 28px; + color: #374151; + .close { + cursor: pointer; + } + } +`; +import Modal from "../Modal"; +export default function ChannelInviteModal({ + cid = null, + title = "", + closeModal, +}) { + const { channel } = useSelector((store) => { + return { + channel: store.channels.byId[cid], + }; + }); + if (!cid) return null; + return ( + + + + Add friends to #{title || channel?.name}{" "} + + + {!channel?.is_public && } + + + + ); +} diff --git a/src/routes/chat/ChannelChat/AddMemberModal.js b/src/routes/chat/ChannelChat/AddMemberModal.js deleted file mode 100644 index 71fb1350..00000000 --- a/src/routes/chat/ChannelChat/AddMemberModal.js +++ /dev/null @@ -1,118 +0,0 @@ -import { useState, useEffect } from "react"; -import { useSelector } from "react-redux"; -import Modal from "../../../common/component/Modal"; -import Button from "../../../common/component/styled/Button"; -import Input from "../../../common/component/styled/Input"; -import Contact from "../../../common/component/Contact"; -import StyledCheckbox from "../../../common/component/styled/Checkbox"; -import { useAddMembersMutation } from "../../../app/services/channel"; -import CloseIcon from "../../../assets/icons/close.svg"; -import toast from "react-hot-toast"; -import useFilteredUsers from "../../../common/hook/useFilteredUsers"; -import Styled from "./add.member.styled"; - -export default function AddMemberModal({ uids = [], cid = null, closeModal }) { - const [ - addMembers, - { isLoading: isAdding, isSuccess }, - ] = useAddMembersMutation(); - const [selects, setSelects] = useState([]); - const { channel, contactData } = useSelector((store) => { - return { - channel: store.channels.byId[cid], - // contactIds: store.contacts.ids, - contactData: store.contacts.byId, - }; - }); - useEffect(() => { - if (isSuccess) { - toast.success("Add members successfully!"); - closeModal(); - } - }, [isSuccess]); - - const handleAddMembers = () => { - addMembers({ id: cid, members: selects }); - }; - const { input, updateInput, contacts = [] } = useFilteredUsers(); - const toggleCheckMember = ({ currentTarget }) => { - const { uid } = currentTarget.dataset; - if (selects.includes(+uid)) { - setSelects((prevs) => { - return prevs.filter((id) => id != uid); - }); - } else { - setSelects([...selects, +uid]); - } - }; - const handleFilterInput = (evt) => { - updateInput(evt.target.value); - }; - if (!channel) return null; - const contactIds = contacts.map(({ uid }) => uid); - console.log("selects", selects); - return ( - - - - Add friends to #{channel.name}{" "} - - - - {/* {selects && selects.length > 0 && ( */} - - {selects.map((uid) => { - return ( - - {contactData[uid].name} - - - ); - })} - - - {/* )} */} - - - {contactIds.map((uid) => { - const added = uids.includes(uid); - return ( - - - - - ); - })} - - - {isAdding ? `Adding` : "Add"} to #{channel.name} - - - - ); -} diff --git a/src/routes/chat/ChannelChat/add.member.styled.js b/src/routes/chat/ChannelChat/add.member.styled.js deleted file mode 100644 index 215cabdb..00000000 --- a/src/routes/chat/ChannelChat/add.member.styled.js +++ /dev/null @@ -1,109 +0,0 @@ -import styled from "styled-components"; - -const Styled = styled.div` - padding: 16px; - filter: drop-shadow(0px 25px 50px rgba(31, 41, 55, 0.25)); - border-radius: 8px; - background-color: #fff; - min-width: 410px; - > .head { - font-weight: 600; - font-size: 18px; - line-height: 28px; - color: #374151; - margin-bottom: 16px; - display: flex; - justify-content: space-between; - align-items: center; - .close { - width: 12px; - height: 12px; - cursor: pointer; - } - } - > .filter { - width: 376px; - min-height: 40px; - padding: 6px 8px; - display: flex; - align-items: center; - margin-bottom: 12px; - background: #ffffff; - border: 1px solid #e5e7eb; - box-shadow: 0px 1px 2px rgba(31, 41, 55, 0.08); - border-radius: 4px; - .selects { - display: flex; - align-items: center; - flex-wrap: wrap; - gap: 5px; - width: 100%; - overflow: scroll; - - /* white-space: nowrap; */ - &::-webkit-scrollbar { - width: 0; /* Remove scrollbar space */ - height: 0; /* Remove scrollbar space */ - background: transparent; /* Optional: just make scrollbar invisible */ - } - .select { - padding: 4px 6px; - background: #52edff; - border-radius: 4px; - font-weight: 600; - font-size: 14px; - line-height: 20px; - color: #ffffff; - display: flex; - justify-content: space-between; - align-items: center; - gap: 5px; - .close { - cursor: pointer; - width: 12px; - height: 12px; - path { - fill: #fff; - fill-opacity: 1; - } - /* filter: invert(1); */ - } - } - .input { - width: fit-content; - } - } - } - .users { - display: flex; - flex-direction: column; - /* height: 260px; */ - padding-bottom: 20px; - max-height: 364px; - overflow: scroll; - .user { - cursor: pointer; - display: flex; - align-items: center; - padding: 4px 8px; - /* margin: 0 4px; */ - width: -webkit-fill-available; - border-radius: 8px; - &:hover { - background: rgba(116, 127, 141, 0.1); - } - > div { - width: 100%; - } - } - } - > .btn { - width: 100%; - margin-top: 16px; - font-weight: 500; - font-size: 14px; - line-height: 20px; - } -`; - -export default Styled; diff --git a/src/routes/chat/ChannelChat/index.js b/src/routes/chat/ChannelChat/index.js index bc8b66f5..63c9b283 100644 --- a/src/routes/chat/ChannelChat/index.js +++ b/src/routes/chat/ChannelChat/index.js @@ -24,7 +24,7 @@ import { StyledChannelChat, StyledHeader, } from "./styled"; -import AddMemberModal from "./AddMemberModal"; +import ChannelInviteModal from "../../../common/component/ChannelInviteModal"; import { NavLink, useLocation } from "react-router-dom"; export default function ChannelChat({ cid = "", dropFiles = [] }) { @@ -40,10 +40,12 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) { data, messageData, loginUid, + loginUser, footprint, } = useSelector((store) => { return { footprint: store.footprint, + loginUser: store.contacts.byId[store.authData.uid], loginUid: store.authData.uid, msgIds: store.channelMessage[cid] || [], userIds: store.contacts.ids, @@ -62,18 +64,15 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) { setAddMemberModalVisible((prev) => !prev); }; - const { name, description, is_public, members = [] } = data; + const { name, description, is_public, members = [], owner } = data; const memberIds = is_public ? userIds : members; + const addVisible = loginUser?.is_admin || owner == loginUid; console.log("channel message list", msgIds); const readIndex = footprint.readChannels[cid]; return ( <> {addMemberModalVisible && ( - + )} - {!is_public && ( + {addVisible && ( Add members