finish room and user chatlogs

This commit is contained in:
dank074 2021-10-19 16:32:22 -05:00
parent a9043bf21e
commit dca22b58c3
21 changed files with 505 additions and 148 deletions

View File

@ -5,6 +5,8 @@ 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 SELECT_USER: string = 'MTE_SELECT_USER';
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

@ -0,0 +1,18 @@
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

@ -0,0 +1,18 @@
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

@ -0,0 +1,18 @@
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,25 +0,0 @@
import { ModToolsEvent } from './ModToolsEvent';
export class ModToolsSelectUserEvent extends ModToolsEvent
{
private _webID: number;
private _name: string;
constructor(webID: number, name: string)
{
super(ModToolsEvent.SELECT_USER);
this._webID = webID;
this._name = name;
}
public get webID(): number
{
return this._webID;
}
public get name(): string
{
return this._name;
}
}

View File

@ -2,6 +2,6 @@
width: 200px;
}
@import './views/room-chatlog/ModToolsChatlogView';
@import './views/room/ModToolsRoomView';
@import './views/chatlog/ChatlogView';
@import './views/user/ModToolsUserView';

View File

@ -1,29 +1,31 @@
import { RoomEngineEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
import { RoomEngineEvent, RoomEngineObjectEvent, RoomObjectCategory } from '@nitrots/nitro-renderer';
import { FC, useCallback, useReducer, useState } from 'react';
import { GetRoomSession } from '../../api';
import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent';
import { ModToolsOpenRoomChatlogEvent } from '../../events/mod-tools/ModToolsOpenRoomChatlogEvent';
import { ModToolsOpenRoomInfoEvent } from '../../events/mod-tools/ModToolsOpenRoomInfoEvent';
import { ModToolsSelectUserEvent } from '../../events/mod-tools/ModToolsSelectUserEvent';
import { ModToolsOpenUserChatlogEvent } from '../../events/mod-tools/ModToolsOpenUserChatlogEvent';
import { ModToolsOpenUserInfoEvent } from '../../events/mod-tools/ModToolsOpenUserInfoEvent';
import { useRoomEngineEvent } from '../../hooks/events';
import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
import { ModToolsContextProvider } from './context/ModToolsContext';
import { ModToolsViewProps } from './ModToolsView.types';
import { initialModTools, ModToolsActions, ModToolsReducer } from './reducers/ModToolsReducer';
import { ISelectedUser } from './utils/ISelectedUser';
import { ModToolsChatlogView } from './views/room-chatlog/ModToolsChatlogView';
import { ModToolsRoomView } from './views/room/ModToolsRoomView';
import { ModToolsTicketsView } from './views/tickets/ModToolsTicketsView';
import { ModToolsUserChatlogView } from './views/user-chatlog/ModToolsUserChatlogView';
import { ModToolsUserView } from './views/user/ModToolsUserView';
export const ModToolsView: FC<ModToolsViewProps> = props =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ modToolsState, dispatchModToolsState ] = useReducer(ModToolsReducer, initialModTools);
const { currentRoomId = null, selectedUser = null, openRooms = null, openChatlogs = null } = modToolsState;
const [ isRoomVisible, setIsRoomVisible ] = useState(false);
const [ isUserVisible, setIsUserVisible ] = useState(false);
const { currentRoomId = null, openRooms = null, openRoomChatlogs = null, openUserChatlogs = null, openUserInfo = null } = modToolsState;
const [ selectedUser, setSelectedUser] = useState<ISelectedUser>(null);
const [ isTicketsVisible, setIsTicketsVisible ] = useState(false);
const [ isChatlogVisible, setChatlogVisible ] = useState(false);
const onModToolsEvent = useCallback((event: ModToolsEvent) =>
{
@ -38,41 +40,76 @@ export const ModToolsView: FC<ModToolsViewProps> = props =>
case ModToolsEvent.TOGGLE_MOD_TOOLS:
setIsVisible(value => !value);
return;
case ModToolsEvent.SELECT_USER: {
const castedEvent = (event as ModToolsSelectUserEvent);
dispatchModToolsState({
type: ModToolsActions.SET_SELECTED_USER,
payload: {
selectedUser: {
webID: castedEvent.webID,
name: castedEvent.name
}
}
});
return;
}
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: [...openRooms, castedEvent.roomId]
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;
}
}
}, [ dispatchModToolsState, setIsVisible, openRooms ]);
}, [openRooms, openRoomChatlogs, openUserInfo, openUserChatlogs]);
useUiEvent(ModToolsEvent.SHOW_MOD_TOOLS, onModToolsEvent);
useUiEvent(ModToolsEvent.HIDE_MOD_TOOLS, onModToolsEvent);
useUiEvent(ModToolsEvent.TOGGLE_MOD_TOOLS, onModToolsEvent);
useUiEvent(ModToolsEvent.SELECT_USER, onModToolsEvent);
useUiEvent(ModToolsEvent.OPEN_ROOM_INFO, onModToolsEvent);
useUiEvent(ModToolsEvent.OPEN_ROOM_CHATLOG, onModToolsEvent);
useUiEvent(ModToolsEvent.OPEN_USER_INFO, onModToolsEvent);
useUiEvent(ModToolsEvent.OPEN_USER_CHATLOG, onModToolsEvent);
const onRoomEngineEvent = useCallback((event: RoomEngineEvent) =>
{
@ -100,6 +137,23 @@ export const ModToolsView: FC<ModToolsViewProps> = props =>
useRoomEngineEvent(RoomEngineEvent.INITIALIZED, onRoomEngineEvent);
useRoomEngineEvent(RoomEngineEvent.DISPOSED, onRoomEngineEvent);
const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) =>
{
if(event.category !== RoomObjectCategory.UNIT) return;
const roomSession = GetRoomSession();
if(!roomSession) return;
const userData = roomSession.userDataManager.getUserDataByIndex(event.objectId);
if(!userData) return;
setSelectedUser({ userId: userData.webID, username: userData.name });
}, []);
useRoomEngineEvent(RoomEngineObjectEvent.SELECTED, onRoomEngineObjectEvent);
const handleClick = useCallback((action: string, value?: string) =>
{
if(!action) return;
@ -139,27 +193,95 @@ export const ModToolsView: FC<ModToolsViewProps> = props =>
});
return;
}
case 'close_chatlog': {
const itemIndex = openChatlogs.indexOf(Number(value));
case 'toggle_room_chatlog': {
if(!openRoomChatlogs)
{
dispatchUiEvent(new ModToolsOpenRoomChatlogEvent(currentRoomId));
return;
}
const clone = Array.from(openChatlogs);
const itemIndex = openRoomChatlogs.indexOf(currentRoomId);
if(itemIndex > -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_CHATLOGS,
type: ModToolsActions.SET_OPEN_ROOM_CHATLOGS,
payload: {
openChatlogs: clone
openRoomChatlogs: clone
}
});
return;
}
case 'toggle_user_info': {
if(!selectedUser) return;
const userId = selectedUser.userId;
if(!openUserInfo)
{
dispatchUiEvent(new ModToolsOpenUserInfoEvent(userId));
return;
}
const itemIndex = openUserInfo.indexOf(userId);
if(itemIndex > -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;
}
}
}, [ dispatchModToolsState, openRooms, openChatlogs, currentRoomId ]);
}, [openRooms, currentRoomId, openRoomChatlogs, selectedUser, openUserInfo, openUserChatlogs]);
useEffect(() =>
{
if(!isVisible) return;
}, [ isVisible ]);
if(!isVisible) return null;
return (
<ModToolsContextProvider value={ { modToolsState, dispatchModToolsState } }>
@ -168,8 +290,8 @@ export const ModToolsView: FC<ModToolsViewProps> = props =>
<NitroCardHeaderView headerText={ 'Mod Tools' } onCloseClick={ event => setIsVisible(false) } />
<NitroCardContentView className="text-black">
<button className="btn btn-primary btn-sm w-100 mb-2" onClick={ () => handleClick('toggle_room') } disabled={ !currentRoomId }><i className="fas fa-home"></i> Room Tool</button>
<button className="btn btn-primary btn-sm w-100 mb-2" onClick={ () => setChatlogVisible(value => !value) } disabled={ !currentRoomId }><i className="fas fa-comments"></i> Chatlog Tool</button>
<button className="btn btn-primary btn-sm w-100 mb-2" onClick={ () => setIsUserVisible(value => !value) } disabled={ !selectedUser }><i className="fas fa-user"></i> User: { selectedUser ? selectedUser.name : '' }</button>
<button className="btn btn-primary btn-sm w-100 mb-2" onClick={ () => handleClick('toggle_room_chatlog') } disabled={ !currentRoomId }><i className="fas fa-comments"></i> Chatlog Tool</button>
<button className="btn btn-primary btn-sm w-100 mb-2" onClick={ () => handleClick('toggle_user_info') } disabled={ !selectedUser }><i className="fas fa-user"></i> User: { selectedUser ? selectedUser.username : '' }</button>
<button className="btn btn-primary btn-sm w-100" onClick={ () => setIsTicketsVisible(value => !value) }><i className="fas fa-exclamation-circle"></i> Report Tool</button>
</NitroCardContentView>
</NitroCardView> }
@ -178,10 +300,23 @@ export const ModToolsView: FC<ModToolsViewProps> = props =>
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())}/>
})
}
{ isUserVisible && <ModToolsUserView /> }
{ isTicketsVisible && <ModToolsTicketsView onCloseClick={ () => setIsTicketsVisible(false) } /> }
{ isChatlogVisible && <ModToolsChatlogView roomId={currentRoomId} onCloseClick={ () => setChatlogVisible(false) }/>}
</ModToolsContextProvider>
);
}

