@@ -3,8 +3,7 @@ import {useNavigate, useParams} from "@solidjs/router";
33import { Accessor , createEffect , createMemo , createSignal , For , Index , onMount , Show } from "solid-js" ;
44import StatusIndicator from "../users/StatusIndicator" ;
55import SidebarSection from "../ui/SidebarSection" ;
6- import { ReactiveSet } from "@solid-primitives/set" ;
7- import { displayName , extendedColor , maxIterator , setDifference } from "../../utils" ;
6+ import { displayName , extendedColor , maxIterator } from "../../utils" ;
87import useContextMenu from "../../hooks/useContextMenu" ;
98import ContextMenu , { ContextMenuButton , DangerContextMenuButton } from "../ui/ContextMenu" ;
109import UserPlus from "../icons/svg/UserPlus" ;
@@ -23,6 +22,7 @@ import Crown from "../icons/svg/Crown";
2322import Robot from "../icons/svg/Robot" ;
2423import UserMinus from "../icons/svg/UserMinus" ;
2524import { t } from "../../i18n" ;
25+ import Gavel from "../icons/svg/Gavel" ;
2626
2727export function GuildMemberGroup ( props : { members : Iterable < User | bigint > , offline ?: boolean } ) {
2828 const api = getApi ( ) !
@@ -41,6 +41,11 @@ export function GuildMemberGroup(props: { members: Iterable<User | bigint>, offl
4141 if ( ! response . ok ) throw new Error ( response . errorJsonOrThrow ( ) . message )
4242 }
4343
44+ const banMember = async ( id : bigint ) => {
45+ const response = await api . request ( 'PUT' , `/guilds/${ guildId ( ) } /bans/${ id } ` )
46+ if ( ! response . ok ) throw new Error ( response . errorJsonOrThrow ( ) . message )
47+ }
48+
4449 return (
4550 < For each = { [ ...props . members ] } >
4651 { ( userOrId ) => {
@@ -101,6 +106,20 @@ export function GuildMemberGroup(props: { members: Iterable<User | bigint>, offl
101106 ) }
102107 />
103108 </ Show >
109+ < Show when = { ! isSelf ( ) && canManage ( ) && permissions ( ) . has ( 'BAN_MEMBERS' ) } >
110+ < DangerContextMenuButton
111+ icon = { Gavel }
112+ label = "Ban Member"
113+ onClick = { ( ) => toast . promise (
114+ banMember ( user_id ) ,
115+ {
116+ loading : 'Banning user...' ,
117+ success : 'User banned.' ,
118+ error : ( err ) => err . message ,
119+ }
120+ ) }
121+ />
122+ </ Show >
104123 </ ContextMenu >
105124 ) }
106125 >
@@ -180,56 +199,37 @@ export default function GuildMemberList() {
180199 const params = useParams ( )
181200 const guildId = ( ) => BigInt ( params . guildId ! )
182201 const guildMemo = createMemo ( ( ) => api . cache ! . guilds . get ( guildId ( ) ) )
183- if ( ! guildMemo ( ) ) return
184202
185203 const isLoaded = createMemo ( ( ) => api . cache ! . isGuildLoaded ( guildId ( ) ) )
186204
187205 onMount ( ( ) => {
188206 api . ws ?. ensureGuildLoaded ( guildId ( ) )
189207 } )
190208
191- const online = new ReactiveSet < bigint > ( )
192- const offline = new ReactiveSet < bigint > ( )
193-
194- const membersMemo = createMemo ( ( ) => api . cache ! . memberReactor . get ( guildMemo ( ) ! . id ) )
195- createEffect < Set < bigint > | undefined > ( ( tracked ) => {
196- const members = membersMemo ( )
197- if ( members == null ) return
198-
199- for ( const member of members ) {
200- if ( tracked ?. has ( member ) ) continue
201- tracked ?. add ( member )
202-
203- createEffect ( ( prev ) => {
204- const status = api . cache ! . presences . get ( member ) ?. status
205- if ( prev != null && ( prev === 'offline' ) === ( status === 'offline' ) )
206- return status
209+ const membersMemo = createMemo ( ( ) => {
210+ const guild = guildMemo ( )
211+ return guild ? ( api . cache ! . memberReactor . get ( guild . id ) ?? [ ] ) : [ ]
212+ } )
207213
208- if ( status === 'offline' || ! status ) {
209- online . delete ( member ) ;
210- offline . add ( member )
211- } else {
212- offline . delete ( member ) ;
213- online . add ( member )
214- }
215- return status
216- } )
214+ const onlineOffline = createMemo ( ( ) => {
215+ const online : bigint [ ] = [ ]
216+ const offline : bigint [ ] = [ ]
217+ for ( const member of membersMemo ( ) ) {
218+ const status = api . cache ! . presences . get ( member ) ?. status
219+ if ( status && status !== 'offline' ) online . push ( member )
220+ else offline . push ( member )
217221 }
218- const updated = new Set ( members )
219- if ( tracked ) for ( const removed of setDifference ( tracked , updated ) ) {
220- online . delete ( removed )
221- offline . delete ( removed )
222- }
223- return updated
224- } , new Set < bigint > ( ) )
222+ return { online, offline }
223+ } )
224+ const online = ( ) => onlineOffline ( ) . online
225+ const offline = ( ) => onlineOffline ( ) . offline
225226
226- // TODO: probably inefficient to have this reevaluate every time member presence changes
227227 const roleGroups = createMemo ( ( ) => {
228228 const roles = api . cache ! . roles
229229 const groups = new Map < bigint , { name : string , position : number , members : bigint [ ] } > ( )
230230 const noRoles = [ ] as bigint [ ]
231231
232- for ( const member of online ) {
232+ for ( const member of online ( ) ) {
233233 const memberRoles = api . cache ! . members . get ( memberKey ( guildId ( ) , member ) ) ?. roles ?. map ( BigInt ) ?? [ ]
234234 const resolved = memberRoles
235235 . map ( r => roles . get ( r ) )
@@ -314,17 +314,17 @@ export default function GuildMemberList() {
314314 </ Show >
315315 ) }
316316 </ For >
317- < Show when = { noRoles ( ) . length } keyed = { false } >
317+ < Show when = { noRoles ( ) . length } >
318318 < SidebarSection badge = { ( ) => noRoles ( ) . length } >
319319 { t ( 'status.online' ) }
320320 </ SidebarSection >
321321 < GuildMemberGroup members = { noRoles ( ) } />
322322 </ Show >
323- < Show when = { offline . size } keyed = { false } >
324- < SidebarSection badge = { ( ) => offline . size } >
323+ < Show when = { offline ( ) . length } >
324+ < SidebarSection badge = { ( ) => offline ( ) . length } >
325325 { t ( 'status.offline' ) }
326326 </ SidebarSection >
327- < GuildMemberGroup members = { offline } offline />
327+ < GuildMemberGroup members = { offline ( ) } offline />
328328 </ Show >
329329 </ >
330330 } >
0 commit comments