mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-27 08:00:51 +01:00
Merge branch '@feature/user-profiles' into 'dev'
This commit is contained in:
commit
9fb1f6dd15
BIN
src/assets/images/profile/icons/bobba.png
Normal file
BIN
src/assets/images/profile/icons/bobba.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 169 B |
BIN
src/assets/images/profile/icons/heart.png
Normal file
BIN
src/assets/images/profile/icons/heart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 201 B |
BIN
src/assets/images/profile/icons/offline.png
Normal file
BIN
src/assets/images/profile/icons/offline.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 306 B |
BIN
src/assets/images/profile/icons/online.gif
Normal file
BIN
src/assets/images/profile/icons/online.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 666 B |
BIN
src/assets/images/profile/icons/smile.png
Normal file
BIN
src/assets/images/profile/icons/smile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 205 B |
BIN
src/assets/images/profile/icons/tick.png
Normal file
BIN
src/assets/images/profile/icons/tick.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 129 B |
@ -513,6 +513,42 @@
|
|||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.icon-pf-online {
|
||||||
|
background: url('../images/profile/icons/online.gif');
|
||||||
|
width: 40px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-pf-offline {
|
||||||
|
background: url('../images/profile/icons/offline.png');
|
||||||
|
width: 40px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-pf-tick {
|
||||||
|
background: url('../images/profile/icons/tick.png');
|
||||||
|
width: 11px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-relationship-heart {
|
||||||
|
background: url('../images/profile/icons/heart.png');
|
||||||
|
width: 16px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-relationship-bobba {
|
||||||
|
background: url('../images/profile/icons/bobba.png');
|
||||||
|
width: 16px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-relationship-smile {
|
||||||
|
background: url('../images/profile/icons/smile.png');
|
||||||
|
width: 16px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
&.spin {
|
&.spin {
|
||||||
animation: rotating 1s linear infinite;
|
animation: rotating 1s linear infinite;
|
||||||
}
|
}
|
||||||
|
@ -17,3 +17,4 @@
|
|||||||
@import './mod-tools/ModToolsView';
|
@import './mod-tools/ModToolsView';
|
||||||
@import './achievements/AchievementsView';
|
@import './achievements/AchievementsView';
|
||||||
@import './user-settings/UserSettingsView';
|
@import './user-settings/UserSettingsView';
|
||||||
|
@import './user-profile/UserProfileVew';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { FollowFriendComposer, MouseEventType } from '@nitrots/nitro-renderer';
|
import { FollowFriendComposer, MouseEventType, UserProfileComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { SendMessageHook } from '../../../../hooks/messages';
|
import { SendMessageHook } from '../../../../hooks/messages';
|
||||||
import { LocalizeText } from '../../../../utils/LocalizeText';
|
import { LocalizeText } from '../../../../utils/LocalizeText';
|
||||||
@ -16,6 +16,11 @@ export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
|
|||||||
SendMessageHook(new FollowFriendComposer(friend.id));
|
SendMessageHook(new FollowFriendComposer(friend.id));
|
||||||
}, [ friend ]);
|
}, [ friend ]);
|
||||||
|
|
||||||
|
const openProfile = useCallback(() =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new UserProfileComposer(friend.id));
|
||||||
|
}, [ friend ]);
|
||||||
|
|
||||||
const onClick = useCallback((event: MouseEvent) =>
|
const onClick = useCallback((event: MouseEvent) =>
|
||||||
{
|
{
|
||||||
const element = elementRef.current;
|
const element = elementRef.current;
|
||||||
@ -56,7 +61,7 @@ export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
|
|||||||
<div className="d-flex justify-content-between">
|
<div className="d-flex justify-content-between">
|
||||||
<i className="icon icon-fb-chat cursor-pointer" />
|
<i className="icon icon-fb-chat cursor-pointer" />
|
||||||
{ friend.followingAllowed && <i onClick={ followFriend } className="icon icon-fb-visit cursor-pointer" /> }
|
{ friend.followingAllowed && <i onClick={ followFriend } className="icon icon-fb-visit cursor-pointer" /> }
|
||||||
<i className="icon icon-fb-profile cursor-pointer" />
|
<i onClick={ openProfile } className="icon icon-fb-profile cursor-pointer" />
|
||||||
</div> }
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -14,6 +14,7 @@ import { NotificationCenterView } from '../notification-center/NotificationCente
|
|||||||
import { RightSideView } from '../right-side/RightSideView';
|
import { RightSideView } from '../right-side/RightSideView';
|
||||||
import { RoomHostView } from '../room-host/RoomHostView';
|
import { RoomHostView } from '../room-host/RoomHostView';
|
||||||
import { ToolbarView } from '../toolbar/ToolbarView';
|
import { ToolbarView } from '../toolbar/ToolbarView';
|
||||||
|
import { UserProfileView } from '../user-profile/UserProfileView';
|
||||||
import { UserSettingsView } from '../user-settings/UserSettingsView';
|
import { UserSettingsView } from '../user-settings/UserSettingsView';
|
||||||
import { WiredView } from '../wired/WiredView';
|
import { WiredView } from '../wired/WiredView';
|
||||||
import { MainViewProps } from './MainView.types';
|
import { MainViewProps } from './MainView.types';
|
||||||
@ -62,6 +63,7 @@ export const MainView: FC<MainViewProps> = props =>
|
|||||||
<RightSideView />
|
<RightSideView />
|
||||||
<NotificationCenterView />
|
<NotificationCenterView />
|
||||||
<UserSettingsView />
|
<UserSettingsView />
|
||||||
|
<UserProfileView />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { RoomSessionUserBadgesEvent } from '@nitrots/nitro-renderer';
|
import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, RoomSessionUserBadgesEvent, UserRelationshipsComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, FocusEvent, KeyboardEvent, useCallback, useEffect, useState } from 'react';
|
import { FC, FocusEvent, KeyboardEvent, useCallback, useEffect, useState } from 'react';
|
||||||
|
import { CreateMessageHook, SendMessageHook } from '../../../../../../hooks';
|
||||||
import { CreateEventDispatcherHook } from '../../../../../../hooks/events';
|
import { CreateEventDispatcherHook } from '../../../../../../hooks/events';
|
||||||
import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
import { LocalizeText } from '../../../../../../utils/LocalizeText';
|
||||||
import { AvatarImageView } from '../../../../../shared/avatar-image/AvatarImageView';
|
import { AvatarImageView } from '../../../../../shared/avatar-image/AvatarImageView';
|
||||||
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView';
|
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView';
|
||||||
|
import { RelationshipsContainerView } from '../../../../../user-profile/views/relationships-container/RelationshipsContainerView';
|
||||||
import { useRoomContext } from '../../../../context/RoomContext';
|
import { useRoomContext } from '../../../../context/RoomContext';
|
||||||
import { RoomWidgetUpdateInfostandUserEvent } from '../../../../events/RoomWidgetUpdateInfostandUserEvent';
|
import { RoomWidgetUpdateInfostandUserEvent } from '../../../../events/RoomWidgetUpdateInfostandUserEvent';
|
||||||
import { RoomWidgetChangeMottoMessage } from '../../../../messages';
|
import { RoomWidgetChangeMottoMessage } from '../../../../messages';
|
||||||
@ -16,6 +18,7 @@ export const InfoStandWidgetUserView: FC<InfoStandWidgetUserViewProps> = props =
|
|||||||
const [ badges, setBadges ] = useState<string[]>([]);
|
const [ badges, setBadges ] = useState<string[]>([]);
|
||||||
const [ motto, setMotto ] = useState(null);
|
const [ motto, setMotto ] = useState(null);
|
||||||
const [ isEditingMotto, setIsEditingMotto ] = useState(false);
|
const [ isEditingMotto, setIsEditingMotto ] = useState(false);
|
||||||
|
const [ userRelationships, setUserRelationships ] = useState<RelationshipStatusInfoMessageParser>(null);
|
||||||
|
|
||||||
const saveMotto = useCallback((motto: string) =>
|
const saveMotto = useCallback((motto: string) =>
|
||||||
{
|
{
|
||||||
@ -50,11 +53,27 @@ export const InfoStandWidgetUserView: FC<InfoStandWidgetUserViewProps> = props =
|
|||||||
|
|
||||||
CreateEventDispatcherHook(RoomSessionUserBadgesEvent.RSUBE_BADGES, eventDispatcher, onRoomSessionUserBadgesEvent);
|
CreateEventDispatcherHook(RoomSessionUserBadgesEvent.RSUBE_BADGES, eventDispatcher, onRoomSessionUserBadgesEvent);
|
||||||
|
|
||||||
|
const OnUserRelationshipsEvent = useCallback((event: RelationshipStatusInfoEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if (userData && userData.webID === parser.userId)
|
||||||
|
setUserRelationships(parser);
|
||||||
|
}, [userData]);
|
||||||
|
|
||||||
|
CreateMessageHook(RelationshipStatusInfoEvent, OnUserRelationshipsEvent);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
setBadges(userData.badges);
|
setBadges(userData.badges);
|
||||||
setIsEditingMotto(false);
|
setIsEditingMotto(false);
|
||||||
setMotto(userData.motto);
|
setMotto(userData.motto);
|
||||||
|
SendMessageHook(new UserRelationshipsComposer(userData.webID));
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
setBadges([]);
|
||||||
|
setUserRelationships(null);
|
||||||
|
}
|
||||||
}, [ userData ]);
|
}, [ userData ]);
|
||||||
|
|
||||||
if(!userData) return null;
|
if(!userData) return null;
|
||||||
@ -122,7 +141,9 @@ export const InfoStandWidgetUserView: FC<InfoStandWidgetUserViewProps> = props =
|
|||||||
<div className="small text-wrap">
|
<div className="small text-wrap">
|
||||||
{ LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + userData.carryItem) ]) }
|
{ LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + userData.carryItem) ]) }
|
||||||
</div>
|
</div>
|
||||||
</> }
|
</>
|
||||||
|
}
|
||||||
|
<RelationshipsContainerView relationships={userRelationships} simple={true}/>
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { MouseEventType } from '@nitrots/nitro-renderer';
|
import { MouseEventType, UserProfileComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useRef } from 'react';
|
import { FC, useCallback, useEffect, useRef } from 'react';
|
||||||
|
import { GetSessionDataManager } from '../../../api';
|
||||||
|
import { SendMessageHook } from '../../../hooks';
|
||||||
import { ToolbarViewItems } from '../ToolbarView.types';
|
import { ToolbarViewItems } from '../ToolbarView.types';
|
||||||
import { ToolbarMeViewProps } from './ToolbarMeView.types';
|
import { ToolbarMeViewProps } from './ToolbarMeView.types';
|
||||||
|
|
||||||
@ -29,6 +31,11 @@ export const ToolbarMeView: FC<ToolbarMeViewProps> = props =>
|
|||||||
}
|
}
|
||||||
}, [ elementRef, setMeExpanded ]);
|
}, [ elementRef, setMeExpanded ]);
|
||||||
|
|
||||||
|
const openProfile = useCallback(() =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new UserProfileComposer(GetSessionDataManager().userId));
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ elementRef } className="d-flex nitro-toolbar-me px-1 py-2">
|
<div ref={ elementRef } className="d-flex nitro-toolbar-me px-1 py-2">
|
||||||
<div className="navigation-items">
|
<div className="navigation-items">
|
||||||
@ -42,7 +49,7 @@ export const ToolbarMeView: FC<ToolbarMeViewProps> = props =>
|
|||||||
<i className="icon icon-me-achievements"></i>
|
<i className="icon icon-me-achievements"></i>
|
||||||
</div>
|
</div>
|
||||||
<div className="navigation-item">
|
<div className="navigation-item">
|
||||||
<i className="icon icon-me-profile"></i>
|
<i className="icon icon-me-profile" onClick={() => openProfile()}></i>
|
||||||
</div>
|
</div>
|
||||||
<div className="navigation-item">
|
<div className="navigation-item">
|
||||||
<i className="icon icon-me-rooms"></i>
|
<i className="icon icon-me-rooms"></i>
|
||||||
|
50
src/views/user-profile/UserProfileVew.scss
Normal file
50
src/views/user-profile/UserProfileVew.scss
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
.user-profile {
|
||||||
|
.content-area {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-container
|
||||||
|
{
|
||||||
|
border-right: 1px solid gray;
|
||||||
|
|
||||||
|
.avatar-image {
|
||||||
|
left: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-friend {
|
||||||
|
margin: 5px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-container
|
||||||
|
{
|
||||||
|
min-height: 50px;
|
||||||
|
background: rgba(0, 0, 0, .1);
|
||||||
|
border-radius: 5px;
|
||||||
|
margin: 0px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rooms-button-container
|
||||||
|
{
|
||||||
|
border-top: 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
|
||||||
|
{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@import './views/relationships-container/RelationshipsContainerView';
|
95
src/views/user-profile/UserProfileView.tsx
Normal file
95
src/views/user-profile/UserProfileView.tsx
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, UserCurrentBadgesComposer, UserCurrentBadgesEvent, UserProfileEvent, UserProfileParser, UserRelationshipsComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import { CreateMessageHook, SendMessageHook } from '../../hooks';
|
||||||
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
|
||||||
|
import { LocalizeText } from '../../utils';
|
||||||
|
import { BadgesContainerView } from './views/badges-container/BadgesContainerView';
|
||||||
|
import { FriendsContainerView } from './views/friends-container/FriendsContainerView';
|
||||||
|
import { UserContainerView } from './views/user-container/UserContainerView';
|
||||||
|
|
||||||
|
export const UserProfileView: FC = props =>
|
||||||
|
{
|
||||||
|
const [userProfile, setUserProfile] = useState<UserProfileParser>(null);
|
||||||
|
const [userBadges, setUserBadges] = useState<string[]>([]);
|
||||||
|
const [userRelationships, setUserRelationships] = useState<RelationshipStatusInfoMessageParser>(null);
|
||||||
|
|
||||||
|
const OnClose = useCallback(() =>
|
||||||
|
{
|
||||||
|
setUserProfile(null);
|
||||||
|
setUserBadges([]);
|
||||||
|
setUserRelationships(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const OnUserCurrentBadgesEvent = useCallback((event: UserCurrentBadgesEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if (userProfile && parser.userId === userProfile.id)
|
||||||
|
setUserBadges(parser.badges);
|
||||||
|
}, [userProfile, setUserBadges]);
|
||||||
|
|
||||||
|
CreateMessageHook(UserCurrentBadgesEvent, OnUserCurrentBadgesEvent);
|
||||||
|
|
||||||
|
const OnUserRelationshipsEvent = useCallback((event: RelationshipStatusInfoEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if (userProfile && parser.userId === userProfile.id)
|
||||||
|
setUserRelationships(parser);
|
||||||
|
}, [userProfile, setUserRelationships]);
|
||||||
|
|
||||||
|
CreateMessageHook(RelationshipStatusInfoEvent, OnUserRelationshipsEvent);
|
||||||
|
|
||||||
|
const OnUserProfileEvent = useCallback((event: UserProfileEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(userProfile && userProfile.id !== parser.id)
|
||||||
|
{
|
||||||
|
setUserBadges([]);
|
||||||
|
setUserRelationships(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
setUserProfile(parser);
|
||||||
|
SendMessageHook(new UserCurrentBadgesComposer(parser.id));
|
||||||
|
SendMessageHook(new UserRelationshipsComposer(parser.id));
|
||||||
|
}, [userProfile]);
|
||||||
|
|
||||||
|
CreateMessageHook(UserProfileEvent, OnUserProfileEvent);
|
||||||
|
|
||||||
|
if (!userProfile) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="user-profile">
|
||||||
|
<NitroCardView>
|
||||||
|
<NitroCardHeaderView headerText={LocalizeText('extendedprofile.caption')} onCloseClick={OnClose} />
|
||||||
|
<NitroCardContentView>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-sm-6 user-container">
|
||||||
|
<UserContainerView id={userProfile.id} username={userProfile.username} motto={userProfile.motto} figure={userProfile.figure} secondsSinceLastLogin={userProfile.secondsSinceLastVisit} creation={userProfile.registration} achievementScore={userProfile.achievementPoints} isFriend={userProfile.isMyFriend} isOnline={userProfile.isOnline} requestSent={userProfile.requestSent} />
|
||||||
|
<BadgesContainerView badges={userBadges} />
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-6">
|
||||||
|
{
|
||||||
|
userRelationships && <FriendsContainerView relationships={userRelationships} friendsCount={userProfile.friendsCount} />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="row rooms-button-container align-items-center">
|
||||||
|
<div className="col-sm-12 d-flex align-content-center w-100">
|
||||||
|
<i className="icon icon-rooms" /><span className="rooms-button">{LocalizeText('extendedprofile.rooms')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-sm-4">
|
||||||
|
groups list goes here
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-8">
|
||||||
|
group info goes here
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
|
||||||
|
import { BadgesContainerViewProps } from './BadgesContainerView.types';
|
||||||
|
|
||||||
|
export const BadgesContainerView: FC<BadgesContainerViewProps> = props =>
|
||||||
|
{
|
||||||
|
const {badges = null} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="row badge-container d-flex">
|
||||||
|
<div className="nitro-card-grid theme-default">
|
||||||
|
<div className="row row-cols-5 align-content-start">
|
||||||
|
{
|
||||||
|
badges.map( (badge, index) => {
|
||||||
|
return (
|
||||||
|
<div className="grid-item-container" key={index}>
|
||||||
|
<BadgeImageView badgeCode={badge}/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
export interface BadgesContainerViewProps {
|
||||||
|
badges: string[];
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { LocalizeText } from '../../../../utils';
|
||||||
|
import { RelationshipsContainerView } from '../relationships-container/RelationshipsContainerView';
|
||||||
|
import { FriendsContainerViewProps } from './FriendsContainerView.types';
|
||||||
|
|
||||||
|
export const FriendsContainerView: FC<FriendsContainerViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { relationships = null, friendsCount = null } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="friends-container h-100">
|
||||||
|
<div className="mb-1" dangerouslySetInnerHTML={{ __html: LocalizeText('extendedprofile.friends.count', ['count'], [friendsCount.toString()]) }} />
|
||||||
|
<div className="mb-1"><b>{LocalizeText('extendedprofile.relstatus')}</b></div>
|
||||||
|
<RelationshipsContainerView relationships={relationships} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
import { RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export interface FriendsContainerViewProps {
|
||||||
|
relationships: RelationshipStatusInfoMessageParser;
|
||||||
|
friendsCount: number;
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
.relationships-container {
|
||||||
|
|
||||||
|
.relationship-container {
|
||||||
|
//margin-bottom: 10px;
|
||||||
|
|
||||||
|
.relationship
|
||||||
|
{
|
||||||
|
margin-left: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
&.advanced {
|
||||||
|
background-color: white;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relationship-text {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-image {
|
||||||
|
position: absolute;
|
||||||
|
width: 50px;
|
||||||
|
height: 80px;
|
||||||
|
right: 0;
|
||||||
|
margin-top: -60px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.others-text {
|
||||||
|
margin-left: 20px;
|
||||||
|
height: 21px;
|
||||||
|
color: #939392;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
import { RelationshipStatusEnum, RelationshipStatusInfo, UserProfileComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback } from 'react';
|
||||||
|
import { SendMessageHook } from '../../../../hooks';
|
||||||
|
import { LocalizeText } from '../../../../utils';
|
||||||
|
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
|
||||||
|
import { RelationshipsContainerViewProps } from './RelationshipsContainerView.types';
|
||||||
|
|
||||||
|
export const RelationshipsContainerView: FC<RelationshipsContainerViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { relationships = null, simple = false } = props;
|
||||||
|
|
||||||
|
const OnUserClick = useCallback((user: RelationshipStatusInfo) =>
|
||||||
|
{
|
||||||
|
if (user)
|
||||||
|
SendMessageHook(new UserProfileComposer(user.randomFriendId));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const RelationshipComponent = useCallback(({ type }) =>
|
||||||
|
{
|
||||||
|
const relationshipInfo = (relationships && relationships.relationshipStatusMap.hasKey(type)) ? relationships.relationshipStatusMap.getValue(type) : null;
|
||||||
|
|
||||||
|
if (simple && !relationshipInfo) return null;
|
||||||
|
|
||||||
|
const relationshipName = RelationshipStatusEnum.RELATIONSHIP_NAMES[type].toLocaleLowerCase();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relationship-container row row-cols-2 d-flex align-items-center">
|
||||||
|
<i className={`icon icon-relationship-${relationshipName} col-2`} />
|
||||||
|
<span className={'relationship col-10' + (!simple ? ' advanced' : '')}>
|
||||||
|
<span className="cursor-pointer relationship-text" onClick={() => OnUserClick(relationshipInfo)}>
|
||||||
|
{
|
||||||
|
(relationshipInfo && relationshipInfo.friendCount > 0) ? relationshipInfo.randomFriendName : LocalizeText('extendedprofile.add.friends')
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
{
|
||||||
|
(simple && relationshipInfo && relationshipInfo.friendCount > 1) &&
|
||||||
|
<span>
|
||||||
|
{' ' + LocalizeText(`extendedprofile.relstatus.others.${relationshipName}`, ['count'], [(relationshipInfo.friendCount - 1).toString()])}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
(!simple && relationshipInfo && relationshipInfo.friendCount > 0) &&
|
||||||
|
<AvatarImageView figure={relationshipInfo.randomFriendFigure} headOnly={true} direction={4} />
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{
|
||||||
|
!simple && <div className="others-text">
|
||||||
|
{
|
||||||
|
(relationshipInfo && relationshipInfo.friendCount > 1) ? LocalizeText(`extendedprofile.relstatus.others.${relationshipName}`, ['count'], [(relationshipInfo.friendCount - 1).toString()]) : ''
|
||||||
|
}
|
||||||
|
{
|
||||||
|
(relationshipInfo && relationshipInfo.friendCount < 1) ? LocalizeText('extendedprofile.no.friends.in.this.category') : ''
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, [OnUserClick, relationships, simple]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="row justify-content-center relationships-container align-items-center flex-fill">
|
||||||
|
<RelationshipComponent type={RelationshipStatusEnum.HEART} />
|
||||||
|
<RelationshipComponent type={RelationshipStatusEnum.SMILE} />
|
||||||
|
<RelationshipComponent type={RelationshipStatusEnum.BOBBA} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export interface RelationshipsContainerViewProps
|
||||||
|
{
|
||||||
|
relationships: RelationshipStatusInfoMessageParser;
|
||||||
|
simple?: boolean;
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
import { FriendlyTime } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback } from 'react';
|
||||||
|
import { GetSessionDataManager } from '../../../../api';
|
||||||
|
import { LocalizeText } from '../../../../utils';
|
||||||
|
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
|
||||||
|
import { UserContainerViewProps } from './UserContainerView.types';
|
||||||
|
|
||||||
|
export const UserContainerView: FC<UserContainerViewProps> = props =>
|
||||||
|
{
|
||||||
|
const {figure = null, username = null, motto = null, creation = null, secondsSinceLastLogin = null, achievementScore, isFriend = null, isOnline = null, id = null, requestSent = null} = props;
|
||||||
|
|
||||||
|
const OnlineIcon = useCallback(() => {
|
||||||
|
if(isOnline) return (<i className="icon icon-pf-online" />);
|
||||||
|
else return (<i className="icon icon-pf-offline" />);
|
||||||
|
}, [isOnline]);
|
||||||
|
|
||||||
|
const FriendRequestComponent = useCallback(() => {
|
||||||
|
if(id === GetSessionDataManager().userId) return (<span><i className="icon icon-pf-tick" />{LocalizeText('extendedprofile.me')}</span> );
|
||||||
|
|
||||||
|
if(isFriend) return (<span><i className="icon icon-pf-tick" />{LocalizeText('extendedprofile.friend')}</span>);
|
||||||
|
|
||||||
|
if(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>)
|
||||||
|
}, [id, isFriend, requestSent]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-sm-4">
|
||||||
|
<AvatarImageView figure={figure} direction={2} />
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-8">
|
||||||
|
<div className="user-info-container">
|
||||||
|
<h5>{username}</h5>
|
||||||
|
<div className="mb-1">{motto}</div>
|
||||||
|
<div className="mb-1" dangerouslySetInnerHTML={{ __html: LocalizeText('extendedprofile.created', ['created'], [creation]) }} />
|
||||||
|
<div className="mb-1" dangerouslySetInnerHTML={{ __html: LocalizeText('extendedprofile.last.login', ['lastlogin'], [FriendlyTime.format(secondsSinceLastLogin, '.ago', 2)]) }} />
|
||||||
|
<div className="mb-1"><b>{LocalizeText('extendedprofile.achievementscore')}</b> {achievementScore}</div>
|
||||||
|
<OnlineIcon />
|
||||||
|
<FriendRequestComponent />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
export interface UserContainerViewProps {
|
||||||
|
id: number;
|
||||||
|
username: string;
|
||||||
|
figure: string;
|
||||||
|
motto: string;
|
||||||
|
creation: string;
|
||||||
|
secondsSinceLastLogin: number;
|
||||||
|
achievementScore: number;
|
||||||
|
isFriend: boolean;
|
||||||
|
requestSent: boolean;
|
||||||
|
isOnline: boolean;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user