Mod tool changes

This commit is contained in:
Bill 2022-07-28 01:23:22 -04:00
parent 0fb8a46b0e
commit 909f996dd8
37 changed files with 490 additions and 889 deletions

View File

@ -13,6 +13,7 @@ export * from './guide-tool';
export * from './hc-center';
export * from './help';
export * from './inventory';
export * from './mod-tools';
export * from './navigator';
export * from './nitro';
export * from './nitro/avatar';

View File

@ -1,4 +1,4 @@
export const getSourceName = (categoryId: number): string =>
export const GetIssueCategoryName = (categoryId: number) =>
{
switch(categoryId)
{
@ -29,7 +29,7 @@ export const getSourceName = (categoryId: number): string =>
return 'Photo';
case 15:
return 'Ambassador';
default:
return 'Unknown';
}
return 'Unknown';
}

View File

@ -1,4 +1,5 @@
export interface ISelectedUser {
export interface ISelectedUser
{
userId: number;
username: string;
}

View File

@ -0,0 +1,49 @@
export class ModActionDefinition
{
public static ALERT: number = 1;
public static MUTE: number = 2;
public static BAN: number = 3;
public static KICK: number = 4;
public static TRADE_LOCK: number = 5;
public static MESSAGE: number = 6;
private readonly _actionId: number;
private readonly _name: string;
private readonly _actionType: number;
private readonly _sanctionTypeId: number;
private readonly _actionLengthHours: number;
constructor(actionId: number, actionName: string, actionType: number, sanctionTypeId: number, actionLengthHours:number)
{
this._actionId = actionId;
this._name = actionName;
this._actionType = actionType;
this._sanctionTypeId = sanctionTypeId;
this._actionLengthHours = actionLengthHours;
}
public get actionId(): number
{
return this._actionId;
}
public get name(): string
{
return this._name;
}
public get actionType(): number
{
return this._actionType;
}
public get sanctionTypeId(): number
{
return this._sanctionTypeId;
}
public get actionLengthHours(): number
{
return this._actionLengthHours;
}
}

View File

@ -0,0 +1,4 @@
export * from './GetIssueCategoryName';
export * from './ISelectedUser';
export * from './IUserInfo';
export * from './ModActionDefinition';

View File

@ -1,16 +1,14 @@
import { FC, useMemo, useState } from 'react';
import { FC, useState } from 'react';
import { LocalizeText, ReportState } from '../../../api';
import { Button, Column, Flex, Text } from '../../../common';
import { useHelp } from '../../../hooks';
import { GetCfhCategories } from '../../mod-tools/common/GetCFHCategories';
import { useHelp, useModTools } from '../../../hooks';
export const SelectTopicView: FC<{}> = props =>
{
const [ selectedCategory, setSelectedCategory ] = useState(-1);
const [ selectedTopic, setSelectedTopic ] = useState(-1);
const { setActiveReport = null } = useHelp();
const cfhCategories = useMemo(() => GetCfhCategories(), []);
const { cfhCategories = [] } = useModTools();
const submitTopic = () =>
{

View File

@ -1,20 +0,0 @@
import { createContext, Dispatch, FC, ProviderProps, useContext } from 'react';
import { IModToolsAction, IModToolsState } from './reducers/ModToolsReducer';
export interface IModToolsContext
{
modToolsState: IModToolsState;
dispatchModToolsState: Dispatch<IModToolsAction>;
}
const ModToolsContext = createContext<IModToolsContext>({
modToolsState: null,
dispatchModToolsState: null
});
export const ModToolsContextProvider: FC<ProviderProps<IModToolsContext>> = props =>
{
return <ModToolsContext.Provider value={ props.value }>{ props.children }</ModToolsContext.Provider>
}
export const useModToolsContext = () => useContext(ModToolsContext);

View File

@ -1,258 +0,0 @@
import { CfhSanctionMessageEvent, CfhTopicsInitEvent, IssueDeletedMessageEvent, IssueInfoMessageEvent, IssuePickFailedMessageEvent, ModeratorActionResultMessageEvent, ModeratorInitMessageEvent, ModeratorToolPreferencesEvent, RoomEngineEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react';
import { NotificationAlertType, PlaySound, SoundNames } from '../../api';
import { ModToolsEvent, ModToolsOpenRoomChatlogEvent, ModToolsOpenRoomInfoEvent, ModToolsOpenUserChatlogEvent, ModToolsOpenUserInfoEvent } from '../../events';
import { useMessageEvent, useNotification, useRoomEngineEvent, useUiEvent } from '../../hooks';
import { SetCfhCategories } from './common/GetCFHCategories';
import { useModToolsContext } from './ModToolsContext';
import { ModToolsActions } from './reducers/ModToolsReducer';
export const ModToolsMessageHandler: FC<{}> = props =>
{
const { modToolsState = null, dispatchModToolsState = null } = useModToolsContext();
const { openRooms = null, openRoomChatlogs = null, openUserChatlogs = null, openUserInfo = null, tickets= null } = modToolsState;
const { simpleAlert = null } = useNotification();
const onModeratorInitMessageEvent = useCallback((event: ModeratorInitMessageEvent) =>
{
const parser = event.getParser();
if(!parser) return;
const data = parser.data;
dispatchModToolsState({
type: ModToolsActions.SET_INIT_DATA,
payload: {
settings: data
}
});
dispatchModToolsState({
type: ModToolsActions.SET_TICKETS,
payload: {
tickets: data.issues
}
});
}, [ dispatchModToolsState ]);
const onIssueInfoMessageEvent = useCallback((event: IssueInfoMessageEvent) =>
{
const parser = event.getParser();
if(!parser) return;
const newTickets = tickets ? Array.from(tickets) : [];
const existingIndex = newTickets.findIndex( entry => entry.issueId === parser.issueData.issueId)
if(existingIndex > -1)
{
newTickets[existingIndex] = parser.issueData;
}
else
{
newTickets.push(parser.issueData);
PlaySound(SoundNames.MODTOOLS_NEW_TICKET);
}
dispatchModToolsState({
type: ModToolsActions.SET_TICKETS,
payload: {
tickets: newTickets
}
});
}, [ dispatchModToolsState, tickets ]);
const onModeratorToolPreferencesEvent = useCallback((event: ModeratorToolPreferencesEvent) =>
{
const parser = event.getParser();
if(!parser) return;
}, []);
const onIssuePickFailedMessageEvent = useCallback((event: IssuePickFailedMessageEvent) =>
{
const parser = event.getParser();
if(!parser) return;
simpleAlert('Failed to pick issue', NotificationAlertType.DEFAULT, null, null, 'Error')
}, [ simpleAlert ]);
const onIssueDeletedMessageEvent = useCallback((event: IssueDeletedMessageEvent) =>
{
const parser = event.getParser();
if(!parser) return;
const newTickets = tickets ? Array.from(tickets) : [];
const existingIndex = newTickets.findIndex( entry => entry.issueId === parser.issueId);
if(existingIndex === -1) return;
newTickets.splice(existingIndex, 1);
dispatchModToolsState({
type: ModToolsActions.SET_TICKETS,
payload: {
tickets: newTickets
}
});
}, [ dispatchModToolsState, tickets ]);
const onModeratorActionResultMessageEvent = useCallback((event: ModeratorActionResultMessageEvent) =>
{
const parser = event.getParser();
if(!parser) return;
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');
}
}, [ simpleAlert ]);
const onCfhTopicsInitEvent = useCallback((event: CfhTopicsInitEvent) =>
{
const parser = event.getParser();
if(!parser) return;
const categories = parser.callForHelpCategories;
dispatchModToolsState({
type: ModToolsActions.SET_CFH_CATEGORIES,
payload: {
cfhCategories: categories
}
});
SetCfhCategories(categories);
}, [ dispatchModToolsState ]);
const onCfhSanctionMessageEvent = useCallback((event: CfhSanctionMessageEvent) =>
{
const parser = event.getParser();
if(!parser) return;
// todo: update sanction data
}, []);
useMessageEvent(ModeratorInitMessageEvent, onModeratorInitMessageEvent);
useMessageEvent(IssueInfoMessageEvent, onIssueInfoMessageEvent);
useMessageEvent(ModeratorToolPreferencesEvent, onModeratorToolPreferencesEvent);
useMessageEvent(IssuePickFailedMessageEvent, onIssuePickFailedMessageEvent);
useMessageEvent(IssueDeletedMessageEvent, onIssueDeletedMessageEvent);
useMessageEvent(ModeratorActionResultMessageEvent, onModeratorActionResultMessageEvent);
useMessageEvent(CfhTopicsInitEvent, onCfhTopicsInitEvent);
useMessageEvent(CfhSanctionMessageEvent, onCfhSanctionMessageEvent);
const onRoomEngineEvent = useCallback((event: RoomEngineEvent) =>
{
switch(event.type)
{
case RoomEngineEvent.INITIALIZED:
dispatchModToolsState({
type: ModToolsActions.SET_CURRENT_ROOM_ID,
payload: {
currentRoomId: event.roomId
}
});
return;
case RoomEngineEvent.DISPOSED:
dispatchModToolsState({
type: ModToolsActions.SET_CURRENT_ROOM_ID,
payload: {
currentRoomId: null
}
});
return;
}
}, [ dispatchModToolsState ]);
useRoomEngineEvent(RoomEngineEvent.INITIALIZED, onRoomEngineEvent);
useRoomEngineEvent(RoomEngineEvent.DISPOSED, onRoomEngineEvent);
const onModToolsEvent = useCallback((event: ModToolsEvent) =>
{
switch(event.type)
{
case ModToolsEvent.OPEN_ROOM_INFO: {
const castedEvent = (event as ModToolsOpenRoomInfoEvent);
if(openRooms && openRooms.includes(castedEvent.roomId)) return;
const rooms = openRooms || [];
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_ROOMS,
payload: {
openRooms: [ ...rooms, castedEvent.roomId ]
}
});
return;
}
case ModToolsEvent.OPEN_ROOM_CHATLOG: {
const castedEvent = (event as ModToolsOpenRoomChatlogEvent);
if(openRoomChatlogs && openRoomChatlogs.includes(castedEvent.roomId)) return;
const chatlogs = openRoomChatlogs || [];
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_ROOM_CHATLOGS,
payload: {
openRoomChatlogs: [ ...chatlogs, castedEvent.roomId ]
}
});
return;
}
case ModToolsEvent.OPEN_USER_INFO: {
const castedEvent = (event as ModToolsOpenUserInfoEvent);
if(openUserInfo && openUserInfo.includes(castedEvent.userId)) return;
const userInfo = openUserInfo || [];
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_USERINFO,
payload: {
openUserInfo: [ ...userInfo, castedEvent.userId ]
}
});
return;
}
case ModToolsEvent.OPEN_USER_CHATLOG: {
const castedEvent = (event as ModToolsOpenUserChatlogEvent);
if(openUserChatlogs && openUserChatlogs.includes(castedEvent.userId)) return;
const userChatlog = openUserChatlogs || [];
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_USER_CHATLOGS,
payload: {
openUserChatlogs: [ ...userChatlog, castedEvent.userId ]
}
});
return;
}
}
}, [ openRooms, dispatchModToolsState, openRoomChatlogs, openUserInfo, openUserChatlogs ]);
useUiEvent(ModToolsEvent.OPEN_ROOM_INFO, onModToolsEvent);
useUiEvent(ModToolsEvent.OPEN_ROOM_CHATLOG, onModToolsEvent);
useUiEvent(ModToolsEvent.OPEN_USER_INFO, onModToolsEvent);
useUiEvent(ModToolsEvent.OPEN_USER_CHATLOG, onModToolsEvent);
return null;
}