View File

@ -2,48 +2,47 @@ import { Reducer } from 'react';
export interface IModToolsState
{
selectedUser: {webID: number, name: string};
currentRoomId: number;
openRooms: number[];
openChatlogs: number[];
openRoomChatlogs: number[];
openUserInfo: number[];
openUserChatlogs: number[];
}
export interface IModToolsAction
{
type: string;
payload: {
selectedUser?: {webID: number, name: string};
currentRoomId?: number;
openRooms?: number[];
openChatlogs?: number[];
openRoomChatlogs?: number[];
openUserInfo?: number[];
openUserChatlogs?: number[];
}
}
export class ModToolsActions
{
public static SET_SELECTED_USER: string = 'MTA_SET_SELECTED_USER';
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_CHATLOGS: string = 'MTA_SET_OPEN_CHATLOGS';
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 RESET_STATE: string = 'MTA_RESET_STATE';
}
export const initialModTools: IModToolsState = {
selectedUser: null,
currentRoomId: null,
openRooms: null,
openChatlogs: null
openRoomChatlogs: null,
openUserChatlogs: null,
openUserInfo: null
};
export const ModToolsReducer: Reducer<IModToolsState, IModToolsAction> = (state, action) =>
{
switch(action.type)
{
case ModToolsActions.SET_SELECTED_USER: {
const selectedUser = (action.payload.selectedUser || state.selectedUser || null);
return { ...state, selectedUser };
}
case ModToolsActions.SET_CURRENT_ROOM_ID: {
const currentRoomId = (action.payload.currentRoomId || state.currentRoomId || null);
@ -54,6 +53,21 @@ export const ModToolsReducer: Reducer<IModToolsState, IModToolsAction> = (state,
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.RESET_STATE: {
return { ...initialModTools };
}

View File

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

View File

@ -26,6 +26,10 @@
word-break: break-all;
}
}
.room-info {
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
}
}
}
}

