diff --git a/src/App.scss b/src/App.scss index 7dc98e83..27afe7cb 100644 --- a/src/App.scss +++ b/src/App.scss @@ -72,6 +72,9 @@ $room-info-width: 325px; $nitro-group-creator-width: 383px; $nitro-mod-tools-width: 175px; +$nitro-group-manager-width: 375px; +$nitro-group-manager-height: 355px; + .nitro-app { width: 100%; height: 100%; diff --git a/src/components/groups/GroupView.scss b/src/components/groups/GroupView.scss index 900df082..b787fd43 100644 --- a/src/components/groups/GroupView.scss +++ b/src/components/groups/GroupView.scss @@ -1,8 +1,3 @@ -.nitro-group-manager { - width: 420px; - max-height: 400px; -} - .nitro-group-tab-image { width: 122px; height: 68px; @@ -82,6 +77,55 @@ } } +.group-badge-preview { + width: 42px; + height: 42px; + background-color: $grid-bg-color; + + &.active { + border-color: $grid-active-border-color !important; + background-color: $grid-active-bg-color; + + &: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-badge-color-swatch, +.group-badge-position-swatch { + position: relative; + border-radius: $border-radius; + width: 16px; + height: 16px; + background: $white; + border: 2px solid $white; + box-shadow: inset 3px 3px rgba(0, 0, 0, .1); + + &.active { + box-shadow: none; + } +} + +.group-badge-position-swatch { + box-shadow: inset 3px 3px rgba(0, 0, 0, .1); + + &.active { + background: $primary; + } +} + +.group-badge-color-swatch { + box-shadow: inset 2px 2px rgba(0, 0, 0, .2); +} + .group-color-swatch { width: 30px; height: 40px; diff --git a/src/components/groups/views/GroupBadgeCreatorView.tsx b/src/components/groups/views/GroupBadgeCreatorView.tsx new file mode 100644 index 00000000..acc6a22f --- /dev/null +++ b/src/components/groups/views/GroupBadgeCreatorView.tsx @@ -0,0 +1,107 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Dispatch, FC, SetStateAction, useEffect, useRef, useState } from 'react'; +import { Base, Column, Flex, Grid } from '../../../common'; +import { BatchUpdates } from '../../../hooks'; +import { BadgeImageView } from '../../../views/shared/badge-image/BadgeImageView'; +import { GroupBadgePart } from '../common/GroupBadgePart'; +import { useGroupsContext } from '../GroupsContext'; + +interface GroupBadgeCreatorViewProps +{ + badgeParts: GroupBadgePart[]; + setBadgeParts: Dispatch>; +} + +const POSITIONS: number[] = [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]; + +export const GroupBadgeCreatorView: FC = props => +{ + const { badgeParts = [], setBadgeParts = null } = props; + const [ selectedIndex, setSelectedIndex ] = useState(-1); + const [ copiedBadgeParts, setCopiedBadgeParts ] = useState(null); + 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 newBadgeParts = [ ...copiedBadgeParts ]; + + newBadgeParts[partIndex][property] = value; + + BatchUpdates(() => + { + setCopiedBadgeParts(newBadgeParts); + + if(property === 'key') setSelectedIndex(-1); + }); + } + + useEffect(() => + { + BatchUpdates(() => + { + setCopiedBadgeParts(badgeParts); + setSelectedIndex(-1); + }); + }, [ badgeParts ]); + + useEffect(() => + { + if(!copiedBadgeParts || (copiedBadgeParts === badgeParts)) return; + + setBadgeParts(copiedBadgeParts); + }, [ copiedBadgeParts, badgeParts, setBadgeParts ]); + + if(!copiedBadgeParts || !copiedBadgeParts.length) return null; + + return ( + <> + { ((selectedIndex < 0) && copiedBadgeParts && (copiedBadgeParts.length > 0)) && copiedBadgeParts.map((part, index) => + { + return ( + + setSelectedIndex(index) }> + { (copiedBadgeParts[index].code && (copiedBadgeParts[index].code.length > 0)) && + } + { (!copiedBadgeParts[index].code || !copiedBadgeParts[index].code.length) && + + + } + + { (part.type !== GroupBadgePart.BASE) && + + { POSITIONS.map((position, posIndex) => + { + return setPartProperty(index, 'position', position) }> + }) } + } + + { (badgePartColors.length > 0) && badgePartColors.map((item, colorIndex) => + { + return setPartProperty(index, 'color', (colorIndex + 1)) }> + }) } + + + ); + }) } + { (selectedIndex >= 0) && + + { (copiedBadgeParts[selectedIndex].type === GroupBadgePart.SYMBOL) && + setPartProperty(selectedIndex, 'key', 0) }> + + + + } + { ((copiedBadgeParts[selectedIndex].type === GroupBadgePart.BASE) ? badgeBases : badgeSymbols).map((item, index) => + { + return ( + setPartProperty(selectedIndex, 'key', item.id) }> + + + ); + }) } + } + + ); +} diff --git a/src/components/groups/views/information/GroupInformationView.tsx b/src/components/groups/views/information/GroupInformationView.tsx index 37e10c31..fdb7bd24 100644 --- a/src/components/groups/views/information/GroupInformationView.tsx +++ b/src/components/groups/views/information/GroupInformationView.tsx @@ -108,8 +108,8 @@ export const GroupInformationView: FC = props => <> - - + + handleAction('members') }>{ LocalizeText('group.membercount', [ 'totalMembers' ], [ groupInformation.membersCount.toString() ]) } diff --git a/src/components/groups/views/manager/GroupManagerView.scss b/src/components/groups/views/manager/GroupManagerView.scss index f9178010..2dd3baa5 100644 --- a/src/components/groups/views/manager/GroupManagerView.scss +++ b/src/components/groups/views/manager/GroupManagerView.scss @@ -1,3 +1,4 @@ .nitro-group-manager { - width: 385px; + height: $nitro-group-manager-height; + width: $nitro-group-manager-width; } diff --git a/src/components/groups/views/manager/GroupManagerView.tsx b/src/components/groups/views/manager/GroupManagerView.tsx index 92001faa..986a9d99 100644 --- a/src/components/groups/views/manager/GroupManagerView.tsx +++ b/src/components/groups/views/manager/GroupManagerView.tsx @@ -1,4 +1,4 @@ -import { GroupDeleteComposer, GroupSaveBadgeComposer, GroupSaveColorsComposer, GroupSaveInformationComposer, GroupSavePreferencesComposer } from '@nitrots/nitro-renderer'; +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'; @@ -44,7 +44,7 @@ export const GroupManagerView: FC<{}> = props => }); SendMessageHook(new GroupSaveInformationComposer(groupId, groupName, groupDescription)); - SendMessageHook(new GroupSaveBadgeComposer(groupId, badge)); + //SendMessageHook(new GroupSaveBadgeComposer(groupId, badge)); SendMessageHook(new GroupSaveColorsComposer(groupId, groupColors[0], groupColors[1])); SendMessageHook(new GroupSavePreferencesComposer(groupId, groupState, groupCanMembersDecorate ? 0 : 1)); diff --git a/src/components/groups/views/tabs/GroupSharedTabs.scss b/src/components/groups/views/tabs/GroupSharedTabs.scss index 4b9b3b5e..c1657df1 100644 --- a/src/components/groups/views/tabs/GroupSharedTabs.scss +++ b/src/components/groups/views/tabs/GroupSharedTabs.scss @@ -1,82 +1,7 @@ .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; } } - -.nitro-groups-color-grid { - - .color-swatch { - position: relative; - border-radius: $border-radius; - width: 16px; - height: 16px; - border: 2px solid $white; - box-shadow: inset 3px 3px rgba(0, 0, 0, .1); - - &.active { - box-shadow: none; - } - } -} - -.shared-tab-badge { - .position-swatch { - position: relative; - border-radius: $border-radius; - width: 16px; - height: 16px; - background: $white; - border: 2px solid $white; - box-shadow: inset 3px 3px rgba(0, 0, 0, .1); - - &.active { - background: $primary; - box-shadow: none; - } - } - - .selection-list { - height: 160px; - min-height: 160px; - max-height: 160px; - } -} - -.shared-tab-colors { - - .color-swatch { - position: relative; - border-radius: $border-radius; - width: 15px; - height: 15px; - border: 2px solid $white; - box-shadow: inset 2px 2px rgba(0, 0, 0, .2); - - &.active { - box-shadow: none; - } - } -} diff --git a/src/components/groups/views/tabs/GroupTabBadgeView.tsx b/src/components/groups/views/tabs/GroupTabBadgeView.tsx index dae659b4..7b790fba 100644 --- a/src/components/groups/views/tabs/GroupTabBadgeView.tsx +++ b/src/components/groups/views/tabs/GroupTabBadgeView.tsx @@ -1,11 +1,12 @@ -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import classNames from 'classnames'; -import { FC, useCallback, useEffect, useState } from 'react'; +import { GroupSaveBadgeComposer } from '@nitrots/nitro-renderer'; +import { FC, useEffect, useState } from 'react'; import { Column, Flex, Grid } from '../../../../common'; +import { SendMessageHook } from '../../../../hooks'; import { BadgeImageView } from '../../../../views/shared/badge-image/BadgeImageView'; import { GroupBadgePart } from '../../common/GroupBadgePart'; import { useGroupsContext } from '../../GroupsContext'; import { GroupsActions } from '../../reducers/GroupsReducer'; +import { GroupBadgeCreatorView } from '../GroupBadgeCreatorView'; const POSITIONS: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8]; @@ -17,57 +18,26 @@ interface GroupTabBadgeViewProps export const GroupTabBadgeView: FC = props => { const { skipDefault = null } = props; - const [ editingIndex, setEditingIndex ] = useState(0); - const [ isSelectingModel, setIsSelectingModel ] = useState(false); + const [ badgeParts, setBadgeParts ] = useState(null); const { groupsState = null, dispatchGroupsState = null } = useGroupsContext(); - const { badgeBases = null, badgeSymbols = null, badgePartColors = null, groupBadgeParts = null } = groupsState; + const { badgeBases = null, badgeSymbols = null, badgePartColors = null, groupId = -1, groupBadgeParts = null } = groupsState; - const switchIndex = useCallback((index: number) => + const getModifiedBadgeCode = () => { - setIsSelectingModel(false); - setEditingIndex(index); - }, []); + if(!badgeParts || !badgeParts.length) return ''; - 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 - } - }); + let badgeCode = ''; - if(property === 'key') setIsSelectingModel(false); - }, [ editingIndex, groupBadgeParts, dispatchGroupsState ]); + badgeParts.forEach(part => (part.code && (badgeCode += part.code))); - 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 badgeCode; + } useEffect(() => { - if(skipDefault || !badgeBases || !badgePartColors || groupBadgeParts) return; - - const badgeParts: GroupBadgePart[] = [ + if(groupBadgeParts && groupBadgeParts.length) return; + + const badgeParts = [ 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), @@ -79,45 +49,63 @@ export const GroupTabBadgeView: FC = props => type: GroupsActions.SET_GROUP_BADGE_PARTS, payload: { badgeParts } }); + }, [ groupBadgeParts, badgeBases, badgePartColors, dispatchGroupsState ]); + + useEffect(() => + { + setBadgeParts(groupBadgeParts); + }, [ groupBadgeParts ]); + + useEffect(() => + { + if((groupId <= 0) || !badgeParts || !badgeParts.length || !groupBadgeParts || !groupBadgeParts.length || (badgeParts === groupBadgeParts)) return; + + const badge = []; + + badgeParts.forEach((part) => + { + if(!part.code) return; + + badge.push(part.key); + badge.push(part.color); + badge.push(part.position); + }); + + console.log('send') - }, [ skipDefault, badgeBases, badgePartColors, groupBadgeParts, dispatchGroupsState ]); + SendMessageHook(new GroupSaveBadgeComposer(groupId, badge)); + }, [ groupId, badgeParts, groupBadgeParts ]); + + // useEffect(() => + // { + // if((groupId <= 0) || !badgeParts || !badgeParts.length || (badgeParts === groupBadgeParts)) return; + + // const badge = []; + + // badgeParts.forEach((part) => + // { + // if(!part.code) return; + + // badge.push(part.key); + // badge.push(part.color); + // badge.push(part.position); + // }); + + // console.log('send') + + // SendMessageHook(new GroupSaveBadgeComposer(groupId, badge)); + // }, [ groupId, groupBadgeParts, badgeParts ]); return ( -
- - - + + + + - - { (groupBadgeParts.length > 0) && groupBadgeParts.map((part, index) => - { - if(part.type === GroupBadgePart.BASE) return null; - - return ( - - setIsSelectingModel(true) }> - { (groupBadgeParts[index]['code'] && (groupBadgeParts[index]['code'].length > 0)) && - } - { (!groupBadgeParts[index]['code'] || !groupBadgeParts[index]['code'].length) && - } - - - { POSITIONS.map((position) => - { - return
selectPartProperty('position', position) }>
- }) } -
- - { (badgePartColors.length > 0) && badgePartColors.map((item, colorIndex) => - { - return
selectPartProperty('color', item.id) }>
- }) } -
-
- ); - }) } -
-
-
+
+ + + +
); }; diff --git a/src/components/groups/views/tabs/GroupTabColorsView.tsx b/src/components/groups/views/tabs/GroupTabColorsView.tsx index 41ac8c80..364da6b0 100644 --- a/src/components/groups/views/tabs/GroupTabColorsView.tsx +++ b/src/components/groups/views/tabs/GroupTabColorsView.tsx @@ -60,19 +60,19 @@ export const GroupTabColorsView: FC<{}> = props => { LocalizeText('group.edit.color.primary.color') } - + { groupColors && groupColorsA && groupColorsA.map((item, index) => { - return
selectColor(0, item.id) }>
+ return
selectColor(0, item.id) }>
}) }
{ LocalizeText('group.edit.color.secondary.color') } - + { groupColorsB && groupColorsB.map((item, index) => { - return
selectColor(1, item.id) }>
+ return
selectColor(1, item.id) }>
}) }
diff --git a/src/components/groups/views/tabs/GroupTabSettingsView.tsx b/src/components/groups/views/tabs/GroupTabSettingsView.tsx index 5d2676ef..8b16a9c0 100644 --- a/src/components/groups/views/tabs/GroupTabSettingsView.tsx +++ b/src/components/groups/views/tabs/GroupTabSettingsView.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; import { LocalizeText } from '../../../../api/utils/LocalizeText'; -import { Column, Flex, Text } from '../../../../common'; +import { Column, Flex, HorizontalRule, Text } from '../../../../common'; import { useGroupsContext } from '../../GroupsContext'; import { GroupsActions } from '../../reducers/GroupsReducer'; @@ -32,23 +32,25 @@ export const GroupTabSettingsView: FC<{}> = props => } return ( - <> - { STATES.map((state, index) => - { - return ( - - setState(index) } /> - - - - { LocalizeText(`group.edit.settings.type.${state}.label`) } - - { LocalizeText(`group.edit.settings.type.${state}.help`) } - - - ); - }) } -
+ + + { STATES.map((state, index) => + { + return ( + + setState(index) } /> + + + + { LocalizeText(`group.edit.settings.type.${state}.label`) } + + { LocalizeText(`group.edit.settings.type.${state}.help`) } + + + ); + }) } + + toggleCanMembersDecorate() } /> @@ -56,6 +58,6 @@ export const GroupTabSettingsView: FC<{}> = props => { LocalizeText('group.edit.settings.rights.members.help') } - + ); };