View File

@ -1,13 +1,8 @@
import { RoomEngineObjectEvent, RoomObjectCategory, RoomObjectType } from '@nitrots/nitro-renderer';
import { FC, useCallback, useReducer, useRef, useState } from 'react';
import { DispatchUiEvent, GetRoomSession } from '../../api';
import { ILinkEventTracker, RoomEngineEvent, RoomId, RoomObjectCategory, RoomObjectType } from '@nitrots/nitro-renderer';
import { FC, useEffect, useRef, useState } from 'react';
import { AddEventLinkTracker, CreateLinkEvent, GetRoomSession, ISelectedUser, RemoveLinkEventTracker } from '../../api';
import { Base, Button, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
import { ModToolsEvent, ModToolsOpenRoomChatlogEvent, ModToolsOpenRoomInfoEvent, ModToolsOpenUserInfoEvent } from '../../events';
import { useRoomEngineEvent, useUiEvent } from '../../hooks';
import { ISelectedUser } from './common/ISelectedUser';
import { ModToolsContextProvider } from './ModToolsContext';
import { ModToolsMessageHandler } from './ModToolsMessageHandler';
import { initialModTools, ModToolsActions, ModToolsReducer } from './reducers/ModToolsReducer';
import { useModTools, useObjectSelectedEvent, useRoomEngineEvent } from '../../hooks';
import { ModToolsChatlogView } from './views/room/ModToolsChatlogView';
import { ModToolsRoomView } from './views/room/ModToolsRoomView';
import { ModToolsTicketsView } from './views/tickets/ModToolsTicketsView';
@ -17,33 +12,31 @@ import { ModToolsUserView } from './views/user/ModToolsUserView';
export const ModToolsView: FC<{}> = props =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ currentRoomId, setCurrentRoomId ] = useState<number>(-1);
const [ selectedUser, setSelectedUser ] = useState<ISelectedUser>(null);
const [ isTicketsVisible, setIsTicketsVisible ] = useState(false);
const [ modToolsState, dispatchModToolsState ] = useReducer(ModToolsReducer, initialModTools);
const { currentRoomId = null, openRooms = null, openRoomChatlogs = null, openUserChatlogs = null, openUserInfo = null } = modToolsState;
const { openRooms = [], openRoomChatlogs = [], openUserChatlogs = [], openUserInfos = [], openRoomInfo = null, closeRoomInfo = null, toggleRoomInfo = null, openRoomChatlog = null, closeRoomChatlog = null, toggleRoomChatlog = null, openUserInfo = null, closeUserInfo = null, toggleUserInfo = null, openUserChatlog = null, closeUserChatlog = null, toggleUserChatlog = null } = useModTools();
const elementRef = useRef<HTMLDivElement>(null);
const onModToolsEvent = useCallback((event: ModToolsEvent) =>
useRoomEngineEvent<RoomEngineEvent>([
RoomEngineEvent.INITIALIZED,
RoomEngineEvent.DISPOSED
], event =>
{
if(RoomId.isRoomPreviewerId(event.roomId)) return;
switch(event.type)
{
case ModToolsEvent.SHOW_MOD_TOOLS:
setIsVisible(true);
case RoomEngineEvent.INITIALIZED:
setCurrentRoomId(event.roomId);
return;
case ModToolsEvent.HIDE_MOD_TOOLS:
setIsVisible(false);
return;
case ModToolsEvent.TOGGLE_MOD_TOOLS:
setIsVisible(value => !value);
case RoomEngineEvent.DISPOSED:
setCurrentRoomId(-1);
return;
}
}, []);
});
useUiEvent(ModToolsEvent.SHOW_MOD_TOOLS, onModToolsEvent);
useUiEvent(ModToolsEvent.HIDE_MOD_TOOLS, onModToolsEvent);
useUiEvent(ModToolsEvent.TOGGLE_MOD_TOOLS, onModToolsEvent);
const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) =>
useObjectSelectedEvent(event =>
{
if(event.category !== RoomObjectCategory.UNIT) return;
@ -51,178 +44,104 @@ export const ModToolsView: FC<{}> = props =>
if(!roomSession) return;
const userData = roomSession.userDataManager.getUserDataByIndex(event.objectId);
const userData = roomSession.userDataManager.getUserDataByIndex(event.id);
if(!userData || userData.type !== RoomObjectType.USER) return;
setSelectedUser({ userId: userData.webID, username: userData.name });
}, []);
useRoomEngineEvent(RoomEngineObjectEvent.SELECTED, onRoomEngineObjectEvent);
});
const handleClick = useCallback((action: string, value?: string) =>
useEffect(() =>
{
if(!action) return;
switch(action)
{
case 'toggle_room': {
if(!openRooms)
const linkTracker: ILinkEventTracker = {
linkReceived: (url: string) =>
{
const parts = url.split('/');
if(parts.length < 2) return;
switch(parts[1])
{
DispatchUiEvent(new ModToolsOpenRoomInfoEvent(currentRoomId));
return;
case 'show':
setIsVisible(true);
return;
case 'hide':
setIsVisible(false);
return;
case 'toggle':
setIsVisible(prevValue => !prevValue);
return;
case 'open-room-info':
openRoomInfo(Number(parts[2]));
return;
case 'close-room-info':
closeRoomInfo(Number(parts[2]));
return;
case 'toggle-room-info':
toggleRoomInfo(Number(parts[2]));
return;
case 'open-room-chatlog':
openRoomChatlog(Number(parts[2]));
return;
case 'close-room-chatlog':
closeRoomChatlog(Number(parts[2]));
return;
case 'toggle-room-chatlog':
toggleRoomChatlog(Number(parts[2]));
return;
case 'open-user-info':
openUserInfo(Number(parts[2]));
return;
case 'close-user-info':
closeUserInfo(Number(parts[2]));
return;
case 'toggle-user-info':
toggleUserInfo(Number(parts[2]));
return;
case 'open-user-chatlog':
openUserChatlog(Number(parts[2]));
return;
case 'close-user-chatlog':
closeUserChatlog(Number(parts[2]));
return;
case 'toggle-user-chatlog':
toggleUserChatlog(Number(parts[2]));
return;
}
},
eventUrlPrefix: 'mod-tools/'
};
if(openRooms.indexOf(currentRoomId) > -1)
{
handleClick('close_room', currentRoomId.toString());
}
else
{
DispatchUiEvent(new ModToolsOpenRoomInfoEvent(currentRoomId));
}
return;
}
case 'close_room': {
const itemIndex = openRooms.indexOf(Number(value));
AddEventLinkTracker(linkTracker);
const clone = Array.from(openRooms);
clone.splice(itemIndex, 1);
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_ROOMS,
payload: {
openRooms: clone
}
});
return;
}
case 'toggle_room_chatlog': {
if(!openRoomChatlogs)
{
DispatchUiEvent(new ModToolsOpenRoomChatlogEvent(currentRoomId));
return;
}
if(openRoomChatlogs.indexOf(currentRoomId) > -1)
{
handleClick('close_room_chatlog', currentRoomId.toString());
}
else
{
DispatchUiEvent(new ModToolsOpenRoomChatlogEvent(currentRoomId));
}
return;
}
case 'close_room_chatlog': {
const itemIndex = openRoomChatlogs.indexOf(Number(value));
const clone = Array.from(openRoomChatlogs);
clone.splice(itemIndex, 1);
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_ROOM_CHATLOGS,
payload: {
openRoomChatlogs: clone
}
});
return;
}
case 'toggle_user_info': {
if(!selectedUser) return;
const userId = selectedUser.userId;
if(!openUserInfo)
{
DispatchUiEvent(new ModToolsOpenUserInfoEvent(userId));
return;
}
if(openUserInfo.indexOf(userId) > -1)
{
handleClick('close_user_info', userId.toString());
}
else
{
DispatchUiEvent(new ModToolsOpenUserInfoEvent(userId));
}
return;
}
case 'close_user_info': {
const itemIndex = openUserInfo.indexOf(Number(value));
const clone = Array.from(openUserInfo);
clone.splice(itemIndex, 1);
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_USERINFO,
payload: {
openUserInfo: clone
}
});
return;
}
case 'close_user_chatlog': {
const itemIndex = openUserChatlogs.indexOf(Number(value));
const clone = Array.from(openUserChatlogs);
clone.splice(itemIndex, 1);
dispatchModToolsState({
type: ModToolsActions.SET_OPEN_USER_CHATLOGS,
payload: {
openUserChatlogs: clone
}
});
return;
}
}
}, [ openRooms, currentRoomId, openRoomChatlogs, selectedUser, openUserInfo, openUserChatlogs ]);
return () => RemoveLinkEventTracker(linkTracker);
}, [ openRoomInfo, closeRoomInfo, toggleRoomInfo, openRoomChatlog, closeRoomChatlog, toggleRoomChatlog, openUserInfo, closeUserInfo, toggleUserInfo, openUserChatlog, closeUserChatlog, toggleUserChatlog ]);
return (
<ModToolsContextProvider value={ { modToolsState, dispatchModToolsState } }>
<ModToolsMessageHandler />
<>
{ isVisible &&
<NitroCardView uniqueKey="mod-tools" className="nitro-mod-tools" windowPosition={ DraggableWindowPosition.TOP_LEFT } theme="primary-slim" >
<NitroCardHeaderView headerText={ 'Mod Tools' } onCloseClick={ event => setIsVisible(false) } />
<NitroCardContentView className="text-black" gap={ 1 }>
<Button gap={ 1 } onClick={ event => handleClick('toggle_room') } disabled={ !currentRoomId } className="position-relative">
<Button gap={ 1 } onClick={ event => CreateLinkEvent(`mod-tools/toggle-room-info/${ currentRoomId }`) } disabled={ (currentRoomId <= 0) } className="position-relative">
<Base className="icon icon-small-room position-absolute start-1"/> Room Tool
</Button>
<Button innerRef={ elementRef } gap={ 1 } onClick={ event => handleClick('toggle_room_chatlog') } disabled={ !currentRoomId } className="position-relative">
<Button innerRef={ elementRef } gap={ 1 } onClick={ event => CreateLinkEvent(`mod-tools/toggle-room-chatlog/${ currentRoomId }`) } disabled={ (currentRoomId <= 0) } className="position-relative">
<Base className="icon icon-chat-history position-absolute start-1"/> Chatlog Tool
</Button>
<Button gap={ 1 } onClick={ () => handleClick('toggle_user_info') } disabled={ !selectedUser } className="position-relative">
<Button gap={ 1 } onClick={ () => CreateLinkEvent(`mod-tools/toggle-user-info/${ selectedUser.userId }`) } disabled={ !selectedUser } className="position-relative">
<Base className="icon icon-user position-absolute start-1"/> User: { selectedUser ? selectedUser.username : '' }
</Button>
<Button gap={ 1 } onClick={ () => setIsTicketsVisible(value => !value) } className="position-relative">
<Button gap={ 1 } onClick={ () => setIsTicketsVisible(prevValue => !prevValue) } className="position-relative">
<Base className="icon icon-tickets position-absolute start-1"/> Report Tool
</Button>
</NitroCardContentView>
</NitroCardView> }
{ openRooms && openRooms.map(roomId =>
{
return <ModToolsRoomView key={ roomId } roomId={ roomId } onCloseClick={ () => handleClick('close_room', roomId.toString()) } />;
})
}
{ openRoomChatlogs && openRoomChatlogs.map(roomId =>
{
return <ModToolsChatlogView key={ roomId } roomId={ roomId } onCloseClick={ () => handleClick('close_room_chatlog', roomId.toString()) } />;
})
}
{ openUserInfo && openUserInfo.map(userId =>
{
return <ModToolsUserView key={ userId } userId={ userId } onCloseClick={ () => handleClick('close_user_info', userId.toString()) }/>
})
}
{ openUserChatlogs && openUserChatlogs.map(userId =>
{
return <ModToolsUserChatlogView key={ userId } userId={ userId } onCloseClick={ () => handleClick('close_user_chatlog', userId.toString()) }/>
})
}
{ (openRooms.length > 0) && openRooms.map(roomId => <ModToolsRoomView key={ roomId } roomId={ roomId } onCloseClick={ () => CreateLinkEvent(`mod-tools/close-room-info/${ roomId }`) } />) }
{ (openRoomChatlogs.length > 0) && openRoomChatlogs.map(roomId => <ModToolsChatlogView key={ roomId } roomId={ roomId } onCloseClick={ () => CreateLinkEvent(`mod-tools/close-room-chatlog/${ roomId }`) } />) }
{ (openUserInfos.length > 0) && openUserInfos.map(userId => <ModToolsUserView key={ userId } userId={ userId } onCloseClick={ () => CreateLinkEvent(`mod-tools/close-user-info/${ userId }`) }/>) }
{ (openUserChatlogs.length > 0) && openUserChatlogs.map(userId => <ModToolsUserChatlogView key={ userId } userId={ userId } onCloseClick={ () => CreateLinkEvent(`mod-tools/close-user-chatlog/${ userId }`) }/>) }
{ isTicketsVisible && <ModToolsTicketsView onCloseClick={ () => setIsTicketsVisible(false) } /> }
</ModToolsContextProvider>
</>
);
}

