Refactor reporting, add messenger reporting

This commit is contained in:
Bill 2022-07-26 18:19:30 -04:00
parent 3f9a39f623
commit 7dc980af90
34 changed files with 471 additions and 523 deletions

View File

@ -2,4 +2,5 @@ export class ChatEntryType
{ {
public static TYPE_CHAT = 1; public static TYPE_CHAT = 1;
public static TYPE_ROOM_INFO = 2; public static TYPE_ROOM_INFO = 2;
public static TYPE_IM = 3;
} }

View File

@ -0,0 +1,6 @@
export const MessengerHistoryCurrentDate = (secondsSinceNow: number = 0) =>
{
const currentTime = secondsSinceNow ? new Date(Date.now() - secondsSinceNow * 1000) : new Date();
return `${ currentTime.getHours().toString().padStart(2, '0') }:${ currentTime.getMinutes().toString().padStart(2, '0') }`;
}

View File

@ -2,3 +2,4 @@ export * from './ChatEntryType';
export * from './ChatHistoryCurrentDate'; export * from './ChatHistoryCurrentDate';
export * from './IChatEntry'; export * from './IChatEntry';
export * from './IRoomHistoryEntry'; export * from './IRoomHistoryEntry';
export * from './MessengerHistoryCurrentDate';

View File

@ -1,12 +1,19 @@
import { IChatEntry } from '../chat-history'; import { IChatEntry } from '../chat-history';
export interface IHelpReportState export interface IHelpReport
{ {
reportType: number;
reportedUserId: number; reportedUserId: number;
reportedChats: IChatEntry[]; reportedChats: IChatEntry[];
cfhCategory: number; cfhCategory: number;
cfhTopic: number; cfhTopic: number;
roomId: number; roomId: number;
roomName: string;
groupId: number;
threadId: number;
messageId: number;
extraData: string;
roomObjectId: number;
message: string; message: string;
currentStep: number; currentStep: number;
} }

View File

@ -0,0 +1,8 @@
export class ReportState
{
public static readonly SELECT_USER = 0;
public static readonly SELECT_CHATS = 1;
public static readonly SELECT_TOPICS = 2;
public static readonly INPUT_REPORT_MESSAGE = 3;
public static readonly REPORT_SUMMARY = 4;
}

View File

@ -0,0 +1,11 @@
export class ReportType
{
public static readonly EMERGENCY = 1;
public static readonly GUIDE = 2;
public static readonly IM = 3;
public static readonly ROOM = 4;
public static readonly BULLY = 6;
public static readonly THREAD = 7;
public static readonly MESSAGE = 8;
public static readonly PHOTO = 9;
}

View File

@ -1,4 +1,6 @@
export * from './CallForHelpResult'; export * from './CallForHelpResult';
export * from './GetCloseReasonKey'; export * from './GetCloseReasonKey';
export * from './IHelpReportState'; export * from './IHelpReport';
export * from './IReportedUser'; export * from './IReportedUser';
export * from './ReportState';
export * from './ReportType';

View File