View File

@ -1,16 +1,18 @@
import { UserProfileComposer } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { ChatRecordData, ModtoolRoomChatlogLine, UserProfileComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react';
import { AutoSizer, CellMeasurer, CellMeasurerCache, List, ListRowProps, ListRowRenderer } from 'react-virtualized';
import { SendMessageHook } from '../../../../hooks';
import { TryVisitRoom } from '../../../../api';
import { ModToolsOpenRoomInfoEvent } from '../../../../events/mod-tools/ModToolsOpenRoomInfoEvent';
import { dispatchUiEvent, SendMessageHook } from '../../../../hooks';
import { ChatlogViewProps } from './ChatlogView.types';
export const ChatlogView: FC<ChatlogViewProps> = props =>
{
const { record = null } = props;
const { records = null } = props;
const rowRenderer: ListRowRenderer = (props: ListRowProps) =>
const simpleRowRenderer: ListRowRenderer = (props: ListRowProps) =>
{
const item = record.chatlog[props.index];
const item = records[0].chatlog[props.index];
return (
<CellMeasurer
@ -29,40 +31,122 @@ export const ChatlogView: FC<ChatlogViewProps> = props =>
);
};
const advancedRowRenderer: ListRowRenderer = (props: ListRowProps) =>
{
let chatlogEntry: ModtoolRoomChatlogLine;
let currentRecord: ChatRecordData;
let isRoomInfo = false;
let totalIndex = 0;
for(let i = 0; i < records.length; i++)
{
currentRecord = records[i];
totalIndex++; // row for room info
totalIndex = totalIndex + currentRecord.chatlog.length;
if(props.index > (totalIndex - 1))
{
continue; // it is not in current one
}
if( (props.index + 1) === (totalIndex - currentRecord.chatlog.length))
{
console.log(`global: ${props.index} roomInfo ${currentRecord.roomName}`);
isRoomInfo = true;
break;
}
const index = props.index - (totalIndex - currentRecord.chatlog.length);
chatlogEntry = currentRecord.chatlog[index];
console.log(`global: ${props.index} local: ${index} value: ${chatlogEntry}`);
break;
}
return (
<CellMeasurer
cache={cache}
columnIndex={0}
key={props.key}
parent={props.parent}
rowIndex={props.index}
>
{isRoomInfo && <RoomInfo roomId={currentRecord.roomId} roomName={currentRecord.roomName} uniqueKey={props.key} style={props.style}/>}
{!isRoomInfo &&
<div key={props.key} style={props.style} className="row chatlog-entry justify-content-start">
<div className="col-auto text-center">{chatlogEntry.timestamp}</div>
<div className="col-sm-2 justify-content-start username"><span className="fw-bold cursor-pointer" onClick={() => SendMessageHook(new UserProfileComposer(chatlogEntry.userId))}>{chatlogEntry.userName}</span></div>
<div className="col justify-content-start h-100"><span className="text-break text-wrap h-100">{chatlogEntry.message}</span></div>
</div>
}
</CellMeasurer>
);
}
const getNumRowsForAdvanced = useCallback(() =>
{
let count = 0;
for(let i = 0; i < records.length; i++)
{
count++; // add room info row
count = count + records[i].chatlog.length;
}
return count;
}, [records]);
const cache = new CellMeasurerCache({
defaultHeight: 25,
fixedWidth: true
});
const RoomInfo = useCallback(({ roomId, roomName, uniqueKey, style }) =>
{
return (
<div key={uniqueKey} style={style} className="row justify-content-start gap-2 room-info">
<div className="col-7"><span className="fw-bold">Room: </span>{roomName}</div>
<button className="btn btn-sm btn-primary col-sm-auto" onClick={() => TryVisitRoom(roomId)}>Visit Room</button>
<button className="btn btn-sm btn-primary col-sm-auto" onClick={() => dispatchUiEvent(new ModToolsOpenRoomInfoEvent(roomId))}>Room Tools</button>
</div>
);
}, []);
return (
<>
{record && <div className="chatlog-messages w-100 h-100 overflow-hidden">
<div className="row align-items-start w-100">
<div className="col-auto text-center fw-bold">Time</div>
<div className="col-sm-2 username-label fw-bold">User</div>
<div className="col fw-bold">Message</div>
</div>
<div className="row w-100 h-100 chatlog">
<AutoSizer defaultWidth={400} defaultHeight={200}>
{({ height, width }) =>
{
cache.clearAll();
{
(records && records.length) &&
<>
{(records.length === 1) && <RoomInfo roomId={records[0].roomId} roomName={records[0].roomName} uniqueKey={records[0].roomId} style={{}} />}
<div className="chatlog-messages w-100 h-100 overflow-hidden">
<div className="row align-items-start w-100">
<div className="col-auto text-center fw-bold">Time</div>
<div className="col-sm-2 username-label fw-bold">User</div>
<div className="col fw-bold">Message</div>
</div>
<div className="row w-100 h-100 chatlog">
<AutoSizer defaultWidth={400} defaultHeight={200}>
{({ height, width }) =>
{
cache.clearAll();
return (
<List
width={width}
height={height}
rowCount={record.chatlog.length}
rowHeight={cache.rowHeight}
className={'chatlog-container'}
rowRenderer={rowRenderer}
deferredMeasurementCache={cache} />
)
}
}
</AutoSizer>
</div>
</div>}
return (
<List
width={width}
height={height}
rowCount={records.length > 1 ? getNumRowsForAdvanced() : records[0].chatlog.length}
rowHeight={cache.rowHeight}
className={'chatlog-container'}
rowRenderer={records.length > 1 ? advancedRowRenderer : simpleRowRenderer}
deferredMeasurementCache={cache} />
)
}
}
</AutoSizer>
</div>
</div>
</>
}
</>
);
}

View File

@ -2,5 +2,5 @@ import { ChatRecordData } from '@nitrots/nitro-renderer';
export interface ChatlogViewProps
{
record: ChatRecordData;
records: ChatRecordData[];
}

View File

@ -1,3 +0,0 @@
.nitro-mod-tools-room-chatlog {
}

View File

@ -1,6 +1,5 @@
import { ChatRecordData, ModtoolRequestRoomChatlogComposer, ModtoolRoomChatlogEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { TryVisitRoom } from '../../../../api';
import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
import { ChatlogView } from '../chatlog/ChatlogView';
@ -28,33 +27,12 @@ export const ModToolsChatlogView: FC<ModToolsChatlogViewProps> = props =>
CreateMessageHook(ModtoolRoomChatlogEvent, onModtoolRoomChatlogEvent);
const handleClick = useCallback((action: string, value?: string) =>
{
if(!action) return;
switch(action)
{
case 'close':
onCloseClick();
return;
case 'visit_room':
TryVisitRoom(roomChatlog.roomId);
return;
}
}, [onCloseClick, roomChatlog]);
return (
<NitroCardView className="nitro-mod-tools-room-chatlog" simple={true}>
<NitroCardHeaderView headerText={'Room Chatlog' + (roomChatlog ? ': ' + roomChatlog.roomName : '')} onCloseClick={event => handleClick('close')} />
<NitroCardHeaderView headerText={'Room Chatlog' + (roomChatlog ? ': ' + roomChatlog.roomName : '')} onCloseClick={() => onCloseClick()} />
<NitroCardContentView className="text-black h-100">
{roomChatlog &&
<>
<div className="w-100 d-flex justify-content-start">
<button className="btn btn-sm btn-primary me-2" onClick={event => handleClick('visit_room')}>Visit Room</button>
<button className="btn btn-sm btn-primary">Room Tools</button>
</div>
<ChatlogView record={roomChatlog} />
</>
<ChatlogView records={[roomChatlog]} />
}
</NitroCardContentView>
</NitroCardView>

View File

@ -1,3 +1,8 @@
.nitro-mod-tools-room {
width: 240px;
.username {
color: #1E7295;
text-decoration: underline;
}
}

View File

@ -1,5 +1,8 @@
import { ModtoolRequestRoomInfoComposer, ModtoolRoomInfoEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { TryVisitRoom } from '../../../../api';
import { ModToolsOpenRoomChatlogEvent } from '../../../../events/mod-tools/ModToolsOpenRoomChatlogEvent';
import { dispatchUiEvent } from '../../../../hooks';
import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
import { ModToolsRoomViewProps } from './ModToolsRoomView.types';
@ -57,15 +60,15 @@ export const ModToolsRoomView: FC<ModToolsRoomViewProps> = props =>
<NitroCardContentView className="text-black">
<div className="d-flex justify-content-between align-items-center mb-1">
<div>
<b>Room Owner:</b> <a href="#" className="fw-bold">{ ownerName }</a>
<b>Room Owner:</b> <span className="username fw-bold cursor-pointer">{ ownerName }</span>
</div>
<button className="btn btn-sm btn-primary">Visit Room</button>
<button className="btn btn-sm btn-primary" onClick={() => TryVisitRoom(roomId)}>Visit Room</button>
</div>
<div className="d-flex justify-content-between align-items-center mb-1">
<div>
<b>Users in room:</b> { usersInRoom }
</div>
<button className="btn btn-sm btn-primary">Chatlog</button>
<button className="btn btn-sm btn-primary" onClick={() => dispatchUiEvent(new ModToolsOpenRoomChatlogEvent(roomId))}>Chatlog</button>
</div>
<div className="d-flex justify-content-between align-items-center mb-2">
<div>

View File

@ -0,0 +1,41 @@
import { ChatRecordData, ModtoolRequestUserChatlogComposer, ModtoolUserChatlogEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { CreateMessageHook, SendMessageHook } from '../../../../hooks';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
import { ChatlogView } from '../chatlog/ChatlogView';
import { ModToolsUserChatlogViewProps } from './ModToolsUserChatlogView.types';
export const ModToolsUserChatlogView: FC<ModToolsUserChatlogViewProps> = props =>
{
const { userId = null, onCloseClick = null } = props;
const [userChatlog, setUserChatlog] = useState<ChatRecordData[]>(null);
const [username, setUsername] = useState<string>(null);
useEffect(() =>
{
SendMessageHook(new ModtoolRequestUserChatlogComposer(userId));
}, [userId]);
const onModtoolUserChatlogEvent = useCallback((event: ModtoolUserChatlogEvent) =>
{
const parser = event.getParser();
if(!parser) return;
setUsername(parser.username);
setUserChatlog(parser.roomVisits);
}, [setUsername, setUserChatlog]);
CreateMessageHook(ModtoolUserChatlogEvent, onModtoolUserChatlogEvent);
return (
<NitroCardView className="nitro-mod-tools-user-chatlog" simple={true}>
<NitroCardHeaderView headerText={'User Chatlog' + (username ? ': ' + username : '')} onCloseClick={() => onCloseClick()} />
<NitroCardContentView className="text-black h-100">
{userChatlog &&
<ChatlogView records={userChatlog} />
}
</NitroCardContentView>
</NitroCardView>
);
}

View File

@ -0,0 +1,5 @@
export interface ModToolsUserChatlogViewProps
{
userId: number;
onCloseClick: () => void;
}

View File

@ -0,0 +1,8 @@
.nitro-mod-tools-user {
width: 240px;
.username {
color: #1E7295;
text-decoration: underline;
}
}

View File

@ -1,14 +1,58 @@
import { FC } from 'react';
import { ModeratorUserInfoData, ModtoolRequestUserInfoComposer, ModtoolUserInfoEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { ModToolsOpenUserChatlogEvent } from '../../../../events/mod-tools/ModToolsOpenUserChatlogEvent';
import { CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../hooks';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
import { ModToolsUserViewProps } from './ModToolsUserView.types';
export const ModToolsUserView: FC<ModToolsUserViewProps> = props =>
{
return (
<NitroCardView className="nitro-mod-tools-user" simple={ true }>
<NitroCardHeaderView headerText={ 'User Info' } onCloseClick={ event => {} } />
<NitroCardContentView className="text-black">
const { onCloseClick = null, userId = null, simple = true } = props;
const [userInfo, setUserInfo] = useState<ModeratorUserInfoData>(null);
useEffect(() =>
{
SendMessageHook(new ModtoolRequestUserInfoComposer(userId));
}, [userId]);
const onModtoolUserInfoEvent = useCallback((event: ModtoolUserInfoEvent) =>
{
const parser = event.getParser();
if(!parser) return;
console.log(parser);
setUserInfo(parser.data);
}, [setUserInfo]);
CreateMessageHook(ModtoolUserInfoEvent, onModtoolUserInfoEvent);
return (
<NitroCardView className="nitro-mod-tools-user" simple={true}>
<NitroCardHeaderView headerText={'User Info: ' + (userInfo ? userInfo.userName : '')} onCloseClick={() => onCloseClick()} />
<NitroCardContentView className="text-black">
{userInfo &&
<>
{!simple &&
<div className="col-sm-3 px-0 d-flex align-items-center">
<AvatarImageView figure={userInfo.figure} direction={2} />
</div>
}
<div className="d-flex justify-content-between align-items-center mb-1">
<div>
<b>Name:</b> <span className="username fw-bold cursor-pointer">{userInfo.userName}</span>
</div>
<button className="btn btn-sm btn-primary" onClick={() => dispatchUiEvent(new ModToolsOpenUserChatlogEvent(userId))}>Chatlog</button>
</div>
<div className="d-flex justify-content-between align-items-center mb-1">
<div>
<b>CFHs:</b> {userInfo.cfhCount}
</div>
</div>
</>
}
</NitroCardContentView>
</NitroCardView>
);

View File

@ -1,2 +1,6 @@
export interface ModToolsUserViewProps
{}
{
userId: number;
onCloseClick: () => void;
simple?: boolean;
}