diff --git a/.prettierrc b/.prettierrc index 77039d87f..15acb02b2 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,5 +2,6 @@ "tabWidth": 2, "useTabs": false, "plugins": ["prettier-plugin-organize-imports"], - "organizeImportsTypeOrder": "first" + "organizeImportsTypeOrder": "first", + "endOfLine": "auto" } diff --git a/packages/client/components/app/menus/UserContextMenu.tsx b/packages/client/components/app/menus/UserContextMenu.tsx index d67cdee22..a2a9beaaf 100644 --- a/packages/client/components/app/menus/UserContextMenu.tsx +++ b/packages/client/components/app/menus/UserContextMenu.tsx @@ -189,6 +189,17 @@ export function UserContextMenu(props: { navigator.clipboard.writeText(props.user.id); } + /** + * Remove user from group + */ + function removeMember() { + openModal({ + type: "remove_member", + user: props.user, + group: props.channel!, + }); + } + return ( @@ -328,6 +339,23 @@ export function UserContextMenu(props: { + + + Remove Member + + + + + Report user @@ -414,11 +444,14 @@ export function UserContextMenu(props: { * Provide floating user menus on this element * @param user User * @param member Server Member + * @param contextMessage Message + * @param contextGroup Group */ export function floatingUserMenus( user: User, member?: ServerMember, contextMessage?: Message, + contextGroup?: Channel, ): JSX.Directives["floating"] & object { return { userCard: { @@ -435,7 +468,7 @@ export function floatingUserMenus( user={user} member={member} contextMessage={contextMessage} - channel={contextMessage?.channel} + channel={contextMessage?.channel ?? contextGroup} /> ); }, diff --git a/packages/client/components/modal/modals.tsx b/packages/client/components/modal/modals.tsx index a835c16ee..25d68f3e0 100644 --- a/packages/client/components/modal/modals.tsx +++ b/packages/client/components/modal/modals.tsx @@ -45,6 +45,7 @@ import { MFAFlowModal } from "./modals/MFAFlow"; import { MFARecoveryModal } from "./modals/MFARecovery"; import { OnboardingModal } from "./modals/Onboarding"; import { PolicyChangeModal } from "./modals/PolicyChange"; +import { RemoveMemberModal } from "./modals/RemoveMember"; import { RenameSessionModal } from "./modals/RenameSession"; import { ReportContentModal } from "./modals/ReportContent"; import { ResetBotTokenModal } from "./modals/ResetBotToken"; @@ -184,6 +185,9 @@ export function RenderModal(props: ActiveModal & { onClose: () => void }) { return ; case "edit_category": return ; + case "remove_member": + return ; + case "screen_share_settings": return ; default: diff --git a/packages/client/components/modal/modals/RemoveMember.tsx b/packages/client/components/modal/modals/RemoveMember.tsx new file mode 100644 index 000000000..207a13d76 --- /dev/null +++ b/packages/client/components/modal/modals/RemoveMember.tsx @@ -0,0 +1,50 @@ +import { Trans } from "@lingui-solid/solid/macro"; + +import { Avatar, Column, Dialog, DialogProps, Text } from "@revolt/ui"; + +import { useMutation } from "@tanstack/solid-query"; +import { useModals } from ".."; +import { Modals } from "../types"; + +/** + * Ban a server member with reason + */ +export function RemoveMemberModal( + props: DialogProps & Modals & { type: "remove_member" }, +) { + const { showError } = useModals(); + + const removeMember = useMutation(() => ({ + mutationFn: (user: string) => { + return props.group.removeMember(user); + }, + onError: showError, + })); + + return ( + Remove Member} + actions={[ + { text: Cancel }, + { + text: Remove, + onClick: () => removeMember.mutateAsync(props.user.id), + }, + ]} + isDisabled={removeMember.isPending} + > + + + + + Are you sure you want to remove{" "} + {props.user?.displayName ?? props.user.username} from{" "} + {props.group.name}? + + + + + ); +} diff --git a/packages/client/components/modal/types.ts b/packages/client/components/modal/types.ts index 0c8cebb52..c69fee896 100644 --- a/packages/client/components/modal/types.ts +++ b/packages/client/components/modal/types.ts @@ -7,9 +7,9 @@ import { Emoji, File, ImageEmbed, + Message, MFA, MFATicket, - Message, PublicBot, PublicChannelInvite, Server, @@ -317,6 +317,10 @@ export type Modals = server: Server; category: CategoryData; } + | { + type: "remove_member"; + group: Channel; + user: User; | { type: "screen_share_settings"; trackReference: TrackReference; diff --git a/packages/client/src/interface/channels/text/MemberSidebar.tsx b/packages/client/src/interface/channels/text/MemberSidebar.tsx index 7c3835a5c..ee7dfe905 100644 --- a/packages/client/src/interface/channels/text/MemberSidebar.tsx +++ b/packages/client/src/interface/channels/text/MemberSidebar.tsx @@ -1,4 +1,4 @@ -import { Match, Show, Switch, createEffect, createMemo, on } from "solid-js"; +import { createEffect, createMemo, Match, on, Show, Switch } from "solid-js"; import { useLingui } from "@lingui-solid/solid/macro"; import { VirtualContainer } from "@minht11/solid-virtual-container"; @@ -16,9 +16,9 @@ import { OverflowingText, Row, Tooltip, - UserStatus, - Username, typography, + Username, + UserStatus, } from "@revolt/ui"; interface Props { @@ -311,7 +311,7 @@ export function GroupMemberSidebar(props: Props) { width: "100%", }} > - + )} @@ -378,7 +378,11 @@ const NameStatusStack = styled("div", { /** * Member */ -function Member(props: { user?: User; member?: ServerMember }) { +function Member(props: { + user?: User; + member?: ServerMember; + group?: Channel; +}) { const { t } = useLingui(); /** @@ -408,6 +412,8 @@ function Member(props: { user?: User; member?: ServerMember }) { use:floating={floatingUserMenus( (props.user ?? props.member?.user)!, props.member, + undefined, + props.group, )} >