@ -1,9 +1,9 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { FollowFriendMessageComposer, ILinkEventTracker } from '@nitrots/nitro-renderer'; import { FollowFriendMessageComposer, ILinkEventTracker } from '@nitrots/nitro-renderer';
import { FC, KeyboardEvent, useEffect, useRef, useState } from 'react'; import { FC, KeyboardEvent, useEffect, useRef, useState } from 'react';
import { AddEventLinkTracker, GetUserProfile, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../../../api'; import { AddEventLinkTracker, GetUserProfile, LocalizeText, RemoveLinkEventTracker, ReportType, SendMessageComposer } from '../../../../api';
import { Base, Button, ButtonGroup, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, LayoutGridItem, LayoutItemCountView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; import { Base, Button, ButtonGroup, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, LayoutGridItem, LayoutItemCountView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { useMessenger } from '../../../../hooks'; import { useHelp, useMessenger } from '../../../../hooks';
import { FriendsMessengerThreadView } from './messenger-thread/FriendsMessengerThreadView'; import { FriendsMessengerThreadView } from './messenger-thread/FriendsMessengerThreadView';
export const FriendsMessengerView: FC<{}> = props => export const FriendsMessengerView: FC<{}> = props =>
@ -12,6 +12,7 @@ export const FriendsMessengerView: FC<{}> = props =>
const [ lastThreadId, setLastThreadId ] = useState(-1); const [ lastThreadId, setLastThreadId ] = useState(-1);
const [ messageText, setMessageText ] = useState(''); const [ messageText, setMessageText ] = useState('');
const { visibleThreads = [], activeThread = null, getMessageThread = null, sendMessage = null, setActiveThreadId = null, closeThread = null } = useMessenger(); const { visibleThreads = [], activeThread = null, getMessageThread = null, sendMessage = null, setActiveThreadId = null, closeThread = null } = useMessenger();
const { report = null } = useHelp();
const messagesBox = useRef<HTMLDivElement>(); const messagesBox = useRef<HTMLDivElement>();
const followFriend = () => (activeThread && activeThread.participant && SendMessageComposer(new FollowFriendMessageComposer(activeThread.participant.id))); const followFriend = () => (activeThread && activeThread.participant && SendMessageComposer(new FollowFriendMessageComposer(activeThread.participant.id)));
@ -141,7 +142,7 @@ export const FriendsMessengerView: FC<{}> = props =>
<Base className="nitro-friends-spritesheet icon-profile-sm" /> <Base className="nitro-friends-spritesheet icon-profile-sm" />
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<Button variant="danger" onClick={ openProfile }> <Button variant="danger" onClick={ () => report(ReportType.IM, { reportedUserId: activeThread.participant.id }) }>
{ LocalizeText('messenger.window.button.report') } { LocalizeText('messenger.window.button.report') }
</Button> </Button>
</Flex> </Flex>

View File

@ -1,9 +1,9 @@
import { GuideOnDutyStatusMessageEvent, GuideSessionAttachedMessageEvent, GuideSessionDetachedMessageEvent, GuideSessionEndedMessageEvent, GuideSessionInvitedToGuideRoomMessageEvent, GuideSessionMessageMessageEvent, GuideSessionOnDutyUpdateMessageComposer, GuideSessionPartnerIsTypingMessageEvent, GuideSessionStartedMessageEvent, ILinkEventTracker, PerkAllowancesMessageEvent, PerkEnum } from '@nitrots/nitro-renderer'; import { GuideOnDutyStatusMessageEvent, GuideSessionAttachedMessageEvent, GuideSessionDetachedMessageEvent, GuideSessionEndedMessageEvent, GuideSessionInvitedToGuideRoomMessageEvent, GuideSessionMessageMessageEvent, GuideSessionOnDutyUpdateMessageComposer, GuideSessionPartnerIsTypingMessageEvent, GuideSessionStartedMessageEvent, ILinkEventTracker, PerkAllowancesMessageEvent, PerkEnum } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react'; import { FC, useCallback, useEffect, useState } from 'react';
import { AddEventLinkTracker, DispatchUiEvent, GetConfiguration, GetSessionDataManager, GuideSessionState, GuideToolMessage, GuideToolMessageGroup, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api'; import { AddEventLinkTracker, GetConfiguration, GetSessionDataManager, GuideSessionState, GuideToolMessage, GuideToolMessageGroup, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
import { GuideToolEvent, NotificationAlertEvent } from '../../events'; import { GuideToolEvent } from '../../events';
import { useMessageEvent, useUiEvent } from '../../hooks'; import { useMessageEvent, useNotification, useUiEvent } from '../../hooks';
import { GuideToolAcceptView } from './views/GuideToolAcceptView'; import { GuideToolAcceptView } from './views/GuideToolAcceptView';
import { GuideToolMenuView } from './views/GuideToolMenuView'; import { GuideToolMenuView } from './views/GuideToolMenuView';
import { GuideToolOngoingView } from './views/GuideToolOngoingView'; import { GuideToolOngoingView } from './views/GuideToolOngoingView';
@ -39,6 +39,8 @@ export const GuideToolView: FC<{}> = props =>
const [ ongoingIsTyping, setOngoingIsTyping ] = useState<boolean>(false); const [ ongoingIsTyping, setOngoingIsTyping ] = useState<boolean>(false);
const [ ongoingMessageGroups, setOngoingMessageGroups ] = useState<GuideToolMessageGroup[]>([]); const [ ongoingMessageGroups, setOngoingMessageGroups ] = useState<GuideToolMessageGroup[]>([]);
const { simpleAlert = null } = useNotification();
const updateSessionState = useCallback((newState: string, replacement?: string) => const updateSessionState = useCallback((newState: string, replacement?: string) =>
{ {
switch(newState) switch(newState)
@ -296,7 +298,7 @@ export const GuideToolView: FC<{}> = props =>
case 'toggle_duty': case 'toggle_duty':
if(!isHandlingBullyReports && !isHandlingGuideRequests && !isHandlingHelpRequests) if(!isHandlingBullyReports && !isHandlingGuideRequests && !isHandlingHelpRequests)
{ {
DispatchUiEvent(new NotificationAlertEvent([ LocalizeText('guide.help.guide.tool.noqueueselected.message') ], null, null, null, LocalizeText('guide.help.guide.tool.noqueueselected.caption'), null)); simpleAlert(LocalizeText('guide.help.guide.tool.noqueueselected.message'), null, null, null, LocalizeText('guide.help.guide.tool.noqueueselected.caption'), null);
return; return;
} }
@ -312,7 +314,7 @@ export const GuideToolView: FC<{}> = props =>
window.open(url); window.open(url);
return; return;
} }
}, [ isHandlingBullyReports, isHandlingGuideRequests, isHandlingHelpRequests ]); }, [ isHandlingBullyReports, isHandlingGuideRequests, isHandlingHelpRequests, simpleAlert ]);
if(!isVisible) return null; if(!isVisible) return null;

View File

@ -1,20 +0,0 @@
import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react';
import { IHelpReportState } from '../../api';
interface IHelpContext
{
helpReportState: IHelpReportState;
setHelpReportState: Dispatch<SetStateAction<IHelpReportState>>;
}
const HelpContext = createContext<IHelpContext>({
helpReportState: null,
setHelpReportState: null
});
export const HelpContextProvider: FC<ProviderProps<IHelpContext>> = props =>
{
return <HelpContext.Provider value={ props.value }>{ props.children }</HelpContext.Provider>
}
export const useHelpContext = () => useContext(HelpContext);

View File

@ -1,45 +0,0 @@
import { CallForHelpResultMessageEvent, GetPendingCallsForHelpMessageComposer, IssueCloseNotificationMessageEvent } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { CallForHelpResult, GetCloseReasonKey, LocalizeText, NotificationAlertType, SendMessageComposer } from '../../api';
import { useMessageEvent, useNotification } from '../../hooks';
export const HelpMessageHandler: FC<{}> = props =>
{
const { simpleAlert = null } = useNotification();
useMessageEvent<CallForHelpResultMessageEvent>(CallForHelpResultMessageEvent, event =>
{
const parser = event.getParser();
let message = parser.messageText;
switch(parser.resultType)
{
case CallForHelpResult.TOO_MANY_PENDING_CALLS_CODE:
SendMessageComposer(new GetPendingCallsForHelpMessageComposer());
simpleAlert(LocalizeText('help.cfh.error.pending'), NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.error.title'));
break;
case CallForHelpResult.HAS_ABUSIVE_CALL_CODE:
simpleAlert(LocalizeText('help.cfh.error.abusive'), NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.error.title'));
break;
default:
if(message.trim().length === 0)
{
message = LocalizeText('help.cfh.sent.text');
}
simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.sent.title'));
}
});
useMessageEvent<IssueCloseNotificationMessageEvent>(IssueCloseNotificationMessageEvent, event =>
{
const parser = event.getParser();
const message = parser.messageText.length === 0 ? LocalizeText('help.cfh.closed.' + GetCloseReasonKey(parser.closeReason)) : parser.messageText;
simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('mod.alert.title'));
});
return null;
}

View File

@ -1,14 +1,12 @@
import { ILinkEventTracker } from '@nitrots/nitro-renderer'; import { ILinkEventTracker } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { AddEventLinkTracker, IHelpReportState, LocalizeText, RemoveLinkEventTracker } from '../../api'; import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker, ReportState } from '../../api';
import { Base, Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common'; import { Base, Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
import { HelpReportUserEvent } from '../../events'; import { useHelp } from '../../hooks';
import { useUiEvent } from '../../hooks';
import { HelpContextProvider } from './HelpContext';
import { HelpMessageHandler } from './HelpMessageHandler';
import { DescribeReportView } from './views/DescribeReportView'; import { DescribeReportView } from './views/DescribeReportView';
import { HelpIndexView } from './views/HelpIndexView'; import { HelpIndexView } from './views/HelpIndexView';
import { NameChangeView } from './views/name-change/NameChangeView'; import { NameChangeView } from './views/name-change/NameChangeView';
import { ReportSummaryView } from './views/ReportSummaryView';
import { SanctionSatusView } from './views/SanctionStatusView'; import { SanctionSatusView } from './views/SanctionStatusView';
import { SelectReportedChatsView } from './views/SelectReportedChatsView'; import { SelectReportedChatsView } from './views/SelectReportedChatsView';
import { SelectReportedUserView } from './views/SelectReportedUserView'; import { SelectReportedUserView } from './views/SelectReportedUserView';
@ -17,17 +15,18 @@ import { SelectTopicView } from './views/SelectTopicView';
export const HelpView: FC<{}> = props => export const HelpView: FC<{}> = props =>
{ {
const [ isVisible, setIsVisible ] = useState(false); const [ isVisible, setIsVisible ] = useState(false);
const [ helpReportState, setHelpReportState ] = useState<IHelpReportState>({ const { activeReport = null, setActiveReport = null, report = null } = useHelp();
reportedUserId: -1,
reportedChats: [],
cfhCategory: -1,
cfhTopic: -1,
roomId: -1,
message: '',
currentStep: 0
});
const linkReceived = useCallback((url: string) => const close = () =>
{
setActiveReport(null);
setIsVisible(false);
}
useEffect(() =>
{
const linkTracker: ILinkEventTracker = {
linkReceived: (url: string) =>
{ {
const parts = url.split('/'); const parts = url.split('/');
@ -44,73 +43,62 @@ export const HelpView: FC<{}> = props =>
case 'toggle': case 'toggle':
setIsVisible(prevValue => !prevValue); setIsVisible(prevValue => !prevValue);
return; return;
case 'tour':
// todo: launch tour
return;
case 'report':
if((parts.length >= 5) && (parts[2] === 'room'))
{
const roomId = parseInt(parts[3]);
const unknown = unescape(parts.splice(4).join('/'));
//this.reportRoom(roomId, unknown, "");
} }
}, []); return;
}
const onHelpReportUserEvent = useCallback((event: HelpReportUserEvent) => },
{
setHelpReportState({
reportedUserId: event.reportedUserId,
reportedChats: [],
cfhCategory: -1,
cfhTopic: -1,
roomId: -1,
message: '',
currentStep: 2
});
setIsVisible(true);
}, []);
useUiEvent(HelpReportUserEvent.REPORT_USER, onHelpReportUserEvent);
useEffect(() =>
{
const linkTracker: ILinkEventTracker = {
linkReceived,
eventUrlPrefix: 'help/' eventUrlPrefix: 'help/'
}; };
AddEventLinkTracker(linkTracker); AddEventLinkTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker); return () => RemoveLinkEventTracker(linkTracker);
}, [ linkReceived ]); }, []);
useEffect(() => useEffect(() =>
{ {
if(!isVisible) return; if(!activeReport) return;
setHelpReportState({ setIsVisible(true);
reportedUserId: -1, }, [ activeReport ]);
reportedChats: [],
cfhCategory: -1,
cfhTopic: -1,
roomId: -1,
message: '',
currentStep: 0
});
}, [ isVisible ]);
const CurrentStepView = useCallback(() => if(!isVisible && !activeReport) return null;
const CurrentStepView = () =>
{ {
switch(helpReportState.currentStep) if(activeReport)
{ {
case 0: return <HelpIndexView /> switch(activeReport.currentStep)
case 1: return <SelectReportedUserView /> {
case 2: return <SelectReportedChatsView /> case ReportState.SELECT_USER:
case 3: return <SelectTopicView /> return <SelectReportedUserView />;
case 4: return <DescribeReportView /> case ReportState.SELECT_CHATS:
return <SelectReportedChatsView />;
case ReportState.SELECT_TOPICS:
return <SelectTopicView />;
case ReportState.INPUT_REPORT_MESSAGE:
return <DescribeReportView />;
case ReportState.REPORT_SUMMARY:
return <ReportSummaryView />;
}
} }
return null; return <HelpIndexView />;
}, [ helpReportState.currentStep ]); }
return ( return (
<HelpContextProvider value={ { helpReportState, setHelpReportState } }> <>
<HelpMessageHandler />
{ isVisible &&
<NitroCardView className="nitro-help" theme="primary-slim"> <NitroCardView className="nitro-help" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText('help.button.cfh') } onCloseClick={ event => setIsVisible(false) } /> <NitroCardHeaderView headerText={ LocalizeText('help.button.cfh') } onCloseClick={ close } />
<NitroCardContentView className="text-black"> <NitroCardContentView className="text-black">
<Grid> <Grid>
<Column center size={ 5 } overflow="hidden"> <Column center size={ 5 } overflow="hidden">
@ -121,9 +109,9 @@ export const HelpView: FC<{}> = props =>
</Column> </Column>
</Grid> </Grid>
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> } </NitroCardView>
<SanctionSatusView /> <SanctionSatusView />
<NameChangeView /> <NameChangeView />
</HelpContextProvider> </>
); );
} }

