Skip to content

Commit

Permalink
✨ (groups): Admin can delete group for all members (#160)
Browse files Browse the repository at this point in the history
* ✨ 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 <[email protected]>
Co-authored-by: Sarah Kamal <[email protected]>
  • Loading branch information
3 people authored Dec 21, 2024
1 parent d679009 commit 34e2860
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 31 deletions.
13 changes: 8 additions & 5 deletions app/src/components/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
`;

Expand All @@ -53,7 +56,7 @@ type ModalProps = {
isOpen: boolean;
onClose: () => void;
title: string;
message: string;
message?: string;
children: React.ReactNode;
};

Expand All @@ -75,7 +78,7 @@ function Modal({ onClose, isOpen, title, message, children }: ModalProps) {
&times;
</CloseButton>
<ModalTitle>{title}</ModalTitle>
<ModalMessage>{message}</ModalMessage>
{message && <ModalMessage>{message}</ModalMessage>}
{children}
</ModalContainer>
</ModalOverlay>
Expand Down
116 changes: 116 additions & 0 deletions app/src/features/groups/ConfirmDeleteGroupModal.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Modal
title="Delete Group"
onClose={onClose}
isOpen={isOpen}
message="Are you sure you want to delete and leave this group?"
>
{isCurrUserAdmin && (
<CheckboxContainer onClick={() => setChecked((prev) => !prev)}>
<Checkbox
data-testid="delete-for-all-checkbox"
// onChange={() => setChecked((prev) => !prev)}
checked={checked}
/>
<span>delete for all users</span>
</CheckboxContainer>
)}
<Buttons>
<Button onClick={onClose}>Cancel</Button>
<Button
data-testid="delete-button"
$type="error"
onClick={handleDelete}
>
Delete
</Button>
</Buttons>
</Modal>
);
}

export default ConfirmDeleteGroupModal;
28 changes: 16 additions & 12 deletions app/src/features/groups/EditGroupInfo.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -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;

Expand All @@ -38,17 +38,21 @@ function EditGroupInfo() {
dispatch,
admins,
groupMembers,
chatId: chatId!,
leaveGroup,
setIsRightSideBarOpen,
resetRightSideBar,
chatType: chatType!,
backView,
numGivenPermissions
numGivenPermissions,
setIsModalOpen
});

return (
<Container data-testid="group-settings-container">
{isModalOpen && (
<ConfirmDeleteGroupModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}

/>
)}
{settings.map((setting, index) => (
<SettingsRow
key={index}
Expand Down
24 changes: 11 additions & 13 deletions app/src/features/groups/data/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,23 @@ type SettingsProps = {
dispatch: Dispatch;
admins: any[];
groupMembers: any[];
chatId: string;

chatType: string;
backView: sideBarPages;
numGivenPermissions: number;
leaveGroup: (params: { chatId: string }) => void;
setIsRightSideBarOpen: (value: boolean) => void;
resetRightSideBar: () => { type: string };

setIsModalOpen: (value: boolean) => void;
};

const getSettings = ({
chatType,
dispatch,
admins,
groupMembers,
chatId,
leaveGroup,
setIsRightSideBarOpen,
resetRightSideBar,

backView,
numGivenPermissions
numGivenPermissions,
setIsModalOpen
}: SettingsProps) => [
{
testid: "group-type",
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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());
}
}
];
Expand Down
33 changes: 32 additions & 1 deletion app/src/sockets/SocketProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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 (
<SocketContext.Provider
value={{
Expand All @@ -624,7 +654,8 @@ function SocketProvider({ children }: SocketProviderProps) {
removeMembers,
acceptCall,
createVoiceCall,
setPermission
setPermission,
deleteGroup
}}
>
{children}
Expand Down
1 change: 1 addition & 0 deletions app/src/types/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit 34e2860

Please sign in to comment.