View File

@ -1,7 +0,0 @@
import { CallForHelpCategoryData } from '@nitrots/nitro-renderer';
let cfhCategories: CallForHelpCategoryData[] = [];
export const SetCfhCategories = (categories: CallForHelpCategoryData[]) => (cfhCategories = categories);
export const GetCfhCategories = () => cfhCategories;

View File

@ -1,49 +0,0 @@
export class ModActionDefinition
{
public static ALERT:number = 1;
public static MUTE:number = 2;
public static BAN:number = 3;
public static KICK:number = 4;
public static TRADE_LOCK:number = 5;
public static MESSAGE:number = 6;
private readonly _actionId:number;
private readonly _name:string;
private readonly _actionType:number;
private readonly _sanctionTypeId:number;
private readonly _actionLengthHours:number;
constructor(actionId:number, actionName:string, actionType:number, sanctionTypeId:number, actionLengthHours:number)
{
this._actionId = actionId;
this._name = actionName;
this._actionType = actionType;
this._sanctionTypeId = sanctionTypeId;
this._actionLengthHours = actionLengthHours;
}
public get actionId():number
{
return this._actionId;
}
public get name():string
{
return this._name;
}
public get actionType():number
{
return this._actionType;
}
public get sanctionTypeId():number
{
return this._sanctionTypeId;
}
public get actionLengthHours():number
{
return this._actionLengthHours;
}
}

