From 34e286040c321316d103c5a03797b34b4fb04d27 Mon Sep 17 00:00:00 2001 From: Asmaa Abozaid <130288326+Asmaa-204@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:54:13 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20(groups):=20Admin=20can=20delete=20?= =?UTF-8?q?group=20for=20all=20members=20(#160)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Feat(profile-picture): set/remove profile picture feat(profile-picture): set/remove profile picture * admin mock * fix: adjust sixing (#158) fix: voice notes * ✨ (groups): Admin can delete group for all members --------- Co-authored-by: ahmedHamdiy Co-authored-by: Sarah Kamal <143711089+sarah-kamall@users.noreply.github.com> --- app/src/components/Modal.tsx | 13 +- .../groups/ConfirmDeleteGroupModal.tsx | 116 ++++++++++++++++++ app/src/features/groups/EditGroupInfo.tsx | 28 +++-- app/src/features/groups/data/settings.ts | 24 ++-- app/src/sockets/SocketProvider.tsx | 33 ++++- app/src/types/socket.ts | 1 + 6 files changed, 184 insertions(+), 31 deletions(-) create mode 100644 app/src/features/groups/ConfirmDeleteGroupModal.tsx diff --git a/app/src/components/Modal.tsx b/app/src/components/Modal.tsx index 74b84e1d..e2bbee32 100644 --- a/app/src/components/Modal.tsx +++ b/app/src/components/Modal.tsx @@ -20,17 +20,20 @@ const ModalContainer = styled.div` padding: 2rem; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); - text-align: center; width: 400px; + + display: flex; + flex-direction: column; + align-items: flex-start; + + gap: 1rem; `; const ModalTitle = styled.h2` - margin-bottom: 1rem; color: var(--color-text); `; const ModalMessage = styled.p` - margin-bottom: 2rem; color: var(--color-text-secondary); `; @@ -53,7 +56,7 @@ type ModalProps = { isOpen: boolean; onClose: () => void; title: string; - message: string; + message?: string; children: React.ReactNode; }; @@ -75,7 +78,7 @@ function Modal({ onClose, isOpen, title, message, children }: ModalProps) { × {title} - {message} + {message && {message}} {children} diff --git a/app/src/features/groups/ConfirmDeleteGroupModal.tsx b/app/src/features/groups/ConfirmDeleteGroupModal.tsx new file mode 100644 index 00000000..8c9f17aa --- /dev/null +++ b/app/src/features/groups/ConfirmDeleteGroupModal.tsx @@ -0,0 +1,116 @@ +import { useState } from "react"; +import { useDispatch } from "react-redux"; +import styled from "styled-components"; + +import Checkbox from "@components/Checkbox"; +import Modal from "@components/Modal"; + +import { useSocket } from "@hooks/useSocket"; +import { useRightSideBarContext } from "./contexts/RightSideBarProvider"; +import { resetRightSideBar } from "@state/side-bar/sideBar"; +import { useGroupInfo } from "./hooks/useGroupInfo"; + +const Buttons = styled.div` + display: flex; + justify-content: space-between; + + width: 100%; +`; + +const CheckboxContainer = styled.div` + display: flex; + align-items: center; + gap: 0.5rem; + + cursor: pointer; + + width: 100%; + padding: 0.5rem 1rem; + + border-radius: var(--border-radius-default-tiny); + + & span { + color: var(--color-text); + } + + &:hover { + background-color: var(--color-item-hover); + } +`; + +const Button = styled.button<{ $type?: string }>` + border: none; + border-radius: var(--border-radius-default-tiny); + padding: 0.5rem 1rem; + + text-transform: uppercase; + letter-spacing: 1px; + font-weight: 600; + font-size: 1rem; + + background-color: transparent; + color: ${({ $type }) => + $type === "error" ? "var(--color-error)" : "var(--accent-color)"}; + + &:hover { + background-color: ${({ $type }) => + $type === "error" + ? "var(--color-error-shade)" + : "var(--color-item-hover)"}; + } +`; + +type ModalProps = { + isOpen: boolean; + onClose: () => void; +}; + +function ConfirmDeleteGroupModal({ isOpen, onClose }: ModalProps) { + const [checked, setChecked] = useState(false); + const { leaveGroup, deleteGroup } = useSocket(); + const { setIsRightSideBarOpen } = useRightSideBarContext(); + const dispatch = useDispatch(); + const { chatId, isCurrUserAdmin } = useGroupInfo(); + + function handleDelete() { + if (checked) { + deleteGroup({ chatId: chatId! }); + } else { + leaveGroup({ chatId: chatId! }); + } + dispatch(resetRightSideBar()); + setIsRightSideBarOpen(false); + } + + return ( + + {isCurrUserAdmin && ( + setChecked((prev) => !prev)}> + setChecked((prev) => !prev)} + checked={checked} + /> + delete for all users + + )} + + + + + + ); +} + +export default ConfirmDeleteGroupModal; diff --git a/app/src/features/groups/EditGroupInfo.tsx b/app/src/features/groups/EditGroupInfo.tsx index 827a9161..7a8882e4 100644 --- a/app/src/features/groups/EditGroupInfo.tsx +++ b/app/src/features/groups/EditGroupInfo.tsx @@ -1,10 +1,11 @@ +import { useState } from "react"; +import { useDispatch } from "react-redux"; import styled from "styled-components"; + import SettingsRow from "./SettingsRow"; -import { useDispatch } from "react-redux"; -import { resetRightSideBar } from "@state/side-bar/sideBar"; +import ConfirmDeleteGroupModal from "./ConfirmDeleteGroupModal"; import { useGroupInfo } from "./hooks/useGroupInfo"; -import { useSocket } from "@hooks/useSocket"; -import { useRightSideBarContext } from "./contexts/RightSideBarProvider"; + import { getSettings } from "./data/settings"; import { sideBarPages } from "types/sideBar"; @@ -19,13 +20,12 @@ function EditGroupInfo() { const { admins, groupMembers, - chatId, isPending, chatType, numGivenPermissions } = useGroupInfo(); - const { leaveGroup } = useSocket(); - const { setIsRightSideBarOpen } = useRightSideBarContext(); + + const [isModalOpen, setIsModalOpen] = useState(false); if (isPending) return null; @@ -38,17 +38,21 @@ function EditGroupInfo() { dispatch, admins, groupMembers, - chatId: chatId!, - leaveGroup, - setIsRightSideBarOpen, - resetRightSideBar, chatType: chatType!, backView, - numGivenPermissions + numGivenPermissions, + setIsModalOpen }); return ( + {isModalOpen && ( + setIsModalOpen(false)} + + /> + )} {settings.map((setting, index) => ( void; - setIsRightSideBarOpen: (value: boolean) => void; - resetRightSideBar: () => { type: string }; + + setIsModalOpen: (value: boolean) => void; }; const getSettings = ({ @@ -21,12 +20,10 @@ const getSettings = ({ dispatch, admins, groupMembers, - chatId, - leaveGroup, - setIsRightSideBarOpen, - resetRightSideBar, + backView, - numGivenPermissions + numGivenPermissions, + setIsModalOpen }: SettingsProps) => [ { testid: "group-type", @@ -58,7 +55,7 @@ const getSettings = ({ testid: "members", icon: "Members" as iconStrings, title: chatType === "group" ? "Members" : "Subscribers", - subtitle: groupMembers.length, + subtitle: groupMembers?.length, onClick: () => dispatch( updateSideBarView({ @@ -86,9 +83,10 @@ const getSettings = ({ title: `Delete and Leave ${chatType}`, subtitle: "", onClick: () => { - leaveGroup({ chatId }); - setIsRightSideBarOpen(false); - dispatch(resetRightSideBar()); + setIsModalOpen(true); + // leaveGroup({ chatId }); + // setIsRightSideBarOpen(false); + // dispatch(resetRightSideBar()); } } ]; diff --git a/app/src/sockets/SocketProvider.tsx b/app/src/sockets/SocketProvider.tsx index 0622ed20..ce89515b 100644 --- a/app/src/sockets/SocketProvider.tsx +++ b/app/src/sockets/SocketProvider.tsx @@ -254,6 +254,14 @@ function SocketProvider({ children }: SocketProviderProps) { } ); + socket.on( + "DELETE_GROUP_CHANNEL_SERVER", + ({ chatId }: { chatId: string }) => { + console.log("DELETE_GROUP_CHANNEL_SERVER", chatId); + queryClient.invalidateQueries({ queryKey: ["chats"] }); + } + ); + socket.on("REMOVE_MEMBERS_SERVER", ({ memberId }: { memberId: string }) => { console.log("REMOVE_MEMBERS_SERVER"); @@ -607,6 +615,28 @@ function SocketProvider({ children }: SocketProviderProps) { } } + function deleteGroup({ chatId }: { chatId: string }) { + if (isConnected && socket) { + socket.emit( + "DELETE_GROUP_CHANNEL_CLIENT", + { chatId }, + ({ success, message, error }: AckCreateGroup) => { + console.log(message, error, success); + if (success) { + toast.success(message); + queryClient.invalidateQueries({ queryKey: ["chats"] }); + navigate("/"); + } else { + toast.error(message); + console.error(error); + } + } + ); + } else { + console.warn("Cannot delete group: not connected to socket server"); + } + } + return ( {children} diff --git a/app/src/types/socket.ts b/app/src/types/socket.ts index 1ebbe548..c6c9d3ab 100644 --- a/app/src/types/socket.ts +++ b/app/src/types/socket.ts @@ -55,6 +55,7 @@ export interface SocketContextType { who: "everyone" | "admins"; }) => void; leaveGroup: ({ chatId }: { chatId: string }) => void; + deleteGroup: ({ chatId }: { chatId: string }) => void; createVoiceCall: ({ chatId }: { chatId: string }) => void; acceptCall: (callId: string | null) => void; }