View File

@ -1,31 +1,31 @@
import { CallForHelpMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useState } from 'react'; import { FC, useState } from 'react';
import { CreateLinkEvent, LocalizeText, SendMessageComposer } from '../../../api'; import { LocalizeText, ReportState, ReportType } from '../../../api';
import { Button, Column, Text } from '../../../common'; import { Button, Column, Flex, Text } from '../../../common';
import { useHelpContext } from '../HelpContext'; import { useHelp } from '../../../hooks';
export const DescribeReportView: FC<{}> = props => export const DescribeReportView: FC<{}> = props =>
{ {
const [ message, setMessage ] = useState(''); const [ message, setMessage ] = useState('');
const { helpReportState = null, setHelpReportState = null } = useHelpContext(); const { activeReport = null, setActiveReport = null } = useHelp();
const { reportedChats, cfhTopic, reportedUserId } = helpReportState;
const submitReport = () => const submitMessage = () =>
{ {
if(message.length < 15) return; if(message.length < 15) return;
const roomId = reportedChats[0].roomId; setActiveReport(prevValue =>
const chats: (string | number )[] = [];
reportedChats.forEach(entry =>
{ {
chats.push(entry.entityId); const currentStep = ReportState.REPORT_SUMMARY;
chats.push(entry.message);
return { ...prevValue, message, currentStep };
}); });
}
SendMessageComposer(new CallForHelpMessageComposer(message, cfhTopic, reportedUserId, roomId, chats)); const back = () =>
{
CreateLinkEvent('help/hide'); setActiveReport(prevValue =>
{
return { ...prevValue, currentStep: (prevValue.currentStep - 1) };
});
} }
return ( return (
@ -35,9 +35,14 @@ export const DescribeReportView: FC<{}> = props =>
<Text>{ LocalizeText('help.cfh.input.text') }</Text> <Text>{ LocalizeText('help.cfh.input.text') }</Text>
</Column> </Column>
<textarea className="form-control h-100" value={ message } onChange={ event => setMessage(event.target.value) } /> <textarea className="form-control h-100" value={ message } onChange={ event => setMessage(event.target.value) } />
<Button variant="success" disabled={ (message.length < 15) } onClick={ submitReport }> <Flex gap={ 2 } justifyContent="between">
{ LocalizeText('help.bully.submit') } <Button variant="secondary" disabled={ !(activeReport.reportType === ReportType.BULLY || activeReport.reportType === ReportType.EMERGENCY) } onClick={ back }>
{ LocalizeText('generic.back') }
</Button> </Button>
<Button disabled={ (message.length < 15) } onClick={ submitMessage }>
{ LocalizeText('help.emergency.main.submit.button') }
</Button>
</Flex>
</> </>
); );
} }

View File

