mirror of
https://github.com/billsonnn/nitro-react.git
synced 2025-01-31 18:32:36 +01:00
Merge branch 'dev' of https://github.com/billsonnn/nitro-react into dev
This commit is contained in:
commit
f73284147c
7
src/api/groups/GetGroupInformation.ts
Normal file
7
src/api/groups/GetGroupInformation.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { GroupInformationComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { SendMessageHook } from '../../hooks';
|
||||||
|
|
||||||
|
export function GetGroupInformation(groupId: number): void
|
||||||
|
{
|
||||||
|
SendMessageHook(new GroupInformationComposer(groupId, true));
|
||||||
|
}
|
1
src/api/groups/index.ts
Normal file
1
src/api/groups/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './GetGroupInformation';
|
@ -1,4 +1,5 @@
|
|||||||
export * from './core';
|
export * from './core';
|
||||||
|
export * from './groups';
|
||||||
export * from './navigator';
|
export * from './navigator';
|
||||||
export * from './nitro';
|
export * from './nitro';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
src: url('../webfonts/Ubuntu.ttf');
|
src: url('../webfonts/Ubuntu.ttf');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: GameUbuntu;
|
||||||
|
src: url('../webfonts/Ubuntu-C.ttf');
|
||||||
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: UbuntuItalics;
|
font-family: UbuntuItalics;
|
||||||
src: url('../webfonts/Ubuntu-i.ttf');
|
src: url('../webfonts/Ubuntu-i.ttf');
|
||||||
|
@ -521,7 +521,7 @@
|
|||||||
|
|
||||||
&.icon-pf-offline {
|
&.icon-pf-offline {
|
||||||
background: url('../images/profile/icons/offline.png');
|
background: url('../images/profile/icons/offline.png');
|
||||||
width: 40px;
|
width: 39px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
src/assets/webfonts/Ubuntu-C.ttf
Normal file
BIN
src/assets/webfonts/Ubuntu-C.ttf
Normal file
Binary file not shown.
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
font-family: 'Ubuntu Condensed', sans-serif;
|
font-family: GameUbuntu, sans-serif;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -12,8 +12,6 @@ body {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
image-rendering: pixelated;
|
image-rendering: pixelated;
|
||||||
image-rendering: -moz-crisp-edges;
|
image-rendering: -moz-crisp-edges;
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@import './App';
|
@import './App';
|
||||||
|
@ -1 +1,3 @@
|
|||||||
@import './views/GroupinformationView';
|
@import './views/information/GroupInformationView';
|
||||||
|
@import './views/information-standalone/GroupInformationStandaloneView';
|
||||||
|
@import './views/room-information/GroupRoomInformationView';
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
|
import { GroupInformationBoxView } from './views/information-standalone/GroupInformationStandaloneView';
|
||||||
|
|
||||||
export const GroupsView: FC<{}> = props =>
|
export const GroupsView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
return null;
|
return (
|
||||||
|
<>
|
||||||
|
<GroupInformationBoxView />
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
import { GroupInformationComposer, GroupInformationEvent, GroupInformationParser } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
|
||||||
import { LocalizeText } from '../../../api';
|
|
||||||
import { CreateMessageHook, SendMessageHook } from '../../../hooks';
|
|
||||||
import { BadgeImageView } from '../../shared/badge-image/BadgeImageView';
|
|
||||||
import { GroupMembershipType } from '../common/GroupMembershipType';
|
|
||||||
import { GroupType } from '../common/GroupType';
|
|
||||||
import { GroupInformationViewProps } from './GroupInformationView.types';
|
|
||||||
|
|
||||||
export const GroupInformationView: FC<GroupInformationViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { group = null } = props;
|
|
||||||
|
|
||||||
const [ groupInformation, setGroupInformation ] = useState<GroupInformationParser>(null);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
setGroupInformation(null);
|
|
||||||
if(group) SendMessageHook(new GroupInformationComposer(group.id, true));
|
|
||||||
}, [ group ]);
|
|
||||||
|
|
||||||
const onGroupInformationEvent = useCallback((event: GroupInformationEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
setGroupInformation(parser);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
CreateMessageHook(GroupInformationEvent, onGroupInformationEvent);
|
|
||||||
|
|
||||||
if(!groupInformation) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="group-information p-2">
|
|
||||||
<div>
|
|
||||||
<div className="group-badge text-center">
|
|
||||||
<BadgeImageView badgeCode={ group.badge } isGroup={ true } />
|
|
||||||
<div className="mt-3">
|
|
||||||
<a href="#" className="small text-black">
|
|
||||||
{ LocalizeText('group.membercount', ['totalMembers'], [groupInformation.membersCount.toString()]) }
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{ groupInformation.pendingRequestsCount > 0 && <a href="#" className="small text-black">
|
|
||||||
{ LocalizeText('group.pendingmembercount', ['totalMembers'], [groupInformation.pendingRequestsCount.toString()]) }
|
|
||||||
</a> }
|
|
||||||
</div>
|
|
||||||
<div className="mt-3">
|
|
||||||
{ groupInformation.membershipType === GroupMembershipType.MEMBER && !groupInformation.isAdmin && <i className="icon icon-group-member" title={ LocalizeText('group.youaremember') } /> }
|
|
||||||
{ groupInformation.isAdmin && !groupInformation.isOwner && <i className="icon icon-group-admin" title={ LocalizeText('group.youareadmin') } /> }
|
|
||||||
{ groupInformation.isOwner && <i className="icon icon-group-owner" title={ LocalizeText('group.youareowner') } /> }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="ms-2 w-100">
|
|
||||||
<div className="fw-bold d-flex align-items-center">
|
|
||||||
<i className={ 'icon icon-group-type-' + groupInformation.type } />
|
|
||||||
{ groupInformation.canMembersDecorate && <i className="icon icon-group-decorate ms-1" /> }
|
|
||||||
<div className="ms-1">{ group.title }</div>
|
|
||||||
</div>
|
|
||||||
<div>{ LocalizeText('group.created', ['date', 'owner'], [groupInformation.createdAt, groupInformation.ownerName]) }</div>
|
|
||||||
<div className="group-description small overflow-auto">{ groupInformation.description }</div>
|
|
||||||
<div>
|
|
||||||
<a href="#" className="small text-black">
|
|
||||||
{ LocalizeText('group.linktobase') }
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a href="#" className="small text-black">
|
|
||||||
{ LocalizeText('group.buyfurni') }
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a href="#" className="small text-black">
|
|
||||||
{ LocalizeText('group.showgroups') }
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{ groupInformation.type !== GroupType.PRIVATE &&
|
|
||||||
<button className="btn btn-primary w-100 mt-2" disabled={ groupInformation.membershipType === GroupMembershipType.REQUEST_PENDING }>
|
|
||||||
{ groupInformation.membershipType === GroupMembershipType.MEMBER && LocalizeText('group.leave') }
|
|
||||||
{ groupInformation.membershipType === GroupMembershipType.NOT_MEMBER && groupInformation.type === GroupType.REGULAR && LocalizeText('group.join') }
|
|
||||||
{ groupInformation.type === GroupType.EXCLUSIVE && <>
|
|
||||||
{ groupInformation.membershipType === GroupMembershipType.NOT_MEMBER && LocalizeText('group.requestmembership') }
|
|
||||||
{ groupInformation.membershipType === GroupMembershipType.REQUEST_PENDING && LocalizeText('group.membershippending') }
|
|
||||||
</> }
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,6 +0,0 @@
|
|||||||
import { GroupDataParser } from '@nitrots/nitro-renderer';
|
|
||||||
|
|
||||||
export interface GroupInformationViewProps
|
|
||||||
{
|
|
||||||
group: GroupDataParser;
|
|
||||||
}
|
|
@ -0,0 +1,3 @@
|
|||||||
|
.nitro-group-information-standalone {
|
||||||
|
width: 500px;
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
import { GroupInformationEvent, GroupInformationParser } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import { LocalizeText } from '../../../../api';
|
||||||
|
import { CreateMessageHook } from '../../../../hooks';
|
||||||
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
|
||||||
|
import { GroupInformationView } from '../information/GroupInformationView';
|
||||||
|
|
||||||
|
export const GroupInformationBoxView: FC<{}> = props =>
|
||||||
|
{
|
||||||
|
const [ groupInformation, setGroupInformation ] = useState<GroupInformationParser>(null);
|
||||||
|
|
||||||
|
const onGroupInformationEvent = useCallback((event: GroupInformationEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(!parser.flag) return;
|
||||||
|
|
||||||
|
if(groupInformation) setGroupInformation(null);
|
||||||
|
|
||||||
|
setGroupInformation(parser);
|
||||||
|
}, [ groupInformation ]);
|
||||||
|
|
||||||
|
CreateMessageHook(GroupInformationEvent, onGroupInformationEvent);
|
||||||
|
|
||||||
|
if(!groupInformation) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardView className="nitro-group-information-standalone" simple={ true }>
|
||||||
|
<NitroCardHeaderView headerText={ LocalizeText('group.window.title') } onCloseClick={ () => setGroupInformation(null) } />
|
||||||
|
<NitroCardContentView className="pb-2">
|
||||||
|
<GroupInformationView groupInformation={ groupInformation } onClose={ () => setGroupInformation(null) } />
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
);
|
||||||
|
};
|
153
src/views/groups/views/information/GroupInformationView.tsx
Normal file
153
src/views/groups/views/information/GroupInformationView.tsx
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
import { GroupDeleteComposer, GroupInformationComposer, GroupJoinComposer, GroupRemoveMemberComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback } from 'react';
|
||||||
|
import { CreateLinkEvent, GetSessionDataManager, LocalizeText, TryVisitRoom } from '../../../../api';
|
||||||
|
import { SendMessageHook } from '../../../../hooks';
|
||||||
|
import { CatalogPageName } from '../../../catalog/common/CatalogPageName';
|
||||||
|
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
|
||||||
|
import { GroupMembershipType } from '../../common/GroupMembershipType';
|
||||||
|
import { GroupType } from '../../common/GroupType';
|
||||||
|
import { GroupInformationViewProps } from './GroupInformationView.types';
|
||||||
|
|
||||||
|
export const GroupInformationView: FC<GroupInformationViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { groupInformation = null, onClose = null } = props;
|
||||||
|
|
||||||
|
const tryJoinGroup = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(!groupInformation) return;
|
||||||
|
|
||||||
|
SendMessageHook(new GroupJoinComposer(groupInformation.id));
|
||||||
|
SendMessageHook(new GroupInformationComposer(groupInformation.id, false));
|
||||||
|
}, [ groupInformation ]);
|
||||||
|
|
||||||
|
const tryLeaveGroup = useCallback(() =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId));
|
||||||
|
SendMessageHook(new GroupInformationComposer(groupInformation.id, false));
|
||||||
|
if(onClose) onClose();
|
||||||
|
}, [ groupInformation, onClose ]);
|
||||||
|
|
||||||
|
const isRealOwner = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(!groupInformation) return false;
|
||||||
|
|
||||||
|
return (groupInformation.ownerName === GetSessionDataManager().userName);
|
||||||
|
}, [ groupInformation ]);
|
||||||
|
|
||||||
|
const getRoleIcon = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.NOT_MEMBER || groupInformation.membershipType === GroupMembershipType.REQUEST_PENDING) return null;
|
||||||
|
|
||||||
|
if(isRealOwner()) return <i className="icon icon-group-owner" title={ LocalizeText('group.youareowner') } />;
|
||||||
|
|
||||||
|
if(groupInformation.isAdmin) return <i className="icon icon-group-admin" title={ LocalizeText('group.youareadmin') } />;
|
||||||
|
|
||||||
|
return <i className="icon icon-group-member" title={ LocalizeText('group.youaremember') } />;
|
||||||
|
}, [ groupInformation, isRealOwner ]);
|
||||||
|
|
||||||
|
const getButtonText = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(groupInformation.type === GroupType.PRIVATE) return '';
|
||||||
|
|
||||||
|
if(isRealOwner()) return 'group.youareowner';
|
||||||
|
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.MEMBER) return 'group.leave';
|
||||||
|
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.NOT_MEMBER && groupInformation.type === GroupType.REGULAR) return 'group.join';
|
||||||
|
|
||||||
|
if(groupInformation.type === GroupType.EXCLUSIVE)
|
||||||
|
{
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.NOT_MEMBER) return 'group.requestmembership';
|
||||||
|
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.REQUEST_PENDING) return 'group.membershippending';
|
||||||
|
}
|
||||||
|
}, [ groupInformation, isRealOwner ]);
|
||||||
|
|
||||||
|
const handleButtonClick = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(groupInformation.type === GroupType.PRIVATE && groupInformation.membershipType === GroupMembershipType.NOT_MEMBER) return;
|
||||||
|
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.MEMBER) return tryLeaveGroup();
|
||||||
|
|
||||||
|
return tryJoinGroup();
|
||||||
|
}, [ groupInformation, tryLeaveGroup, tryJoinGroup ]);
|
||||||
|
|
||||||
|
const handleAction = useCallback((action: string) =>
|
||||||
|
{
|
||||||
|
switch(action)
|
||||||
|
{
|
||||||
|
case 'homeroom':
|
||||||
|
TryVisitRoom(groupInformation.roomId);
|
||||||
|
break;
|
||||||
|
case 'furniture':
|
||||||
|
CreateLinkEvent('catalog/open/' + CatalogPageName.GUILD_CUSTOM_FURNI);
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
if(window.confirm(LocalizeText('group.deleteconfirm.title') + ' - ' + LocalizeText('group.deleteconfirm.desc')))
|
||||||
|
{
|
||||||
|
SendMessageHook(new GroupDeleteComposer(groupInformation.id));
|
||||||
|
if(onClose) onClose();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}, [ groupInformation, onClose ]);
|
||||||
|
|
||||||
|
if(!groupInformation) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="group-information text-black p-2">
|
||||||
|
<div>
|
||||||
|
<div className="group-badge text-center">
|
||||||
|
<BadgeImageView badgeCode={ groupInformation.badge } isGroup={ true } />
|
||||||
|
<div className="mt-3">
|
||||||
|
<a href="#" className="small text-black">
|
||||||
|
{ LocalizeText('group.membercount', ['totalMembers'], [groupInformation.membersCount.toString()]) }
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{ groupInformation.pendingRequestsCount > 0 && <a href="#" className="small text-black">
|
||||||
|
{ LocalizeText('group.pendingmembercount', ['totalMembers'], [groupInformation.pendingRequestsCount.toString()]) }
|
||||||
|
</a> }
|
||||||
|
</div>
|
||||||
|
<div className="mt-3">
|
||||||
|
{ getRoleIcon() }
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{ groupInformation.isOwner && <a href="#" className="small text-danger" onClick={ () => handleAction('delete') }>
|
||||||
|
{ LocalizeText('group.delete') }
|
||||||
|
</a> }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="ms-2 w-100">
|
||||||
|
<div className="fw-bold d-flex align-items-center">
|
||||||
|
<i className={ 'icon icon-group-type-' + groupInformation.type } />
|
||||||
|
{ groupInformation.canMembersDecorate && <i className="icon icon-group-decorate ms-1" /> }
|
||||||
|
<div className="ms-1">{ groupInformation.title }</div>
|
||||||
|
</div>
|
||||||
|
<div>{ LocalizeText('group.created', ['date', 'owner'], [groupInformation.createdAt, groupInformation.ownerName]) }</div>
|
||||||
|
<div className="group-description small overflow-auto">{ groupInformation.description }</div>
|
||||||
|
<div>
|
||||||
|
<a href="#" className="small text-black" onClick={ () => handleAction('homeroom') }>
|
||||||
|
{ LocalizeText('group.linktobase') }
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="#" className="small text-black" onClick={ () => handleAction('furniture') }>
|
||||||
|
{ LocalizeText('group.buyfurni') }
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="#" className="small text-black">
|
||||||
|
{ LocalizeText('group.showgroups') }
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{ groupInformation.type !== GroupType.PRIVATE &&
|
||||||
|
<button className="btn btn-primary w-100 mt-2" disabled={ groupInformation.membershipType === GroupMembershipType.REQUEST_PENDING || isRealOwner() } onClick={ handleButtonClick }>
|
||||||
|
{ LocalizeText(getButtonText()) }
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,7 @@
|
|||||||
|
import { GroupInformationParser } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export interface GroupInformationViewProps
|
||||||
|
{
|
||||||
|
groupInformation: GroupInformationParser;
|
||||||
|
onClose?: () => void;
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
.nitro-group-room-information {
|
||||||
|
pointer-events: all;
|
||||||
|
padding: 2px;
|
||||||
|
background-color: $gable-green;
|
||||||
|
border: 2px solid rgba($white, 0.5);
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
.group-badge {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
import { DesktopViewEvent, GroupInformationComposer, GroupInformationEvent, GroupInformationParser, GroupJoinComposer, GroupRemoveMemberComposer, RoomInfoEvent } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import { GetGroupInformation, GetSessionDataManager, LocalizeText } from '../../../../api';
|
||||||
|
import { CreateMessageHook, SendMessageHook } from '../../../../hooks';
|
||||||
|
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
|
||||||
|
import { GroupMembershipType } from '../../common/GroupMembershipType';
|
||||||
|
import { GroupType } from '../../common/GroupType';
|
||||||
|
|
||||||
|
export const GroupRoomInformationView: FC<{}> = props =>
|
||||||
|
{
|
||||||
|
const [ groupId, setGroupId ] = useState<number>(null);
|
||||||
|
const [ groupInformation, setGroupInformation ] = useState<GroupInformationParser>(null);
|
||||||
|
const [ isExpended, setIsExpended ] = useState<boolean>(true);
|
||||||
|
|
||||||
|
const onRoomInfoEvent = useCallback((event: RoomInfoEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
setGroupInformation(null);
|
||||||
|
|
||||||
|
if(parser.data.habboGroupId)
|
||||||
|
{
|
||||||
|
setGroupId(parser.data.habboGroupId);
|
||||||
|
SendMessageHook(new GroupInformationComposer(parser.data.habboGroupId, false));
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(RoomInfoEvent, onRoomInfoEvent);
|
||||||
|
|
||||||
|
const onGroupInformationEvent = useCallback((event: GroupInformationEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(parser.flag || groupId !== parser.id) return;
|
||||||
|
|
||||||
|
setGroupInformation(null);
|
||||||
|
setGroupInformation(parser);
|
||||||
|
}, [ groupId ]);
|
||||||
|
|
||||||
|
CreateMessageHook(GroupInformationEvent, onGroupInformationEvent);
|
||||||
|
|
||||||
|
const onDesktopViewEvent = useCallback((event: DesktopViewEvent) =>
|
||||||
|
{
|
||||||
|
setGroupId(0);
|
||||||
|
setGroupInformation(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(DesktopViewEvent, onDesktopViewEvent);
|
||||||
|
|
||||||
|
const isRealOwner = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(!groupInformation) return false;
|
||||||
|
|
||||||
|
return (groupInformation.ownerName === GetSessionDataManager().userName);
|
||||||
|
}, [ groupInformation ]);
|
||||||
|
|
||||||
|
const tryJoinGroup = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(!groupInformation) return;
|
||||||
|
|
||||||
|
SendMessageHook(new GroupJoinComposer(groupInformation.id));
|
||||||
|
SendMessageHook(new GroupInformationComposer(groupInformation.id, false));
|
||||||
|
}, [ groupInformation ]);
|
||||||
|
|
||||||
|
const tryLeaveGroup = useCallback(() =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId));
|
||||||
|
SendMessageHook(new GroupInformationComposer(groupInformation.id, false));
|
||||||
|
}, [ groupInformation ]);
|
||||||
|
|
||||||
|
const getButtonText = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(groupInformation.type === GroupType.PRIVATE) return '';
|
||||||
|
|
||||||
|
if(isRealOwner()) return 'group.youareowner';
|
||||||
|
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.MEMBER) return 'group.leave';
|
||||||
|
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.NOT_MEMBER && groupInformation.type === GroupType.REGULAR) return 'group.join';
|
||||||
|
|
||||||
|
if(groupInformation.type === GroupType.EXCLUSIVE)
|
||||||
|
{
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.NOT_MEMBER) return 'group.requestmembership';
|
||||||
|
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.REQUEST_PENDING) return 'group.membershippending';
|
||||||
|
}
|
||||||
|
}, [ groupInformation, isRealOwner ]);
|
||||||
|
|
||||||
|
const handleButtonClick = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(groupInformation.type === GroupType.PRIVATE && groupInformation.membershipType === GroupMembershipType.NOT_MEMBER) return;
|
||||||
|
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.MEMBER) return tryLeaveGroup();
|
||||||
|
|
||||||
|
return tryJoinGroup();
|
||||||
|
}, [ groupInformation, tryLeaveGroup, tryJoinGroup ]);
|
||||||
|
|
||||||
|
if(!groupInformation) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="nitro-group-room-information rounded py-1 px-2">
|
||||||
|
<div className="d-flex justify-content-between align-items-center cursor-pointer" onClick={ () => setIsExpended(value => !value) }>
|
||||||
|
<div>{ LocalizeText('group.homeroominfo.title') }</div>
|
||||||
|
<i className={ 'fas fa-chevron-' + (isExpended ? 'up' : 'down') } />
|
||||||
|
</div>
|
||||||
|
{ isExpended && <>
|
||||||
|
<div className="d-flex cursor-pointer" onClick={ () => GetGroupInformation(groupInformation.id) }>
|
||||||
|
<div className="group-badge flex-shrink-0 me-1">
|
||||||
|
<BadgeImageView badgeCode={ groupInformation.badge } isGroup={ true } />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{ groupInformation.title }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{ groupInformation.type !== GroupType.PRIVATE && !isRealOwner() &&
|
||||||
|
<button className="btn btn-sm btn-primary w-100 mt-1" disabled={ groupInformation.membershipType === GroupMembershipType.REQUEST_PENDING || isRealOwner() } onClick={ handleButtonClick }>
|
||||||
|
{ LocalizeText(getButtonText()) }
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</> }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -6,6 +6,7 @@ import { AchievementsView } from '../achievements/AchievementsView';
|
|||||||
import { AvatarEditorView } from '../avatar-editor/AvatarEditorView';
|
import { AvatarEditorView } from '../avatar-editor/AvatarEditorView';
|
||||||
import { CatalogView } from '../catalog/CatalogView';
|
import { CatalogView } from '../catalog/CatalogView';
|
||||||
import { FriendListView } from '../friend-list/FriendListView';
|
import { FriendListView } from '../friend-list/FriendListView';
|
||||||
|
import { GroupsView } from '../groups/GroupsView';
|
||||||
import { HotelView } from '../hotel-view/HotelView';
|
import { HotelView } from '../hotel-view/HotelView';
|
||||||
import { InventoryView } from '../inventory/InventoryView';
|
import { InventoryView } from '../inventory/InventoryView';
|
||||||
import { ModToolsView } from '../mod-tools/ModToolsView';
|
import { ModToolsView } from '../mod-tools/ModToolsView';
|
||||||
@ -62,6 +63,7 @@ export const MainView: FC<MainViewProps> = props =>
|
|||||||
<RightSideView />
|
<RightSideView />
|
||||||
<UserSettingsView />
|
<UserSettingsView />
|
||||||
<UserProfileView />
|
<UserProfileView />
|
||||||
|
<GroupsView />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.nitro-room-info {
|
.nitro-room-info {
|
||||||
width: 230px;
|
width: 250px;
|
||||||
|
|
||||||
.gray {
|
.gray {
|
||||||
filter: grayscale(1);
|
filter: grayscale(1);
|
||||||
@ -17,4 +17,9 @@
|
|||||||
background-color: rgba($black, .125);
|
background-color: rgba($black, .125);
|
||||||
border-color: $black !important;
|
border-color: $black !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.group-badge {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { RoomMuteComposer, RoomSettingsComposer, RoomStaffPickComposer, UserHomeRoomComposer } from '@nitrots/nitro-renderer';
|
import { RoomMuteComposer, RoomSettingsComposer, RoomStaffPickComposer, SecurityLevel, UserHomeRoomComposer } from '@nitrots/nitro-renderer';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { GetConfiguration, LocalizeText } from '../../../../api';
|
import { GetConfiguration, GetSessionDataManager, LocalizeText } from '../../../../api';
|
||||||
import { NavigatorEvent } from '../../../../events';
|
import { NavigatorEvent } from '../../../../events';
|
||||||
import { RoomWidgetThumbnailEvent } from '../../../../events/room-widgets/thumbnail';
|
import { RoomWidgetThumbnailEvent } from '../../../../events/room-widgets/thumbnail';
|
||||||
import { dispatchUiEvent } from '../../../../hooks/events';
|
import { dispatchUiEvent } from '../../../../hooks/events';
|
||||||
@ -43,6 +43,16 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
|
|||||||
setIsRoomMuted(roomInfoData.enteredGuestRoom.allInRoomMuted);
|
setIsRoomMuted(roomInfoData.enteredGuestRoom.allInRoomMuted);
|
||||||
}, [ roomInfoData ]);
|
}, [ roomInfoData ]);
|
||||||
|
|
||||||
|
const hasPermission = useCallback((permission: string) =>
|
||||||
|
{
|
||||||
|
switch(permission)
|
||||||
|
{
|
||||||
|
case 'settings': return GetSessionDataManager().securityLevel >= SecurityLevel.MODERATOR || roomInfoData.currentRoomOwner;
|
||||||
|
case 'staff_pick': return GetSessionDataManager().securityLevel >= SecurityLevel.COMMUNITY;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}, [ roomInfoData ]);
|
||||||
|
|
||||||
const processAction = useCallback((action: string, value?: string) =>
|
const processAction = useCallback((action: string, value?: string) =>
|
||||||
{
|
{
|
||||||
if(!roomInfoData || !roomInfoData.enteredGuestRoom) return;
|
if(!roomInfoData || !roomInfoData.enteredGuestRoom) return;
|
||||||
@ -131,10 +141,10 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
|
|||||||
{ roomThumbnail && <img alt="" src={ roomThumbnail } /> }
|
{ roomThumbnail && <img alt="" src={ roomThumbnail } /> }
|
||||||
</div>
|
</div>
|
||||||
{ roomInfoData.enteredGuestRoom.habboGroupId > 0 && <div className="d-flex align-items-center mb-2 cursor-pointer" onClick={ () => processAction('open_group_info') }>
|
{ roomInfoData.enteredGuestRoom.habboGroupId > 0 && <div className="d-flex align-items-center mb-2 cursor-pointer" onClick={ () => processAction('open_group_info') }>
|
||||||
<div className="me-2">
|
<div className="group-badge flex-shrink-0 me-1">
|
||||||
<BadgeImageView badgeCode={ roomInfoData.enteredGuestRoom.groupBadgeCode } isGroup={ true } />
|
<BadgeImageView badgeCode={ roomInfoData.enteredGuestRoom.groupBadgeCode } isGroup={ true } />
|
||||||
</div>
|
</div>
|
||||||
<div className="text-decoration-underline">
|
<div className="text-decoration-underline small">
|
||||||
{ LocalizeText('navigator.guildbase', ['groupName'], [roomInfoData.enteredGuestRoom.groupName]) }
|
{ LocalizeText('navigator.guildbase', ['groupName'], [roomInfoData.enteredGuestRoom.groupName]) }
|
||||||
</div>
|
</div>
|
||||||
</div> }
|
</div> }
|
||||||
@ -142,11 +152,13 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
|
|||||||
<i className="icon icon-arrows me-1" />
|
<i className="icon icon-arrows me-1" />
|
||||||
<span>{ LocalizeText('navigator.embed.caption') }</span>
|
<span>{ LocalizeText('navigator.embed.caption') }</span>
|
||||||
</div>
|
</div>
|
||||||
<button className="btn btn-sm btn-primary w-100 mb-1" onClick={ () => processAction('open_room_settings') }>{ LocalizeText('navigator.room.popup.info.room.settings') }</button>
|
{ hasPermission('settings') && <>
|
||||||
<button className="btn btn-sm btn-primary w-100 mb-1" disabled={ true }>{ LocalizeText('open.floor.plan.editor') }</button>
|
<button className="btn btn-sm btn-primary w-100 mb-1" onClick={ () => processAction('open_room_settings') }>{ LocalizeText('navigator.room.popup.info.room.settings') }</button>
|
||||||
<button className="btn btn-sm btn-primary w-100 mb-1" onClick={ () => processAction('toggle_pick') }>{ LocalizeText(isRoomPicked ? 'navigator.staffpicks.unpick' : 'navigator.staffpicks.pick') }</button>
|
<button className="btn btn-sm btn-primary w-100 mb-1" disabled={ true }>{ LocalizeText('open.floor.plan.editor') }</button>
|
||||||
|
</> }
|
||||||
|
{ hasPermission('staff_pick') && <button className="btn btn-sm btn-primary w-100 mb-1" onClick={ () => processAction('toggle_pick') }>{ LocalizeText(isRoomPicked ? 'navigator.staffpicks.unpick' : 'navigator.staffpicks.pick') }</button> }
|
||||||
<button className="btn btn-sm btn-danger w-100 mb-1" disabled={ true }>{ LocalizeText('help.emergency.main.report.room') }</button>
|
<button className="btn btn-sm btn-danger w-100 mb-1" disabled={ true }>{ LocalizeText('help.emergency.main.report.room') }</button>
|
||||||
<button className="btn btn-sm btn-primary w-100" onClick={ () => processAction('toggle_mute') }>{ LocalizeText(isRoomMuted ? 'navigator.muteall_on' : 'navigator.muteall_off') }</button>
|
{ hasPermission('settings') && <button className="btn btn-sm btn-primary w-100" onClick={ () => processAction('toggle_mute') }>{ LocalizeText(isRoomMuted ? 'navigator.muteall_on' : 'navigator.muteall_off') }</button> }
|
||||||
</> }
|
</> }
|
||||||
|
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
|
import { GroupRoomInformationView } from '../groups/views/room-information/GroupRoomInformationView';
|
||||||
import { NotificationCenterView } from '../notification-center/NotificationCenterView';
|
import { NotificationCenterView } from '../notification-center/NotificationCenterView';
|
||||||
import { PurseView } from '../purse/PurseView';
|
import { PurseView } from '../purse/PurseView';
|
||||||
import { RightSideProps } from './RightSideView.types';
|
import { RightSideProps } from './RightSideView.types';
|
||||||
@ -9,6 +10,7 @@ export const RightSideView: FC<RightSideProps> = props =>
|
|||||||
<div className="nitro-right-side">
|
<div className="nitro-right-side">
|
||||||
<div className="position-relative d-flex flex-column">
|
<div className="position-relative d-flex flex-column">
|
||||||
<PurseView />
|
<PurseView />
|
||||||
|
<GroupRoomInformationView />
|
||||||
<NotificationCenterView />
|
<NotificationCenterView />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
max-width: 350px;
|
max-width: 350px;
|
||||||
min-height: 25px;
|
min-height: 25px;
|
||||||
font-size: $font-size-sm;
|
font-size: 15px;
|
||||||
|
|
||||||
border-image-slice: 17 6 6 29 fill;
|
border-image-slice: 17 6 6 29 fill;
|
||||||
border-image-width: 17px 6px 6px 29px;
|
border-image-width: 17px 6px 6px 29px;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, UserCurrentBadgesComposer, UserCurrentBadgesEvent, UserProfileEvent, UserProfileParser, UserRelationshipsComposer } from '@nitrots/nitro-renderer';
|
import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, UserCurrentBadgesComposer, UserCurrentBadgesEvent, UserProfileComposer, UserProfileEvent, UserProfileParser, UserRelationshipsComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useState } from 'react';
|
import { FC, useCallback, useState } from 'react';
|
||||||
import { LocalizeText } from '../../api';
|
import { GetSessionDataManager, LocalizeText } from '../../api';
|
||||||
import { CreateMessageHook, SendMessageHook } from '../../hooks';
|
import { CreateMessageHook, SendMessageHook } from '../../hooks';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
|
||||||
import { BadgesContainerView } from './views/badges-container/BadgesContainerView';
|
import { BadgesContainerView } from './views/badges-container/BadgesContainerView';
|
||||||
@ -21,6 +21,11 @@ export const UserProfileView: FC = props =>
|
|||||||
setUserRelationships(null);
|
setUserRelationships(null);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const onLeaveGroup = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(userProfile && userProfile.id === GetSessionDataManager().userId) SendMessageHook(new UserProfileComposer(userProfile.id));
|
||||||
|
}, [ userProfile ]);
|
||||||
|
|
||||||
const OnUserCurrentBadgesEvent = useCallback((event: UserCurrentBadgesEvent) =>
|
const OnUserCurrentBadgesEvent = useCallback((event: UserCurrentBadgesEvent) =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
@ -45,14 +50,14 @@ export const UserProfileView: FC = props =>
|
|||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
if(userProfile && userProfile.id !== parser.id)
|
if(userProfile)
|
||||||
{
|
{
|
||||||
|
setUserProfile(null);
|
||||||
setUserBadges([]);
|
setUserBadges([]);
|
||||||
setUserRelationships(null);
|
setUserRelationships(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
setUserProfile(parser);
|
setUserProfile(parser);
|
||||||
console.log(parser);
|
|
||||||
SendMessageHook(new UserCurrentBadgesComposer(parser.id));
|
SendMessageHook(new UserCurrentBadgesComposer(parser.id));
|
||||||
SendMessageHook(new UserRelationshipsComposer(parser.id));
|
SendMessageHook(new UserRelationshipsComposer(parser.id));
|
||||||
}, [userProfile]);
|
}, [userProfile]);
|
||||||
@ -67,8 +72,8 @@ export const UserProfileView: FC = props =>
|
|||||||
<NitroCardContentView>
|
<NitroCardContentView>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-sm-7 user-container">
|
<div className="col-sm-7 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} />
|
<UserContainerView userProfile={ userProfile } />
|
||||||
<BadgesContainerView badges={userBadges} />
|
<BadgesContainerView badges={ userBadges } />
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-5">
|
<div className="col-sm-5">
|
||||||
{
|
{
|
||||||
@ -81,7 +86,7 @@ export const UserProfileView: FC = props =>
|
|||||||
<i className="icon icon-rooms" /><span className="rooms-button">{LocalizeText('extendedprofile.rooms')}</span>
|
<i className="icon icon-rooms" /><span className="rooms-button">{LocalizeText('extendedprofile.rooms')}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<GroupsContainerView groups={ userProfile.groups } />
|
<GroupsContainerView groups={ userProfile.groups } onLeaveGroup={ onLeaveGroup } />
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
</NitroCardView>
|
</NitroCardView>
|
||||||
)
|
)
|
||||||
|
@ -7,7 +7,7 @@ export const BadgesContainerView: FC<BadgesContainerViewProps> = props =>
|
|||||||
const { badges = null } = props;
|
const { badges = null } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row badge-container d-flex">
|
<div className="row badge-container d-flex mt-1">
|
||||||
<div className="nitro-card-grid theme-default">
|
<div className="nitro-card-grid theme-default">
|
||||||
<div className="row row-cols-5 align-content-start">
|
<div className="row row-cols-5 align-content-start">
|
||||||
{
|
{
|
||||||
|
@ -1,19 +1,40 @@
|
|||||||
|
import { GroupInformationComposer, GroupInformationEvent, GroupInformationParser } from '@nitrots/nitro-renderer';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { GroupInformationView } from '../../../groups/views/GroupInformationView';
|
import { CreateMessageHook, SendMessageHook } from '../../../../hooks';
|
||||||
|
import { GroupInformationView } from '../../../groups/views/information/GroupInformationView';
|
||||||
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
|
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
|
||||||
import { GroupsContainerViewProps } from './GroupsContainerView.types';
|
import { GroupsContainerViewProps } from './GroupsContainerView.types';
|
||||||
|
|
||||||
export const GroupsContainerView: FC<GroupsContainerViewProps> = props =>
|
export const GroupsContainerView: FC<GroupsContainerViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { groups = null } = props;
|
const { groups = null, onLeaveGroup = null } = props;
|
||||||
|
|
||||||
const [ selectedIndex, setSelectedIndex ] = useState<number>(null);
|
const [ selectedGroupId, setSelectedGroupId ] = useState<number>(null);
|
||||||
|
const [ groupInformation, setGroupInformation ] = useState<GroupInformationParser>(null);
|
||||||
|
|
||||||
|
const onGroupInformationEvent = useCallback((event: GroupInformationEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(!selectedGroupId || selectedGroupId !== parser.id || parser.flag) return;
|
||||||
|
|
||||||
|
if(groupInformation) setGroupInformation(null);
|
||||||
|
|
||||||
|
setGroupInformation(parser);
|
||||||
|
}, [ groupInformation, selectedGroupId ]);
|
||||||
|
|
||||||
|
CreateMessageHook(GroupInformationEvent, onGroupInformationEvent);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(groups.length > 0 && selectedIndex === null) setSelectedIndex(0);
|
if(groups.length > 0 && !selectedGroupId) setSelectedGroupId(groups[0].id);
|
||||||
}, [ groups ]);
|
}, [ groups, selectedGroupId ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(selectedGroupId) SendMessageHook(new GroupInformationComposer(selectedGroupId, false));
|
||||||
|
}, [ selectedGroupId ]);
|
||||||
|
|
||||||
if(!groups) return null;
|
if(!groups) return null;
|
||||||
|
|
||||||
@ -23,14 +44,14 @@ export const GroupsContainerView: FC<GroupsContainerViewProps> = props =>
|
|||||||
<div className="h-100 overflow-auto d-flex flex-column gap-1">
|
<div className="h-100 overflow-auto d-flex flex-column gap-1">
|
||||||
{ groups.map((group, index) =>
|
{ groups.map((group, index) =>
|
||||||
{
|
{
|
||||||
return <div key={ index } onClick={ () => setSelectedIndex(index) } className={ 'profile-groups-item flex-shrink-0 d-flex align-items-center justify-content-center cursor-pointer' + classNames({ ' active': selectedIndex === index }) }>
|
return <div key={ index } onClick={ () => setSelectedGroupId(group.id) } className={ 'profile-groups-item flex-shrink-0 d-flex align-items-center justify-content-center cursor-pointer' + classNames({ ' active': selectedGroupId === group.id }) }>
|
||||||
<BadgeImageView badgeCode={ group.badge } isGroup={ true } />
|
<BadgeImageView badgeCode={ group.badge } isGroup={ true } />
|
||||||
</div>
|
</div>
|
||||||
}) }
|
}) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-100">
|
<div className="w-100">
|
||||||
{ selectedIndex > -1 && <GroupInformationView group={ groups[selectedIndex] } /> }
|
{ groupInformation && <GroupInformationView groupInformation={ groupInformation } onClose={ onLeaveGroup } /> }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -3,4 +3,5 @@ import { GroupDataParser } from '@nitrots/nitro-renderer';
|
|||||||
export interface GroupsContainerViewProps
|
export interface GroupsContainerViewProps
|
||||||
{
|
{
|
||||||
groups: GroupDataParser[];
|
groups: GroupDataParser[];
|
||||||
|
onLeaveGroup: () => void;
|
||||||
}
|
}
|
||||||
|
@ -6,38 +6,38 @@ import { UserContainerViewProps } from './UserContainerView.types';
|
|||||||
|
|
||||||
export const UserContainerView: FC<UserContainerViewProps> = props =>
|
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 { userProfile = null } = props;
|
||||||
|
|
||||||
const OnlineIcon = useCallback(() =>
|
const OnlineIcon = useCallback(() =>
|
||||||
{
|
{
|
||||||
if(isOnline) return (<i className="icon icon-pf-online" />);
|
if(userProfile.isOnline) return (<i className="icon icon-pf-online" />);
|
||||||
else return (<i className="icon icon-pf-offline" />);
|
else return (<i className="icon icon-pf-offline" />);
|
||||||
}, [isOnline]);
|
}, [ userProfile ]);
|
||||||
|
|
||||||
const FriendRequestComponent = useCallback(() =>
|
const FriendRequestComponent = useCallback(() =>
|
||||||
{
|
{
|
||||||
if(id === GetSessionDataManager().userId) return (<span><i className="icon icon-pf-tick" />{LocalizeText('extendedprofile.me')}</span> );
|
if(userProfile.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(userProfile.isMyFriend) 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>);
|
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>)
|
return (<button className="btn btn-success btn-sm add-friend">{LocalizeText('extendedprofile.addasafriend')}</button>)
|
||||||
}, [id, isFriend, requestSent]);
|
}, [ userProfile ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-sm-3 px-0 d-flex align-items-center">
|
<div className="col-sm-3 px-0 d-flex align-items-center">
|
||||||
<AvatarImageView figure={figure} direction={2} />
|
<AvatarImageView figure={userProfile.figure} direction={2} />
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-8">
|
<div className="col-sm-8">
|
||||||
<div className="user-info-container">
|
<div className="user-info-container">
|
||||||
<div className="fw-bold">{username}</div>
|
<div className="fw-bold">{userProfile.username}</div>
|
||||||
<div className="mb-1 fst-italic">{motto}</div>
|
<div className="fst-italic">{userProfile.motto}</div>
|
||||||
<div className="mb-1" dangerouslySetInnerHTML={{ __html: LocalizeText('extendedprofile.created', ['created'], [creation]) }} />
|
<div dangerouslySetInnerHTML={{ __html: LocalizeText('extendedprofile.created', ['created'], [userProfile.registration]) }} />
|
||||||
<div className="mb-1" dangerouslySetInnerHTML={{ __html: LocalizeText('extendedprofile.last.login', ['lastlogin'], [FriendlyTime.format(secondsSinceLastLogin, '.ago', 2)]) }} />
|
<div dangerouslySetInnerHTML={{ __html: LocalizeText('extendedprofile.last.login', ['lastlogin'], [FriendlyTime.format(userProfile.secondsSinceLastVisit, '.ago', 2)]) }} />
|
||||||
<div className="mb-1"><b>{LocalizeText('extendedprofile.achievementscore')}</b> {achievementScore}</div>
|
<div><b>{LocalizeText('extendedprofile.achievementscore')}</b> {userProfile.achievementPoints}</div>
|
||||||
<div className="d-flex flex-row align-items-center">
|
<div className="d-flex flex-row align-items-center gap-2">
|
||||||
<OnlineIcon />
|
<OnlineIcon />
|
||||||
<FriendRequestComponent />
|
<FriendRequestComponent />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
export interface UserContainerViewProps {
|
import { UserProfileParser } from '@nitrots/nitro-renderer';
|
||||||
id: number;
|
|
||||||
username: string;
|
export interface UserContainerViewProps
|
||||||
figure: string;
|
{
|
||||||
motto: string;
|
userProfile: UserProfileParser;
|
||||||
creation: string;
|
|
||||||
secondsSinceLastLogin: number;
|
|
||||||
achievementScore: number;
|
|
||||||
isFriend: boolean;
|
|
||||||
requestSent: boolean;
|
|
||||||
isOnline: boolean;
|
|
||||||
}
|
}
|
||||||
|
@ -3,36 +3,52 @@
|
|||||||
padding:7px;
|
padding:7px;
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
width: 16px;
|
|
||||||
height: 9px;
|
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
|
|
||||||
&.icon-mv-1 {
|
&.icon-mv-1 {
|
||||||
|
width: 16px;
|
||||||
|
height: 9px;
|
||||||
background-image: url('../../assets/images/wired/icon_wired_around.png');
|
background-image: url('../../assets/images/wired/icon_wired_around.png');
|
||||||
}
|
}
|
||||||
&.icon-mv-2 {
|
&.icon-mv-2 {
|
||||||
|
width: 16px;
|
||||||
|
height: 9px;
|
||||||
background-image: url('../../assets/images/wired/icon_wired_up_down.png');
|
background-image: url('../../assets/images/wired/icon_wired_up_down.png');
|
||||||
}
|
}
|
||||||
&.icon-mv-3 {
|
&.icon-mv-3 {
|
||||||
|
width: 16px;
|
||||||
|
height: 9px;
|
||||||
background-image: url('../../assets/images/wired/icon_wired_left_right.png');
|
background-image: url('../../assets/images/wired/icon_wired_left_right.png');
|
||||||
}
|
}
|
||||||
&.icon-ne {
|
&.icon-ne {
|
||||||
|
width: 16px;
|
||||||
|
height: 9px;
|
||||||
background-image: url('../../assets/images/wired/icon_wired_north_east.png');
|
background-image: url('../../assets/images/wired/icon_wired_north_east.png');
|
||||||
}
|
}
|
||||||
&.icon-se {
|
&.icon-se {
|
||||||
|
width: 16px;
|
||||||
|
height: 9px;
|
||||||
background-image: url('../../assets/images/wired/icon_wired_south_east.png');
|
background-image: url('../../assets/images/wired/icon_wired_south_east.png');
|
||||||
}
|
}
|
||||||
&.icon-sw {
|
&.icon-sw {
|
||||||
|
width: 16px;
|
||||||
|
height: 9px;
|
||||||
background-image: url('../../assets/images/wired/icon_wired_south_west.png');
|
background-image: url('../../assets/images/wired/icon_wired_south_west.png');
|
||||||
}
|
}
|
||||||
&.icon-nw {
|
&.icon-nw {
|
||||||
|
width: 16px;
|
||||||
|
height: 9px;
|
||||||
background-image: url('../../assets/images/wired/icon_wired_north_west.png');
|
background-image: url('../../assets/images/wired/icon_wired_north_west.png');
|
||||||
}
|
}
|
||||||
&.icon-rot-1 {
|
&.icon-rot-1 {
|
||||||
|
width: 16px;
|
||||||
|
height: 9px;
|
||||||
background-image: url('../../assets/images/wired/icon_wired_rotate_clockwise.png');
|
background-image: url('../../assets/images/wired/icon_wired_rotate_clockwise.png');
|
||||||
}
|
}
|
||||||
&.icon-rot-2 {
|
&.icon-rot-2 {
|
||||||
|
width: 16px;
|
||||||
|
height: 9px;
|
||||||
background-image: url('../../assets/images/wired/icon_wired_rotate_counter_clockwise.png');
|
background-image: url('../../assets/images/wired/icon_wired_rotate_counter_clockwise.png');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user