View File

@ -1,105 +0,0 @@
import { CallForHelpCategoryData, IssueMessageData, ModeratorInitData } from '@nitrots/nitro-renderer';
import { Reducer } from 'react';
export interface IModToolsState
{
settings: ModeratorInitData;
currentRoomId: number;
openRooms: number[];
openRoomChatlogs: number[];
openUserInfo: number[];
openUserChatlogs: number[];
tickets: IssueMessageData[]
cfhCategories: CallForHelpCategoryData[];
}
export interface IModToolsAction
{
type: string;
payload: {
settings?: ModeratorInitData;
currentRoomId?: number;
openRooms?: number[];
openRoomChatlogs?: number[];
openUserInfo?: number[];
openUserChatlogs?: number[];
tickets?: IssueMessageData[];
cfhCategories?: CallForHelpCategoryData[];
}
}
export class ModToolsActions
{
public static SET_INIT_DATA: string = 'MTA_SET_INIT_DATA';
public static SET_CURRENT_ROOM_ID: string = 'MTA_SET_CURRENT_ROOM_ID';
public static SET_OPEN_ROOMS: string = 'MTA_SET_OPEN_ROOMS';
public static SET_OPEN_USERINFO: string = 'MTA_SET_OPEN_USERINFO';
public static SET_OPEN_ROOM_CHATLOGS: string = 'MTA_SET_OPEN_CHATLOGS';
public static SET_OPEN_USER_CHATLOGS: string = 'MTA_SET_OPEN_USER_CHATLOGS';
public static SET_TICKETS: string = 'MTA_SET_TICKETS';
public static SET_CFH_CATEGORIES: string = 'MTA_SET_CFH_CATEGORIES';
public static RESET_STATE: string = 'MTA_RESET_STATE';
}
export const initialModTools: IModToolsState = {
settings: null,
currentRoomId: null,
openRooms: null,
openRoomChatlogs: null,
openUserChatlogs: null,
openUserInfo: null,
tickets: null,
cfhCategories: null
};
export const ModToolsReducer: Reducer<IModToolsState, IModToolsAction> = (state, action) =>
{
switch(action.type)
{
case ModToolsActions.SET_INIT_DATA: {
const settings = (action.payload.settings || state.settings || null);
return { ...state, settings };
}
case ModToolsActions.SET_CURRENT_ROOM_ID: {
const currentRoomId = (action.payload.currentRoomId || state.currentRoomId || null);
return { ...state, currentRoomId };
}
case ModToolsActions.SET_OPEN_ROOMS: {
const openRooms = (action.payload.openRooms || state.openRooms || null);
return { ...state, openRooms };
}
case ModToolsActions.SET_OPEN_USERINFO: {
const openUserInfo = (action.payload.openUserInfo || state.openUserInfo || null);
return { ...state, openUserInfo };
}
case ModToolsActions.SET_OPEN_ROOM_CHATLOGS: {
const openRoomChatlogs = (action.payload.openRoomChatlogs || state.openRoomChatlogs || null);
return { ...state, openRoomChatlogs };
}
case ModToolsActions.SET_OPEN_USER_CHATLOGS: {
const openUserChatlogs = (action.payload.openUserChatlogs || state.openUserChatlogs || null);
return { ...state, openUserChatlogs };
}
case ModToolsActions.SET_TICKETS: {
const tickets = (action.payload.tickets || state.tickets || null);
return { ...state, tickets };
}
case ModToolsActions.SET_CFH_CATEGORIES: {
const cfhCategories = (action.payload.cfhCategories || state.cfhCategories || null);
return { ...state, cfhCategories };
}
case ModToolsActions.RESET_STATE: {
return { ...initialModTools };
}
default:
return state;
}
}

View File

