mirror of
https://github.com/billsonnn/nitro-react.git
synced 2025-01-19 05:46:27 +01:00
Overhaul groups
This commit is contained in:
parent
332c9553d5
commit
da8b401279
@ -72,7 +72,7 @@ $room-info-width: 325px;
|
|||||||
$nitro-group-creator-width: 383px;
|
$nitro-group-creator-width: 383px;
|
||||||
$nitro-mod-tools-width: 175px;
|
$nitro-mod-tools-width: 175px;
|
||||||
|
|
||||||
$nitro-group-manager-width: 375px;
|
$nitro-group-manager-width: 390px;
|
||||||
$nitro-group-manager-height: 355px;
|
$nitro-group-manager-height: 355px;
|
||||||
|
|
||||||
$nitro-chooser-width: 200px;
|
$nitro-chooser-width: 200px;
|
||||||
|
@ -2,6 +2,6 @@ import { CreateLinkEvent } from '..';
|
|||||||
|
|
||||||
export function GetGroupMembers(groupId: number, levelId?: number): void
|
export function GetGroupMembers(groupId: number, levelId?: number): void
|
||||||
{
|
{
|
||||||
if(!levelId) CreateLinkEvent(`groups/members/${groupId}`);
|
if(!levelId) CreateLinkEvent(`group-members/${ groupId }`);
|
||||||
else CreateLinkEvent(`groups/members/${groupId}/${levelId}`);
|
else CreateLinkEvent(`group-members/${ groupId }/${ levelId }`);
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,59 @@
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@import './views/creator/GroupCreatorView';
|
.nitro-group-manager {
|
||||||
@import './views/manager/GroupManagerView';
|
height: $nitro-group-manager-height;
|
||||||
@import './views/room-information/GroupRoomInformationView';
|
width: $nitro-group-manager-width;
|
||||||
@import './views/tabs/GroupSharedTabs';
|
}
|
||||||
|
|
||||||
|
.nitro-group-creator {
|
||||||
|
height: $nitro-group-manager-height;
|
||||||
|
width: $nitro-group-manager-width;
|
||||||
|
|
||||||
|
.creator-tabs {
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
position: relative;
|
||||||
|
margin-left: -6px;
|
||||||
|
background-image: url('../../assets/images/groups/creator_tabs.png');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tab-blue-flat {
|
||||||
|
width: 84px;
|
||||||
|
height: 24px;
|
||||||
|
background-position: 0px 0px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
height: 28px;
|
||||||
|
background-position: 0px -24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tab-blue-arrow {
|
||||||
|
width: 83px;
|
||||||
|
height: 24px;
|
||||||
|
background-position: 0px -52px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
height: 28px;
|
||||||
|
background-position: 0px -76px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tab-yellow {
|
||||||
|
width: 133px;
|
||||||
|
height: 28px;
|
||||||
|
background-position: 0px -104px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
height: 33px;
|
||||||
|
background-position: 0px -132px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { createContext, Dispatch, FC, ProviderProps, useContext } from 'react';
|
import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react';
|
||||||
import { IGroupsAction, IGroupsState } from './reducers/GroupsReducer';
|
import { IGroupCustomize } from './common/IGroupCustomize';
|
||||||
|
|
||||||
interface IGroupsContext
|
interface IGroupsContext
|
||||||
{
|
{
|
||||||
groupsState: IGroupsState;
|
groupCustomize: IGroupCustomize;
|
||||||
dispatchGroupsState: Dispatch<IGroupsAction>;
|
setGroupCustomize: Dispatch<SetStateAction<IGroupCustomize>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GroupsContext = createContext<IGroupsContext>({
|
const GroupsContext = createContext<IGroupsContext>({
|
||||||
groupsState: null,
|
groupCustomize: null,
|
||||||
dispatchGroupsState: null
|
setGroupCustomize: null
|
||||||
});
|
});
|
||||||
|
|
||||||
export const GroupsContextProvider: FC<ProviderProps<IGroupsContext>> = props =>
|
export const GroupsContextProvider: FC<ProviderProps<IGroupsContext>> = props =>
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
import { GroupBadgePartsEvent, GroupBuyDataEvent, GroupSettingsEvent, RoomCreatedEvent } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useCallback } from 'react';
|
|
||||||
import { CreateMessageHook } from '../../hooks';
|
|
||||||
import { GroupBadgePart } from './common/GroupBadgePart';
|
|
||||||
import { useGroupsContext } from './GroupsContext';
|
|
||||||
import { GroupsActions } from './reducers/GroupsReducer';
|
|
||||||
|
|
||||||
function compareId(a, b)
|
|
||||||
{
|
|
||||||
if( a.id < b.id ) return -1;
|
|
||||||
if( a.id > b.id ) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GroupsMessageHandler: FC<{}> = props =>
|
|
||||||
{
|
|
||||||
const { groupsState = null, dispatchGroupsState = null } = useGroupsContext();
|
|
||||||
const { availableRooms = null } = groupsState;
|
|
||||||
|
|
||||||
const onGroupBuyDataEvent = useCallback((event: GroupBuyDataEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
const rooms: { id: number, name: string }[] = [];
|
|
||||||
|
|
||||||
parser.availableRooms.forEach((name, id) =>
|
|
||||||
{
|
|
||||||
rooms.push({ id, name });
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatchGroupsState({
|
|
||||||
type: GroupsActions.SET_PURHCASE_SETTINGS,
|
|
||||||
payload: {
|
|
||||||
objectValues: rooms,
|
|
||||||
numberValues: [ parser.groupCost ]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [ dispatchGroupsState ]);
|
|
||||||
|
|
||||||
|
|
||||||
const onRoomCreatedEvent = useCallback((event: RoomCreatedEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
const clonedRooms = Array.from(availableRooms);
|
|
||||||
clonedRooms.push({
|
|
||||||
id: parser.roomId,
|
|
||||||
name: parser.roomName
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatchGroupsState({
|
|
||||||
type: GroupsActions.SET_PURHCASE_SETTINGS,
|
|
||||||
payload: {
|
|
||||||
objectValues: clonedRooms
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [ availableRooms, dispatchGroupsState ]);
|
|
||||||
|
|
||||||
const onGroupBadgePartsEvent = useCallback((event: GroupBadgePartsEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
const bases: { id: number, images: string[] }[] = [];
|
|
||||||
const symbols: { id: number, images: string[] }[] = [];
|
|
||||||
const partColors: { id: number, color: string }[] = [];
|
|
||||||
const colorsA: { id: number, color: string }[] = [];
|
|
||||||
const colorsB: { id: number, color: string }[] = [];
|
|
||||||
|
|
||||||
parser.bases.forEach((images, id) =>
|
|
||||||
{
|
|
||||||
bases.push({ id, images });
|
|
||||||
});
|
|
||||||
|
|
||||||
parser.symbols.forEach((images, id) =>
|
|
||||||
{
|
|
||||||
symbols.push({ id, images });
|
|
||||||
});
|
|
||||||
|
|
||||||
parser.partColors.forEach((color, id) =>
|
|
||||||
{
|
|
||||||
partColors.push({ id, color });
|
|
||||||
});
|
|
||||||
|
|
||||||
parser.colorsA.forEach((color, id) =>
|
|
||||||
{
|
|
||||||
colorsA.push({ id, color });
|
|
||||||
});
|
|
||||||
|
|
||||||
parser.colorsB.forEach((color, id) =>
|
|
||||||
{
|
|
||||||
colorsB.push({ id, color });
|
|
||||||
});
|
|
||||||
|
|
||||||
bases.sort(compareId);
|
|
||||||
symbols.sort(compareId);
|
|
||||||
partColors.sort(compareId);
|
|
||||||
colorsA.sort(compareId);
|
|
||||||
colorsB.sort(compareId);
|
|
||||||
|
|
||||||
dispatchGroupsState({
|
|
||||||
type: GroupsActions.SET_GROUP_BADGE_PARTS_CONFIG,
|
|
||||||
payload: {
|
|
||||||
objectValues: [ bases, symbols, partColors, colorsA, colorsB ]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [ dispatchGroupsState ]);
|
|
||||||
|
|
||||||
const onGroupSettingsEvent = useCallback((event: GroupSettingsEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
const groupBadgeParts: GroupBadgePart[] = [];
|
|
||||||
|
|
||||||
parser.badgeParts.forEach((part, id) =>
|
|
||||||
{
|
|
||||||
groupBadgeParts.push(new GroupBadgePart(
|
|
||||||
part.isBase ? GroupBadgePart.BASE : GroupBadgePart.SYMBOL,
|
|
||||||
part.key,
|
|
||||||
part.color,
|
|
||||||
part.position
|
|
||||||
));
|
|
||||||
});
|
|
||||||
|
|
||||||
dispatchGroupsState({
|
|
||||||
type: GroupsActions.SET_GROUP_SETTINGS,
|
|
||||||
payload: {
|
|
||||||
stringValues: [ parser.title, parser.description ],
|
|
||||||
numberValues: [ parser.id, parser.state, parser.colorA, parser.colorB ],
|
|
||||||
boolValues: [ parser.canMembersDecorate ],
|
|
||||||
objectValues: groupBadgeParts
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [ dispatchGroupsState ]);
|
|
||||||
|
|
||||||
CreateMessageHook(GroupBuyDataEvent, onGroupBuyDataEvent);
|
|
||||||
CreateMessageHook(RoomCreatedEvent, onRoomCreatedEvent);
|
|
||||||
CreateMessageHook(GroupBadgePartsEvent, onGroupBadgePartsEvent);
|
|
||||||
CreateMessageHook(GroupSettingsEvent, onGroupSettingsEvent);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
@ -1,31 +1,19 @@
|
|||||||
import { GroupBadgePartsComposer, GroupPurchasedEvent, GroupSettingsComposer, ILinkEventTracker } from '@nitrots/nitro-renderer';
|
import { GroupBadgePartsComposer, GroupBadgePartsEvent, GroupPurchasedEvent, GroupSettingsComposer, ILinkEventTracker } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { AddEventLinkTracker, RemoveLinkEventTracker, TryVisitRoom } from '../../api';
|
import { AddEventLinkTracker, RemoveLinkEventTracker, TryVisitRoom } from '../../api';
|
||||||
import { BatchUpdates, CreateMessageHook, SendMessageHook } from '../../hooks';
|
import { CreateMessageHook, SendMessageHook } from '../../hooks';
|
||||||
|
import { CompareId } from './common/CompareId';
|
||||||
|
import { IGroupCustomize } from './common/IGroupCustomize';
|
||||||
import { GroupsContextProvider } from './GroupsContext';
|
import { GroupsContextProvider } from './GroupsContext';
|
||||||
import { GroupsMessageHandler } from './GroupsMessageHandler';
|
import { GroupCreatorView } from './views/GroupCreatorView';
|
||||||
import { GroupsReducer, initialGroups } from './reducers/GroupsReducer';
|
import { GroupInformationStandaloneView } from './views/GroupInformationStandaloneView';
|
||||||
import { GroupCreatorView } from './views/creator/GroupCreatorView';
|
import { GroupManagerView } from './views/GroupManagerView';
|
||||||
import { GroupInformationStandaloneView } from './views/information-standalone/GroupInformationStandaloneView';
|
import { GroupMembersView } from './views/GroupMembersView';
|
||||||
import { GroupManagerView } from './views/manager/GroupManagerView';
|
|
||||||
import { GroupMembersView } from './views/members/GroupMembersView';
|
|
||||||
|
|
||||||
export const GroupsView: FC<{}> = props =>
|
export const GroupsView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ currentGroupId, setCurrentGroupId ] = useState<number>(null);
|
|
||||||
const [ currentGroupLevelId, setCurrentGroupLevelId ] = useState<number>(null);
|
|
||||||
const [ isMembersVisible, setMembersVisible ] = useState<boolean>(false);
|
|
||||||
const [ isCreatorVisible, setCreatorVisible ] = useState<boolean>(false);
|
const [ isCreatorVisible, setCreatorVisible ] = useState<boolean>(false);
|
||||||
const [ groupsState, dispatchGroupsState ] = useReducer(GroupsReducer, initialGroups);
|
const [ groupCustomize, setGroupCustomize ] = useState<IGroupCustomize>(null);
|
||||||
|
|
||||||
const closeMembers = () =>
|
|
||||||
{
|
|
||||||
BatchUpdates(() =>
|
|
||||||
{
|
|
||||||
setCurrentGroupId(null);
|
|
||||||
setCurrentGroupLevelId(null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const onGroupPurchasedEvent = useCallback((event: GroupPurchasedEvent) =>
|
const onGroupPurchasedEvent = useCallback((event: GroupPurchasedEvent) =>
|
||||||
{
|
{
|
||||||
@ -37,6 +25,35 @@ export const GroupsView: FC<{}> = props =>
|
|||||||
|
|
||||||
CreateMessageHook(GroupPurchasedEvent, onGroupPurchasedEvent);
|
CreateMessageHook(GroupPurchasedEvent, onGroupPurchasedEvent);
|
||||||
|
|
||||||
|
const onGroupBadgePartsEvent = useCallback((event: GroupBadgePartsEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
const customize: IGroupCustomize = {
|
||||||
|
badgeBases: [],
|
||||||
|
badgeSymbols: [],
|
||||||
|
badgePartColors: [],
|
||||||
|
groupColorsA: [],
|
||||||
|
groupColorsB: []
|
||||||
|
};
|
||||||
|
|
||||||
|
parser.bases.forEach((images, id) => customize.badgeBases.push({ id, images }));
|
||||||
|
parser.symbols.forEach((images, id) => customize.badgeSymbols.push({ id, images }));
|
||||||
|
parser.partColors.forEach((color, id) => customize.badgePartColors.push({ id, color }));
|
||||||
|
parser.colorsA.forEach((color, id) => customize.groupColorsA.push({ id, color }));
|
||||||
|
parser.colorsB.forEach((color, id) => customize.groupColorsB.push({ id, color }));
|
||||||
|
|
||||||
|
customize.badgeBases.sort(CompareId);
|
||||||
|
customize.badgeSymbols.sort(CompareId);
|
||||||
|
customize.badgePartColors.sort(CompareId);
|
||||||
|
customize.groupColorsA.sort(CompareId);
|
||||||
|
customize.groupColorsB.sort(CompareId);
|
||||||
|
|
||||||
|
setGroupCustomize(customize);
|
||||||
|
}, [ setGroupCustomize ]);
|
||||||
|
|
||||||
|
CreateMessageHook(GroupBadgePartsEvent, onGroupBadgePartsEvent);
|
||||||
|
|
||||||
const linkReceived = useCallback((url: string) =>
|
const linkReceived = useCallback((url: string) =>
|
||||||
{
|
{
|
||||||
const parts = url.split('/');
|
const parts = url.split('/');
|
||||||
@ -51,21 +68,8 @@ export const GroupsView: FC<{}> = props =>
|
|||||||
case 'manage':
|
case 'manage':
|
||||||
if(!parts[2]) return;
|
if(!parts[2]) return;
|
||||||
|
|
||||||
|
setCreatorVisible(false);
|
||||||
SendMessageHook(new GroupSettingsComposer(Number(parts[2])));
|
SendMessageHook(new GroupSettingsComposer(Number(parts[2])));
|
||||||
return;
|
|
||||||
case 'members':
|
|
||||||
if(!parts[2]) return;
|
|
||||||
|
|
||||||
const groupId = (parseInt(parts[2]) || -1);
|
|
||||||
const levelId = (parseInt(parts[3]) || 3);
|
|
||||||
|
|
||||||
BatchUpdates(() =>
|
|
||||||
{
|
|
||||||
setCurrentGroupId(groupId);
|
|
||||||
setCurrentGroupLevelId(levelId);
|
|
||||||
setMembersVisible(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
@ -88,13 +92,13 @@ export const GroupsView: FC<{}> = props =>
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GroupsContextProvider value={ { groupsState, dispatchGroupsState } }>
|
<GroupsContextProvider value={ { groupCustomize, setGroupCustomize } }>
|
||||||
<GroupsMessageHandler />
|
|
||||||
<div className="nitro-groups">
|
<div className="nitro-groups">
|
||||||
<GroupCreatorView isVisible={ isCreatorVisible } onClose={ () => setCreatorVisible(false) } />
|
{ isCreatorVisible &&
|
||||||
<GroupManagerView />
|
<GroupCreatorView onClose={ () => setCreatorVisible(false) } /> }
|
||||||
{ isMembersVisible &&
|
{ !isCreatorVisible &&
|
||||||
<GroupMembersView groupId={ currentGroupId } levelId={ currentGroupLevelId } setLevelId={ setCurrentGroupLevelId } onClose={ closeMembers } /> }
|
<GroupManagerView /> }
|
||||||
|
<GroupMembersView />
|
||||||
<GroupInformationStandaloneView />
|
<GroupInformationStandaloneView />
|
||||||
</div>
|
</div>
|
||||||
</GroupsContextProvider>
|
</GroupsContextProvider>
|
||||||
|
8
src/components/groups/common/CompareId.ts
Normal file
8
src/components/groups/common/CompareId.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export const CompareId = (a, b) =>
|
||||||
|
{
|
||||||
|
if(a.id < b.id) return -1;
|
||||||
|
|
||||||
|
if(a.id > b.id) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
8
src/components/groups/common/IGroupCustomize.ts
Normal file
8
src/components/groups/common/IGroupCustomize.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export interface IGroupCustomize
|
||||||
|
{
|
||||||
|
badgeBases: { id: number, images: string[] }[];
|
||||||
|
badgeSymbols: { id: number, images: string[] }[];
|
||||||
|
badgePartColors: { id: number, color: string }[];
|
||||||
|
groupColorsA: { id: number, color: string }[];
|
||||||
|
groupColorsB: { id: number, color: string }[];
|
||||||
|
}
|
13
src/components/groups/common/IGroupData.ts
Normal file
13
src/components/groups/common/IGroupData.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { GroupBadgePart } from './GroupBadgePart';
|
||||||
|
|
||||||
|
export interface IGroupData
|
||||||
|
{
|
||||||
|
groupId: number;
|
||||||
|
groupName: string;
|
||||||
|
groupDescription: string;
|
||||||
|
groupHomeroomId: number;
|
||||||
|
groupState: number;
|
||||||
|
groupCanMembersDecorate: boolean;
|
||||||
|
groupColors: number[];
|
||||||
|
groupBadgeParts: GroupBadgePart[];
|
||||||
|
}
|
@ -1,148 +0,0 @@
|
|||||||
import { Reducer } from 'react';
|
|
||||||
import { GroupBadgePart } from '../common/GroupBadgePart';
|
|
||||||
|
|
||||||
export interface IGroupsState
|
|
||||||
{
|
|
||||||
availableRooms: { id: number, name: string }[];
|
|
||||||
purchaseCost: number;
|
|
||||||
badgeBases: { id: number, images: string[] }[];
|
|
||||||
badgeSymbols: { id: number, images: string[] }[];
|
|
||||||
badgePartColors: { id: number, color: string }[];
|
|
||||||
groupId: number;
|
|
||||||
groupColorsA: { id: number, color: string }[];
|
|
||||||
groupColorsB: { id: number, color: string }[];
|
|
||||||
groupName: string;
|
|
||||||
groupDescription: string;
|
|
||||||
groupHomeroomId: number;
|
|
||||||
groupBadgeParts: GroupBadgePart[];
|
|
||||||
groupColors: number[];
|
|
||||||
groupState: number;
|
|
||||||
groupCanMembersDecorate: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IGroupsAction
|
|
||||||
{
|
|
||||||
type: string;
|
|
||||||
payload?: {
|
|
||||||
objectValues?: any[];
|
|
||||||
stringValues?: string[];
|
|
||||||
numberValues?: number[];
|
|
||||||
boolValues?: boolean[];
|
|
||||||
badgeParts?: GroupBadgePart[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GroupsActions
|
|
||||||
{
|
|
||||||
public static SET_PURHCASE_SETTINGS: string = 'GA_SET_PURHCASE_SETTINGS';
|
|
||||||
public static SET_GROUP_BADGE_PARTS_CONFIG: string = 'GA_SET_GROUP_BADGE_PARTS_CONFIG';
|
|
||||||
public static SET_GROUP_NAME: string = 'GA_SET_GROUP_NAME';
|
|
||||||
public static SET_GROUP_DESCRIPTION: string = 'GA_SET_GROUP_DESCRIPTION';
|
|
||||||
public static SET_GROUP_HOMEROOM_ID: string = 'GA_SET_GROUP_HOMEROOM_ID';
|
|
||||||
public static SET_GROUP_BADGE_PARTS: string = 'GA_SET_BADGE_PARTS';
|
|
||||||
public static SET_GROUP_COLORS: string = 'GA_SET_GROUP_COLORS';
|
|
||||||
public static SET_GROUP_STATE: string = 'GA_SET_GROUP_STATE';
|
|
||||||
public static SET_GROUP_CAN_MEMBERS_DECORATE: string = 'GA_SET_GROUP_CAN_MEMBERS_DECORATE';
|
|
||||||
public static SET_GROUP_SETTINGS: string = 'GA_SET_GROUP_SETTINGS';
|
|
||||||
public static RESET_GROUP_SETTINGS: string = 'GA_RESET_GROUP_SETTINGS';
|
|
||||||
}
|
|
||||||
|
|
||||||
export const initialGroups: IGroupsState = {
|
|
||||||
availableRooms: null,
|
|
||||||
purchaseCost: null,
|
|
||||||
badgeBases: null,
|
|
||||||
badgeSymbols: null,
|
|
||||||
badgePartColors: null,
|
|
||||||
groupId: null,
|
|
||||||
groupColorsA: null,
|
|
||||||
groupColorsB: null,
|
|
||||||
groupName: '',
|
|
||||||
groupDescription: '',
|
|
||||||
groupHomeroomId: 0,
|
|
||||||
groupBadgeParts: null,
|
|
||||||
groupColors: null,
|
|
||||||
groupState: null,
|
|
||||||
groupCanMembersDecorate: null
|
|
||||||
};
|
|
||||||
|
|
||||||
export const GroupsReducer: Reducer<IGroupsState, IGroupsAction> = (state, action) =>
|
|
||||||
{
|
|
||||||
switch(action.type)
|
|
||||||
{
|
|
||||||
case GroupsActions.SET_PURHCASE_SETTINGS: {
|
|
||||||
const availableRooms = action.payload.objectValues;
|
|
||||||
const purchaseCost = (action.payload.numberValues[0] || state.purchaseCost || 0);
|
|
||||||
|
|
||||||
return { ...state, availableRooms, purchaseCost };
|
|
||||||
}
|
|
||||||
case GroupsActions.SET_GROUP_BADGE_PARTS_CONFIG: {
|
|
||||||
const badgeBases = (action.payload.objectValues[0] || state.badgeBases || null);
|
|
||||||
const badgeSymbols = (action.payload.objectValues[1] || state.badgeSymbols || null);
|
|
||||||
const badgePartColors = (action.payload.objectValues[2] || state.badgePartColors || null);
|
|
||||||
const groupColorsA = (action.payload.objectValues[3] || state.groupColorsA || null);
|
|
||||||
const groupColorsB = (action.payload.objectValues[4] || state.groupColorsB || null);
|
|
||||||
|
|
||||||
return { ...state, badgeBases, badgeSymbols, badgePartColors, groupColorsA, groupColorsB };
|
|
||||||
}
|
|
||||||
case GroupsActions.SET_GROUP_NAME: {
|
|
||||||
const groupName = action.payload.stringValues[0];
|
|
||||||
|
|
||||||
return { ...state, groupName };
|
|
||||||
}
|
|
||||||
case GroupsActions.SET_GROUP_DESCRIPTION: {
|
|
||||||
const groupDescription = action.payload.stringValues[0];
|
|
||||||
|
|
||||||
return { ...state, groupDescription };
|
|
||||||
}
|
|
||||||
case GroupsActions.SET_GROUP_HOMEROOM_ID: {
|
|
||||||
const groupHomeroomId = action.payload.numberValues[0];
|
|
||||||
|
|
||||||
return { ...state, groupHomeroomId };
|
|
||||||
}
|
|
||||||
case GroupsActions.SET_GROUP_BADGE_PARTS: {
|
|
||||||
const groupBadgeParts = action.payload.badgeParts;
|
|
||||||
|
|
||||||
return { ...state, groupBadgeParts };
|
|
||||||
}
|
|
||||||
case GroupsActions.SET_GROUP_COLORS: {
|
|
||||||
const groupColors = action.payload.objectValues;
|
|
||||||
|
|
||||||
return { ...state, groupColors };
|
|
||||||
}
|
|
||||||
case GroupsActions.SET_GROUP_STATE: {
|
|
||||||
const groupState = action.payload.numberValues[0];
|
|
||||||
|
|
||||||
return { ...state, groupState };
|
|
||||||
}
|
|
||||||
case GroupsActions.SET_GROUP_CAN_MEMBERS_DECORATE: {
|
|
||||||
const groupCanMembersDecorate = action.payload.boolValues[0];
|
|
||||||
|
|
||||||
return { ...state, groupCanMembersDecorate };
|
|
||||||
}
|
|
||||||
case GroupsActions.SET_GROUP_SETTINGS: {
|
|
||||||
const groupId = action.payload.numberValues[0];
|
|
||||||
const groupName = action.payload.stringValues[0];
|
|
||||||
const groupDescription = action.payload.stringValues[1];
|
|
||||||
const groupBadgeParts = action.payload.objectValues;
|
|
||||||
const groupState = action.payload.numberValues[1];
|
|
||||||
const groupColors = action.payload.numberValues.slice(2);
|
|
||||||
const groupCanMembersDecorate = action.payload.boolValues[0];
|
|
||||||
|
|
||||||
return { ...state, groupId, groupName, groupDescription, groupBadgeParts, groupColors, groupState, groupCanMembersDecorate };
|
|
||||||
}
|
|
||||||
case GroupsActions.RESET_GROUP_SETTINGS: {
|
|
||||||
const groupId = null;
|
|
||||||
const groupName = '';
|
|
||||||
const groupDescription = '';
|
|
||||||
const groupHomeroomId = 0;
|
|
||||||
const groupBadgeParts = null;
|
|
||||||
const groupColors = null;
|
|
||||||
const groupState = null;
|
|
||||||
const groupCanMembersDecorate = null;
|
|
||||||
|
|
||||||
return { ...state, groupId, groupName, groupDescription, groupHomeroomId, groupBadgeParts, groupColors, groupState, groupCanMembersDecorate };
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { Dispatch, FC, SetStateAction, useEffect, useRef, useState } from 'react';
|
import { Dispatch, FC, SetStateAction, useState } from 'react';
|
||||||
import { Base, Column, Flex, Grid } from '../../../common';
|
import { Base, Column, Flex, Grid } from '../../../common';
|
||||||
import { BatchUpdates } from '../../../hooks';
|
|
||||||
import { BadgeImageView } from '../../../views/shared/badge-image/BadgeImageView';
|
import { BadgeImageView } from '../../../views/shared/badge-image/BadgeImageView';
|
||||||
import { GroupBadgePart } from '../common/GroupBadgePart';
|
import { GroupBadgePart } from '../common/GroupBadgePart';
|
||||||
import { useGroupsContext } from '../GroupsContext';
|
import { useGroupsContext } from '../GroupsContext';
|
||||||
@ -18,53 +17,31 @@ export const GroupBadgeCreatorView: FC<GroupBadgeCreatorViewProps> = props =>
|
|||||||
{
|
{
|
||||||
const { badgeParts = [], setBadgeParts = null } = props;
|
const { badgeParts = [], setBadgeParts = null } = props;
|
||||||
const [ selectedIndex, setSelectedIndex ] = useState<number>(-1);
|
const [ selectedIndex, setSelectedIndex ] = useState<number>(-1);
|
||||||
const [ copiedBadgeParts, setCopiedBadgeParts ] = useState<GroupBadgePart[]>(null);
|
const { groupCustomize = null } = useGroupsContext();
|
||||||
const { groupsState = null } = useGroupsContext();
|
|
||||||
const { badgeBases = null, badgeSymbols = null, badgePartColors = null } = groupsState;
|
|
||||||
const willUnmount = useRef(false);
|
|
||||||
|
|
||||||
const setPartProperty = (partIndex: number, property: string, value: number) =>
|
const setPartProperty = (partIndex: number, property: string, value: number) =>
|
||||||
{
|
{
|
||||||
const newBadgeParts = [ ...copiedBadgeParts ];
|
const newBadgeParts = [ ...badgeParts ];
|
||||||
|
|
||||||
newBadgeParts[partIndex][property] = value;
|
newBadgeParts[partIndex][property] = value;
|
||||||
|
|
||||||
BatchUpdates(() =>
|
setBadgeParts(newBadgeParts);
|
||||||
{
|
|
||||||
setCopiedBadgeParts(newBadgeParts);
|
|
||||||
|
|
||||||
if(property === 'key') setSelectedIndex(-1);
|
if(property === 'key') setSelectedIndex(-1);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() =>
|
if(!badgeParts || !badgeParts.length) return null;
|
||||||
{
|
|
||||||
BatchUpdates(() =>
|
|
||||||
{
|
|
||||||
setCopiedBadgeParts(badgeParts);
|
|
||||||
setSelectedIndex(-1);
|
|
||||||
});
|
|
||||||
}, [ badgeParts ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if(!copiedBadgeParts || (copiedBadgeParts === badgeParts)) return;
|
|
||||||
|
|
||||||
setBadgeParts(copiedBadgeParts);
|
|
||||||
}, [ copiedBadgeParts, badgeParts, setBadgeParts ]);
|
|
||||||
|
|
||||||
if(!copiedBadgeParts || !copiedBadgeParts.length) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{ ((selectedIndex < 0) && copiedBadgeParts && (copiedBadgeParts.length > 0)) && copiedBadgeParts.map((part, index) =>
|
{ ((selectedIndex < 0) && badgeParts && (badgeParts.length > 0)) && badgeParts.map((part, index) =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Flex key={ index } alignItems="center" justifyContent="between" gap={ 2 } className="bg-muted rounded px-2 py-1">
|
<Flex key={ index } alignItems="center" justifyContent="between" gap={ 2 } className="bg-muted rounded px-2 py-1">
|
||||||
<Flex pointer center className="bg-muted rounded p-1" onClick={ event => setSelectedIndex(index) }>
|
<Flex pointer center className="bg-muted rounded p-1" onClick={ event => setSelectedIndex(index) }>
|
||||||
{ (copiedBadgeParts[index].code && (copiedBadgeParts[index].code.length > 0)) &&
|
{ (badgeParts[index].code && (badgeParts[index].code.length > 0)) &&
|
||||||
<BadgeImageView badgeCode={ copiedBadgeParts[index].code } isGroup={ true } /> }
|
<BadgeImageView badgeCode={ badgeParts[index].code } isGroup={ true } /> }
|
||||||
{ (!copiedBadgeParts[index].code || !copiedBadgeParts[index].code.length) &&
|
{ (!badgeParts[index].code || !badgeParts[index].code.length) &&
|
||||||
<Flex center className="badge-image group-badge">
|
<Flex center className="badge-image group-badge">
|
||||||
<FontAwesomeIcon icon="plus" />
|
<FontAwesomeIcon icon="plus" />
|
||||||
</Flex> }
|
</Flex> }
|
||||||
@ -73,13 +50,13 @@ export const GroupBadgeCreatorView: FC<GroupBadgeCreatorViewProps> = props =>
|
|||||||
<Grid gap={ 1 } columnCount={ 3 }>
|
<Grid gap={ 1 } columnCount={ 3 }>
|
||||||
{ POSITIONS.map((position, posIndex) =>
|
{ POSITIONS.map((position, posIndex) =>
|
||||||
{
|
{
|
||||||
return <Base key={ posIndex } pointer className={ `group-badge-position-swatch ${ (copiedBadgeParts[index].position === position) ? 'active' : '' }` } onClick={ event => setPartProperty(index, 'position', position) }></Base>
|
return <Base key={ posIndex } pointer className={ `group-badge-position-swatch ${ (badgeParts[index].position === position) ? 'active' : '' }` } onClick={ event => setPartProperty(index, 'position', position) }></Base>
|
||||||
}) }
|
}) }
|
||||||
</Grid> }
|
</Grid> }
|
||||||
<Grid gap={ 1 } columnCount={ 8 }>
|
<Grid gap={ 1 } columnCount={ 8 }>
|
||||||
{ (badgePartColors.length > 0) && badgePartColors.map((item, colorIndex) =>
|
{ (groupCustomize.badgePartColors.length > 0) && groupCustomize.badgePartColors.map((item, colorIndex) =>
|
||||||
{
|
{
|
||||||
return <Base key={ colorIndex } pointer className={ `group-badge-color-swatch ${ (copiedBadgeParts[index].color === (colorIndex + 1)) ? 'active' : '' }` } style={{ backgroundColor: '#' + item.color }} onClick={ event => setPartProperty(index, 'color', (colorIndex + 1)) }></Base>
|
return <Base key={ colorIndex } pointer className={ `group-badge-color-swatch ${ (badgeParts[index].color === (colorIndex + 1)) ? 'active' : '' }` } style={{ backgroundColor: '#' + item.color }} onClick={ event => setPartProperty(index, 'color', (colorIndex + 1)) }></Base>
|
||||||
}) }
|
}) }
|
||||||
</Grid>
|
</Grid>
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -87,17 +64,17 @@ export const GroupBadgeCreatorView: FC<GroupBadgeCreatorViewProps> = props =>
|
|||||||
}) }
|
}) }
|
||||||
{ (selectedIndex >= 0) &&
|
{ (selectedIndex >= 0) &&
|
||||||
<Grid gap={ 1 } columnCount={ 5 }>
|
<Grid gap={ 1 } columnCount={ 5 }>
|
||||||
{ (copiedBadgeParts[selectedIndex].type === GroupBadgePart.SYMBOL) &&
|
{ (badgeParts[selectedIndex].type === GroupBadgePart.SYMBOL) &&
|
||||||
<Column pointer center className="bg-muted rounded p-1" onClick={ event => setPartProperty(selectedIndex, 'key', 0) }>
|
<Column pointer center className="bg-muted rounded p-1" onClick={ event => setPartProperty(selectedIndex, 'key', 0) }>
|
||||||
<Flex center className="badge-image group-badge">
|
<Flex center className="badge-image group-badge">
|
||||||
<FontAwesomeIcon icon="times" />
|
<FontAwesomeIcon icon="times" />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Column> }
|
</Column> }
|
||||||
{ ((copiedBadgeParts[selectedIndex].type === GroupBadgePart.BASE) ? badgeBases : badgeSymbols).map((item, index) =>
|
{ ((badgeParts[selectedIndex].type === GroupBadgePart.BASE) ? groupCustomize.badgeBases : groupCustomize.badgeSymbols).map((item, index) =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Column key={ index } pointer center className="bg-muted rounded p-1" onClick={ event => setPartProperty(selectedIndex, 'key', item.id) }>
|
<Column key={ index } pointer center className="bg-muted rounded p-1" onClick={ event => setPartProperty(selectedIndex, 'key', item.id) }>
|
||||||
<BadgeImageView badgeCode={ GroupBadgePart.getCode(copiedBadgeParts[selectedIndex].type, item.id, copiedBadgeParts[selectedIndex].color, 4) } isGroup={ true } />
|
<BadgeImageView badgeCode={ GroupBadgePart.getCode(badgeParts[selectedIndex].type, item.id, badgeParts[selectedIndex].color, 4) } isGroup={ true } />
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
}) }
|
}) }
|
||||||
|
174
src/components/groups/views/GroupCreatorView.tsx
Normal file
174
src/components/groups/views/GroupCreatorView.tsx
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
import { GroupBuyComposer, GroupBuyDataComposer, GroupBuyDataEvent } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
|
import { HasHabboClub, LocalizeText } from '../../../api';
|
||||||
|
import { Base, Button, Column, Flex, Text } from '../../../common';
|
||||||
|
import { BatchUpdates, CreateMessageHook, SendMessageHook } from '../../../hooks';
|
||||||
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../layout';
|
||||||
|
import { IGroupData } from '../common/IGroupData';
|
||||||
|
import { GroupTabBadgeView } from './tabs/GroupTabBadgeView';
|
||||||
|
import { GroupTabColorsView } from './tabs/GroupTabColorsView';
|
||||||
|
import { GroupTabCreatorConfirmationView } from './tabs/GroupTabCreatorConfirmationView';
|
||||||
|
import { GroupTabIdentityView } from './tabs/GroupTabIdentityView';
|
||||||
|
|
||||||
|
interface GroupCreatorViewProps
|
||||||
|
{
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TABS: number[] = [ 1, 2, 3, 4 ];
|
||||||
|
|
||||||
|
export const GroupCreatorView: FC<GroupCreatorViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { onClose = null } = props;
|
||||||
|
const [ currentTab, setCurrentTab ] = useState<number>(1);
|
||||||
|
const [ closeAction, setCloseAction ] = useState<{ action: () => boolean }>(null);
|
||||||
|
const [ groupData, setGroupData ] = useState<IGroupData>(null);
|
||||||
|
const [ availableRooms, setAvailableRooms ] = useState<{ id: number, name: string }[]>(null);
|
||||||
|
const [ purchaseCost, setPurchaseCost ] = useState<number>(0);
|
||||||
|
|
||||||
|
const close = () =>
|
||||||
|
{
|
||||||
|
setCloseAction(null);
|
||||||
|
setGroupData(null);
|
||||||
|
|
||||||
|
if(onClose) onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
const buyGroup = () =>
|
||||||
|
{
|
||||||
|
if(!groupData) return;
|
||||||
|
|
||||||
|
const badge = [];
|
||||||
|
|
||||||
|
groupData.groupBadgeParts.forEach(part =>
|
||||||
|
{
|
||||||
|
if(part.code)
|
||||||
|
{
|
||||||
|
badge.push(part.key);
|
||||||
|
badge.push(part.color);
|
||||||
|
badge.push(part.position);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SendMessageHook(new GroupBuyComposer(groupData.groupName, groupData.groupDescription, groupData.groupHomeroomId, groupData.groupColors[0], groupData.groupColors[1], badge));
|
||||||
|
}
|
||||||
|
|
||||||
|
const previousStep = () =>
|
||||||
|
{
|
||||||
|
if(closeAction && closeAction.action)
|
||||||
|
{
|
||||||
|
if(!closeAction.action()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentTab === 1)
|
||||||
|
{
|
||||||
|
onClose();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentTab(value => value - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextStep = () =>
|
||||||
|
{
|
||||||
|
if(closeAction && closeAction.action)
|
||||||
|
{
|
||||||
|
if(!closeAction.action()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentTab === 4)
|
||||||
|
{
|
||||||
|
buyGroup();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentTab(value => (value === 4 ? value : value + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
const onGroupBuyDataEvent = useCallback((event: GroupBuyDataEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
const rooms: { id: number, name: string }[] = [];
|
||||||
|
|
||||||
|
parser.availableRooms.forEach((name, id) => rooms.push({ id, name }));
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setAvailableRooms(rooms);
|
||||||
|
setPurchaseCost(parser.groupCost);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(GroupBuyDataEvent, onGroupBuyDataEvent);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setCurrentTab(1);
|
||||||
|
|
||||||
|
setGroupData({
|
||||||
|
groupId: -1,
|
||||||
|
groupName: null,
|
||||||
|
groupDescription: null,
|
||||||
|
groupHomeroomId: -1,
|
||||||
|
groupState: 1,
|
||||||
|
groupCanMembersDecorate: true,
|
||||||
|
groupColors: null,
|
||||||
|
groupBadgeParts: null
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
SendMessageHook(new GroupBuyDataComposer());
|
||||||
|
}, [ setGroupData ]);
|
||||||
|
|
||||||
|
if(!groupData) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardView className="nitro-group-creator">
|
||||||
|
<NitroCardHeaderView headerText={ LocalizeText('group.create.title') } onCloseClick={ close } />
|
||||||
|
<NitroCardContentView>
|
||||||
|
<Flex center className="creator-tabs">
|
||||||
|
{ TABS.map((tab, index) =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<Flex center key={ index } className={ `tab tab-${ ((tab === 1) ? 'blue-flat' : (tab === 4) ? 'yellow' : 'blue-arrow') } ${ (currentTab === tab) ? 'active' : '' }` }>
|
||||||
|
<Text variant="white">{ LocalizeText(`group.create.steplabel.${ tab }`) }</Text>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}) }
|
||||||
|
</Flex>
|
||||||
|
<Column overflow="hidden">
|
||||||
|
<Flex alignItems="center" gap={ 2 }>
|
||||||
|
<Base className={ `nitro-group-tab-image tab-${ currentTab }`} />
|
||||||
|
<Column grow gap={ 0 }>
|
||||||
|
<Text bold fontSize={ 4 }>{ LocalizeText(`group.create.stepcaption.${ currentTab }`) }</Text>
|
||||||
|
<Text>{ LocalizeText(`group.create.stepdesc.${ currentTab }`) }</Text>
|
||||||
|
</Column>
|
||||||
|
</Flex>
|
||||||
|
<Column overflow="hidden">
|
||||||
|
{ (currentTab === 1) &&
|
||||||
|
<GroupTabIdentityView groupData={ groupData } setGroupData={ setGroupData } setCloseAction={ setCloseAction } isCreator={ true } availableRooms={ availableRooms } /> }
|
||||||
|
{ (currentTab === 2) &&
|
||||||
|
<GroupTabBadgeView groupData={ groupData } setGroupData={ setGroupData } setCloseAction={ setCloseAction } /> }
|
||||||
|
{ (currentTab === 3) &&
|
||||||
|
<GroupTabColorsView groupData={ groupData } setGroupData={ setGroupData } setCloseAction={ setCloseAction } /> }
|
||||||
|
{ (currentTab === 4) &&
|
||||||
|
<GroupTabCreatorConfirmationView groupData={ groupData } setGroupData={ setGroupData } purchaseCost={ purchaseCost } /> }
|
||||||
|
</Column>
|
||||||
|
<Flex justifyContent="between">
|
||||||
|
<Button variant="link" className="text-black" onClick={ previousStep }>
|
||||||
|
{ LocalizeText(currentTab === 1 ? 'generic.cancel' : 'group.create.previousstep') }
|
||||||
|
</Button>
|
||||||
|
<Button disabled={ ((currentTab === 4) && !HasHabboClub()) } variant={ ((currentTab === 4) ? HasHabboClub() ? 'success' : 'danger' : 'primary') } onClick={ nextStep }>
|
||||||
|
{ LocalizeText((currentTab === 4) ? HasHabboClub() ? 'group.create.confirm.buy' : 'group.create.confirm.viprequired' : 'group.create.nextstep') }
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Column>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
);
|
||||||
|
};
|
@ -1,9 +1,9 @@
|
|||||||
import { GroupInformationEvent, GroupInformationParser } from '@nitrots/nitro-renderer';
|
import { GroupInformationEvent, GroupInformationParser } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useState } from 'react';
|
import { FC, useCallback, useState } from 'react';
|
||||||
import { LocalizeText } from '../../../../api';
|
import { LocalizeText } from '../../../api';
|
||||||
import { BatchUpdates, CreateMessageHook } from '../../../../hooks';
|
import { CreateMessageHook } from '../../../hooks';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../layout';
|
||||||
import { GroupInformationView } from '../information/GroupInformationView';
|
import { GroupInformationView } from './GroupInformationView';
|
||||||
|
|
||||||
export const GroupInformationStandaloneView: FC<{}> = props =>
|
export const GroupInformationStandaloneView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
@ -13,14 +13,8 @@ export const GroupInformationStandaloneView: FC<{}> = props =>
|
|||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
if(!parser.flag) return;
|
if((groupInformation && (groupInformation.id === parser.id)) || parser.flag) setGroupInformation(parser);
|
||||||
|
}, [ groupInformation ]);
|
||||||
BatchUpdates(() =>
|
|
||||||
{
|
|
||||||
setGroupInformation(null);
|
|
||||||
setGroupInformation(parser);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
CreateMessageHook(GroupInformationEvent, onGroupInformationEvent);
|
CreateMessageHook(GroupInformationEvent, onGroupInformationEvent);
|
||||||
|
|
||||||
@ -28,7 +22,7 @@ export const GroupInformationStandaloneView: FC<{}> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardView className="nitro-group-information-standalone" simple>
|
<NitroCardView className="nitro-group-information-standalone" simple>
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('group.window.title') } onCloseClick={ () => setGroupInformation(null) } />
|
<NitroCardHeaderView headerText={ LocalizeText('group.window.title') } onCloseClick={ event => setGroupInformation(null) } />
|
||||||
<NitroCardContentView>
|
<NitroCardContentView>
|
||||||
<GroupInformationView groupInformation={ groupInformation } onClose={ () => setGroupInformation(null) } />
|
<GroupInformationView groupInformation={ groupInformation } onClose={ () => setGroupInformation(null) } />
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
@ -1,16 +1,18 @@
|
|||||||
import { GroupInformationParser, GroupRemoveMemberComposer } from '@nitrots/nitro-renderer';
|
import { GroupInformationParser, GroupRemoveMemberComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback } from 'react';
|
import { FC, useCallback } from 'react';
|
||||||
import { CreateLinkEvent, GetSessionDataManager, LocalizeText, TryVisitRoom } from '../../../../api';
|
import { CreateLinkEvent, GetSessionDataManager, LocalizeText, TryVisitRoom } from '../../../api';
|
||||||
import { GetGroupManager } from '../../../../api/groups/GetGroupManager';
|
import { GetGroupManager } from '../../../api/groups/GetGroupManager';
|
||||||
import { GetGroupMembers } from '../../../../api/groups/GetGroupMembers';
|
import { GetGroupMembers } from '../../../api/groups/GetGroupMembers';
|
||||||
import { TryJoinGroup } from '../../../../api/groups/TryJoinGroup';
|
import { TryJoinGroup } from '../../../api/groups/TryJoinGroup';
|
||||||
import { Button, Column, Flex, Grid, Text } from '../../../../common';
|
import { Button, Column, Flex, Grid, Text } from '../../../common';
|
||||||
import { SendMessageHook } from '../../../../hooks';
|
import { SendMessageHook } from '../../../hooks';
|
||||||
import { NotificationUtilities } from '../../../../views/notification-center/common/NotificationUtilities';
|
import { NotificationUtilities } from '../../../views/notification-center/common/NotificationUtilities';
|
||||||
import { BadgeImageView } from '../../../../views/shared/badge-image/BadgeImageView';
|
import { BadgeImageView } from '../../../views/shared/badge-image/BadgeImageView';
|
||||||
import { CatalogPageName } from '../../../catalog/common/CatalogPageName';
|
import { CatalogPageName } from '../../catalog/common/CatalogPageName';
|
||||||
import { GroupMembershipType } from '../../common/GroupMembershipType';
|
import { GroupMembershipType } from '../common/GroupMembershipType';
|
||||||
import { GroupType } from '../../common/GroupType';
|
import { GroupType } from '../common/GroupType';
|
||||||
|
|
||||||
|
const STATES: string[] = [ 'regular', 'exclusive', 'private' ];
|
||||||
|
|
||||||
interface GroupInformationViewProps
|
interface GroupInformationViewProps
|
||||||
{
|
{
|
||||||
@ -125,9 +127,9 @@ export const GroupInformationView: FC<GroupInformationViewProps> = props =>
|
|||||||
<Flex alignItems="center" gap={ 2 }>
|
<Flex alignItems="center" gap={ 2 }>
|
||||||
<Text bold>{ groupInformation.title }</Text>
|
<Text bold>{ groupInformation.title }</Text>
|
||||||
<Flex gap={ 1 }>
|
<Flex gap={ 1 }>
|
||||||
<i className={ 'icon icon-group-type-' + groupInformation.type } />
|
<i className={ 'icon icon-group-type-' + groupInformation.type } title={ LocalizeText(`group.edit.settings.type.${ STATES[groupInformation.type] }.help`)} />
|
||||||
{ groupInformation.canMembersDecorate &&
|
{ groupInformation.canMembersDecorate &&
|
||||||
<i className="icon icon-group-decorate" /> }
|
<i className="icon icon-group-decorate" title={ LocalizeText('group.memberscandecorate') } /> }
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Text small>{ LocalizeText('group.created', ['date', 'owner'], [groupInformation.createdAt, groupInformation.ownerName]) }</Text>
|
<Text small>{ LocalizeText('group.created', ['date', 'owner'], [groupInformation.createdAt, groupInformation.ownerName]) }</Text>
|
125
src/components/groups/views/GroupManagerView.tsx
Normal file
125
src/components/groups/views/GroupManagerView.tsx
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import { GroupBadgePart, GroupInformationEvent, GroupSettingsEvent } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import { LocalizeText } from '../../../api';
|
||||||
|
import { Base, Column, Flex, Text } from '../../../common';
|
||||||
|
import { CreateMessageHook } from '../../../hooks';
|
||||||
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../layout';
|
||||||
|
import { IGroupData } from '../common/IGroupData';
|
||||||
|
import { GroupTabBadgeView } from './tabs/GroupTabBadgeView';
|
||||||
|
import { GroupTabColorsView } from './tabs/GroupTabColorsView';
|
||||||
|
import { GroupTabIdentityView } from './tabs/GroupTabIdentityView';
|
||||||
|
import { GroupTabSettingsView } from './tabs/GroupTabSettingsView';
|
||||||
|
|
||||||
|
const TABS: number[] = [ 1, 2, 3, 5 ];
|
||||||
|
|
||||||
|
export const GroupManagerView: FC<{}> = props =>
|
||||||
|
{
|
||||||
|
const [ currentTab, setCurrentTab ] = useState<number>(1);
|
||||||
|
const [ closeAction, setCloseAction ] = useState<{ action: () => boolean }>(null);
|
||||||
|
const [ groupData, setGroupData ] = useState<IGroupData>(null);
|
||||||
|
|
||||||
|
const close = () =>
|
||||||
|
{
|
||||||
|
setCloseAction(prevValue =>
|
||||||
|
{
|
||||||
|
if(prevValue && prevValue.action) prevValue.action();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
setGroupData(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeTab = (tab: number) =>
|
||||||
|
{
|
||||||
|
if(closeAction && closeAction.action) closeAction.action();
|
||||||
|
|
||||||
|
setCurrentTab(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onGroupInformationEvent = useCallback((event: GroupInformationEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(!groupData || (groupData.groupId !== parser.id)) return;
|
||||||
|
|
||||||
|
setGroupData(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = { ...prevValue };
|
||||||
|
|
||||||
|
newValue.groupName = parser.title;
|
||||||
|
newValue.groupDescription = parser.description;
|
||||||
|
newValue.groupState = parser.type;
|
||||||
|
newValue.groupCanMembersDecorate = parser.canMembersDecorate;
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
}, [ groupData ]);
|
||||||
|
|
||||||
|
CreateMessageHook(GroupInformationEvent, onGroupInformationEvent);
|
||||||
|
|
||||||
|
const onGroupSettingsEvent = useCallback((event: GroupSettingsEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
const groupBadgeParts: GroupBadgePart[] = [];
|
||||||
|
|
||||||
|
parser.badgeParts.forEach((part, id) =>
|
||||||
|
{
|
||||||
|
groupBadgeParts.push(new GroupBadgePart(
|
||||||
|
part.isBase ? GroupBadgePart.BASE : GroupBadgePart.SYMBOL,
|
||||||
|
part.key,
|
||||||
|
part.color,
|
||||||
|
part.position
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
setGroupData({
|
||||||
|
groupId: parser.id,
|
||||||
|
groupName: parser.title,
|
||||||
|
groupDescription: parser.description,
|
||||||
|
groupHomeroomId: parser.roomId,
|
||||||
|
groupState: parser.state,
|
||||||
|
groupCanMembersDecorate: parser.canMembersDecorate,
|
||||||
|
groupColors: [ parser.colorA, parser.colorB ],
|
||||||
|
groupBadgeParts
|
||||||
|
});
|
||||||
|
}, [ setGroupData ]);
|
||||||
|
|
||||||
|
CreateMessageHook(GroupSettingsEvent, onGroupSettingsEvent);
|
||||||
|
|
||||||
|
if(!groupData || (groupData.groupId <= 0)) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardView className="nitro-group-manager">
|
||||||
|
<NitroCardHeaderView headerText={ LocalizeText('group.window.title') } onCloseClick={ close } />
|
||||||
|
<NitroCardTabsView>
|
||||||
|
{ TABS.map(tab =>
|
||||||
|
{
|
||||||
|
return (<NitroCardTabsItemView key={ tab } isActive={ currentTab === tab } onClick={ () => changeTab(tab) }>
|
||||||
|
{ LocalizeText(`group.edit.tab.${tab}`) }
|
||||||
|
</NitroCardTabsItemView>);
|
||||||
|
}) }
|
||||||
|
</NitroCardTabsView>
|
||||||
|
<NitroCardContentView>
|
||||||
|
<Flex alignItems="center" gap={ 2 }>
|
||||||
|
<Base className={ `nitro-group-tab-image tab-${ currentTab }`} />
|
||||||
|
<Column grow gap={ 0 }>
|
||||||
|
<Text bold fontSize={ 4 }>{ LocalizeText(`group.edit.tabcaption.${ currentTab }`) }</Text>
|
||||||
|
<Text>{ LocalizeText(`group.edit.tabdesc.${ currentTab }`) }</Text>
|
||||||
|
</Column>
|
||||||
|
</Flex>
|
||||||
|
<Column grow overflow="hidden">
|
||||||
|
{ currentTab === 1 &&
|
||||||
|
<GroupTabIdentityView groupData={ groupData } setGroupData={ setGroupData } setCloseAction={ setCloseAction } /> }
|
||||||
|
{ currentTab === 2 &&
|
||||||
|
<GroupTabBadgeView groupData={ groupData } setGroupData={ setGroupData } setCloseAction={ setCloseAction } skipDefault={ true } /> }
|
||||||
|
{ currentTab === 3 &&
|
||||||
|
<GroupTabColorsView groupData={ groupData } setGroupData={ setGroupData } setCloseAction={ setCloseAction } /> }
|
||||||
|
{ currentTab === 5 &&
|
||||||
|
<GroupTabSettingsView groupData={ groupData } setGroupData={ setGroupData } setCloseAction={ setCloseAction } /> }
|
||||||
|
</Column>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
);
|
||||||
|
};
|
@ -1,39 +1,25 @@
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { GroupAdminGiveComposer, GroupAdminTakeComposer, GroupConfirmMemberRemoveEvent, GroupConfirmRemoveMemberComposer, GroupMemberParser, GroupMembersComposer, GroupMembersEvent, GroupMembershipAcceptComposer, GroupMembershipDeclineComposer, GroupMembersParser, GroupRank, GroupRemoveMemberComposer } from '@nitrots/nitro-renderer';
|
import { GroupAdminGiveComposer, GroupAdminTakeComposer, GroupConfirmMemberRemoveEvent, GroupConfirmRemoveMemberComposer, GroupMemberParser, GroupMembersComposer, GroupMembersEvent, GroupMembershipAcceptComposer, GroupMembershipDeclineComposer, GroupMembersParser, GroupRank, GroupRemoveMemberComposer, ILinkEventTracker } from '@nitrots/nitro-renderer';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { GetSessionDataManager, GetUserProfile, LocalizeText } from '../../../../api';
|
import { AddEventLinkTracker, GetSessionDataManager, GetUserProfile, LocalizeText, RemoveLinkEventTracker } from '../../../api';
|
||||||
import { Base, Button, Column, Flex, Grid, Text } from '../../../../common';
|
import { Base, Button, Column, Flex, Grid, Text } from '../../../common';
|
||||||
import { BatchUpdates, CreateMessageHook, SendMessageHook } from '../../../../hooks';
|
import { BatchUpdates, CreateMessageHook, SendMessageHook } from '../../../hooks';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../layout';
|
||||||
import { NotificationUtilities } from '../../../../views/notification-center/common/NotificationUtilities';
|
import { NotificationUtilities } from '../../../views/notification-center/common/NotificationUtilities';
|
||||||
import { AvatarImageView } from '../../../../views/shared/avatar-image/AvatarImageView';
|
import { AvatarImageView } from '../../../views/shared/avatar-image/AvatarImageView';
|
||||||
import { BadgeImageView } from '../../../../views/shared/badge-image/BadgeImageView';
|
import { BadgeImageView } from '../../../views/shared/badge-image/BadgeImageView';
|
||||||
|
|
||||||
interface GroupMembersViewProps
|
export const GroupMembersView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
groupId: number;
|
const [ groupId, setGroupId ] = useState<number>(-1);
|
||||||
levelId: number;
|
const [ levelId, setLevelId ] = useState<number>(-1);
|
||||||
setLevelId: Dispatch<SetStateAction<number>>;
|
const [ membersData, setMembersData ] = useState<GroupMembersParser>(null);
|
||||||
onClose: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { groupId = -1, levelId = -1, setLevelId = null, onClose = null } = props;
|
|
||||||
const [ pageData, setPageData ] = useState<GroupMembersParser>(null);
|
|
||||||
const [ pageId, setPageId ] = useState<number>(-1);
|
const [ pageId, setPageId ] = useState<number>(-1);
|
||||||
const [ searchQuery, setSearchQuery ] = useState<string>('');
|
|
||||||
const [ totalPages, setTotalPages ] = useState<number>(0);
|
const [ totalPages, setTotalPages ] = useState<number>(0);
|
||||||
|
const [ searchQuery, setSearchQuery ] = useState<string>('');
|
||||||
const [ removingMemberName, setRemovingMemberName ] = useState<string>(null);
|
const [ removingMemberName, setRemovingMemberName ] = useState<string>(null);
|
||||||
|
|
||||||
const refreshMembers = useCallback(() =>
|
|
||||||
{
|
|
||||||
if((groupId === -1) || (levelId === -1) || (pageId === -1)) return;
|
|
||||||
|
|
||||||
SendMessageHook(new GroupMembersComposer(groupId, pageId, searchQuery, levelId));
|
|
||||||
}, [ groupId, levelId, pageId, searchQuery ]);
|
|
||||||
|
|
||||||
const previousPage = () => setPageId(prevValue => (prevValue - 1));
|
const previousPage = () => setPageId(prevValue => (prevValue - 1));
|
||||||
|
|
||||||
const nextPage = () => setPageId(prevValue => (prevValue + 1));
|
const nextPage = () => setPageId(prevValue => (prevValue + 1));
|
||||||
@ -42,7 +28,7 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
{
|
{
|
||||||
if(member.rank === GroupRank.OWNER) return 'group.members.owner';
|
if(member.rank === GroupRank.OWNER) return 'group.members.owner';
|
||||||
|
|
||||||
if(pageData.admin)
|
if(membersData.admin)
|
||||||
{
|
{
|
||||||
if(member.rank === GroupRank.ADMIN) return 'group.members.removerights';
|
if(member.rank === GroupRank.ADMIN) return 'group.members.removerights';
|
||||||
|
|
||||||
@ -52,12 +38,19 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const refreshMembers = useCallback(() =>
|
||||||
|
{
|
||||||
|
if((groupId === -1) || (levelId === -1) || (pageId === -1)) return;
|
||||||
|
|
||||||
|
SendMessageHook(new GroupMembersComposer(groupId, pageId, searchQuery, levelId));
|
||||||
|
}, [ groupId, levelId, pageId, searchQuery ]);
|
||||||
|
|
||||||
const toggleAdmin = (member: GroupMemberParser) =>
|
const toggleAdmin = (member: GroupMemberParser) =>
|
||||||
{
|
{
|
||||||
if(member.rank === GroupRank.OWNER) return;
|
if(member.rank === GroupRank.OWNER) return;
|
||||||
|
|
||||||
if(member.rank !== GroupRank.ADMIN) SendMessageHook(new GroupAdminGiveComposer(pageData.groupId, member.id));
|
if(member.rank !== GroupRank.ADMIN) SendMessageHook(new GroupAdminGiveComposer(membersData.groupId, member.id));
|
||||||
else SendMessageHook(new GroupAdminTakeComposer(pageData.groupId, member.id));
|
else SendMessageHook(new GroupAdminTakeComposer(membersData.groupId, member.id));
|
||||||
|
|
||||||
refreshMembers();
|
refreshMembers();
|
||||||
}
|
}
|
||||||
@ -66,7 +59,7 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
{
|
{
|
||||||
if(member.rank !== GroupRank.REQUESTED) return;
|
if(member.rank !== GroupRank.REQUESTED) return;
|
||||||
|
|
||||||
SendMessageHook(new GroupMembershipAcceptComposer(pageData.groupId, member.id));
|
SendMessageHook(new GroupMembershipAcceptComposer(membersData.groupId, member.id));
|
||||||
|
|
||||||
refreshMembers();
|
refreshMembers();
|
||||||
}
|
}
|
||||||
@ -75,7 +68,7 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
{
|
{
|
||||||
if(member.rank === GroupRank.REQUESTED)
|
if(member.rank === GroupRank.REQUESTED)
|
||||||
{
|
{
|
||||||
SendMessageHook(new GroupMembershipDeclineComposer(pageData.groupId, member.id));
|
SendMessageHook(new GroupMembershipDeclineComposer(membersData.groupId, member.id));
|
||||||
|
|
||||||
refreshMembers();
|
refreshMembers();
|
||||||
|
|
||||||
@ -83,7 +76,7 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
setRemovingMemberName(member.name);
|
setRemovingMemberName(member.name);
|
||||||
SendMessageHook(new GroupConfirmRemoveMemberComposer(pageData.groupId, member.id));
|
SendMessageHook(new GroupConfirmRemoveMemberComposer(membersData.groupId, member.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
const onGroupMembersEvent = useCallback((event: GroupMembersEvent) =>
|
const onGroupMembersEvent = useCallback((event: GroupMembersEvent) =>
|
||||||
@ -92,8 +85,8 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
|
|
||||||
BatchUpdates(() =>
|
BatchUpdates(() =>
|
||||||
{
|
{
|
||||||
setPageData(parser);
|
setMembersData(parser);
|
||||||
//setSearchLevelId(parser.level);
|
setLevelId(parser.level);
|
||||||
setTotalPages(Math.ceil(parser.totalMembersCount / parser.pageSize));
|
setTotalPages(Math.ceil(parser.totalMembersCount / parser.pageSize));
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@ -106,26 +99,49 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
|
|
||||||
NotificationUtilities.confirm(LocalizeText(((parser.furnitureCount > 0) ? 'group.kickconfirm.desc' : 'group.kickconfirm_nofurni.desc'), [ 'user', 'amount' ], [ removingMemberName, parser.furnitureCount.toString() ]), () =>
|
NotificationUtilities.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));
|
SendMessageHook(new GroupRemoveMemberComposer(membersData.groupId, parser.userId));
|
||||||
|
|
||||||
refreshMembers();
|
refreshMembers();
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
setRemovingMemberName(null);
|
setRemovingMemberName(null);
|
||||||
}, [ pageData, removingMemberName, refreshMembers ]);
|
}, [ membersData, removingMemberName, refreshMembers ]);
|
||||||
|
|
||||||
CreateMessageHook(GroupConfirmMemberRemoveEvent, onGroupConfirmMemberRemoveEvent);
|
CreateMessageHook(GroupConfirmMemberRemoveEvent, onGroupConfirmMemberRemoveEvent);
|
||||||
|
|
||||||
|
const linkReceived = useCallback((url: string) =>
|
||||||
|
{
|
||||||
|
const parts = url.split('/');
|
||||||
|
|
||||||
|
if(parts.length < 2) return;
|
||||||
|
|
||||||
|
const groupId = (parseInt(parts[1]) || -1);
|
||||||
|
const levelId = (parseInt(parts[2]) || 3);
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setGroupId(groupId);
|
||||||
|
setLevelId(levelId);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
const linkTracker: ILinkEventTracker = {
|
||||||
|
linkReceived,
|
||||||
|
eventUrlPrefix: 'group-members/'
|
||||||
|
};
|
||||||
|
|
||||||
|
AddEventLinkTracker(linkTracker);
|
||||||
|
|
||||||
|
return () => RemoveLinkEventTracker(linkTracker);
|
||||||
|
}, [ linkReceived ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
setPageId(0);
|
setPageId(0);
|
||||||
}, [ groupId, levelId, searchQuery ]);
|
}, [ groupId, levelId, searchQuery ]);
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if((groupId === -1) || (levelId === -1) || (pageId === -1)) return;
|
if((groupId === -1) || (levelId === -1) || (pageId === -1)) return;
|
||||||
@ -133,15 +149,29 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
SendMessageHook(new GroupMembersComposer(groupId, pageId, searchQuery, levelId));
|
SendMessageHook(new GroupMembersComposer(groupId, pageId, searchQuery, levelId));
|
||||||
}, [ groupId, levelId, pageId, searchQuery ]);
|
}, [ groupId, levelId, pageId, searchQuery ]);
|
||||||
|
|
||||||
if(!groupId || !pageData) return null;
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(groupId === -1) return;
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setLevelId(-1);
|
||||||
|
setMembersData(null);
|
||||||
|
setTotalPages(0);
|
||||||
|
setSearchQuery('');
|
||||||
|
setRemovingMemberName(null);
|
||||||
|
})
|
||||||
|
}, [ groupId ]);
|
||||||
|
|
||||||
|
if((groupId === -1) || !membersData) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardView className="nitro-group-members" simple>
|
<NitroCardView className="nitro-group-members" simple>
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('group.members.title', ['groupName'], [ pageData ? pageData.groupTitle : '' ]) } onCloseClick={ onClose } />
|
<NitroCardHeaderView headerText={ LocalizeText('group.members.title', ['groupName'], [ membersData ? membersData.groupTitle : '' ]) } onCloseClick={ event => setGroupId(-1) } />
|
||||||
<NitroCardContentView overflow="hidden">
|
<NitroCardContentView overflow="hidden">
|
||||||
<Flex gap={ 2 }>
|
<Flex gap={ 2 }>
|
||||||
<Flex center className="group-badge">
|
<Flex center className="group-badge">
|
||||||
<BadgeImageView badgeCode={ pageData.badge } isGroup={ true } className="mx-auto d-block"/>
|
<BadgeImageView badgeCode={ membersData.badge } isGroup={ true } className="mx-auto d-block"/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Column fullWidth gap={ 1 }>
|
<Column fullWidth gap={ 1 }>
|
||||||
<input type="text" className="form-control form-control-sm w-100" placeholder={ LocalizeText('group.members.searchinfo') } value={ searchQuery } onChange={ event => setSearchQuery(event.target.value) } />
|
<input type="text" className="form-control form-control-sm w-100" placeholder={ LocalizeText('group.members.searchinfo') } value={ searchQuery } onChange={ event => setSearchQuery(event.target.value) } />
|
||||||
@ -153,7 +183,7 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Grid columnCount={ 2 } overflow="auto" className="nitro-group-members-list-grid">
|
<Grid columnCount={ 2 } overflow="auto" className="nitro-group-members-list-grid">
|
||||||
{ pageData.result.map((member, index) =>
|
{ membersData.result.map((member, index) =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Flex key={ index } gap={ 2 } alignItems="center" overflow="hidden" className="member-list-item bg-white rounded p-2">
|
<Flex key={ index } gap={ 2 } alignItems="center" overflow="hidden" className="member-list-item bg-white rounded p-2">
|
||||||
@ -168,13 +198,13 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
{ (member.rank !== GroupRank.REQUESTED) &&
|
{ (member.rank !== GroupRank.REQUESTED) &&
|
||||||
<Flex center>
|
<Flex center>
|
||||||
<i className={ 'icon icon-group-small-' + classNames({ 'owner': (member.rank === GroupRank.OWNER), 'admin': (member.rank === GroupRank.ADMIN), 'not-admin': (member.rank === GroupRank.MEMBER), 'cursor-pointer': pageData.admin }) } title={ LocalizeText(getRankDescription(member)) } onClick={ () => toggleAdmin(member) } />
|
<i className={ 'icon icon-group-small-' + classNames({ 'owner': (member.rank === GroupRank.OWNER), 'admin': (member.rank === GroupRank.ADMIN), 'not-admin': (member.rank === GroupRank.MEMBER), 'cursor-pointer': membersData.admin }) } title={ LocalizeText(getRankDescription(member)) } onClick={ () => toggleAdmin(member) } />
|
||||||
</Flex> }
|
</Flex> }
|
||||||
{ (member.rank === GroupRank.REQUESTED) &&
|
{ (member.rank === GroupRank.REQUESTED) &&
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="center">
|
||||||
<Base pointer className="nitro-friends-spritesheet icon-accept" title={ LocalizeText('group.members.accept') } onClick={ () => acceptMembership(member) }></Base>
|
<Base pointer className="nitro-friends-spritesheet icon-accept" title={ LocalizeText('group.members.accept') } onClick={ () => acceptMembership(member) }></Base>
|
||||||
</Flex> }
|
</Flex> }
|
||||||
{ (member.rank !== GroupRank.OWNER) && pageData.admin && (member.id !== GetSessionDataManager().userId) &&
|
{ (member.rank !== GroupRank.OWNER) && membersData.admin && (member.id !== GetSessionDataManager().userId) &&
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="center">
|
||||||
<Base pointer className="nitro-friends-spritesheet icon-deny" title={ LocalizeText(member.rank === GroupRank.REQUESTED ? 'group.members.reject' : 'group.members.kick') } onClick={ () => removeMemberOrDeclineMembership(member) }></Base>
|
<Base pointer className="nitro-friends-spritesheet icon-deny" title={ LocalizeText(member.rank === GroupRank.REQUESTED ? 'group.members.reject' : 'group.members.kick') } onClick={ () => removeMemberOrDeclineMembership(member) }></Base>
|
||||||
</Flex> }
|
</Flex> }
|
||||||
@ -184,13 +214,13 @@ export const GroupMembersView: FC<GroupMembersViewProps> = props =>
|
|||||||
}) }
|
}) }
|
||||||
</Grid>
|
</Grid>
|
||||||
<Flex gap={ 1 } justifyContent="between" alignItems="center">
|
<Flex gap={ 1 } justifyContent="between" alignItems="center">
|
||||||
<Button disabled={ (pageData.pageIndex === 0) } onClick={ previousPage }>
|
<Button disabled={ (membersData.pageIndex === 0) } onClick={ previousPage }>
|
||||||
<FontAwesomeIcon icon="chevron-left" />
|
<FontAwesomeIcon icon="chevron-left" />
|
||||||
</Button>
|
</Button>
|
||||||
<Text small>
|
<Text small>
|
||||||
{ LocalizeText('group.members.pageinfo', ['amount', 'page', 'totalPages'], [pageData.totalMembersCount.toString(), (pageData.pageIndex + 1).toString(), totalPages.toString()]) }
|
{ LocalizeText('group.members.pageinfo', ['amount', 'page', 'totalPages'], [membersData.totalMembersCount.toString(), (membersData.pageIndex + 1).toString(), totalPages.toString()]) }
|
||||||
</Text>
|
</Text>
|
||||||
<Button disabled={ (pageData.pageIndex === (totalPages - 1)) } onClick={ nextPage }>
|
<Button disabled={ (membersData.pageIndex === (totalPages - 1)) } onClick={ nextPage }>
|
||||||
<FontAwesomeIcon icon="chevron-right" />
|
<FontAwesomeIcon icon="chevron-right" />
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
149
src/components/groups/views/GroupRoomInformationView.tsx
Normal file
149
src/components/groups/views/GroupRoomInformationView.tsx
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { DesktopViewEvent, GetGuestRoomResultEvent, GroupInformationComposer, GroupInformationEvent, GroupInformationParser, GroupRemoveMemberComposer, HabboGroupDeactivatedMessageEvent, RoomEntryInfoMessageEvent } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import { GetGroupInformation, GetSessionDataManager, LocalizeText, TryJoinGroup } from '../../../api';
|
||||||
|
import { GetGroupManager } from '../../../api/groups/GetGroupManager';
|
||||||
|
import { Base, Button, Column, Flex, Text } from '../../../common';
|
||||||
|
import { CreateMessageHook, SendMessageHook } from '../../../hooks';
|
||||||
|
import { NotificationBubbleView } from '../../../layout';
|
||||||
|
import { NotificationUtilities } from '../../../views/notification-center/common/NotificationUtilities';
|
||||||
|
import { BadgeImageView } from '../../../views/shared/badge-image/BadgeImageView';
|
||||||
|
import { GroupMembershipType } from '../common/GroupMembershipType';
|
||||||
|
import { GroupType } from '../common/GroupType';
|
||||||
|
|
||||||
|
export const GroupRoomInformationView: FC<{}> = props =>
|
||||||
|
{
|
||||||
|
const [ expectedGroupId, setExpectedGroupId ] = useState<number>(0);
|
||||||
|
const [ groupInformation, setGroupInformation ] = useState<GroupInformationParser>(null);
|
||||||
|
const [ isOpen, setIsOpen ] = useState<boolean>(true);
|
||||||
|
|
||||||
|
const onDesktopViewEvent = useCallback((event: DesktopViewEvent) =>
|
||||||
|
{
|
||||||
|
setExpectedGroupId(0);
|
||||||
|
setGroupInformation(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(DesktopViewEvent, onDesktopViewEvent);
|
||||||
|
|
||||||
|
const onRoomEntryInfoMessageEvent = useCallback((event: RoomEntryInfoMessageEvent) =>
|
||||||
|
{
|
||||||
|
setExpectedGroupId(0);
|
||||||
|
setGroupInformation(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(RoomEntryInfoMessageEvent, onRoomEntryInfoMessageEvent);
|
||||||
|
|
||||||
|
const onGetGuestRoomResultEvent = useCallback((event: GetGuestRoomResultEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(!parser.roomEnter) return;
|
||||||
|
|
||||||
|
if(parser.data.habboGroupId > 0)
|
||||||
|
{
|
||||||
|
setExpectedGroupId(parser.data.habboGroupId);
|
||||||
|
SendMessageHook(new GroupInformationComposer(parser.data.habboGroupId, false));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setExpectedGroupId(0);
|
||||||
|
setGroupInformation(null);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(GetGuestRoomResultEvent, onGetGuestRoomResultEvent);
|
||||||
|
|
||||||
|
const onHabboGroupDeactivatedMessageEvent = useCallback((event: HabboGroupDeactivatedMessageEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(!groupInformation || ((parser.groupId !== groupInformation.id) && (parser.groupId !== expectedGroupId))) return;
|
||||||
|
|
||||||
|
setExpectedGroupId(0);
|
||||||
|
setGroupInformation(null);
|
||||||
|
}, [ expectedGroupId, groupInformation ]);
|
||||||
|
|
||||||
|
CreateMessageHook(HabboGroupDeactivatedMessageEvent, onHabboGroupDeactivatedMessageEvent);
|
||||||
|
|
||||||
|
const onGroupInformationEvent = useCallback((event: GroupInformationEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if(parser.id !== expectedGroupId) return;
|
||||||
|
|
||||||
|
setGroupInformation(parser);
|
||||||
|
}, [ expectedGroupId ]);
|
||||||
|
|
||||||
|
CreateMessageHook(GroupInformationEvent, onGroupInformationEvent);
|
||||||
|
|
||||||
|
const leaveGroup = () =>
|
||||||
|
{
|
||||||
|
NotificationUtilities.confirm(LocalizeText('group.leaveconfirm.desc'), () =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId));
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isRealOwner = (groupInformation && (groupInformation.ownerName === GetSessionDataManager().userName));
|
||||||
|
|
||||||
|
const getButtonText = () =>
|
||||||
|
{
|
||||||
|
if(isRealOwner) return 'group.manage';
|
||||||
|
|
||||||
|
if(groupInformation.type === GroupType.PRIVATE) return '';
|
||||||
|
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleButtonClick = () =>
|
||||||
|
{
|
||||||
|
if(isRealOwner) return GetGroupManager(groupInformation.id);
|
||||||
|
|
||||||
|
if((groupInformation.type === GroupType.PRIVATE) && (groupInformation.membershipType === GroupMembershipType.NOT_MEMBER)) return;
|
||||||
|
|
||||||
|
if(groupInformation.membershipType === GroupMembershipType.MEMBER)
|
||||||
|
{
|
||||||
|
leaveGroup();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TryJoinGroup(groupInformation.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!groupInformation) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NotificationBubbleView fadesOut={ false } close={ null }>
|
||||||
|
<Column>
|
||||||
|
<Flex alignItems="center" justifyContent="between" pointer onClick={ event => setIsOpen(value => !value) }>
|
||||||
|
<Text variant="white">{ LocalizeText('group.homeroominfo.title') }</Text>
|
||||||
|
<FontAwesomeIcon icon={ isOpen ? 'chevron-up' : 'chevron-down' } />
|
||||||
|
</Flex>
|
||||||
|
{ isOpen &&
|
||||||
|
<>
|
||||||
|
<Flex pointer alignItems="center" gap={ 2 } onClick={ event => GetGroupInformation(groupInformation.id) }>
|
||||||
|
<Base className="group-badge">
|
||||||
|
<BadgeImageView badgeCode={ groupInformation.badge } isGroup={ true } />
|
||||||
|
</Base>
|
||||||
|
<Text variant="white">{ groupInformation.title }</Text>
|
||||||
|
</Flex>
|
||||||
|
{ (groupInformation.type !== GroupType.PRIVATE || isRealOwner) &&
|
||||||
|
<Button fullWidth variant="success" disabled={ (groupInformation.membershipType === GroupMembershipType.REQUEST_PENDING) } onClick={ handleButtonClick }>
|
||||||
|
{ LocalizeText(getButtonText()) }
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
</> }
|
||||||
|
</Column>
|
||||||
|
</NotificationBubbleView>
|
||||||
|
);
|
||||||
|
};
|
@ -1,55 +0,0 @@
|
|||||||
import { FC, useCallback } from 'react';
|
|
||||||
import { LocalizeText } from '../../../../api';
|
|
||||||
import { BadgeImageView } from '../../../../views/shared/badge-image/BadgeImageView';
|
|
||||||
import { useGroupsContext } from '../../GroupsContext';
|
|
||||||
|
|
||||||
export const GroupCreatorTabConfirmationView: FC<{}> = props =>
|
|
||||||
{
|
|
||||||
const { groupsState = null, dispatchGroupsState = null } = useGroupsContext();
|
|
||||||
const { groupName = '', groupDescription = '', groupBadgeParts = null, groupColors = null, groupColorsA = null, groupColorsB = null, purchaseCost = 0 } = groupsState;
|
|
||||||
|
|
||||||
const getCompleteBadgeCode = useCallback(() =>
|
|
||||||
{
|
|
||||||
let code = '';
|
|
||||||
|
|
||||||
if(!groupBadgeParts) return code;
|
|
||||||
|
|
||||||
groupBadgeParts.forEach((badgePart) =>
|
|
||||||
{
|
|
||||||
if(badgePart.code) code = code + badgePart.code;
|
|
||||||
});
|
|
||||||
|
|
||||||
return code;
|
|
||||||
}, [ groupBadgeParts ]);
|
|
||||||
|
|
||||||
const getGroupColor = useCallback((colorIndex: number) =>
|
|
||||||
{
|
|
||||||
if(colorIndex === 0) return groupColorsA.find(c => c.id === groupColors[colorIndex]).color;
|
|
||||||
|
|
||||||
return groupColorsB.find(c => c.id === groupColors[colorIndex]).color;
|
|
||||||
}, [ groupColors, groupColorsA, groupColorsB ]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="d-flex gap-3 h-100">
|
|
||||||
<div>
|
|
||||||
<div className="fw-bold text-nowrap">{ LocalizeText('group.create.confirm.guildbadge') }</div>
|
|
||||||
<div className="badge-preview">
|
|
||||||
<BadgeImageView badgeCode={ getCompleteBadgeCode() } isGroup={ true } />
|
|
||||||
</div>
|
|
||||||
<div className="d-flex flex-column align-items-center mt-2">
|
|
||||||
<div className="fw-bold text-nowrap">{ LocalizeText('group.edit.color.guild.color') }</div>
|
|
||||||
{ groupColors && <div className="d-flex">
|
|
||||||
<div className="group-color-swatch" style={{ backgroundColor: '#' + getGroupColor(0) }}></div>
|
|
||||||
<div className="group-color-swatch" style={{ backgroundColor: '#' + getGroupColor(1) }}></div>
|
|
||||||
</div> }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="d-flex flex-column h-100">
|
|
||||||
<div className="fw-bold">{ groupName }</div>
|
|
||||||
<div>{ groupDescription }</div>
|
|
||||||
<div className="mt-3" dangerouslySetInnerHTML={ { __html: LocalizeText('group.create.confirm.info') } } />
|
|
||||||
<div className="mt-auto rounded bg-primary p-1 text-center text-white">{ LocalizeText('group.create.confirm.buyinfo', ['amount'], [purchaseCost.toString()]) }</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,52 +0,0 @@
|
|||||||
.nitro-group-creator {
|
|
||||||
width: $nitro-group-creator-width;
|
|
||||||
|
|
||||||
.creator-tabs {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.tab {
|
|
||||||
position: relative;
|
|
||||||
margin-left: -6px;
|
|
||||||
background-image: url('../../../../assets/images/groups/creator_tabs.png');
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.tab-blue-flat {
|
|
||||||
width: 84px;
|
|
||||||
height: 24px;
|
|
||||||
background-position: 0px 0px;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
height: 28px;
|
|
||||||
background-position: 0px -24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.tab-blue-arrow {
|
|
||||||
width: 83px;
|
|
||||||
height: 24px;
|
|
||||||
background-position: 0px -52px;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
height: 28px;
|
|
||||||
background-position: 0px -76px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.tab-yellow {
|
|
||||||
width: 133px;
|
|
||||||
height: 28px;
|
|
||||||
background-position: 0px -104px;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
height: 33px;
|
|
||||||
background-position: 0px -132px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,138 +0,0 @@
|
|||||||
import { GroupBuyComposer, GroupBuyDataComposer } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
|
||||||
import { HasHabboClub, LocalizeText } from '../../../../api';
|
|
||||||
import { Base, Button, Column, Flex, Text } from '../../../../common';
|
|
||||||
import { SendMessageHook } from '../../../../hooks';
|
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
|
|
||||||
import { NotificationUtilities } from '../../../../views/notification-center/common/NotificationUtilities';
|
|
||||||
import { useGroupsContext } from '../../GroupsContext';
|
|
||||||
import { GroupsActions } from '../../reducers/GroupsReducer';
|
|
||||||
import { GroupTabBadgeView } from '../tabs/GroupTabBadgeView';
|
|
||||||
import { GroupTabColorsView } from '../tabs/GroupTabColorsView';
|
|
||||||
import { GroupTabIdentityView } from '../tabs/GroupTabIdentityView';
|
|
||||||
import { GroupCreatorTabConfirmationView } from './GroupCreatorTabConfirmationView';
|
|
||||||
|
|
||||||
const TABS: number[] = [1, 2, 3, 4];
|
|
||||||
|
|
||||||
interface GroupCreatorViewProps
|
|
||||||
{
|
|
||||||
isVisible: boolean;
|
|
||||||
onClose: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GroupCreatorView: FC<GroupCreatorViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { isVisible = false, onClose = null } = props;
|
|
||||||
const [ currentTab, setCurrentTab ] = useState<number>(1);
|
|
||||||
const { groupsState = null, dispatchGroupsState = null } = useGroupsContext();
|
|
||||||
const { groupName = null, groupDescription = null, groupHomeroomId = null, groupColors = null, groupBadgeParts = null } = groupsState;
|
|
||||||
|
|
||||||
const buyGroup = useCallback(() =>
|
|
||||||
{
|
|
||||||
if(!groupBadgeParts) return;
|
|
||||||
|
|
||||||
const badge = [];
|
|
||||||
|
|
||||||
groupBadgeParts.forEach((part) =>
|
|
||||||
{
|
|
||||||
if(part.code)
|
|
||||||
{
|
|
||||||
badge.push(part.key);
|
|
||||||
badge.push(part.color);
|
|
||||||
badge.push(part.position);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
SendMessageHook(new GroupBuyComposer(groupName, groupDescription, groupHomeroomId, groupColors[0], groupColors[1], badge));
|
|
||||||
}, [ groupName, groupDescription, groupHomeroomId, groupColors, groupBadgeParts ]);
|
|
||||||
|
|
||||||
const previousStep = useCallback(() =>
|
|
||||||
{
|
|
||||||
if(currentTab === 1) return onClose();
|
|
||||||
|
|
||||||
setCurrentTab(value => value - 1);
|
|
||||||
}, [ currentTab, onClose ]);
|
|
||||||
|
|
||||||
const nextStep = useCallback(() =>
|
|
||||||
{
|
|
||||||
switch(currentTab)
|
|
||||||
{
|
|
||||||
case 1: {
|
|
||||||
if(!groupName || groupName.length === 0 || !groupHomeroomId)
|
|
||||||
{
|
|
||||||
NotificationUtilities.simpleAlert(LocalizeText('group.edit.error.no.name.or.room.selected'));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 4:
|
|
||||||
buyGroup();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
setCurrentTab(value => (value === 4 ? value : value + 1));
|
|
||||||
}, [ currentTab, groupName, groupHomeroomId, buyGroup ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if(!isVisible)
|
|
||||||
{
|
|
||||||
setCurrentTab(1);
|
|
||||||
|
|
||||||
dispatchGroupsState({
|
|
||||||
type: GroupsActions.RESET_GROUP_SETTINGS
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SendMessageHook(new GroupBuyDataComposer());
|
|
||||||
}, [ isVisible, dispatchGroupsState ]);
|
|
||||||
|
|
||||||
if(!isVisible) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NitroCardView className="nitro-group-creator" simple={ true }>
|
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('group.create.title') } onCloseClick={ onClose } />
|
|
||||||
<NitroCardContentView>
|
|
||||||
<Flex className="creator-tabs">
|
|
||||||
{ TABS.map((tab, index) =>
|
|
||||||
{
|
|
||||||
return (
|
|
||||||
<Flex center key={ index } className={ `tab tab-${ ((tab === 1) ? 'blue-flat' : (tab === 4) ? 'yellow' : 'blue-arrow') } ${ (currentTab === tab) ? 'active' : '' }` }>
|
|
||||||
<Text variant="white">{ LocalizeText(`group.create.steplabel.${ tab }`) }</Text>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}) }
|
|
||||||
</Flex>
|
|
||||||
<Flex alignItems="center" gap={ 2 }>
|
|
||||||
<Base className={ `nitro-group-tab-image tab-${ currentTab }`} />
|
|
||||||
<Column grow gap={ 0 }>
|
|
||||||
<Text bold fontSize={ 4 }>{ LocalizeText(`group.create.stepcaption.${ currentTab }`) }</Text>
|
|
||||||
<Text>{ LocalizeText(`group.create.stepdesc.${ currentTab }`) }</Text>
|
|
||||||
</Column>
|
|
||||||
</Flex>
|
|
||||||
<Column>
|
|
||||||
{ (currentTab === 1) &&
|
|
||||||
<GroupTabIdentityView isCreator={ true } /> }
|
|
||||||
{ (currentTab === 2) &&
|
|
||||||
<GroupTabBadgeView /> }
|
|
||||||
{ (currentTab === 3) &&
|
|
||||||
<GroupTabColorsView /> }
|
|
||||||
{ (currentTab === 4) &&
|
|
||||||
<GroupCreatorTabConfirmationView /> }
|
|
||||||
</Column>
|
|
||||||
<Flex justifyContent="between">
|
|
||||||
<Button variant="link" className="text-black" onClick={ previousStep }>
|
|
||||||
{ LocalizeText(currentTab === 1 ? 'generic.cancel' : 'group.create.previousstep') }
|
|
||||||
</Button>
|
|
||||||
<Button disabled={ ((currentTab === 4) && !HasHabboClub()) } variant={ ((currentTab === 4) ? HasHabboClub() ? 'success' : 'danger' : 'primary') } onClick={ nextStep }>
|
|
||||||
{ LocalizeText((currentTab === 4) ? HasHabboClub() ? 'group.create.confirm.buy' : 'group.create.confirm.viprequired' : 'group.create.nextstep') }
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
</NitroCardContentView>
|
|
||||||
</NitroCardView>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,4 +0,0 @@
|
|||||||
.nitro-group-manager {
|
|
||||||
height: $nitro-group-manager-height;
|
|
||||||
width: $nitro-group-manager-width;
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
import { GroupDeleteComposer, GroupSaveColorsComposer, GroupSaveInformationComposer, GroupSavePreferencesComposer } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useCallback, useState } from 'react';
|
|
||||||
import { LocalizeText } from '../../../../api';
|
|
||||||
import { Base, Button, Column, Flex, Text } from '../../../../common';
|
|
||||||
import { SendMessageHook } from '../../../../hooks';
|
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout';
|
|
||||||
import { useGroupsContext } from '../../GroupsContext';
|
|
||||||
import { GroupsActions } from '../../reducers/GroupsReducer';
|
|
||||||
import { GroupTabBadgeView } from '../tabs/GroupTabBadgeView';
|
|
||||||
import { GroupTabColorsView } from '../tabs/GroupTabColorsView';
|
|
||||||
import { GroupTabIdentityView } from '../tabs/GroupTabIdentityView';
|
|
||||||
import { GroupTabSettingsView } from '../tabs/GroupTabSettingsView';
|
|
||||||
|
|
||||||
const TABS: number[] = [1, 2, 3, 5];
|
|
||||||
|
|
||||||
export const GroupManagerView: FC<{}> = props =>
|
|
||||||
{
|
|
||||||
const { groupsState = null, dispatchGroupsState = null } = useGroupsContext();
|
|
||||||
const { groupId = null, groupName = null, groupDescription = null, groupColors = null, groupBadgeParts = null, groupState = null, groupCanMembersDecorate = null } = groupsState;
|
|
||||||
|
|
||||||
const [ currentTab, setCurrentTab ] = useState<number>(1);
|
|
||||||
|
|
||||||
const onClose = useCallback(() =>
|
|
||||||
{
|
|
||||||
dispatchGroupsState({
|
|
||||||
type: GroupsActions.RESET_GROUP_SETTINGS
|
|
||||||
});
|
|
||||||
}, [ dispatchGroupsState ]);
|
|
||||||
|
|
||||||
const saveGroup = useCallback(() =>
|
|
||||||
{
|
|
||||||
const badge = [];
|
|
||||||
|
|
||||||
if(!groupBadgeParts) return;
|
|
||||||
|
|
||||||
groupBadgeParts.forEach((part) =>
|
|
||||||
{
|
|
||||||
if(part.code)
|
|
||||||
{
|
|
||||||
badge.push(part.key);
|
|
||||||
badge.push(part.color);
|
|
||||||
badge.push(part.position);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
SendMessageHook(new GroupSaveInformationComposer(groupId, groupName, groupDescription));
|
|
||||||
//SendMessageHook(new GroupSaveBadgeComposer(groupId, badge));
|
|
||||||
SendMessageHook(new GroupSaveColorsComposer(groupId, groupColors[0], groupColors[1]));
|
|
||||||
SendMessageHook(new GroupSavePreferencesComposer(groupId, groupState, groupCanMembersDecorate ? 0 : 1));
|
|
||||||
|
|
||||||
onClose();
|
|
||||||
}, [ groupBadgeParts, groupId, groupName, groupDescription, groupColors, groupState, groupCanMembersDecorate, onClose ]);
|
|
||||||
|
|
||||||
const deleteGroup = useCallback(() =>
|
|
||||||
{
|
|
||||||
if(window.confirm(LocalizeText('group.deleteconfirm.title') + ' - ' + LocalizeText('group.deleteconfirm.desc')))
|
|
||||||
{
|
|
||||||
SendMessageHook(new GroupDeleteComposer(groupId));
|
|
||||||
onClose();
|
|
||||||
}
|
|
||||||
}, [ groupId, onClose ]);
|
|
||||||
|
|
||||||
if(!groupId) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NitroCardView className="nitro-group-manager" simple={ false }>
|
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('group.window.title') } onCloseClick={ onClose } />
|
|
||||||
<NitroCardTabsView>
|
|
||||||
{ TABS.map(tab =>
|
|
||||||
{
|
|
||||||
return (<NitroCardTabsItemView key={ tab } isActive={ currentTab === tab } onClick={ () => setCurrentTab(tab) }>
|
|
||||||
{ LocalizeText(`group.edit.tab.${tab}`) }
|
|
||||||
</NitroCardTabsItemView>);
|
|
||||||
}) }
|
|
||||||
</NitroCardTabsView>
|
|
||||||
<NitroCardContentView>
|
|
||||||
<Flex alignItems="center" gap={ 2 }>
|
|
||||||
<Base className={ `nitro-group-tab-image tab-${ currentTab }`} />
|
|
||||||
<Column grow gap={ 0 }>
|
|
||||||
<Text bold fontSize={ 4 }>{ LocalizeText(`group.edit.tabcaption.${ currentTab }`) }</Text>
|
|
||||||
<Text>{ LocalizeText(`group.edit.tabdesc.${ currentTab }`) }</Text>
|
|
||||||
</Column>
|
|
||||||
</Flex>
|
|
||||||
<Column grow overflow="hidden">
|
|
||||||
{ currentTab === 1 &&
|
|
||||||
<GroupTabIdentityView /> }
|
|
||||||
{ currentTab === 2 &&
|
|
||||||
<GroupTabBadgeView skipDefault={ true } /> }
|
|
||||||
{ currentTab === 3 &&
|
|
||||||
<GroupTabColorsView /> }
|
|
||||||
{ currentTab === 5 &&
|
|
||||||
<GroupTabSettingsView /> }
|
|
||||||
</Column>
|
|
||||||
<Flex justifyContent="between">
|
|
||||||
<Button variant="danger" onClick={ deleteGroup }>{ LocalizeText('group.delete') }</Button>
|
|
||||||
<Button variant="success" onClick={ saveGroup }>{ LocalizeText('save') }</Button>
|
|
||||||
</Flex>
|
|
||||||
</NitroCardContentView>
|
|
||||||
</NitroCardView>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,13 +0,0 @@
|
|||||||
.nitro-group-room-information {
|
|
||||||
pointer-events: all;
|
|
||||||
padding: 6px 5px;
|
|
||||||
background-color: rgba($dark,.95);
|
|
||||||
box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
|
|
||||||
font-size: $font-size-sm;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
|
|
||||||
.group-badge {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,129 +0,0 @@
|
|||||||
import { DesktopViewEvent, GetGuestRoomResultEvent, GroupInformationComposer, GroupInformationEvent, GroupInformationParser, GroupJoinComposer, GroupRemoveMemberComposer } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useCallback, useState } from 'react';
|
|
||||||
import { GetGroupInformation, GetSessionDataManager, LocalizeText } from '../../../../api';
|
|
||||||
import { GetGroupManager } from '../../../../api/groups/GetGroupManager';
|
|
||||||
import { CreateMessageHook, SendMessageHook } from '../../../../hooks';
|
|
||||||
import { BadgeImageView } from '../../../../views/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 onGetGuestRoomResultEvent = useCallback((event: GetGuestRoomResultEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
setGroupInformation(null);
|
|
||||||
|
|
||||||
if(parser.data.habboGroupId)
|
|
||||||
{
|
|
||||||
setGroupId(parser.data.habboGroupId);
|
|
||||||
SendMessageHook(new GroupInformationComposer(parser.data.habboGroupId, false));
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
CreateMessageHook(GetGuestRoomResultEvent, onGetGuestRoomResultEvent);
|
|
||||||
|
|
||||||
const onGroupInformationEvent = useCallback((event: GroupInformationEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
if(parser.flag || groupId !== parser.id) return;
|
|
||||||
console.log(parser);
|
|
||||||
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(() =>
|
|
||||||
{
|
|
||||||
if(window.confirm(LocalizeText('group.leaveconfirm.desc')))
|
|
||||||
{
|
|
||||||
SendMessageHook(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId));
|
|
||||||
SendMessageHook(new GroupInformationComposer(groupInformation.id, false));
|
|
||||||
}
|
|
||||||
}, [ groupInformation ]);
|
|
||||||
|
|
||||||
const getButtonText = useCallback(() =>
|
|
||||||
{
|
|
||||||
if(isRealOwner()) return 'group.manage';
|
|
||||||
|
|
||||||
if(groupInformation.type === GroupType.PRIVATE) return '';
|
|
||||||
|
|
||||||
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(isRealOwner()) return GetGroupManager(groupInformation.id);
|
|
||||||
|
|
||||||
if(groupInformation.type === GroupType.PRIVATE && groupInformation.membershipType === GroupMembershipType.NOT_MEMBER) return;
|
|
||||||
|
|
||||||
if(groupInformation.membershipType === GroupMembershipType.MEMBER) return tryLeaveGroup();
|
|
||||||
|
|
||||||
return tryJoinGroup();
|
|
||||||
}, [ groupInformation, tryLeaveGroup, tryJoinGroup, isRealOwner ]);
|
|
||||||
|
|
||||||
if(!groupInformation) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="nitro-group-room-information rounded">
|
|
||||||
<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(groupId) }>
|
|
||||||
<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-success w-100 mt-1" disabled={ groupInformation.membershipType === GroupMembershipType.REQUEST_PENDING } onClick={ handleButtonClick }>
|
|
||||||
{ LocalizeText(getButtonText()) }
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</> }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
.nitro-groups {
|
|
||||||
|
|
||||||
.group-color-swatch {
|
|
||||||
width: 30px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +1,26 @@
|
|||||||
import { GroupSaveBadgeComposer } from '@nitrots/nitro-renderer';
|
import { GroupSaveBadgeComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
|
||||||
import { Column, Flex, Grid } from '../../../../common';
|
import { Column, Flex, Grid } from '../../../../common';
|
||||||
import { SendMessageHook } from '../../../../hooks';
|
import { SendMessageHook } from '../../../../hooks';
|
||||||
import { BadgeImageView } from '../../../../views/shared/badge-image/BadgeImageView';
|
import { BadgeImageView } from '../../../../views/shared/badge-image/BadgeImageView';
|
||||||
import { GroupBadgePart } from '../../common/GroupBadgePart';
|
import { GroupBadgePart } from '../../common/GroupBadgePart';
|
||||||
|
import { IGroupData } from '../../common/IGroupData';
|
||||||
import { useGroupsContext } from '../../GroupsContext';
|
import { useGroupsContext } from '../../GroupsContext';
|
||||||
import { GroupsActions } from '../../reducers/GroupsReducer';
|
|
||||||
import { GroupBadgeCreatorView } from '../GroupBadgeCreatorView';
|
import { GroupBadgeCreatorView } from '../GroupBadgeCreatorView';
|
||||||
|
|
||||||
const POSITIONS: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8];
|
|
||||||
|
|
||||||
interface GroupTabBadgeViewProps
|
interface GroupTabBadgeViewProps
|
||||||
{
|
{
|
||||||
skipDefault?: boolean;
|
skipDefault?: boolean;
|
||||||
|
setCloseAction: Dispatch<SetStateAction<{ action: () => boolean }>>;
|
||||||
|
groupData: IGroupData;
|
||||||
|
setGroupData: Dispatch<SetStateAction<IGroupData>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GroupTabBadgeView: FC<GroupTabBadgeViewProps> = props =>
|
export const GroupTabBadgeView: FC<GroupTabBadgeViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { skipDefault = null } = props;
|
const { groupData = null, setGroupData = null, setCloseAction = null, skipDefault = null } = props;
|
||||||
const [ badgeParts, setBadgeParts ] = useState<GroupBadgePart[]>(null);
|
const [ badgeParts, setBadgeParts ] = useState<GroupBadgePart[]>(null);
|
||||||
const { groupsState = null, dispatchGroupsState = null } = useGroupsContext();
|
const { groupCustomize = null } = useGroupsContext();
|
||||||
const { badgeBases = null, badgeSymbols = null, badgePartColors = null, groupId = -1, groupBadgeParts = null } = groupsState;
|
|
||||||
|
|
||||||
const getModifiedBadgeCode = () =>
|
const getModifiedBadgeCode = () =>
|
||||||
{
|
{
|
||||||
@ -33,36 +33,29 @@ export const GroupTabBadgeView: FC<GroupTabBadgeViewProps> = props =>
|
|||||||
return badgeCode;
|
return badgeCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() =>
|
const saveBadge = useCallback(() =>
|
||||||
{
|
{
|
||||||
if(groupBadgeParts && groupBadgeParts.length) return;
|
if(!groupData || !badgeParts || !badgeParts.length) return false;
|
||||||
|
|
||||||
const badgeParts = [
|
if((groupData.groupBadgeParts === badgeParts)) return true;
|
||||||
new GroupBadgePart(GroupBadgePart.BASE, badgeBases[0].id, badgePartColors[0].id),
|
|
||||||
new GroupBadgePart(GroupBadgePart.SYMBOL, 0, badgePartColors[0].id),
|
|
||||||
new GroupBadgePart(GroupBadgePart.SYMBOL, 0, badgePartColors[0].id),
|
|
||||||
new GroupBadgePart(GroupBadgePart.SYMBOL, 0, badgePartColors[0].id),
|
|
||||||
new GroupBadgePart(GroupBadgePart.SYMBOL, 0, badgePartColors[0].id)
|
|
||||||
];
|
|
||||||
|
|
||||||
dispatchGroupsState({
|
if(groupData.groupId <= 0)
|
||||||
type: GroupsActions.SET_GROUP_BADGE_PARTS,
|
{
|
||||||
payload: { badgeParts }
|
setGroupData(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = { ...prevValue };
|
||||||
|
|
||||||
|
newValue.groupBadgeParts = badgeParts;
|
||||||
|
|
||||||
|
return newValue;
|
||||||
});
|
});
|
||||||
}, [ groupBadgeParts, badgeBases, badgePartColors, dispatchGroupsState ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
return true;
|
||||||
{
|
}
|
||||||
setBadgeParts(groupBadgeParts);
|
|
||||||
}, [ groupBadgeParts ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
if((groupId <= 0) || !badgeParts || !badgeParts.length || !groupBadgeParts || !groupBadgeParts.length || (badgeParts === groupBadgeParts)) return;
|
|
||||||
|
|
||||||
const badge = [];
|
const badge = [];
|
||||||
|
|
||||||
badgeParts.forEach((part) =>
|
badgeParts.forEach(part =>
|
||||||
{
|
{
|
||||||
if(!part.code) return;
|
if(!part.code) return;
|
||||||
|
|
||||||
@ -71,30 +64,49 @@ export const GroupTabBadgeView: FC<GroupTabBadgeViewProps> = props =>
|
|||||||
badge.push(part.position);
|
badge.push(part.position);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('send')
|
SendMessageHook(new GroupSaveBadgeComposer(groupData.groupId, badge));
|
||||||
|
|
||||||
SendMessageHook(new GroupSaveBadgeComposer(groupId, badge));
|
return true;
|
||||||
}, [ groupId, badgeParts, groupBadgeParts ]);
|
}, [ groupData, badgeParts, setGroupData ]);
|
||||||
|
|
||||||
// useEffect(() =>
|
useEffect(() =>
|
||||||
// {
|
{
|
||||||
// if((groupId <= 0) || !badgeParts || !badgeParts.length || (badgeParts === groupBadgeParts)) return;
|
if(groupData.groupBadgeParts) return;
|
||||||
|
|
||||||
// const badge = [];
|
const badgeParts = [
|
||||||
|
new GroupBadgePart(GroupBadgePart.BASE, groupCustomize.badgeBases[0].id, groupCustomize.badgePartColors[0].id),
|
||||||
|
new GroupBadgePart(GroupBadgePart.SYMBOL, 0, groupCustomize.badgePartColors[0].id),
|
||||||
|
new GroupBadgePart(GroupBadgePart.SYMBOL, 0, groupCustomize.badgePartColors[0].id),
|
||||||
|
new GroupBadgePart(GroupBadgePart.SYMBOL, 0, groupCustomize.badgePartColors[0].id),
|
||||||
|
new GroupBadgePart(GroupBadgePart.SYMBOL, 0, groupCustomize.badgePartColors[0].id)
|
||||||
|
];
|
||||||
|
|
||||||
// badgeParts.forEach((part) =>
|
setGroupData(prevValue =>
|
||||||
// {
|
{
|
||||||
// if(!part.code) return;
|
const groupBadgeParts = badgeParts;
|
||||||
|
|
||||||
// badge.push(part.key);
|
return { ...prevValue, groupBadgeParts };
|
||||||
// badge.push(part.color);
|
});
|
||||||
// badge.push(part.position);
|
}, [ groupData.groupBadgeParts, groupCustomize, setGroupData ]);
|
||||||
// });
|
|
||||||
|
|
||||||
// console.log('send')
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(groupData.groupId <= 0)
|
||||||
|
{
|
||||||
|
setBadgeParts(groupData.groupBadgeParts ? [ ...groupData.groupBadgeParts ] : null);
|
||||||
|
|
||||||
// SendMessageHook(new GroupSaveBadgeComposer(groupId, badge));
|
return;
|
||||||
// }, [ groupId, groupBadgeParts, badgeParts ]);
|
}
|
||||||
|
|
||||||
|
setBadgeParts(groupData.groupBadgeParts);
|
||||||
|
}, [ groupData ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
setCloseAction({ action: saveBadge });
|
||||||
|
|
||||||
|
return () => setCloseAction(null);
|
||||||
|
}, [ setCloseAction, saveBadge ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid overflow="hidden" gap={ 1 }>
|
<Grid overflow="hidden" gap={ 1 }>
|
||||||
|
@ -1,58 +1,107 @@
|
|||||||
|
import { GroupSaveColorsComposer } from '@nitrots/nitro-renderer';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { FC, useEffect } from 'react';
|
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
|
||||||
import { LocalizeText } from '../../../../api';
|
import { LocalizeText } from '../../../../api';
|
||||||
import { AutoGrid, Base, Column, Flex, Grid, Text } from '../../../../common';
|
import { AutoGrid, Base, Column, Flex, Grid, Text } from '../../../../common';
|
||||||
|
import { SendMessageHook } from '../../../../hooks';
|
||||||
|
import { IGroupData } from '../../common/IGroupData';
|
||||||
import { useGroupsContext } from '../../GroupsContext';
|
import { useGroupsContext } from '../../GroupsContext';
|
||||||
import { GroupsActions } from '../../reducers/GroupsReducer';
|
|
||||||
|
|
||||||
export const GroupTabColorsView: FC<{}> = props =>
|
interface GroupTabColorsViewProps
|
||||||
{
|
{
|
||||||
const { groupsState = null, dispatchGroupsState = null } = useGroupsContext();
|
groupData: IGroupData;
|
||||||
const { groupColors = null, groupColorsA = null, groupColorsB = null } = groupsState;
|
setGroupData: Dispatch<SetStateAction<IGroupData>>;
|
||||||
|
setCloseAction: Dispatch<SetStateAction<{ action: () => boolean }>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GroupTabColorsView: FC<GroupTabColorsViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { groupData = null, setGroupData = null, setCloseAction = null } = props;
|
||||||
|
const [ colors, setColors ] = useState<number[]>(null);
|
||||||
|
const { groupCustomize = null } = useGroupsContext();
|
||||||
|
|
||||||
const getGroupColor = (colorIndex: number) =>
|
const getGroupColor = (colorIndex: number) =>
|
||||||
{
|
{
|
||||||
if(colorIndex === 0) return groupColorsA.find(color => (color.id === groupColors[colorIndex])).color;
|
if(colorIndex === 0) return groupCustomize.groupColorsA.find(color => (color.id === colors[colorIndex])).color;
|
||||||
|
|
||||||
return groupColorsB.find(color => (color.id === groupColors[colorIndex])).color;
|
return groupCustomize.groupColorsB.find(color => (color.id === colors[colorIndex])).color;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectColor = (colorIndex: number, colorId: number) =>
|
const selectColor = (colorIndex: number, colorId: number) =>
|
||||||
{
|
{
|
||||||
const clonedGroupColors = Array.from(groupColors);
|
setColors(prevValue =>
|
||||||
|
{
|
||||||
|
const newColors = [ ...prevValue ];
|
||||||
|
|
||||||
clonedGroupColors[colorIndex] = colorId;
|
newColors[colorIndex] = colorId;
|
||||||
|
|
||||||
dispatchGroupsState({
|
return newColors;
|
||||||
type: GroupsActions.SET_GROUP_COLORS,
|
|
||||||
payload: {
|
|
||||||
objectValues: clonedGroupColors
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const saveColors = useCallback(() =>
|
||||||
|
{
|
||||||
|
if(!groupData || !colors || !colors.length) return false;
|
||||||
|
|
||||||
|
if(groupData.groupColors === colors) return true;
|
||||||
|
|
||||||
|
if(groupData.groupId <= 0)
|
||||||
|
{
|
||||||
|
setGroupData(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = { ...prevValue };
|
||||||
|
|
||||||
|
newValue.groupColors = [ ...colors ];
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendMessageHook(new GroupSaveColorsComposer(groupData.groupId, colors[0], colors[1]));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}, [ groupData, colors, setGroupData ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!groupColorsA || !groupColorsB || groupColors) return;
|
if(!groupCustomize.groupColorsA || !groupCustomize.groupColorsB || groupData.groupColors) return;
|
||||||
|
|
||||||
const colors: number[] = [
|
const groupColors = [ groupCustomize.groupColorsA[0].id, groupCustomize.groupColorsB[0].id ];
|
||||||
groupColorsA[0].id,
|
|
||||||
groupColorsB[0].id
|
|
||||||
];
|
|
||||||
|
|
||||||
dispatchGroupsState({
|
setGroupData(prevValue =>
|
||||||
type: GroupsActions.SET_GROUP_COLORS,
|
{
|
||||||
payload: {
|
return { ...prevValue, groupColors };
|
||||||
objectValues: colors
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}, [ dispatchGroupsState, groupColors, groupColorsA, groupColorsB ]);
|
}, [ groupCustomize, groupData.groupColors, setGroupData ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(groupData.groupId <= 0)
|
||||||
|
{
|
||||||
|
setColors(groupData.groupColors ? [ ...groupData.groupColors ] : null);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setColors(groupData.groupColors);
|
||||||
|
}, [ groupData ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
setCloseAction({ action: saveColors });
|
||||||
|
|
||||||
|
return () => setCloseAction(null);
|
||||||
|
}, [ setCloseAction, saveColors ]);
|
||||||
|
|
||||||
|
if(!colors) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid overflow="hidden">
|
<Grid overflow="hidden">
|
||||||
<Column size={ 2 } gap={ 1 }>
|
<Column size={ 2 } gap={ 1 }>
|
||||||
<Text bold>{ LocalizeText('group.edit.color.guild.color') }</Text>
|
<Text bold>{ LocalizeText('group.edit.color.guild.color') }</Text>
|
||||||
{ groupColors && (groupColors.length > 0) &&
|
{ groupData.groupColors && (groupData.groupColors.length > 0) &&
|
||||||
<Flex overflow="hidden" className="rounded border">
|
<Flex overflow="hidden" className="rounded border">
|
||||||
<Base className="group-color-swatch" style={{ backgroundColor: '#' + getGroupColor(0) }} />
|
<Base className="group-color-swatch" style={{ backgroundColor: '#' + getGroupColor(0) }} />
|
||||||
<Base className="group-color-swatch" style={{ backgroundColor: '#' + getGroupColor(1) }} />
|
<Base className="group-color-swatch" style={{ backgroundColor: '#' + getGroupColor(1) }} />
|
||||||
@ -61,18 +110,18 @@ export const GroupTabColorsView: FC<{}> = props =>
|
|||||||
<Column size={ 5 } gap={ 1 } overflow="hidden">
|
<Column size={ 5 } gap={ 1 } overflow="hidden">
|
||||||
<Text bold>{ LocalizeText('group.edit.color.primary.color') }</Text>
|
<Text bold>{ LocalizeText('group.edit.color.primary.color') }</Text>
|
||||||
<AutoGrid gap={ 1 } columnCount={ 7 } columnMinWidth={ 16 } columnMinHeight={ 16 }>
|
<AutoGrid gap={ 1 } columnCount={ 7 } columnMinWidth={ 16 } columnMinHeight={ 16 }>
|
||||||
{ groupColors && groupColorsA && groupColorsA.map((item, index) =>
|
{ groupData.groupColors && groupCustomize.groupColorsA && groupCustomize.groupColorsA.map((item, index) =>
|
||||||
{
|
{
|
||||||
return <div key={ index } className={ 'group-badge-color-swatch cursor-pointer' + classNames({ ' active': (groupColors[0] === item.id) }) } style={{ backgroundColor: '#' + item.color }} onClick={ () => selectColor(0, item.id) }></div>
|
return <div key={ index } className={ 'group-badge-color-swatch cursor-pointer' + classNames({ ' active': (groupData.groupColors[0] === item.id) }) } style={{ backgroundColor: '#' + item.color }} onClick={ () => selectColor(0, item.id) }></div>
|
||||||
}) }
|
}) }
|
||||||
</AutoGrid>
|
</AutoGrid>
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 5 } gap={ 1 } overflow="hidden">
|
<Column size={ 5 } gap={ 1 } overflow="hidden">
|
||||||
<Text bold>{ LocalizeText('group.edit.color.secondary.color') }</Text>
|
<Text bold>{ LocalizeText('group.edit.color.secondary.color') }</Text>
|
||||||
<AutoGrid gap={ 1 } columnCount={ 7 } columnMinWidth={ 16 } columnMinHeight={ 16 }>
|
<AutoGrid gap={ 1 } columnCount={ 7 } columnMinWidth={ 16 } columnMinHeight={ 16 }>
|
||||||
{ groupColorsB && groupColorsB.map((item, index) =>
|
{ groupData.groupColors && groupCustomize.groupColorsB && groupCustomize.groupColorsB.map((item, index) =>
|
||||||
{
|
{
|
||||||
return <div key={ index } className={ 'group-badge-color-swatch cursor-pointer' + classNames({ ' active': (groupColors[1] === item.id) }) } style={{ backgroundColor: '#' + item.color }} onClick={ () => selectColor(1, item.id) }></div>
|
return <div key={ index } className={ 'group-badge-color-swatch cursor-pointer' + classNames({ ' active': (groupData.groupColors[1] === item.id) }) } style={{ backgroundColor: '#' + item.color }} onClick={ () => selectColor(1, item.id) }></div>
|
||||||
}) }
|
}) }
|
||||||
</AutoGrid>
|
</AutoGrid>
|
||||||
</Column>
|
</Column>
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
import { Dispatch, FC, SetStateAction } from 'react';
|
||||||
|
import { LocalizeText } from '../../../../api';
|
||||||
|
import { Base, Column, Flex, Grid, Text } from '../../../../common';
|
||||||
|
import { BadgeImageView } from '../../../../views/shared/badge-image/BadgeImageView';
|
||||||
|
import { IGroupData } from '../../common/IGroupData';
|
||||||
|
import { useGroupsContext } from '../../GroupsContext';
|
||||||
|
|
||||||
|
interface GroupTabCreatorConfirmationViewProps
|
||||||
|
{
|
||||||
|
groupData: IGroupData;
|
||||||
|
setGroupData: Dispatch<SetStateAction<IGroupData>>;
|
||||||
|
purchaseCost: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GroupTabCreatorConfirmationView: FC<GroupTabCreatorConfirmationViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { groupData = null, setGroupData = null, purchaseCost = 0 } = props;
|
||||||
|
const { groupCustomize = null } = useGroupsContext();
|
||||||
|
|
||||||
|
const getCompleteBadgeCode = () =>
|
||||||
|
{
|
||||||
|
if(!groupData || !groupData.groupBadgeParts || !groupData.groupBadgeParts.length) return '';
|
||||||
|
|
||||||
|
let badgeCode = '';
|
||||||
|
|
||||||
|
groupData.groupBadgeParts.forEach(part => (part.code && (badgeCode += part.code)));
|
||||||
|
|
||||||
|
return badgeCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getGroupColor = (colorIndex: number) =>
|
||||||
|
{
|
||||||
|
if(colorIndex === 0) return groupCustomize.groupColorsA.find(c => c.id === groupData.groupColors[colorIndex]).color;
|
||||||
|
|
||||||
|
return groupCustomize.groupColorsB.find(c => c.id === groupData.groupColors[colorIndex]).color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!groupData) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid overflow="hidden" gap={ 1 }>
|
||||||
|
<Column size={ 3 }>
|
||||||
|
<Column center className="bg-muted rounded p-1" gap={ 2 }>
|
||||||
|
<Text bold center>{ LocalizeText('group.create.confirm.guildbadge') }</Text>
|
||||||
|
<BadgeImageView badgeCode={ getCompleteBadgeCode() } isGroup={ true } />
|
||||||
|
</Column>
|
||||||
|
<Column center className="bg-muted rounded p-1" gap={ 2 }>
|
||||||
|
<Text bold center>{ LocalizeText('group.edit.color.guild.color') }</Text>
|
||||||
|
<Flex overflow="hidden" className="rounded border">
|
||||||
|
<Base className="group-color-swatch" style={{ backgroundColor: '#' + getGroupColor(0) }} />
|
||||||
|
<Base className="group-color-swatch" style={{ backgroundColor: '#' + getGroupColor(1) }} />
|
||||||
|
</Flex>
|
||||||
|
</Column>
|
||||||
|
</Column>
|
||||||
|
<Column size={ 9 } justifyContent="between">
|
||||||
|
<Column>
|
||||||
|
<Column gap={ 1 }>
|
||||||
|
<Text bold>{ groupData.groupName }</Text>
|
||||||
|
<Text>{ groupData.groupDescription }</Text>
|
||||||
|
</Column>
|
||||||
|
<Text overflow="auto">{ LocalizeText('group.create.confirm.info') }</Text>
|
||||||
|
</Column>
|
||||||
|
<Text center variant="white" className="bg-primary rounded p-1">
|
||||||
|
{ LocalizeText('group.create.confirm.buyinfo', [ 'amount' ], [ purchaseCost.toString() ]) }
|
||||||
|
</Text>
|
||||||
|
</Column>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
};
|
@ -1,75 +1,117 @@
|
|||||||
import { FC } from 'react';
|
import { GroupDeleteComposer, GroupSaveInformationComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
|
||||||
import { CreateLinkEvent, LocalizeText } from '../../../../api';
|
import { CreateLinkEvent, LocalizeText } from '../../../../api';
|
||||||
import { Column, Flex, Text } from '../../../../common';
|
import { Base, Button, Column, Flex, Text } from '../../../../common';
|
||||||
import { useGroupsContext } from '../../GroupsContext';
|
import { BatchUpdates, SendMessageHook } from '../../../../hooks';
|
||||||
import { GroupsActions } from '../../reducers/GroupsReducer';
|
import { NotificationUtilities } from '../../../../views/notification-center/common/NotificationUtilities';
|
||||||
|
import { IGroupData } from '../../common/IGroupData';
|
||||||
|
|
||||||
interface GroupTabIdentityViewProps
|
interface GroupTabIdentityViewProps
|
||||||
{
|
{
|
||||||
|
groupData: IGroupData;
|
||||||
|
setGroupData: Dispatch<SetStateAction<IGroupData>>;
|
||||||
|
setCloseAction: Dispatch<SetStateAction<{ action: () => boolean }>>;
|
||||||
isCreator?: boolean;
|
isCreator?: boolean;
|
||||||
|
availableRooms?: { id: number, name: string }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GroupTabIdentityView: FC<GroupTabIdentityViewProps> = props =>
|
export const GroupTabIdentityView: FC<GroupTabIdentityViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { isCreator = false } = props;
|
const { groupData = null, setGroupData = null, setCloseAction = null, isCreator = false, availableRooms = [] } = props;
|
||||||
const { groupsState = null, dispatchGroupsState = null } = useGroupsContext();
|
const [ groupName, setGroupName ] = useState<string>('');
|
||||||
const { groupName = '', groupDescription = '', groupHomeroomId = 0, availableRooms = null } = groupsState;
|
const [ groupDescription, setGroupDescription ] = useState<string>('');
|
||||||
|
const [ groupHomeroomId, setGroupHomeroomId ] = useState<number>(-1);
|
||||||
|
|
||||||
const setName = (name: string) =>
|
const deleteGroup = () =>
|
||||||
{
|
{
|
||||||
dispatchGroupsState({
|
if(!groupData || (groupData.groupId <= 0)) return;
|
||||||
type: GroupsActions.SET_GROUP_NAME,
|
|
||||||
payload: {
|
NotificationUtilities.confirm(LocalizeText('group.deleteconfirm.desc'), () =>
|
||||||
stringValues: [ name ]
|
{
|
||||||
}
|
SendMessageHook(new GroupDeleteComposer(groupData.groupId));
|
||||||
})
|
}, null, null, null, LocalizeText('group.deleteconfirm.title'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const setDescription = (description: string) =>
|
const saveIdentity = useCallback(() =>
|
||||||
{
|
{
|
||||||
dispatchGroupsState({
|
if(!groupData || !groupName || !groupName.length) return false;
|
||||||
type: GroupsActions.SET_GROUP_DESCRIPTION,
|
|
||||||
payload: {
|
if((groupName === groupData.groupName) && (groupDescription === groupData.groupDescription)) return true;
|
||||||
stringValues: [ description ]
|
|
||||||
}
|
if(groupData.groupId <= 0)
|
||||||
})
|
{
|
||||||
|
if(groupHomeroomId <= 0) return false;
|
||||||
|
|
||||||
|
setGroupData(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = { ...prevValue };
|
||||||
|
|
||||||
|
newValue.groupName = groupName;
|
||||||
|
newValue.groupDescription = groupDescription;
|
||||||
|
newValue.groupHomeroomId = groupHomeroomId;
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const setHomeroomId = (id: number) =>
|
SendMessageHook(new GroupSaveInformationComposer(groupData.groupId, groupName, (groupDescription || '')));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}, [ groupData, groupName, groupDescription, groupHomeroomId, setGroupData ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
dispatchGroupsState({
|
BatchUpdates(() =>
|
||||||
type: GroupsActions.SET_GROUP_HOMEROOM_ID,
|
{
|
||||||
payload: {
|
setGroupName(groupData.groupName || '');
|
||||||
numberValues: [ id ]
|
setGroupDescription(groupData.groupDescription || '');
|
||||||
}
|
setGroupHomeroomId(groupData.groupHomeroomId);
|
||||||
})
|
});
|
||||||
}
|
}, [ groupData ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
setCloseAction({ action: saveIdentity });
|
||||||
|
|
||||||
|
return () => setCloseAction(null);
|
||||||
|
}, [ setCloseAction, saveIdentity ]);
|
||||||
|
|
||||||
|
if(!groupData) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Column justifyContent="between" overflow="auto">
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
<Text className="col-3">{ LocalizeText('group.edit.name') }</Text>
|
<Text center className="col-3">{ LocalizeText('group.edit.name') }</Text>
|
||||||
<input type="text" className="form-control form-control-sm" value={ groupName } maxLength={ 29 } onChange={ event => setName(event.target.value) } />
|
<input type="text" className="form-control form-control-sm" value={ groupName } maxLength={ 29 } onChange={ event => setGroupName(event.target.value) } />
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
<Text className="col-3">{ LocalizeText('group.edit.desc') }</Text>
|
<Text center className="col-3">{ LocalizeText('group.edit.desc') }</Text>
|
||||||
<textarea className="form-control form-control-sm" value={ groupDescription } maxLength={ 254 } onChange={ event => setDescription(event.target.value) } />
|
<textarea className="form-control form-control-sm" value={ groupDescription } maxLength={ 254 } onChange={ event => setGroupDescription(event.target.value) } />
|
||||||
</Flex>
|
</Flex>
|
||||||
{ isCreator &&
|
{ isCreator &&
|
||||||
<Flex gap={ 1 }>
|
<>
|
||||||
<Text className="col-3">{ LocalizeText('group.edit.base') }</Text>
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
<Column gap={ 1 }>
|
<Text center className="col-3">{ LocalizeText('group.edit.base') }</Text>
|
||||||
<select className="form-select form-select-sm" value={ groupHomeroomId } onChange={ event => setHomeroomId(Number(event.target.value)) }>
|
<Column fullWidth gap={ 1 }>
|
||||||
<option value={ 0 } disabled>{ LocalizeText('group.edit.base.select.room') }</option>
|
<select className="form-select form-select-sm" value={ groupHomeroomId } onChange={ event => setGroupHomeroomId(parseInt(event.target.value)) }>
|
||||||
|
<option value={ -1 } disabled>{ LocalizeText('group.edit.base.select.room') }</option>
|
||||||
{ availableRooms && availableRooms.map((room, index) => <option key={ index } value={ room.id }>{ room.name }</option>) }
|
{ availableRooms && availableRooms.map((room, index) => <option key={ index } value={ room.id }>{ room.name }</option>) }
|
||||||
</select>
|
</select>
|
||||||
|
</Column>
|
||||||
|
</Flex>
|
||||||
|
<Flex gap={ 1 }>
|
||||||
|
<Base className="col-3"> </Base>
|
||||||
<Text small>{ LocalizeText('group.edit.base.warning') }</Text>
|
<Text small>{ LocalizeText('group.edit.base.warning') }</Text>
|
||||||
|
</Flex>
|
||||||
|
</> }
|
||||||
</Column>
|
</Column>
|
||||||
</Flex> }
|
{ !isCreator &&
|
||||||
</Column>
|
<Button variant="danger" onClick={ deleteGroup }>{ LocalizeText('group.delete') }</Button> }
|
||||||
{ isCreator &&
|
{ isCreator &&
|
||||||
<Text underline center fullWidth pointer onClick={ event => CreateLinkEvent('navigator/create') }>{ LocalizeText('group.createroom') }</Text> }
|
<Text underline center fullWidth pointer onClick={ event => CreateLinkEvent('navigator/create') }>{ LocalizeText('group.createroom') }</Text> }
|
||||||
</>
|
</Column>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,35 +1,66 @@
|
|||||||
import { FC } from 'react';
|
import { GroupSavePreferencesComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
|
||||||
import { LocalizeText } from '../../../../api/utils/LocalizeText';
|
import { LocalizeText } from '../../../../api/utils/LocalizeText';
|
||||||
import { Column, Flex, HorizontalRule, Text } from '../../../../common';
|
import { Column, Flex, HorizontalRule, Text } from '../../../../common';
|
||||||
import { useGroupsContext } from '../../GroupsContext';
|
import { BatchUpdates, SendMessageHook } from '../../../../hooks';
|
||||||
import { GroupsActions } from '../../reducers/GroupsReducer';
|
import { IGroupData } from '../../common/IGroupData';
|
||||||
|
|
||||||
const STATES: string[] = ['regular', 'exclusive', 'private'];
|
const STATES: string[] = [ 'regular', 'exclusive', 'private' ];
|
||||||
|
|
||||||
export const GroupTabSettingsView: FC<{}> = props =>
|
interface GroupTabSettingsViewProps
|
||||||
{
|
{
|
||||||
const { groupsState = null, dispatchGroupsState = null } = useGroupsContext();
|
groupData: IGroupData;
|
||||||
const { groupState = null, groupCanMembersDecorate = false } = groupsState;
|
setGroupData: Dispatch<SetStateAction<IGroupData>>;
|
||||||
|
setCloseAction: Dispatch<SetStateAction<{ action: () => boolean }>>;
|
||||||
|
}
|
||||||
|
|
||||||
const setState = (state: number) =>
|
export const GroupTabSettingsView: FC<GroupTabSettingsViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { groupData = null, setGroupData = null, setCloseAction = null } = props;
|
||||||
|
const [ groupState, setGroupState ] = useState<number>(groupData.groupState);
|
||||||
|
const [ groupDecorate, setGroupDecorate ] = useState<boolean>(groupData.groupCanMembersDecorate);
|
||||||
|
|
||||||
|
const saveSettings = useCallback(() =>
|
||||||
{
|
{
|
||||||
dispatchGroupsState({
|
if(!groupData) return false;
|
||||||
type: GroupsActions.SET_GROUP_STATE,
|
|
||||||
payload: {
|
if((groupState === groupData.groupState) && (groupDecorate === groupData.groupCanMembersDecorate)) return true;
|
||||||
numberValues: [ state ]
|
|
||||||
}
|
if(groupData.groupId <= 0)
|
||||||
})
|
{
|
||||||
|
setGroupData(prevValue =>
|
||||||
|
{
|
||||||
|
const newValue = { ...prevValue };
|
||||||
|
|
||||||
|
newValue.groupState = groupState;
|
||||||
|
newValue.groupCanMembersDecorate = groupDecorate;
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleCanMembersDecorate = () =>
|
SendMessageHook(new GroupSavePreferencesComposer(groupData.groupId, groupState, groupDecorate ? 0 : 1));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}, [ groupData, groupState, groupDecorate, setGroupData ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
dispatchGroupsState({
|
BatchUpdates(() =>
|
||||||
type: GroupsActions.SET_GROUP_CAN_MEMBERS_DECORATE,
|
{
|
||||||
payload: {
|
setGroupState(groupData.groupState);
|
||||||
boolValues: [ !groupCanMembersDecorate ]
|
setGroupDecorate(groupData.groupCanMembersDecorate);
|
||||||
}
|
});
|
||||||
})
|
}, [ groupData ]);
|
||||||
}
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
setCloseAction({ action: saveSettings });
|
||||||
|
|
||||||
|
return () => setCloseAction(null);
|
||||||
|
}, [ setCloseAction, saveSettings ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column overflow="auto">
|
<Column overflow="auto">
|
||||||
@ -38,13 +69,13 @@ export const GroupTabSettingsView: FC<{}> = props =>
|
|||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Flex key={ index } alignItems="center" gap={ 1 }>
|
<Flex key={ index } alignItems="center" gap={ 1 }>
|
||||||
<input className="form-check-input" type="radio" name="groupState" checked={ (groupState === index) } onChange={ event => setState(index) } />
|
<input className="form-check-input" type="radio" name="groupState" checked={ (groupState === index) } onChange={ event => setGroupState(index) } />
|
||||||
<Column gap={ 0 }>
|
<Column gap={ 0 }>
|
||||||
<Flex gap={ 1 }>
|
<Flex gap={ 1 }>
|
||||||
<i className={ `icon icon-group-type-${index}` } />
|
<i className={ `icon icon-group-type-${ index }` } />
|
||||||
<Text bold>{ LocalizeText(`group.edit.settings.type.${state}.label`) }</Text>
|
<Text bold>{ LocalizeText(`group.edit.settings.type.${ state }.label`) }</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Text>{ LocalizeText(`group.edit.settings.type.${state}.help`) }</Text>
|
<Text>{ LocalizeText(`group.edit.settings.type.${ state }.help`) }</Text>
|
||||||
</Column>
|
</Column>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
@ -52,7 +83,7 @@ export const GroupTabSettingsView: FC<{}> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
<HorizontalRule />
|
<HorizontalRule />
|
||||||
<Flex alignItems="center" gap={ 1 }>
|
<Flex alignItems="center" gap={ 1 }>
|
||||||
<input className="form-check-input" type="checkbox" checked={ groupCanMembersDecorate } onChange={() => toggleCanMembersDecorate() } />
|
<input className="form-check-input" type="checkbox" checked={ groupDecorate } onChange={ event => setGroupDecorate(prevValue => !prevValue) } />
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Text bold>{ LocalizeText('group.edit.settings.rights.caption') }</Text>
|
<Text bold>{ LocalizeText('group.edit.settings.rights.caption') }</Text>
|
||||||
<Text>{ LocalizeText('group.edit.settings.rights.members.help') }</Text>
|
<Text>{ LocalizeText('group.edit.settings.rights.members.help') }</Text>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { Column } from '../../common';
|
import { Column } from '../../common';
|
||||||
import { NotificationCenterView } from '../../views/notification-center/NotificationCenterView';
|
import { NotificationCenterView } from '../../views/notification-center/NotificationCenterView';
|
||||||
import { GroupRoomInformationView } from '../groups/views/room-information/GroupRoomInformationView';
|
import { GroupRoomInformationView } from '../groups/views/GroupRoomInformationView';
|
||||||
import { PurseView } from '../purse/PurseView';
|
import { PurseView } from '../purse/PurseView';
|
||||||
|
|
||||||
export const RightSideView: FC<{}> = props =>
|
export const RightSideView: FC<{}> = props =>
|
||||||
|
@ -3,7 +3,7 @@ import classNames from 'classnames';
|
|||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { CreateMessageHook, SendMessageHook } from '../../../hooks';
|
import { CreateMessageHook, SendMessageHook } from '../../../hooks';
|
||||||
import { BadgeImageView } from '../../../views/shared/badge-image/BadgeImageView';
|
import { BadgeImageView } from '../../../views/shared/badge-image/BadgeImageView';
|
||||||
import { GroupInformationView } from '../../groups/views/information/GroupInformationView';
|
import { GroupInformationView } from '../../groups/views/GroupInformationView';
|
||||||
|
|
||||||
interface GroupsContainerViewProps
|
interface GroupsContainerViewProps
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user