@ -1,30 +1,23 @@
import { GetCfhStatusMessageComposer } from '@nitrots/nitro-renderer'; import { GetCfhStatusMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react'; import { FC } from 'react';
import { DispatchUiEvent, LocalizeText, SendMessageComposer } from '../../../api'; import { DispatchUiEvent, LocalizeText, ReportState, SendMessageComposer } from '../../../api';
import { Button, Column, Text } from '../../../common'; import { Button, Column, Text } from '../../../common';
import { GuideToolEvent } from '../../../events'; import { GuideToolEvent } from '../../../events';
import { useHelpContext } from '../HelpContext'; import { useHelp } from '../../../hooks';
export const HelpIndexView: FC<{}> = props => export const HelpIndexView: FC<{}> = props =>
{ {
const { helpReportState = null, setHelpReportState = null } = useHelpContext(); const { setActiveReport = null } = useHelp();
const onReportClick = useCallback(() => const onReportClick = () =>
{ {
const reportState = Object.assign({}, helpReportState ); setActiveReport(prevValue =>
reportState.currentStep = 1; {
setHelpReportState(reportState); const currentStep = ReportState.SELECT_USER;
},[ helpReportState, setHelpReportState ]);
const onRequestMySanctionStatusClick = useCallback(() => return { ...prevValue, currentStep };
{ });
SendMessageComposer(new GetCfhStatusMessageComposer(false)); }
}, []);
const onNewHelpRequestClick = useCallback(() =>
{
DispatchUiEvent(new GuideToolEvent(GuideToolEvent.CREATE_HELP_REQUEST));
}, []);
return ( return (
<> <>
@ -34,9 +27,9 @@ export const HelpIndexView: FC<{}> = props =>
</Column> </Column>
<Column gap={ 1 }> <Column gap={ 1 }>
<Button onClick={ onReportClick }>{ LocalizeText('help.main.bully.subtitle') }</Button> <Button onClick={ onReportClick }>{ LocalizeText('help.main.bully.subtitle') }</Button>
<Button onClick={ onNewHelpRequestClick }>{ LocalizeText('help.main.help.title') }</Button> <Button onClick={ () => DispatchUiEvent(new GuideToolEvent(GuideToolEvent.CREATE_HELP_REQUEST)) }>{ LocalizeText('help.main.help.title') }</Button>
<Button disabled={ true }>{ LocalizeText('help.main.self.tips.title') }</Button> <Button disabled={ true }>{ LocalizeText('help.main.self.tips.title') }</Button>
<Button variant="link" className="text-black" onClick={ onRequestMySanctionStatusClick }>{ LocalizeText('help.main.my.sanction.status') }</Button> <Button variant="link" className="text-black" onClick={ () => SendMessageComposer(new GetCfhStatusMessageComposer(false)) }>{ LocalizeText('help.main.my.sanction.status') }</Button>
</Column> </Column>
</> </>
) )

View File

@ -0,0 +1,57 @@
import { CallForHelpFromForumMessageMessageComposer, CallForHelpFromForumThreadMessageComposer, CallForHelpFromIMMessageComposer, CallForHelpFromPhotoMessageComposer, CallForHelpMessageComposer } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { GetSessionDataManager, LocalizeText, ReportType, SendMessageComposer } from '../../../api';
import { Button, Column, Text } from '../../../common';
import { useHelp } from '../../../hooks';
export const ReportSummaryView: FC<{}> = props =>
{
const { activeReport = null, setActiveReport = null } = useHelp();
const submitReport = () =>
{
const chats: (string | number )[] = [];
switch(activeReport.reportType)
{
case ReportType.BULLY:
case ReportType.EMERGENCY:
case ReportType.ROOM: {
const reportedRoomId = ((activeReport.roomId <= 0) ? activeReport.reportedChats[0].roomId : activeReport.roomId);
activeReport.reportedChats.forEach(entry => chats.push(entry.entityId, entry.message));
SendMessageComposer(new CallForHelpMessageComposer(activeReport.message, activeReport.cfhTopic, activeReport.reportedUserId, reportedRoomId, chats));
break;
}
case ReportType.IM:
activeReport.reportedChats.forEach(entry => chats.push(entry.entityId, entry.message));
SendMessageComposer(new CallForHelpFromIMMessageComposer(activeReport.message, activeReport.cfhTopic, activeReport.reportedUserId, chats));
break;
case ReportType.THREAD:
SendMessageComposer(new CallForHelpFromForumThreadMessageComposer(activeReport.groupId, activeReport.threadId, activeReport.cfhTopic, activeReport.message));
break;
case ReportType.MESSAGE:
SendMessageComposer(new CallForHelpFromForumMessageMessageComposer(activeReport.groupId, activeReport.threadId, activeReport.messageId, activeReport.cfhTopic, activeReport.message));
break;
case ReportType.PHOTO:
SendMessageComposer(new CallForHelpFromPhotoMessageComposer(activeReport.extraData, activeReport.cfhTopic, activeReport.roomId, GetSessionDataManager().userId, activeReport.roomObjectId));
break;
}
setActiveReport(null);
}
return (
<>
<Column gap={ 1 }>
<Text fontSize={ 4 }>{ LocalizeText('help.cfh.button.send') }</Text>
<Text>{ LocalizeText('help.main.summary') }</Text>
</Column>
<Button variant="success" onClick={ submitReport }>
{ LocalizeText('guide.help.request.emergency.submit.button') }
</Button>
</>
)
}

View File

@ -1,25 +1,13 @@
import { SanctionStatusEvent, SanctionStatusMessageParser } from '@nitrots/nitro-renderer'; import { FC } from 'react';
import { FC, useCallback, useState } from 'react';
import { LocalizeText } from '../../../api'; import { LocalizeText } from '../../../api';
import { Base, Button, Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../common'; import { Base, Button, Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../common';
import { useMessageEvent } from '../../../hooks'; import { useHelp } from '../../../hooks';
export const SanctionSatusView:FC<{}> = props => export const SanctionSatusView:FC<{}> = props =>
{ {
const [ sanctionInfo, setSanctionInfo ] = useState<SanctionStatusMessageParser>(null); const { sanctionInfo = null, setSanctionInfo = null } = useHelp();
const onSanctionStatusEvent = useCallback((event: SanctionStatusEvent) => const sanctionLocalization = (param: string, sanctionName: string, length?: number) =>
{
const parser = event.getParser();
if(!parser) return;
setSanctionInfo(parser);
}, []);
useMessageEvent(SanctionStatusEvent, onSanctionStatusEvent);
const sanctionLocalization = useCallback((param: string, sanctionName: string, length?: number) =>
{ {
let localizationName = `help.sanction.${ param }`; let localizationName = `help.sanction.${ param }`;
@ -44,7 +32,7 @@ export const SanctionSatusView:FC<{}> = props =>
} }
return LocalizeText(localizationName, [ 'hours' ], [ length.toString() ]); return LocalizeText(localizationName, [ 'hours' ], [ length.toString() ]);
}, []); }
if(!sanctionInfo) return null; if(!sanctionInfo) return null;

View File

@ -1,52 +1,57 @@
import { RoomObjectType } from '@nitrots/nitro-renderer'; import { RoomObjectType } from '@nitrots/nitro-renderer';
import { FC, useMemo, useState } from 'react'; import { FC, useMemo, useState } from 'react';
import { ChatEntryType, IChatEntry, LocalizeText } from '../../../api'; import { ChatEntryType, IChatEntry, LocalizeText, ReportState, ReportType } from '../../../api';
import { AutoGrid, Button, Column, Flex, LayoutGridItem, Text } from '../../../common'; import { AutoGrid, Button, Column, Flex, LayoutGridItem, Text } from '../../../common';
import { useChatHistory } from '../../../hooks'; import { useChatHistory, useHelp } from '../../../hooks';
import { useHelpContext } from '../HelpContext';
export const SelectReportedChatsView: FC<{}> = props => export const SelectReportedChatsView: FC<{}> = props =>
{ {
const [ selectedChats, setSelectedChats ] = useState<Map<number, IChatEntry>>(new Map()); const [ selectedChats, setSelectedChats ] = useState<IChatEntry[]>([]);
const { chatHistory = [] } = useChatHistory(); const { activeReport = null, setActiveReport = null } = useHelp();
const { helpReportState = null, setHelpReportState = null } = useHelpContext(); const { chatHistory = [], messengerHistory = [] } = useChatHistory();
const { reportedUserId = -1 } = helpReportState;
const userChats = useMemo(() => const userChats = useMemo(() =>
{ {
return chatHistory.filter(chat => (chat.type === ChatEntryType.TYPE_CHAT) && (chat.entityId === reportedUserId) && (chat.entityType === RoomObjectType.USER)); switch(activeReport.reportType)
}, [ chatHistory, reportedUserId ]); {
case ReportType.BULLY:
case ReportType.EMERGENCY:
return chatHistory.filter(chat => (chat.type === ChatEntryType.TYPE_CHAT) && (chat.entityId === activeReport.reportedUserId) && (chat.entityType === RoomObjectType.USER));
case ReportType.IM:
return messengerHistory.filter(chat => (chat.entityId === activeReport.reportedUserId) && (chat.type === ChatEntryType.TYPE_IM));
}
}, [ activeReport, chatHistory, messengerHistory ]);
const selectChat = (chatEntry: IChatEntry) => const selectChat = (chatEntry: IChatEntry) =>
{ {
const chats = new Map(selectedChats); setSelectedChats(prevValue =>
{
const newValue = [ ...prevValue ];
const index = newValue.indexOf(chatEntry);
if(chats.has(chatEntry.id)) chats.delete(chatEntry.id); if(index >= 0) newValue.splice(index, 1);
else chats.set(chatEntry.id, chatEntry); else newValue.push(chatEntry);
setSelectedChats(chats); return newValue;
});
} }
const submitChats = () => const submitChats = () =>
{ {
if(!selectedChats || (selectedChats.size <= 0)) return; if(!selectedChats || (selectedChats.length <= 0)) return;
setHelpReportState(prevValue => setActiveReport(prevValue =>
{ {
const reportedChats = Array.from(selectedChats.values()); return { ...prevValue, reportedChats: selectedChats, currentStep: ReportState.SELECT_TOPICS };
const currentStep = 3;
return { ...prevValue, reportedChats, currentStep };
}); });
} }
const back = () => const back = () =>
{ {
setHelpReportState(prevValue => setActiveReport(prevValue =>
{ {
const currentStep = (prevValue.currentStep - 1); return { ...prevValue, currentStep: (prevValue.currentStep - 1) };
return { ...prevValue, currentStep };
}); });
} }
@ -64,7 +69,7 @@ export const SelectReportedChatsView: FC<{}> = props =>
{ userChats.map((chat, index) => { userChats.map((chat, index) =>
{ {
return ( return (
<LayoutGridItem key={ chat.id } onClick={ event => selectChat(chat) } itemActive={ selectedChats.has(chat.id) }> <LayoutGridItem key={ chat.id } onClick={ event => selectChat(chat) } itemActive={ (selectedChats.indexOf(chat) >= 0) }>
<Text>{ chat.message }</Text> <Text>{ chat.message }</Text>
</LayoutGridItem> </LayoutGridItem>
); );
@ -72,10 +77,10 @@ export const SelectReportedChatsView: FC<{}> = props =>
</AutoGrid> } </AutoGrid> }
</Column> </Column>
<Flex gap={ 2 } justifyContent="between"> <Flex gap={ 2 } justifyContent="between">
<Button variant="secondary" onClick={ back }> <Button variant="secondary" onClick={ back } disabled={ (activeReport.reportType === ReportType.IM) }>
{ LocalizeText('generic.back') } { LocalizeText('generic.back') }
</Button> </Button>
<Button disabled={ (selectedChats.size <= 0) } onClick={ submitChats }> <Button disabled={ (selectedChats.length <= 0) } onClick={ submitChats }>
{ LocalizeText('help.emergency.main.submit.button') } { LocalizeText('help.emergency.main.submit.button') }
</Button> </Button>
</Flex> </Flex>

View File

@ -1,15 +1,14 @@
import { RoomObjectType } from '@nitrots/nitro-renderer'; import { RoomObjectType } from '@nitrots/nitro-renderer';
import { FC, useMemo, useState } from 'react'; import { FC, useMemo, useState } from 'react';
import { ChatEntryType, GetSessionDataManager, IReportedUser, LocalizeText } from '../../../api'; import { ChatEntryType, GetSessionDataManager, IReportedUser, LocalizeText, ReportState } from '../../../api';
import { AutoGrid, Button, Column, Flex, LayoutGridItem, Text } from '../../../common'; import { AutoGrid, Button, Column, Flex, LayoutGridItem, Text } from '../../../common';
import { useChatHistory } from '../../../hooks'; import { useChatHistory, useHelp } from '../../../hooks';
import { useHelpContext } from '../HelpContext';
export const SelectReportedUserView: FC<{}> = props => export const SelectReportedUserView: FC<{}> = props =>
{ {
const [ selectedUserId, setSelectedUserId ] = useState(-1); const [ selectedUserId, setSelectedUserId ] = useState(-1);
const { chatHistory = [] } = useChatHistory(); const { chatHistory = [] } = useChatHistory();
const { helpReportState = null, setHelpReportState = null } = useHelpContext(); const { activeReport = null, setActiveReport = null } = useHelp();
const availableUsers = useMemo(() => const availableUsers = useMemo(() =>
{ {
@ -17,13 +16,7 @@ export const SelectReportedUserView: FC<{}> = props =>
chatHistory.forEach(chat => chatHistory.forEach(chat =>
{ {
if((chat.type === ChatEntryType.TYPE_CHAT) && (chat.entityType === RoomObjectType.USER) && (chat.entityId !== GetSessionDataManager().userId)) if((chat.type === ChatEntryType.TYPE_CHAT) && (chat.entityType === RoomObjectType.USER) && (chat.entityId !== GetSessionDataManager().userId) && !users.has(chat.entityId)) users.set(chat.entityId, { id: chat.entityId, username: chat.name });
{
if(!users.has(chat.entityId))
{
users.set(chat.entityId, { id: chat.entityId, username: chat.name })
}
}
}); });
return Array.from(users.values()); return Array.from(users.values());
@ -33,28 +26,27 @@ export const SelectReportedUserView: FC<{}> = props =>
{ {
if(selectedUserId <= 0) return; if(selectedUserId <= 0) return;
setHelpReportState(prevValue => setActiveReport(prevValue =>
{ {
const reportedUserId = selectedUserId; return { ...prevValue, reportedUserId: selectedUserId, currentStep: ReportState.SELECT_CHATS };
const currentStep = 2;
return { ...prevValue, reportedUserId, currentStep };
}); });
} }
const selectUser = (userId: number) => const selectUser = (userId: number) =>
{ {
if(selectedUserId === userId) setSelectedUserId(-1); setSelectedUserId(prevValue =>
else setSelectedUserId(userId); {
if(userId === prevValue) return -1;
return userId;
});
} }
const back = () => const back = () =>
{ {
setHelpReportState(prevValue => setActiveReport(prevValue =>
{ {
const currentStep = (prevValue.currentStep - 1); return { ...prevValue, currentStep: (prevValue.currentStep - 1) };
return { ...prevValue, currentStep };
}); });
} }

View File

@ -1,14 +1,14 @@
import { FC, useMemo, useState } from 'react'; import { FC, useMemo, useState } from 'react';
import { LocalizeText } from '../../../api'; import { LocalizeText, ReportState } from '../../../api';
import { Button, Column, Flex, Text } from '../../../common'; import { Button, Column, Flex, Text } from '../../../common';
import { useHelp } from '../../../hooks';
import { GetCfhCategories } from '../../mod-tools/common/GetCFHCategories'; import { GetCfhCategories } from '../../mod-tools/common/GetCFHCategories';
import { useHelpContext } from '../HelpContext';
export const SelectTopicView: FC<{}> = props => export const SelectTopicView: FC<{}> = props =>
{ {
const { setHelpReportState = null } = useHelpContext();
const [ selectedCategory, setSelectedCategory ] = useState(-1); const [ selectedCategory, setSelectedCategory ] = useState(-1);
const [ selectedTopic, setSelectedTopic ] = useState(-1); const [ selectedTopic, setSelectedTopic ] = useState(-1);
const { setActiveReport = null } = useHelp();
const cfhCategories = useMemo(() => GetCfhCategories(), []); const cfhCategories = useMemo(() => GetCfhCategories(), []);
@ -16,23 +16,17 @@ export const SelectTopicView: FC<{}> = props =>
{ {
if((selectedCategory < 0) || (selectedTopic < 0)) return; if((selectedCategory < 0) || (selectedTopic < 0)) return;
setHelpReportState(prevValue => setActiveReport(prevValue =>
{ {
const cfhCategory = selectedCategory; return { ...prevValue, cfhCategory: selectedCategory, cfhTopic: cfhCategories[selectedCategory].topics[selectedTopic].id, currentStep: ReportState.INPUT_REPORT_MESSAGE };
const cfhTopic = cfhCategories[selectedCategory].topics[selectedTopic].id;
const currentStep = 4;
return { ...prevValue, cfhCategory, cfhTopic, currentStep };
}); });
} }
const back = () => const back = () =>
{ {
setHelpReportState(prevValue => setActiveReport(prevValue =>
{ {
const currentStep = (prevValue.currentStep - 1); return { ...prevValue, currentStep: (prevValue.currentStep - 1) };
return { ...prevValue, currentStep };
}); });
} }

View File

@ -1,8 +1,8 @@
import { ModMessageMessageComposer } from '@nitrots/nitro-renderer'; import { ModMessageMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react'; import { FC, useCallback, useState } from 'react';
import { DispatchUiEvent, SendMessageComposer } from '../../../../api'; import { SendMessageComposer } from '../../../../api';
import { Button, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; import { Button, DraggableWindowPosition, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
import { NotificationAlertEvent } from '../../../../events'; import { useNotification } from '../../../../hooks';
import { ISelectedUser } from '../../common/ISelectedUser'; import { ISelectedUser } from '../../common/ISelectedUser';
interface ModToolsUserSendMessageViewProps interface ModToolsUserSendMessageViewProps
@ -15,12 +15,13 @@ export const ModToolsUserSendMessageView: FC<ModToolsUserSendMessageViewProps> =
{ {
const { user = null, onCloseClick = null } = props; const { user = null, onCloseClick = null } = props;
const [ message, setMessage ] = useState(''); const [ message, setMessage ] = useState('');
const { simpleAlert = null } = useNotification();
const sendMessage = useCallback(() => const sendMessage = useCallback(() =>
{ {
if(message.trim().length === 0) if(message.trim().length === 0)
{ {
DispatchUiEvent(new NotificationAlertEvent([ 'Please write a message to user.' ], null, null, null, 'Error', null)); simpleAlert('Please write a message to user.', null, null, null, 'Error', null);
return; return;
} }
@ -28,7 +29,7 @@ export const ModToolsUserSendMessageView: FC<ModToolsUserSendMessageViewProps> =
SendMessageComposer(new ModMessageMessageComposer(user.userId, message, -999)); SendMessageComposer(new ModMessageMessageComposer(user.userId, message, -999));
onCloseClick(); onCloseClick();
}, [ message, user, onCloseClick ]); }, [ message, user, onCloseClick, simpleAlert ]);
if(!user) return null; if(!user) return null;

View File

@ -1,10 +1,9 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { RoomControllerLevel, RoomObjectCategory, RoomObjectVariable, RoomUnitGiveHandItemComposer, SetRelationshipStatusComposer, TradingOpenComposer } from '@nitrots/nitro-renderer'; import { RoomControllerLevel, RoomObjectCategory, RoomObjectVariable, RoomUnitGiveHandItemComposer, SetRelationshipStatusComposer, TradingOpenComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useMemo, useState } from 'react'; import { FC, useEffect, useMemo, useState } from 'react';
import { AvatarInfoUser, CreateLinkEvent, DispatchUiEvent, GetOwnRoomObject, GetSessionDataManager, GetUserProfile, LocalizeText, MessengerFriend, RoomWidgetUpdateChatInputContentEvent, SendMessageComposer } from '../../../../../api'; import { AvatarInfoUser, CreateLinkEvent, DispatchUiEvent, GetOwnRoomObject, GetSessionDataManager, GetUserProfile, LocalizeText, MessengerFriend, ReportType, RoomWidgetUpdateChatInputContentEvent, SendMessageComposer } from '../../../../../api';
import { Base, Flex } from '../../../../../common'; import { Base, Flex } from '../../../../../common';
import { HelpReportUserEvent } from '../../../../../events'; import { useFriends, useHelp, useRoom } from '../../../../../hooks';
import { useFriends, useRoom } from '../../../../../hooks';
import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView'; import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView';
import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView'; import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView';
import { ContextMenuView } from '../../context-menu/ContextMenuView'; import { ContextMenuView } from '../../context-menu/ContextMenuView';
@ -29,6 +28,7 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
const [ mode, setMode ] = useState(MODE_NORMAL); const [ mode, setMode ] = useState(MODE_NORMAL);
const [ respectsLeft, setRespectsLeft ] = useState(0); const [ respectsLeft, setRespectsLeft ] = useState(0);
const { canRequestFriend = null } = useFriends(); const { canRequestFriend = null } = useFriends();
const { report = null } = useHelp();
const { roomSession = null } = useRoom(); const { roomSession = null } = useRoom();
const isShowGiveRights = useMemo(() => const isShowGiveRights = useMemo(() =>
@ -159,7 +159,7 @@ export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = p
SendMessageComposer(new TradingOpenComposer(avatarInfo.roomIndex)); SendMessageComposer(new TradingOpenComposer(avatarInfo.roomIndex));
break; break;
case 'report': case 'report':
DispatchUiEvent(new HelpReportUserEvent(avatarInfo.webID)); report(ReportType.BULLY, { reportedUserId: avatarInfo.webID });
break; break;
case 'pass_hand_item': case 'pass_hand_item':
SendMessageComposer(new RoomUnitGiveHandItemComposer(avatarInfo.webID)); SendMessageComposer(new RoomUnitGiveHandItemComposer(avatarInfo.webID));

View File

@ -1,20 +0,0 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
export class HelpReportUserEvent extends NitroEvent
{
public static REPORT_USER: string = 'HCE_HELP_CENTER_REPORT_USER';
private _reportedUserId: number;
constructor(userId: number)
{
super(HelpReportUserEvent.REPORT_USER);
this._reportedUserId = userId;
}
public get reportedUserId(): number
{
return this._reportedUserId;
}
}

View File

@ -1,2 +1 @@
export * from './HelpNameChangeEvent'; export * from './HelpNameChangeEvent';
export * from './HelpReportUserEvent';

View File

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

View File

@ -1,55 +0,0 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
export class NotificationAlertEvent extends NitroEvent
{
public static ALERT: string = 'NAE_ALERT';
private _messages: string[];
private _alertType: string;
private _clickUrl: string;
private _clickUrlText: string;
private _title: string;
private _imageUrl: string;
constructor(messages: string[], alertType: string = null, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null)
{
super(NotificationAlertEvent.ALERT);
this._messages = messages;
this._alertType = alertType;
this._clickUrl = clickUrl;
this._clickUrlText = clickUrlText;
this._title = title;
this._imageUrl = imageUrl;
}
public get messages(): string[]
{
return this._messages;
}
public get alertType(): string
{
return this._alertType;
}
public get clickUrl(): string
{
return this._clickUrl;
}
public get clickUrlText(): string
{
return this._clickUrlText;
}
public get title(): string
{
return this._title;
}
public get imageUrl(): string
{
return this._imageUrl;
}
}

View File

@ -1,41 +0,0 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
export class NotificationBubbleEvent extends NitroEvent
{
public static NEW_BUBBLE: string = 'NBE_NEW_BUBBLE';
private _message: string;
private _notificationType: string;
private _imageUrl: string;
private _linkUrl: string;
constructor(message: string, notificationType: string, imageUrl: string, linkUrl: string)
{
super(NotificationBubbleEvent.NEW_BUBBLE);
this._message = message;
this._notificationType = notificationType;
this._imageUrl = imageUrl;
this._linkUrl = linkUrl;
}
public get message(): string
{
return this._message;
}
public get notificationType(): string
{
return this._notificationType;
}
public get imageUrl(): string
{
return this._imageUrl;
}
public get linkUrl(): string
{
return this._linkUrl;
}
}

View File

@ -1,34 +0,0 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
export class NotificationCenterAlertEvent extends NitroEvent
{
public static HOTEL_ALERT: string = 'NCAE_HOTEL_ALERT';
private _message: string[];
private _clickUrl: string;
private _headerText: string;
constructor(type: string, message: string[], clickUrl = null, headerText = null)
{
super(type);
this._message = message;
this._clickUrl = clickUrl;
this._headerText = headerText;
}
public get message(): string[]
{
return this._message;
}
public get clickUrl(): string
{
return this._clickUrl;
}
public get headerText(): string
{
return this._headerText;
}
}

View File

@ -1,9 +0,0 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
export class NotificationCenterEvent extends NitroEvent
{
public static SHOW_NOTIFICATION_CENTER: string = 'NCE_SHOW_NOTIFICATION_CENTER';
public static HIDE_NOTIFICATION_CENTER: string = 'NCE_HIDE_NOTIFICATION_CENTER';
public static TOGGLE_NOTIFICATION_CENTER: string = 'NCE_TOGGLE_NOTIFICATION_CENTER';
public static ADD_NOTIFICATION: string = 'NCE_ADD_NOTIFICATION';
}

View File

@ -1,62 +0,0 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
export class NotificationConfirmEvent extends NitroEvent
{
public static CONFIRM: string = 'NCE_CONFIRM';
private _confirmType: string;
private _message: string;
private _onConfirm: Function;
private _onCancel: Function;
private _confirmText: string;
private _cancelText: string;
private _title: string;
constructor(confirmType: string, message: string, onConfirm: Function, onCancel: Function, confirmText: string, cancelText: string, title: string)
{
super(NotificationConfirmEvent.CONFIRM);
this._confirmType = confirmType;
this._message = message;
this._onConfirm = onConfirm;
this._onCancel = onCancel;
this._confirmText = confirmText;
this._cancelText = cancelText;
this._title = title;
}
public get confirmType(): string
{
return this._confirmType;
}
public get message(): string
{
return this._message;
}
public get onConfirm(): Function
{
return this._onConfirm;
}
public get onCancel(): Function
{
return this._onCancel;
}
public get confirmText(): string
{
return this._confirmText;
}
public get cancelText(): string
{
return this._cancelText;
}
public get title(): string
{
return this._title;
}
}

View File

@ -1,5 +0,0 @@
export * from './NotificationAlertEvent';
export * from './NotificationBubbleEvent';
export * from './NotificationCenterAlertEvent';
export * from './NotificationCenterEvent';
export * from './NotificationConfirmEvent';

View File

@ -1,18 +1,21 @@
import { GetGuestRoomResultEvent, RoomSessionChatEvent, RoomSessionEvent } from '@nitrots/nitro-renderer'; import { GetGuestRoomResultEvent, NewConsoleMessageEvent, RoomInviteEvent, RoomSessionChatEvent, RoomSessionEvent } from '@nitrots/nitro-renderer';
import { useState } from 'react'; import { useState } from 'react';
import { useBetween } from 'use-between'; import { useBetween } from 'use-between';
import { ChatEntryType, ChatHistoryCurrentDate, GetRoomSession, IChatEntry, IRoomHistoryEntry } from '../../api'; import { ChatEntryType, ChatHistoryCurrentDate, GetRoomSession, IChatEntry, IRoomHistoryEntry, MessengerHistoryCurrentDate } from '../../api';
import { useMessageEvent, useRoomSessionManagerEvent } from '../events'; import { useMessageEvent, useRoomSessionManagerEvent } from '../events';
const CHAT_HISTORY_MAX = 1000; const CHAT_HISTORY_MAX = 1000;
const ROOM_HISTORY_MAX = 10; const ROOM_HISTORY_MAX = 10;
const MESSENGER_HISTORY_MAX = 1000;
let CHAT_HISTORY_COUNTER: number = 0; let CHAT_HISTORY_COUNTER: number = 0;
let MESSENGER_HISTORY_COUNTER: number = 0;
const useChatHistoryState = () => const useChatHistoryState = () =>
{ {
const [ chatHistory, setChatHistory ] = useState<IChatEntry[]>([]); const [ chatHistory, setChatHistory ] = useState<IChatEntry[]>([]);
const [ roomHistory, setRoomHistory ] = useState<IRoomHistoryEntry[]>([]); const [ roomHistory, setRoomHistory ] = useState<IRoomHistoryEntry[]>([]);
const [ messengerHistory, setMessengerHistory ] = useState<IChatEntry[]>([]);
const [ needsRoomInsert, setNeedsRoomInsert ] = useState(false); const [ needsRoomInsert, setNeedsRoomInsert ] = useState(false);
const addChatEntry = (entry: IChatEntry) => const addChatEntry = (entry: IChatEntry) =>
@ -45,6 +48,22 @@ const useChatHistoryState = () =>
}); });
} }
const addMessengerEntry = (entry: IChatEntry) =>
{
entry.id = MESSENGER_HISTORY_COUNTER++;
setMessengerHistory(prevValue =>
{
const newValue = [ ...prevValue ];
newValue.push(entry);
if(newValue.length > MESSENGER_HISTORY_MAX) newValue.shift();
return newValue;
});
}
useRoomSessionManagerEvent<RoomSessionChatEvent>(RoomSessionChatEvent.CHAT_EVENT, event => useRoomSessionManagerEvent<RoomSessionChatEvent>(RoomSessionChatEvent.CHAT_EVENT, event =>
{ {
const roomSession = GetRoomSession(); const roomSession = GetRoomSession();
@ -78,7 +97,21 @@ const useChatHistoryState = () =>
setNeedsRoomInsert(false); setNeedsRoomInsert(false);
}); });
return { chatHistory, roomHistory }; useMessageEvent<NewConsoleMessageEvent>(NewConsoleMessageEvent, event =>
{
const parser = event.getParser();
addMessengerEntry({ id: -1, entityId: parser.senderId, name: '', message: parser.messageText, roomId: -1, timestamp: MessengerHistoryCurrentDate(parser.secondsSinceSent), type: ChatEntryType.TYPE_IM });
});
useMessageEvent<RoomInviteEvent>(RoomInviteEvent, event =>
{
const parser = event.getParser();
addMessengerEntry({ id: -1, entityId: parser.senderId, name: '', message: parser.messageText, roomId: -1, timestamp: MessengerHistoryCurrentDate(), type: ChatEntryType.TYPE_IM });
});
return { chatHistory, roomHistory, messengerHistory };
} }
export const useChatHistory = () => useBetween(useChatHistoryState); export const useChatHistory = () => useBetween(useChatHistoryState);

1
src/hooks/help/index.ts Normal file
View File

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

144
src/hooks/help/useHelp.ts Normal file
View File

@ -0,0 +1,144 @@
import { CallForHelpDisabledNotifyMessageEvent, CallForHelpPendingCallsDeletedMessageEvent, CallForHelpPendingCallsMessageEvent, CallForHelpReplyMessageEvent, CallForHelpResultMessageEvent, DeletePendingCallsForHelpMessageComposer, GetPendingCallsForHelpMessageComposer, IssueCloseNotificationMessageEvent, SanctionStatusEvent, SanctionStatusMessageParser } from '@nitrots/nitro-renderer';
import { useState } from 'react';
import { useBetween } from 'use-between';
import { CallForHelpResult, GetCloseReasonKey, IHelpReport, LocalizeText, NotificationAlertType, ReportState, ReportType, SendMessageComposer } from '../../api';
import { useMessageEvent } from '../events';
import { useNotification } from '../notification';
const useHelpState = () =>
{
const [ activeReport, setActiveReport ] = useState<IHelpReport>(null);
const [ sanctionInfo, setSanctionInfo ] = useState<SanctionStatusMessageParser>(null);
const { simpleAlert = null, showConfirm = null } = useNotification();
const report = (type: number, options: Partial<IHelpReport>) =>
{
const newReport: IHelpReport = {
reportType: type,
reportedUserId: -1,
reportedChats: [],
cfhCategory: -1,
cfhTopic: -1,
roomId: -1,
roomName: '',
messageId: -1,
threadId: -1,
groupId: -1,
extraData: '',
roomObjectId: -1,
message: '',
currentStep: 0
};
switch(type)
{
case ReportType.BULLY:
case ReportType.EMERGENCY:
case ReportType.IM:
newReport.reportedUserId = options.reportedUserId;
newReport.currentStep = ReportState.SELECT_CHATS;
break;
case ReportType.ROOM:
newReport.roomId = options.roomId;
newReport.roomName = options.roomName;
newReport.currentStep = ReportState.SELECT_TOPICS;
break;
case ReportType.THREAD:
newReport.groupId = options.groupId;
newReport.threadId = options.threadId;
newReport.currentStep = ReportState.SELECT_TOPICS;
break;
case ReportType.MESSAGE:
newReport.groupId = options.groupId;
newReport.threadId = options.threadId;
newReport.messageId = options.messageId;
newReport.currentStep = ReportState.SELECT_TOPICS;
break;
case ReportType.PHOTO:
break;
case ReportType.GUIDE:
break;
}
setActiveReport(newReport);
}
useMessageEvent<CallForHelpResultMessageEvent>(CallForHelpResultMessageEvent, event =>
{
const parser = event.getParser();
let message = parser.messageText;
switch(parser.resultType)
{
case CallForHelpResult.TOO_MANY_PENDING_CALLS_CODE:
SendMessageComposer(new GetPendingCallsForHelpMessageComposer());
simpleAlert(LocalizeText('help.cfh.error.pending'), NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.error.title'));
break;
case CallForHelpResult.HAS_ABUSIVE_CALL_CODE:
simpleAlert(LocalizeText('help.cfh.error.abusive'), NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.error.title'));
break;
default:
if(message.trim().length === 0)
{
message = LocalizeText('help.cfh.sent.text');
}
simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.sent.title'));
}
});
useMessageEvent<IssueCloseNotificationMessageEvent>(IssueCloseNotificationMessageEvent, event =>
{
const parser = event.getParser();
const message = parser.messageText.length === 0 ? LocalizeText('help.cfh.closed.' + GetCloseReasonKey(parser.closeReason)) : parser.messageText;
simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('mod.alert.title'));
});
useMessageEvent<CallForHelpPendingCallsMessageEvent>(CallForHelpPendingCallsMessageEvent, event =>
{
const parser = event.getParser();
if(parser.count > 0)
{
showConfirm(LocalizeText('help.emergency.pending.title') + '\n' + parser.pendingCalls[0].message, () =>
{
SendMessageComposer(new DeletePendingCallsForHelpMessageComposer());
}, null, LocalizeText('help.emergency.pending.button.discard'), LocalizeText('help.emergency.pending.button.keep'), LocalizeText('help.emergency.pending.message.subtitle'));
}
});
useMessageEvent<CallForHelpPendingCallsDeletedMessageEvent>(CallForHelpPendingCallsDeletedMessageEvent, event =>
{
const message = 'Your pending calls were deleted'; // todo: add localization
simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('mod.alert.title'));
});
useMessageEvent<CallForHelpReplyMessageEvent>(CallForHelpReplyMessageEvent, event =>
{
const parser = event.getParser();
simpleAlert(parser.message, NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.reply.title'));
});
useMessageEvent<CallForHelpDisabledNotifyMessageEvent>(CallForHelpDisabledNotifyMessageEvent, event =>
{
const parser = event.getParser();
simpleAlert(LocalizeText('help.emergency.global_mute.message'), NotificationAlertType.MODERATION, parser.infoUrl, LocalizeText('help.emergency.global_mute.link'), LocalizeText('help.emergency.global_mute.subtitle'))
});
useMessageEvent<SanctionStatusEvent>(SanctionStatusEvent, event =>
{
const parser = event.getParser();
setSanctionInfo(parser);
});
return { activeReport, setActiveReport, sanctionInfo, setSanctionInfo, report };
}
export const useHelp = () => useBetween(useHelpState);

View File

@ -7,6 +7,7 @@ export * from './events/core';
export * from './events/nitro'; export * from './events/nitro';
export * from './friends'; export * from './friends';
export * from './groups'; export * from './groups';
export * from './help';
export * from './inventory'; export * from './inventory';
export * from './navigator'; export * from './navigator';
export * from './notification'; export * from './notification';