@ -1,10 +1,9 @@
import { ChatRecordData } from '@nitrots/nitro-renderer';
import { CSSProperties, FC, Key, useCallback } from 'react';
import { AutoSizer, CellMeasurer, CellMeasurerCache, List, ListRowProps } from 'react-virtualized';
import { DispatchUiEvent, TryVisitRoom } from '../../../../api';
import { CreateLinkEvent, TryVisitRoom } from '../../../../api';
import { Base, Button, Column, Flex, Grid, Text } from '../../../../common';
import { ModToolsOpenUserInfoEvent } from '../../../../events';
import { ModToolsOpenRoomInfoEvent } from '../../../../events/mod-tools/ModToolsOpenRoomInfoEvent';
import { useModTools } from '../../../../hooks';
interface ChatlogViewProps
{
@ -14,6 +13,7 @@ interface ChatlogViewProps
export const ChatlogView: FC<ChatlogViewProps> = props =>
{
const { records = null } = props;
const { openRoomInfo = null } = useModTools();
const rowRenderer = (props: ListRowProps) =>
{
@ -29,7 +29,7 @@ export const ChatlogView: FC<ChatlogViewProps> = props =>
>
<Grid key={ props.key } fullHeight={ false } style={ props.style } gap={ 1 } alignItems="center" className="log-entry py-1 border-bottom">
<Text className="g-col-2">{ chatlogEntry.timestamp }</Text>
<Text className="g-col-3" bold underline pointer onClick={ event => DispatchUiEvent(new ModToolsOpenUserInfoEvent(chatlogEntry.userId)) }>{ chatlogEntry.userName }</Text>
<Text className="g-col-3" bold underline pointer onClick={ event => CreateLinkEvent(`mod-tools/open-user-info/${ chatlogEntry.userId }`) }>{ chatlogEntry.userName }</Text>
<Text textBreak wrap className="g-col-7">{ chatlogEntry.message }</Text>
</Grid>
</CellMeasurer>
@ -79,7 +79,7 @@ export const ChatlogView: FC<ChatlogViewProps> = props =>
{ !isRoomInfo &&
<Grid key={ props.key } fullHeight={ false } style={ props.style } gap={ 1 } alignItems="center" className="log-entry py-1 border-bottom">
<Text className="g-col-2">{ chatlogEntry.timestamp }</Text>
<Text className="g-col-3" bold underline pointer onClick={ event => DispatchUiEvent(new ModToolsOpenUserInfoEvent(chatlogEntry.userId)) }>{ chatlogEntry.userName }</Text>
<Text className="g-col-3" bold underline pointer onClick={ event => CreateLinkEvent(`mod-tools/open-user-info/${ chatlogEntry.userId }`) }>{ chatlogEntry.userName }</Text>
<Text textBreak wrap className="g-col-7">{ chatlogEntry.message }</Text>
</Grid> }
</CellMeasurer>
@ -109,7 +109,7 @@ export const ChatlogView: FC<ChatlogViewProps> = props =>
</Flex>
<Flex gap={ 1 }>
<Button onClick={ event => TryVisitRoom(props.roomId) }>Visit Room</Button>
<Button onClick={ event => DispatchUiEvent(new ModToolsOpenRoomInfoEvent(props.roomId)) }>Room Tools</Button>
<Button onClick={ event => openRoomInfo(props.roomId) }>Room Tools</Button>
</Flex>
</Flex>
);

View File

@ -1,5 +1,5 @@
import { ChatRecordData, GetRoomChatlogMessageComposer, RoomChatlogEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { SendMessageComposer } from '../../../../api';
import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { useMessageEvent } from '../../../../hooks';
@ -16,16 +16,14 @@ export const ModToolsChatlogView: FC<ModToolsChatlogViewProps> = props =>
const { roomId = null, onCloseClick = null } = props;
const [ roomChatlog, setRoomChatlog ] = useState<ChatRecordData>(null);
const onModtoolRoomChatlogEvent = useCallback((event: RoomChatlogEvent) =>
useMessageEvent<RoomChatlogEvent>(RoomChatlogEvent, event =>
{
const parser = event.getParser();
if(!parser || parser.data.roomId !== roomId) return;
setRoomChatlog(parser.data);
}, [ roomId ]);
useMessageEvent(RoomChatlogEvent, onModtoolRoomChatlogEvent);
});
useEffect(() =>
{

View File

@ -1,8 +1,7 @@
import { GetModeratorRoomInfoMessageComposer, ModerateRoomMessageComposer, ModeratorActionMessageComposer, ModeratorRoomInfoEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { DispatchUiEvent, SendMessageComposer, TryVisitRoom } from '../../../../api';
import { FC, useEffect, useState } from 'react';
import { CreateLinkEvent, SendMessageComposer, TryVisitRoom } from '../../../../api';
import { Button, Column, DraggableWindowPosition, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { ModToolsOpenRoomChatlogEvent } from '../../../../events/mod-tools/ModToolsOpenRoomChatlogEvent';
import { useMessageEvent } from '../../../../hooks';
interface ModToolsRoomViewProps
@ -14,39 +13,19 @@ interface ModToolsRoomViewProps
export const ModToolsRoomView: FC<ModToolsRoomViewProps> = props =>
{
const { roomId = null, onCloseClick = null } = props;
const [ infoRequested, setInfoRequested ] = useState(false);
const [ loadedRoomId, setLoadedRoomId ] = useState(null);
const [ name, setName ] = useState(null);
const [ ownerId, setOwnerId ] = useState(null);
const [ ownerName, setOwnerName ] = useState(null);
const [ ownerInRoom, setOwnerInRoom ] = useState(false);
const [ usersInRoom, setUsersInRoom ] = useState(0);
//form data
const [ kickUsers, setKickUsers ] = useState(false);
const [ lockRoom, setLockRoom ] = useState(false);
const [ changeRoomName, setChangeRoomName ] = useState(false);
const [ message, setMessage ] = useState('');
const onModtoolRoomInfoEvent = useCallback((event: ModeratorRoomInfoEvent) =>
{
const parser = event.getParser();
if(!parser || parser.data.flatId !== roomId) return;
setLoadedRoomId(parser.data.flatId);
setName(parser.data.room.name);
setOwnerId(parser.data.ownerId);
setOwnerName(parser.data.ownerName);
setOwnerInRoom(parser.data.ownerInRoom);
setUsersInRoom(parser.data.userCount);
}, [ roomId ]);
useMessageEvent(ModeratorRoomInfoEvent, onModtoolRoomInfoEvent);
const handleClick = useCallback((action: string, value?: string) =>
const handleClick = (action: string, value?: string) =>
{
if(!action) return;
@ -65,7 +44,21 @@ export const ModToolsRoomView: FC<ModToolsRoomViewProps> = props =>
SendMessageComposer(new ModerateRoomMessageComposer(roomId, lockRoom ? 1 : 0, changeRoomName ? 1 : 0, kickUsers ? 1 : 0));
return;
}
}, [ changeRoomName, kickUsers, lockRoom, message, roomId ]);
}
useMessageEvent<ModeratorRoomInfoEvent>(ModeratorRoomInfoEvent, event =>
{
const parser = event.getParser();
if(!parser || parser.data.flatId !== roomId) return;
setLoadedRoomId(parser.data.flatId);
setName(parser.data.room.name);
setOwnerId(parser.data.ownerId);
setOwnerName(parser.data.ownerName);
setOwnerInRoom(parser.data.ownerInRoom);
setUsersInRoom(parser.data.userCount);
});
useEffect(() =>
{
@ -96,7 +89,7 @@ export const ModToolsRoomView: FC<ModToolsRoomViewProps> = props =>
</Column>
<Column gap={ 1 }>
<Button onClick={ event => TryVisitRoom(roomId) }>Visit Room</Button>
<Button onClick={ event => DispatchUiEvent(new ModToolsOpenRoomChatlogEvent(roomId)) }>Chatlog</Button>
<Button onClick={ event => CreateLinkEvent(`mod-tools/open-room-chatlog/${ roomId }`) }>Chatlog</Button>
</Column>
</Flex>
<Column className="bg-muted rounded p-2" gap={ 1 }>

View File

@ -1,5 +1,5 @@
import { CfhChatlogData, CfhChatlogEvent, GetCfhChatlogMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { SendMessageComposer } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { useMessageEvent } from '../../../../hooks';
@ -16,22 +16,20 @@ export const CfhChatlogView: FC<CfhChatlogViewProps> = props =>
const { onCloseClick = null, issueId = null } = props;
const [ chatlogData, setChatlogData ] = useState<CfhChatlogData>(null);
useMessageEvent<CfhChatlogEvent>(CfhChatlogEvent, event =>
{
const parser = event.getParser();
if(!parser || parser.data.issueId !== issueId) return;
setChatlogData(parser.data);
});
useEffect(() =>
{
SendMessageComposer(new GetCfhChatlogMessageComposer(issueId));
}, [ issueId ]);
const onCfhChatlogEvent = useCallback((event: CfhChatlogEvent) =>
{
const parser = event.getParser();
if(!parser || parser.data.issueId !== issueId) return;
setChatlogData(parser.data);
}, [ issueId ]);
useMessageEvent(CfhChatlogEvent, onCfhChatlogEvent);
return (
<NitroCardView className="nitro-mod-tools-chatlog" theme="primary-slim">
<NitroCardHeaderView headerText={ 'Issue Chatlog' } onCloseClick={ onCloseClick } />

View File

@ -1,10 +1,8 @@
import { CloseIssuesMessageComposer, ReleaseIssuesMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useMemo, useState } from 'react';
import { DispatchUiEvent, LocalizeText, SendMessageComposer } from '../../../../api';
import { FC, useState } from 'react';
import { GetIssueCategoryName, LocalizeText, SendMessageComposer } from '../../../../api';
import { Button, Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { ModToolsOpenUserInfoEvent } from '../../../../events';
import { getSourceName } from '../../common/IssueCategoryNames';
import { useModToolsContext } from '../../ModToolsContext';
import { useModTools } from '../../../../hooks';
import { CfhChatlogView } from './CfhChatlogView';
interface IssueInfoViewProps
@ -16,16 +14,9 @@ interface IssueInfoViewProps
export const ModToolsIssueInfoView: FC<IssueInfoViewProps> = props =>
{
const { issueId = null, onIssueInfoClosed = null } = props;
const { modToolsState = null } = useModToolsContext();
const { tickets = null } = modToolsState;
const [ cfhChatlogOpen, setcfhChatlogOpen ] = useState(false);
const ticket = useMemo(() =>
{
if(!tickets || !tickets.length) return null;
return tickets.find(issue => issue.issueId === issueId);
}, [ issueId, tickets ]);
const { tickets = [], openUserInfo = null } = useModTools();
const ticket = tickets.find(issue => (issue.issueId === issueId));
const releaseIssue = (issueId: number) =>
{
@ -40,8 +31,6 @@ export const ModToolsIssueInfoView: FC<IssueInfoViewProps> = props =>
onIssueInfoClosed(issueId)
}
const openUserInfo = (userId: number) => DispatchUiEvent(new ModToolsOpenUserInfoEvent(userId));
return (
<>
@ -55,7 +44,7 @@ export const ModToolsIssueInfoView: FC<IssueInfoViewProps> = props =>
<tbody>
<tr>
<th>Source</th>
<td>{ getSourceName(ticket.categoryId) }</td>
<td>{ GetIssueCategoryName(ticket.categoryId) }</td>
</tr>
<tr>
<th>Category</th>

View File

@ -6,14 +6,12 @@ import { Base, Button, Column, Grid } from '../../../../common';
interface ModToolsMyIssuesTabViewProps
{
myIssues: IssueMessageData[];
onIssueHandleClick(issueId: number): void;
handleIssue: (issueId: number) => void;
}
export const ModToolsMyIssuesTabView: FC<ModToolsMyIssuesTabViewProps> = props =>
{
const { myIssues = null, onIssueHandleClick = null } = props;
const onReleaseIssue = (issueId: number) => SendMessageComposer(new ReleaseIssuesMessageComposer([ issueId ]));
const { myIssues = null, handleIssue = null } = props;
return (
<Column gap={ 0 } overflow="hidden">
@ -35,10 +33,10 @@ export const ModToolsMyIssuesTabView: FC<ModToolsMyIssuesTabViewProps> = props =
<Base className="g-col-3">{ issue.reportedUserName }</Base>
<Base className="g-col-3">{ new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString() }</Base>
<Base className="g-col-2">
<Button variant="primary" onClick={ event => onIssueHandleClick(issue.issueId) }>Handle</Button>
<Button variant="primary" onClick={ event => handleIssue(issue.issueId) }>Handle</Button>
</Base>
<Base className="g-col-2">
<Button variant="danger" onClick={ event => onReleaseIssue(issue.issueId) }>Release</Button>
<Button variant="danger" onClick={ event => SendMessageComposer(new ReleaseIssuesMessageComposer([ issue.issueId ])) }>Release</Button>
</Base>
</Grid>
);

View File

@ -12,8 +12,6 @@ export const ModToolsOpenIssuesTabView: FC<ModToolsOpenIssuesTabViewProps> = pro
{
const { openIssues = null } = props;
const onPickIssue = (issueId: number) => SendMessageComposer(new PickIssuesMessageComposer([ issueId ], false, 0, 'pick issue button'));
return (
<Column gap={ 0 } overflow="hidden">
<Column gap={ 2 }>
@ -33,7 +31,7 @@ export const ModToolsOpenIssuesTabView: FC<ModToolsOpenIssuesTabViewProps> = pro
<Base className="g-col-3">{ issue.reportedUserName }</Base>
<Base className="g-col-4">{ new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString() }</Base>
<Base className="g-col-3">
<Button variant="success" onClick={ event => onPickIssue(issue.issueId) }>Pick Issue</Button>
<Button variant="success" onClick={ event => SendMessageComposer(new PickIssuesMessageComposer([ issue.issueId ], false, 0, 'pick issue button')) }>Pick Issue</Button>
</Base>
</Grid>
);

View File

@ -1,8 +1,8 @@
import { IssueMessageData } from '@nitrots/nitro-renderer';
import { FC, useCallback, useMemo, useState } from 'react';
import { FC, useState } from 'react';
import { GetSessionDataManager } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../common';
import { useModToolsContext } from '../../ModToolsContext';
import { useModTools } from '../../../../hooks';
import { ModToolsIssueInfoView } from './ModToolsIssueInfoView';
import { ModToolsMyIssuesTabView } from './ModToolsMyIssuesTabView';
import { ModToolsOpenIssuesTabView } from './ModToolsOpenIssuesTabView';
@ -22,67 +22,52 @@ const TABS: string[] = [
export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
{
const { onCloseClick = null } = props;
const { modToolsState = null } = useModToolsContext();
const { tickets= null } = modToolsState;
const [ currentTab, setCurrentTab ] = useState<number>(0);
const [ issueInfoWindows, setIssueInfoWindows ] = useState<number[]>([]);
const { tickets = [] } = useModTools();
const openIssues = useMemo(() =>
const openIssues = tickets.filter(issue => issue.state === IssueMessageData.STATE_OPEN);
const myIssues = tickets.filter(issue => (issue.state === IssueMessageData.STATE_PICKED) && (issue.pickerUserId === GetSessionDataManager().userId));
const pickedIssues = tickets.filter(issue => issue.state === IssueMessageData.STATE_PICKED);
const closeIssue = (issueId: number) =>
{
if(!tickets) return [];
return tickets.filter(issue => issue.state === IssueMessageData.STATE_OPEN);
}, [ tickets ]);
const myIssues = useMemo(() =>
{
if(!tickets) return [];
return tickets.filter(issue => (issue.state === IssueMessageData.STATE_PICKED) && (issue.pickerUserId === GetSessionDataManager().userId));
}, [ tickets ]);
const pickedIssues = useMemo(() =>
{
if(!tickets) return [];
return tickets.filter(issue => issue.state === IssueMessageData.STATE_PICKED);
}, [ tickets ]);
const onIssueInfoClosed = useCallback((issueId: number) =>
{
const indexOfValue = issueInfoWindows.indexOf(issueId);
if(indexOfValue === -1) return;
const newValues = Array.from(issueInfoWindows);
newValues.splice(indexOfValue, 1);
setIssueInfoWindows(newValues);
}, [ issueInfoWindows ]);
const onIssueHandleClicked = useCallback((issueId: number) =>
{
if(issueInfoWindows.indexOf(issueId) === -1)
setIssueInfoWindows(prevValue =>
{
const newValues = Array.from(issueInfoWindows);
newValues.push(issueId);
setIssueInfoWindows(newValues);
}
else
{
onIssueInfoClosed(issueId);
}
}, [ issueInfoWindows, onIssueInfoClosed ]);
const newValue = [ ...prevValue ];
const existingIndex = newValue.indexOf(issueId);
const CurrentTabComponent = useCallback(() =>
if(existingIndex >= 0) newValue.splice(existingIndex, 1);
return newValue;
});
}
const handleIssue = (issueId: number) =>
{
setIssueInfoWindows(prevValue =>
{
const newValue = [ ...prevValue ];
const existingIndex = newValue.indexOf(issueId);
if(existingIndex === -1) newValue.push(issueId);
else newValue.splice(existingIndex, 1);
return newValue;
})
}
const CurrentTabComponent = () =>
{
switch(currentTab)
{
case 0: return <ModToolsOpenIssuesTabView openIssues={ openIssues }/>;
case 1: return <ModToolsMyIssuesTabView myIssues={ myIssues } onIssueHandleClick={ onIssueHandleClicked }/>;
case 1: return <ModToolsMyIssuesTabView myIssues={ myIssues } handleIssue={ handleIssue }/>;
case 2: return <ModToolsPickedIssuesTabView pickedIssues={ pickedIssues }/>;
default: return null;
}
}, [ currentTab, myIssues, onIssueHandleClicked, openIssues, pickedIssues ]);
return null;
}
return (
<>
@ -100,7 +85,7 @@ export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
<CurrentTabComponent />
</NitroCardContentView>
</NitroCardView>
{ issueInfoWindows && (issueInfoWindows.length > 0) && issueInfoWindows.map(issueId => <ModToolsIssueInfoView key={ issueId } issueId={ issueId } onIssueInfoClosed={ onIssueInfoClosed } />) }
{ issueInfoWindows && (issueInfoWindows.length > 0) && issueInfoWindows.map(issueId => <ModToolsIssueInfoView key={ issueId } issueId={ issueId } onIssueInfoClosed={ closeIssue } />) }
</>
);
}

View File

@ -1,5 +1,5 @@
import { ChatRecordData, GetUserChatlogMessageComposer, UserChatlogEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { SendMessageComposer } from '../../../../api';
import { DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { useMessageEvent } from '../../../../hooks';
@ -16,8 +16,8 @@ export const ModToolsUserChatlogView: FC<ModToolsUserChatlogViewProps> = props =
const { userId = null, onCloseClick = null } = props;
const [ userChatlog, setUserChatlog ] = useState<ChatRecordData[]>(null);
const [ username, setUsername ] = useState<string>(null);
const onModtoolUserChatlogEvent = useCallback((event: UserChatlogEvent) =>
useMessageEvent<UserChatlogEvent>(UserChatlogEvent, event =>
{
const parser = event.getParser();
@ -25,9 +25,7 @@ export const ModToolsUserChatlogView: FC<ModToolsUserChatlogViewProps> = props =
setUsername(parser.data.username);
setUserChatlog(parser.data.roomChatlogs);
}, [ userId ]);
useMessageEvent(UserChatlogEvent, onModtoolUserChatlogEvent);
});
useEffect(() =>
{

View File

@ -1,11 +1,8 @@
import { CallForHelpTopicData, DefaultSanctionMessageComposer, ModAlertMessageComposer, ModBanMessageComposer, ModKickMessageComposer, ModMessageMessageComposer, ModMuteMessageComposer, ModTradingLockMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useMemo, useState } from 'react';
import { LocalizeText, NotificationAlertType, SendMessageComposer } from '../../../../api';
import { ISelectedUser, LocalizeText, ModActionDefinition, NotificationAlertType, SendMessageComposer } from '../../../../api';
import { Button, Column, DraggableWindowPosition, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { useNotification } from '../../../../hooks';
import { ISelectedUser } from '../../common/ISelectedUser';
import { ModActionDefinition } from '../../common/ModActionDefinition';
import { useModToolsContext } from '../../ModToolsContext';
import { useModTools, useNotification } from '../../../../hooks';
interface ModToolsUserModActionViewProps
{
@ -34,8 +31,7 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
const [ selectedTopic, setSelectedTopic ] = useState(-1);
const [ selectedAction, setSelectedAction ] = useState(-1);
const [ message, setMessage ] = useState<string>('');
const { modToolsState = null } = useModToolsContext();
const { cfhCategories = null, settings = null } = modToolsState;
const { cfhCategories = null, settings = null } = useModTools();
const { simpleAlert = null } = useNotification();
const topics = useMemo(() =>
@ -53,19 +49,22 @@ export const ModToolsUserModActionView: FC<ModToolsUserModActionViewProps> = pro
return values;
}, [ cfhCategories ]);
const sendAlert = (message: string) =>
{
simpleAlert(message, NotificationAlertType.DEFAULT, null, null, 'Error');
}
const sendAlert = (message: string) => simpleAlert(message, NotificationAlertType.DEFAULT, null, null, 'Error');
const sendDefaultSanction = () =>
{
let errorMessage: string = null;
const category = topics[selectedTopic];
if(selectedTopic === -1) errorMessage = 'You must select a CFH topic';
if(errorMessage) return sendAlert(errorMessage);
const messageOrDefault = (message.trim().length === 0) ? LocalizeText(`help.cfh.topic.${ category.id }`) : message;
SendMessageComposer(new DefaultSanctionMessageComposer(user.userId, selectedTopic, messageOrDefault));
onCloseClick();
}

View File

@ -1,5 +1,5 @@
import { GetRoomVisitsMessageComposer, RoomVisitsData, RoomVisitsEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { FC, useEffect, useState } from 'react';
import { AutoSizer, List, ListRowProps } from 'react-virtualized';
import { SendMessageComposer, TryVisitRoom } from '../../../../api';
import { Base, Column, DraggableWindowPosition, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
@ -16,16 +16,21 @@ export const ModToolsUserRoomVisitsView: FC<ModToolsUserRoomVisitsViewProps> = p
const { userId = null, onCloseClick = null } = props;
const [ roomVisitData, setRoomVisitData ] = useState<RoomVisitsData>(null);
const onModtoolReceivedRoomsUserEvent = useCallback((event: RoomVisitsEvent) =>
useMessageEvent<RoomVisitsEvent>(RoomVisitsEvent, event =>
{
const parser = event.getParser();
if(!parser || (parser.data.userId !== userId)) return;
if(parser.data.userId !== userId) return;
setRoomVisitData(parser.data);
});
useEffect(() =>
{
SendMessageComposer(new GetRoomVisitsMessageComposer(userId));
}, [ userId ]);
useMessageEvent(RoomVisitsEvent, onModtoolReceivedRoomsUserEvent);
if(!userId) return null;
const RowRenderer = (props: ListRowProps) =>
{
@ -40,13 +45,6 @@ export const ModToolsUserRoomVisitsView: FC<ModToolsUserRoomVisitsViewProps> = p
);
}
useEffect(() =>
{
SendMessageComposer(new GetRoomVisitsMessageComposer(userId));
}, [ userId ]);
if(!userId) return null;
return (
<NitroCardView className="nitro-mod-tools-user-visits" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }>
<NitroCardHeaderView headerText={ 'User Visits' } onCloseClick={ onCloseClick } />

View File

@ -1,9 +1,8 @@
import { ModMessageMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { SendMessageComposer } from '../../../../api';
import { FC, useState } from 'react';
import { ISelectedUser, SendMessageComposer } from '../../../../api';
import { Button, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { useNotification } from '../../../../hooks';
import { ISelectedUser } from '../../common/ISelectedUser';
interface ModToolsUserSendMessageViewProps
{
@ -17,7 +16,9 @@ export const ModToolsUserSendMessageView: FC<ModToolsUserSendMessageViewProps> =
const [ message, setMessage ] = useState('');
const { simpleAlert = null } = useNotification();
const sendMessage = useCallback(() =>
if(!user) return null;
const sendMessage = () =>
{
if(message.trim().length === 0)
{
@ -29,9 +30,7 @@ export const ModToolsUserSendMessageView: FC<ModToolsUserSendMessageViewProps> =
SendMessageComposer(new ModMessageMessageComposer(user.userId, message, -999));
onCloseClick();
}, [ message, user, onCloseClick, simpleAlert ]);
if(!user) return null;
}
return (
<NitroCardView className="nitro-mod-tools-user-message" theme="primary-slim" windowPosition={ DraggableWindowPosition.TOP_LEFT }>

View File

@ -1,8 +1,7 @@
import { FriendlyTime, GetModeratorUserInfoMessageComposer, ModeratorUserInfoData, ModeratorUserInfoEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { DispatchUiEvent, LocalizeText, SendMessageComposer } from '../../../../api';
import { FC, useEffect, useMemo, useState } from 'react';
import { CreateLinkEvent, LocalizeText, SendMessageComposer } from '../../../../api';
import { Button, Column, DraggableWindowPosition, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
import { ModToolsOpenUserChatlogEvent } from '../../../../events';
import { useMessageEvent } from '../../../../hooks';
import { ModToolsUserModActionView } from './ModToolsUserModActionView';
import { ModToolsUserRoomVisitsView } from './ModToolsUserRoomVisitsView';
@ -22,17 +21,6 @@ export const ModToolsUserView: FC<ModToolsUserViewProps> = props =>
const [ modActionVisible, setModActionVisible ] = useState(false);
const [ roomVisitsVisible, setRoomVisitsVisible ] = useState(false);
const onModtoolUserInfoEvent = useCallback((event: ModeratorUserInfoEvent) =>
{
const parser = event.getParser();
if(!parser || parser.data.userId !== userId) return;
setUserInfo(parser.data);
}, [ userId ]);
useMessageEvent(ModeratorUserInfoEvent, onModtoolUserInfoEvent);
const userProperties = useMemo(() =>
{
if(!userInfo) return null;
@ -98,6 +86,15 @@ export const ModToolsUserView: FC<ModToolsUserViewProps> = props =>
];
}, [ userInfo ]);
useMessageEvent<ModeratorUserInfoEvent>(ModeratorUserInfoEvent, event =>
{
const parser = event.getParser();
if(!parser || parser.data.userId !== userId) return;
setUserInfo(parser.data);
});
useEffect(() =>
{
SendMessageComposer(new GetModeratorUserInfoMessageComposer(userId));
@ -132,7 +129,7 @@ export const ModToolsUserView: FC<ModToolsUserViewProps> = props =>
</table>
</Column>
<Column size={ 4 } gap={ 1 }>
<Button onClick={ event => DispatchUiEvent(new ModToolsOpenUserChatlogEvent(userId)) }>
<Button onClick={ event => CreateLinkEvent(`mod-tools/open-user-chatlog/${ userId }`) }>
Room Chat
</Button>
<Button onClick={ event => setSendMessageVisible(!sendMessageVisible) }>

View File

@ -1,8 +1,7 @@
import { Dispose, DropBounce, EaseOut, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, Wait } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { CreateLinkEvent, DispatchUiEvent, GetSessionDataManager, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api';
import { CreateLinkEvent, GetSessionDataManager, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api';
import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common';
import { ModToolsEvent } from '../../events';
import { useAchievements, useFriends, useInventoryUnseenTracker, useMessageEvent, useMessenger, useRoomEngineEvent, useSessionInfo } from '../../hooks';
import { ToolbarMeView } from './ToolbarMeView';
@ -95,7 +94,7 @@ export const ToolbarView: FC<{ isInRoom: boolean }> = props =>
{ isInRoom &&
<Base pointer className="navigation-item icon icon-camera" onClick={ event => CreateLinkEvent('camera/toggle') } /> }
{ isMod &&
<Base pointer className="navigation-item icon icon-modtools" onClick={ event => DispatchUiEvent(new ModToolsEvent(ModToolsEvent.TOGGLE_MOD_TOOLS)) } /> }
<Base pointer className="navigation-item icon icon-modtools" onClick={ event => CreateLinkEvent('mod-tools/toggle') } /> }
</Flex>
<Flex alignItems="center" id="toolbar-chat-input-container" />
</Flex>

View File

@ -2,7 +2,6 @@ export * from './catalog';
export * from './guide-tool';
export * from './help';
export * from './inventory';
export * from './mod-tools';
export * from './room-widgets';
export * from './room-widgets/thumbnail';
export * from './wired';

View File

@ -1,12 +0,0 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
export class ModToolsEvent extends NitroEvent
{
public static SHOW_MOD_TOOLS: string = 'MTE_SHOW_MOD_TOOLS';
public static HIDE_MOD_TOOLS: string = 'MTE_HIDE_MOD_TOOLS';
public static TOGGLE_MOD_TOOLS: string = 'MTE_TOGGLE_MOD_TOOLS';
public static OPEN_ROOM_INFO: string = 'MTE_OPEN_ROOM_INFO';
public static OPEN_ROOM_CHATLOG: string = 'MTE_OPEN_ROOM_CHATLOG';
public static OPEN_USER_INFO: string = 'MTE_OPEN_USER_INFO';
public static OPEN_USER_CHATLOG: string = 'MTE_OPEN_USER_CHATLOG';
}

View File

@ -1,18 +0,0 @@
import { ModToolsEvent } from './ModToolsEvent';
export class ModToolsOpenRoomChatlogEvent extends ModToolsEvent
{
private _roomId: number;
constructor(roomId: number)
{
super(ModToolsEvent.OPEN_ROOM_CHATLOG);
this._roomId = roomId;
}
public get roomId(): number
{
return this._roomId;
}
}

View File

@ -1,18 +0,0 @@
import { ModToolsEvent } from './ModToolsEvent';
export class ModToolsOpenRoomInfoEvent extends ModToolsEvent
{
private _roomId: number;
constructor(roomId: number)
{
super(ModToolsEvent.OPEN_ROOM_INFO);
this._roomId = roomId;
}
public get roomId(): number
{
return this._roomId;
}
}

View File

@ -1,18 +0,0 @@
import { ModToolsEvent } from './ModToolsEvent';
export class ModToolsOpenUserChatlogEvent extends ModToolsEvent
{
private _userId: number;
constructor(userId: number)
{
super(ModToolsEvent.OPEN_USER_CHATLOG);
this._userId = userId;
}
public get userId(): number
{
return this._userId;
}
}

View File

@ -1,18 +0,0 @@
import { ModToolsEvent } from './ModToolsEvent';
export class ModToolsOpenUserInfoEvent extends ModToolsEvent
{
private _userId: number;
constructor(userId: number)
{
super(ModToolsEvent.OPEN_USER_INFO);
this._userId = userId;
}
public get userId(): number
{
return this._userId;
}
}

View File

@ -1,5 +0,0 @@
export * from './ModToolsEvent';
export * from './ModToolsOpenRoomChatlogEvent';
export * from './ModToolsOpenRoomInfoEvent';
export * from './ModToolsOpenUserChatlogEvent';
export * from './ModToolsOpenUserInfoEvent';

View File

@ -9,6 +9,7 @@ export * from './friends';
export * from './groups';
export * from './help';
export * from './inventory';
export * from './mod-tools';
export * from './navigator';
export * from './notification';
export * from './purse';

View File

@ -0,0 +1 @@
export * from './useModTools';

View File

@ -0,0 +1,207 @@
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);
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);
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);
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);
return newValue;
});
}
const toggleUserChatlog = (userId: number) =>
{
if(openRoomChatlogs.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);