import React from 'react'; import { GetSessionDataManager, RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, RoomSessionFavoriteGroupUpdateEvent, RoomSessionUserBadgesEvent, RoomSessionUserFigureUpdateEvent, UserRelationshipsComposer } from '@nitrots/nitro-renderer'; import { Dispatch, FC, FocusEvent, KeyboardEvent, SetStateAction, useCallback, useEffect, useMemo, useState } from 'react'; import { FaPencilAlt, FaTimes } from 'react-icons/fa'; import { AvatarInfoUser, CloneObject, GetConfigurationValue, GetGroupInformation, GetUserProfile, LocalizeText, SendMessageComposer } from '../../../../../api'; import { Base, Column, Flex, LayoutAvatarImageView, LayoutBadgeImageView, Text, UserProfileIconView } from '../../../../../common'; import { useMessageEvent, useNitroEvent, useRoom } from '../../../../../hooks'; import { InfoStandBadgeSlotView } from './InfoStandBadgeSlotView'; import { InfoStandWidgetUserRelationshipsView } from './InfoStandWidgetUserRelationshipsView'; import { InfoStandWidgetUserTagsView } from './InfoStandWidgetUserTagsView'; import { BackgroundsView } from '../../../../backgrounds/BackgroundsView'; interface InfoStandWidgetUserViewProps { avatarInfo: AvatarInfoUser; setAvatarInfo: Dispatch>; onClose: () => void; } export const InfoStandWidgetUserView: FC = props => { const { avatarInfo = null, setAvatarInfo = null, onClose = null } = props; const [motto, setMotto] = useState(null); const [isEditingMotto, setIsEditingMotto] = useState(false); const [relationships, setRelationships] = useState(null); const [backgroundId, setBackgroundId] = useState(null); const [standId, setStandId] = useState(null); const [overlayId, setOverlayId] = useState(null); const [isVisible, setIsVisible] = useState(false); const { roomSession = null } = useRoom(); const infostandBackgroundClass = `background-${backgroundId ?? 'default'}`; const infostandStandClass = `stand-${standId ?? 'default'}`; const infostandOverlayClass = `overlay-${overlayId ?? 'default'}`; const handleProfileClick = useCallback(() => { GetUserProfile(avatarInfo.webID); }, [avatarInfo.webID]); const handleEditClick = useCallback((event: React.MouseEvent) => { event.stopPropagation(); setIsVisible(prev => !prev); }, []); const saveMotto = (motto: string) => { if (!isEditingMotto || motto.length > GetConfigurationValue('motto.max.length', 38) || !roomSession) return; roomSession.sendMottoMessage(motto); setIsEditingMotto(false); }; const onMottoBlur = (event: FocusEvent) => saveMotto(event.target.value); const onMottoKeyDown = (event: KeyboardEvent) => { event.stopPropagation(); switch (event.key) { case 'Enter': saveMotto((event.target as HTMLInputElement).value); return; } }; useNitroEvent(RoomSessionUserBadgesEvent.RSUBE_BADGES, event => { if (!avatarInfo || avatarInfo.webID !== event.userId) return; // Deduplicate badges from server const seen = new Set(); const dedupedBadges = event.badges.map(code => { if (!code || seen.has(code)) return ''; seen.add(code); return code; }); const oldBadges = avatarInfo.badges.join(''); if (oldBadges === dedupedBadges.join('')) return; setAvatarInfo(prevValue => { if (!prevValue) return prevValue; const newValue = CloneObject(prevValue); newValue.badges = dedupedBadges; return newValue; }); }); useNitroEvent(RoomSessionUserFigureUpdateEvent.USER_FIGURE, event => { if (!avatarInfo || avatarInfo.roomIndex !== event.roomIndex) return; setAvatarInfo(prevValue => { if (!prevValue) return prevValue; const newValue = CloneObject(prevValue); newValue.figure = event.figure; newValue.motto = event.customInfo; newValue.achievementScore = event.activityPoints; newValue.backgroundId = event.backgroundId; newValue.standId = event.standId; newValue.overlayId = event.overlayId; return newValue; }); }); useNitroEvent(RoomSessionFavoriteGroupUpdateEvent.FAVOURITE_GROUP_UPDATE, event => { if (!avatarInfo || avatarInfo.roomIndex !== event.roomIndex) return; setAvatarInfo(prevValue => { if (!prevValue) return prevValue; const newValue = CloneObject(prevValue); const clearGroup = (event.status === -1) || (event.habboGroupId <= 0); newValue.groupId = clearGroup ? -1 : event.habboGroupId; newValue.groupName = clearGroup ? null : event.habboGroupName; newValue.groupBadgeId = clearGroup ? null : GetSessionDataManager().getGroupBadge(event.habboGroupId); return newValue; }); }); useMessageEvent(RelationshipStatusInfoEvent, event => { const parser = event.getParser(); if (!avatarInfo || avatarInfo.webID !== parser.userId) return; setRelationships(parser); }); useEffect(() => { setIsEditingMotto(false); setMotto(avatarInfo.motto); setBackgroundId(avatarInfo.backgroundId); setStandId(avatarInfo.standId); setOverlayId(avatarInfo.overlayId); SendMessageComposer(new UserRelationshipsComposer(avatarInfo.webID)); return () => { setIsEditingMotto(false); setMotto(null); setRelationships(null); setBackgroundId(null); setStandId(null); setOverlayId(null); }; }, [avatarInfo]); if (!avatarInfo) return null; return ( <>
{avatarInfo.name}

{avatarInfo.type === AvatarInfoUser.OWN_USER && ( )} { (() => { const maxSlots = GetConfigurationValue('user.badges.max.slots', 5); const isOwnUser = avatarInfo.type === AvatarInfoUser.OWN_USER; const showGroup = maxSlots <= 5; const items: React.ReactNode[] = []; items.push(); if(showGroup) { items.push( 0} onClick={event => GetGroupInformation(avatarInfo.groupId)}> {avatarInfo.groupId > 0 && } ); } else { items.push(); } const startIdx = showGroup ? 1 : 2; for(let i = startIdx; i < maxSlots; i++) { items.push(); } const rows: React.ReactNode[][] = []; for(let i = 0; i < items.length; i += 2) { rows.push(items.slice(i, i + 2)); } return rows.map((row, idx) => ( {row} )); })() }

{avatarInfo.type !== AvatarInfoUser.OWN_USER && ( {motto} )} {avatarInfo.type === AvatarInfoUser.OWN_USER && ( {!isEditingMotto && ( setIsEditingMotto(true)}> {motto}  )} {isEditingMotto && ( ('motto.max.length', 38)} type="text" value={motto} onBlur={onMottoBlur} onChange={event => setMotto(event.target.value)} onKeyDown={onMottoKeyDown} /> )} )}
{LocalizeText('infostand.text.achievement_score') + ' ' + avatarInfo.achievementScore} {avatarInfo.carryItem > 0 && ( <>
{LocalizeText('infostand.text.handitem', ['item'], [LocalizeText('handitem' + avatarInfo.carryItem)])} )}
{GetConfigurationValue('user.tags.enabled') && ( )}
{isVisible && avatarInfo.type === AvatarInfoUser.OWN_USER && (
)} ); };