mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
357 lines
16 KiB
TypeScript
357 lines
16 KiB
TypeScript
import { AddLinkEventTracker, GetSessionDataManager, GuideOnDutyStatusMessageEvent, GuideSessionAttachedMessageEvent, GuideSessionDetachedMessageEvent, GuideSessionEndedMessageEvent, GuideSessionErrorMessageEvent, GuideSessionInvitedToGuideRoomMessageEvent, GuideSessionMessageMessageEvent, GuideSessionOnDutyUpdateMessageComposer, GuideSessionPartnerIsTypingMessageEvent, GuideSessionStartedMessageEvent, ILinkEventTracker, PerkAllowancesMessageEvent, PerkEnum, RemoveLinkEventTracker } from '@nitrots/nitro-renderer';
|
|
import { FC, useCallback, useEffect, useState } from 'react';
|
|
import { GetConfigurationValue, GuideSessionState, GuideToolMessage, GuideToolMessageGroup, LocalizeText, SendMessageComposer } from '../../api';
|
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
|
|
import { GuideToolEvent } from '../../events';
|
|
import { useMessageEvent, useNotification, useUiEvent } from '../../hooks';
|
|
import { GuideToolAcceptView } from './views/GuideToolAcceptView';
|
|
import { GuideToolMenuView } from './views/GuideToolMenuView';
|
|
import { GuideToolOngoingView } from './views/GuideToolOngoingView';
|
|
import { GuideToolUserCreateRequestView } from './views/GuideToolUserCreateRequestView';
|
|
import { GuideToolUserFeedbackView } from './views/GuideToolUserFeedbackView';
|
|
import { GuideToolUserNoHelpersView } from './views/GuideToolUserNoHelpersView';
|
|
import { GuideToolUserPendingView } from './views/GuideToolUserPendingView';
|
|
import { GuideToolUserSomethingWrogView } from './views/GuideToolUserSomethingWrogView';
|
|
import { GuideToolUserThanksView } from './views/GuideToolUserThanksView';
|
|
|
|
export const GuideToolView: FC<{}> = props =>
|
|
{
|
|
const [ isVisible, setIsVisible ] = useState<boolean>(false);
|
|
const [ headerText, setHeaderText ] = useState<string>(LocalizeText('guide.help.guide.tool.title'));
|
|
const [ noCloseButton, setNoCloseButton ] = useState<boolean>(false);
|
|
const [ sessionState, setSessionState ] = useState<string>(GuideSessionState.GUIDE_TOOL_MENU);
|
|
|
|
const [ isOnDuty, setIsOnDuty ] = useState<boolean>(false);
|
|
const [ isHandlingBullyReports, setIsHandlingBullyReports ] = useState<boolean>(false);
|
|
const [ isHandlingGuideRequests, setIsHandlingGuideRequests ] = useState<boolean>(false);
|
|
const [ isHandlingHelpRequests, setIsHandlingHelpRequests ] = useState<boolean>(false);
|
|
|
|
const [ helpersOnDuty, setHelpersOnDuty ] = useState<number>(0);
|
|
const [ guidesOnDuty, setGuidesOnDuty ] = useState<number>(0);
|
|
const [ guardiansOnDuty, setGuardiansOnDuty ] = useState<number>(0);
|
|
|
|
const [ userRequest, setUserRequest ] = useState<string>('');
|
|
|
|
const [ helpRequestDescription, setHelpRequestDescription ] = useState<string>(null);
|
|
const [ helpRequestAverageTime, setHelpRequestAverageTime ] = useState<number>(0);
|
|
|
|
const [ ongoingUserId, setOngoingUserId ] = useState<number>(0);
|
|
const [ ongoingUsername, setOngoingUsername ] = useState<string>(null);
|
|
const [ ongoingFigure, setOngoingFigure ] = useState<string>(null);
|
|
const [ ongoingIsTyping, setOngoingIsTyping ] = useState<boolean>(false);
|
|
const [ ongoingMessageGroups, setOngoingMessageGroups ] = useState<GuideToolMessageGroup[]>([]);
|
|
|
|
const { simpleAlert = null } = useNotification();
|
|
|
|
const updateSessionState = useCallback((newState: string, replacement?: string) =>
|
|
{
|
|
switch(newState)
|
|
{
|
|
case GuideSessionState.GUIDE_TOOL_MENU:
|
|
setHeaderText(LocalizeText('guide.help.guide.tool.title'));
|
|
setNoCloseButton(false);
|
|
break;
|
|
case GuideSessionState.GUIDE_ACCEPT:
|
|
setHeaderText(LocalizeText('guide.help.request.guide.accept.title'));
|
|
setNoCloseButton(true);
|
|
break;
|
|
case GuideSessionState.GUIDE_ONGOING:
|
|
setHeaderText(LocalizeText('guide.help.request.guide.ongoing.title', [ 'name' ], [ replacement ]));
|
|
setNoCloseButton(true);
|
|
break;
|
|
case GuideSessionState.USER_CREATE:
|
|
setHeaderText(LocalizeText('guide.help.request.user.create.title'));
|
|
setNoCloseButton(false);
|
|
break;
|
|
case GuideSessionState.USER_PENDING:
|
|
setHeaderText(LocalizeText('guide.help.request.user.pending.title'));
|
|
setNoCloseButton(true);
|
|
break;
|
|
case GuideSessionState.USER_ONGOING:
|
|
setHeaderText(LocalizeText('guide.help.request.user.ongoing.title', [ 'name' ], [ replacement ]));
|
|
setNoCloseButton(true);
|
|
break;
|
|
case GuideSessionState.USER_FEEDBACK:
|
|
setHeaderText(LocalizeText('guide.help.request.user.feedback.title'));
|
|
setNoCloseButton(true);
|
|
break;
|
|
case GuideSessionState.USER_THANKS:
|
|
setHeaderText(LocalizeText('guide.help.request.user.thanks.title'));
|
|
setNoCloseButton(false);
|
|
break;
|
|
case GuideSessionState.USER_NO_HELPERS:
|
|
setHeaderText(LocalizeText('guide.help.request.no_tour_guides.heading'));
|
|
setNoCloseButton(false);
|
|
break;
|
|
case GuideSessionState.USER_SOMETHING_WRONG:
|
|
setHeaderText(LocalizeText('guide.help.request.user.guide.disconnected.error.heading'));
|
|
setNoCloseButton(false);
|
|
break;
|
|
}
|
|
|
|
setSessionState(newState);
|
|
setIsVisible(true);
|
|
}, []);
|
|
|
|
const onGuideToolEvent = useCallback((event: GuideToolEvent) =>
|
|
{
|
|
switch(event.type)
|
|
{
|
|
case GuideToolEvent.SHOW_GUIDE_TOOL:
|
|
setIsVisible(true);
|
|
return;
|
|
case GuideToolEvent.HIDE_GUIDE_TOOL:
|
|
setIsVisible(false);
|
|
return;
|
|
case GuideToolEvent.TOGGLE_GUIDE_TOOL:
|
|
setIsVisible(value => !value);
|
|
return;
|
|
case GuideToolEvent.CREATE_HELP_REQUEST:
|
|
updateSessionState(GuideSessionState.USER_CREATE);
|
|
return;
|
|
}
|
|
}, [ updateSessionState ]);
|
|
|
|
useUiEvent(GuideToolEvent.SHOW_GUIDE_TOOL, onGuideToolEvent);
|
|
useUiEvent(GuideToolEvent.HIDE_GUIDE_TOOL, onGuideToolEvent);
|
|
useUiEvent(GuideToolEvent.TOGGLE_GUIDE_TOOL, onGuideToolEvent);
|
|
useUiEvent(GuideToolEvent.CREATE_HELP_REQUEST, onGuideToolEvent);
|
|
|
|
useMessageEvent<PerkAllowancesMessageEvent>(PerkAllowancesMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
if(!parser.isAllowed(PerkEnum.USE_GUIDE_TOOL) && isOnDuty)
|
|
{
|
|
setIsOnDuty(false);
|
|
SendMessageComposer(new GuideSessionOnDutyUpdateMessageComposer(false, false, false, false));
|
|
}
|
|
});
|
|
|
|
useMessageEvent<GuideOnDutyStatusMessageEvent>(GuideOnDutyStatusMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setIsOnDuty(parser.onDuty);
|
|
setGuidesOnDuty(parser.guidesOnDuty);
|
|
setHelpersOnDuty(parser.helpersOnDuty);
|
|
setGuardiansOnDuty(parser.guardiansOnDuty);
|
|
});
|
|
|
|
useMessageEvent<GuideSessionAttachedMessageEvent>(GuideSessionAttachedMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setHelpRequestDescription(parser.helpRequestDescription);
|
|
setHelpRequestAverageTime(parser.roleSpecificWaitTime);
|
|
|
|
if(parser.asGuide && isOnDuty) updateSessionState(GuideSessionState.GUIDE_ACCEPT);
|
|
|
|
if(!parser.asGuide) updateSessionState(GuideSessionState.USER_PENDING);
|
|
});
|
|
|
|
useMessageEvent<GuideSessionStartedMessageEvent>(GuideSessionStartedMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
if(isOnDuty)
|
|
{
|
|
setOngoingUserId(parser.requesterUserId);
|
|
setOngoingUsername(parser.requesterName);
|
|
setOngoingFigure(parser.requesterFigure);
|
|
updateSessionState(GuideSessionState.GUIDE_ONGOING, parser.requesterName);
|
|
}
|
|
else
|
|
{
|
|
setOngoingUserId(parser.guideUserId);
|
|
setOngoingUsername(parser.guideName);
|
|
setOngoingFigure(parser.guideFigure);
|
|
updateSessionState(GuideSessionState.USER_ONGOING, parser.guideName);
|
|
}
|
|
});
|
|
|
|
useMessageEvent<GuideSessionPartnerIsTypingMessageEvent>(GuideSessionPartnerIsTypingMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setOngoingIsTyping(parser.isTyping);
|
|
});
|
|
|
|
useMessageEvent<GuideSessionMessageMessageEvent>(GuideSessionMessageMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
const messageGroups = [ ...ongoingMessageGroups ];
|
|
|
|
let lastGroup = messageGroups[messageGroups.length - 1];
|
|
|
|
if(!lastGroup || lastGroup.userId !== parser.senderId)
|
|
{
|
|
lastGroup = new GuideToolMessageGroup(parser.senderId);
|
|
messageGroups.push(lastGroup);
|
|
}
|
|
|
|
lastGroup.addChat(new GuideToolMessage(parser.chatMessage));
|
|
setOngoingMessageGroups(messageGroups);
|
|
});
|
|
|
|
useMessageEvent<GuideSessionInvitedToGuideRoomMessageEvent>(GuideSessionInvitedToGuideRoomMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
if(parser.roomId !== 0)
|
|
{
|
|
const messageGroups = [ ...ongoingMessageGroups ];
|
|
|
|
let lastGroup = messageGroups[messageGroups.length - 1];
|
|
|
|
const guideId = (isOnDuty ? GetSessionDataManager().userId : ongoingUserId);
|
|
|
|
if(!lastGroup || lastGroup.userId !== guideId)
|
|
{
|
|
lastGroup = new GuideToolMessageGroup(guideId);
|
|
messageGroups.push(lastGroup);
|
|
}
|
|
|
|
lastGroup.addChat(new GuideToolMessage(parser.roomName, parser.roomId));
|
|
setOngoingMessageGroups(messageGroups);
|
|
}
|
|
});
|
|
|
|
useMessageEvent<GuideSessionEndedMessageEvent>(GuideSessionEndedMessageEvent, event =>
|
|
{
|
|
if(isOnDuty)
|
|
{
|
|
setOngoingUserId(0);
|
|
setOngoingUsername(null);
|
|
setOngoingFigure(null);
|
|
setOngoingIsTyping(false);
|
|
setOngoingMessageGroups([]);
|
|
updateSessionState(GuideSessionState.GUIDE_TOOL_MENU);
|
|
}
|
|
else
|
|
{
|
|
updateSessionState(GuideSessionState.USER_FEEDBACK);
|
|
}
|
|
});
|
|
|
|
useMessageEvent<GuideSessionErrorMessageEvent>(GuideSessionErrorMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
// SOMETHING_WRONG_REQUEST = 0, NO_HELPERS_AVAILABLE = 1, NO_GUARDIANS_AVAILABLE = 2
|
|
|
|
switch(parser['errorCode'])
|
|
{
|
|
case 0:
|
|
updateSessionState(GuideSessionState.USER_SOMETHING_WRONG);
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
updateSessionState(GuideSessionState.USER_NO_HELPERS);
|
|
break;
|
|
}
|
|
});
|
|
|
|
useMessageEvent<GuideSessionDetachedMessageEvent>(GuideSessionDetachedMessageEvent, event =>
|
|
{
|
|
setOngoingUserId(0);
|
|
setOngoingUsername(null);
|
|
setOngoingFigure(null);
|
|
setOngoingIsTyping(false);
|
|
setOngoingMessageGroups([]);
|
|
|
|
if(isOnDuty)
|
|
{
|
|
|
|
updateSessionState(GuideSessionState.GUIDE_TOOL_MENU);
|
|
}
|
|
else
|
|
{
|
|
updateSessionState(GuideSessionState.USER_THANKS);
|
|
}
|
|
});
|
|
|
|
useEffect(() =>
|
|
{
|
|
const linkTracker: ILinkEventTracker = {
|
|
linkReceived: (url: string) =>
|
|
{
|
|
const parts = url.split('/');
|
|
|
|
if(parts.length < 2) return;
|
|
|
|
switch(parts[1])
|
|
{
|
|
case 'tour':
|
|
//Create Tour Request
|
|
return;
|
|
}
|
|
},
|
|
eventUrlPrefix: 'help/'
|
|
};
|
|
|
|
AddLinkEventTracker(linkTracker);
|
|
|
|
return () => RemoveLinkEventTracker(linkTracker);
|
|
}, []);
|
|
|
|
const processAction = useCallback((action: string) =>
|
|
{
|
|
switch(action)
|
|
{
|
|
case 'close':
|
|
setIsVisible(false);
|
|
setUserRequest('');
|
|
setSessionState(GuideSessionState.GUIDE_TOOL_MENU);
|
|
return;
|
|
case 'toggle_duty':
|
|
if(!isHandlingBullyReports && !isHandlingGuideRequests && !isHandlingHelpRequests)
|
|
{
|
|
simpleAlert(LocalizeText('guide.help.guide.tool.noqueueselected.message'), null, null, null, LocalizeText('guide.help.guide.tool.noqueueselected.caption'), null);
|
|
return;
|
|
}
|
|
|
|
setIsOnDuty(v =>
|
|
{
|
|
SendMessageComposer(new GuideSessionOnDutyUpdateMessageComposer(!v, v ? false : isHandlingGuideRequests, v ? false : isHandlingHelpRequests, v ? false : isHandlingBullyReports));
|
|
return !v;
|
|
});
|
|
|
|
return;
|
|
case 'forum_link':
|
|
const url: string = GetConfigurationValue<string>('group.homepage.url', '').replace('%groupid%', GetConfigurationValue<string>('guide.help.alpha.groupid', '0'));
|
|
window.open(url);
|
|
return;
|
|
}
|
|
}, [ isHandlingBullyReports, isHandlingGuideRequests, isHandlingHelpRequests, simpleAlert ]);
|
|
|
|
if(!isVisible) return null;
|
|
|
|
return (
|
|
<NitroCardView className="nitro-guide-tool" theme="primary-slim">
|
|
<NitroCardHeaderView headerText={ headerText } noCloseButton={ noCloseButton } onCloseClick={ event => processAction('close') } />
|
|
<NitroCardContentView className="text-black">
|
|
{ (sessionState === GuideSessionState.GUIDE_TOOL_MENU) &&
|
|
<GuideToolMenuView guardiansOnDuty={ guardiansOnDuty } guidesOnDuty={ guidesOnDuty } helpersOnDuty={ helpersOnDuty } isHandlingBullyReports={ isHandlingBullyReports } isHandlingGuideRequests={ isHandlingGuideRequests } isHandlingHelpRequests={ isHandlingHelpRequests } isOnDuty={ isOnDuty } processAction={ processAction } setIsHandlingBullyReports={ setIsHandlingBullyReports } setIsHandlingGuideRequests={ setIsHandlingGuideRequests } setIsHandlingHelpRequests={ setIsHandlingHelpRequests } /> }
|
|
{ (sessionState === GuideSessionState.GUIDE_ACCEPT) &&
|
|
<GuideToolAcceptView helpRequestAverageTime={ helpRequestAverageTime } helpRequestDescription={ helpRequestDescription } /> }
|
|
{ [ GuideSessionState.GUIDE_ONGOING, GuideSessionState.USER_ONGOING ].includes(sessionState) &&
|
|
<GuideToolOngoingView isGuide={ isOnDuty } isTyping={ ongoingIsTyping } messageGroups={ ongoingMessageGroups } userFigure={ ongoingFigure } userId={ ongoingUserId } userName={ ongoingUsername } /> }
|
|
{ (sessionState === GuideSessionState.USER_CREATE) &&
|
|
<GuideToolUserCreateRequestView setUserRequest={ setUserRequest } userRequest={ userRequest } /> }
|
|
{ (sessionState === GuideSessionState.USER_PENDING) &&
|
|
<GuideToolUserPendingView helpRequestAverageTime={ helpRequestAverageTime } helpRequestDescription={ helpRequestDescription } /> }
|
|
{ (sessionState === GuideSessionState.USER_FEEDBACK) &&
|
|
<GuideToolUserFeedbackView userName={ ongoingUsername } /> }
|
|
{ (sessionState === GuideSessionState.USER_THANKS) &&
|
|
<GuideToolUserThanksView /> }
|
|
{ (sessionState === GuideSessionState.USER_NO_HELPERS) &&
|
|
<GuideToolUserNoHelpersView /> }
|
|
{ (sessionState === GuideSessionState.USER_SOMETHING_WRONG) &&
|
|
<GuideToolUserSomethingWrogView /> }
|
|
</NitroCardContentView>
|
|
</NitroCardView>
|
|
);
|
|
};
|