From 3cd6d56b3ea174aebaa748e47e416dfe929674db Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Mon, 6 Sep 2021 02:53:24 -0300 Subject: [PATCH] GroupMembers updates --- src/api/groups/GetGroupMembers.ts | 5 +- src/api/index.ts | 1 + src/api/user/GetUserProfile.ts | 7 ++ src/api/user/index.ts | 1 + .../groups/icons/group_icon_accept_member.png | Bin 0 -> 174 bytes .../groups/icons/group_icon_remove_member.png | Bin 168 -> 173 bytes src/assets/styles/icons.scss | 6 ++ src/views/groups/GroupsMessageHandler.tsx | 4 +- src/views/groups/common/GroupBadgePart.ts | 3 +- .../information/GroupInformationView.tsx | 14 ++- .../views/members/GroupMembersView.scss | 4 +- .../groups/views/members/GroupMembersView.tsx | 91 +++++++++++++++--- .../GroupRoomInformationView.tsx | 7 +- .../user-profile-icon/UserProfileIconView.tsx | 12 +-- 14 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 src/api/user/GetUserProfile.ts create mode 100644 src/api/user/index.ts create mode 100644 src/assets/images/groups/icons/group_icon_accept_member.png diff --git a/src/api/groups/GetGroupMembers.ts b/src/api/groups/GetGroupMembers.ts index 58dbce6e..b6b0e522 100644 --- a/src/api/groups/GetGroupMembers.ts +++ b/src/api/groups/GetGroupMembers.ts @@ -1,6 +1,7 @@ import { CreateLinkEvent } from '..'; -export function GetGroupMembers(groupId: number): void +export function GetGroupMembers(groupId: number, levelId?: number): void { - CreateLinkEvent(`groups/members/${groupId}`); + if(!levelId) CreateLinkEvent(`groups/members/${groupId}`); + else CreateLinkEvent(`groups/members/${groupId}/${levelId}`); } diff --git a/src/api/index.ts b/src/api/index.ts index 77777005..773325c3 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -2,4 +2,5 @@ export * from './core'; export * from './groups'; export * from './navigator'; export * from './nitro'; +export * from './user'; export * from './utils'; diff --git a/src/api/user/GetUserProfile.ts b/src/api/user/GetUserProfile.ts new file mode 100644 index 00000000..d29f7ff5 --- /dev/null +++ b/src/api/user/GetUserProfile.ts @@ -0,0 +1,7 @@ +import { UserProfileComposer } from '@nitrots/nitro-renderer'; +import { SendMessageHook } from '../../hooks'; + +export function GetUserProfile(userId: number): void +{ + SendMessageHook(new UserProfileComposer(userId)); +} diff --git a/src/api/user/index.ts b/src/api/user/index.ts new file mode 100644 index 00000000..1c609ea7 --- /dev/null +++ b/src/api/user/index.ts @@ -0,0 +1 @@ +export * from './GetUserProfile'; diff --git a/src/assets/images/groups/icons/group_icon_accept_member.png b/src/assets/images/groups/icons/group_icon_accept_member.png new file mode 100644 index 0000000000000000000000000000000000000000..da56941a0d624f6c76fae89e559ad24824207984 GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp@K+MO%1|+}KPrC%9I14-?iy0WWg+Q3`(%rg0K*0o0 z7srr_TggBE|F>u6IPSv!SG^@M>!DQKz8VjK!zPO|JZ`LP5?0P`$v(84F;e;BEQbaa zUxS8VVIQGbW=CHG))!J7S%;P}uAg6!d00EGXj0j&X$Idor1L_t(|+GF_t|33o=$3zGHCxl^Y;Tm4Pd`J+(G@@v@WT}l4 zBWr|f0!hFCvSMU0yqaK&(D_(3p({kU8K)*}HW1WAvQ1?9iR92DIi5&K5nxTkraR>H d$3RYk1pwI#2n)l!T;~7)002ovPDHLkV1oDeGz9VY7jtCX#I;%TFYS9?9`UN{T>96~tnU^hc}) Y0H2HoH-=OvNB{r;07*qoM6N<$f@mo&(f|Me diff --git a/src/assets/styles/icons.scss b/src/assets/styles/icons.scss index 6ca7b485..87dfb3b9 100644 --- a/src/assets/styles/icons.scss +++ b/src/assets/styles/icons.scss @@ -621,6 +621,12 @@ height: 14px; } + &.icon-group-accept-member { + background: url('../images/groups/icons/group_icon_accept_member.png'); + width: 13px; + height: 14px; + } + &.icon-group-small-owner { background: url('../images/groups/icons/group_icon_small_owner.png'); width: 13px; diff --git a/src/views/groups/GroupsMessageHandler.tsx b/src/views/groups/GroupsMessageHandler.tsx index efa2b1bf..0bb9e943 100644 --- a/src/views/groups/GroupsMessageHandler.tsx +++ b/src/views/groups/GroupsMessageHandler.tsx @@ -114,8 +114,8 @@ export const GroupsMessageHandler: FC<{}> = props => parser.badgeParts.forEach((part, id) => { groupBadgeParts.push(new GroupBadgePart( - part.isBase ? GroupBadgePart.BASE : part.key >= 100 ? GroupBadgePart.SYMBOL_ALT : GroupBadgePart.SYMBOL, - part.key >= 100 ? part.key - 100 : part.key, + part.isBase ? GroupBadgePart.BASE : GroupBadgePart.SYMBOL, + part.key, part.color, part.position )); diff --git a/src/views/groups/common/GroupBadgePart.ts b/src/views/groups/common/GroupBadgePart.ts index d6846d86..3e24ed6f 100644 --- a/src/views/groups/common/GroupBadgePart.ts +++ b/src/views/groups/common/GroupBadgePart.ts @@ -2,7 +2,6 @@ export class GroupBadgePart { public static BASE: string = 'b'; public static SYMBOL: string = 's'; - public static SYMBOL_ALT: string = 't'; public type: string; public key: number; @@ -26,6 +25,6 @@ export class GroupBadgePart public static getCode(type: string, key: number, color: number, position: number): string { - return (type === GroupBadgePart.BASE ? type : key >= 100 ? GroupBadgePart.SYMBOL_ALT : GroupBadgePart.SYMBOL) + (key < 10 ? '0' : '') + (type === GroupBadgePart.BASE ? key : key >= 100 ? key - 100 : key) + (color < 10 ? '0' : '') + color + position; + return type + (key < 10 ? '0' : '') + key + (color < 10 ? '0' : '') + color + position; } } diff --git a/src/views/groups/views/information/GroupInformationView.tsx b/src/views/groups/views/information/GroupInformationView.tsx index 99e32161..e53a433a 100644 --- a/src/views/groups/views/information/GroupInformationView.tsx +++ b/src/views/groups/views/information/GroupInformationView.tsx @@ -24,8 +24,11 @@ export const GroupInformationView: FC = props => const leaveGroup = useCallback(() => { - SendMessageHook(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId)); - if(onClose) onClose(); + if(window.confirm(LocalizeText('group.leaveconfirm.desc'))) + { + SendMessageHook(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId)); + if(onClose) onClose(); + } }, [ groupInformation, onClose ]); const isRealOwner = useCallback(() => @@ -80,6 +83,9 @@ export const GroupInformationView: FC = props => case 'members': GetGroupMembers(groupInformation.id); break; + case 'members_pending': + GetGroupMembers(groupInformation.id, 2); + break; case 'manage': GetGroupManager(groupInformation.id); break; @@ -104,8 +110,8 @@ export const GroupInformationView: FC = props =>
handleAction('members') }> { LocalizeText('group.membercount', ['totalMembers'], [groupInformation.membersCount.toString()]) }
- { groupInformation.pendingRequestsCount > 0 &&
- { LocalizeText('group.pendingmembercount', ['totalMembers'], [groupInformation.pendingRequestsCount.toString()]) } + { groupInformation.pendingRequestsCount > 0 &&
handleAction('members_pending') }> + { LocalizeText('group.pendingmembercount', ['amount'], [groupInformation.pendingRequestsCount.toString()]) }
} { groupInformation.isOwner &&
handleAction('manage') }> { LocalizeText('group.manage') } diff --git a/src/views/groups/views/members/GroupMembersView.scss b/src/views/groups/views/members/GroupMembersView.scss index 7973c711..d405bd57 100644 --- a/src/views/groups/views/members/GroupMembersView.scss +++ b/src/views/groups/views/members/GroupMembersView.scss @@ -16,12 +16,12 @@ position: relative; overflow: hidden; width: 40px; - height: 40px; + height: 50px; .avatar-image { position: absolute; left: -25px; - top: -25px; + top: -20px; } } } diff --git a/src/views/groups/views/members/GroupMembersView.tsx b/src/views/groups/views/members/GroupMembersView.tsx index 92391e4a..53890df8 100644 --- a/src/views/groups/views/members/GroupMembersView.tsx +++ b/src/views/groups/views/members/GroupMembersView.tsx @@ -1,7 +1,7 @@ -import { GroupMemberParser, GroupMembersComposer, GroupMembersEvent, GroupMembersParser, GroupRank } from '@nitrots/nitro-renderer'; +import { GroupAdminGiveComposer, GroupAdminTakeComposer, GroupConfirmMemberRemoveEvent, GroupConfirmRemoveMemberComposer, GroupMemberParser, GroupMembersComposer, GroupMembersEvent, GroupMembershipAcceptComposer, GroupMembershipDeclineComposer, GroupMembersParser, GroupRank, GroupRemoveMemberComposer } from '@nitrots/nitro-renderer'; import classNames from 'classnames'; import { FC, KeyboardEvent, useCallback, useEffect, useState } from 'react'; -import { GetSessionDataManager, LocalizeText } from '../../../../api'; +import { GetSessionDataManager, GetUserProfile, LocalizeText } from '../../../../api'; import { CreateMessageHook, SendMessageHook } from '../../../../hooks'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; @@ -16,23 +16,40 @@ export const GroupMembersView: FC = props => const [ searchQuery, setSearchQuery ] = useState(''); const [ searchLevelId, setSearchLevelId ] = useState(3); const [ totalPages, setTotalPages ] = useState(0); + const [ removingMemberName, setRemovingMemberName ] = useState(null); - const searchMembers = useCallback((pageId: number) => + const searchMembers = useCallback((pageId: number, newLevelId?: number) => { if(!groupId) return; - SendMessageHook(new GroupMembersComposer(groupId, pageId, searchQuery, searchLevelId)); + SendMessageHook(new GroupMembersComposer(groupId, pageId, searchQuery, newLevelId !== null ? newLevelId : searchLevelId)); }, [ groupId, searchQuery, searchLevelId ]); const onGroupMembersEvent = useCallback((event: GroupMembersEvent) => { const parser = event.getParser(); + setPageData(null); setPageData(parser); + setSearchLevelId(parser.level); setTotalPages(Math.ceil(parser.totalMembersCount / parser.pageSize)); }, []); + const onGroupConfirmMemberRemoveEvent = useCallback((event: GroupConfirmMemberRemoveEvent) => + { + const parser = event.getParser(); + + if(window.confirm(LocalizeText(parser.furnitureCount > 0 ? 'group.kickconfirm.desc' : 'group.kickconfirm_nofurni.desc', ['user', 'amount'], [removingMemberName, parser.furnitureCount.toString()]))) + { + SendMessageHook(new GroupRemoveMemberComposer(pageData.groupId, parser.userId)); + searchMembers(pageData.pageIndex); + } + + setRemovingMemberName(null); + }, [ pageData, removingMemberName, searchMembers ]); + CreateMessageHook(GroupMembersEvent, onGroupMembersEvent); + CreateMessageHook(GroupConfirmMemberRemoveEvent, onGroupConfirmMemberRemoveEvent); useEffect(() => { @@ -43,13 +60,15 @@ export const GroupMembersView: FC = props => if(!groupId) return; if(levelId !== null) setSearchLevelId(levelId); - searchMembers(0); + + searchMembers(0, levelId); }, [ groupId, levelId ]); - useEffect(() => + const selectSearchLevelId = useCallback((level: number) => { - searchMembers(0); - }, [ searchLevelId ]); + setSearchLevelId(level); + searchMembers(0, level); + }, [ searchMembers ]); const previousPage = useCallback(() => { @@ -82,6 +101,45 @@ export const GroupMembersView: FC = props => return ''; }, [ pageData ]); + const toggleAdmin = useCallback((member: GroupMemberParser) => + { + if(member.rank === GroupRank.OWNER) return; + + if(member.rank !== GroupRank.ADMIN) + { + SendMessageHook(new GroupAdminGiveComposer(pageData.groupId, member.id)); + } + else + { + SendMessageHook(new GroupAdminTakeComposer(pageData.groupId, member.id)); + } + + searchMembers(pageData.pageIndex); + }, [ pageData ]); + + const acceptMembership = useCallback((member) => + { + if(member.rank === GroupRank.REQUESTED) + { + SendMessageHook(new GroupMembershipAcceptComposer(pageData.groupId, member.id)); + searchMembers(pageData.pageIndex); + } + }, [ pageData ]); + + const removeMemberOrDeclineMembership = useCallback((member) => + { + if(member.rank === GroupRank.REQUESTED) + { + SendMessageHook(new GroupMembershipDeclineComposer(pageData.groupId, member.id)); + searchMembers(pageData.pageIndex); + } + else + { + setRemovingMemberName(member.name); + SendMessageHook(new GroupConfirmRemoveMemberComposer(pageData.groupId, member.id)); + } + }, [ pageData ]); + if(!pageData) return null; return ( @@ -94,7 +152,7 @@ export const GroupMembersView: FC = props =>
setSearchQuery(e.target.value) } onBlur={ () => searchMembers(pageData.pageIndex) } onKeyDown={ onKeyDown } /> - selectSearchLevelId(Number(e.target.value)) }> @@ -107,19 +165,22 @@ export const GroupMembersView: FC = props => return (
-
+
{ GetUserProfile(member.id) } }>
-
-
{ member.name }
-
{ LocalizeText('group.members.since', ['date'], [member.joinedAt]) }
+
+
{ GetUserProfile(member.id) } }>{ member.name }
+ { member.rank !== GroupRank.REQUESTED &&
{ LocalizeText('group.members.since', ['date'], [member.joinedAt]) }
}
- + toggleAdmin(member) } />
+ { member.rank === GroupRank.REQUESTED &&
+ acceptMembership(member) } /> +
} { member.rank !== GroupRank.OWNER && pageData.admin && member.id !== GetSessionDataManager().userId &&
- + removeMemberOrDeclineMembership(member) } />
}
diff --git a/src/views/groups/views/room-information/GroupRoomInformationView.tsx b/src/views/groups/views/room-information/GroupRoomInformationView.tsx index 78a5e7fe..8a66491d 100644 --- a/src/views/groups/views/room-information/GroupRoomInformationView.tsx +++ b/src/views/groups/views/room-information/GroupRoomInformationView.tsx @@ -65,8 +65,11 @@ export const GroupRoomInformationView: FC<{}> = props => const tryLeaveGroup = useCallback(() => { - SendMessageHook(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId)); - SendMessageHook(new GroupInformationComposer(groupInformation.id, false)); + if(window.confirm(LocalizeText('group.leaveconfirm.desc'))) + { + SendMessageHook(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId)); + SendMessageHook(new GroupInformationComposer(groupInformation.id, false)); + } }, [ groupInformation ]); const getButtonText = useCallback(() => diff --git a/src/views/shared/user-profile-icon/UserProfileIconView.tsx b/src/views/shared/user-profile-icon/UserProfileIconView.tsx index e2b4ded3..23225082 100644 --- a/src/views/shared/user-profile-icon/UserProfileIconView.tsx +++ b/src/views/shared/user-profile-icon/UserProfileIconView.tsx @@ -1,18 +1,12 @@ -import { UserProfileComposer } from '@nitrots/nitro-renderer'; -import { FC, useCallback } from 'react'; -import { SendMessageHook } from '../../../hooks'; +import { FC } from 'react'; +import { GetUserProfile } from '../../../api'; import { UserProfileIconViewProps } from './UserProfileIconView.types'; export const UserProfileIconView: FC = props => { const { userId = 0, userName = null } = props; - const visitProfile = useCallback(() => - { - if(userId) SendMessageHook(new UserProfileComposer(userId)); - }, [ userId ]); - return (<> - + GetUserProfile(userId) } /> ); }