mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 23:16:21 +00:00
5c3589c29e
ModToolsView
- Subscribe to useRoomUserListSnapshot so the selected user's
"still in room" state is reactive — green dot when the user is
in the current room, gray dot when they've left. Previously the
selection was a static capture at click time.
- Add an inline X to clear the selected-user slot without having
to click a different avatar.
- Report Tool button shows a count badge for OPEN tickets
(IssueMessageData.STATE_OPEN) so a new ticket arriving while
the panel is open is visible immediately. Caps display at 99+.
- Tooltip on the room-bound buttons explains why they're disabled
("Enter a room first") instead of showing a silent disabled state.
- Buttons grow their labels with `flex-grow text-start` so the
trailing dot / badge / clear-X sits flush right.
useModTools
- Fix splice(index) → splice(index, 1) in close{Room,RoomChatlog,
UserInfo,UserChatlog} — the omitted second argument was
silently deleting EVERY subsequent open panel, not just the one
being closed. Visible whenever a moderator had two or more panels
of the same kind open.
- Fix toggleUserChatlog reading from openRoomChatlogs instead of
openUserChatlogs — copy-paste typo made the toggle inconsistent
with the underlying state.
208 lines
6.6 KiB
TypeScript
208 lines
6.6 KiB
TypeScript
import { CallForHelpCategoryData, CfhSanctionMessageEvent, CfhTopicsInitEvent, IssueDeletedMessageEvent, IssueInfoMessageEvent, IssueMessageData, IssuePickFailedMessageEvent, ModeratorActionResultMessageEvent, ModeratorInitData, ModeratorInitMessageEvent, ModeratorToolPreferencesEvent } from '@nitrots/nitro-renderer';
|
|
import { useState } from 'react';
|
|
import { useBetween } from 'use-between';
|
|
import { NotificationAlertType, PlaySound, SoundNames } from '../../api';
|
|
import { useMessageEvent } from '../events';
|
|
import { useNotification } from '../notification';
|
|
|
|
const useModToolsState = () =>
|
|
{
|
|
const [ settings, setSettings ] = useState<ModeratorInitData>(null);
|
|
const [ openRooms, setOpenRooms ] = useState<number[]>([]);
|
|
const [ openRoomChatlogs, setOpenRoomChatlogs ] = useState<number[]>([]);
|
|
const [ openUserInfos, setOpenUserInfos ] = useState<number[]>([]);
|
|
const [ openUserChatlogs, setOpenUserChatlogs ] = useState<number[]>([]);
|
|
const [ tickets, setTickets ] = useState<IssueMessageData[]>([]);
|
|
const [ cfhCategories, setCfhCategories ] = useState<CallForHelpCategoryData[]>([]);
|
|
const { simpleAlert = null } = useNotification();
|
|
|
|
const openRoomInfo = (roomId: number) =>
|
|
{
|
|
if(openRooms.indexOf(roomId) >= 0) return;
|
|
|
|
setOpenRooms(prevValue => [ ...prevValue, roomId ]);
|
|
};
|
|
|
|
const closeRoomInfo = (roomId: number) =>
|
|
{
|
|
setOpenRooms(prevValue =>
|
|
{
|
|
const newValue = [ ...prevValue ];
|
|
const existingIndex = newValue.indexOf(roomId);
|
|
|
|
if(existingIndex >= 0) newValue.splice(existingIndex, 1);
|
|
|
|
return newValue;
|
|
});
|
|
};
|
|
|
|
const toggleRoomInfo = (roomId: number) =>
|
|
{
|
|
if(openRooms.indexOf(roomId) >= 0) closeRoomInfo(roomId);
|
|
else openRoomInfo(roomId);
|
|
};
|
|
|
|
const openRoomChatlog = (roomId: number) =>
|
|
{
|
|
if(openRoomChatlogs.indexOf(roomId) >= 0) return;
|
|
|
|
setOpenRoomChatlogs(prevValue => [ ...prevValue, roomId ]);
|
|
};
|
|
|
|
const closeRoomChatlog = (roomId: number) =>
|
|
{
|
|
setOpenRoomChatlogs(prevValue =>
|
|
{
|
|
const newValue = [ ...prevValue ];
|
|
const existingIndex = newValue.indexOf(roomId);
|
|
|
|
if(existingIndex >= 0) newValue.splice(existingIndex, 1);
|
|
|
|
return newValue;
|
|
});
|
|
};
|
|
|
|
const toggleRoomChatlog = (roomId: number) =>
|
|
{
|
|
if(openRoomChatlogs.indexOf(roomId) >= 0) closeRoomChatlog(roomId);
|
|
else openRoomChatlog(roomId);
|
|
};
|
|
|
|
const openUserInfo = (userId: number) =>
|
|
{
|
|
if(openUserInfos.indexOf(userId) >= 0) return;
|
|
|
|
setOpenUserInfos(prevValue => [ ...prevValue, userId ]);
|
|
};
|
|
|
|
const closeUserInfo = (userId: number) =>
|
|
{
|
|
setOpenUserInfos(prevValue =>
|
|
{
|
|
const newValue = [ ...prevValue ];
|
|
const existingIndex = newValue.indexOf(userId);
|
|
|
|
if(existingIndex >= 0) newValue.splice(existingIndex, 1);
|
|
|
|
return newValue;
|
|
});
|
|
};
|
|
|
|
const toggleUserInfo = (userId: number) =>
|
|
{
|
|
if(openUserInfos.indexOf(userId) >= 0) closeUserInfo(userId);
|
|
else openUserInfo(userId);
|
|
};
|
|
|
|
const openUserChatlog = (userId: number) =>
|
|
{
|
|
if(openUserChatlogs.indexOf(userId) >= 0) return;
|
|
|
|
setOpenUserChatlogs(prevValue => [ ...prevValue, userId ]);
|
|
};
|
|
|
|
const closeUserChatlog = (userId: number) =>
|
|
{
|
|
setOpenUserChatlogs(prevValue =>
|
|
{
|
|
const newValue = [ ...prevValue ];
|
|
const existingIndex = newValue.indexOf(userId);
|
|
|
|
if(existingIndex >= 0) newValue.splice(existingIndex, 1);
|
|
|
|
return newValue;
|
|
});
|
|
};
|
|
|
|
const toggleUserChatlog = (userId: number) =>
|
|
{
|
|
if(openUserChatlogs.indexOf(userId) >= 0) closeUserChatlog(userId);
|
|
else openUserChatlog(userId);
|
|
};
|
|
|
|
useMessageEvent<ModeratorInitMessageEvent>(ModeratorInitMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
const data = parser.data;
|
|
|
|
setSettings(data);
|
|
setTickets(data.issues);
|
|
});
|
|
|
|
useMessageEvent<IssueInfoMessageEvent>(IssueInfoMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setTickets(prevValue =>
|
|
{
|
|
const newValue = [ ...prevValue ];
|
|
const existingIndex = newValue.findIndex(ticket => (ticket.issueId === parser.issueData.issueId));
|
|
|
|
if(existingIndex >= 0) newValue[existingIndex] = parser.issueData;
|
|
else
|
|
{
|
|
newValue.push(parser.issueData);
|
|
|
|
PlaySound(SoundNames.MODTOOLS_NEW_TICKET);
|
|
}
|
|
|
|
return newValue;
|
|
});
|
|
});
|
|
|
|
useMessageEvent<ModeratorToolPreferencesEvent>(ModeratorToolPreferencesEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
});
|
|
|
|
useMessageEvent<IssuePickFailedMessageEvent>(IssuePickFailedMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
if(!parser) return;
|
|
|
|
simpleAlert('Failed to pick issue', NotificationAlertType.DEFAULT, null, null, 'Error');
|
|
});
|
|
|
|
useMessageEvent<IssueDeletedMessageEvent>(IssueDeletedMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setTickets(prevValue =>
|
|
{
|
|
const newValue = [ ...prevValue ];
|
|
const existingIndex = newValue.findIndex(ticket => (ticket.issueId === parser.issueId));
|
|
|
|
if(existingIndex >= 0) newValue.splice(existingIndex, 1);
|
|
|
|
return newValue;
|
|
});
|
|
});
|
|
|
|
useMessageEvent<ModeratorActionResultMessageEvent>(ModeratorActionResultMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
if(parser.success) simpleAlert('Moderation action was successfull', NotificationAlertType.MODERATION, null, null, 'Success');
|
|
else simpleAlert('There was a problem applying tht moderation action', NotificationAlertType.MODERATION, null, null, 'Error');
|
|
});
|
|
|
|
useMessageEvent<CfhTopicsInitEvent>(CfhTopicsInitEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setCfhCategories(parser.callForHelpCategories);
|
|
});
|
|
|
|
useMessageEvent<CfhSanctionMessageEvent>(CfhSanctionMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
// todo: update sanction data
|
|
});
|
|
|
|
return { settings, openRooms, openRoomChatlogs, openUserChatlogs, openUserInfos, cfhCategories, tickets, openRoomInfo, closeRoomInfo, toggleRoomInfo, openRoomChatlog, closeRoomChatlog, toggleRoomChatlog, openUserInfo, closeUserInfo, toggleUserInfo, openUserChatlog, closeUserChatlog, toggleUserChatlog };
|
|
};
|
|
|
|
export const useModTools = () => useBetween(useModToolsState);
|