🆙 Init V3

This commit is contained in:
DuckieTM
2026-01-31 09:10:52 +01:00
commit 7feb10ab15
1733 changed files with 53405 additions and 0 deletions
@@ -0,0 +1,88 @@
import { RoomDataParser } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { IRoomData, LocalizeText } from '../../../../api';
import { Text } from '../../../../common';
interface NavigatorRoomSettingsTabViewProps
{
roomData: IRoomData;
handleChange: (field: string, value: string | number | boolean) => void;
}
export const NavigatorRoomSettingsAccessTabView: FC<NavigatorRoomSettingsTabViewProps> = props =>
{
const { roomData = null, handleChange = null } = props;
const [ password, setPassword ] = useState<string>('');
const [ confirmPassword, setConfirmPassword ] = useState('');
const [ isTryingPassword, setIsTryingPassword ] = useState(false);
const saveRoomPassword = () =>
{
if(!isTryingPassword || ((password.length <= 0) || (confirmPassword.length <= 0) || (password !== confirmPassword))) return;
handleChange('password', password);
};
useEffect(() =>
{
setPassword('');
setConfirmPassword('');
setIsTryingPassword(false);
}, [ roomData ]);
return (
<>
<div className="flex flex-col gap-1">
<Text small bold>{ LocalizeText('navigator.roomsettings.roomaccess.caption') }</Text>
<Text small>{ LocalizeText('navigator.roomsettings.roomaccess.info') }</Text>
</div>
<div className="overflow-auto">
<div className="flex flex-col gap-1">
<Text small bold>{ LocalizeText('navigator.roomsettings.doormode') }</Text>
<div className="flex items-center gap-1">
<input checked={ (roomData.lockState === RoomDataParser.OPEN_STATE) && !isTryingPassword } className="form-check-input" name="lockState" type="radio" onChange={ event => handleChange('lock_state', RoomDataParser.OPEN_STATE) } />
<Text small>{ LocalizeText('navigator.roomsettings.doormode.open') }</Text>
</div>
<div className="flex items-center gap-1">
<input checked={ (roomData.lockState === RoomDataParser.DOORBELL_STATE) && !isTryingPassword } className="form-check-input" name="lockState" type="radio" onChange={ event => handleChange('lock_state', RoomDataParser.DOORBELL_STATE) } />
<Text small>{ LocalizeText('navigator.roomsettings.doormode.doorbell') }</Text>
</div>
<div className="flex items-center gap-1">
<input checked={ (roomData.lockState === RoomDataParser.INVISIBLE_STATE) && !isTryingPassword } className="form-check-input" name="lockState" type="radio" onChange={ event => handleChange('lock_state', RoomDataParser.INVISIBLE_STATE) } />
<Text small>{ LocalizeText('navigator.roomsettings.doormode.invisible') }</Text>
</div>
<div className="flex w-full gap-1">
<input checked={ (roomData.lockState === RoomDataParser.PASSWORD_STATE) || isTryingPassword } className="form-check-input" name="lockState" type="radio" onChange={ event => setIsTryingPassword(event.target.checked) } />
{ !isTryingPassword && (roomData.lockState !== RoomDataParser.PASSWORD_STATE) &&
<Text small>{ LocalizeText('navigator.roomsettings.doormode.password') }</Text> }
{ (isTryingPassword || (roomData.lockState === RoomDataParser.PASSWORD_STATE)) &&
<div className="flex flex-col gap-1">
<Text small>{ LocalizeText('navigator.roomsettings.doormode.password') }</Text>
<input className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem] form-control-sm col-span-4" placeholder={ LocalizeText('navigator.roomsettings.password') } type="password" value={ password } onChange={ event => setPassword(event.target.value) } onFocus={ event => setIsTryingPassword(true) } />
{ isTryingPassword && (password.length <= 0) &&
<Text small bold variant="danger">
{ LocalizeText('navigator.roomsettings.passwordismandatory') }
</Text> }
<input className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem] form-control-sm col-span-4" placeholder={ LocalizeText('navigator.roomsettings.passwordconfirm') } type="password" value={ confirmPassword } onBlur={ saveRoomPassword } onChange={ event => setConfirmPassword(event.target.value) } />
{ isTryingPassword && ((password.length > 0) && (password !== confirmPassword)) &&
<Text small bold variant="danger">
{ LocalizeText('navigator.roomsettings.invalidconfirm') }
</Text> }
</div> }
</div>
</div>
<div className="flex flex-col gap-1">
<Text small bold>{ LocalizeText('navigator.roomsettings.pets') }</Text>
<div className="flex items-center gap-1">
<input checked={ roomData.allowPets } className="form-check-input" type="checkbox" onChange={ event => handleChange('allow_pets', event.target.checked) } />
<Text small>{ LocalizeText('navigator.roomsettings.allowpets') }</Text>
</div>
<div className="flex items-center gap-1">
<input checked={ roomData.allowPetsEat } className="form-check-input" type="checkbox" onChange={ event => handleChange('allow_pets_eat', event.target.checked) } />
<Text small>{ LocalizeText('navigator.roomsettings.allowfoodconsume') }</Text>
</div>
</div>
</div>
</>
);
};
@@ -0,0 +1,172 @@
import { CreateLinkEvent, RoomDeleteComposer, RoomSettingsSaveErrorEvent, RoomSettingsSaveErrorParser } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { FaTimes } from 'react-icons/fa';
import { GetMaxVisitorsList, IRoomData, LocalizeText, SendMessageComposer } from '../../../../api';
import { Column, Text } from '../../../../common';
import { useMessageEvent, useNavigator, useNotification } from '../../../../hooks';
import { NitroInput } from '../../../../layout';
const ROOM_NAME_MIN_LENGTH = 3;
const ROOM_NAME_MAX_LENGTH = 60;
const DESC_MAX_LENGTH = 255;
const TAGS_MAX_LENGTH = 15;
interface NavigatorRoomSettingsTabViewProps
{
roomData: IRoomData;
handleChange: (field: string, value: string | number | boolean | string[]) => void;
onClose: () => void;
}
export const NavigatorRoomSettingsBasicTabView: FC<NavigatorRoomSettingsTabViewProps> = props =>
{
const { roomData = null, handleChange = null, onClose = null } = props;
const [ roomName, setRoomName ] = useState<string>('');
const [ roomDescription, setRoomDescription ] = useState<string>('');
const [ roomTag1, setRoomTag1 ] = useState<string>('');
const [ roomTag2, setRoomTag2 ] = useState<string>('');
const [ tagIndex, setTagIndex ] = useState(0);
const [ typeError, setTypeError ] = useState<string>('');
const { showConfirm = null } = useNotification();
const { categories = null } = useNavigator();
useMessageEvent<RoomSettingsSaveErrorEvent>(RoomSettingsSaveErrorEvent, event =>
{
const parser = event.getParser();
if(!parser) return;
switch(parser.code)
{
case RoomSettingsSaveErrorParser.ERROR_INVALID_TAG:
setTypeError('navigator.roomsettings.unacceptablewords');
case RoomSettingsSaveErrorParser.ERROR_NON_USER_CHOOSABLE_TAG:
setTypeError('navigator.roomsettings.nonuserchoosabletag');
break;
default:
setTypeError('');
break;
}
});
const deleteRoom = () =>
{
showConfirm(LocalizeText('navigator.roomsettings.deleteroom.confirm.message', [ 'room_name' ], [ roomData.roomName ]), () =>
{
SendMessageComposer(new RoomDeleteComposer(roomData.roomId));
if(onClose) onClose();
CreateLinkEvent('navigator/search/myworld_view');
},
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);
};
const saveTags = (index: number) =>
{
if(index === 0 && (roomTag1 === roomData.tags[0]) || (roomTag1.length > TAGS_MAX_LENGTH)) return;
if(index === 1 && (roomTag2 === roomData.tags[1]) || (roomTag2.length > TAGS_MAX_LENGTH)) return;
if(roomTag1 === '' && roomTag2 !== '') setRoomTag2('');
setTypeError('');
setTagIndex(index);
handleChange('tags', (roomTag1 === '' && roomTag2 !== '') ? [ roomTag2 ] : [ roomTag1, roomTag2 ]);
};
useEffect(() =>
{
setRoomName(roomData.roomName);
setRoomDescription(roomData.roomDescription);
setRoomTag1((roomData.tags.length > 0 && roomData.tags[0]) ? roomData.tags[0] : '');
setRoomTag2((roomData.tags.length > 0 && roomData.tags[1]) ? roomData.tags[1] : '');
}, [ roomData ]);
return (
<>
<div className="flex items-center gap-1">
<Text small className="col-span-3">{ LocalizeText('navigator.roomname') }</Text>
<Column fullWidth gap={ 0 }>
<NitroInput className="form-control-sm" maxLength={ ROOM_NAME_MAX_LENGTH } value={ roomName } onBlur={ saveRoomName } onChange={ event => setRoomName(event.target.value) } />
{ (roomName.length < ROOM_NAME_MIN_LENGTH) &&
<Text bold small variant="danger">
{ LocalizeText('navigator.roomsettings.roomnameismandatory') }
</Text> }
</Column>
</div>
<div className="flex items-center gap-1">
<Text small className="col-span-3">{ LocalizeText('navigator.roomsettings.desc') }</Text>
<textarea className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem] form-control-sm" maxLength={ DESC_MAX_LENGTH } value={ roomDescription } onBlur={ saveRoomDescription } onChange={ event => setRoomDescription(event.target.value) } />
</div>
<div className="flex items-center gap-1">
<Text small className="col-span-3">{ LocalizeText('navigator.category') }</Text>
<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>) }
</select>
</div>
<div className="flex items-center gap-1">
<Text small className="col-span-3">{ LocalizeText('navigator.maxvisitors') }</Text>
<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>) }
</select>
</div>
<div className="flex items-center gap-0">
<Text small className="col-span-3">{ LocalizeText('navigator.tradesettings') }</Text>
<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="1">{ LocalizeText('navigator.roomsettings.trade_not_with_Controller') }</option>
<option value="2">{ LocalizeText('navigator.roomsettings.trade_allowed') }</option>
</select>
</div>
<div className="flex items-center gap-1">
<Text small className="col-span-3">{ LocalizeText('navigator.tags') }</Text>
<Column fullWidth gap={ 0 }>
<NitroInput className="form-control-sm" value={ roomTag1 } onBlur={ () => saveTags(0) } onChange={ event => setRoomTag1(event.target.value) } />
{ (roomTag1.length > TAGS_MAX_LENGTH) &&
<Text bold small variant="danger">
{ LocalizeText('navigator.roomsettings.toomanycharacters') }
</Text> }
{ (tagIndex === 0 && typeError != '') &&
<Text bold small variant="danger">
{ LocalizeText(typeError) }
</Text> }
</Column>
<Column fullWidth gap={ 0 }>
<NitroInput className="form-control-sm" value={ roomTag2 } onBlur={ () => saveTags(1) } onChange={ event => setRoomTag2(event.target.value) } />
{ (roomTag2.length > TAGS_MAX_LENGTH) &&
<Text bold small variant="danger">
{ LocalizeText('navigator.roomsettings.toomanycharacters') }
</Text> }
{ (tagIndex === 1 && typeError != '') &&
<Text bold small variant="danger">
{ LocalizeText(typeError) }
</Text> }
</Column>
</div>
<div className="flex items-center gap-1">
<div className="col-span-1" />
<input checked={ roomData.allowWalkthrough } className="form-check-input" type="checkbox" onChange={ event => handleChange('allow_walkthrough', event.target.checked) } />
<Text small>{ LocalizeText('navigator.roomsettings.allow_walk_through') }</Text>
</div>
<Text small bold pointer underline className="flex items-center justify-center gap-1" variant="danger" onClick={ deleteRoom }>
<FaTimes className="fa-icon" />
{ LocalizeText('navigator.roomsettings.delete') }
</Text>
</>
);
};
@@ -0,0 +1,118 @@
import { BannedUserData, BannedUsersFromRoomEvent, RoomBannedUsersComposer, RoomModerationSettings, RoomUnbanUserComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { IRoomData, LocalizeText, SendMessageComposer } from '../../../../api';
import { Button, Column, Flex, Grid, Text, UserProfileIconView } from '../../../../common';
import { useMessageEvent } from '../../../../hooks';
interface NavigatorRoomSettingsTabViewProps
{
roomData: IRoomData;
handleChange: (field: string, value: string | number | boolean) => void;
}
export const NavigatorRoomSettingsModTabView: FC<NavigatorRoomSettingsTabViewProps> = props =>
{
const { roomData = null, handleChange = null } = props;
const [ selectedUserId, setSelectedUserId ] = useState<number>(-1);
const [ bannedUsers, setBannedUsers ] = useState<BannedUserData[]>([]);
const unBanUser = (userId: number) =>
{
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));
setSelectedUserId(-1);
};
useMessageEvent<BannedUsersFromRoomEvent>(BannedUsersFromRoomEvent, event =>
{
const parser = event.getParser();
if(!roomData || (roomData.roomId !== parser.roomId)) return;
setBannedUsers(parser.bannedUsers);
});
useEffect(() =>
{
SendMessageComposer(new RoomBannedUsersComposer(roomData.roomId));
}, [ roomData.roomId ]);
return (
<Grid overflow="auto">
<Column size={ 6 }>
<Text small bold>{ LocalizeText('navigator.roomsettings.moderation.banned.users') } ({ bannedUsers.length })</Text>
<Flex className="bg-white rounded list-container p-2" overflow="hidden">
<Column fullWidth gap={ 1 } overflow="auto">
{ bannedUsers && (bannedUsers.length > 0) && bannedUsers.map((user, index) =>
{
return (
<Flex key={ index } shrink alignItems="center" gap={ 1 } overflow="hidden">
<UserProfileIconView userName={ user.userName } />
<Text small grow pointer onClick={ event => setSelectedUserId(user.userId) }> { user.userName }</Text>
</Flex>
);
}) }
</Column>
</Flex>
<Button disabled={ (selectedUserId <= 0) } onClick={ event => unBanUser(selectedUserId) }>
{ LocalizeText('navigator.roomsettings.moderation.unban') } { selectedUserId > 0 && bannedUsers.find(user => (user.userId === selectedUserId))?.userName }
</Button>
</Column>
<Column size={ 6 }>
<div className="flex flex-col gap-1">
<Text small bold>{ LocalizeText('navigator.roomsettings.moderation.mute.header') }</Text>
<div className="flex items-center gap-1">
<select className="form-select form-select-sm" value={ roomData.moderationSettings.allowMute } onChange={ event => handleChange('moderation_mute', event.target.value) }>
<option value={ RoomModerationSettings.MODERATION_LEVEL_NONE }>
{ LocalizeText('navigator.roomsettings.moderation.none') }
</option>
<option value={ RoomModerationSettings.MODERATION_LEVEL_USER_WITH_RIGHTS }>
{ LocalizeText('navigator.roomsettings.moderation.rights') }
</option>
</select>
</div>
</div>
<div className="flex flex-col gap-1">
<Text small bold>{ LocalizeText('navigator.roomsettings.moderation.kick.header') }</Text>
<div className="flex items-center gap-1">
<select className="form-select form-select-sm" value={ roomData.moderationSettings.allowKick } onChange={ event => handleChange('moderation_kick', event.target.value) }>
<option value={ RoomModerationSettings.MODERATION_LEVEL_NONE }>
{ LocalizeText('navigator.roomsettings.moderation.none') }
</option>
<option value={ RoomModerationSettings.MODERATION_LEVEL_USER_WITH_RIGHTS }>
{ LocalizeText('navigator.roomsettings.moderation.rights') }
</option>
<option value={ RoomModerationSettings.MODERATION_LEVEL_ALL }>
{ LocalizeText('navigator.roomsettings.moderation.all') }
</option>
</select>
</div>
</div>
<div className="flex flex-col gap-1">
<Text small bold>{ LocalizeText('navigator.roomsettings.moderation.ban.header') }</Text>
<div className="flex items-center gap-1">
<select className="form-select form-select-sm" value={ roomData.moderationSettings.allowBan } onChange={ event => handleChange('moderation_ban', event.target.value) }>
<option value={ RoomModerationSettings.MODERATION_LEVEL_NONE }>
{ LocalizeText('navigator.roomsettings.moderation.none') }
</option>
<option value={ RoomModerationSettings.MODERATION_LEVEL_USER_WITH_RIGHTS }>
{ LocalizeText('navigator.roomsettings.moderation.rights') }
</option>
</select>
</div>
</div>
</Column>
</Grid>
);
};
@@ -0,0 +1,91 @@
import { FlatControllerAddedEvent, FlatControllerRemovedEvent, FlatControllersEvent, RemoveAllRightsMessageComposer, RoomTakeRightsComposer, RoomUsersWithRightsComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { IRoomData, LocalizeText, SendMessageComposer } from '../../../../api';
import { Button, Column, Flex, Grid, Text, UserProfileIconView } from '../../../../common';
import { useMessageEvent } from '../../../../hooks';
interface NavigatorRoomSettingsTabViewProps
{
roomData: IRoomData;
handleChange: (field: string, value: string | number | boolean) => void;
}
export const NavigatorRoomSettingsRightsTabView: FC<NavigatorRoomSettingsTabViewProps> = props =>
{
const { roomData = null } = props;
const [ usersWithRights, setUsersWithRights ] = useState<Map<number, string>>(new Map());
useMessageEvent<FlatControllersEvent>(FlatControllersEvent, event =>
{
const parser = event.getParser();
if(!roomData || (roomData.roomId !== parser.roomId)) return;
setUsersWithRights(parser.users);
});
useMessageEvent<FlatControllerAddedEvent>(FlatControllerAddedEvent, event =>
{
const parser = event.getParser();
if(!roomData || (roomData.roomId !== parser.roomId)) return;
setUsersWithRights(prevValue =>
{
const newValue = new Map(prevValue);
newValue.set(parser.data.userId, parser.data.userName);
return newValue;
});
});
useMessageEvent<FlatControllerRemovedEvent>(FlatControllerRemovedEvent, event =>
{
const parser = event.getParser();
if(!roomData || (roomData.roomId !== parser.roomId)) return;
setUsersWithRights(prevValue =>
{
const newValue = new Map(prevValue);
newValue.delete(parser.userId);
return newValue;
});
});
useEffect(() =>
{
SendMessageComposer(new RoomUsersWithRightsComposer(roomData.roomId));
}, [ roomData.roomId ]);
return (
<Grid>
<Column size={ 6 }>
<Text small bold>
{ LocalizeText('navigator.flatctrls.userswithrights', [ 'displayed', 'total' ], [ usersWithRights.size.toString(), usersWithRights.size.toString() ]) }
</Text>
<Flex className="bg-white rounded list-container p-2" overflow="hidden">
<Column fullWidth gap={ 1 } overflow="auto">
{ Array.from(usersWithRights.entries()).map(([ id, name ], index) =>
{
return (
<Flex key={ index } shrink alignItems="center" gap={ 1 } overflow="hidden">
<UserProfileIconView userName={ name } />
<Text small grow pointer onClick={ event => SendMessageComposer(new RoomTakeRightsComposer(id)) }> { name }</Text>
</Flex>
);
}) }
</Column>
</Flex>
</Column>
<Column justifyContent="end" size={ 6 }>
<Button disabled={ !usersWithRights.size } variant="danger" onClick={ event => SendMessageComposer(new RemoveAllRightsMessageComposer(roomData.roomId)) } >
{ LocalizeText('navigator.flatctrls.clear') }
</Button>
</Column>
</Grid>
);
};
@@ -0,0 +1,206 @@
import { RoomBannedUsersComposer, RoomDataParser, RoomSettingsDataEvent, SaveRoomSettingsComposer } from '@nitrots/nitro-renderer';
import { FC, useState } from 'react';
import { IRoomData, LocalizeText, SendMessageComposer } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../common';
import { useMessageEvent } from '../../../../hooks';
import { NavigatorRoomSettingsAccessTabView } from './NavigatorRoomSettingsAccessTabView';
import { NavigatorRoomSettingsBasicTabView } from './NavigatorRoomSettingsBasicTabView';
import { NavigatorRoomSettingsModTabView } from './NavigatorRoomSettingsModTabView';
import { NavigatorRoomSettingsRightsTabView } from './NavigatorRoomSettingsRightsTabView';
import { NavigatorRoomSettingsVipChatTabView } from './NavigatorRoomSettingsVipChatTabView';
const TABS: string[] = [
'navigator.roomsettings.tab.1',
'navigator.roomsettings.tab.2',
'navigator.roomsettings.tab.3',
'navigator.roomsettings.tab.4',
'navigator.roomsettings.tab.5'
];
export const NavigatorRoomSettingsView: FC<{}> = props =>
{
const [ roomData, setRoomData ] = useState<IRoomData>(null);
const [ currentTab, setCurrentTab ] = useState(TABS[0]);
useMessageEvent<RoomSettingsDataEvent>(RoomSettingsDataEvent, event =>
{
const parser = event.getParser();
if(!parser) return;
const data = parser.data;
setRoomData({
roomId: data.roomId,
roomName: data.name,
roomDescription: data.description,
categoryId: data.categoryId,
userCount: data.maximumVisitorsLimit,
tags: data.tags,
tradeState: data.tradeMode,
allowWalkthrough: data.allowWalkThrough,
lockState: data.doorMode,
password: null,
allowPets: data.allowPets,
allowPetsEat: data.allowFoodConsume,
hideWalls: data.hideWalls,
wallThickness: data.wallThickness,
floorThickness: data.floorThickness,
chatSettings: {
mode: data.chatSettings.mode,
weight: data.chatSettings.weight,
speed: data.chatSettings.speed,
distance: data.chatSettings.distance,
protection: data.chatSettings.protection
},
moderationSettings: {
allowMute: data.roomModerationSettings.allowMute,
allowKick: data.roomModerationSettings.allowKick,
allowBan: data.roomModerationSettings.allowBan
}
});
SendMessageComposer(new RoomBannedUsersComposer(data.roomId));
});
const onClose = () =>
{
setRoomData(null);
setCurrentTab(TABS[0]);
};
const handleChange = (field: string, value: string | number | boolean | string[]) =>
{
setRoomData(prevValue =>
{
const newValue = { ...prevValue };
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 'tags':
newValue.tags = value as Array<string>;
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;
}
SendMessageComposer(
new SaveRoomSettingsComposer(
newValue.roomId,
newValue.roomName,
newValue.roomDescription,
newValue.lockState,
newValue.password,
newValue.userCount,
newValue.categoryId,
newValue.tags.length,
newValue.tags,
newValue.tradeState,
newValue.allowPets,
newValue.allowPetsEat,
newValue.allowWalkthrough,
newValue.hideWalls,
newValue.wallThickness,
newValue.floorThickness,
newValue.moderationSettings.allowMute,
newValue.moderationSettings.allowKick,
newValue.moderationSettings.allowBan,
newValue.chatSettings.mode,
newValue.chatSettings.weight,
newValue.chatSettings.speed,
newValue.chatSettings.distance,
newValue.chatSettings.protection
));
return newValue;
});
};
if(!roomData) return null;
return (
<NitroCardView className="nitro-room-settings" uniqueKey="nitro-room-settings">
<NitroCardHeaderView headerText={ LocalizeText('navigator.roomsettings') } onCloseClick={ onClose } />
<NitroCardTabsView>
{ TABS.map(tab =>
{
return <NitroCardTabsItemView key={ tab } isActive={ (currentTab === tab) } onClick={ event => setCurrentTab(tab) }>{ LocalizeText(tab) }</NitroCardTabsItemView>;
}) }
</NitroCardTabsView>
<NitroCardContentView>
{ (currentTab === TABS[0]) &&
<NavigatorRoomSettingsBasicTabView handleChange={ handleChange } roomData={ roomData } onClose={ onClose } /> }
{ (currentTab === TABS[1]) &&
<NavigatorRoomSettingsAccessTabView handleChange={ handleChange } roomData={ roomData } /> }
{ (currentTab === TABS[2]) &&
<NavigatorRoomSettingsRightsTabView handleChange={ handleChange } roomData={ roomData } /> }
{ (currentTab === TABS[3]) &&
<NavigatorRoomSettingsVipChatTabView handleChange={ handleChange } roomData={ roomData } /> }
{ (currentTab === TABS[4]) &&
<NavigatorRoomSettingsModTabView handleChange={ handleChange } roomData={ roomData } /> }
</NitroCardContentView>
</NitroCardView>
);
};
@@ -0,0 +1,77 @@
import { RoomChatSettings } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { IRoomData, LocalizeText } from '../../../../api';
import { Column, Grid, Text } from '../../../../common';
import { NitroInput } from '../../../../layout';
interface NavigatorRoomSettingsTabViewProps
{
roomData: IRoomData;
handleChange: (field: string, value: string | number | boolean) => void;
}
export const NavigatorRoomSettingsVipChatTabView: FC<NavigatorRoomSettingsTabViewProps> = props =>
{
const { roomData = null, handleChange = null } = props;
const [ chatDistance, setChatDistance ] = useState<number>(0);
useEffect(() =>
{
setChatDistance(roomData.chatSettings.distance);
}, [ roomData.chatSettings ]);
return (
<>
<div className="flex flex-col gap-1">
<Text small bold>{ LocalizeText('navigator.roomsettings.vip.caption') }</Text>
<Text small>{ LocalizeText('navigator.roomsettings.vip.info') }</Text>
</div>
<Grid overflow="auto">
<Column gap={ 1 } size={ 6 }>
<Text small bold>{ LocalizeText('navigator.roomsettings.chat_settings') }</Text>
<Text small>{ LocalizeText('navigator.roomsettings.chat_settings.info') }</Text>
<select className="form-select form-select-sm" value={ roomData.chatSettings.mode } onChange={ event => handleChange('bubble_mode', event.target.value) }>
<option value={ RoomChatSettings.CHAT_MODE_FREE_FLOW }>{ LocalizeText('navigator.roomsettings.chat.mode.free.flow') }</option>
<option value={ RoomChatSettings.CHAT_MODE_LINE_BY_LINE }>{ LocalizeText('navigator.roomsettings.chat.mode.line.by.line') }</option>
</select>
<select className="form-select form-select-sm" value={ roomData.chatSettings.weight } onChange={ event => handleChange('chat_weight', event.target.value) }>
<option value={ RoomChatSettings.CHAT_BUBBLE_WIDTH_NORMAL }>{ LocalizeText('navigator.roomsettings.chat.bubbles.width.normal') }</option>
<option value={ RoomChatSettings.CHAT_BUBBLE_WIDTH_THIN }>{ LocalizeText('navigator.roomsettings.chat.bubbles.width.thin') }</option>
<option value={ RoomChatSettings.CHAT_BUBBLE_WIDTH_WIDE }>{ LocalizeText('navigator.roomsettings.chat.bubbles.width.wide') }</option>
</select>
<select className="form-select form-select-sm" value={ roomData.chatSettings.speed } onChange={ event => handleChange('bubble_speed', event.target.value) }>
<option value={ RoomChatSettings.CHAT_SCROLL_SPEED_FAST }>{ LocalizeText('navigator.roomsettings.chat.speed.fast') }</option>
<option value={ RoomChatSettings.CHAT_SCROLL_SPEED_NORMAL }>{ LocalizeText('navigator.roomsettings.chat.speed.normal') }</option>
<option value={ RoomChatSettings.CHAT_SCROLL_SPEED_SLOW }>{ LocalizeText('navigator.roomsettings.chat.speed.slow') }</option>
</select>
<select className="form-select form-select-sm" value={ roomData.chatSettings.protection } onChange={ event => handleChange('flood_protection', event.target.value) }>
<option value={ RoomChatSettings.FLOOD_FILTER_LOOSE }>{ LocalizeText('navigator.roomsettings.chat.flood.loose') }</option>
<option value={ RoomChatSettings.FLOOD_FILTER_NORMAL }>{ LocalizeText('navigator.roomsettings.chat.flood.normal') }</option>
<option value={ RoomChatSettings.FLOOD_FILTER_STRICT }>{ LocalizeText('navigator.roomsettings.chat.flood.strict') }</option>
</select>
<Text small>{ LocalizeText('navigator.roomsettings.chat_settings.hearing.distance') }</Text>
<NitroInput className="form-control-sm" min="0" type="number" value={ chatDistance } onBlur={ event => handleChange('chat_distance', chatDistance) } onChange={ event => setChatDistance(event.target.valueAsNumber) } />
</Column>
<Column gap={ 1 } size={ 6 }>
<Text small bold>{ LocalizeText('navigator.roomsettings.vip_settings') }</Text>
<div className="flex items-center gap-1">
<input checked={ roomData.hideWalls } className="form-check-input" type="checkbox" onChange={ event => handleChange('hide_walls', event.target.checked) } />
<Text small>{ LocalizeText('navigator.roomsettings.hide_walls') }</Text>
</div>
<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="1">{ LocalizeText('navigator.roomsettings.wall_thickness.thick') }</option>
<option value="-1">{ LocalizeText('navigator.roomsettings.wall_thickness.thin') }</option>
<option value="-2">{ LocalizeText('navigator.roomsettings.wall_thickness.thinnest') }</option>
</select>
<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="1">{ LocalizeText('navigator.roomsettings.floor_thickness.thick') }</option>
<option value="-1">{ LocalizeText('navigator.roomsettings.floor_thickness.thin') }</option>
<option value="-2">{ LocalizeText('navigator.roomsettings.floor_thickness.thinnest') }</option>
</select>
</Column>
</Grid>
</>
);
};