mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-26 23:50:52 +01:00
Navigator updates
This commit is contained in:
parent
38ad92b522
commit
384337b2f6
@ -3,5 +3,29 @@ import { NitroEvent } from 'nitro-renderer';
|
|||||||
export class NavigatorEvent extends NitroEvent
|
export class NavigatorEvent extends NitroEvent
|
||||||
{
|
{
|
||||||
public static SHOW_NAVIGATOR: string = 'NE_SHOW_NAVIGATOR';
|
public static SHOW_NAVIGATOR: string = 'NE_SHOW_NAVIGATOR';
|
||||||
|
public static HIDE_NAVIGATOR: string = 'NE_HIDE_NAVIGATOR';
|
||||||
public static TOGGLE_NAVIGATOR: string = 'NE_TOGGLE_NAVIGATOR';
|
public static TOGGLE_NAVIGATOR: string = 'NE_TOGGLE_NAVIGATOR';
|
||||||
|
public static VISIT_ROOM: string = 'NE_VISIT_ROOM';
|
||||||
|
public static TRY_VISIT_ROOM: string = 'NE_TRY_VISIT_ROOM';
|
||||||
|
|
||||||
|
private _roomId: number;
|
||||||
|
private _password: string;
|
||||||
|
|
||||||
|
constructor(type: string, roomId: number = -1, password = null)
|
||||||
|
{
|
||||||
|
super(type);
|
||||||
|
|
||||||
|
this._roomId = roomId;
|
||||||
|
this._password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get roomId(): number
|
||||||
|
{
|
||||||
|
return this._roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get password(): string
|
||||||
|
{
|
||||||
|
return this._password;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,16 @@ import { GenericErrorEvent, NavigatorCategoriesComposer, NavigatorMetadataEvent,
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { GetRoomSessionManager, GetSessionDataManager } from '../../api';
|
import { GetRoomSessionManager, GetSessionDataManager } from '../../api';
|
||||||
import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event';
|
import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event';
|
||||||
import { NavigatorLockViewStage } from './lock/NavigatorLockView.types';
|
import { useNavigatorContext } from './context/NavigatorContext';
|
||||||
import { NavigatorMessageHandlerProps } from './NavigatorMessageHandler.types';
|
import { NavigatorMessageHandlerProps } from './NavigatorMessageHandler.types';
|
||||||
|
import { NavigatorActions } from './reducers/NavigatorReducer';
|
||||||
|
|
||||||
export function NavigatorMessageHandler(props: NavigatorMessageHandlerProps): JSX.Element
|
export function NavigatorMessageHandler(props: NavigatorMessageHandlerProps): JSX.Element
|
||||||
{
|
{
|
||||||
const { setTopLevelContext = null, setTopLevelContexts = null, setSearchResults = null, showLock = null, hideLock = null } = props;
|
const { dispatchNavigatorState = null } = useNavigatorContext();
|
||||||
|
|
||||||
const onUserInfoEvent = useCallback((event: UserInfoEvent) =>
|
const onUserInfoEvent = useCallback((event: UserInfoEvent) =>
|
||||||
{
|
{
|
||||||
//const parser = event.getParser();
|
|
||||||
|
|
||||||
SendMessageHook(new NavigatorCategoriesComposer());
|
SendMessageHook(new NavigatorCategoriesComposer());
|
||||||
SendMessageHook(new NavigatorSettingsComposer());
|
SendMessageHook(new NavigatorSettingsComposer());
|
||||||
}, []);
|
}, []);
|
||||||
@ -57,7 +56,7 @@ export function NavigatorMessageHandler(props: NavigatorMessageHandlerProps): JS
|
|||||||
{
|
{
|
||||||
case RoomDataParser.DOORBELL_STATE:
|
case RoomDataParser.DOORBELL_STATE:
|
||||||
case RoomDataParser.PASSWORD_STATE:
|
case RoomDataParser.PASSWORD_STATE:
|
||||||
showLock();
|
//showLock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,65 +72,59 @@ export function NavigatorMessageHandler(props: NavigatorMessageHandlerProps): JS
|
|||||||
|
|
||||||
const onRoomDoorbellEvent = useCallback((event: RoomDoorbellEvent) =>
|
const onRoomDoorbellEvent = useCallback((event: RoomDoorbellEvent) =>
|
||||||
{
|
{
|
||||||
if(!event) return;
|
|
||||||
|
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
if(!parser) return;
|
// if(!parser.userName || (parser.userName.length === 0))
|
||||||
|
// {
|
||||||
if(!parser.userName || (parser.userName.length === 0))
|
// showLock(NavigatorLockViewStage.WAITING);
|
||||||
{
|
// }
|
||||||
showLock(NavigatorLockViewStage.WAITING);
|
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onRoomDoorbellAcceptedEvent = useCallback((event: RoomDoorbellAcceptedEvent) =>
|
const onRoomDoorbellAcceptedEvent = useCallback((event: RoomDoorbellAcceptedEvent) =>
|
||||||
{
|
{
|
||||||
if(!event) return;
|
|
||||||
|
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
if(!parser) return;
|
// if(!parser.userName || (parser.userName.length === 0))
|
||||||
|
// {
|
||||||
if(!parser.userName || (parser.userName.length === 0))
|
// hideLock();
|
||||||
{
|
// }
|
||||||
hideLock();
|
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onGenericErrorEvent = useCallback((event: GenericErrorEvent) =>
|
const onGenericErrorEvent = useCallback((event: GenericErrorEvent) =>
|
||||||
{
|
{
|
||||||
if(!event) return;
|
|
||||||
|
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
if(!parser) return;
|
// switch(parser.errorCode)
|
||||||
|
// {
|
||||||
switch(parser.errorCode)
|
// case -100002:
|
||||||
{
|
// showLock(NavigatorLockViewStage.FAILED);
|
||||||
case -100002:
|
// break;
|
||||||
showLock(NavigatorLockViewStage.FAILED);
|
// }
|
||||||
break;
|
|
||||||
}
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onNavigatorMetadataEvent = useCallback((event: NavigatorMetadataEvent) =>
|
const onNavigatorMetadataEvent = useCallback((event: NavigatorMetadataEvent) =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
setTopLevelContexts(parser.topLevelContexts);
|
dispatchNavigatorState({
|
||||||
|
type: NavigatorActions.SET_TOP_LEVEL_CONTEXTS,
|
||||||
if(parser.topLevelContexts.length > 0) setTopLevelContext(parser.topLevelContexts[0]);
|
payload: {
|
||||||
|
topLevelContexts: parser.topLevelContexts
|
||||||
// clear search
|
}
|
||||||
}, [ setTopLevelContext, setTopLevelContexts ]);
|
});
|
||||||
|
}, [ dispatchNavigatorState ]);
|
||||||
|
|
||||||
const onNavigatorSearchEvent = useCallback((event: NavigatorSearchEvent) =>
|
const onNavigatorSearchEvent = useCallback((event: NavigatorSearchEvent) =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
setSearchResults(parser.result.results);
|
dispatchNavigatorState({
|
||||||
}, [ setSearchResults ]);
|
type: NavigatorActions.SET_SEARCH_RESULT,
|
||||||
|
payload: {
|
||||||
|
searchResult: parser.result
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [ dispatchNavigatorState ]);
|
||||||
|
|
||||||
CreateMessageHook(UserInfoEvent, onUserInfoEvent);
|
CreateMessageHook(UserInfoEvent, onUserInfoEvent);
|
||||||
CreateMessageHook(RoomForwardEvent, onRoomForwardEvent);
|
CreateMessageHook(RoomForwardEvent, onRoomForwardEvent);
|
||||||
|
@ -1,11 +1,3 @@
|
|||||||
import { NavigatorSearchResultList, NavigatorTopLevelContext } from 'nitro-renderer';
|
|
||||||
import { NavigatorLockViewStage } from './lock/NavigatorLockView.types';
|
|
||||||
|
|
||||||
export interface NavigatorMessageHandlerProps
|
export interface NavigatorMessageHandlerProps
|
||||||
{
|
{
|
||||||
setTopLevelContext: (context: NavigatorTopLevelContext) => void;
|
|
||||||
setTopLevelContexts: (contexts: NavigatorTopLevelContext[]) => void;
|
|
||||||
setSearchResults: (results: NavigatorSearchResultList[]) => void;
|
|
||||||
showLock: (stage?: NavigatorLockViewStage) => void;
|
|
||||||
hideLock: () => void;
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,4 @@
|
|||||||
width: 400px;
|
width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@import './lock/NavigatorLockView';
|
@import './views/NavigatorViews';
|
||||||
@import './result-lists/NavigatorResultListsView';
|
|
||||||
@import './search/NavigatorSearchView';
|
|
||||||
@import './tabs/NavigatorTabsView';
|
|
||||||
|
@ -1,70 +1,34 @@
|
|||||||
import { NavigatorInitComposer, NavigatorSearchComposer, NavigatorSearchResultList, NavigatorTopLevelContext, RoomDataParser, RoomInfoComposer, RoomSessionEvent } from 'nitro-renderer';
|
import { NavigatorInitComposer, NavigatorSearchComposer, RoomInfoComposer, RoomSessionEvent } from 'nitro-renderer';
|
||||||
import { createContext, FC, MouseEvent, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
|
||||||
import { GetRoomSessionManager } from '../../api';
|
import { GetRoomSessionManager } from '../../api';
|
||||||
import { NavigatorEvent } from '../../events';
|
import { NavigatorEvent } from '../../events';
|
||||||
import { DraggableWindow } from '../../hooks/draggable-window/DraggableWindow';
|
|
||||||
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
|
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
|
||||||
import { useUiEvent } from '../../hooks/events/ui/ui-event';
|
import { useUiEvent } from '../../hooks/events/ui/ui-event';
|
||||||
import { SendMessageHook } from '../../hooks/messages/message-event';
|
import { SendMessageHook } from '../../hooks/messages/message-event';
|
||||||
import { TransitionAnimation } from '../../transitions/TransitionAnimation';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout';
|
||||||
import { TransitionAnimationTypes } from '../../transitions/TransitionAnimation.types';
|
|
||||||
import { LocalizeText } from '../../utils/LocalizeText';
|
import { LocalizeText } from '../../utils/LocalizeText';
|
||||||
import { NavigatorLockView } from './lock/NavigatorLockView';
|
import { NavigatorContextProvider } from './context/NavigatorContext';
|
||||||
import { NavigatorLockViewStage } from './lock/NavigatorLockView.types';
|
|
||||||
import { NavigatorMessageHandler } from './NavigatorMessageHandler';
|
import { NavigatorMessageHandler } from './NavigatorMessageHandler';
|
||||||
import { INavigatorContext, NavigatorViewProps } from './NavigatorView.types';
|
import { NavigatorViewProps } from './NavigatorView.types';
|
||||||
import { NavigatorResultListsView } from './result-lists/NavigatorResultListsView';
|
import { initialNavigator, NavigatorActions, NavigatorReducer } from './reducers/NavigatorReducer';
|
||||||
import { NavigatorSearchView } from './search/NavigatorSearchView';
|
import { NavigatorSearchResultSetView } from './views/search-result-set/NavigatorSearchResultSetView';
|
||||||
import { NavigatorTabsView } from './tabs/NavigatorTabsView';
|
import { NavigatorSearchView } from './views/search/NavigatorSearchView';
|
||||||
|
|
||||||
export const NavigatorContext = createContext<INavigatorContext>(null);
|
|
||||||
|
|
||||||
export const NavigatorView: FC<NavigatorViewProps> = props =>
|
export const NavigatorView: FC<NavigatorViewProps> = props =>
|
||||||
{
|
{
|
||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
const [ isLoaded, setIsLoaded ] = useState(false);
|
const [ navigatorState, dispatchNavigatorState ] = useReducer(NavigatorReducer, initialNavigator);
|
||||||
const [ isLoading, setIsLoading ] = useState(false);
|
const { needsNavigatorUpdate = false, topLevelContext = null, topLevelContexts = null } = navigatorState;
|
||||||
const [ isSearching, setIsSearching ] = useState(false);
|
|
||||||
const [ isLockVisible, setIsLockVisible ] = useState(false);
|
|
||||||
|
|
||||||
const [ lockStage, setLockStage ] = useState<NavigatorLockViewStage>(NavigatorLockViewStage.INIT);
|
const visitRoom = useCallback((roomId: number, password: string = null) =>
|
||||||
const [ lastRoomVisited, setLastRoomVisited ] = useState<RoomDataParser>(null);
|
|
||||||
|
|
||||||
const [ topLevelContexts, setTopLevelContexts ] = useState<NavigatorTopLevelContext[]>(null);
|
|
||||||
const [ topLevelContext, setTopLevelContext ] = useState<NavigatorTopLevelContext>(null);
|
|
||||||
const [ searchResults, setSearchResults ] = useState<NavigatorSearchResultList[]>(null);
|
|
||||||
|
|
||||||
function hideNavigator(event: MouseEvent = null): void
|
|
||||||
{
|
{
|
||||||
if(event) event.preventDefault();
|
|
||||||
|
|
||||||
setIsVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideLock(): void
|
|
||||||
{
|
|
||||||
setIsLockVisible(false);
|
|
||||||
setLockStage(NavigatorLockViewStage.INIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showLock(stage: NavigatorLockViewStage = NavigatorLockViewStage.INIT)
|
|
||||||
{
|
|
||||||
setLockStage(stage);
|
|
||||||
setIsLockVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function visitRoom(roomId: number, password: string = null): void
|
|
||||||
{
|
|
||||||
setIsLockVisible(false);
|
|
||||||
GetRoomSessionManager().createSession(roomId, password);
|
GetRoomSessionManager().createSession(roomId, password);
|
||||||
}
|
}, []);
|
||||||
|
|
||||||
function tryVisitRoom(room: RoomDataParser): void
|
const tryVisitRoom = useCallback((roomId: number) =>
|
||||||
{
|
{
|
||||||
setIsLockVisible(false);
|
SendMessageHook(new RoomInfoComposer(roomId, false, true));
|
||||||
setLastRoomVisited(room);
|
}, []);
|
||||||
SendMessageHook(new RoomInfoComposer(room.roomId, false, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
const onNavigatorEvent = useCallback((event: NavigatorEvent) =>
|
const onNavigatorEvent = useCallback((event: NavigatorEvent) =>
|
||||||
{
|
{
|
||||||
@ -73,11 +37,26 @@ export const NavigatorView: FC<NavigatorViewProps> = props =>
|
|||||||
case NavigatorEvent.SHOW_NAVIGATOR:
|
case NavigatorEvent.SHOW_NAVIGATOR:
|
||||||
setIsVisible(true);
|
setIsVisible(true);
|
||||||
return;
|
return;
|
||||||
|
case NavigatorEvent.HIDE_NAVIGATOR:
|
||||||
|
setIsVisible(false);
|
||||||
|
return;
|
||||||
case NavigatorEvent.TOGGLE_NAVIGATOR:
|
case NavigatorEvent.TOGGLE_NAVIGATOR:
|
||||||
setIsVisible(value => !value);
|
setIsVisible(value => !value);
|
||||||
return;
|
return;
|
||||||
|
case NavigatorEvent.VISIT_ROOM:
|
||||||
|
visitRoom(event.roomId, event.password);
|
||||||
|
return;
|
||||||
|
case NavigatorEvent.TRY_VISIT_ROOM:
|
||||||
|
tryVisitRoom(event.roomId);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}, []);
|
}, [ visitRoom, tryVisitRoom ]);
|
||||||
|
|
||||||
|
useUiEvent(NavigatorEvent.SHOW_NAVIGATOR, onNavigatorEvent);
|
||||||
|
useUiEvent(NavigatorEvent.HIDE_NAVIGATOR, onNavigatorEvent);
|
||||||
|
useUiEvent(NavigatorEvent.TOGGLE_NAVIGATOR, onNavigatorEvent);
|
||||||
|
useUiEvent(NavigatorEvent.VISIT_ROOM, onNavigatorEvent);
|
||||||
|
useUiEvent(NavigatorEvent.TRY_VISIT_ROOM, onNavigatorEvent);
|
||||||
|
|
||||||
const onRoomSessionEvent = useCallback((event: RoomSessionEvent) =>
|
const onRoomSessionEvent = useCallback((event: RoomSessionEvent) =>
|
||||||
{
|
{
|
||||||
@ -89,65 +68,54 @@ export const NavigatorView: FC<NavigatorViewProps> = props =>
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const search = useCallback((value: string = null) =>
|
|
||||||
{
|
|
||||||
if(!topLevelContext) return;
|
|
||||||
|
|
||||||
setIsSearching(true);
|
|
||||||
|
|
||||||
sendSearch(topLevelContext.code, '');
|
|
||||||
}, [ topLevelContext ]);
|
|
||||||
|
|
||||||
function sendSearch(code: string, query: string): void
|
|
||||||
{
|
|
||||||
SendMessageHook(new NavigatorSearchComposer(code, query));
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if(!isVisible) return;
|
|
||||||
|
|
||||||
if(!isLoaded)
|
|
||||||
{
|
|
||||||
SendMessageHook(new NavigatorInitComposer());
|
|
||||||
|
|
||||||
setIsLoaded(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
search();
|
|
||||||
}
|
|
||||||
}, [ isVisible, isLoaded, search ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
setIsSearching(false);
|
|
||||||
}, [ searchResults ]);
|
|
||||||
|
|
||||||
useUiEvent(NavigatorEvent.SHOW_NAVIGATOR, onNavigatorEvent);
|
|
||||||
useUiEvent(NavigatorEvent.TOGGLE_NAVIGATOR, onNavigatorEvent);
|
|
||||||
|
|
||||||
useRoomSessionManagerEvent(RoomSessionEvent.CREATED, onRoomSessionEvent);
|
useRoomSessionManagerEvent(RoomSessionEvent.CREATED, onRoomSessionEvent);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!isVisible || !needsNavigatorUpdate) return;
|
||||||
|
|
||||||
|
dispatchNavigatorState({
|
||||||
|
type: NavigatorActions.SET_NEEDS_UPDATE,
|
||||||
|
payload: {
|
||||||
|
flag: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SendMessageHook(new NavigatorInitComposer());
|
||||||
|
|
||||||
|
}, [ isVisible, needsNavigatorUpdate ]);
|
||||||
|
|
||||||
|
const sendSearch = useCallback((code: string, data: string) =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new NavigatorSearchComposer(code, data));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!topLevelContexts || !topLevelContexts.length) return;
|
||||||
|
|
||||||
|
const context = topLevelContexts[0];
|
||||||
|
|
||||||
|
sendSearch(context.code, '');
|
||||||
|
}, [ topLevelContexts, sendSearch ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigatorContext.Provider value={{ onTryVisitRoom: tryVisitRoom }}>
|
<NavigatorContextProvider value={ { navigatorState, dispatchNavigatorState } }>
|
||||||
<NavigatorMessageHandler setTopLevelContext={ setTopLevelContext } setTopLevelContexts={ setTopLevelContexts } setSearchResults={ setSearchResults } showLock={ showLock } hideLock={ hideLock } />
|
<NavigatorMessageHandler />
|
||||||
{ isVisible && <DraggableWindow handle=".drag-handler">
|
{ isVisible &&
|
||||||
<div className="nitro-navigator d-flex flex-column bg-primary border border-black shadow rounded">
|
<NitroCardView className="nitro-navigator">
|
||||||
<div className="drag-handler d-flex justify-content-between align-items-center px-3 pt-3">
|
<NitroCardHeaderView headerText={ LocalizeText('navigator.title') } onCloseClick={ event => setIsVisible(false) } />
|
||||||
<div className="h6 m-0">{ LocalizeText((isLoading || isSearching) ? 'navigator.title.is.busy' : 'navigator.title') }</div>
|
<NitroCardTabsView>
|
||||||
<button type="button" className="close" onClick={ hideNavigator }>
|
{ topLevelContexts.map((context, index) =>
|
||||||
<i className="fas fa-times"></i>
|
{
|
||||||
</button>
|
return <NitroCardTabsItemView key={ index } tabText={ LocalizeText(('navigator.toplevelview.' + context.code)) } isActive={ (topLevelContext === context) } onClick={ event => sendSearch(context.code, '') } />
|
||||||
</div>
|
}) }
|
||||||
<NavigatorTabsView topLevelContext={ topLevelContext } topLevelContexts={ topLevelContexts } setTopLevelContext={ setTopLevelContext } />
|
</NitroCardTabsView>
|
||||||
<NavigatorSearchView />
|
<NitroCardContentView>
|
||||||
<TransitionAnimation className="d-flex px-3 pb-3" type={ TransitionAnimationTypes.FADE_IN } inProp={ (!isSearching && !!searchResults) } timeout={ 150 }>
|
<NavigatorSearchView />
|
||||||
<NavigatorResultListsView resultLists={ searchResults } />
|
<NavigatorSearchResultSetView />
|
||||||
</TransitionAnimation>
|
</NitroCardContentView>
|
||||||
</div>
|
</NitroCardView> }
|
||||||
</DraggableWindow> }
|
</NavigatorContextProvider>
|
||||||
{ isLockVisible && <NavigatorLockView roomData={ lastRoomVisited } stage={ lockStage } onHideLock={ hideLock } onVisitRoom={ visitRoom }></NavigatorLockView> }
|
|
||||||
</NavigatorContext.Provider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
14
src/views/navigator/context/NavigatorContext.tsx
Normal file
14
src/views/navigator/context/NavigatorContext.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { createContext, FC, useContext } from 'react';
|
||||||
|
import { INavigatorContext, NavigatorContextProps } from './NavigatorContext.types';
|
||||||
|
|
||||||
|
const NavigatorContext = createContext<INavigatorContext>({
|
||||||
|
navigatorState: null,
|
||||||
|
dispatchNavigatorState: null
|
||||||
|
});
|
||||||
|
|
||||||
|
export const NavigatorContextProvider: FC<NavigatorContextProps> = props =>
|
||||||
|
{
|
||||||
|
return <NavigatorContext.Provider value={ props.value }>{ props.children }</NavigatorContext.Provider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNavigatorContext = () => useContext(NavigatorContext);
|
13
src/views/navigator/context/NavigatorContext.types.ts
Normal file
13
src/views/navigator/context/NavigatorContext.types.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Dispatch, ProviderProps } from 'react';
|
||||||
|
import { INavigatorAction, INavigatorState } from '../reducers/NavigatorReducer';
|
||||||
|
|
||||||
|
export interface INavigatorContext
|
||||||
|
{
|
||||||
|
navigatorState: INavigatorState;
|
||||||
|
dispatchNavigatorState: Dispatch<INavigatorAction>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NavigatorContextProps extends ProviderProps<INavigatorContext>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
.nitro-navigator-lock {
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
import { RoomDataParser } from 'nitro-renderer';
|
|
||||||
import { DraggableWindow } from '../../../hooks/draggable-window/DraggableWindow';
|
|
||||||
import { LocalizeText } from '../../../utils/LocalizeText';
|
|
||||||
import { NavigatorLockDoorbellView } from './doorbell/NavigatorLockDoorbellView';
|
|
||||||
import { NavigatorLockViewProps } from './NavigatorLockView.types';
|
|
||||||
import { NavigatorLockPasswordView } from './password/NavigatorLockPasswordView';
|
|
||||||
|
|
||||||
export function NavigatorLockView(props: NavigatorLockViewProps): JSX.Element
|
|
||||||
{
|
|
||||||
const { roomData = null, stage = null, onHideLock = null, onVisitRoom = null } = props;
|
|
||||||
|
|
||||||
function visitRoom(password?: string): void
|
|
||||||
{
|
|
||||||
onVisitRoom(roomData.roomId, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DraggableWindow handle=".drag-handler">
|
|
||||||
<div className="nitro-navigator-lock d-flex flex-column bg-primary border border-black shadow rounded position-absolute">
|
|
||||||
<div className="drag-handler d-flex justify-content-between align-items-center px-3 pt-3">
|
|
||||||
<div className="h6 m-0">{ LocalizeText(roomData.doorMode === RoomDataParser.PASSWORD_STATE ? 'navigator.password.title' : 'navigator.doorbell.title') }</div>
|
|
||||||
<button type="button" className="close" onClick={ onHideLock }>
|
|
||||||
<i className="fas fa-times"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="p-3">
|
|
||||||
{ roomData && <>
|
|
||||||
<h5>{ roomData.roomName }</h5>
|
|
||||||
{ roomData.doorMode && roomData.doorMode === RoomDataParser.DOORBELL_STATE && <NavigatorLockDoorbellView stage={stage} onVisitRoom={ visitRoom } onHideLock={ onHideLock } /> }
|
|
||||||
{ roomData.doorMode && roomData.doorMode === RoomDataParser.PASSWORD_STATE && <NavigatorLockPasswordView stage={stage} onVisitRoom={ visitRoom } onHideLock={ onHideLock } /> }
|
|
||||||
</> }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</DraggableWindow>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { RoomDataParser } from 'nitro-renderer';
|
|
||||||
|
|
||||||
export interface NavigatorLockViewProps
|
|
||||||
{
|
|
||||||
roomData: RoomDataParser;
|
|
||||||
stage: NavigatorLockViewStage;
|
|
||||||
onHideLock: () => void;
|
|
||||||
onVisitRoom: (roomId: number, password?: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum NavigatorLockViewStage
|
|
||||||
{
|
|
||||||
INIT = 'navigator_lock_view_stage_init',
|
|
||||||
WAITING = 'navigator_lock_view_stage_waiting',
|
|
||||||
FAILED = 'navigator_lock_view_stage_failed'
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
import { LocalizeText } from '../../../../utils/LocalizeText';
|
|
||||||
import { NavigatorLockViewStage } from '../NavigatorLockView.types';
|
|
||||||
import { NavigatorLockDoorbellViewProps } from './NavigatorLockDoorbellView.types';
|
|
||||||
|
|
||||||
export function NavigatorLockDoorbellView(props: NavigatorLockDoorbellViewProps): JSX.Element
|
|
||||||
{
|
|
||||||
const { stage = null, onVisitRoom = null, onHideLock = null } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{ stage && <div className="mb-3">
|
|
||||||
{ stage === NavigatorLockViewStage.INIT && LocalizeText('navigator.doorbell.info') }
|
|
||||||
{ stage === NavigatorLockViewStage.WAITING && LocalizeText('navigator.doorbell.waiting') }
|
|
||||||
{ stage === NavigatorLockViewStage.FAILED && LocalizeText('navigator.doorbell.no.answer') }
|
|
||||||
</div> }
|
|
||||||
<div className="d-flex justify-content-between">
|
|
||||||
<button type="button" className="btn btn-secondary" onClick={ () => onHideLock() }>{ LocalizeText('generic.cancel') }</button>
|
|
||||||
{ stage === NavigatorLockViewStage.INIT && <button type="button" className="btn btn-primary" onClick={ () => onVisitRoom() }>{ LocalizeText('navigator.doorbell.button.ring') }</button> }
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
import { NavigatorLockViewStage } from '../NavigatorLockView.types';
|
|
||||||
|
|
||||||
export interface NavigatorLockDoorbellViewProps
|
|
||||||
{
|
|
||||||
stage: NavigatorLockViewStage;
|
|
||||||
onVisitRoom: (password?: string) => void;
|
|
||||||
onHideLock: () => void;
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import { LocalizeText } from '../../../../utils/LocalizeText';
|
|
||||||
import { NavigatorLockViewStage } from '../NavigatorLockView.types';
|
|
||||||
import { NavigatorLockPasswordViewProps } from './NavigatorLockPasswordView.types';
|
|
||||||
|
|
||||||
export function NavigatorLockPasswordView(props: NavigatorLockPasswordViewProps): JSX.Element
|
|
||||||
{
|
|
||||||
const { stage = null, onVisitRoom = null, onHideLock = null } = props;
|
|
||||||
|
|
||||||
const [ password, setPassword ] = useState<string>(null);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{ stage && <div className="mb-2">
|
|
||||||
{ stage === NavigatorLockViewStage.INIT && LocalizeText('navigator.password.info') }
|
|
||||||
{ stage === NavigatorLockViewStage.FAILED && LocalizeText('navigator.password.retryinfo') }
|
|
||||||
</div> }
|
|
||||||
<div className="form-group mb-3">
|
|
||||||
<label>{ LocalizeText('navigator.password.enter') }</label>
|
|
||||||
<input autoComplete="off" type="password" className="form-control form-control-sm" placeholder="*****" value={ password } onChange={ (event) => setPassword(event.target.value) } />
|
|
||||||
</div>
|
|
||||||
<div className="d-flex justify-content-between">
|
|
||||||
<button type="button" className="btn btn-secondary" onClick={ () => onHideLock() }>{ LocalizeText('generic.cancel') }</button>
|
|
||||||
<button type="button" className="btn btn-primary" onClick={ () => onVisitRoom(password) }>{ LocalizeText('navigator.password.button.try') }</button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
import { NavigatorLockViewStage } from '../NavigatorLockView.types';
|
|
||||||
|
|
||||||
export interface NavigatorLockPasswordViewProps
|
|
||||||
{
|
|
||||||
stage: NavigatorLockViewStage;
|
|
||||||
onVisitRoom: (password?: string) => void;
|
|
||||||
onHideLock: () => void;
|
|
||||||
}
|
|
87
src/views/navigator/reducers/NavigatorReducer.tsx
Normal file
87
src/views/navigator/reducers/NavigatorReducer.tsx
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import { NavigatorSearchResultSet, NavigatorTopLevelContext } from 'nitro-renderer';
|
||||||
|
import { Reducer } from 'react';
|
||||||
|
|
||||||
|
export interface INavigatorState
|
||||||
|
{
|
||||||
|
needsNavigatorUpdate: boolean;
|
||||||
|
topLevelContext: NavigatorTopLevelContext;
|
||||||
|
topLevelContexts: NavigatorTopLevelContext[];
|
||||||
|
searchResult: NavigatorSearchResultSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface INavigatorAction
|
||||||
|
{
|
||||||
|
type: string;
|
||||||
|
payload: {
|
||||||
|
flag?: boolean;
|
||||||
|
topLevelContext?: NavigatorTopLevelContext;
|
||||||
|
topLevelContexts?: NavigatorTopLevelContext[];
|
||||||
|
searchResult?: NavigatorSearchResultSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NavigatorActions
|
||||||
|
{
|
||||||
|
public static SET_NEEDS_UPDATE: string = 'NA_SET_NEEDS_UPDATE';
|
||||||
|
public static SET_TOP_LEVEL_CONTEXT: string = 'NA_SET_TOP_LEVEL_CONTEXT';
|
||||||
|
public static SET_TOP_LEVEL_CONTEXTS: string = 'NA_SET_TOP_LEVEL_CONTEXTS';
|
||||||
|
public static SET_SEARCH_RESULT: string = 'NA_SET_SEARCH_RESULT';
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initialNavigator: INavigatorState = {
|
||||||
|
needsNavigatorUpdate: true,
|
||||||
|
topLevelContext: null,
|
||||||
|
topLevelContexts: null,
|
||||||
|
searchResult: null
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NavigatorReducer: Reducer<INavigatorState, INavigatorAction> = (state, action) =>
|
||||||
|
{
|
||||||
|
switch(action.type)
|
||||||
|
{
|
||||||
|
case NavigatorActions.SET_NEEDS_UPDATE:
|
||||||
|
return { ...state, needsNavigatorUpdate: (action.payload.flag || false) };
|
||||||
|
case NavigatorActions.SET_TOP_LEVEL_CONTEXT: {
|
||||||
|
let topLevelContext = (action.payload.topLevelContext || state.topLevelContext || null);
|
||||||
|
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
if(topLevelContext)
|
||||||
|
{
|
||||||
|
const foundIndex = state.topLevelContexts.indexOf(topLevelContext);
|
||||||
|
|
||||||
|
if(foundIndex > -1) index = foundIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
topLevelContext = (state.topLevelContexts[index] || null);
|
||||||
|
|
||||||
|
return { ...state, topLevelContext };
|
||||||
|
}
|
||||||
|
case NavigatorActions.SET_TOP_LEVEL_CONTEXTS: {
|
||||||
|
const topLevelContexts = (action.payload.topLevelContexts || state.topLevelContexts || null);
|
||||||
|
const topLevelContext = topLevelContexts[0];
|
||||||
|
|
||||||
|
return { ...state, topLevelContext, topLevelContexts };
|
||||||
|
}
|
||||||
|
case NavigatorActions.SET_SEARCH_RESULT: {
|
||||||
|
const searchResult = (action.payload.searchResult || state.searchResult || null);
|
||||||
|
const searchCode = searchResult.code;
|
||||||
|
|
||||||
|
let topLevelContext = state.topLevelContext;
|
||||||
|
|
||||||
|
if(searchCode !== topLevelContext.code)
|
||||||
|
{
|
||||||
|
for(const existingContext of state.topLevelContexts)
|
||||||
|
{
|
||||||
|
if(existingContext.code !== searchCode) continue;
|
||||||
|
|
||||||
|
topLevelContext = existingContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...state, topLevelContext, searchResult };
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
.nitro-navigator-result-lists {
|
|
||||||
height: 400px;
|
|
||||||
max-height: 400px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
@import './result-list/NavigatorResultListView';
|
|
@ -1,17 +0,0 @@
|
|||||||
import { NavigatorResultListsViewProps } from './NavigatorResultListsView.types';
|
|
||||||
import { NavigatorResultListView } from './result-list/NavigatorResultListView';
|
|
||||||
|
|
||||||
export function NavigatorResultListsView(props: NavigatorResultListsViewProps): JSX.Element
|
|
||||||
{
|
|
||||||
const { resultLists = null } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="nitro-navigator-result-lists w-100">
|
|
||||||
{ resultLists && resultLists.length && resultLists.map((resultList, index) =>
|
|
||||||
{
|
|
||||||
return <NavigatorResultListView key={ index } resultList={ resultList } />
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
import { NavigatorSearchResultList } from 'nitro-renderer';
|
|
||||||
|
|
||||||
export interface NavigatorResultListsViewProps
|
|
||||||
{
|
|
||||||
resultLists: NavigatorSearchResultList[];
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
@import './result/NavigatorResultView';
|
|
@ -1,69 +0,0 @@
|
|||||||
import classNames from 'classnames';
|
|
||||||
import { MouseEvent, useEffect, useState } from 'react';
|
|
||||||
import { LocalizeText } from '../../../../utils/LocalizeText';
|
|
||||||
import { NavigatorResultListViewDisplayMode, NavigatorResultListViewProps } from './NavigatorResultListView.types';
|
|
||||||
import { NavigatorResultView } from './result/NavigatorResultView';
|
|
||||||
|
|
||||||
export function NavigatorResultListView(props: NavigatorResultListViewProps): JSX.Element
|
|
||||||
{
|
|
||||||
const { resultList = null } = props;
|
|
||||||
|
|
||||||
const [ isExtended, setIsExtended ] = useState(true);
|
|
||||||
const [ displayMode, setDisplayMode ] = useState<number>(0);
|
|
||||||
|
|
||||||
function toggleList(): void
|
|
||||||
{
|
|
||||||
setIsExtended(!isExtended);
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
setDisplayMode(resultList.mode);
|
|
||||||
}, [ resultList ]);
|
|
||||||
|
|
||||||
function toggleDisplayMode(event: MouseEvent): void
|
|
||||||
{
|
|
||||||
if(event) event.stopPropagation();
|
|
||||||
|
|
||||||
const newDisplayMode = displayMode === NavigatorResultListViewDisplayMode.LIST ? NavigatorResultListViewDisplayMode.THUMBNAILS : NavigatorResultListViewDisplayMode.LIST;
|
|
||||||
setDisplayMode(newDisplayMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getListCode(): string
|
|
||||||
{
|
|
||||||
let name = resultList.code;
|
|
||||||
|
|
||||||
if((!name || name.length === 0) && (resultList.data && resultList.data.length > 0))
|
|
||||||
{
|
|
||||||
return resultList.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(resultList.code.startsWith('${'))
|
|
||||||
{
|
|
||||||
name = name.substr(2, (name.length - 3));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = ('navigator.searchcode.title.' + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="nitro-navigator-result-list p-2">
|
|
||||||
<div className="d-flex mb-2 small cursor-pointer" onClick={ toggleList }>
|
|
||||||
<i className={ "fas " + classNames({ 'fa-plus': !isExtended, 'fa-minus': isExtended })}></i>
|
|
||||||
<div className="align-self-center w-100 ml-2">{ LocalizeText(getListCode()) }</div>
|
|
||||||
<i className={ "fas " + classNames({ 'fa-bars': displayMode === NavigatorResultListViewDisplayMode.LIST, 'fa-th': displayMode >= NavigatorResultListViewDisplayMode.THUMBNAILS })} onClick={ toggleDisplayMode }></i>
|
|
||||||
</div>
|
|
||||||
<div className={ 'row mr-n2 row-cols-' + classNames({ '1': displayMode === NavigatorResultListViewDisplayMode.LIST, '2': displayMode >= NavigatorResultListViewDisplayMode.THUMBNAILS }) }>
|
|
||||||
{ isExtended && resultList && resultList.rooms.map((room, index) =>
|
|
||||||
{
|
|
||||||
return <NavigatorResultView key={ index } result={ room } />
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
import classNames from 'classnames';
|
|
||||||
import { RoomDataParser } from 'nitro-renderer';
|
|
||||||
import React, { useContext } from 'react';
|
|
||||||
import { NavigatorContext } from '../../../NavigatorView';
|
|
||||||
import { NavigatorResultViewProps } from './NavigatorResultView.types';
|
|
||||||
|
|
||||||
export function NavigatorResultView(props: NavigatorResultViewProps): JSX.Element
|
|
||||||
{
|
|
||||||
const { result = null } = props;
|
|
||||||
|
|
||||||
const navigatorContext = useContext(NavigatorContext);
|
|
||||||
|
|
||||||
function getUserCounterColor(): string
|
|
||||||
{
|
|
||||||
const num: number = (100 * (result.userCount / result.maxUserCount));
|
|
||||||
|
|
||||||
let bg = 'badge-primary';
|
|
||||||
|
|
||||||
if(num >= 92)
|
|
||||||
{
|
|
||||||
bg = 'badge-danger';
|
|
||||||
}
|
|
||||||
else if(num >= 50)
|
|
||||||
{
|
|
||||||
bg = 'badge-warning text-white';
|
|
||||||
}
|
|
||||||
else if(num > 0)
|
|
||||||
{
|
|
||||||
bg = 'badge-success';
|
|
||||||
}
|
|
||||||
|
|
||||||
return bg;
|
|
||||||
}
|
|
||||||
|
|
||||||
function openInfo(event: React.MouseEvent): void
|
|
||||||
{
|
|
||||||
event.stopPropagation();
|
|
||||||
console.log('info');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="col px-2">
|
|
||||||
<div className="d-flex flex-column justify-content-center align-items-center nitro-navigator-result small" onClick={ () => navigatorContext.onTryVisitRoom(result) }>
|
|
||||||
<div className="d-flex justify-content-between w-100 px-2 py-1">
|
|
||||||
<div className="d-flex justify-content-center flex-grow-1 overflow-hidden">
|
|
||||||
<div className={ "d-flex justify-content-center align-items-center badge text-center " + getUserCounterColor() }>
|
|
||||||
<i className="fas fa-user mr-1"></i> { result.userCount }
|
|
||||||
</div>
|
|
||||||
<div className="d-flex flex-column justify-content-center align-items-start flex-grow-1 px-2 overflow-hidden">
|
|
||||||
<span className="d-block text-truncate" style={ { maxWidth: '95%' } }>{ result.roomName }</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="d-flex flex-row-reverse align-items-center">
|
|
||||||
<i className="fas fa-info-circle" onClick={ openInfo }></i>
|
|
||||||
{ result.habboGroupId > 0 && <i className="fas fa-users mr-2"></i> }
|
|
||||||
{ result.doorMode !== RoomDataParser.OPEN_STATE &&
|
|
||||||
<i className={ 'mr-2 fas ' + classNames( {'fa-lock': result.doorMode === RoomDataParser.DOORBELL_STATE, 'fa-key': result.doorMode === RoomDataParser.PASSWORD_STATE })}></i>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
import { RoomDataParser } from 'nitro-renderer';
|
|
||||||
|
|
||||||
export interface NavigatorResultViewProps
|
|
||||||
{
|
|
||||||
result: RoomDataParser;
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
import { FC } from 'react';
|
|
||||||
import { LocalizeText } from '../../../utils/LocalizeText';
|
|
||||||
import { NavigatorSearchViewProps } from './NavigatorSearchView.types';
|
|
||||||
|
|
||||||
export const NavigatorSearchView: FC<NavigatorSearchViewProps> = props =>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<div className="d-flex input-group px-3 mb-1">
|
|
||||||
<div className="input-group-prepend">
|
|
||||||
<button type="button" className="btn btn-secondary btn-sm" >{ LocalizeText('navigator.filter.') }</button>
|
|
||||||
<div className="dropdown-menu">
|
|
||||||
<button className="dropdown-item">{ LocalizeText('navigator.filter.') }</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('navigator.filter.input.placeholder') } />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
@import './tab/NavigatorTabView';
|
|
@ -1,19 +0,0 @@
|
|||||||
import { NavigatorTabsViewProps } from './NavigatorTabsView.types';
|
|
||||||
import { NavigatorTabView } from './tab/NavigatorTabView';
|
|
||||||
|
|
||||||
export function NavigatorTabsView(props: NavigatorTabsViewProps): JSX.Element
|
|
||||||
{
|
|
||||||
const { topLevelContext = null, topLevelContexts = null, setTopLevelContext = null } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-3">
|
|
||||||
{ topLevelContexts && topLevelContexts.length &&
|
|
||||||
<div className="btn-group w-100">
|
|
||||||
{ topLevelContexts.map((context, index) =>
|
|
||||||
{
|
|
||||||
return <NavigatorTabView key={ index } context={ context } isActive={ context === topLevelContext } setTopLevelContext={ setTopLevelContext } />
|
|
||||||
}) }
|
|
||||||
</div> }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
import { NavigatorTopLevelContext } from 'nitro-renderer';
|
|
||||||
|
|
||||||
export interface NavigatorTabsViewProps
|
|
||||||
{
|
|
||||||
topLevelContext: NavigatorTopLevelContext;
|
|
||||||
topLevelContexts: NavigatorTopLevelContext[];
|
|
||||||
setTopLevelContext: (context: NavigatorTopLevelContext) => void;
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
import classNames from 'classnames';
|
|
||||||
import { MouseEvent } from 'react';
|
|
||||||
import { LocalizeText } from '../../../../utils/LocalizeText';
|
|
||||||
import { NavigatorTabViewProps } from './NavigatorTabView.types';
|
|
||||||
|
|
||||||
export function NavigatorTabView(props: NavigatorTabViewProps): JSX.Element
|
|
||||||
{
|
|
||||||
const { context = null, isActive = false, setTopLevelContext = null } = props;
|
|
||||||
|
|
||||||
function onClick(event: MouseEvent): void
|
|
||||||
{
|
|
||||||
setTopLevelContext(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button type="button" className={ "btn btn-secondary btn-sm " + classNames({ 'active': isActive })} onClick={ onClick }>{ LocalizeText(('navigator.toplevelview.' + context.code)) }</button>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
import { NavigatorTopLevelContext } from 'nitro-renderer';
|
|
||||||
|
|
||||||
export interface NavigatorTabViewProps
|
|
||||||
{
|
|
||||||
context: NavigatorTopLevelContext;
|
|
||||||
isActive?: boolean;
|
|
||||||
setTopLevelContext: (context: NavigatorTopLevelContext) => void;
|
|
||||||
}
|
|
3
src/views/navigator/views/NavigatorViews.scss
Normal file
3
src/views/navigator/views/NavigatorViews.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@import './search/NavigatorSearchView';
|
||||||
|
@import './search-result/NavigatorSearchResultView';
|
||||||
|
@import './search-result-item/NavigatorSearchResultItemView';
|
@ -0,0 +1,11 @@
|
|||||||
|
.nitro-navigator-result {
|
||||||
|
color: $black;
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
width: 35px;
|
||||||
|
|
||||||
|
.fas {
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import { RoomDataParser } from 'nitro-renderer';
|
||||||
|
import { FC, MouseEvent } from 'react';
|
||||||
|
import { NavigatorEvent } from '../../../../events';
|
||||||
|
import { dispatchUiEvent } from '../../../../hooks/events/ui/ui-event';
|
||||||
|
import { NavigatorSearchResultItemViewProps } from './NavigatorSearchResultItemView.types';
|
||||||
|
|
||||||
|
export const NavigatorSearchResultItemView: FC<NavigatorSearchResultItemViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { roomData = null } = props;
|
||||||
|
|
||||||
|
function getUserCounterColor(): string
|
||||||
|
{
|
||||||
|
const num: number = (100 * (roomData.userCount / roomData.maxUserCount));
|
||||||
|
|
||||||
|
let bg = 'bg-primary';
|
||||||
|
|
||||||
|
if(num >= 92)
|
||||||
|
{
|
||||||
|
bg = 'bg-danger';
|
||||||
|
}
|
||||||
|
else if(num >= 50)
|
||||||
|
{
|
||||||
|
bg = 'bg-warning';
|
||||||
|
}
|
||||||
|
else if(num > 0)
|
||||||
|
{
|
||||||
|
bg = 'bg-success';
|
||||||
|
}
|
||||||
|
|
||||||
|
return bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openInfo(event: MouseEvent): void
|
||||||
|
{
|
||||||
|
event.stopPropagation();
|
||||||
|
console.log('info');
|
||||||
|
}
|
||||||
|
|
||||||
|
function visitRoom(): void
|
||||||
|
{
|
||||||
|
dispatchUiEvent(new NavigatorEvent(NavigatorEvent.TRY_VISIT_ROOM, roomData.roomId));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="col">
|
||||||
|
<div className="d-flex flex-column justify-content-center align-items-center nitro-navigator-result small cursor-pointer" onClick={ visitRoom }>
|
||||||
|
<div className="d-flex justify-content-between w-100 px-2 py-1">
|
||||||
|
<div className="d-flex justify-content-center flex-grow-1 overflow-hidden">
|
||||||
|
<div className={ 'd-flex align-items-center justify-content-center badge p-1 ' + getUserCounterColor() }>
|
||||||
|
<i className="fas fa-user"></i>
|
||||||
|
{ roomData.userCount }
|
||||||
|
</div>
|
||||||
|
<div className="d-flex flex-column justify-content-center align-items-start flex-grow-1 px-2 overflow-hidden">
|
||||||
|
<span className="d-block text-truncate" style={ { maxWidth: '95%' } }>{ roomData.roomName }</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="d-flex flex-row-reverse align-items-center">
|
||||||
|
<i className="fas fa-info-circle" onClick={ openInfo }></i>
|
||||||
|
{ roomData.habboGroupId > 0 && <i className="fas fa-users mr-2"></i> }
|
||||||
|
{ roomData.doorMode !== RoomDataParser.OPEN_STATE &&
|
||||||
|
<i className={ 'mr-2 fas ' + classNames( {'fa-lock': roomData.doorMode === RoomDataParser.DOORBELL_STATE, 'fa-key': roomData.doorMode === RoomDataParser.PASSWORD_STATE })}></i>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
import { RoomDataParser } from 'nitro-renderer';
|
||||||
|
|
||||||
|
export interface NavigatorSearchResultItemViewProps
|
||||||
|
{
|
||||||
|
roomData: RoomDataParser
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { useNavigatorContext } from '../../context/NavigatorContext';
|
||||||
|
import { NavigatorSearchResultView } from '../search-result/NavigatorSearchResultView';
|
||||||
|
import { NavigatorSearchResultSetViewProps } from './NavigatorSearchResultSetView.types';
|
||||||
|
|
||||||
|
export const NavigatorSearchResultSetView: FC<NavigatorSearchResultSetViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { navigatorState = null } = useNavigatorContext();
|
||||||
|
const { searchResult = null } = navigatorState;
|
||||||
|
|
||||||
|
if(!searchResult || !searchResult.results.length) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ (searchResult.results.map((result, index) =>
|
||||||
|
{
|
||||||
|
return <NavigatorSearchResultView key={ index } searchResult={ result } />
|
||||||
|
})) }
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
export interface NavigatorSearchResultSetViewProps
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1,26 +1,17 @@
|
|||||||
.nitro-navigator-result {
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nitro-navigator-result-list {
|
.nitro-navigator-result-list {
|
||||||
|
|
||||||
.nitro-navigator-result {
|
.nitro-navigator-result {
|
||||||
border-radius: $border-radius;
|
background: $grid-active-bg-color;
|
||||||
background: $secondary;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.row {
|
&.row {
|
||||||
|
|
||||||
&.row-cols-1 {
|
&.row-cols-1 {
|
||||||
|
|
||||||
.col:nth-child(even) {
|
.col:nth-child(even) {
|
||||||
|
|
||||||
.nitro-navigator-result {
|
.nitro-navigator-result {
|
||||||
border-radius: $border-radius;
|
background: $white !important;
|
||||||
background: $primary !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -29,9 +20,9 @@
|
|||||||
|
|
||||||
.col:nth-child(4n+3),
|
.col:nth-child(4n+3),
|
||||||
.col:nth-child(4n+4) {
|
.col:nth-child(4n+4) {
|
||||||
|
|
||||||
.nitro-navigator-result {
|
.nitro-navigator-result {
|
||||||
border-radius: $border-radius;
|
background: $white !important;
|
||||||
background: $primary !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import { FC, useEffect, useState } from 'react';
|
||||||
|
import { LocalizeText } from '../../../../utils/LocalizeText';
|
||||||
|
import { NavigatorSearchResultItemView } from '../search-result-item/NavigatorSearchResultItemView';
|
||||||
|
import { NavigatorSearchResultViewDisplayMode, NavigatorSearchResultViewProps } from './NavigatorSearchResultView.types';
|
||||||
|
|
||||||
|
export const NavigatorSearchResultView: FC<NavigatorSearchResultViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { searchResult = null } = props;
|
||||||
|
|
||||||
|
const [ isExtended, setIsExtended ] = useState(true);
|
||||||
|
const [ displayMode, setDisplayMode ] = useState<number>(0);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!searchResult) return;
|
||||||
|
|
||||||
|
//setIsExtended(searchResult.closed);
|
||||||
|
//setDisplayMode(searchResult.mode);
|
||||||
|
}, [ searchResult ]);
|
||||||
|
|
||||||
|
function getResultTitle(): string
|
||||||
|
{
|
||||||
|
let name = searchResult.code;
|
||||||
|
|
||||||
|
if(!name || !name.length) return searchResult.data;
|
||||||
|
|
||||||
|
if(name.startsWith('${')) return name.substr(2, (name.length - 3));
|
||||||
|
|
||||||
|
return ('navigator.searchcode.title.' + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleExtended(): void
|
||||||
|
{
|
||||||
|
setIsExtended(prevValue =>
|
||||||
|
{
|
||||||
|
return !prevValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleDisplayMode(): void
|
||||||
|
{
|
||||||
|
setDisplayMode(prevValue =>
|
||||||
|
{
|
||||||
|
if(prevValue === NavigatorSearchResultViewDisplayMode.LIST) return NavigatorSearchResultViewDisplayMode.THUMBNAILS;
|
||||||
|
|
||||||
|
return NavigatorSearchResultViewDisplayMode.LIST;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white rounded mb-1 overflow-hidden">
|
||||||
|
<div className="d-flex flex-column">
|
||||||
|
<div className="d-flex align-items-center p-2 pb-0 mb-2">
|
||||||
|
<div className="d-flex flex-grow-1">
|
||||||
|
<button type="button" className="btn btn-primary btn-sm p-0 px-1 me-1" onClick={ toggleExtended }>
|
||||||
|
<i className={ "fas " + (isExtended ? 'fa-minus' : 'fa-plus') }></i>
|
||||||
|
</button>
|
||||||
|
<div className="h5 m-0 text-black">{ LocalizeText(getResultTitle()) }</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" className="btn btn-primary btn-sm p-0 px-1 ms-1" onClick={ toggleDisplayMode }>
|
||||||
|
<i className={ "fas " + classNames({ 'fa-bars': (displayMode === NavigatorSearchResultViewDisplayMode.LIST), 'fa-th': displayMode >= NavigatorSearchResultViewDisplayMode.THUMBNAILS })}></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{ isExtended &&
|
||||||
|
<div className={ 'nitro-navigator-result-list row row-cols-' + classNames({ '1': (displayMode === NavigatorSearchResultViewDisplayMode.LIST), '2': (displayMode >= NavigatorSearchResultViewDisplayMode.THUMBNAILS) }) }>
|
||||||
|
{ searchResult.rooms.length && searchResult.rooms.map((room, index) =>
|
||||||
|
{
|
||||||
|
return <NavigatorSearchResultItemView key={ index } roomData={ room } />
|
||||||
|
}) }
|
||||||
|
</div> }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
// <div className="nitro-navigator-result-list p-2">
|
||||||
|
// <div className="d-flex mb-2 small cursor-pointer" onClick={ toggleList }>
|
||||||
|
// <i className={ "fas " + classNames({ 'fa-plus': !isExtended, 'fa-minus': isExtended })}></i>
|
||||||
|
// <div className="align-self-center w-100 ml-2">{ LocalizeText(getListCode()) }</div>
|
||||||
|
// <i className={ "fas " + classNames({ 'fa-bars': displayMode === NavigatorResultListViewDisplayMode.LIST, 'fa-th': displayMode >= NavigatorResultListViewDisplayMode.THUMBNAILS })} onClick={ toggleDisplayMode }></i>
|
||||||
|
// </div>
|
||||||
|
// <div className={ 'row mr-n2 row-cols-' + classNames({ '1': displayMode === NavigatorResultListViewDisplayMode.LIST, '2': displayMode >= NavigatorResultListViewDisplayMode.THUMBNAILS }) }>
|
||||||
|
// { isExtended && resultList && resultList.rooms.map((room, index) =>
|
||||||
|
// {
|
||||||
|
// return <NavigatorResultView key={ index } result={ room } />
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
import { NavigatorSearchResultList } from 'nitro-renderer';
|
import { NavigatorSearchResultList } from 'nitro-renderer';
|
||||||
|
|
||||||
export interface NavigatorResultListViewProps
|
export interface NavigatorSearchResultViewProps
|
||||||
{
|
{
|
||||||
resultList: NavigatorSearchResultList;
|
searchResult: NavigatorSearchResultList;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NavigatorResultListViewDisplayMode
|
export class NavigatorSearchResultViewDisplayMode
|
||||||
{
|
{
|
||||||
public static readonly LIST: number = 0;
|
public static readonly LIST: number = 0;
|
||||||
public static readonly THUMBNAILS: number = 1;
|
public static readonly THUMBNAILS: number = 1;
|
25
src/views/navigator/views/search/NavigatorSearchView.tsx
Normal file
25
src/views/navigator/views/search/NavigatorSearchView.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { LocalizeText } from '../../../../utils/LocalizeText';
|
||||||
|
import { NavigatorSearchViewProps } from './NavigatorSearchView.types';
|
||||||
|
|
||||||
|
export const NavigatorSearchView: FC<NavigatorSearchViewProps> = props =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<div className="d-flex mb-1">
|
||||||
|
<div className="flex-grow-1 input-group">
|
||||||
|
<button type="button" className="btn btn-primary btn-sm dropdown-toggle">{ LocalizeText('navigator.filter.') }</button>
|
||||||
|
<ul className="dropdown-menu">
|
||||||
|
<li>
|
||||||
|
<p className="dropdown-item">{ LocalizeText('navigator.filter.') }</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<input type="text" className="form-control form-control-sm" />
|
||||||
|
</div>
|
||||||
|
<div className="ms-1 d-flex">
|
||||||
|
<button type="button" className="btn btn-primary btn-sm">
|
||||||
|
<i className="fas fa-search"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user