Navigator settings update

This commit is contained in:
Bill 2022-03-27 18:44:29 -04:00
parent d250f24df5
commit afc6bc44f8
12 changed files with 455 additions and 367 deletions

View File

@ -0,0 +1,8 @@
export interface IRoomChatSettings
{
mode: number;
weight: number;
speed: number;
distance: number;
protection: number;
}

View File

@ -0,0 +1,23 @@
import { IRoomChatSettings } from './IRoomChatSettings';
import { IRoomModerationSettings } from './IRoomModerationSettings';
export interface IRoomData
{
roomId: number;
roomName: string;
roomDescription: string;
categoryId: number;
userCount: number;
tags: string[];
tradeState: number;
allowWalkthrough: boolean;
lockState: number;
password: string;
allowPets: boolean;
allowPetsEat: boolean;
hideWalls: boolean;
wallThickness: number;
floorThickness: number;
chatSettings: IRoomChatSettings;
moderationSettings: IRoomModerationSettings;
}

View File

@ -0,0 +1,6 @@
export interface IRoomModerationSettings
{
allowMute: number;
allowKick: number;
allowBan: number;
}

View File

@ -1,6 +1,9 @@
export * from './DoorStateType'; export * from './DoorStateType';
export * from './INavigatorData'; export * from './INavigatorData';
export * from './INavigatorSearchFilter'; export * from './INavigatorSearchFilter';
export * from './IRoomChatSettings';
export * from './IRoomData';
export * from './IRoomModerationSettings';
export * from './NavigatorSearchResultViewDisplayMode'; export * from './NavigatorSearchResultViewDisplayMode';
export * from './RoomInfoData'; export * from './RoomInfoData';
export * from './RoomModels'; export * from './RoomModels';

View File

