diff --git a/src/assets/styles/bootstrap/_variables.scss b/src/assets/styles/bootstrap/_variables.scss index a53ad2b2..842ab815 100644 --- a/src/assets/styles/bootstrap/_variables.scss +++ b/src/assets/styles/bootstrap/_variables.scss @@ -390,7 +390,7 @@ $container-max-widths: ( $grid-columns: 12 !default; $grid-gutter-width: 16px !default; -$grid-row-columns: 6 !default; +$grid-row-columns: 18 !default; $gutters: $spacers !default; diff --git a/src/layout/card/grid/NitroCardGridView.scss b/src/layout/card/grid/NitroCardGridView.scss index a924d2ce..f5794406 100644 --- a/src/layout/card/grid/NitroCardGridView.scss +++ b/src/layout/card/grid/NitroCardGridView.scss @@ -34,5 +34,38 @@ } } + .row-cols-6 { + + .col { + padding-right: 0.25rem; + + &:nth-child(6n+6) { + padding-right: 0; + } + } + } + + .row-cols-7 { + + .col { + padding-right: 0.25rem; + + &:nth-child(7n+7) { + padding-right: 0; + } + } + } + + .row-cols-8 { + + .col { + padding-right: 0.25rem; + + &:nth-child(8n+8) { + padding-right: 0; + } + } + } + @import './item/NitroCardGridItemView.scss'; } diff --git a/src/views/groups/GroupView.scss b/src/views/groups/GroupView.scss index acfe8f77..354f6406 100644 --- a/src/views/groups/GroupView.scss +++ b/src/views/groups/GroupView.scss @@ -2,3 +2,4 @@ @import './views/information/GroupInformationView'; @import './views/information-standalone/GroupInformationStandaloneView'; @import './views/room-information/GroupRoomInformationView'; +@import './views/shared-tabs/GroupSharedTabs'; diff --git a/src/views/groups/GroupsMessageHandler.tsx b/src/views/groups/GroupsMessageHandler.tsx index 54299d25..2a57ca9d 100644 --- a/src/views/groups/GroupsMessageHandler.tsx +++ b/src/views/groups/GroupsMessageHandler.tsx @@ -1,26 +1,112 @@ -import { GroupBadgePartsEvent } from '@nitrots/nitro-renderer'; +import { GroupBadgePartsEvent, GroupBuyDataEvent, RoomCreatedEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; import { CreateMessageHook } from '../../hooks'; import { useGroupsContext } from './context/GroupsContext'; import { GroupsActions } from './context/GroupsContext.types'; +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: { + objectArrays: rooms, + numberValue: 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: { + objectArrays: clonedRooms + } + }); + }, []); + 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_BADGE_PARTS, + type: GroupsActions.SET_GROUP_BADGE_PARTS_CONFIG, payload: { - arrayMaps: [ parser.bases, parser.symbols ], - stringMaps: [ parser.partColors, parser.colorsA, parser.colorsB ] + objectArrays: [ bases, symbols, partColors, colorsA, colorsB ] } }) }, [ dispatchGroupsState ]); + CreateMessageHook(GroupBuyDataEvent, onGroupBuyDataEvent); + CreateMessageHook(RoomCreatedEvent, onRoomCreatedEvent); CreateMessageHook(GroupBadgePartsEvent, onGroupBadgePartsEvent); return null; diff --git a/src/views/groups/GroupsView.tsx b/src/views/groups/GroupsView.tsx index bdfc443a..e4b9af32 100644 --- a/src/views/groups/GroupsView.tsx +++ b/src/views/groups/GroupsView.tsx @@ -1,7 +1,7 @@ -import { GroupBadgePartsComposer, ILinkEventTracker } from '@nitrots/nitro-renderer'; +import { GroupBadgePartsComposer, GroupPurchasedEvent, ILinkEventTracker } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; -import { AddEventLinkTracker, RemoveLinkEventTracker } from '../../api'; -import { SendMessageHook } from '../../hooks'; +import { AddEventLinkTracker, RemoveLinkEventTracker, TryVisitRoom } from '../../api'; +import { CreateMessageHook, SendMessageHook } from '../../hooks'; import { GroupsContextProvider } from './context/GroupsContext'; import { GroupsReducer, initialGroups } from './context/GroupsContext.types'; import { GroupsMessageHandler } from './GroupsMessageHandler'; @@ -44,12 +44,24 @@ export const GroupsView: FC<{}> = props => return () => RemoveLinkEventTracker(linkTracker); }, [ linkReceived ]); + + const onGroupPurchasedEvent = useCallback((event: GroupPurchasedEvent) => + { + const parser = event.getParser(); + + setIsCreatorVisible(false); + TryVisitRoom(parser.roomId); + }, []); + + CreateMessageHook(GroupPurchasedEvent, onGroupPurchasedEvent); return ( +
setIsCreatorVisible(false) } /> +
); }; diff --git a/src/views/groups/common/GroupBadgePart.ts b/src/views/groups/common/GroupBadgePart.ts index 03338223..d6846d86 100644 --- a/src/views/groups/common/GroupBadgePart.ts +++ b/src/views/groups/common/GroupBadgePart.ts @@ -9,18 +9,23 @@ export class GroupBadgePart public color: number; public position: number; - constructor(type: string) + constructor(type: string, key?: number, color?: number, position?: number) { this.type = type; - this.key = 0; - this.color = 0; - this.position = 4; + this.key = key ? key : 0; + this.color = color ? color : 0; + this.position = position ? position : 4; } public get code(): string { if(this.key === 0) return null; - return this.type + (this.key < 10 ? '0' : '') + this.key + (this.color < 10 ? '0' : '') + this.color + (this.type === GroupBadgePart.BASE ? '' : this.position); + return GroupBadgePart.getCode(this.type, this.key, this.color, this.position); + } + + public static getCode(type: string, key: number, color: number, position: number): string + { + return (type === GroupBadgePart.BASE ? type : key >= 100 ? GroupBadgePart.SYMBOL_ALT : GroupBadgePart.SYMBOL) + (key < 10 ? '0' : '') + (type === GroupBadgePart.BASE ? key : key >= 100 ? key - 100 : key) + (color < 10 ? '0' : '') + color + position; } } diff --git a/src/views/groups/common/GroupSettings.ts b/src/views/groups/common/GroupSettings.ts deleted file mode 100644 index cf1e4ae3..00000000 --- a/src/views/groups/common/GroupSettings.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { GroupBadgePart } from './GroupBadgePart'; - -export class GroupSettings -{ - private _id: number; - private _name: string; - private _description: string; - private _roomId: string; - - private _badgeParts: GroupBadgePart[]; - private _colorA: number; - private _colorB: number; - - private _state: number; - private _canMembersDecorate: boolean; - - constructor() - { - this._id = 0; - this._name = ''; - this._description = ''; - this._roomId = '0'; - - this._badgeParts = []; - this._colorA = 0; - this.colorB = 0; - - this._state = 0; - this._canMembersDecorate = false; - - this._badgeParts.push(new GroupBadgePart(GroupBadgePart.BASE)); - this._badgeParts.push(new GroupBadgePart(GroupBadgePart.SYMBOL)); - this._badgeParts.push(new GroupBadgePart(GroupBadgePart.SYMBOL)); - this._badgeParts.push(new GroupBadgePart(GroupBadgePart.SYMBOL)); - this._badgeParts.push(new GroupBadgePart(GroupBadgePart.SYMBOL)); - } - - public getBadgePart(index: number): GroupBadgePart - { - return this._badgeParts[index]; - } - - public setPartsColor(color: number): void - { - this._badgeParts.forEach((symbol) => - { - symbol.color = color; - }); - } - - public get id(): number - { - return this._id; - } - - public set id(id: number) - { - this._id = id; - } - - public get name(): string - { - return this._name; - } - - public set name(name: string) - { - this._name = name; - } - - public get description(): string - { - return this._description; - } - - public set description(description: string) - { - this._description = description; - } - - public get roomId(): string - { - return this._roomId; - } - - public set roomId(id: string) - { - this._roomId = id; - } - - public get badgeParts(): GroupBadgePart[] - { - return this._badgeParts; - } - - public set badgeParts(parts: GroupBadgePart[]) - { - this._badgeParts = parts; - } - - public get colorA(): number - { - return this._colorA; - } - - public set colorA(id: number) - { - this._colorA = id; - } - - public get colorB(): number - { - return this._colorB; - } - - public set colorB(id: number) - { - this._colorB = id; - } - - public get currentBadgeCode(): string - { - let code = ''; - - this._badgeParts.forEach((part) => - { - if(part.code) - { - code = code + part.code; - } - }); - - return code; - } - - public get currentBadgeArray(): number[] - { - const badge = []; - - this._badgeParts.forEach((part) => - { - if(part.code) - { - badge.push(part.key); - badge.push(part.color); - badge.push(part.position); - } - }); - - return badge; - } - - public get state(): number - { - return this._state; - } - - public set state(state: number) - { - this._state = state; - } - - public get canMembersDecorate(): boolean - { - return this._canMembersDecorate; - } - - public set canMembersDecorate(value: boolean) - { - this._canMembersDecorate = value; - } -} diff --git a/src/views/groups/context/GroupsContext.types.ts b/src/views/groups/context/GroupsContext.types.ts index dcef1768..210d9cd2 100644 --- a/src/views/groups/context/GroupsContext.types.ts +++ b/src/views/groups/context/GroupsContext.types.ts @@ -1,4 +1,5 @@ import { Dispatch, ProviderProps, Reducer } from 'react'; +import { GroupBadgePart } from './../common/GroupBadgePart'; export interface IGroupsContext { @@ -13,37 +14,46 @@ export interface GroupsContextProps extends ProviderProps export interface IGroupsState { - badgeBases: Map; - badgeSymbols: Map; - badgePartColors: Map; - groupColorsA: Map; - groupColorsB: Map; + availableRooms: { id: number, name: string }[]; + purchaseCost: number; + 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 }[]; groupName: string; groupDescription: string; groupHomeroomId: number; + groupBadgeParts: GroupBadgePart[]; + groupColors: number[]; } export interface IGroupsAction { type: string; payload?: { - arrayMaps?: Map[]; - stringMaps?: Map[]; + objectArrays?: any[]; stringValue?: string; numberValue?: number; + badgeParts?: GroupBadgePart[]; } } export class GroupsActions { - public static SET_BADGE_PARTS: string = 'GA_SET_BADGE_PARTS'; + 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 RESET_GROUP_SETTINGS: string = 'GA_RESET_GROUP_SETTINGS'; } export const initialGroups: IGroupsState = { + availableRooms: null, + purchaseCost: null, badgeBases: null, badgeSymbols: null, badgePartColors: null, @@ -51,19 +61,27 @@ export const initialGroups: IGroupsState = { groupColorsB: null, groupName: '', groupDescription: '', - groupHomeroomId: 0 + groupHomeroomId: 0, + groupBadgeParts: null, + groupColors: null }; export const GroupsReducer: Reducer = (state, action) => { switch(action.type) { - case GroupsActions.SET_BADGE_PARTS: { - const badgeBases = (action.payload.arrayMaps[0] || state.badgeBases || null); - const badgeSymbols = (action.payload.arrayMaps[1] || state.badgeSymbols || null); - const badgePartColors = (action.payload.stringMaps[0] || state.badgePartColors || null); - const groupColorsA = (action.payload.stringMaps[1] || state.groupColorsA || null); - const groupColorsB = (action.payload.stringMaps[2] || state.groupColorsB || null); + case GroupsActions.SET_PURHCASE_SETTINGS: { + const availableRooms = action.payload.objectArrays; + const purchaseCost = (action.payload.numberValue || state.purchaseCost || 0); + + return { ...state, availableRooms, purchaseCost }; + } + case GroupsActions.SET_GROUP_BADGE_PARTS_CONFIG: { + const badgeBases = (action.payload.objectArrays[0] || state.badgeBases || null); + const badgeSymbols = (action.payload.objectArrays[1] || state.badgeSymbols || null); + const badgePartColors = (action.payload.objectArrays[2] || state.badgePartColors || null); + const groupColorsA = (action.payload.objectArrays[3] || state.groupColorsA || null); + const groupColorsB = (action.payload.objectArrays[4] || state.groupColorsB || null); return { ...state, badgeBases, badgeSymbols, badgePartColors, groupColorsA, groupColorsB }; } @@ -82,12 +100,24 @@ export const GroupsReducer: Reducer = (state, actio 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.objectArrays; + + return { ...state, groupColors }; + } case GroupsActions.RESET_GROUP_SETTINGS: { const groupName = ''; const groupDescription = ''; const groupHomeroomId = 0; - - return { ...state, groupName, groupDescription, groupHomeroomId }; + const groupBadgeParts = null; + const groupColors = null; + + return { ...state, groupName, groupDescription, groupHomeroomId, groupBadgeParts, groupColors }; } default: return state; diff --git a/src/views/groups/views/creator/GroupCreatorView.scss b/src/views/groups/views/creator/GroupCreatorView.scss index e1c376ab..df40ce78 100644 --- a/src/views/groups/views/creator/GroupCreatorView.scss +++ b/src/views/groups/views/creator/GroupCreatorView.scss @@ -112,4 +112,10 @@ } } } + + .creator-tab { + height: 230px; + min-height: 230px; + max-height: 230px; + } } diff --git a/src/views/groups/views/creator/GroupCreatorView.tsx b/src/views/groups/views/creator/GroupCreatorView.tsx index a62a3969..10a23970 100644 --- a/src/views/groups/views/creator/GroupCreatorView.tsx +++ b/src/views/groups/views/creator/GroupCreatorView.tsx @@ -1,27 +1,28 @@ -import { GroupBuyDataComposer, GroupBuyDataEvent } from '@nitrots/nitro-renderer'; +import { GroupBuyComposer, GroupBuyDataComposer } from '@nitrots/nitro-renderer'; import classNames from 'classnames'; import { FC, useCallback, useEffect, useState } from 'react'; import { Button } from 'react-bootstrap'; -import { LocalizeText } from '../../../../api'; -import { CreateMessageHook, SendMessageHook } from '../../../../hooks'; +import { HasHabboClub, LocalizeText } from '../../../../api'; +import { SendMessageHook } from '../../../../hooks'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; import { useGroupsContext } from '../../context/GroupsContext'; import { GroupsActions } from '../../context/GroupsContext.types'; +import { GroupSharedTabBadgeView } from '../shared-tabs/tab-badge/GroupSharedTabBadgeView'; +import { GroupSharedTabColorsView } from '../shared-tabs/tab-colors/GroupSharedTabColorsView'; import { GroupCreatorViewProps } from './GroupCreatorView.types'; -import { GroupCreatorTabIdentityView } from './views/creator-tab-identity/GroupCreatorTabIdentityView'; +import { GroupCreatorTabConfirmationView } from './views/tab-confirmation/GroupCreatorTabConfirmationView'; +import { GroupCreatorTabIdentityView } from './views/tab-identity/GroupCreatorTabIdentityView'; const TABS: number[] = [1, 2, 3, 4]; export const GroupCreatorView: FC = props => { const { groupsState = null, dispatchGroupsState = null } = useGroupsContext(); - const { groupName = null, groupHomeroomId = null } = groupsState; + const { groupName = null, groupDescription = null, groupHomeroomId = null, groupColors = null, groupBadgeParts = null } = groupsState; const { isVisible = false, onClose = null } = props; const [ currentTab, setCurrentTab ] = useState(1); - const [ availableRooms, setAvailableRooms ] = useState>(null); - const [ cost, setCost ] = useState(0); useEffect(() => { @@ -38,15 +39,24 @@ export const GroupCreatorView: FC = props => } }, [ isVisible ]); - const onGroupBuyDataEvent = useCallback((event: GroupBuyDataEvent) => + const buyGroup = useCallback(() => { - const parser = event.getParser(); + const badge = []; - setAvailableRooms(parser.availableRooms); - setCost(parser.groupCost); - }, []); + if(!groupBadgeParts) return; - CreateMessageHook(GroupBuyDataEvent, onGroupBuyDataEvent); + 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(() => { @@ -67,6 +77,10 @@ export const GroupCreatorView: FC = props => } break; } + case 4: { + buyGroup(); + break; + } } setCurrentTab(value => @@ -98,12 +112,15 @@ export const GroupCreatorView: FC = props =>
{ LocalizeText('group.create.stepdesc.' + currentTab) }
-
- { currentTab === 1 && } +
+ { currentTab === 1 && } + { currentTab === 2 && } + { currentTab === 3 && } + { currentTab === 4 && }
- +
diff --git a/src/views/groups/views/creator/views/creator-tab-identity/GroupCreatorTabIdentityView.types.ts b/src/views/groups/views/creator/views/creator-tab-identity/GroupCreatorTabIdentityView.types.ts deleted file mode 100644 index f53468af..00000000 --- a/src/views/groups/views/creator/views/creator-tab-identity/GroupCreatorTabIdentityView.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface GroupCreatorTabIdentityViewProps -{ - availableRooms: Map; -} diff --git a/src/views/groups/views/creator/views/tab-confirmation/GroupCreatorTabConfirmationView.tsx b/src/views/groups/views/creator/views/tab-confirmation/GroupCreatorTabConfirmationView.tsx new file mode 100644 index 00000000..4fc01ae9 --- /dev/null +++ b/src/views/groups/views/creator/views/tab-confirmation/GroupCreatorTabConfirmationView.tsx @@ -0,0 +1,55 @@ +import { FC, useCallback } from 'react'; +import { LocalizeText } from '../../../../../../api'; +import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; +import { useGroupsContext } from '../../../../context/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 ( +
+
+
{ LocalizeText('group.create.confirm.guildbadge') }
+
+ +
+
+
{ LocalizeText('group.edit.color.guild.color') }
+ { groupColors &&
+
+
+
} +
+
+
+
{ groupName }
+
{ groupDescription }
+
+
{ LocalizeText('group.create.confirm.buyinfo', ['amount'], [purchaseCost.toString()]) }
+
+
+ ); +}; diff --git a/src/views/groups/views/creator/views/creator-tab-identity/GroupCreatorTabIdentityView.tsx b/src/views/groups/views/creator/views/tab-identity/GroupCreatorTabIdentityView.tsx similarity index 71% rename from src/views/groups/views/creator/views/creator-tab-identity/GroupCreatorTabIdentityView.tsx rename to src/views/groups/views/creator/views/tab-identity/GroupCreatorTabIdentityView.tsx index b19421b6..201b544d 100644 --- a/src/views/groups/views/creator/views/creator-tab-identity/GroupCreatorTabIdentityView.tsx +++ b/src/views/groups/views/creator/views/tab-identity/GroupCreatorTabIdentityView.tsx @@ -2,14 +2,11 @@ import { FC, useCallback } from 'react'; import { CreateLinkEvent, LocalizeText } from '../../../../../../api'; import { useGroupsContext } from '../../../../context/GroupsContext'; import { GroupsActions } from '../../../../context/GroupsContext.types'; -import { GroupCreatorTabIdentityViewProps } from './GroupCreatorTabIdentityView.types'; -export const GroupCreatorTabIdentityView: FC = props => +export const GroupCreatorTabIdentityView: FC<{}> = props => { const { groupsState = null, dispatchGroupsState = null } = useGroupsContext(); - const { groupName = '', groupDescription = '', groupHomeroomId = 0 } = groupsState; - - const { availableRooms = null } = props; + const { groupName = '', groupDescription = '', groupHomeroomId = 0, availableRooms = null } = groupsState; const setName = useCallback((name: string) => { @@ -41,26 +38,26 @@ export const GroupCreatorTabIdentityView: FC = }) }, [ dispatchGroupsState ]); - return (<> + return (
- - setName(e.target.value) } /> + + setName(e.target.value) } />
- - setDescription(e.target.value) } /> + + setDescription(e.target.value) } />
- +
{ LocalizeText('group.edit.base.warning') }
CreateLinkEvent('navigator/create') }>{ LocalizeText('group.createroom') }
- ); +
); }; diff --git a/src/views/groups/views/shared-tabs/GroupSharedTabs.scss b/src/views/groups/views/shared-tabs/GroupSharedTabs.scss new file mode 100644 index 00000000..6da2ee1e --- /dev/null +++ b/src/views/groups/views/shared-tabs/GroupSharedTabs.scss @@ -0,0 +1,40 @@ +.nitro-groups { + .badge-preview { + position: relative; + width: 50px; + height: 50px; + background: $white; + border-radius: $border-radius; + + &.active { + &:before { + position: absolute; + content: ' '; + width: 0; + height: 0; + border-top: 10px solid white; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + bottom: -10px; + } + } + } + + .group-color-swatch { + width: 30px; + height: 40px; + + &:first-child { + border-top-left-radius: $border-radius; + border-bottom-left-radius: $border-radius; + } + + &:last-child { + border-top-right-radius: $border-radius; + border-bottom-right-radius: $border-radius; + } + } +} + +@import './tab-badge/GroupSharedTabBadgeView'; +@import './tab-colors/GroupSharedTabColorsView'; diff --git a/src/views/groups/views/shared-tabs/tab-badge/GroupSharedTabBadgeView.scss b/src/views/groups/views/shared-tabs/tab-badge/GroupSharedTabBadgeView.scss new file mode 100644 index 00000000..1ad61e27 --- /dev/null +++ b/src/views/groups/views/shared-tabs/tab-badge/GroupSharedTabBadgeView.scss @@ -0,0 +1,26 @@ +.shared-tab-badge { + .position-swatch { + position: relative; + border-radius: $border-radius; + width: 16px; + height: 12px; + background: $white; + + &.active { + background: $primary; + } + } + + .color-swatch { + position: relative; + border-radius: $border-radius; + width: 16px; + height: 12px; + } + + .selection-list { + height: 160px; + min-height: 160px; + max-height: 160px; + } +} diff --git a/src/views/groups/views/shared-tabs/tab-badge/GroupSharedTabBadgeView.tsx b/src/views/groups/views/shared-tabs/tab-badge/GroupSharedTabBadgeView.tsx new file mode 100644 index 00000000..c4572551 --- /dev/null +++ b/src/views/groups/views/shared-tabs/tab-badge/GroupSharedTabBadgeView.tsx @@ -0,0 +1,128 @@ +import classNames from 'classnames'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { BadgeImageView } from '../../../../shared/badge-image/BadgeImageView'; +import { GroupBadgePart } from '../../../common/GroupBadgePart'; +import { useGroupsContext } from '../../../context/GroupsContext'; +import { GroupsActions } from '../../../context/GroupsContext.types'; + +const POSITIONS: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + +export const GroupSharedTabBadgeView: FC<{}> = props => +{ + const { groupsState = null, dispatchGroupsState = null } = useGroupsContext(); + const { badgeBases = null, badgeSymbols = null, badgePartColors = null, groupBadgeParts = null } = groupsState; + + const [ editingIndex, setEditingIndex ] = useState(0); + const [ isSelectingModel, setIsSelectingModel ] = useState(false); + + useEffect(() => + { + if(!badgeBases || !badgePartColors || groupBadgeParts) return; + + const badgeParts: GroupBadgePart[] = [ + new GroupBadgePart(GroupBadgePart.BASE, badgeBases[0].id, badgePartColors[0].id), + new GroupBadgePart(GroupBadgePart.SYMBOL), + new GroupBadgePart(GroupBadgePart.SYMBOL), + new GroupBadgePart(GroupBadgePart.SYMBOL), + new GroupBadgePart(GroupBadgePart.SYMBOL) + ]; + + dispatchGroupsState({ + type: GroupsActions.SET_GROUP_BADGE_PARTS, + payload: { badgeParts } + }); + + }, [ badgeBases, badgePartColors, groupBadgeParts ]); + + const selectPartProperty = useCallback((property: string, key: number) => + { + const clonedBadgeParts = Array.from(groupBadgeParts); + + clonedBadgeParts[editingIndex][property] = key; + + dispatchGroupsState({ + type: GroupsActions.SET_GROUP_BADGE_PARTS, + payload: { + badgeParts: clonedBadgeParts + } + }); + + if(property === 'key') setIsSelectingModel(false); + }, [ editingIndex, groupBadgeParts, dispatchGroupsState ]); + + const getCompleteBadgeCode = useCallback(() => + { + let code = ''; + + if(!groupBadgeParts) return code; + + groupBadgeParts.forEach((badgePart) => + { + if(badgePart.code) code = code + badgePart.code; + }); + + return code; + }, [ groupBadgeParts ]); + + const getCurrentPart = useCallback((property: string) => + { + return groupBadgeParts[editingIndex][property]; + }, [ groupBadgeParts, editingIndex ]); + + return ( +
+
+
+ +
+
+
+ { groupBadgeParts && groupBadgeParts.map((badgePart, partIndex) => + { + return ( +
setEditingIndex(partIndex) }> + { badgePart.code && } + { !badgePart.code && } +
+ ) + }) } +
+ { !isSelectingModel && groupBadgeParts &&
+
setIsSelectingModel(true) }> + { getCurrentPart('code') && } + { !getCurrentPart('code') && } +
+
+
+ { POSITIONS.map((position) => + { + return
selectPartProperty('position', position) }>
+ }) } +
+
+
+
+ { badgePartColors && badgePartColors.map((item, index) => + { + return
selectPartProperty('color', item.id) }>
+ }) } +
+
+
} + { isSelectingModel &&
+ { groupBadgeParts[editingIndex].type !== GroupBadgePart.BASE && <> +
selectPartProperty('key', 0) }> + +
+ } + { (groupBadgeParts[editingIndex].type === GroupBadgePart.BASE ? badgeBases : badgeSymbols).map((item, index) => + { + return
selectPartProperty('key', item.id) }> + +
+ }) } +
} +
+
+
); +}; diff --git a/src/views/groups/views/shared-tabs/tab-colors/GroupSharedTabColorsView.scss b/src/views/groups/views/shared-tabs/tab-colors/GroupSharedTabColorsView.scss new file mode 100644 index 00000000..06045fff --- /dev/null +++ b/src/views/groups/views/shared-tabs/tab-colors/GroupSharedTabColorsView.scss @@ -0,0 +1,9 @@ +.shared-tab-colors { + + .color-swatch { + position: relative; + border-radius: $border-radius; + width: 15px; + height: 12px; + } +} diff --git a/src/views/groups/views/shared-tabs/tab-colors/GroupSharedTabColorsView.tsx b/src/views/groups/views/shared-tabs/tab-colors/GroupSharedTabColorsView.tsx new file mode 100644 index 00000000..332d183f --- /dev/null +++ b/src/views/groups/views/shared-tabs/tab-colors/GroupSharedTabColorsView.tsx @@ -0,0 +1,87 @@ +import { FC, useCallback, useEffect, useState } from 'react'; +import { LocalizeText } from '../../../../../api'; +import { useGroupsContext } from '../../../context/GroupsContext'; +import { GroupsActions } from '../../../context/GroupsContext.types'; + +export const GroupSharedTabColorsView: FC<{}> = props => +{ + const { groupsState = null, dispatchGroupsState = null } = useGroupsContext(); + const { groupColors = null, groupColorsA = null, groupColorsB = null } = groupsState; + + const [ selectingColorIndex, setSelectingColorIndex ] = useState(0); + + useEffect(() => + { + if(!groupColorsA || !groupColorsB || groupColors) return; + + const colors: number[] = [ + groupColorsA[0].id, + groupColorsB[0].id + ]; + + dispatchGroupsState({ + type: GroupsActions.SET_GROUP_COLORS, + payload: { + objectArrays: colors + } + }); + + }, [ groupColors, groupColorsA, groupColorsB ]); + + 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 ]); + + const selectColor = useCallback((colorId: number) => + { + const clonedGroupColors = Array.from(groupColors); + + clonedGroupColors[selectingColorIndex] = colorId; + + dispatchGroupsState({ + type: GroupsActions.SET_GROUP_COLORS, + payload: { + objectArrays: clonedGroupColors + } + }); + }, [ selectingColorIndex, groupColors, dispatchGroupsState ]); + + return ( +
+
+
{ LocalizeText('group.edit.color.guild.color') }
+ { groupColors &&
+
+
+
} +
+ { selectingColorIndex === 0 &&
+
{ LocalizeText('group.edit.color.primary.color') }
+
+
+ { groupColorsA && groupColorsA.map((item, index) => + { + return
selectColor(item.id) }>
+ }) } +
+
setSelectingColorIndex(1) } />
+
+
} + { selectingColorIndex === 1 &&
+
{ LocalizeText('group.edit.color.secondary.color') }
+
+
setSelectingColorIndex(0) } />
+
+ { groupColorsB && groupColorsB.map((item, index) => + { + return
selectColor(item.id) }>
+ }) } +
+
+
} +
+ ); +};