mirror of
https://github.com/billsonnn/nitro-react.git
synced 2025-02-17 01:12:37 +01:00
added user reporting and issue handling
This commit is contained in:
parent
4603e5271d
commit
710f0f1e01
@ -2,6 +2,7 @@ import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespec
|
||||
import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..';
|
||||
import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../../../events';
|
||||
import { FriendsSendFriendRequestEvent } from '../../../../../events/friends/FriendsSendFriendRequestEvent';
|
||||
import { HelpReportUserEvent } from '../../../../../events/help/HelpReportUserEvent';
|
||||
import { dispatchUiEvent } from '../../../../../hooks/events';
|
||||
import { SendMessageHook } from '../../../../../hooks/messages';
|
||||
import { PetSupplementEnum } from '../../../../../views/room/widgets/avatar-info/common/PetSupplementEnum';
|
||||
@ -164,6 +165,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
|
||||
case RoomWidgetUserActionMessage.REPORT:
|
||||
return;
|
||||
case RoomWidgetUserActionMessage.REPORT_CFH_OTHER:
|
||||
dispatchUiEvent(new HelpReportUserEvent(userId));
|
||||
return;
|
||||
case RoomWidgetUserActionMessage.AMBASSADOR_ALERT_USER:
|
||||
this.container.roomSession.sendAmbassadorAlertMessage(userId);
|
||||
|
@ -5,23 +5,16 @@ export class HelpReportUserEvent extends HelpEvent
|
||||
public static REPORT_USER: string = 'HCE_HELP_CENTER_REPORT_USER';
|
||||
|
||||
private _reportedUserId: number;
|
||||
private _reportedUsername: string;
|
||||
|
||||
constructor(userId: number, username: string)
|
||||
constructor(userId: number)
|
||||
{
|
||||
super(HelpReportUserEvent.REPORT_USER);
|
||||
|
||||
this._reportedUserId = userId;
|
||||
this._reportedUsername = username;
|
||||
}
|
||||
|
||||
public get reportedUserId(): number
|
||||
{
|
||||
return this._reportedUserId;
|
||||
}
|
||||
|
||||
public get reportedUsername(): string
|
||||
{
|
||||
return this._reportedUsername;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
.nitro-help {
|
||||
height: 400px;
|
||||
height: 430px;
|
||||
width: 300px;
|
||||
|
||||
.index-image {
|
||||
|
@ -45,14 +45,25 @@ export const SelectReportedChatsView: FC<{}> = props =>
|
||||
setHelpReportState(reportState);
|
||||
|
||||
}, [helpReportState, selectedChats, setHelpReportState]);
|
||||
|
||||
const back = useCallback(() =>
|
||||
{
|
||||
const reportState = Object.assign({}, helpReportState);
|
||||
reportState.currentStep = --reportState.currentStep;
|
||||
setHelpReportState(reportState);
|
||||
}, [helpReportState, setHelpReportState]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="d-grid col-12 mx-auto justify-content-center">
|
||||
<div className="col-12"><h3 className="fw-bold">{LocalizeText('help.emergency.chat_report.subtitle')}</h3></div>
|
||||
<div className="text-wrap">{LocalizeText('help.emergency.chat_report.description')}</div>
|
||||
{ userChats.length > 0 &&
|
||||
<div className="text-wrap">{LocalizeText('help.emergency.chat_report.description')}</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
{
|
||||
(userChats.length === 0) && <div>{LocalizeText('help.cfh.error.no_user_data')}</div>
|
||||
}
|
||||
{ userChats.length > 0 &&
|
||||
<>
|
||||
<NitroCardGridView columns={1}>
|
||||
@ -65,7 +76,11 @@ export const SelectReportedChatsView: FC<{}> = props =>
|
||||
)
|
||||
})}
|
||||
</NitroCardGridView>
|
||||
<button className="btn btn-secondary mt-2" type="button" disabled={selectedChats.size <= 0} onClick={submitChats}>{LocalizeText('help.emergency.main.submit.button')}</button>
|
||||
|
||||
<div className="d-flex gap-2 justify-content-between mt-auto">
|
||||
<button className="btn btn-secondary mt-2" type="button" onClick={back}>{LocalizeText('generic.back')}</button>
|
||||
<button className="btn btn-primary mt-2" type="button" disabled={selectedChats.size <= 0} onClick={submitChats}>{LocalizeText('help.emergency.main.submit.button')}</button>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { RoomObjectType } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { LocalizeText } from '../../../api';
|
||||
import { GetSessionDataManager, LocalizeText } from '../../../api';
|
||||
import { NitroCardGridItemView, NitroCardGridView } from '../../../layout';
|
||||
import { GetChatHistory } from '../../chat-history/common/GetChatHistory';
|
||||
import { ChatEntryType } from '../../chat-history/context/ChatHistoryContext.types';
|
||||
@ -19,7 +19,7 @@ export const SelectReportedUserView: FC<{}> = props =>
|
||||
GetChatHistory().chats
|
||||
.forEach(chat =>
|
||||
{
|
||||
if((chat.type === ChatEntryType.TYPE_CHAT) && (chat.entityType === RoomObjectType.USER))//todo: remove own chats
|
||||
if((chat.type === ChatEntryType.TYPE_CHAT) && (chat.entityType === RoomObjectType.USER) && (chat.entityId !== GetSessionDataManager().userId))
|
||||
{
|
||||
if(!users.has(chat.entityId))
|
||||
{
|
||||
@ -47,6 +47,13 @@ export const SelectReportedUserView: FC<{}> = props =>
|
||||
else setSelectedUserId(userId);
|
||||
}, [selectedUserId]);
|
||||
|
||||
const back = useCallback(() =>
|
||||
{
|
||||
const reportState = Object.assign({}, helpReportState);
|
||||
reportState.currentStep = --reportState.currentStep;
|
||||
setHelpReportState(reportState);
|
||||
}, [helpReportState, setHelpReportState]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="d-grid col-12 mx-auto justify-content-center">
|
||||
@ -63,14 +70,17 @@ export const SelectReportedUserView: FC<{}> = props =>
|
||||
{availableUsers.map((user, index) =>
|
||||
{
|
||||
return (
|
||||
<NitroCardGridItemView key={user.id} onClick={() => selectUser(user.id)} itemActive={( selectedUserId === user.id)}>
|
||||
<NitroCardGridItemView key={user.id} onClick={() => selectUser(user.id)} itemActive={(selectedUserId === user.id)}>
|
||||
<span dangerouslySetInnerHTML={{ __html: (user.username) }} />
|
||||
</NitroCardGridItemView>
|
||||
)
|
||||
})}
|
||||
</NitroCardGridView>
|
||||
|
||||
<button className="btn btn-secondary mt-2" type="button" disabled={selectedUserId <= 0} onClick={submitUser}>{LocalizeText('help.emergency.main.submit.button')}</button>
|
||||
<div className="d-flex gap-2 justify-content-between mt-auto">
|
||||
<button className="btn btn-secondary mt-2" type="button" onClick={back}>{LocalizeText('generic.back')}</button>
|
||||
<button className="btn btn-primary mt-2" type="button" disabled={selectedUserId <= 0} onClick={submitUser}>{LocalizeText('help.emergency.main.submit.button')}</button>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</>
|
||||
|
@ -6,8 +6,8 @@ import { useHelpContext } from '../context/HelpContext';
|
||||
export const SelectTopicView: FC<{}> = props =>
|
||||
{
|
||||
const { helpReportState = null, setHelpReportState = null } = useHelpContext();
|
||||
const [ selectedCategory, setSelectedCategory ] = useState(-1);
|
||||
const [ selectedTopic, setSelectedTopic ] = useState(-1);
|
||||
const [selectedCategory, setSelectedCategory] = useState(-1);
|
||||
const [selectedTopic, setSelectedTopic] = useState(-1);
|
||||
|
||||
const cfhCategories = useMemo(() =>
|
||||
{
|
||||
@ -17,7 +17,7 @@ export const SelectTopicView: FC<{}> = props =>
|
||||
const submitTopic = useCallback(() =>
|
||||
{
|
||||
if(selectedCategory < 0) return;
|
||||
if(selectedTopic < 0 ) return;
|
||||
if(selectedTopic < 0) return;
|
||||
|
||||
const reportState = Object.assign({}, helpReportState);
|
||||
reportState.cfhCategory = selectedCategory;
|
||||
@ -25,29 +25,40 @@ export const SelectTopicView: FC<{}> = props =>
|
||||
reportState.currentStep = 4;
|
||||
setHelpReportState(reportState);
|
||||
}, [cfhCategories, helpReportState, selectedCategory, selectedTopic, setHelpReportState]);
|
||||
|
||||
|
||||
const back = useCallback(() =>
|
||||
{
|
||||
const reportState = Object.assign({}, helpReportState);
|
||||
reportState.currentStep = --reportState.currentStep;
|
||||
setHelpReportState(reportState);
|
||||
}, [helpReportState, setHelpReportState]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="d-grid col-12 mx-auto justify-content-center">
|
||||
<div className="col-12"><h3 className="fw-bold">{LocalizeText('help.emergency.chat_report.subtitle')}</h3></div>
|
||||
<div className="text-wrap">{LocalizeText('help.cfh.pick.topic')}</div>
|
||||
</div>
|
||||
<div className="d-grid gap-2 col-8 mx-auto overflow-auto">
|
||||
{ (selectedCategory < 0) &&
|
||||
cfhCategories.map((category, index) =>
|
||||
<div className="d-grid gap-2 col-8 mx-auto">
|
||||
{(selectedCategory < 0) &&
|
||||
cfhCategories.map((category, index) =>
|
||||
{
|
||||
return <button key={index} className="btn btn-danger" type="button" onClick={() => setSelectedCategory(index)}>{LocalizeText(`help.cfh.reason.${category.name}`)}</button>
|
||||
})
|
||||
}
|
||||
{ (selectedCategory >= 0 ) &&
|
||||
cfhCategories[selectedCategory].topics.map((topic, index) =>
|
||||
{
|
||||
return <button key={index} className="btn btn-danger" type="button" onClick={() => setSelectedTopic(index)}>{LocalizeText('help.cfh.topic.' + topic.id)}</button>
|
||||
})
|
||||
}
|
||||
}
|
||||
{(selectedCategory >= 0) &&
|
||||
cfhCategories[selectedCategory].topics.map((topic, index) =>
|
||||
{
|
||||
return <button key={index} className="btn btn-danger" type="button" onClick={() => setSelectedTopic(index)}>{LocalizeText('help.cfh.topic.' + topic.id)}</button>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="d-flex gap-2 justify-content-between mt-auto">
|
||||
<button className="btn btn-secondary mt-2" type="button" onClick={back}>{LocalizeText('generic.back')}</button>
|
||||
<button className="btn btn-primary mt-2" type="button" disabled={selectedTopic < 0} onClick={submitTopic}>{LocalizeText('help.emergency.main.submit.button')}</button>
|
||||
</div>
|
||||
|
||||
<button className="btn btn-secondary mt-2" type="button" disabled={selectedTopic < 0} onClick={submitTopic}>{LocalizeText('help.emergency.main.submit.button')}</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,20 +1,9 @@
|
||||
.nitro-mod-tools {
|
||||
width: 200px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.nitro-mod-tools-tickets
|
||||
{
|
||||
width: 400px;
|
||||
|
||||
.issues
|
||||
{
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
@import './views/room/room-tools/ModToolsRoomView';
|
||||
@import './views/chatlog/ChatlogView';
|
||||
@import './views/user/user-info/ModToolsUserView';
|
||||
@import './views/user/user-room-visits/ModToolsUserRoomVisitsView';
|
||||
@import './views/tickets/ModToolsTicketView';
|
||||
|
35
src/views/mod-tools/common/IssueCategoryNames.ts
Normal file
35
src/views/mod-tools/common/IssueCategoryNames.ts
Normal file
@ -0,0 +1,35 @@
|
||||
export const getSourceName = (categoryId: number): string =>
|
||||
{
|
||||
switch(categoryId)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
return 'Normal';
|
||||
case 3:
|
||||
return 'Automatic';
|
||||
case 4:
|
||||
return 'Automatic IM';
|
||||
case 5:
|
||||
return 'Guide System';
|
||||
case 6:
|
||||
return 'IM';
|
||||
case 7:
|
||||
return 'Room';
|
||||
case 8:
|
||||
return 'Panic';
|
||||
case 9:
|
||||
return 'Guardian';
|
||||
case 10:
|
||||
return 'Automatic Helper';
|
||||
case 11:
|
||||
return 'Discussion';
|
||||
case 12:
|
||||
return 'Selfie';
|
||||
case 14:
|
||||
return 'Photo';
|
||||
case 15:
|
||||
return 'Ambassador';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
11
src/views/mod-tools/views/tickets/ModToolsTicketView.scss
Normal file
11
src/views/mod-tools/views/tickets/ModToolsTicketView.scss
Normal file
@ -0,0 +1,11 @@
|
||||
.nitro-mod-tools-tickets
|
||||
{
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.nitro-mod-tools-handle-issue
|
||||
{
|
||||
width: 400px;
|
||||
height: 300px;
|
||||
}
|
@ -3,6 +3,7 @@ import { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { GetSessionDataManager } from '../../../../api';
|
||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout';
|
||||
import { useModToolsContext } from '../../context/ModToolsContext';
|
||||
import { IssueInfoView } from './issue-info/IssueInfoView';
|
||||
import { ModToolsTicketsViewProps } from './ModToolsTicketsView.types';
|
||||
import { ModToolsMyIssuesTabView } from './my-issues/ModToolsMyIssuesTabView';
|
||||
import { ModToolsOpenIssuesTabView } from './open-issues/ModToolsOpenIssuesTabView';
|
||||
@ -20,11 +21,11 @@ export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
|
||||
const { modToolsState = null } = useModToolsContext();
|
||||
const { tickets= null } = modToolsState;
|
||||
const [ currentTab, setCurrentTab ] = useState<number>(0);
|
||||
const [ issueInfoWindows, setIssueInfoWindows ] = useState<number[]>([]);
|
||||
|
||||
const openIssues = useMemo(() =>
|
||||
{
|
||||
if(!tickets) return [];
|
||||
console.log(tickets);
|
||||
|
||||
return tickets.filter(issue => issue.state === IssueMessageData.STATE_OPEN);
|
||||
}, [tickets]);
|
||||
@ -43,18 +44,44 @@ export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
|
||||
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)
|
||||
{
|
||||
const newValues = Array.from(issueInfoWindows);
|
||||
newValues.push(issueId);
|
||||
setIssueInfoWindows(newValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
onIssueInfoClosed(issueId);
|
||||
}
|
||||
}, [issueInfoWindows, onIssueInfoClosed]);
|
||||
|
||||
const CurrentTabComponent = useCallback(() =>
|
||||
{
|
||||
switch(currentTab)
|
||||
{
|
||||
case 0: return <ModToolsOpenIssuesTabView openIssues={openIssues}/>;
|
||||
case 1: return <ModToolsMyIssuesTabView myIssues={myIssues} />;
|
||||
case 1: return <ModToolsMyIssuesTabView myIssues={myIssues} onIssueHandleClick={onIssueHandleClicked}/>;
|
||||
case 2: return <ModToolsPickedIssuesTabView pickedIssues={pickedIssues}/>;
|
||||
default: return null;
|
||||
}
|
||||
}, [currentTab, myIssues, openIssues, pickedIssues]);
|
||||
}, [currentTab, myIssues, onIssueHandleClicked, openIssues, pickedIssues]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<NitroCardView className="nitro-mod-tools-tickets" simple={ false }>
|
||||
<NitroCardHeaderView headerText={ 'Tickets' } onCloseClick={ onCloseClick } />
|
||||
<NitroCardContentView className="p-0 text-black">
|
||||
@ -71,5 +98,9 @@ export const ModToolsTicketsView: FC<ModToolsTicketsViewProps> = props =>
|
||||
</div>
|
||||
</NitroCardContentView>
|
||||
</NitroCardView>
|
||||
{
|
||||
issueInfoWindows && issueInfoWindows.map(issueId => <IssueInfoView key={issueId} issueId={issueId} onIssueInfoClosed={onIssueInfoClosed}/>)
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
import { CfhChatlogData, CfhChatlogEvent, GetCfhChatlogMessageComposer } 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 { CfhChatlogViewProps } from './CfhChatlogView.types';
|
||||
|
||||
export const CfhChatlogView: FC<CfhChatlogViewProps> = props =>
|
||||
{
|
||||
const { onCloseClick = null, issueId = null } = props;
|
||||
const [ chatlogData, setChatlogData ] = useState<CfhChatlogData>(null);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
SendMessageHook(new GetCfhChatlogMessageComposer(issueId));
|
||||
}, [issueId]);
|
||||
|
||||
const onCfhChatlogEvent = useCallback((event: CfhChatlogEvent) =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(!parser || parser.data.issueId !== issueId) return;
|
||||
|
||||
setChatlogData(parser.data);
|
||||
}, [issueId]);
|
||||
|
||||
CreateMessageHook(CfhChatlogEvent, onCfhChatlogEvent);
|
||||
|
||||
return (
|
||||
<NitroCardView className="nitro-mod-tools-cfh-chatlog" simple={true}>
|
||||
<NitroCardHeaderView headerText={'Issue Chatlog'} onCloseClick={onCloseClick} />
|
||||
<NitroCardContentView className="text-black">
|
||||
{ chatlogData && <ChatlogView records={[chatlogData.chatRecord]} />}
|
||||
</NitroCardContentView>
|
||||
</NitroCardView>
|
||||
);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
export interface CfhChatlogViewProps
|
||||
{
|
||||
issueId: number;
|
||||
onCloseClick(): void;
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
import { CloseIssuesMessageComposer, ReleaseIssuesMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { LocalizeText } from '../../../../../api';
|
||||
import { ModToolsOpenUserInfoEvent } from '../../../../../events/mod-tools/ModToolsOpenUserInfoEvent';
|
||||
import { dispatchUiEvent, SendMessageHook } from '../../../../../hooks';
|
||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
|
||||
import { getSourceName } from '../../../common/IssueCategoryNames';
|
||||
import { useModToolsContext } from '../../../context/ModToolsContext';
|
||||
import { CfhChatlogView } from './CfhChatlogView';
|
||||
import { IssueInfoViewProps } from './IssueInfoView.types';
|
||||
|
||||
export const IssueInfoView: 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(() =>
|
||||
{
|
||||
return tickets.find( issue => issue.issueId === issueId);
|
||||
}, [issueId, tickets]);
|
||||
|
||||
const onReleaseIssue = useCallback((issueId: number) =>
|
||||
{
|
||||
SendMessageHook(new ReleaseIssuesMessageComposer([issueId]));
|
||||
onIssueInfoClosed(issueId);
|
||||
}, [onIssueInfoClosed]);
|
||||
|
||||
const openUserInfo = useCallback((userId: number) =>
|
||||
{
|
||||
dispatchUiEvent(new ModToolsOpenUserInfoEvent(userId));
|
||||
}, []);
|
||||
|
||||
const closeIssue = useCallback((resolutionType: number) =>
|
||||
{
|
||||
SendMessageHook(new CloseIssuesMessageComposer([issueId], resolutionType));
|
||||
onIssueInfoClosed(issueId)
|
||||
}, [issueId, onIssueInfoClosed]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<NitroCardView className="nitro-mod-tools-handle-issue" simple={true}>
|
||||
<NitroCardHeaderView headerText={'Resolving issue ' + issueId} onCloseClick={() => onIssueInfoClosed(issueId)} />
|
||||
<NitroCardContentView className="text-black">
|
||||
<div className="row">
|
||||
<div className="col-8">
|
||||
<h3>Issue Information</h3>
|
||||
<div><span className="fw-bold">Source: </span>{getSourceName(ticket.categoryId)}</div>
|
||||
<div><span className="fw-bold">Category: </span>{LocalizeText('help.cfh.topic.' + ticket.reportedCategoryId)}</div>
|
||||
<div><span className="fw-bold">Description: </span>{ticket.message}</div>
|
||||
<div><span className="fw-bold">Caller: </span><button className="btn btn-link fw-bold" onClick={() => openUserInfo(ticket.reporterUserId)}>{ticket.reporterUserName}</button></div>
|
||||
<div><span className="fw-bold">Reported User: </span><button className="btn btn-link fw-bold" onClick={() => openUserInfo(ticket.reportedUserId)}>{ticket.reportedUserName}</button></div>
|
||||
</div>
|
||||
<div className="col-4">
|
||||
<div className="d-grid gap-2 mb-4">
|
||||
<button className="btn btn-secondary" onClick={() => setcfhChatlogOpen(!cfhChatlogOpen)}>Chatlog</button>
|
||||
</div>
|
||||
<div className="d-grid gap-2">
|
||||
<button className="btn btn-primary" onClick={() => closeIssue(CloseIssuesMessageComposer.RESOLUTION_USELESS)}>Close as useless</button>
|
||||
<button className="btn btn-danger" onClick={() => closeIssue(CloseIssuesMessageComposer.RESOLUTION_ABUSIVE)}>Close as abusive</button>
|
||||
<button className="btn btn-success" onClick={() => closeIssue(CloseIssuesMessageComposer.RESOLUTION_RESOLVED)}>Close as resolved</button>
|
||||
<button className="btn btn-secondary" onClick={() => onReleaseIssue(issueId)}>Release</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</NitroCardContentView>
|
||||
</NitroCardView>
|
||||
{ cfhChatlogOpen && <CfhChatlogView issueId={issueId} onCloseClick={() => setcfhChatlogOpen(false) }/>}
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
export interface IssueInfoViewProps
|
||||
{
|
||||
issueId: number;
|
||||
onIssueInfoClosed(issueId: number): void;
|
||||
}
|
@ -1,53 +1,45 @@
|
||||
import { FC } from 'react';
|
||||
import { AutoSizer, List, ListRowProps, ListRowRenderer } from 'react-virtualized';
|
||||
import { ReleaseIssuesMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback } from 'react';
|
||||
import { SendMessageHook } from '../../../../../hooks';
|
||||
import { ModToolsMyIssuesTabViewProps } from './ModToolsMyIssuesTabView.types';
|
||||
|
||||
export const ModToolsMyIssuesTabView: FC<ModToolsMyIssuesTabViewProps> = props =>
|
||||
{
|
||||
const { myIssues = null } = props;
|
||||
|
||||
const RowRenderer: ListRowRenderer = (props: ListRowProps) =>
|
||||
{
|
||||
const item = myIssues[props.index];
|
||||
|
||||
return (
|
||||
<div key={props.key} style={props.style} className="row issue-entry justify-content-start">
|
||||
<div className="col-auto text-center">{item.categoryId}</div>
|
||||
<div className="col justify-content-start username"><span className="fw-bold cursor-pointer">{item.reportedUserName}</span></div>
|
||||
<div className="col-sm-2 justify-content-start"><span className="text-break text-wrap h-100">{item.getOpenTime(new Date().getTime())}</span></div>
|
||||
<div className="col-sm-2">
|
||||
<button className="btn btn-sm btn-primary">View Issue</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const { myIssues = null, onIssueHandleClick = null } = props;
|
||||
|
||||
|
||||
const onReleaseIssue = useCallback((issueId: number) =>
|
||||
{
|
||||
SendMessageHook(new ReleaseIssuesMessageComposer([issueId]));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="row align-items-start w-100">
|
||||
<div className="col-auto text-center fw-bold">Type</div>
|
||||
<div className="col fw-bold">Room/Player</div>
|
||||
<div className="col-sm-2 fw-bold">Opened</div>
|
||||
<div className="col-sm-2"></div>
|
||||
</div>
|
||||
<div className="row w-100 issues">
|
||||
<AutoSizer defaultWidth={400} defaultHeight={200}>
|
||||
{({ height, width }) =>
|
||||
{
|
||||
return (
|
||||
<List
|
||||
width={width}
|
||||
height={height}
|
||||
rowCount={myIssues.length}
|
||||
rowHeight={25}
|
||||
className={'issues-container'}
|
||||
rowRenderer={RowRenderer}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
</AutoSizer>
|
||||
</div>
|
||||
<table className="table text-black table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Type</th>
|
||||
<th scope="col">Room/Player</th>
|
||||
<th scope="col">Opened</th>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{myIssues.map(issue =>
|
||||
{
|
||||
return (
|
||||
<tr className="text-black" key={issue.issueId}>
|
||||
<td>{issue.categoryId}</td>
|
||||
<td>{issue.reportedUserName}</td>
|
||||
<td>{new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString()}</td>
|
||||
<td><button className="btn btn-sm btn-primary" onClick={() => onIssueHandleClick(issue.issueId)}>Handle</button></td>
|
||||
<td><button className="btn btn-sm btn-danger" onClick={() => onReleaseIssue(issue.issueId)}>Release</button></td>
|
||||
</tr>)
|
||||
})
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -3,4 +3,5 @@ import { IssueMessageData } from '@nitrots/nitro-renderer';
|
||||
export interface ModToolsMyIssuesTabViewProps
|
||||
{
|
||||
myIssues: IssueMessageData[];
|
||||
onIssueHandleClick(issueId: number): void;
|
||||
}
|
||||
|
@ -1,53 +1,42 @@
|
||||
import { FC } from 'react';
|
||||
import { AutoSizer, List, ListRowProps, ListRowRenderer } from 'react-virtualized';
|
||||
import { PickIssuesMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback } from 'react';
|
||||
import { SendMessageHook } from '../../../../../hooks';
|
||||
import { ModToolsOpenIssuesTabViewProps } from './ModToolsOpenIssuesTabView.types';
|
||||
|
||||
export const ModToolsOpenIssuesTabView: FC<ModToolsOpenIssuesTabViewProps> = props =>
|
||||
{
|
||||
const { openIssues = null } = props;
|
||||
|
||||
const RowRenderer: ListRowRenderer = (props: ListRowProps) =>
|
||||
const onPickIssue = useCallback((issueId: number) =>
|
||||
{
|
||||
const item = openIssues[props.index];
|
||||
SendMessageHook(new PickIssuesMessageComposer([issueId], false, 0, 'pick issue button'));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div key={props.key} style={props.style} className="row issue-entry justify-content-start">
|
||||
<div className="col-auto text-center">{item.categoryId}</div>
|
||||
<div className="col justify-content-start username"><span className="fw-bold cursor-pointer">{item.reportedUserName}</span></div>
|
||||
<div className="col-sm-2 justify-content-start"><span className="text-break text-wrap h-100">{item.getOpenTime(new Date().getTime())}</span></div>
|
||||
<div className="col-sm-2">
|
||||
<button className="btn btn-sm btn-primary">Pick Issue</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="row align-items-start w-100">
|
||||
<div className="col-auto text-center fw-bold">Type</div>
|
||||
<div className="col fw-bold">Room/Player</div>
|
||||
<div className="col-sm-2 fw-bold">Opened</div>
|
||||
<div className="col-sm-2"></div>
|
||||
</div>
|
||||
<div className="row w-100 issues">
|
||||
<AutoSizer defaultWidth={400} defaultHeight={200}>
|
||||
{({ height, width }) =>
|
||||
{
|
||||
return (
|
||||
<List
|
||||
width={width}
|
||||
height={height}
|
||||
rowCount={openIssues.length}
|
||||
rowHeight={25}
|
||||
className={'issues-container'}
|
||||
rowRenderer={RowRenderer}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
</AutoSizer>
|
||||
</div>
|
||||
<table className="table text-black table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Type</th>
|
||||
<th scope="col">Room/Player</th>
|
||||
<th scope="col">Opened</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{openIssues.map(issue =>
|
||||
{
|
||||
return (
|
||||
<tr className="text-black" key={issue.issueId}>
|
||||
<td>{issue.categoryId}</td>
|
||||
<td>{issue.reportedUserName}</td>
|
||||
<td>{new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString()}</td>
|
||||
<td><button className="btn btn-sm btn-success" onClick={() => onPickIssue(issue.issueId)}>Pick Issue</button></td>
|
||||
</tr>)
|
||||
})
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,53 +1,35 @@
|
||||
import { FC } from 'react';
|
||||
import { AutoSizer, List, ListRowProps, ListRowRenderer } from 'react-virtualized';
|
||||
import { ModToolsPickedIssuesTabViewProps } from './ModToolsPickedIssuesTabView.types';
|
||||
|
||||
export const ModToolsPickedIssuesTabView: FC<ModToolsPickedIssuesTabViewProps> = props =>
|
||||
{
|
||||
const { pickedIssues = null } = props;
|
||||
|
||||
const RowRenderer: ListRowRenderer = (props: ListRowProps) =>
|
||||
{
|
||||
const item = pickedIssues[props.index];
|
||||
|
||||
return (
|
||||
<div key={props.key} style={props.style} className="row issue-entry justify-content-start">
|
||||
<div className="col-auto text-center">{item.categoryId}</div>
|
||||
<div className="col justify-content-start username"><span className="fw-bold cursor-pointer">{item.reportedUserName}</span></div>
|
||||
<div className="col-sm-2 justify-content-start"><span className="text-break text-wrap h-100">{item.getOpenTime(new Date().getTime())}</span></div>
|
||||
<div className="col-sm-2">
|
||||
{item.pickerUserName}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="row align-items-start w-100">
|
||||
<div className="col-auto text-center fw-bold">Type</div>
|
||||
<div className="col fw-bold">Room/Player</div>
|
||||
<div className="col-sm-2 fw-bold">Opened</div>
|
||||
<div className="col-sm-2 fw-bold">Picker</div>
|
||||
</div>
|
||||
<div className="row w-100 issues">
|
||||
<AutoSizer defaultWidth={400} defaultHeight={200}>
|
||||
{({ height, width }) =>
|
||||
{
|
||||
return (
|
||||
<List
|
||||
width={width}
|
||||
height={height}
|
||||
rowCount={pickedIssues.length}
|
||||
rowHeight={25}
|
||||
className={'issues-container'}
|
||||
rowRenderer={RowRenderer}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
</AutoSizer>
|
||||
</div>
|
||||
<table className="table text-black table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Type</th>
|
||||
<th scope="col">Room/Player</th>
|
||||
<th scope="col">Opened</th>
|
||||
<th scope="col">Picker</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{pickedIssues.map(issue =>
|
||||
{
|
||||
return (
|
||||
<tr className="text-black" key={issue.issueId}>
|
||||
<td>{issue.categoryId}</td>
|
||||
<td>{issue.reportedUserName}</td>
|
||||
<td>{new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString()}</td>
|
||||
<td>{issue.pickerUserName}</td>
|
||||
</tr>)
|
||||
})
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user