From feba77e905af36d0dcfe66dc827fa1bad4ad39d0 Mon Sep 17 00:00:00 2001 From: p9 Date: Wed, 22 Apr 2026 13:27:26 +0530 Subject: [PATCH] Preact: Add user mod actions panel --- play.pokemonshowdown.com/src/client-main.ts | 1 + play.pokemonshowdown.com/src/panel-popups.tsx | 212 +++++++++++------- 2 files changed, 132 insertions(+), 81 deletions(-) diff --git a/play.pokemonshowdown.com/src/client-main.ts b/play.pokemonshowdown.com/src/client-main.ts index 503e281e7..d5362394d 100644 --- a/play.pokemonshowdown.com/src/client-main.ts +++ b/play.pokemonshowdown.com/src/client-main.ts @@ -1832,6 +1832,7 @@ export const PS = new class extends PSModel { "groupchat-*": "*right", "users": "*popup", "useroptions-*": "*popup", + "usermodoptions-*": "*popup", "userlist": "*semimodal-popup", "avatars": "*semimodal-popup", "changepassword": "*semimodal-popup", diff --git a/play.pokemonshowdown.com/src/panel-popups.tsx b/play.pokemonshowdown.com/src/panel-popups.tsx index 67eab3d8a..a0a8f877f 100644 --- a/play.pokemonshowdown.com/src/panel-popups.tsx +++ b/play.pokemonshowdown.com/src/panel-popups.tsx @@ -144,6 +144,7 @@ class UserPanel extends PSRoomPanel {

{} {} + {}

)); @@ -221,12 +222,90 @@ class UserOptionsPanel extends PSRoomPanel { static readonly routes = ['useroptions-*']; static readonly location = 'popup'; static readonly noURL = true; + declare state: { + requestSent?: boolean, + }; + getTargets() { + const [, targetUser, targetRoomid] = PSUtils.splitFirst(this.props.room.id, '-', 2); + let targetRoom = (PS.rooms[targetRoomid] || null) as ChatRoom | null; + if (targetRoom?.type !== 'chat') targetRoom = targetRoom?.getParent() as ChatRoom; + if (targetRoom?.type !== 'chat') targetRoom = targetRoom?.getParent() as ChatRoom; + if (targetRoom?.type !== 'chat') targetRoom = null; + return { targetUser: targetUser as ID, targetRoomid: targetRoomid as RoomID, targetRoom }; + } + + handleAddFriend = (ev: Event) => { + const { targetUser, targetRoom } = this.getTargets(); + targetRoom?.send(`/friend add ${targetUser}`); + this.setState({ requestSent: true }); + ev.preventDefault(); + ev.stopImmediatePropagation(); + }; + + handleIgnore = () => { + const { targetUser, targetRoom } = this.getTargets(); + targetRoom?.send(`/ignore ${targetUser}`); + this.close(); + }; + + handleUnignore = () => { + const { targetUser, targetRoom } = this.getTargets(); + targetRoom?.send(`/unignore ${targetUser}`); + this.close(); + }; + + isIgnoringUser = (userid: string) => { + const ignoring = PS.prefs.ignore || {}; + if (ignoring[userid] === 1) return true; + return false; + }; + + override render() { + const room = this.props.room; + const { targetUser } = this.getTargets(); + + return
+

+ {this.isIgnoringUser(targetUser) ? ( + + ) : ( + + )} +

+

+ +

+

+ {this.state.requestSent ? ( + + ) : ( + + )} +

+
; + } +} + +class UserModOptionsPanel extends PSRoomPanel { + static readonly id = 'usermodoptions'; + static readonly routes = ['usermodoptions-*']; + static readonly location = 'popup'; + static readonly noURL = true; declare state: { showMuteInput?: boolean, showBanInput?: boolean, showLockInput?: boolean, showConfirm?: boolean, - requestSent?: boolean, data?: Record, }; getTargets() { @@ -280,28 +359,10 @@ class UserOptionsPanel extends PSRoomPanel { cmd += `${targetUser} ${data.reason ? ',' + data.reason : ''}`; targetRoom?.send(cmd); this.close(); - }; - - handleAddFriend = (ev: Event) => { - const { targetUser, targetRoom } = this.getTargets(); - targetRoom?.send(`/friend add ${targetUser}`); - this.setState({ requestSent: true }); ev.preventDefault(); ev.stopImmediatePropagation(); }; - handleIgnore = () => { - const { targetUser, targetRoom } = this.getTargets(); - targetRoom?.send(`/ignore ${targetUser}`); - this.close(); - }; - - handleUnignore = () => { - const { targetUser, targetRoom } = this.getTargets(); - targetRoom?.send(`/unignore ${targetUser}`); - this.close(); - }; - muteUser = (ev: Event) => { this.setState({ showMuteInput: false }); const hrMute = (ev.currentTarget as HTMLButtonElement).value === "1hr"; @@ -345,10 +406,13 @@ class UserOptionsPanel extends PSRoomPanel { ev.stopImmediatePropagation(); }; - isIgnoringUser = (userid: string) => { - const ignoring = PS.prefs.ignore || {}; - if (ignoring[userid] === 1) return true; - return false; + handleModlog = (ev: Event) => { + const { targetUser, targetRoom } = this.getTargets(); + const isGlobalModlog = (ev.currentTarget as HTMLButtonElement).value === "globalmodlog"; + targetRoom?.send(`/modlog userid=${targetUser}, room=${isGlobalModlog ? 'global' : targetRoom?.id}`); + this.close(); + ev.preventDefault(); + ev.stopImmediatePropagation(); }; override render() { @@ -370,37 +434,12 @@ class UserOptionsPanel extends PSRoomPanel { if (actionName === 'lock') { return canLock && !this.state.showBanInput && !this.state.showMuteInput && !this.state.showConfirm; } + if (actionName === 'modlog') { + return !this.state.showLockInput && !this.state.showBanInput && !this.state.showConfirm && !this.state.showMuteInput; + } }; return
-

- {this.isIgnoringUser(targetUser) ? ( - - ) : ( - - )} -

-

- -

-

- {this.state.requestSent ? ( - - ) : ( - - )} -

- {(canMute || canBan || canLock) &&
} {this.state.showConfirm &&

{this.state.data?.action} {targetUser} {} @@ -416,36 +455,46 @@ class UserOptionsPanel extends PSRoomPanel {

}

- {isVisible('mute') && (this.state.showMuteInput ? ( -

- {}
- {} - {} - -
- ) : ( - - ))} {} - {isVisible('ban') && (this.state.showBanInput ? ( -
-
- {} - {} - -
- ) : ( - - ))} {} +

+ {isVisible('mute') && (this.state.showMuteInput ? ( +

+ {}
+ {} + {} + +
+ ) : ( + + ))} {} + {isVisible('ban') && (this.state.showBanInput ? ( +
+
+ {} + {} + +
+ ) : ( + + ))} {} +

+

+ {canMute && isVisible('modlog') && } {} + {canLock && isVisible('modlog') && } {} +

{isVisible('lock') && (this.state.showLockInput ? (