From 9d664896d5683e1751febb0235877da9b8ffcea0 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sat, 15 Jan 2022 01:04:50 -0300 Subject: [PATCH 1/7] Name change is DONE! --- src/events/help/HelpNameChangeEvent.ts | 6 ++ src/views/help/HelpView.scss | 4 + src/views/help/HelpView.tsx | 2 + .../NameChangeConfirmationView.tsx | 47 ++++++++ .../views/name-change/NameChangeInitView.tsx | 19 ++++ .../views/name-change/NameChangeInputView.tsx | 102 ++++++++++++++++++ .../help/views/name-change/NameChangeView.tsx | 68 ++++++++++++ .../views/name-change/NameChangeView.types.ts | 5 + .../AvatarInfoWidgetOwnAvatarView.tsx | 4 + 9 files changed, 257 insertions(+) create mode 100644 src/events/help/HelpNameChangeEvent.ts create mode 100644 src/views/help/views/name-change/NameChangeConfirmationView.tsx create mode 100644 src/views/help/views/name-change/NameChangeInitView.tsx create mode 100644 src/views/help/views/name-change/NameChangeInputView.tsx create mode 100644 src/views/help/views/name-change/NameChangeView.tsx create mode 100644 src/views/help/views/name-change/NameChangeView.types.ts diff --git a/src/events/help/HelpNameChangeEvent.ts b/src/events/help/HelpNameChangeEvent.ts new file mode 100644 index 00000000..076f5b51 --- /dev/null +++ b/src/events/help/HelpNameChangeEvent.ts @@ -0,0 +1,6 @@ +import { NitroEvent } from '@nitrots/nitro-renderer/src/core/events/NitroEvent'; + +export class HelpNameChangeEvent extends NitroEvent +{ + public static INIT: string = 'HC_NAME_CHANGE_INIT'; +} diff --git a/src/views/help/HelpView.scss b/src/views/help/HelpView.scss index b6ba7d76..3dd5ff68 100644 --- a/src/views/help/HelpView.scss +++ b/src/views/help/HelpView.scss @@ -12,3 +12,7 @@ .nitro-cfh-sanction-status { width: 400px; } + +.nitro-change-username { + width: 300px; +} diff --git a/src/views/help/HelpView.tsx b/src/views/help/HelpView.tsx index 9ebea6eb..3f1a7fab 100644 --- a/src/views/help/HelpView.tsx +++ b/src/views/help/HelpView.tsx @@ -9,6 +9,7 @@ import { IHelpReportState, initialReportState } from './context/HelpContext.type import { HelpMessageHandler } from './HelpMessageHandler'; import { DescribeReportView } from './views/DescribeReportView'; import { HelpIndexView } from './views/HelpIndexView'; +import { NameChangeView } from './views/name-change/NameChangeView'; import { SanctionSatusView } from './views/SanctionStatusView'; import { SelectReportedChatsView } from './views/SelectReportedChatsView'; import { SelectReportedUserView } from './views/SelectReportedUserView'; @@ -76,6 +77,7 @@ export const HelpView: FC<{}> = props => } + ); } diff --git a/src/views/help/views/name-change/NameChangeConfirmationView.tsx b/src/views/help/views/name-change/NameChangeConfirmationView.tsx new file mode 100644 index 00000000..6a91d4c2 --- /dev/null +++ b/src/views/help/views/name-change/NameChangeConfirmationView.tsx @@ -0,0 +1,47 @@ +import { ChangeUserNameMessageComposer, UserNameChangeMessageEvent } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useState } from 'react'; +import { GetSessionDataManager, LocalizeText } from '../../../../api'; +import { CreateMessageHook, SendMessageHook } from '../../../../hooks'; +import { NameChangeLayoutViewProps } from './NameChangeView.types'; + +export const NameChangeConfirmationView:FC = props => +{ + const { username = '', onAction = null } = props; + + const [ isConfirming, setIsConfirming ] = useState(false); + + const onUserNameChangeMessageEvent = useCallback((event: UserNameChangeMessageEvent) => + { + const parser = event.getParser(); + + if(!parser) return; + + if(parser.webId !== GetSessionDataManager().userId) return; + + onAction('close'); + }, [ onAction ]); + + CreateMessageHook(UserNameChangeMessageEvent, onUserNameChangeMessageEvent); + + const confirm = useCallback(() => + { + if(isConfirming) return; + + setIsConfirming(true); + SendMessageHook(new ChangeUserNameMessageComposer(username)); + }, [ isConfirming, username ]); + + return ( +
+
{ LocalizeText('tutorial.name_change.info.confirm') }
+
+
{ LocalizeText('tutorial.name_change.confirm') }
+
{ username }
+
+
+ + +
+
+ ); +} diff --git a/src/views/help/views/name-change/NameChangeInitView.tsx b/src/views/help/views/name-change/NameChangeInitView.tsx new file mode 100644 index 00000000..d995dc3c --- /dev/null +++ b/src/views/help/views/name-change/NameChangeInitView.tsx @@ -0,0 +1,19 @@ +import { FC } from 'react'; +import { GetSessionDataManager, LocalizeText } from '../../../../api'; +import { NameChangeLayoutViewProps } from './NameChangeView.types'; + +export const NameChangeInitView:FC = props => +{ + const { onAction = null } = props; + + return ( +
+
{ LocalizeText('tutorial.name_change.info.main') }
+
{ LocalizeText('tutorial.name_change.current', ['name'], [GetSessionDataManager().userName]) }
+
+ + +
+
+ ); +} diff --git a/src/views/help/views/name-change/NameChangeInputView.tsx b/src/views/help/views/name-change/NameChangeInputView.tsx new file mode 100644 index 00000000..3e1b3d12 --- /dev/null +++ b/src/views/help/views/name-change/NameChangeInputView.tsx @@ -0,0 +1,102 @@ +import { CheckUserNameMessageComposer, CheckUserNameResultMessageEvent } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useState } from 'react'; +import { LocalizeText } from '../../../../api'; +import { CreateMessageHook, SendMessageHook } from '../../../../hooks'; +import { NameChangeLayoutViewProps } from './NameChangeView.types'; + +const AVAILABLE: number = 0; +const TOO_SHORT: number = 2; +const TOO_LONG: number = 3; +const NOT_VALID: number = 4; +const TAKEN_WITH_SUGGESTIONS: number = 5; +const DISABLED: number = 6; + +export const NameChangeInputView:FC = props => +{ + const { onAction = null } = props; + + const [ newUsername, setNewUsername ] = useState(''); + const [ canProceed, setCanProceed ] = useState(false); + const [ isChecking, setIsChecking ] = useState(false); + const [ errorCode, setErrorCode ] = useState(null); + const [ suggestions, setSuggestions ] = useState([]); + + const onCheckUserNameResultMessageEvent = useCallback((event: CheckUserNameResultMessageEvent) => + { + setIsChecking(false); + + const parser = event.getParser(); + + if(!parser) return; + + switch(parser.resultCode) + { + case AVAILABLE: + setCanProceed(true); + break; + case TOO_SHORT: + setErrorCode('short'); + break; + case TOO_LONG: + setErrorCode('long'); + break; + case NOT_VALID: + setErrorCode('invalid'); + break; + case TAKEN_WITH_SUGGESTIONS: + setSuggestions(parser.nameSuggestions); + setErrorCode('taken'); + break; + case DISABLED: + setErrorCode('change_not_allowed'); + } + }, []); + + CreateMessageHook(CheckUserNameResultMessageEvent, onCheckUserNameResultMessageEvent); + + const check = useCallback(() => + { + if(newUsername === '') return; + + setCanProceed(false); + setSuggestions([]); + setErrorCode(null); + + setIsChecking(true); + SendMessageHook(new CheckUserNameMessageComposer(newUsername)); + }, [ newUsername ]); + + const handleUsernameChange = useCallback((username: string) => + { + setCanProceed(false); + setSuggestions([]); + setErrorCode(null); + + setNewUsername(username); + }, []); + + return ( +
+
{ LocalizeText('tutorial.name_change.info.select') }
+
+ handleUsernameChange(e.target.value) } /> + +
+ { !errorCode && !canProceed &&
{ LocalizeText('help.tutorial.name.info') }
} + { errorCode &&
{ LocalizeText(`help.tutorial.name.${errorCode}`, ['name'], [newUsername]) }
} + { canProceed &&
{ LocalizeText('help.tutorial.name.available', ['name'], [newUsername]) }
} + { suggestions &&
+ { + suggestions.map((suggestion, i) => + { + return (
handleUsernameChange(suggestion) }>{ suggestion }
); + }) + } +
} +
+ + +
+
+ ); +} diff --git a/src/views/help/views/name-change/NameChangeView.tsx b/src/views/help/views/name-change/NameChangeView.tsx new file mode 100644 index 00000000..e40613fe --- /dev/null +++ b/src/views/help/views/name-change/NameChangeView.tsx @@ -0,0 +1,68 @@ +import { FC, useCallback, useMemo, useState } from 'react'; +import { LocalizeText } from '../../../../api'; +import { HelpNameChangeEvent } from '../../../../events/help/HelpNameChangeEvent'; +import { useUiEvent } from '../../../../hooks'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; +import { NameChangeConfirmationView } from './NameChangeConfirmationView'; +import { NameChangeInitView } from './NameChangeInitView'; +import { NameChangeInputView } from './NameChangeInputView'; + +const INIT: string = 'INIT'; +const INPUT: string = 'INPUT'; +const CONFIRMATION: string = 'CONFIRMATION'; + +export const NameChangeView:FC<{}> = props => +{ + const [ isVisible, setIsVisible ] = useState(false); + const [ layout, setLayout ] = useState(INIT); + const [ newUsername, setNewUsername ] = useState(''); + + const onHelpNameChangeEvent = useCallback((event: HelpNameChangeEvent) => + { + setLayout(INIT); + setIsVisible(true); + }, []); + + useUiEvent(HelpNameChangeEvent.INIT, onHelpNameChangeEvent); + + const onAction = useCallback((action: string, value?: string) => + { + switch(action) + { + case 'start': + setLayout(INPUT); + break; + case 'confirmation': + setNewUsername(value); + setLayout(CONFIRMATION); + break; + case 'close': + setNewUsername(''); + setIsVisible(false); + break; + } + }, []); + + const titleKey = useMemo(() => + { + switch(layout) + { + case INIT: return 'tutorial.name_change.title.main'; + case INPUT: return 'tutorial.name_change.title.select'; + case CONFIRMATION: return 'tutorial.name_change.title.confirm'; + } + }, [layout]); + + if(!isVisible) return null; + + return ( + + onAction('close') } /> + + { layout === INIT && } + { layout === INPUT && } + { layout === CONFIRMATION && } + + + ) +} diff --git a/src/views/help/views/name-change/NameChangeView.types.ts b/src/views/help/views/name-change/NameChangeView.types.ts new file mode 100644 index 00000000..13222e1f --- /dev/null +++ b/src/views/help/views/name-change/NameChangeView.types.ts @@ -0,0 +1,5 @@ +export interface NameChangeLayoutViewProps +{ + username?: string; + onAction: (action: string, value?: string) => void; +} diff --git a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx index 8d1d9c46..c83c58b5 100644 --- a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx +++ b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx @@ -2,6 +2,7 @@ import { AvatarAction, AvatarExpressionEnum, RoomControllerLevel, RoomObjectCate import { FC, useCallback, useMemo, useState } from 'react'; import { GetCanStandUp, GetCanUseExpression, GetOwnPosture, GetUserProfile, HasHabboClub, HasHabboVip, IsRidingHorse, LocalizeText, RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetUpdateDecorateModeEvent, RoomWidgetUserActionMessage } from '../../../../../../api'; import { AvatarEditorEvent } from '../../../../../../events'; +import { HelpNameChangeEvent } from '../../../../../../events/help/HelpNameChangeEvent'; import { dispatchUiEvent } from '../../../../../../hooks'; import { CurrencyIcon } from '../../../../../shared/currency-icon/CurrencyIcon'; import { useRoomContext } from '../../../../context/RoomContext'; @@ -42,6 +43,9 @@ export const AvatarInfoWidgetOwnAvatarView: FC Date: Sun, 13 Feb 2022 12:52:28 -0300 Subject: [PATCH 2/7] Update user setting styling --- src/views/user-settings/UserSettingsView.tsx | 72 +++++++++++--------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/src/views/user-settings/UserSettingsView.tsx b/src/views/user-settings/UserSettingsView.tsx index 9a915b33..d8870e07 100644 --- a/src/views/user-settings/UserSettingsView.tsx +++ b/src/views/user-settings/UserSettingsView.tsx @@ -114,44 +114,48 @@ export const UserSettingsView: FC<{}> = props => if(!isVisible) return null; return ( - + processAction('close_view')} /> - -
- processAction('oldchat', event.target.checked) } /> - -
-
- processAction('room_invites', event.target.checked) } /> - -
-
- processAction('camera_follow', event.target.checked) } /> - -
-
{ LocalizeText('widget.memenu.settings.volume') }
-
- -
- 0) ? ' fa-volume-down' : '') + ((userSettings.volumeSystem >= 50) ? ' text-muted' : '') } /> - processAction('system_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') }/> - + +
+
+ processAction('oldchat', event.target.checked) } /> + +
+
+ processAction('room_invites', event.target.checked) } /> + +
+
+ processAction('camera_follow', event.target.checked) } /> +
-
- -
- 0) ? ' fa-volume-down' : '') + ((userSettings.volumeFurni >= 50) ? ' text-muted' : '') } /> - processAction('furni_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') }/> - +
+
{ LocalizeText('widget.memenu.settings.volume') }
+
+ +
+ 0) ? ' fa-volume-down' : '') + ((userSettings.volumeSystem >= 50) ? ' text-muted' : '') } /> + processAction('system_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') }/> + +
-
-
- -
- 0) ? ' fa-volume-down' : '') + ((userSettings.volumeTrax >= 50) ? ' text-muted' : '') } /> - processAction('trax_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') }/> - +
+ +
+ 0) ? ' fa-volume-down' : '') + ((userSettings.volumeFurni >= 50) ? ' text-muted' : '') } /> + processAction('furni_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') }/> + +
+
+
+ +
+ 0) ? ' fa-volume-down' : '') + ((userSettings.volumeTrax >= 50) ? ' text-muted' : '') } /> + processAction('trax_volume', event.target.value) } onMouseUp={ () => saveRangeSlider('volume') }/> + +
From f41aafaae94bc89a2201809857d9bcbaa732a6df Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sun, 13 Feb 2022 13:10:15 -0300 Subject: [PATCH 3/7] Update navcigator/create-room layout --- .../creator/NavigatorRoomCreatorView.scss | 5 +- .../creator/NavigatorRoomCreatorView.tsx | 80 +++++++++---------- 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/views/navigator/views/creator/NavigatorRoomCreatorView.scss b/src/views/navigator/views/creator/NavigatorRoomCreatorView.scss index ea0addeb..611a27c2 100644 --- a/src/views/navigator/views/creator/NavigatorRoomCreatorView.scss +++ b/src/views/navigator/views/creator/NavigatorRoomCreatorView.scss @@ -1,7 +1,8 @@ .room-model-list { display: flex; - overflow-x: auto; - scroll-snap-type: x mandatory; + flex-direction: column; + overflow-y: auto; + scroll-snap-type: y mandatory; scroll-behavior: smooth; -webkit-overflow-scrolling: touch; diff --git a/src/views/navigator/views/creator/NavigatorRoomCreatorView.tsx b/src/views/navigator/views/creator/NavigatorRoomCreatorView.tsx index bfc1bb51..a8e877f4 100644 --- a/src/views/navigator/views/creator/NavigatorRoomCreatorView.tsx +++ b/src/views/navigator/views/creator/NavigatorRoomCreatorView.tsx @@ -66,64 +66,56 @@ export const NavigatorRoomCreatorView: FC = props }, [ name, description, category, visitorsCount, tradesSetting, selectedModelName ]); return ( -
-
-
-
- - setName(e.target.value) } /> -
+
+
+
+ + setName(e.target.value) } />
-
-
- - -
+
+ +
-
-
- - -
+
+ +
-
-
- - -
+
+ +
+
+ + setDescription(e.target.value) } /> +
+
-
- - setDescription(e.target.value) } /> -
-
+
{ NAVIGATOR_ROOM_MODELS.map(model => { - return (
selectModel(model.name) } className={ 'h-100 cursor-pointer d-flex flex-column justify-content-center align-items-center p-1 me-2 rounded border border-2' + classNames({ ' active': selectedModelName === model.name, ' disabled': GetSessionDataManager().clubLevel < model.clubLevel }) }> + return (
selectModel(model.name) } className={ 'cursor-pointer position-relative d-flex flex-column justify-content-center align-items-center p-1 rounded border border-2' + classNames({ ' active': selectedModelName === model.name, ' disabled': GetSessionDataManager().clubLevel < model.clubLevel }) }> + { model.clubLevel > HabboClubLevelEnum.NO_CLUB &&
}
{ model.tileSize } { LocalizeText('navigator.createroom.tilesize') }
- { model.clubLevel > HabboClubLevelEnum.NO_CLUB && }
); }) }
-
); } From 9666a4103ab6b7e7db017d08fe6fa1d092f28e5e Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sun, 13 Feb 2022 16:50:14 -0300 Subject: [PATCH 4/7] Add room-info to room-tools --- .../room-tools/RoomToolsWidgetView.scss | 85 +++++++++------- .../room-tools/RoomToolsWidgetView.tsx | 98 +++++++++++++++---- 2 files changed, 127 insertions(+), 56 deletions(-) diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss b/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss index 044a286b..d8ea1e57 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss @@ -2,50 +2,61 @@ position: absolute; bottom: 125px; left: -145px; - background: rgba($dark,.95); - box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4); - border-top-right-radius: $border-radius; - border-bottom-right-radius: $border-radius; transition: all .2s ease; - + &.open { left: 0px; } - - .list-group-item { - background: transparent; - padding: 3px 0px; - color: $white; - border-color: rgba($black, 0.3); - cursor: pointer; - - &:hover { - text-decoration: underline; + + .nitro-room-tools-content { + background: rgba($dark,.95); + box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4); + border-top-right-radius: $border-radius; + border-bottom-right-radius: $border-radius; + + .list-group-item { + background: transparent; + padding: 3px 0px; + color: $white; + border-color: rgba($black, 0.3); + cursor: pointer; + + &:hover { + text-decoration: underline; + } + + &:first-child { + padding-top: 8px; + } + + &:last-child { + border-bottom: none; + padding-bottom: 8px; + } + + &.disabled { + opacity: .5; + } } - - &:first-child { - padding-top: 8px; - } - - &:last-child { - border-bottom: none; - padding-bottom: 8px; - } - - &.disabled { - opacity: .5; + + .tools-item { + .icon { + width: 22px; + background-repeat: no-repeat; + background-position: center; + } + + &:hover { + text-decoration: underline; + } } } - .tools-item { - .icon { - width: 22px; - background-repeat: no-repeat; - background-position: center; - } - - &:hover { - text-decoration: underline; - } + .nitro-room-tools-info { + background: rgba($dark,.95); + box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4); + transition: all .2s ease; + pointer-events: none; + max-width: 250px; } } diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx index d9e9b6e8..b4674424 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -1,11 +1,11 @@ -import { RoomLikeRoomComposer } from '@nitrots/nitro-renderer'; +import { GetGuestRoomResultEvent, RoomLikeRoomComposer } from '@nitrots/nitro-renderer'; import classNames from 'classnames'; import { FC, useCallback, useState } from 'react'; import { LocalizeText, RoomWidgetZoomToggleMessage } from '../../../../api'; import { NavigatorEvent } from '../../../../events'; import { ChatHistoryEvent } from '../../../../events/chat-history/ChatHistoryEvent'; import { dispatchUiEvent } from '../../../../hooks/events'; -import { SendMessageHook } from '../../../../hooks/messages'; +import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages'; import { useRoomContext } from '../../context/RoomContext'; export const RoomToolsWidgetView: FC<{}> = props => @@ -16,6 +16,12 @@ export const RoomToolsWidgetView: FC<{}> = props => const [ isZoomedIn, setIsZoomedIn ] = useState(false); const [ isLiked, setIsLiked ] = useState(false); + const [ roomName, setRoomName ] = useState(null); + const [ roomOwner, setRoomOwner ] = useState(null); + const [ roomTags, setRoomTags ] = useState(null); + const [ roomInfoOpacity, setRoomInfoOpacity ] = useState(false); + const [ roomInfoDisplay, setRoomInfoDisplay ] = useState(false); + const handleToolClick = useCallback((action: string) => { switch(action) @@ -42,28 +48,82 @@ export const RoomToolsWidgetView: FC<{}> = props => return; } }, [ isZoomedIn, isLiked, widgetHandler ]); + + const onGetGuestRoomResultEvent = useCallback((event: GetGuestRoomResultEvent) => + { + const parser = event.getParser(); + + let updated = false; + + if(roomName !== parser.data.roomName) + { + updated = true; + setRoomName(parser.data.roomName); + } + + if(roomOwner !== parser.data.ownerName) + { + updated = true; + setRoomOwner(parser.data.ownerName); + } + + if(roomTags !== parser.data.tags) + { + updated = true; + setRoomTags(parser.data.tags); + } + + if(updated) + { + setRoomInfoOpacity(true); + setRoomInfoDisplay(true); + + setTimeout(() => + { + setRoomInfoOpacity(false); + + setTimeout(() => setRoomInfoDisplay(false), 1000); + }, 3000); + } + }, [ roomName, roomOwner, roomTags ]); + + CreateMessageHook(GetGuestRoomResultEvent, onGetGuestRoomResultEvent); return ( -
-
-
handleToolClick('settings') }> - { LocalizeText('room.settings.button.text') } +
+
+
+
handleToolClick('settings') }> + { LocalizeText('room.settings.button.text') } +
+
handleToolClick('zoom') }> + { LocalizeText('room.zoom.button.text') } +
+
handleToolClick('chat_history') }> + { LocalizeText('room.chathistory.button.text') } +
+
handleToolClick('like_room') }> + { LocalizeText('room.like.button.text') } +
+
handleToolClick('toggle_room_link') }> + { LocalizeText('navigator.embed.caption') } +
-
handleToolClick('zoom') }> - { LocalizeText('room.zoom.button.text') } -
-
handleToolClick('chat_history') }> - { LocalizeText('room.chathistory.button.text') } -
-
handleToolClick('like_room') }> - { LocalizeText('room.like.button.text') } -
-
handleToolClick('toggle_room_link') }> - { LocalizeText('navigator.embed.caption') } +
setIsExpanded(value => !value)}> +
-
setIsExpanded(value => !value)}> - +
+
+
{ roomName }
+
{ roomOwner }
+
+ { roomTags && roomTags.length > 0 &&
+ { roomTags.map(tag => + { + return
#{ tag }
+ }) } +
}
); From 77819a7e2bcd6a8da057548f4b546384fae2b923 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sun, 13 Feb 2022 19:38:20 -0300 Subject: [PATCH 5/7] Room invite + friend deletion --- src/views/friends/FriendsView.scss | 8 ++ .../FriendsGroupItemView.tsx | 33 +++-- .../FriendsGroupItemView.types.ts | 1 + .../views/friends-group/FriendsGroupView.tsx | 6 +- .../friends-group/FriendsGroupView.types.ts | 2 + .../views/friends-list/FriendsListView.tsx | 134 ++++++++++++++---- .../FriendsRemoveConfirmationView.tsx | 22 +++ .../FriendsRemoveConfirmationView.types.ts | 7 + .../FriendsRoomInviteView.tsx | 26 ++++ .../FriendsRoomInviteView.types.ts | 6 + .../views/messenger/FriendsMessengerView.tsx | 17 ++- .../room-tools/RoomToolsWidgetView.tsx | 2 +- 12 files changed, 218 insertions(+), 46 deletions(-) create mode 100644 src/views/friends/views/friends-remove-confirmation/FriendsRemoveConfirmationView.tsx create mode 100644 src/views/friends/views/friends-remove-confirmation/FriendsRemoveConfirmationView.types.ts create mode 100644 src/views/friends/views/friends-room-invite/FriendsRoomInviteView.tsx create mode 100644 src/views/friends/views/friends-room-invite/FriendsRoomInviteView.types.ts diff --git a/src/views/friends/FriendsView.scss b/src/views/friends/FriendsView.scss index 6bfa3033..5ac057b6 100644 --- a/src/views/friends/FriendsView.scss +++ b/src/views/friends/FriendsView.scss @@ -92,5 +92,13 @@ } } +.nitro-friends-room-invite { + width: $friends-list-width; +} + +.nitro-friends-remove-confirmation { + width: $friends-list-width; +} + @import "./views/friend-bar/FriendBarView"; @import "./views/messenger/FriendsMessengerView"; diff --git a/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx b/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx index 5e9d745e..888c0c57 100644 --- a/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx +++ b/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx @@ -1,4 +1,5 @@ import { FollowFriendMessageComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer'; +import classNames from 'classnames'; import { FC, useCallback, useState } from 'react'; import { LocalizeText, OpenMessengerChat } from '../../../../api'; import { SendMessageHook } from '../../../../hooks'; @@ -9,7 +10,7 @@ import { FriendsGroupItemViewProps } from './FriendsGroupItemView.types'; export const FriendsGroupItemView: FC = props => { - const { friend = null, selected = false, children = null, ...rest } = props; + const { friend = null, selected = false, selectFriend = null, children = null, ...rest } = props; const [ isExpanded, setIsExpanded ] = useState(false); @@ -20,8 +21,10 @@ export const FriendsGroupItemView: FC = props => SendMessageHook(new FollowFriendMessageComposer(friend.id)); }, [ friend ]); - const openMessengerChat = useCallback(() => + const openMessengerChat = useCallback((e) => { + e.stopPropagation(); + if(!friend) return; OpenMessengerChat(friend.id); @@ -40,8 +43,16 @@ export const FriendsGroupItemView: FC = props => } }, [ friend ]); - const updateRelationship = useCallback((type: number) => + const initUpdateRelationship = useCallback((e) => { + e.stopPropagation(); + setIsExpanded(true); + }, []); + + const updateRelationship = useCallback((e, type: number) => + { + e.stopPropagation(); + if(type !== friend.relationshipStatus) SendMessageHook(new SetRelationshipStatusComposer(friend.id, type)); setIsExpanded(false); @@ -50,8 +61,10 @@ export const FriendsGroupItemView: FC = props => if(!friend) return null; return ( - - + +
e.stopPropagation() }> + +
{ friend.name }
{ !isExpanded && @@ -60,14 +73,14 @@ export const FriendsGroupItemView: FC = props => } { friend.online && } - setIsExpanded(true) } title={ LocalizeText('infostand.link.relationship') } /> + } { isExpanded && <> - updateRelationship(MessengerFriend.RELATIONSHIP_HEART) } /> - updateRelationship(MessengerFriend.RELATIONSHIP_SMILE) } /> - updateRelationship(MessengerFriend.RELATIONSHIP_BOBBA) } /> - updateRelationship(MessengerFriend.RELATIONSHIP_NONE) } /> + updateRelationship(e, MessengerFriend.RELATIONSHIP_HEART) } /> + updateRelationship(e, MessengerFriend.RELATIONSHIP_SMILE) } /> + updateRelationship(e, MessengerFriend.RELATIONSHIP_BOBBA) } /> + updateRelationship(e, MessengerFriend.RELATIONSHIP_NONE) } /> } { children } diff --git a/src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts b/src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts index ed8ccd86..392d57d7 100644 --- a/src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts +++ b/src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts @@ -5,4 +5,5 @@ export interface FriendsGroupItemViewProps extends NitroLayoutFlexProps { friend: MessengerFriend; selected?: boolean; + selectFriend: () => void; } diff --git a/src/views/friends/views/friends-group/FriendsGroupView.tsx b/src/views/friends/views/friends-group/FriendsGroupView.tsx index 55b82fca..e1cad75e 100644 --- a/src/views/friends/views/friends-group/FriendsGroupView.tsx +++ b/src/views/friends/views/friends-group/FriendsGroupView.tsx @@ -4,15 +4,15 @@ import { FriendsGroupViewProps } from './FriendsGroupView.types'; export const FriendsGroupView: FC = props => { - const { list = null } = props; + const { list = null, selectedFriendsIds = null, selectFriend = null } = props; if(!list) return null; return ( <> - { list.map((item, index) => + { selectedFriendsIds && list && list.map((item, index) => { - return ; + return selectFriend(item.id) } />; }) } ); diff --git a/src/views/friends/views/friends-group/FriendsGroupView.types.ts b/src/views/friends/views/friends-group/FriendsGroupView.types.ts index 5ce24421..3400723c 100644 --- a/src/views/friends/views/friends-group/FriendsGroupView.types.ts +++ b/src/views/friends/views/friends-group/FriendsGroupView.types.ts @@ -3,4 +3,6 @@ import { MessengerFriend } from '../../common/MessengerFriend'; export interface FriendsGroupViewProps { list: MessengerFriend[]; + selectedFriendsIds: number[]; + selectFriend: (userId: number) => void; } diff --git a/src/views/friends/views/friends-list/FriendsListView.tsx b/src/views/friends/views/friends-list/FriendsListView.tsx index 7ceaa48d..66f2cb2e 100644 --- a/src/views/friends/views/friends-list/FriendsListView.tsx +++ b/src/views/friends/views/friends-list/FriendsListView.tsx @@ -1,9 +1,13 @@ -import { FC, useEffect, useState } from 'react'; +import { RemoveFriendComposer, SendRoomInviteComposer } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useMemo, useState } from 'react'; import { LocalizeText } from '../../../../api'; +import { SendMessageHook } from '../../../../hooks'; import { NitroCardAccordionSetView, NitroCardAccordionView, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout'; import { MessengerFriend } from '../../common/MessengerFriend'; import { FriendsGroupView } from '../friends-group/FriendsGroupView'; +import { FriendsRemoveConfirmationView } from '../friends-remove-confirmation/FriendsRemoveConfirmationView'; import { FriendsRequestView } from '../friends-request/FriendsRequestView'; +import { FriendsRoomInviteView } from '../friends-room-invite/FriendsRoomInviteView'; import { FriendsSearchView } from '../friends-search/FriendsSearchView'; import { FriendsListViewProps } from './FriendsListView.types'; @@ -13,39 +17,107 @@ const MODE_SEARCH: number = 1; export const FriendsListView: FC = props => { const { onlineFriends = [], offlineFriends = [], friendRequests = [], onCloseClick = null } = props; - const [ selectedFriends, setSelectedFriends ] = useState([]); - const [ mode, setMode ] = useState(0); - useEffect(() => + const [ selectedFriendsIds, setSelectedFriendsIds ] = useState([]); + const [ mode, setMode ] = useState(0); + + const [ showRoomInvite, setShowRoomInvite ] = useState(false); + const [ showRemoveFriendsConfirmation, setShowRemoveFriendsConfirmation ] = useState(false); + + const removeFriendsText = useMemo(() => { - setSelectedFriends([]); - }, [ onlineFriends, offlineFriends ]); + if(!selectedFriendsIds || !selectedFriendsIds.length) return ''; + + const userNames: string[] = []; + + for(const userId of selectedFriendsIds) + { + let existingFriend: MessengerFriend = onlineFriends.find(f => f.id === userId); + + if(!existingFriend) existingFriend = offlineFriends.find(f => f.id === userId); + + if(!existingFriend) continue; + + userNames.push(existingFriend.name); + } + + return LocalizeText('friendlist.removefriendconfirm.userlist', ['user_names'], [userNames.join(', ')]); + }, [offlineFriends, onlineFriends, selectedFriendsIds]); + + const selectFriend = useCallback((userId: number) => + { + if(userId < 0) return; + + const existingUserIdIndex: number = selectedFriendsIds.indexOf(userId); + + if(existingUserIdIndex > -1) + { + const clonedFriend = [...selectedFriendsIds]; + clonedFriend.splice(existingUserIdIndex, 1) + + setSelectedFriendsIds([...clonedFriend]); + } + else + { + setSelectedFriendsIds([...selectedFriendsIds, userId]); + } + }, [ selectedFriendsIds, setSelectedFriendsIds ]); + + const sendRoomInvite = useCallback((message: string) => + { + if(selectedFriendsIds.length === 0 || !message || message.length === 0) return; + + SendMessageHook(new SendRoomInviteComposer(message, ...selectedFriendsIds)); + setShowRoomInvite(false); + }, [ selectedFriendsIds, setShowRoomInvite ]); + + const removeSelectedFriends = useCallback(() => + { + if(selectedFriendsIds.length === 0) return; + + SendMessageHook(new RemoveFriendComposer(...selectedFriendsIds)); + setSelectedFriendsIds([]); + setShowRemoveFriendsConfirmation(false); + }, [ selectedFriendsIds ]); return ( - - - - setMode(MODE_FRIENDS) }> - { LocalizeText('friendlist.friends') } - - setMode(MODE_SEARCH) }> - { LocalizeText('generic.search') } - - - - { (mode === MODE_FRIENDS) && - - - - - - - - - } - { (mode === MODE_SEARCH) && - } - - + <> + + + + setMode(MODE_FRIENDS) }> + { LocalizeText('friendlist.friends') } + + setMode(MODE_SEARCH) }> + { LocalizeText('generic.search') } + + + + { (mode === MODE_FRIENDS) && + <> + + + + + + + + + + { selectedFriendsIds && selectedFriendsIds.length > 0 &&
+ + +
} + + } + { (mode === MODE_SEARCH) && + } +
+
+ { showRoomInvite && + setShowRoomInvite(false) } sendRoomInvite={ sendRoomInvite } /> } + { showRemoveFriendsConfirmation && + setShowRemoveFriendsConfirmation(false) } removeSelectedFriends={ removeSelectedFriends } /> } + ); }; diff --git a/src/views/friends/views/friends-remove-confirmation/FriendsRemoveConfirmationView.tsx b/src/views/friends/views/friends-remove-confirmation/FriendsRemoveConfirmationView.tsx new file mode 100644 index 00000000..cc3327a8 --- /dev/null +++ b/src/views/friends/views/friends-remove-confirmation/FriendsRemoveConfirmationView.tsx @@ -0,0 +1,22 @@ +import { FC } from 'react'; +import { LocalizeText } from '../../../../api'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; +import { FriendsRemoveConfirmationViewProps } from './FriendsRemoveConfirmationView.types'; + +export const FriendsRemoveConfirmationView: FC = props => +{ + const { selectedFriendsIds = null, removeFriendsText = null, removeSelectedFriends = null, onCloseClick = null } = props; + + return ( + + + +
{ removeFriendsText }
+
+ + +
+
+
+ ); +}; diff --git a/src/views/friends/views/friends-remove-confirmation/FriendsRemoveConfirmationView.types.ts b/src/views/friends/views/friends-remove-confirmation/FriendsRemoveConfirmationView.types.ts new file mode 100644 index 00000000..eeff1c9c --- /dev/null +++ b/src/views/friends/views/friends-remove-confirmation/FriendsRemoveConfirmationView.types.ts @@ -0,0 +1,7 @@ +export interface FriendsRemoveConfirmationViewProps +{ + selectedFriendsIds: number[]; + removeFriendsText: string; + removeSelectedFriends: () => void; + onCloseClick: () => void; +} diff --git a/src/views/friends/views/friends-room-invite/FriendsRoomInviteView.tsx b/src/views/friends/views/friends-room-invite/FriendsRoomInviteView.tsx new file mode 100644 index 00000000..3c4c9d26 --- /dev/null +++ b/src/views/friends/views/friends-room-invite/FriendsRoomInviteView.tsx @@ -0,0 +1,26 @@ +import { FC, useState } from 'react'; +import { LocalizeText } from '../../../../api'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; +import { FriendsRoomInviteViewProps } from './FriendsRoomInviteView.types'; + +export const FriendsRoomInviteView: FC = props => +{ + const { selectedFriendsIds = null, onCloseClick = null, sendRoomInvite = null } = props; + + const [ roomInviteMessage, setRoomInviteMessage ] = useState(''); + + return ( + + + + { LocalizeText('friendlist.invite.summary', ['count'], [selectedFriendsIds.length.toString()]) } + +
{ LocalizeText('friendlist.invite.note') }
+
+ + +
+
+
+ ); +}; diff --git a/src/views/friends/views/friends-room-invite/FriendsRoomInviteView.types.ts b/src/views/friends/views/friends-room-invite/FriendsRoomInviteView.types.ts new file mode 100644 index 00000000..1fc54ff3 --- /dev/null +++ b/src/views/friends/views/friends-room-invite/FriendsRoomInviteView.types.ts @@ -0,0 +1,6 @@ +export interface FriendsRoomInviteViewProps +{ + selectedFriendsIds: number[]; + onCloseClick: () => void; + sendRoomInvite: (message: string) => void; +} diff --git a/src/views/friends/views/messenger/FriendsMessengerView.tsx b/src/views/friends/views/messenger/FriendsMessengerView.tsx index 5544e2b1..919f3bd4 100644 --- a/src/views/friends/views/messenger/FriendsMessengerView.tsx +++ b/src/views/friends/views/messenger/FriendsMessengerView.tsx @@ -1,4 +1,4 @@ -import { FollowFriendMessageComposer, ILinkEventTracker, NewConsoleMessageEvent, SendMessageComposer } from '@nitrots/nitro-renderer'; +import { FollowFriendMessageComposer, ILinkEventTracker, NewConsoleMessageEvent, RoomInviteEvent, SendMessageComposer } from '@nitrots/nitro-renderer'; import { FC, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { AddEventLinkTracker, GetSessionDataManager, GetUserProfile, LocalizeText, RemoveLinkEventTracker } from '../../../../api'; import { MESSENGER_MESSAGE_RECEIVED, MESSENGER_NEW_THREAD, PlaySound } from '../../../../api/utils/PlaySound'; @@ -105,6 +105,21 @@ export const FriendsMessengerView: FC<{}> = props => CreateMessageHook(NewConsoleMessageEvent, onNewConsoleMessageEvent); + const onRoomInviteEvent = useCallback((event: RoomInviteEvent) => + { + const parser = event.getParser(); + + const [threadIndex, thread] = getMessageThreadWithIndex(parser.senderId); + + if((threadIndex === -1) || !thread) return; + + thread.addMessage(parser.senderId, parser.messageText, 0, null, MessengerThreadChat.ROOM_INVITE); + + setMessageThreads(prevValue => [...prevValue]); + }, [getMessageThreadWithIndex]); + + CreateMessageHook(RoomInviteEvent, onRoomInviteEvent); + const sendMessage = useCallback(() => { if(!messageText || !messageText.length) return; diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx index b4674424..f383a6af 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -119,7 +119,7 @@ export const RoomToolsWidgetView: FC<{}> = props =>
{ roomOwner }
{ roomTags && roomTags.length > 0 &&
- { roomTags.map(tag => + { roomTags.map((tag: string) => { return
#{ tag }
}) } From a4c0492034511c1d992455942a725ba59e2a3b33 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sun, 13 Feb 2022 19:42:56 -0300 Subject: [PATCH 6/7] Fix dumb room-tools timeout issue --- .../room-tools/RoomToolsWidgetView.tsx | 48 ++++++++----------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx index f383a6af..6d10b0ff 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -1,6 +1,6 @@ import { GetGuestRoomResultEvent, RoomLikeRoomComposer } from '@nitrots/nitro-renderer'; import classNames from 'classnames'; -import { FC, useCallback, useState } from 'react'; +import { FC, useCallback, useEffect, useState } from 'react'; import { LocalizeText, RoomWidgetZoomToggleMessage } from '../../../../api'; import { NavigatorEvent } from '../../../../events'; import { ChatHistoryEvent } from '../../../../events/chat-history/ChatHistoryEvent'; @@ -53,38 +53,32 @@ export const RoomToolsWidgetView: FC<{}> = props => { const parser = event.getParser(); - let updated = false; + if(roomName !== parser.data.roomName) setRoomName(parser.data.roomName); - if(roomName !== parser.data.roomName) - { - updated = true; - setRoomName(parser.data.roomName); - } + if(roomOwner !== parser.data.ownerName) setRoomOwner(parser.data.ownerName); - if(roomOwner !== parser.data.ownerName) - { - updated = true; - setRoomOwner(parser.data.ownerName); - } + if(roomTags !== parser.data.tags) setRoomTags(parser.data.tags); + }, [ roomName, roomOwner, roomTags ]); - if(roomTags !== parser.data.tags) - { - updated = true; - setRoomTags(parser.data.tags); - } + useEffect(() => + { + setRoomInfoOpacity(true); + setRoomInfoDisplay(true); - if(updated) + let timeoutDisplay = null; + + const timeoutOpacity = setTimeout(() => { - setRoomInfoOpacity(true); - setRoomInfoDisplay(true); + setRoomInfoOpacity(false); - setTimeout(() => - { - setRoomInfoOpacity(false); - - setTimeout(() => setRoomInfoDisplay(false), 1000); - }, 3000); - } + timeoutDisplay = setTimeout(() => setRoomInfoDisplay(false), 1000); + }, 3000); + + return () => + { + clearTimeout(timeoutOpacity); + clearTimeout(timeoutDisplay); + }; }, [ roomName, roomOwner, roomTags ]); CreateMessageHook(GetGuestRoomResultEvent, onGetGuestRoomResultEvent); From 740a51740913ff971a559a60316629fdb7866415 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sun, 13 Feb 2022 19:55:21 -0300 Subject: [PATCH 7/7] Add tags to room-settings --- .../NavigatorRoomSettingsView.tsx | 2 +- .../NavigatorRoomSettingsBasicTabView.tsx | 35 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx index 8fe49ce2..628eca33 100644 --- a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx +++ b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx @@ -143,7 +143,7 @@ export const NavigatorRoomSettingsView: FC<{}> = props => return setCurrentTab(tab) }>{ LocalizeText(tab) } }) } - + { currentTab === TABS[0] && } { currentTab === TABS[1] && } { currentTab === TABS[2] && } diff --git a/src/views/navigator/views/room-settings/views/tab-basic/NavigatorRoomSettingsBasicTabView.tsx b/src/views/navigator/views/room-settings/views/tab-basic/NavigatorRoomSettingsBasicTabView.tsx index 64329cc1..131b19a2 100644 --- a/src/views/navigator/views/room-settings/views/tab-basic/NavigatorRoomSettingsBasicTabView.tsx +++ b/src/views/navigator/views/room-settings/views/tab-basic/NavigatorRoomSettingsBasicTabView.tsx @@ -36,6 +36,30 @@ export const NavigatorRoomSettingsBasicTabView: FC{ LocalizeText('navigator.roomsettings.trade_allowed') }
-
+
+ +
+ 0 ? roomSettingsData.tags[0] : '' } onChange={ event => handleChange('tag_1', event.target.value) } onBlur={ () => onSave(roomSettingsData) } /> + 1 ? roomSettingsData.tags[1] : '' } onChange={ event => handleChange('tag_2', event.target.value) } onBlur={ () => onSave(roomSettingsData) } /> +
+
+
handleChange('allow_walkthrough', event.target.checked) } />
-
+