@ -16,11 +16,9 @@ export class NavigatorRoomInfoViewProps
export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props => export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
{ {
const { onCloseClick = null } = props; const { onCloseClick = null } = props;
const [ roomThumbnail, setRoomThumbnail ] = useState(null);
const [ isRoomPicked, setIsRoomPicked ] = useState(false); const [ isRoomPicked, setIsRoomPicked ] = useState(false);
const [ isRoomMuted, setIsRoomMuted ] = useState(false); const [ isRoomMuted, setIsRoomMuted ] = useState(false);
const { navigatorData = null } = useNavigatorContext(); const { navigatorData = null } = useNavigatorContext();
const isMod = GetSessionDataManager().isModerator;
const hasPermission = (permission: string) => const hasPermission = (permission: string) =>
@ -28,7 +26,7 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
switch(permission) switch(permission)
{ {
case 'settings': case 'settings':
return (GetSessionDataManager().userId === navigatorData.enteredGuestRoom.ownerId || isMod ); return (GetSessionDataManager().userId === navigatorData.enteredGuestRoom.ownerId || GetSessionDataManager().isModerator);
case 'staff_pick': case 'staff_pick':
return GetSessionDataManager().securityLevel >= SecurityLevel.COMMUNITY; return GetSessionDataManager().securityLevel >= SecurityLevel.COMMUNITY;
default: return false; default: return false;
@ -49,7 +47,7 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
newRoomId = navigatorData.enteredGuestRoom.roomId; newRoomId = navigatorData.enteredGuestRoom.roomId;
} }
SendMessageComposer(new UserHomeRoomComposer(newRoomId)); if(newRoomId > 0) SendMessageComposer(new UserHomeRoomComposer(newRoomId));
return; return;
case 'navigator_search_tag': case 'navigator_search_tag':
return; return;

View File

@ -1,27 +1,38 @@
import { RoomDataParser } from '@nitrots/nitro-renderer'; import { RoomDataParser } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react'; import { FC, useEffect, useState } from 'react';
import { LocalizeText, RoomSettingsData } from '../../../../api'; import { IRoomData, LocalizeText } from '../../../../api';
import { Column, Flex, Text } from '../../../../common'; import { Column, Flex, Text } from '../../../../common';
import { BatchUpdates } from '../../../../hooks';
interface NavigatorRoomSettingsTabViewProps interface NavigatorRoomSettingsTabViewProps
{ {
roomSettingsData: RoomSettingsData; roomData: IRoomData;
handleChange: (field: string, value: string | number | boolean) => void; handleChange: (field: string, value: string | number | boolean) => void;
} }
export const NavigatorRoomSettingsAccessTabView: FC<NavigatorRoomSettingsTabViewProps> = props => export const NavigatorRoomSettingsAccessTabView: FC<NavigatorRoomSettingsTabViewProps> = props =>
{ {
const { roomSettingsData = null, handleChange = null } = props; const { roomData = null, handleChange = null } = props;
const [ password, setPassword ] = useState<string>('');
const [ confirmPassword, setConfirmPassword ] = useState('');
const [ isTryingPassword, setIsTryingPassword ] = useState(false);
const isPasswordValid = useCallback(() => const saveRoomPassword = () =>
{ {
return (roomSettingsData.password && (roomSettingsData.password.length > 0) && (roomSettingsData.password === roomSettingsData.confirmPassword)); if(!isTryingPassword || ((password.length <= 0) || (confirmPassword.length <= 0) || (password !== confirmPassword))) return;
}, [ roomSettingsData ]);
const trySave = useCallback(() => handleChange('password', password);
}
useEffect(() =>
{ {
if(isPasswordValid()) handleChange('save', null); BatchUpdates(() =>
}, [ isPasswordValid, handleChange ]); {
setPassword('');
setConfirmPassword('');
setIsTryingPassword(false);
});
}, [ roomData ]);
return ( return (
<> <>
@ -33,27 +44,31 @@ export const NavigatorRoomSettingsAccessTabView: FC<NavigatorRoomSettingsTabView
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('navigator.roomsettings.doormode') }</Text> <Text bold>{ LocalizeText('navigator.roomsettings.doormode') }</Text>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="radio" name="lockState" checked={ (roomSettingsData.lockState === RoomDataParser.OPEN_STATE) } onChange={ event => handleChange('lock_state', RoomDataParser.OPEN_STATE) } /> <input className="form-check-input" type="radio" name="lockState" checked={ (roomData.lockState === RoomDataParser.OPEN_STATE) && !isTryingPassword } onChange={ event => handleChange('lock_state', RoomDataParser.OPEN_STATE) } />
<Text>{ LocalizeText('navigator.roomsettings.doormode.open') }</Text> <Text>{ LocalizeText('navigator.roomsettings.doormode.open') }</Text>
</Flex> </Flex>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="radio" name="lockState" checked={ (roomSettingsData.lockState === RoomDataParser.DOORBELL_STATE) } onChange={ event => handleChange('lock_state', RoomDataParser.DOORBELL_STATE) } /> <input className="form-check-input" type="radio" name="lockState" checked={ (roomData.lockState === RoomDataParser.DOORBELL_STATE) && !isTryingPassword } onChange={ event => handleChange('lock_state', RoomDataParser.DOORBELL_STATE) } />
<Text>{ LocalizeText('navigator.roomsettings.doormode.doorbell') }</Text> <Text>{ LocalizeText('navigator.roomsettings.doormode.doorbell') }</Text>
</Flex> </Flex>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="radio" name="lockState" checked={ (roomSettingsData.lockState === RoomDataParser.INVISIBLE_STATE) } onChange={ event => handleChange('lock_state', RoomDataParser.INVISIBLE_STATE) } /> <input className="form-check-input" type="radio" name="lockState" checked={ (roomData.lockState === RoomDataParser.INVISIBLE_STATE) && !isTryingPassword } onChange={ event => handleChange('lock_state', RoomDataParser.INVISIBLE_STATE) } />
<Text>{ LocalizeText('navigator.roomsettings.doormode.invisible') }</Text> <Text>{ LocalizeText('navigator.roomsettings.doormode.invisible') }</Text>
</Flex> </Flex>
<Flex fullWidth gap={ 1 }> <Flex fullWidth gap={ 1 }>
<input className="form-check-input" type="radio" name="lockState" checked={ (roomSettingsData.lockState === RoomDataParser.PASSWORD_STATE) } onChange={ event => handleChange('lock_state', RoomDataParser.PASSWORD_STATE) } /> <input className="form-check-input" type="radio" name="lockState" checked={ (roomData.lockState === RoomDataParser.PASSWORD_STATE) || isTryingPassword } onChange={ event => setIsTryingPassword(event.target.checked) } />
{ (roomSettingsData.lockState !== RoomDataParser.PASSWORD_STATE) && { !isTryingPassword && (roomData.lockState !== RoomDataParser.PASSWORD_STATE) &&
<Text>{ LocalizeText('navigator.roomsettings.doormode.password') }</Text> } <Text>{ LocalizeText('navigator.roomsettings.doormode.password') }</Text> }
{ (roomSettingsData.lockState === RoomDataParser.PASSWORD_STATE) && { (isTryingPassword || (roomData.lockState === RoomDataParser.PASSWORD_STATE)) &&
<Column gap={ 1 }> <Column gap={ 1 }>
<Text>{ LocalizeText('navigator.roomsettings.doormode.password') }</Text> <Text>{ LocalizeText('navigator.roomsettings.doormode.password') }</Text>
<input type="password" className="form-control form-control-sm col-4" value={ roomSettingsData.password ?? '' } onChange={ (e) => handleChange('password', e.target.value) } onBlur={ trySave } placeholder={ LocalizeText('navigator.roomsettings.password') } /> <input type="password" className="form-control form-control-sm col-4" value={ password } onChange={ event => setPassword(event.target.value) } placeholder={ LocalizeText('navigator.roomsettings.password') } onFocus={ event => setIsTryingPassword(true) } />
<input type="password" className="form-control form-control-sm col-4" value={ roomSettingsData.confirmPassword ?? '' } onChange={ (e) => handleChange('confirm_password', e.target.value) } onBlur={ trySave } placeholder={ LocalizeText('navigator.roomsettings.passwordconfirm') } /> { isTryingPassword && (password.length <= 0) &&
{ !isPasswordValid() && <Text bold small variant="danger">
{ LocalizeText('navigator.roomsettings.passwordismandatory') }
</Text> }
<input type="password" className="form-control form-control-sm col-4" value={ confirmPassword } onChange={ event => setConfirmPassword(event.target.value) } onBlur={ saveRoomPassword } placeholder={ LocalizeText('navigator.roomsettings.passwordconfirm') } />
{ isTryingPassword && ((password.length > 0) && (password !== confirmPassword)) &&
<Text bold small variant="danger"> <Text bold small variant="danger">
{ LocalizeText('navigator.roomsettings.invalidconfirm') } { LocalizeText('navigator.roomsettings.invalidconfirm') }
</Text> } </Text> }
@ -63,11 +78,11 @@ export const NavigatorRoomSettingsAccessTabView: FC<NavigatorRoomSettingsTabView
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('navigator.roomsettings.pets') }</Text> <Text bold>{ LocalizeText('navigator.roomsettings.pets') }</Text>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={ roomSettingsData.allowPets } onChange={ event => handleChange('allow_pets', event.target.checked) } /> <input className="form-check-input" type="checkbox" checked={ roomData.allowPets } onChange={ event => handleChange('allow_pets', event.target.checked) } />
<Text>{ LocalizeText('navigator.roomsettings.allowpets') }</Text> <Text>{ LocalizeText('navigator.roomsettings.allowpets') }</Text>
</Flex> </Flex>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={ roomSettingsData.allowPetsEat } onChange={ event => handleChange('allow_pets_eat', event.target.checked) } /> <input className="form-check-input" type="checkbox" checked={ roomData.allowPetsEat } onChange={ event => handleChange('allow_pets_eat', event.target.checked) } />
<Text>{ LocalizeText('navigator.roomsettings.allowfoodconsume') }</Text> <Text>{ LocalizeText('navigator.roomsettings.allowfoodconsume') }</Text>
</Flex> </Flex>
</Column> </Column>

View File

@ -1,15 +1,18 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { RoomDeleteComposer } from '@nitrots/nitro-renderer'; import { RoomDeleteComposer } from '@nitrots/nitro-renderer';
import { FC } from 'react'; import { FC, useEffect, useState } from 'react';
import { CreateLinkEvent, GetMaxVisitorsList, LocalizeText, NotificationUtilities, RoomSettingsData, SendMessageComposer } from '../../../../api'; import { CreateLinkEvent, GetMaxVisitorsList, IRoomData, LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../api';
import { Base, Flex, Text } from '../../../../common'; import { Base, Column, Flex, Text } from '../../../../common';
import { BatchUpdates } from '../../../../hooks';
import { useNavigatorContext } from '../../NavigatorContext'; import { useNavigatorContext } from '../../NavigatorContext';
const ROOM_NAME_MIN_LENGTH = 3;
const ROOM_NAME_MAX_LENGTH = 60;
const DESC_MAX_LENGTH = 255; const DESC_MAX_LENGTH = 255;
interface NavigatorRoomSettingsTabViewProps interface NavigatorRoomSettingsTabViewProps
{ {
roomSettingsData: RoomSettingsData; roomData: IRoomData;
handleChange: (field: string, value: string | number | boolean) => void; handleChange: (field: string, value: string | number | boolean) => void;
close: () => void; close: () => void;
} }
@ -17,14 +20,16 @@ interface NavigatorRoomSettingsTabViewProps
export const NavigatorRoomSettingsBasicTabView: FC<NavigatorRoomSettingsTabViewProps> = props => export const NavigatorRoomSettingsBasicTabView: FC<NavigatorRoomSettingsTabViewProps> = props =>
{ {
const { roomSettingsData = null, handleChange = null, close = null } = props; const { roomData = null, handleChange = null, close = null } = props;
const [ roomName, setRoomName ] = useState<string>('');
const [ roomDescription, setRoomDescription ] = useState<string>('');
const { categories = null } = useNavigatorContext(); const { categories = null } = useNavigatorContext();
const deleteRoom = () => const deleteRoom = () =>
{ {
NotificationUtilities.confirm(LocalizeText('navigator.roomsettings.deleteroom.confirm.message', [ 'room_name' ], [ roomSettingsData.roomName ] ), () => NotificationUtilities.confirm(LocalizeText('navigator.roomsettings.deleteroom.confirm.message', [ 'room_name' ], [ roomData.roomName ] ), () =>
{ {
SendMessageComposer(new RoomDeleteComposer(roomSettingsData.roomId)); SendMessageComposer(new RoomDeleteComposer(roomData.roomId));
if(close) close(); if(close) close();
@ -33,31 +38,60 @@ export const NavigatorRoomSettingsBasicTabView: FC<NavigatorRoomSettingsTabViewP
null, null, null, LocalizeText('navigator.roomsettings.deleteroom.confirm.title')); null, null, null, LocalizeText('navigator.roomsettings.deleteroom.confirm.title'));
} }
const saveRoomName = () =>
{
if((roomName === roomData.roomName) || (roomName.length < ROOM_NAME_MIN_LENGTH) || (roomName.length > ROOM_NAME_MAX_LENGTH)) return;
handleChange('name', roomName);
}
const saveRoomDescription = () =>
{
if((roomDescription === roomData.roomDescription) || (roomDescription.length > DESC_MAX_LENGTH)) return;
handleChange('description', roomDescription);
}
useEffect(() =>
{
BatchUpdates(() =>
{
setRoomName(roomData.roomName);
setRoomDescription(roomData.roomDescription);
});
}, [ roomData ]);
return ( return (
<> <>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<Text className="col-3">{ LocalizeText('navigator.roomname') }</Text> <Text className="col-3">{ LocalizeText('navigator.roomname') }</Text>
<input className="form-control form-control-sm" value={ roomSettingsData.roomName } onChange={ event => handleChange('name', event.target.value) } onBlur={ event => handleChange('save', null) } /> <Column fullWidth gap={ 0 }>
<input className="form-control form-control-sm" value={ roomName } maxLength={ ROOM_NAME_MAX_LENGTH } onChange={ event => setRoomName(event.target.value) } onBlur={ saveRoomName } />
{ (roomName.length < ROOM_NAME_MIN_LENGTH) &&
<Text bold small variant="danger">
{ LocalizeText('navigator.roomsettings.roomnameismandatory') }
</Text> }
</Column>
</Flex> </Flex>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<Text className="col-3">{ LocalizeText('navigator.roomsettings.desc') }</Text> <Text className="col-3">{ LocalizeText('navigator.roomsettings.desc') }</Text>
<textarea className="form-control form-control-sm" value={ roomSettingsData.roomDescription } onChange={ event => handleChange('description', event.target.value) } onBlur={ event => handleChange('save', null) } maxLength={ DESC_MAX_LENGTH } /> <textarea className="form-control form-control-sm" value={ roomDescription } maxLength={ DESC_MAX_LENGTH } onChange={ event => setRoomDescription(event.target.value) } onBlur={ saveRoomDescription } />
</Flex> </Flex>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<Text className="col-3">{ LocalizeText('navigator.category') }</Text> <Text className="col-3">{ LocalizeText('navigator.category') }</Text>
<select className="form-select form-select-sm" value={ roomSettingsData.categoryId } onChange={ event => handleChange('category', event.target.value) }> <select className="form-select form-select-sm" value={ roomData.categoryId } onChange={ event => handleChange('category', event.target.value) }>
{ categories && categories.map(category => <option key={ category.id } value={ category.id }>{ LocalizeText(category.name) }</option>) } { categories && categories.map(category => <option key={ category.id } value={ category.id }>{ LocalizeText(category.name) }</option>) }
</select> </select>
</Flex> </Flex>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<Text className="col-3">{ LocalizeText('navigator.maxvisitors') }</Text> <Text className="col-3">{ LocalizeText('navigator.maxvisitors') }</Text>
<select className="form-select form-select-sm" value={ roomSettingsData.userCount } onChange={ event => handleChange('max_visitors', event.target.value) }> <select className="form-select form-select-sm" value={ roomData.userCount } onChange={ event => handleChange('max_visitors', event.target.value) }>
{ GetMaxVisitorsList && GetMaxVisitorsList.map(value => <option key={ value } value={ value }>{ value }</option>) } { GetMaxVisitorsList && GetMaxVisitorsList.map(value => <option key={ value } value={ value }>{ value }</option>) }
</select> </select>
</Flex> </Flex>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<Text className="col-3">{ LocalizeText('navigator.tradesettings') }</Text> <Text className="col-3">{ LocalizeText('navigator.tradesettings') }</Text>
<select className="form-select form-select-sm" value={ roomSettingsData.tradeState } onChange={ event => handleChange('trade_state', event.target.value) }> <select className="form-select form-select-sm" value={ roomData.tradeState } onChange={ event => handleChange('trade_state', event.target.value) }>
<option value="0">{ LocalizeText('navigator.roomsettings.trade_not_allowed') }</option> <option value="0">{ LocalizeText('navigator.roomsettings.trade_not_allowed') }</option>
<option value="1">{ LocalizeText('navigator.roomsettings.trade_not_with_Controller') }</option> <option value="1">{ LocalizeText('navigator.roomsettings.trade_not_with_Controller') }</option>
<option value="2">{ LocalizeText('navigator.roomsettings.trade_allowed') }</option> <option value="2">{ LocalizeText('navigator.roomsettings.trade_allowed') }</option>
@ -65,7 +99,7 @@ export const NavigatorRoomSettingsBasicTabView: FC<NavigatorRoomSettingsTabViewP
</Flex> </Flex>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<Base className="col-3" /> <Base className="col-3" />
<input className="form-check-input" type="checkbox" checked={ roomSettingsData.allowWalkthrough } onChange={ event => handleChange('allow_walkthrough', event.target.checked) } /> <input className="form-check-input" type="checkbox" checked={ roomData.allowWalkthrough } onChange={ event => handleChange('allow_walkthrough', event.target.checked) } />
<Text>{ LocalizeText('navigator.roomsettings.allow_walk_through') }</Text> <Text>{ LocalizeText('navigator.roomsettings.allow_walk_through') }</Text>
</Flex> </Flex>
<Text variant="danger" underline bold pointer className="d-flex justify-content-center align-items-center gap-1" onClick={ deleteRoom }> <Text variant="danger" underline bold pointer className="d-flex justify-content-center align-items-center gap-1" onClick={ deleteRoom }>

View File

@ -1,45 +1,103 @@
import { RoomUnbanUserComposer } from '@nitrots/nitro-renderer'; import { BannedUserData, BannedUsersFromRoomEvent, RoomBannedUsersComposer, RoomUnbanUserComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react'; import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText, RoomSettingsData, SendMessageComposer } from '../../../../api'; import { IRoomData, LocalizeText, SendMessageComposer } from '../../../../api';
import { Base, Button, Column, Grid, Text } from '../../../../common'; import { Button, Column, Flex, Grid, Text, UserProfileIconView } from '../../../../common';
import { UseMessageEventHook } from '../../../../hooks';
interface NavigatorRoomSettingsTabViewProps interface NavigatorRoomSettingsTabViewProps
{ {
roomSettingsData: RoomSettingsData; roomData: IRoomData;
handleChange: (field: string, value: string | number | boolean) => void; handleChange: (field: string, value: string | number | boolean) => void;
} }
export const NavigatorRoomSettingsModTabView: FC<NavigatorRoomSettingsTabViewProps> = props => export const NavigatorRoomSettingsModTabView: FC<NavigatorRoomSettingsTabViewProps> = props =>
{ {
const { roomSettingsData = null, handleChange = null } = props; const { roomData = null, handleChange = null } = props;
const [ selectedUserId, setSelectedUserId ] = useState<number>(-1); const [ selectedUserId, setSelectedUserId ] = useState<number>(-1);
const [ bannedUsers, setBannedUsers ] = useState<BannedUserData[]>([]);
const onBannedUsersFromRoomEvent = useCallback((event: BannedUsersFromRoomEvent) =>
{
const parser = event.getParser();
if(!roomData || (roomData.roomId !== parser.roomId)) return;
setBannedUsers(parser.bannedUsers);
}, [ roomData ]);
UseMessageEventHook(BannedUsersFromRoomEvent, onBannedUsersFromRoomEvent);
const unBanUser = useCallback((userId: number) => const unBanUser = useCallback((userId: number) =>
{ {
handleChange('unban_user', userId) setBannedUsers(prevValue =>
{
const newValue = [ ...prevValue ];
const index = newValue.findIndex(value => (value.userId === userId));
if(index >= 0) newValue.splice(index, 1);
return newValue;
})
SendMessageComposer(new RoomUnbanUserComposer(userId, roomData.roomId));
SendMessageComposer(new RoomUnbanUserComposer(userId, roomSettingsData.roomId));
setSelectedUserId(-1); setSelectedUserId(-1);
}, [ roomSettingsData, handleChange ]); }, [ roomData ]);
useEffect(() =>
{
SendMessageComposer(new RoomBannedUsersComposer(roomData.roomId));
}, [ roomData.roomId ]);
return ( return (
<Grid overflow="auto"> <Grid overflow="auto">
<Column size={ 6 }> <Column size={ 6 }>
<Text bold>{ LocalizeText('navigator.roomsettings.moderation.banned.users') } ({ roomSettingsData.bannedUsers.length })</Text> <Text bold>{ LocalizeText('navigator.roomsettings.moderation.banned.users') } ({ bannedUsers.length })</Text>
<Column className="bg-white rounded" overflow="hidden"> <Flex overflow="hidden" className="bg-white rounded list-container p-2">
<Base className="list-container" overflow="auto"> <Column fullWidth overflow="auto" gap={ 1 }>
{ roomSettingsData.bannedUsers.map((user, index) => { bannedUsers && (bannedUsers.length > 0) && bannedUsers.map((user, index) =>
{ {
return <Text key={ index } className={ ((user.userId === selectedUserId) ? 'selected' : '') } onClick={ event => setSelectedUserId(user.userId)}>{ user.userName }</Text> return (
<Flex key={ index } shrink alignItems="center" gap={ 1 } overflow="hidden">
<UserProfileIconView userName={ user.userName } />
<Text pointer grow onClick={ event => setSelectedUserId(user.userId) }> { user.userName }</Text>
</Flex>
);
}) } }) }
</Base> </Column>
</Column> </Flex>
</Column> <Button disabled={ (selectedUserId <= 0) } onClick={ event => unBanUser(selectedUserId) }>
<Column size={ 6 } justifyContent="end"> { LocalizeText('navigator.roomsettings.moderation.unban') } {selectedUserId > 0 && bannedUsers.find(user => (user.userId === selectedUserId))?.userName }
<Button disabled={ (selectedUserId < 1) } onClick={ event => unBanUser(selectedUserId) }>
{/* { LocalizeText('navigator.roomsettings.moderation.unban')} {selectedUserId > 0 && roomSettingsData.bannedUsers.get(selectedUserId) } */}
</Button> </Button>
</Column> </Column>
<Column size={ 6 }>
<Column gap={ 1 }>
<Text bold>{ LocalizeText('navigator.roomsettings.moderation.mute.header') }</Text>
<Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={ (roomData.moderationSettings.allowMute === 1) } onChange={ event => handleChange('moderation_mute', (event.target.checked ? 1 : 0)) } />
<Text>{ LocalizeText('navigator.roomsettings.moderation.rights') }</Text>
</Flex>
</Column>
<Column gap={ 1 }>
<Text bold>{LocalizeText('navigator.roomsettings.moderation.kick.header')}</Text>
<Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={ (roomData.moderationSettings.allowKick === 0) } onChange={ event => handleChange('moderation_kick', (event.target.checked ? 0 : 2)) } />
<Text>{ LocalizeText('navigator.roomsettings.moderation.all') }</Text>
</Flex>
<Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={ ((roomData.moderationSettings.allowKick === 1) || (roomData.moderationSettings.allowKick === 0)) } disabled={ (roomData.moderationSettings.allowKick === 0) } onChange={ event => handleChange('moderation_kick', (event.target.checked ? 1 : 2)) } />
<Text>{ LocalizeText('navigator.roomsettings.moderation.rights') }</Text>
</Flex>
</Column>
<Column gap={ 1 }>
<Text bold>{LocalizeText('navigator.roomsettings.moderation.ban.header')}</Text>
<Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={ (roomData.moderationSettings.allowBan === 1) } onChange={ event => handleChange('moderation_ban', (event.target.checked ? 1 : 0)) } />
<Text>{ LocalizeText('navigator.roomsettings.moderation.rights') }</Text>
</Flex>
</Column>
</Column>
</Grid> </Grid>
); );
} }

View File

@ -1,82 +1,97 @@
import { RemoveAllRightsMessageComposer, RoomTakeRightsComposer } from '@nitrots/nitro-renderer'; import { FlatControllerAddedEvent, FlatControllerRemovedEvent, FlatControllersEvent, RemoveAllRightsMessageComposer, RoomTakeRightsComposer, RoomUsersWithRightsComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react'; import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText, RoomSettingsData, SendMessageComposer } from '../../../../api'; import { IRoomData, LocalizeText, SendMessageComposer } from '../../../../api';
import { Button, Column, Flex, Grid, Text, UserProfileIconView } from '../../../../common'; import { Button, Column, Flex, Grid, Text, UserProfileIconView } from '../../../../common';
import { UseMessageEventHook } from '../../../../hooks';
interface NavigatorRoomSettingsTabViewProps interface NavigatorRoomSettingsTabViewProps
{ {
roomSettingsData: RoomSettingsData; roomData: IRoomData;
handleChange: (field: string, value: string | number | boolean) => void; handleChange: (field: string, value: string | number | boolean) => void;
} }
export const NavigatorRoomSettingsRightsTabView: FC<NavigatorRoomSettingsTabViewProps> = props => export const NavigatorRoomSettingsRightsTabView: FC<NavigatorRoomSettingsTabViewProps> = props =>
{ {
const { roomSettingsData = null, handleChange = null } = props; const { roomData = null } = props;
const [ usersWithRights, setUsersWithRights ] = useState<Map<number, string>>(new Map());
const removeUserRights = useCallback( (userId: number) => const onFlatControllersEvent = useCallback((event: FlatControllersEvent) =>
{ {
handleChange('remove_rights_user', userId); const parser = event.getParser();
SendMessageComposer(new RoomTakeRightsComposer(userId)); if(!roomData || (roomData.roomId !== parser.roomId)) return;
}, [ handleChange ]);
const removeAllRights = useCallback( () => setUsersWithRights(parser.users);
}, [ roomData ]);
UseMessageEventHook(FlatControllersEvent, onFlatControllersEvent);
const onFlatControllerAddedEvent = useCallback((event: FlatControllerAddedEvent) =>
{ {
handleChange('remove_all_rights', null); const parser = event.getParser();
SendMessageComposer(new RemoveAllRightsMessageComposer(roomSettingsData.roomId)); if(!roomData || (roomData.roomId !== parser.roomId)) return;
}, [ roomSettingsData, handleChange ]);
setUsersWithRights(prevValue =>
{
const newValue = new Map(prevValue);
newValue.set(parser.data.userId, parser.data.userName);
return newValue;
});
}, [ roomData ]);
UseMessageEventHook(FlatControllerAddedEvent, onFlatControllerAddedEvent);
const onFlatControllerRemovedEvent = useCallback((event: FlatControllerRemovedEvent) =>
{
const parser = event.getParser();
if(!roomData || (roomData.roomId !== parser.roomId)) return;
setUsersWithRights(prevValue =>
{
const newValue = new Map(prevValue);
newValue.delete(parser.userId);
return newValue;
});
}, [ roomData ]);
UseMessageEventHook(FlatControllerRemovedEvent, onFlatControllerRemovedEvent);
useEffect(() =>
{
SendMessageComposer(new RoomUsersWithRightsComposer(roomData.roomId));
}, [ roomData.roomId ]);
return ( return (
<Grid> <Grid>
<Column size={ 6 }> <Column size={ 6 }>
<Text bold> <Text bold>
{ LocalizeText('navigator.flatctrls.userswithrights', [ 'displayed', 'total' ], [ roomSettingsData.usersWithRights.size.toString(), roomSettingsData.usersWithRights.size.toString() ]) } { LocalizeText('navigator.flatctrls.userswithrights', [ 'displayed', 'total' ], [ usersWithRights.size.toString(), usersWithRights.size.toString() ]) }
</Text> </Text>
<Flex overflow="hidden" className="bg-white rounded list-container p-2"> <Flex overflow="hidden" className="bg-white rounded list-container p-2">
<Column fullWidth overflow="auto" gap={ 1 }> <Column fullWidth overflow="auto" gap={ 1 }>
{ Array.from(roomSettingsData.usersWithRights.entries()).map(([id, name], index) => { Array.from(usersWithRights.entries()).map(([ id, name ], index) =>
{ {
return ( return (
<Flex key={ index } shrink alignItems="center" gap={ 1 } overflow="hidden"> <Flex key={ index } shrink alignItems="center" gap={ 1 } overflow="hidden">
<UserProfileIconView userName={ name } /> <UserProfileIconView userName={ name } />
<Text pointer grow key={index} onClick={ event => removeUserRights(id) }> { name }</Text> <Text pointer grow onClick={ event => SendMessageComposer(new RoomTakeRightsComposer(id)) }> { name }</Text>
</Flex> </Flex>
); );
}) } }) }
</Column> </Column>
</Flex> </Flex>
<Button variant="danger" disabled={ !roomSettingsData.usersWithRights.size } onClick={ removeAllRights } > </Column>
<Column size={ 6 } justifyContent="end">
<Button variant="danger" disabled={ !usersWithRights.size } onClick={ event => SendMessageComposer(new RemoveAllRightsMessageComposer(roomData.roomId)) } >
{ LocalizeText('navigator.flatctrls.clear') } { LocalizeText('navigator.flatctrls.clear') }
</Button> </Button>
</Column> </Column>
<Column size={ 6 }>
<Column gap={ 1 }>
<Text bold>{ LocalizeText('navigator.roomsettings.moderation.mute.header') }</Text>
<Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={ (roomSettingsData.muteState === 1) } onChange={ event => handleChange('moderation_mute', (event.target.checked ? 1 : 0)) } />
<Text>{ LocalizeText('navigator.roomsettings.moderation.rights') }</Text>
</Flex>
</Column>
<Column gap={ 1 }>
<Text bold>{LocalizeText('navigator.roomsettings.moderation.kick.header')}</Text>
<Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={ (roomSettingsData.kickState === 0) } onChange={ event => handleChange('moderation_kick', (event.target.checked ? 0 : 2)) } />
<Text>{ LocalizeText('navigator.roomsettings.moderation.all') }</Text>
</Flex>
<Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={ ((roomSettingsData.kickState === 1) || (roomSettingsData.kickState === 0)) } disabled={ (roomSettingsData.kickState === 0) } onChange={ event => handleChange('moderation_kick', (event.target.checked ? 1 : 2)) } />
<Text>{ LocalizeText('navigator.roomsettings.moderation.rights') }</Text>
</Flex>
</Column>
<Column gap={ 1 }>
<Text bold>{LocalizeText('navigator.roomsettings.moderation.ban.header')}</Text>
<Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={ (roomSettingsData.banState === 1) } onChange={ event => handleChange('moderation_ban', (event.target.checked ? 1 : 0)) } />
<Text>{ LocalizeText('navigator.roomsettings.moderation.rights') }</Text>
</Flex>
</Column>
</Column>
</Grid> </Grid>
); );
} }

View File

@ -1,9 +1,8 @@
import { RoomBannedUsersComposer, RoomSettingsEvent, RoomUsersWithRightsComposer, SaveRoomSettingsComposer } from '@nitrots/nitro-renderer'; import { RoomBannedUsersComposer, RoomDataParser, RoomSettingsEvent, SaveRoomSettingsComposer } from '@nitrots/nitro-renderer';
import { BannedUsersFromRoomEvent, FlatControllerAddedEvent, FlatControllerRemovedEvent, FlatControllersEvent } from '@nitrots/nitro-renderer/src/nitro/communication/messages/incoming/roomsettings';
import { FC, useCallback, useState } from 'react'; import { FC, useCallback, useState } from 'react';
import { LocalizeText, RoomSettingsData, SendMessageComposer } from '../../../../api'; import { IRoomData, LocalizeText, SendMessageComposer } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../common'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../common';
import { UseMessageEventHook } from '../../../../hooks'; import { BatchUpdates, UseMessageEventHook } from '../../../../hooks';
import { NavigatorRoomSettingsAccessTabView } from './NavigatorRoomSettingsAccessTabView'; import { NavigatorRoomSettingsAccessTabView } from './NavigatorRoomSettingsAccessTabView';
import { NavigatorRoomSettingsBasicTabView } from './NavigatorRoomSettingsBasicTabView'; import { NavigatorRoomSettingsBasicTabView } from './NavigatorRoomSettingsBasicTabView';
import { NavigatorRoomSettingsModTabView } from './NavigatorRoomSettingsModTabView'; import { NavigatorRoomSettingsModTabView } from './NavigatorRoomSettingsModTabView';
@ -20,248 +19,170 @@ const TABS: string[] = [
export const NavigatorRoomSettingsView: FC<{}> = props => export const NavigatorRoomSettingsView: FC<{}> = props =>
{ {
const [ roomSettingsData, setRoomSettingsData ] = useState<RoomSettingsData>(null); const [ roomData, setRoomData ] = useState<IRoomData>(null);
const [ currentTab, setCurrentTab ] = useState(TABS[0]); const [ currentTab, setCurrentTab ] = useState(TABS[0]);
const onFlatControllersEvent = useCallback((event: FlatControllersEvent) =>
{
const parser = event.getParser();
if(!parser || !roomSettingsData) return;
if(roomSettingsData.roomId !== parser.roomId) return;
const data = Object.assign({}, roomSettingsData);
data.usersWithRights = new Map(parser.users);
setRoomSettingsData(data);
}, [ roomSettingsData] );
UseMessageEventHook(FlatControllersEvent, onFlatControllersEvent);
const onFlatControllerAddedEvent = useCallback((event: FlatControllerAddedEvent) =>
{
const parser = event.getParser();
if(!parser || !roomSettingsData) return;
if(roomSettingsData.roomId !== parser.roomId) return;
const data = Object.assign({}, roomSettingsData);
// add new controller
setRoomSettingsData(data);
}, [ roomSettingsData] );
UseMessageEventHook(FlatControllerAddedEvent, onFlatControllerAddedEvent);
const onFlatControllerRemovedEvent = useCallback((event: FlatControllerRemovedEvent) =>
{
const parser = event.getParser();
if(!parser || !roomSettingsData) return;
if(roomSettingsData.roomId !== parser.roomId) return;
const data = Object.assign({}, roomSettingsData);
// remove controller
setRoomSettingsData(data);
}, [ roomSettingsData] );
UseMessageEventHook(FlatControllerRemovedEvent, onFlatControllerRemovedEvent);
const updateSettings = useCallback((roomSettings: RoomSettingsData) =>
{
setRoomSettingsData(roomSettings);
}, [ setRoomSettingsData ]);
const onRoomSettingsEvent = useCallback((event: RoomSettingsEvent) => const onRoomSettingsEvent = useCallback((event: RoomSettingsEvent) =>
{ {
const parser = event.getParser(); const parser = event.getParser();
if(!parser) return; if(!parser) return;
setRoomSettingsData(new RoomSettingsData(parser)); setRoomData({
SendMessageComposer(new RoomUsersWithRightsComposer(parser.roomId)); roomId: parser.roomId,
roomName: parser.name,
roomDescription: parser.description,
categoryId: parser.categoryId,
userCount: parser.userCount,
tags: parser.tags,
tradeState: parser.tradeMode,
allowWalkthrough: parser.allowWalkthrough,
lockState: parser.state,
password: null,
allowPets: parser.allowPets,
allowPetsEat: parser.allowPetsEat,
hideWalls: parser.hideWalls,
wallThickness: parser.thicknessWall,
floorThickness: parser.thicknessFloor,
chatSettings: {
mode: parser.chatSettings.mode,
weight: parser.chatSettings.weight,
speed: parser.chatSettings.speed,
distance: parser.chatSettings.distance,
protection: parser.chatSettings.protection
},
moderationSettings: {
allowMute: parser.moderationSettings.allowMute,
allowKick: parser.moderationSettings.allowKick,
allowBan: parser.moderationSettings.allowBan
}
});
SendMessageComposer(new RoomBannedUsersComposer(parser.roomId)); SendMessageComposer(new RoomBannedUsersComposer(parser.roomId));
}, []); }, []);
UseMessageEventHook(RoomSettingsEvent, onRoomSettingsEvent); UseMessageEventHook(RoomSettingsEvent, onRoomSettingsEvent);
const onBannedUsersFromRoomEvent = useCallback((event: BannedUsersFromRoomEvent) => const close = () =>
{ {
const parser = event.getParser(); BatchUpdates(() =>
if(!parser || !roomSettingsData) return;
if(roomSettingsData.roomId !== parser.roomId) return;
const data = Object.assign({}, roomSettingsData);
data.bannedUsers = parser.bannedUsers;
setRoomSettingsData(data);
}, [roomSettingsData]);
UseMessageEventHook(BannedUsersFromRoomEvent, onBannedUsersFromRoomEvent);
const saveSettings = useCallback((data: RoomSettingsData) =>
{
SendMessageComposer(
new SaveRoomSettingsComposer(
data.roomId,
data.roomName,
data.roomDescription,
data.lockState,
data.password,
data.userCount,
data.categoryId,
data.tags.length,
data.tags,
data.tradeState,
data.allowPets,
data.allowPetsEat,
data.allowWalkthrough,
data.hideWalls,
data.wallThickness,
data.floorThickness,
data.muteState,
data.kickState,
data.banState,
data.chatBubbleMode,
data.chatBubbleWeight,
data.chatBubbleSpeed,
data.chatDistance,
data.chatFloodProtection
));
}, []);
const processAction = useCallback((action: string) =>
{
switch(action)
{ {
case 'close': setRoomData(null);
setRoomSettingsData(null); setCurrentTab(TABS[0]);
setCurrentTab(TABS[0]); });
return; }
}
}, [ setRoomSettingsData ]);
const handleChange = useCallback((field: string, value: string | number | boolean) => const handleChange = (field: string, value: string | number | boolean) =>
{ {
const roomSettings = Object.assign({}, roomSettingsData); setRoomData(prevValue =>
{
const newValue = { ...prevValue };
let save = true; switch(field)
{
case 'name':
newValue.roomName = String(value);
break;
case 'description':
newValue.roomDescription = String(value);
break;
case 'category':
newValue.categoryId = Number(value);
break;
case 'max_visitors':
newValue.userCount = Number(value);
break;
case 'trade_state':
newValue.tradeState = Number(value);
break;
case 'allow_walkthrough':
newValue.allowWalkthrough = Boolean(value);
break;
case 'allow_pets':
newValue.allowPets = Boolean(value);
break;
case 'allow_pets_eat':
newValue.allowPetsEat = Boolean(value);
break;
case 'hide_walls':
newValue.hideWalls = Boolean(value);
break;
case 'wall_thickness':
newValue.wallThickness = Number(value);
break;
case 'floor_thickness':
newValue.floorThickness = Number(value);
break;
case 'lock_state':
newValue.lockState = Number(value);
break;
case 'password':
newValue.lockState = RoomDataParser.PASSWORD_STATE;
newValue.password = String(value);
break;
case 'moderation_mute':
newValue.moderationSettings.allowMute = Number(value);
break;
case 'moderation_kick':
newValue.moderationSettings.allowKick = Number(value);
break;
case 'moderation_ban':
newValue.moderationSettings.allowBan = Number(value);
break;
case 'bubble_mode':
newValue.chatSettings.mode = Number(value);
break;
case 'chat_weight':
newValue.chatSettings.weight = Number(value);
break;
case 'bubble_speed':
newValue.chatSettings.speed = Number(value);
break;
case 'flood_protection':
newValue.chatSettings.protection = Number(value);
break;
case 'chat_distance':
newValue.chatSettings.distance = Number(value);
break;
}
switch(field) SendMessageComposer(
{ new SaveRoomSettingsComposer(
case 'name': newValue.roomId,
roomSettings.roomName = String(value); newValue.roomName,
save = false; newValue.roomDescription,
break; newValue.lockState,
case 'description': newValue.password,
roomSettings.roomDescription = String(value); newValue.userCount,
save = false; newValue.categoryId,
break; newValue.tags.length,
case 'category': newValue.tags,
roomSettings.categoryId = Number(value); newValue.tradeState,
break; newValue.allowPets,
case 'max_visitors': newValue.allowPetsEat,
roomSettings.userCount = Number(value); newValue.allowWalkthrough,
break; newValue.hideWalls,
case 'trade_state': newValue.wallThickness,
roomSettings.tradeState = Number(value); newValue.floorThickness,
break; newValue.moderationSettings.allowMute,
case 'allow_walkthrough': newValue.moderationSettings.allowKick,
roomSettings.allowWalkthrough = Boolean(value); newValue.moderationSettings.allowBan,
break; newValue.chatSettings.mode,
case 'allow_pets': newValue.chatSettings.weight,
roomSettings.allowPets = Boolean(value); newValue.chatSettings.speed,
break; newValue.chatSettings.distance,
case 'allow_pets_eat': newValue.chatSettings.protection
roomSettings.allowPetsEat = Boolean(value); ));
break;
case 'hide_walls':
roomSettings.hideWalls = Boolean(value);
break;
case 'wall_thickness':
roomSettings.wallThickness = Number(value);
break;
case 'floor_thickness':
roomSettings.floorThickness = Number(value);
break;
case 'lock_state':
roomSettings.lockState = Number(value);
if(Number(value) === 3) save = false; return newValue;
break; });
case 'password': }
roomSettings.password = String(value);
save = false;
break;
case 'confirm_password':
roomSettings.confirmPassword = String(value);
save = false;
break;
case 'moderation_mute':
roomSettings.muteState = Number(value);
break;
case 'moderation_kick':
roomSettings.kickState = Number(value);
break;
case 'moderation_ban':
roomSettings.banState = Number(value);
break;
case 'bubble_mode':
roomSettings.chatBubbleMode = Number(value);
break;
case 'chat_weight':
roomSettings.chatBubbleWeight = Number(value);
break;
case 'bubble_speed':
roomSettings.chatBubbleSpeed = Number(value);
break;
case 'flood_protection':
roomSettings.chatFloodProtection = Number(value);
break;
case 'chat_distance':
roomSettings.chatDistance = Number(value);
save = false;
break;
case 'unban_user': {
const index = roomSettings.bannedUsers.findIndex(user => (user.userId === Number(value)))
if(index > -1) roomSettings.bannedUsers.splice(index, 1); if(!roomData) return null;
save = false;
break;
}
case 'remove_rights_user':
roomSettings.usersWithRights.delete(Number(value));
save = false;
break;
case 'remove_all_rights':
roomSettings.usersWithRights.clear();
save = false;
break;
case 'save':
save = true;
break;
}
setRoomSettingsData(roomSettings);
if(save) saveSettings(roomSettings);
}, [ roomSettingsData, saveSettings ]);
if(!roomSettingsData) return null;
return ( return (
<NitroCardView uniqueKey="nitro-room-settings" className="nitro-room-settings"> <NitroCardView uniqueKey="nitro-room-settings" className="nitro-room-settings">
<NitroCardHeaderView headerText={ LocalizeText('navigator.roomsettings') } onCloseClick={ () => processAction('close') } /> <NitroCardHeaderView headerText={ LocalizeText('navigator.roomsettings') } onCloseClick={ close } />
<NitroCardTabsView> <NitroCardTabsView>
{ TABS.map(tab => { TABS.map(tab =>
{ {
@ -269,16 +190,16 @@ export const NavigatorRoomSettingsView: FC<{}> = props =>
}) } }) }
</NitroCardTabsView> </NitroCardTabsView>
<NitroCardContentView> <NitroCardContentView>
{ currentTab === TABS[0] && { (currentTab === TABS[0]) &&
<NavigatorRoomSettingsBasicTabView roomSettingsData={ roomSettingsData } handleChange={ handleChange } close={ () => processAction('close') } /> } <NavigatorRoomSettingsBasicTabView roomData={ roomData } handleChange={ handleChange } close={ close } /> }
{ currentTab === TABS[1] && { (currentTab === TABS[1]) &&
<NavigatorRoomSettingsAccessTabView roomSettingsData={ roomSettingsData } handleChange={ handleChange } /> } <NavigatorRoomSettingsAccessTabView roomData={ roomData } handleChange={ handleChange } /> }
{ currentTab === TABS[2] && { (currentTab === TABS[2]) &&
<NavigatorRoomSettingsRightsTabView roomSettingsData= {roomSettingsData } handleChange={ handleChange } /> } <NavigatorRoomSettingsRightsTabView roomData= {roomData } handleChange={ handleChange } /> }
{ currentTab === TABS[3] && { (currentTab === TABS[3]) &&
<NavigatorRoomSettingsVipChatTabView roomSettingsData={ roomSettingsData } handleChange={ handleChange } /> } <NavigatorRoomSettingsVipChatTabView roomData={ roomData } handleChange={ handleChange } /> }
{ currentTab === TABS[4] && { (currentTab === TABS[4]) &&
<NavigatorRoomSettingsModTabView roomSettingsData={ roomSettingsData } handleChange={ handleChange } /> } <NavigatorRoomSettingsModTabView roomData={ roomData } handleChange={ handleChange } /> }
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> </NitroCardView>
); );

View File

@ -1,16 +1,23 @@
import { FC } from 'react'; import { RoomChatSettings } from '@nitrots/nitro-renderer';
import { LocalizeText, RoomSettingsData } from '../../../../api'; import { FC, useEffect, useState } from 'react';
import { IRoomData, LocalizeText } from '../../../../api';
import { Column, Flex, Grid, Text } from '../../../../common'; import { Column, Flex, Grid, Text } from '../../../../common';
interface NavigatorRoomSettingsTabViewProps interface NavigatorRoomSettingsTabViewProps
{ {
roomSettingsData: RoomSettingsData; roomData: IRoomData;
handleChange: (field: string, value: string | number | boolean) => void; handleChange: (field: string, value: string | number | boolean) => void;
} }
export const NavigatorRoomSettingsVipChatTabView: FC<NavigatorRoomSettingsTabViewProps> = props => export const NavigatorRoomSettingsVipChatTabView: FC<NavigatorRoomSettingsTabViewProps> = props =>
{ {
const { roomSettingsData = null, handleChange = null } = props; const { roomData = null, handleChange = null } = props;
const [ chatDistance, setChatDistance ] = useState<number>(0);
useEffect(() =>
{
setChatDistance(roomData.chatSettings.distance);
}, [ roomData.chatSettings ]);
return ( return (
<> <>
@ -22,45 +29,45 @@ export const NavigatorRoomSettingsVipChatTabView: FC<NavigatorRoomSettingsTabVie
<Column size={ 6 } gap={ 1 }> <Column size={ 6 } gap={ 1 }>
<Text bold>{LocalizeText('navigator.roomsettings.chat_settings')}</Text> <Text bold>{LocalizeText('navigator.roomsettings.chat_settings')}</Text>
<Text>{LocalizeText('navigator.roomsettings.chat_settings.info')}</Text> <Text>{LocalizeText('navigator.roomsettings.chat_settings.info')}</Text>
<select className="form-select form-select-sm" value={roomSettingsData.chatBubbleMode} onChange={event => handleChange('bubble_mode', event.target.value)}> <select className="form-select form-select-sm" value={ roomData.chatSettings.mode } onChange={ event => handleChange('bubble_mode', event.target.value) }>
<option value="0">{LocalizeText('navigator.roomsettings.chat.mode.free.flow')}</option> <option value={ RoomChatSettings.CHAT_MODE_FREE_FLOW }>{ LocalizeText('navigator.roomsettings.chat.mode.free.flow') }</option>
<option value="1">{LocalizeText('navigator.roomsettings.chat.mode.line.by.line')}</option> <option value={ RoomChatSettings.CHAT_MODE_LINE_BY_LINE }>{ LocalizeText('navigator.roomsettings.chat.mode.line.by.line') }</option>
</select> </select>
<select className="form-select form-select-sm" value={roomSettingsData.chatBubbleWeight} onChange={event => handleChange('chat_weight', event.target.value)}> <select className="form-select form-select-sm" value={ roomData.chatSettings.weight } onChange={ event => handleChange('chat_weight', event.target.value) }>
<option value="1">{LocalizeText('navigator.roomsettings.chat.bubbles.width.normal')}</option> <option value={ RoomChatSettings.CHAT_BUBBLE_WIDTH_NORMAL }>{ LocalizeText('navigator.roomsettings.chat.bubbles.width.normal') }</option>
<option value="2">{LocalizeText('navigator.roomsettings.chat.bubbles.width.thin')}</option> <option value={ RoomChatSettings.CHAT_BUBBLE_WIDTH_THIN }>{ LocalizeText('navigator.roomsettings.chat.bubbles.width.thin') }</option>
<option value="0">{LocalizeText('navigator.roomsettings.chat.bubbles.width.wide')}</option> <option value={ RoomChatSettings.CHAT_BUBBLE_WIDTH_WIDE }>{ LocalizeText('navigator.roomsettings.chat.bubbles.width.wide') }</option>
</select> </select>
<select className="form-select form-select-sm" value={roomSettingsData.chatBubbleSpeed} onChange={event => handleChange('bubble_speed', event.target.value)}> <select className="form-select form-select-sm" value={ roomData.chatSettings.speed } onChange={ event => handleChange('bubble_speed', event.target.value) }>
<option value="0">{LocalizeText('navigator.roomsettings.chat.speed.fast')}</option> <option value={ RoomChatSettings.CHAT_SCROLL_SPEED_FAST }>{ LocalizeText('navigator.roomsettings.chat.speed.fast') }</option>
<option value="1">{LocalizeText('navigator.roomsettings.chat.speed.normal')}</option> <option value={ RoomChatSettings.CHAT_SCROLL_SPEED_NORMAL }>{ LocalizeText('navigator.roomsettings.chat.speed.normal') }</option>
<option value="2">{LocalizeText('navigator.roomsettings.chat.speed.slow')}</option> <option value={ RoomChatSettings.CHAT_SCROLL_SPEED_SLOW }>{ LocalizeText('navigator.roomsettings.chat.speed.slow') }</option>
</select> </select>
<select className="form-select form-select-sm" value={roomSettingsData.chatFloodProtection} onChange={event => handleChange('flood_protection', event.target.value)}> <select className="form-select form-select-sm" value={ roomData.chatSettings.protection } onChange={ event => handleChange('flood_protection', event.target.value) }>
<option value="0">{LocalizeText('navigator.roomsettings.chat.flood.loose')}</option> <option value={ RoomChatSettings.FLOOD_FILTER_LOOSE }>{ LocalizeText('navigator.roomsettings.chat.flood.loose') }</option>
<option value="1">{LocalizeText('navigator.roomsettings.chat.flood.normal')}</option> <option value={ RoomChatSettings.FLOOD_FILTER_NORMAL }>{ LocalizeText('navigator.roomsettings.chat.flood.normal') }</option>
<option value="2">{LocalizeText('navigator.roomsettings.chat.flood.strict')}</option> <option value={ RoomChatSettings.FLOOD_FILTER_STRICT }>{ LocalizeText('navigator.roomsettings.chat.flood.strict') }</option>
</select> </select>
<Text>{ LocalizeText('navigator.roomsettings.chat_settings.hearing.distance') }</Text> <Text>{ LocalizeText('navigator.roomsettings.chat_settings.hearing.distance') }</Text>
<input type="number" min="0" className="form-control form-control-sm" value={roomSettingsData.chatDistance} onChange={event => handleChange('chat_distance', event.target.valueAsNumber)} onBlur={ event => handleChange('save', null) } /> <input type="number" min="0" className="form-control form-control-sm" value={ chatDistance } onChange={ event => setChatDistance(event.target.valueAsNumber) } onBlur={ event => handleChange('chat_distance', chatDistance) } />
</Column> </Column>
<Column size={ 6 } gap={ 1 }> <Column size={ 6 } gap={ 1 }>
<Text bold>{LocalizeText('navigator.roomsettings.vip_settings')}</Text> <Text bold>{LocalizeText('navigator.roomsettings.vip_settings')}</Text>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" checked={roomSettingsData.hideWalls} onChange={(e) => handleChange('hide_walls', e.target.checked)} /> <input className="form-check-input" type="checkbox" checked={ roomData.hideWalls } onChange={ event => handleChange('hide_walls', event.target.checked) } />
<Text>{LocalizeText('navigator.roomsettings.hide_walls')}</Text> <Text>{LocalizeText('navigator.roomsettings.hide_walls')}</Text>
</Flex> </Flex>
<select className="form-select form-select-sm" value={roomSettingsData.wallThickness} onChange={event => handleChange('wall_thickness', event.target.value)}> <select className="form-select form-select-sm" value={ roomData.wallThickness } onChange={ event => handleChange('wall_thickness', event.target.value) }>
<option value="0">{LocalizeText('navigator.roomsettings.wall_thickness.normal')}</option> <option value="0">{ LocalizeText('navigator.roomsettings.wall_thickness.normal') }</option>
<option value="1">{LocalizeText('navigator.roomsettings.wall_thickness.thick')}</option> <option value="1">{ LocalizeText('navigator.roomsettings.wall_thickness.thick') }</option>
<option value="-1">{LocalizeText('navigator.roomsettings.wall_thickness.thin')}</option> <option value="-1">{ LocalizeText('navigator.roomsettings.wall_thickness.thin') }</option>
<option value="-2">{LocalizeText('navigator.roomsettings.wall_thickness.thinnest')}</option> <option value="-2">{ LocalizeText('navigator.roomsettings.wall_thickness.thinnest') }</option>
</select> </select>
<select className="form-select form-select-sm" value={roomSettingsData.floorThickness} onChange={event => handleChange('floor_thickness', event.target.value)}> <select className="form-select form-select-sm" value={roomData.floorThickness} onChange={ event => handleChange('floor_thickness', event.target.value) }>
<option value="0">{LocalizeText('navigator.roomsettings.floor_thickness.normal')}</option> <option value="0">{ LocalizeText('navigator.roomsettings.floor_thickness.normal') }</option>
<option value="1">{LocalizeText('navigator.roomsettings.floor_thickness.thick')}</option> <option value="1">{ LocalizeText('navigator.roomsettings.floor_thickness.thick') }</option>
<option value="-1">{LocalizeText('navigator.roomsettings.floor_thickness.thin')}</option> <option value="-1">{ LocalizeText('navigator.roomsettings.floor_thickness.thin') }</option>
<option value="-2">{LocalizeText('navigator.roomsettings.floor_thickness.thinnest')}</option> <option value="-2">{ LocalizeText('navigator.roomsettings.floor_thickness.thinnest') }</option>
</select> </select>
</Column> </Column>
</Grid> </Grid>

View File

@ -17,7 +17,7 @@ export const NavigatorSearchResultItemView: FC<NavigatorSearchResultItemViewProp
const { roomData = null, children = null, thumbnail = false, ...rest } = props; const { roomData = null, children = null, thumbnail = false, ...rest } = props;
const { setDoorData = null } = useNavigatorContext(); const { setDoorData = null } = useNavigatorContext();
function getUserCounterColor(): string const getUserCounterColor = () =>
{ {
const num: number = (100 * (roomData.userCount / roomData.maxUserCount)); const num: number = (100 * (roomData.userCount / roomData.maxUserCount));