mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-20 07:26:19 +00:00
Merge branch 'Dev' into feature/pr-20260326
This commit is contained in:
+26
-4
@@ -1,17 +1,30 @@
|
|||||||
import { GetAssetManager, GetAvatarRenderManager, GetCommunication, GetConfiguration, GetLocalizationManager, GetRoomEngine, GetRoomSessionManager, GetSessionDataManager, GetSoundManager, GetStage, GetTexturePool, GetTicker, HabboWebTools, LegacyExternalInterface, LoadGameUrlEvent, NitroLogger, NitroVersion, PrepareRenderer } from '@nitrots/nitro-renderer';
|
import { GetAssetManager, GetAvatarRenderManager, GetCommunication, GetConfiguration, GetLocalizationManager, GetRoomEngine, GetRoomSessionManager, GetSessionDataManager, GetSoundManager, GetStage, GetTexturePool, GetTicker, HabboWebTools, LegacyExternalInterface, LoadGameUrlEvent, NitroEventType, NitroLogger, NitroVersion, PrepareRenderer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { GetUIVersion } from './api';
|
import { GetUIVersion } from './api';
|
||||||
import { Base } from './common';
|
import { Base } from './common';
|
||||||
import { LoadingView } from './components/loading/LoadingView';
|
import { LoadingView } from './components/loading/LoadingView';
|
||||||
import { MainView } from './components/MainView';
|
import { MainView } from './components/MainView';
|
||||||
import { ReconnectView } from './components/reconnect/ReconnectView';
|
import { ReconnectView } from './components/reconnect/ReconnectView';
|
||||||
import { useMessageEvent } from './hooks';
|
import { useMessageEvent, useNitroEvent } from './hooks';
|
||||||
|
|
||||||
NitroVersion.UI_VERSION = GetUIVersion();
|
NitroVersion.UI_VERSION = GetUIVersion();
|
||||||
|
|
||||||
export const App: FC<{}> = props =>
|
export const App: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ isReady, setIsReady ] = useState(false);
|
const [ isReady, setIsReady ] = useState(false);
|
||||||
|
const [ errorMessage, setErrorMessage ] = useState('');
|
||||||
|
const [ homeUrl, setHomeUrl ] = useState('');
|
||||||
|
|
||||||
|
const showSessionExpired = useCallback(() =>
|
||||||
|
{
|
||||||
|
const baseUrl = window.location.origin + '/';
|
||||||
|
setHomeUrl(baseUrl);
|
||||||
|
setErrorMessage('Your session has expired.\nPlease log in again to enter the hotel.');
|
||||||
|
setIsReady(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Listen for socket closed events (code 1000 "Bye" - server rejected SSO)
|
||||||
|
useNitroEvent(NitroEventType.SOCKET_CLOSED, showSessionExpired);
|
||||||
|
|
||||||
useMessageEvent<LoadGameUrlEvent>(LoadGameUrlEvent, event =>
|
useMessageEvent<LoadGameUrlEvent>(LoadGameUrlEvent, event =>
|
||||||
{
|
{
|
||||||
@@ -30,6 +43,14 @@ export const App: FC<{}> = props =>
|
|||||||
{
|
{
|
||||||
if(!window.NitroConfig) throw new Error('NitroConfig is not defined!');
|
if(!window.NitroConfig) throw new Error('NitroConfig is not defined!');
|
||||||
|
|
||||||
|
const ssoTicket = window.NitroConfig['sso.ticket'];
|
||||||
|
|
||||||
|
if(!ssoTicket || ssoTicket === '')
|
||||||
|
{
|
||||||
|
showSessionExpired();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const renderer = await PrepareRenderer({
|
const renderer = await PrepareRenderer({
|
||||||
width: Math.floor(width),
|
width: Math.floor(width),
|
||||||
height: Math.floor(height),
|
height: Math.floor(height),
|
||||||
@@ -83,6 +104,7 @@ export const App: FC<{}> = props =>
|
|||||||
catch(err)
|
catch(err)
|
||||||
{
|
{
|
||||||
NitroLogger.error(err);
|
NitroLogger.error(err);
|
||||||
|
showSessionExpired();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,7 +114,7 @@ export const App: FC<{}> = props =>
|
|||||||
return (
|
return (
|
||||||
<Base fit overflow="hidden" className={ !(window.devicePixelRatio % 1) && 'image-rendering-pixelated' }>
|
<Base fit overflow="hidden" className={ !(window.devicePixelRatio % 1) && 'image-rendering-pixelated' }>
|
||||||
{ !isReady &&
|
{ !isReady &&
|
||||||
<LoadingView /> }
|
<LoadingView isError={ errorMessage.length > 0 } message={ errorMessage } homeUrl={ homeUrl } /> }
|
||||||
{ isReady && <MainView /> }
|
{ isReady && <MainView /> }
|
||||||
<ReconnectView />
|
<ReconnectView />
|
||||||
<Base id="draggable-windows-container" />
|
<Base id="draggable-windows-container" />
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import { Base, Column, Text } from '../../common';
|
|||||||
interface LoadingViewProps {
|
interface LoadingViewProps {
|
||||||
isError?: boolean;
|
isError?: boolean;
|
||||||
message?: string;
|
message?: string;
|
||||||
|
homeUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LoadingView: FC<LoadingViewProps> = props => {
|
export const LoadingView: FC<LoadingViewProps> = props => {
|
||||||
const { isError = false, message = '' } = props;
|
const { isError = false, message = '', homeUrl = '' } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column fullHeight position="relative" className="relative z-[100] bg-[radial-gradient(#1d1a24,#003a6b)]">
|
<Column fullHeight position="relative" className="relative z-[100] bg-[radial-gradient(#1d1a24,#003a6b)]">
|
||||||
@@ -19,11 +20,16 @@ export const LoadingView: FC<LoadingViewProps> = props => {
|
|||||||
{ isError && (message && message.length) ?
|
{ isError && (message && message.length) ?
|
||||||
<Column alignItems="center" className="absolute bottom-[20px] left-1/2 z-[3] -translate-x-1/2 max-w-[80%]" gap={ 2 }>
|
<Column alignItems="center" className="absolute bottom-[20px] left-1/2 z-[3] -translate-x-1/2 max-w-[80%]" gap={ 2 }>
|
||||||
<Text fontSizeCustom={ 20 } variant="white" className="text-center [text-shadow:0px_4px_4px_rgba(0,0,0,0.25)]">
|
<Text fontSizeCustom={ 20 } variant="white" className="text-center [text-shadow:0px_4px_4px_rgba(0,0,0,0.25)]">
|
||||||
Something went wrong while loading
|
|
||||||
</Text>
|
|
||||||
<Base className="px-4 py-3 rounded-lg bg-black/40 text-[#ff6b6b] text-sm font-mono text-center break-words whitespace-pre-wrap max-w-[600px]">
|
|
||||||
{ message }
|
{ message }
|
||||||
</Base>
|
</Text>
|
||||||
|
{ homeUrl &&
|
||||||
|
<a
|
||||||
|
href={ homeUrl }
|
||||||
|
className="mt-3 px-6 py-3 rounded-lg bg-[#3b82f6] hover:bg-[#2563eb] text-white text-base font-semibold no-underline cursor-pointer transition-colors duration-200 [text-shadow:none]"
|
||||||
|
>
|
||||||
|
Back to Hotel
|
||||||
|
</a>
|
||||||
|
}
|
||||||
</Column>
|
</Column>
|
||||||
:
|
:
|
||||||
<Text fontSizeCustom={32} variant="white" className="absolute bottom-[20px] left-1/2 z-[3] -translate-x-1/2 [text-shadow:0px_4px_4px_rgba(0,0,0,0.25)]">
|
<Text fontSizeCustom={32} variant="white" className="absolute bottom-[20px] left-1/2 z-[3] -translate-x-1/2 [text-shadow:0px_4px_4px_rgba(0,0,0,0.25)]">
|
||||||
|
|||||||
@@ -48,14 +48,14 @@ export const ReconnectView: FC<{}> = props =>
|
|||||||
|
|
||||||
const handleReload = useCallback(() =>
|
const handleReload = useCallback(() =>
|
||||||
{
|
{
|
||||||
window.location.reload();
|
window.location.href = window.location.origin + '/';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleGoHome = useCallback(() =>
|
const handleGoHome = useCallback(() =>
|
||||||
{
|
{
|
||||||
sessionStorage.removeItem('nitro.session.lastRoomId');
|
sessionStorage.removeItem('nitro.session.lastRoomId');
|
||||||
sessionStorage.removeItem('nitro.session.lastRoomPassword');
|
sessionStorage.removeItem('nitro.session.lastRoomPassword');
|
||||||
window.location.reload();
|
window.location.href = window.location.origin + '/';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if(!isReconnecting && !hasFailed) return null;
|
if(!isReconnecting && !hasFailed) return null;
|
||||||
@@ -92,24 +92,18 @@ export const ReconnectView: FC<{}> = props =>
|
|||||||
<>
|
<>
|
||||||
<Text fontSizeCustom={ 36 } className="text-center text-red-500">⚠</Text>
|
<Text fontSizeCustom={ 36 } className="text-center text-red-500">⚠</Text>
|
||||||
<Text fontSizeCustom={ 18 } variant="white" className="text-center font-semibold">
|
<Text fontSizeCustom={ 18 } variant="white" className="text-center font-semibold">
|
||||||
Connection failed
|
Session expired
|
||||||
</Text>
|
</Text>
|
||||||
<Text fontSizeCustom={ 14 } variant="white" className="text-center opacity-70">
|
<Text fontSizeCustom={ 14 } variant="white" className="text-center opacity-70">
|
||||||
Unable to reconnect to the server after multiple attempts.
|
Your session has expired. Please log in again to enter the hotel.
|
||||||
</Text>
|
</Text>
|
||||||
<Base className="mt-2 flex gap-3">
|
<Base className="mt-2 flex gap-3">
|
||||||
<Base
|
<a
|
||||||
className="px-6 py-2 rounded-lg bg-[#4dabf7] text-white font-semibold cursor-pointer hover:bg-[#339af0] transition-colors"
|
href={ window.location.origin + '/' }
|
||||||
onClick={ handleReload }
|
className="px-6 py-2 rounded-lg bg-[#3b82f6] text-white font-semibold cursor-pointer hover:bg-[#2563eb] transition-colors no-underline"
|
||||||
>
|
>
|
||||||
Reload Page
|
Back to Hotel
|
||||||
</Base>
|
</a>
|
||||||
<Base
|
|
||||||
className="px-6 py-2 rounded-lg bg-white/10 text-white font-semibold cursor-pointer hover:bg-white/20 transition-colors"
|
|
||||||
onClick={ handleGoHome }
|
|
||||||
>
|
|
||||||
Go to Home
|
|
||||||
</Base>
|
|
||||||
</Base>
|
</Base>
|
||||||
</>
|
</>
|
||||||
) }
|
) }
|
||||||
|
|||||||
Reference in New Issue
Block a user