Update profiles

This commit is contained in:
Bill 2022-03-14 06:39:09 -04:00
parent 10bb7c5aa7
commit 9ec5f9f0de
13 changed files with 232 additions and 259 deletions

View File

@ -35,8 +35,8 @@ $navigator-height: 420px;
$chat-input-style-selector-widget-width: 210px; $chat-input-style-selector-widget-width: 210px;
$chat-input-style-selector-widget-height: 200px; $chat-input-style-selector-widget-height: 200px;
$user-profile-width: 560px; $user-profile-width: 470px;
$user-profile-height: 500px; $user-profile-height: 460px;
$nitro-widget-custom-stack-height-width: 275px; $nitro-widget-custom-stack-height-width: 275px;
$nitro-widget-custom-stack-height-height: 220px; $nitro-widget-custom-stack-height-height: 220px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -1,5 +1,5 @@
.layout-grid-item { .layout-grid-item {
height: var(--nitro-grid-column-min-height, 45px); height: var(--nitro-grid-column-min-height, unset);
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-color: $grid-bg-color; background-color: $grid-bg-color;

View File

@ -1,106 +1,67 @@
.user-profile { .user-profile {
width: 560px; width: $user-profile-width;
height: $user-profile-height;
.content-area {
color: black;
}
.user-container { .user-container {
border-right: 1px solid gray; border-right: 1px solid gray;
.avatar-image { .avatar-container {
left: -10px; width: 75px;
height: 120px;
} }
.add-friend {
margin: 5px;
margin-left: 10px;
}
}
.badge-container {
min-height: 50px;
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
margin: 0px;
margin-bottom: 2px;
} }
.rooms-button-container { .rooms-button-container {
border-top: 1px solid gray; border-top: 1px solid gray;
border-bottom: 1px solid gray; border-bottom: 1px solid gray;
padding: 1px;
.rooms-button {
display: inline-block;
text-align: center;
height: 100%;
text-decoration: underline;
margin-left: 10px;
}
} }
.friends-container { .user-relationship {
height: 100%; height: 25px;
}
}
.profile-groups { .avatar-image-container {
height: 219px;
.profile-groups-item {
width: 50px; width: 50px;
height: 50px; height: 50px;
border-radius: $border-radius;
border-color: $grid-border-color !important;
background-color: $grid-bg-color;
border: nth(map-values($border-widths), 2) solid;
&.active {
border-color: $grid-active-border-color !important;
background-color: $grid-active-bg-color !important;
}
.icon {
z-index: 1;
top: 0px;
right: 0px;
}
}
}
.relationships-container {
.relationship-container {
.relationship
{
position: relative;
&.advanced {
background-color: white;
padding: 5px;
border-radius: 5px;
}
.relationship-text {
text-decoration: underline;
}
.avatar-image { .avatar-image {
position: absolute; top: 20px;
right: -8pxpx;
}
}
}
.user-relationship-count {
margin-top: 2px;
margin-left: 5px;
color: #939392 !important;
}
.user-groups-container {
.layout-grid-item {
width: 50px; width: 50px;
height: 80px;
right: 0;
margin-top: -60px;
} }
} }
.others-text { .no-group-spritesheet {
margin-left: 20px; background: transparent url('../../assets/images/groups/no-group-spritesheet.png') no-repeat;
height: 21px;
color: #939392; &.image-1 {
} width: 95px;
height: 136px;
background-position: -3px -3px;
} }
&.image-2 {
width: 95px;
height: 136px;
background-position: -104px -3px;
}
&.image-3 {
width: 95px;
height: 136px;
background-position: -205px -3px;
}
}
} }

View File

@ -1,7 +1,7 @@
import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, UserCurrentBadgesComposer, UserCurrentBadgesEvent, UserProfileEvent, UserProfileParser, UserRelationshipsComposer } from '@nitrots/nitro-renderer'; import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, UserCurrentBadgesComposer, UserCurrentBadgesEvent, UserProfileEvent, UserProfileParser, UserRelationshipsComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react'; import { FC, useCallback, useState } from 'react';
import { GetSessionDataManager, GetUserProfile, LocalizeText, SendMessageComposer } from '../../api'; import { GetSessionDataManager, GetUserProfile, LocalizeText, SendMessageComposer } from '../../api';
import { Column, Flex, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common'; import { Column, Flex, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
import { BatchUpdates, UseMessageEventHook } from '../../hooks'; import { BatchUpdates, UseMessageEventHook } from '../../hooks';
import { BadgesContainerView } from './views/BadgesContainerView'; import { BadgesContainerView } from './views/BadgesContainerView';
import { FriendsContainerView } from './views/FriendsContainerView'; import { FriendsContainerView } from './views/FriendsContainerView';
@ -26,10 +26,9 @@ export const UserProfileView: FC<{}> = props =>
const onLeaveGroup = useCallback(() => const onLeaveGroup = useCallback(() =>
{ {
if(userProfile && userProfile.id === GetSessionDataManager().userId) if(!userProfile || (userProfile.id !== GetSessionDataManager().userId)) return;
{
GetUserProfile(userProfile.id); GetUserProfile(userProfile.id);
}
}, [ userProfile ]); }, [ userProfile ]);
const onUserCurrentBadgesEvent = useCallback((event: UserCurrentBadgesEvent) => const onUserCurrentBadgesEvent = useCallback((event: UserCurrentBadgesEvent) =>
@ -43,7 +42,7 @@ export const UserProfileView: FC<{}> = props =>
UseMessageEventHook(UserCurrentBadgesEvent, onUserCurrentBadgesEvent); UseMessageEventHook(UserCurrentBadgesEvent, onUserCurrentBadgesEvent);
const OnUserRelationshipsEvent = useCallback((event: RelationshipStatusInfoEvent) => const onUserRelationshipsEvent = useCallback((event: RelationshipStatusInfoEvent) =>
{ {
const parser = event.getParser(); const parser = event.getParser();
@ -52,27 +51,22 @@ export const UserProfileView: FC<{}> = props =>
setUserRelationships(parser); setUserRelationships(parser);
}, [ userProfile ]); }, [ userProfile ]);
UseMessageEventHook(RelationshipStatusInfoEvent, OnUserRelationshipsEvent); UseMessageEventHook(RelationshipStatusInfoEvent, onUserRelationshipsEvent);
const onUserProfileEvent = useCallback((event: UserProfileEvent) => const onUserProfileEvent = useCallback((event: UserProfileEvent) =>
{ {
const parser = event.getParser(); const parser = event.getParser();
if(userProfile)
{
BatchUpdates(() => BatchUpdates(() =>
{ {
setUserProfile(null); setUserProfile(parser);
setUserBadges([]); setUserBadges([]);
setUserRelationships(null); setUserRelationships(null);
}); });
}
setUserProfile(parser);
SendMessageComposer(new UserCurrentBadgesComposer(parser.id)); SendMessageComposer(new UserCurrentBadgesComposer(parser.id));
SendMessageComposer(new UserRelationshipsComposer(parser.id)); SendMessageComposer(new UserRelationshipsComposer(parser.id));
}, [ userProfile ]); }, []);
UseMessageEventHook(UserProfileEvent, onUserProfileEvent); UseMessageEventHook(UserProfileEvent, onUserProfileEvent);
@ -81,22 +75,26 @@ export const UserProfileView: FC<{}> = props =>
return ( return (
<NitroCardView className="user-profile" theme="primary-slim"> <NitroCardView className="user-profile" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText('extendedprofile.caption') } onCloseClick={ onClose } /> <NitroCardHeaderView headerText={ LocalizeText('extendedprofile.caption') } onCloseClick={ onClose } />
<NitroCardContentView> <NitroCardContentView overflow="hidden">
<Grid> <Grid fullHeight={ false } gap={ 2 }>
<Column size={ 7 } className="user-container"> <Column size={ 7 } gap={ 1 } className="user-container pe-2">
<UserContainerView userProfile={ userProfile } /> <UserContainerView userProfile={ userProfile } />
<BadgesContainerView badges={ userBadges } /> <Grid columnCount={ 5 } fullHeight className="bg-muted rounded px-2 py-1">
<BadgesContainerView fullWidth center badges={ userBadges } />
</Grid>
</Column> </Column>
<Column size={ 5 }> <Column size={ 5 }>
{ { userRelationships &&
userRelationships && <FriendsContainerView relationships={userRelationships} friendsCount={userProfile.friendsCount} /> <FriendsContainerView relationships={ userRelationships } friendsCount={ userProfile.friendsCount } /> }
}
</Column> </Column>
</Grid> </Grid>
<Flex alignItems="center" className="rooms-button-container"> <Flex alignItems="center" className="rooms-button-container px-2 py-1">
<i className="icon icon-rooms" /><span className="rooms-button">{LocalizeText('extendedprofile.rooms')}</span> <Flex alignItems="center" gap={ 1 }>
<i className="icon icon-rooms" />
<Text bold underline pointer>{ LocalizeText('extendedprofile.rooms') }</Text>
</Flex> </Flex>
<GroupsContainerView itsMe={ userProfile.id === GetSessionDataManager().userId } groups={ userProfile.groups } onLeaveGroup={ onLeaveGroup } /> </Flex>
<GroupsContainerView fullWidth itsMe={ userProfile.id === GetSessionDataManager().userId } groups={ userProfile.groups } onLeaveGroup={ onLeaveGroup } />
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> </NitroCardView>
) )

View File

@ -1,27 +1,25 @@
import { FC } from 'react'; import { FC } from 'react';
import { Grid, LayoutBadgeImageView, LayoutGridItem } from '../../../common'; import { Column, FlexProps, LayoutBadgeImageView } from '../../../common';
interface BadgesContainerViewProps interface BadgesContainerViewProps extends FlexProps
{ {
badges: string[]; badges: string[];
} }
export const BadgesContainerView: FC<BadgesContainerViewProps> = props => export const BadgesContainerView: FC<BadgesContainerViewProps> = props =>
{ {
const { badges = null } = props; const { badges = null, gap = 1, justifyContent = 'between', ...rest } = props;
return ( return (
<div className="row"> <>
<Grid>
{ badges && (badges.length > 0) && badges.map((badge, index) => { badges && (badges.length > 0) && badges.map((badge, index) =>
{ {
return ( return (
<LayoutGridItem key={ index }> <Column key={ badge } center>
<LayoutBadgeImageView badgeCode={ badge }/> <LayoutBadgeImageView key={ badge } badgeCode={ badge } />
</LayoutGridItem> </Column>
) );
}) } }) }
</Grid> </>
</div> );
)
} }

View File

@ -1,6 +1,7 @@
import { RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer'; import { RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer';
import { FC } from 'react'; import { FC } from 'react';
import { LocalizeText } from '../../../api'; import { LocalizeText } from '../../../api';
import { Column, Text } from '../../../common';
import { RelationshipsContainerView } from './RelationshipsContainerView'; import { RelationshipsContainerView } from './RelationshipsContainerView';
interface FriendsContainerViewProps interface FriendsContainerViewProps
@ -14,12 +15,14 @@ export const FriendsContainerView: FC<FriendsContainerViewProps> = props =>
const { relationships = null, friendsCount = null } = props; const { relationships = null, friendsCount = null } = props;
return ( return (
<div className="friends-container h-100 d-flex flex-column"> <Column gap={ 1 }>
<div className="mb-1" dangerouslySetInnerHTML={{ __html: LocalizeText('extendedprofile.friends.count', ['count'], [friendsCount.toString()]) }} /> <Text small>
<div className="mb-1"><b>{LocalizeText('extendedprofile.relstatus')}</b></div> <b>{ LocalizeText('extendedprofile.friends.count') }</b> { friendsCount }
<div className="h-100 d-flex flex-column justify-content-between"> </Text>
<Text bold small>{ LocalizeText('extendedprofile.relstatus') }</Text>
<Column>
<RelationshipsContainerView relationships={relationships} /> <RelationshipsContainerView relationships={relationships} />
</div> </Column>
</div> </Column>
) )
} }

View File

@ -1,12 +1,11 @@
import { GroupFavoriteComposer, GroupInformationComposer, GroupInformationEvent, GroupInformationParser, HabboGroupEntryData } from '@nitrots/nitro-renderer'; import { GroupFavoriteComposer, GroupInformationComposer, GroupInformationEvent, GroupInformationParser, HabboGroupEntryData } from '@nitrots/nitro-renderer';
import classNames from 'classnames';
import { FC, useCallback, useEffect, useState } from 'react'; import { FC, useCallback, useEffect, useState } from 'react';
import { SendMessageComposer } from '../../../api'; import { SendMessageComposer } from '../../../api';
import { LayoutBadgeImageView } from '../../../common'; import { AutoGrid, Base, Column, Flex, Grid, GridProps, LayoutBadgeImageView, LayoutGridItem } from '../../../common';
import { UseMessageEventHook } from '../../../hooks'; import { BatchUpdates, UseMessageEventHook } from '../../../hooks';
import { GroupInformationView } from '../../groups/views/GroupInformationView'; import { GroupInformationView } from '../../groups/views/GroupInformationView';
interface GroupsContainerViewProps interface GroupsContainerViewProps extends GridProps
{ {
itsMe: boolean; itsMe: boolean;
groups: HabboGroupEntryData[]; groups: HabboGroupEntryData[];
@ -15,16 +14,17 @@ interface GroupsContainerViewProps
export const GroupsContainerView: FC<GroupsContainerViewProps> = props => export const GroupsContainerView: FC<GroupsContainerViewProps> = props =>
{ {
const { itsMe = null, groups = null, onLeaveGroup = null } = props; const { itsMe = null, groups = null, onLeaveGroup = null, overflow = 'hidden', gap = 2, ...rest } = props;
const [ selectedGroupId, setSelectedGroupId ] = useState<number>(null); const [ selectedGroupId, setSelectedGroupId ] = useState<number>(null);
const [ groupInformation, setGroupInformation ] = useState<GroupInformationParser>(null); const [ groupInformation, setGroupInformation ] = useState<GroupInformationParser>(null);
const favoriteGroup = (groupId: number) => SendMessageComposer(new GroupFavoriteComposer(groupId));
const onGroupInformationEvent = useCallback((event: GroupInformationEvent) => const onGroupInformationEvent = useCallback((event: GroupInformationEvent) =>
{ {
const parser = event.getParser(); const parser = event.getParser();
if(!selectedGroupId || selectedGroupId !== parser.id || parser.flag) return; if(!selectedGroupId || (selectedGroupId !== parser.id) || parser.flag) return;
if(groupInformation) setGroupInformation(null); if(groupInformation) setGroupInformation(null);
@ -35,37 +35,54 @@ export const GroupsContainerView: FC<GroupsContainerViewProps> = props =>
useEffect(() => useEffect(() =>
{ {
if(groups.length > 0 && !selectedGroupId) setSelectedGroupId(groups[0].groupId); if(!selectedGroupId) return;
}, [ groups, selectedGroupId ]);
SendMessageComposer(new GroupInformationComposer(selectedGroupId, false));
}, [ selectedGroupId ]);
useEffect(() => useEffect(() =>
{ {
if(selectedGroupId) SendMessageComposer(new GroupInformationComposer(selectedGroupId, false)); BatchUpdates(() =>
}, [ selectedGroupId ]);
const favoriteGroup = useCallback((groupId: number) =>
{ {
SendMessageComposer(new GroupFavoriteComposer(groupId)); setGroupInformation(null);
}, []);
if(!groups) return null; if(groups.length > 0) setSelectedGroupId(groups[0].groupId);
});
}, [ groups ]);
if(!groups || !groups.length)
{
return ( return (
<div className="d-flex"> <Column center fullHeight>
<div className="profile-groups p-2"> <Flex justifyContent="center" gap={ 2 }>
<div className="h-100 overflow-auto d-flex flex-column gap-1"> <Base className="no-group-spritesheet image-1" />
{ groups.map((group, index) => <Base className="no-group-spritesheet image-2" />
{ <Base className="no-group-spritesheet image-3" />
return <div key={ index } onClick={ () => setSelectedGroupId(group.groupId) } className={ 'profile-groups-item position-relative flex-shrink-0 d-flex align-items-center justify-content-center cursor-pointer' + classNames({ ' active': selectedGroupId === group.groupId }) }> </Flex>
{ itsMe && <i className={ 'position-absolute icon icon-group-' + (group.favourite ? 'favorite' : 'not-favorite') } onClick={ () => favoriteGroup(group.groupId) } /> } </Column>
<LayoutBadgeImageView badgeCode={ group.badgeCode } isGroup={ true } /> );
</div> }
}) }
</div> return (
</div> <Grid overflow={ overflow } gap={ 2 } { ...rest }>
<div className="w-100"> <Column alignItems="center" size={ 2 } overflow="auto">
{ groupInformation && <GroupInformationView groupInformation={ groupInformation } onClose={ onLeaveGroup } /> } <AutoGrid overflow={ null } columnCount={ 1 } columnMinHeight={ 50 } className="user-groups-container">
</div> { groups.map((group, index) =>
</div> {
return (
<LayoutGridItem key={ index } overflow="unset" itemActive={ (selectedGroupId === group.groupId) } onClick={ () => setSelectedGroupId(group.groupId) } className="p-1">
{ itsMe &&
<i className={ 'position-absolute end-0 top-0 z-index-1 icon icon-group-' + (group.favourite ? 'favorite' : 'not-favorite') } onClick={ () => favoriteGroup(group.groupId) } /> }
<LayoutBadgeImageView badgeCode={ group.badgeCode } isGroup={ true } />
</LayoutGridItem>
)
}) }
</AutoGrid>
</Column>
<Column size={ 10 }>
{ groupInformation &&
<GroupInformationView groupInformation={ groupInformation } onClose={ onLeaveGroup } /> }
</Column>
</Grid>
); );
} }

View File

@ -1,75 +1,62 @@
import { RelationshipStatusEnum, RelationshipStatusInfo, RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer'; import { RelationshipStatusEnum, RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react'; import { FC } from 'react';
import { GetUserProfile, LocalizeText } from '../../../api'; import { GetUserProfile, LocalizeText } from '../../../api';
import { LayoutAvatarImageView } from '../../../common'; import { Column, Flex, LayoutAvatarImageView, Text } from '../../../common';
interface RelationshipsContainerViewProps interface RelationshipsContainerViewProps
{ {
relationships: RelationshipStatusInfoMessageParser; relationships: RelationshipStatusInfoMessageParser;
simple?: boolean; }
interface RelationshipsContainerRelationshipViewProps
{
type: number;
} }
export const RelationshipsContainerView: FC<RelationshipsContainerViewProps> = props => export const RelationshipsContainerView: FC<RelationshipsContainerViewProps> = props =>
{ {
const { relationships = null, simple = false } = props; const { relationships = null } = props;
const OnUserClick = useCallback((user: RelationshipStatusInfo) => const RelationshipComponent = ({ type }: RelationshipsContainerRelationshipViewProps) =>
{
if(!user) return;
GetUserProfile(user.randomFriendId);
}, []);
const RelationshipComponent = useCallback(({ type }) =>
{ {
const relationshipInfo = (relationships && relationships.relationshipStatusMap.hasKey(type)) ? relationships.relationshipStatusMap.getValue(type) : null; const relationshipInfo = (relationships && relationships.relationshipStatusMap.hasKey(type)) ? relationships.relationshipStatusMap.getValue(type) : null;
if(simple && !relationshipInfo) return null;
const relationshipName = RelationshipStatusEnum.RELATIONSHIP_NAMES[type].toLocaleLowerCase(); const relationshipName = RelationshipStatusEnum.RELATIONSHIP_NAMES[type].toLocaleLowerCase();
return ( return (
<div className="relationship-container d-flex flex-row align-items-center w-100"> <Flex fullWidth gap={ 1 }>
<i className={`nitro-friends-spritesheet icon-${relationshipName} flex-shrink-0 align-self-baseline mt-2`} /> <Flex center className="user-relationship">
<div className="w-100 d-flex flex-column"> <i className={ `nitro-friends-spritesheet icon-${ relationshipName }` } />
<span className={'relationship mx-2' + (!simple ? ' advanced' : '')}> </Flex>
<span className="cursor-pointer relationship-text" onClick={ event => OnUserClick(relationshipInfo)}> <Column grow gap={ 0 }>
{ <Flex alignItems="center" justifyContent="between" className="bg-white rounded px-2 py-1 user-relationship">
(relationshipInfo && relationshipInfo.friendCount > 0) ? relationshipInfo.randomFriendName : LocalizeText('extendedprofile.add.friends') <Text small underline pointer onClick={ event => (relationshipInfo && (relationshipInfo.randomFriendId >= 1) && GetUserProfile(relationshipInfo.randomFriendId)) }>
} { (!relationshipInfo || (relationshipInfo.friendCount === 0)) &&
</span> LocalizeText('extendedprofile.add.friends') }
{ { (relationshipInfo && (relationshipInfo.friendCount >= 1)) &&
(simple && relationshipInfo && relationshipInfo.friendCount > 1) && relationshipInfo.randomFriendName }
<span> </Text>
{' ' + LocalizeText(`extendedprofile.relstatus.others.${relationshipName}`, ['count'], [(relationshipInfo.friendCount - 1).toString()])} { (relationshipInfo && (relationshipInfo.friendCount >= 1)) &&
</span> <Flex center position="relative" className="avatar-image-container">
}
{
(!simple && relationshipInfo && relationshipInfo.friendCount > 0) &&
<LayoutAvatarImageView figure={ relationshipInfo.randomFriendFigure } headOnly={ true } direction={ 4 } /> <LayoutAvatarImageView figure={ relationshipInfo.randomFriendFigure } headOnly={ true } direction={ 4 } />
} </Flex> }
</span> </Flex>
<Text small italics className="user-relationship-count">
{ { (!relationshipInfo || (relationshipInfo.friendCount === 0)) &&
!simple && <div className="others-text"> LocalizeText('extendedprofile.no.friends.in.this.category') }
{ { (relationshipInfo && (relationshipInfo.friendCount > 1)) &&
(relationshipInfo && relationshipInfo.friendCount > 1) ? LocalizeText(`extendedprofile.relstatus.others.${relationshipName}`, ['count'], [(relationshipInfo.friendCount - 1).toString()]) : '' LocalizeText(`extendedprofile.relstatus.others.${ relationshipName }`, [ 'count' ], [ (relationshipInfo.friendCount - 1).toString() ]) }
} &nbsp;
{ </Text>
(relationshipInfo && relationshipInfo.friendCount < 1) ? LocalizeText('extendedprofile.no.friends.in.this.category') : '' </Column>
} </Flex>
</div>
}
</div>
</div>
); );
}, [OnUserClick, relationships, simple]); }
return ( return (
<div className="row justify-content-center relationships-container align-items-center flex-fill"> <>
<RelationshipComponent type={ RelationshipStatusEnum.HEART } /> <RelationshipComponent type={ RelationshipStatusEnum.HEART } />
<RelationshipComponent type={ RelationshipStatusEnum.SMILE } /> <RelationshipComponent type={ RelationshipStatusEnum.SMILE } />
<RelationshipComponent type={ RelationshipStatusEnum.BOBBA } /> <RelationshipComponent type={ RelationshipStatusEnum.BOBBA } />
</div> </>
); );
} }

View File

@ -1,7 +1,7 @@
import { FriendlyTime, UserProfileParser } from '@nitrots/nitro-renderer'; import { FriendlyTime, UserProfileParser } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react'; import { FC } from 'react';
import { GetSessionDataManager, LocalizeText } from '../../../api'; import { GetSessionDataManager, LocalizeText } from '../../../api';
import { LayoutAvatarImageView } from '../../../common'; import { Button, Column, Flex, LayoutAvatarImageView, Text } from '../../../common';
interface UserContainerViewProps interface UserContainerViewProps
{ {
@ -11,42 +11,51 @@ interface UserContainerViewProps
export const UserContainerView: FC<UserContainerViewProps> = props => export const UserContainerView: FC<UserContainerViewProps> = props =>
{ {
const { userProfile = null } = props; const { userProfile = null } = props;
const isOwnProfile = (userProfile.id === GetSessionDataManager().userId);
const OnlineIcon = useCallback(() => const canSendFriendRequest = (!isOwnProfile && !userProfile.isMyFriend && !userProfile.requestSent);
{
if(userProfile.isOnline) return (<i className="icon icon-pf-online" />);
else return (<i className="icon icon-pf-offline" />);
}, [ userProfile ]);
const FriendRequestComponent = useCallback(() =>
{
if(userProfile.id === GetSessionDataManager().userId) return (<span><i className="icon icon-pf-tick" />{LocalizeText('extendedprofile.me')}</span> );
if(userProfile.isMyFriend) return (<span><i className="icon icon-pf-tick" />{LocalizeText('extendedprofile.friend')}</span>);
if(userProfile.requestSent) return (<span><i className="icon icon-pf-tick" />{LocalizeText('extendedprofile.friendrequestsent')}</span>);
return (<button className="btn btn-success btn-sm add-friend">{LocalizeText('extendedprofile.addasafriend')}</button>)
}, [ userProfile ]);
return ( return (
<div className="row"> <Flex gap={ 2 }>
<div className="col-auto px-0 d-flex align-items-center"> <Column center className="avatar-container">
<LayoutAvatarImageView figure={ userProfile.figure } direction={ 2 } /> <LayoutAvatarImageView figure={ userProfile.figure } direction={ 2 } />
</div> </Column>
<div className="col"> <Column>
<div className="user-info-container"> <Column gap={ 0}>
<div className="fw-bold">{userProfile.username}</div> <Text bold>{ userProfile.username }</Text>
<div className="fst-italic text-break small">{userProfile.motto}</div> <Text italics textBreak small>{ userProfile.motto }&nbsp;</Text>
<div dangerouslySetInnerHTML={{ __html: LocalizeText('extendedprofile.created', ['created'], [userProfile.registration]) }} /> </Column>
<div dangerouslySetInnerHTML={{ __html: LocalizeText('extendedprofile.last.login', ['lastlogin'], [FriendlyTime.format(userProfile.secondsSinceLastVisit, '.ago', 2)]) }} /> <Column gap={ 1 }>
<div><b>{LocalizeText('extendedprofile.achievementscore')}</b> {userProfile.achievementPoints}</div> <Text small>
<div className="d-flex flex-row align-items-center gap-2"> <b>{ LocalizeText('extendedprofile.created') }</b> { userProfile.registration }
<OnlineIcon /> </Text>
<FriendRequestComponent /> <Text small>
</div> <b>{ LocalizeText('extendedprofile.last.login') }</b> { FriendlyTime.format(userProfile.secondsSinceLastVisit, '.ago', 2) }
</div> </Text>
</div> <Text small>
</div> <b>{ LocalizeText('extendedprofile.achievementscore') }</b> { userProfile.achievementPoints }
</Text>
</Column>
<Flex gap={ 1 }>
{ userProfile.isOnline &&
<i className="icon icon-pf-online" /> }
{ !userProfile.isOnline &&
<i className="icon icon-pf-offline" /> }
<Flex alignItems="center" gap={ 1 }>
{ canSendFriendRequest &&
<Button variant="success" className="add-friend">{ LocalizeText('extendedprofile.addasafriend') }</Button> }
{ !canSendFriendRequest &&
<>
<i className="icon icon-pf-tick" />
{ isOwnProfile &&
<Text>{ LocalizeText('extendedprofile.me') }</Text> }
{ userProfile.isMyFriend &&
<Text>{ LocalizeText('extendedprofile.friend') }</Text> }
{ userProfile.requestSent &&
<Text>{ LocalizeText('extendedprofile.friendrequestsent') }</Text> }
</> }
</Flex>
</Flex>
</Column>
</Flex>
) )
} }