diff --git a/src/components/inventory/InventoryView.scss b/src/components/inventory/InventoryView.scss index 62815ad..ef1466e 100644 --- a/src/components/inventory/InventoryView.scss +++ b/src/components/inventory/InventoryView.scss @@ -1,10 +1,7 @@ .nitro-inventory { - height: $inventory-height; - min-height: $inventory-height; - max-height: $inventory-height + 150px; width: $inventory-width; - min-width: $inventory-width; - max-width: $inventory-width; + height: $inventory-height; + min-width: 326px; color: #FFF; input { @@ -14,169 +11,29 @@ &.trading { width: 535px; - min-height: $inventory-height + 315px !important; - max-width: $inventory-width + 15px !important; - min-width: $inventory-width + 15px !important; + min-height: 505px; .trading-inventory { - max-height: 240px; + height: 200px; } - - .nitro-item-count { - top: 0px; - right: -2px; - background-color: white; - padding: 0px; - padding-left: 3px; - padding-right: 3px; - color: #306A83; - border: 1px solid #2F6982; - font-weight: normal !important; - font-family: Goldfish; - } - } + } - .empty-image { - background: url("@/assets/images/inventory/empty.png"); - background-repeat: no-repeat; - width: 129px; - height: 181px; - } - .empty-petsimage { - background: url("@/assets/images/inventory/petsempty.png"); - background-repeat: no-repeat; - width: 220px; - height: 220px; - } - .empty-furniimage { - background: url("@/assets/images/inventory/furniempty.png"); - background-repeat: no-repeat; - width: 220px; - height: 220px; - } - .empty-botsimage { - background: url("@/assets/images/inventory/botsempty.png"); - background-repeat: no-repeat; - width: 220px; - height: 220px; - } + .empty-image { + background: url('@/assets/images/inventory/empty.png') no-repeat; + width: 129px; + height: 181px; + } - .bubble-inventory { - position: relative; - font-family: sans-serif; - font-size: 14px; - line-height: 5px; - width: auto; - background: #fff; - border-radius: 15px; - padding: 5px; - text-align: left; - color: #000; - } - .bubble-inventory-bottom-left:after { - content: ""; - position: absolute; - bottom: 0; - left: 15%; - width: 0; - height: 0; - border: 20px solid transparent; - border-top-color: #fff; - border-bottom: 0; - border-right: 0; - margin-left: -10px; - margin-bottom: -20px; - } + .trade-button { + min-height: 0; + font-size: 8px; + padding: 1px 2px; + z-index: 5; + } - .trade-button { - min-height: 0; - font-size: 8px; - padding: 1px 2px; - z-index: 5; - } - - .trade-bg { - border-image-source: url('@/assets/images/inventory/trading_bg.png'); + .trade-bg { + border-image-source: url(@/assets/images/inventory/trading_bg.png); border-image-slice: 15 15 15 15 fill; border-image-width: 15px 15px 15px 15px; - z-index: 1; - } - - .credits-align { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - width: 230px; - } - - .quantity-input { - width: 49px; - } - - .lock-design-left { - margin-left: 21px; - margin-right: 33px; - } - - .lock-design-right { - margin-left: 21px; - } - - .divisor { - height: 180px; - border-left: 2px solid #B4B4B4; - margin-top: 15px; - } - - .inventory-items { - - border-image-source: url(@/assets/images/inventory/item.png) !important; - border-image-slice: 6 6 6 6 fill !important; - border-image-width: 6px 6px 6px 6px !important; - - &.active { - border-image-source: url(@/assets/images/inventory/selected_item.png) !important; - border-image-slice: 6 6 6 6 fill !important; - border-image-width: 6px 6px 6px 6px !important; - } - - &.unseen { - background-color: #9BCA64; - } - - .nitro-item-count { - top: 0px; - right: -2px; - background-color: white; - padding: 0px; - padding-left: 3px; - padding-right: 3px; - color: #306A83; - border: 1px solid #2F6982; - font-weight: normal !important; - font-family: Goldfish; - } } } - -.calc-wrapper { - width: 96%; - height: calc(100% - 100px); -} - -.size-list-badges { - width: 335px; -} - -.size-badges { - width: 145px; -} - -.nitro-inventory-category-filter { - background-color: #C9C9C9; - height: 25px; -} - -.text-shadow-around-text { - text-shadow: -1px 0 white, 0 1px white, 1px 0 #ececec, 0 -1px white; -} \ No newline at end of file diff --git a/src/components/inventory/InventoryView.tsx b/src/components/inventory/InventoryView.tsx index 1fac18f..7cf0969 100644 --- a/src/components/inventory/InventoryView.tsx +++ b/src/components/inventory/InventoryView.tsx @@ -1,10 +1,8 @@ import { BadgePointLimitsEvent, ILinkEventTracker, IRoomSession, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; -import { AddEventLinkTracker, GetLocalization, GetRoomEngine, GroupItem, LocalizeText, RemoveLinkEventTracker, isObjectMoverRequested, setObjectMoverRequested } from '../../api'; +import { AddEventLinkTracker, GetLocalization, GetRoomEngine, isObjectMoverRequested, LocalizeText, RemoveLinkEventTracker, setObjectMoverRequested, UnseenItemCategory } from '../../api'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common'; -import { useInventoryBadges, useInventoryFurni, useInventoryTrade, useInventoryUnseenTracker, useMessageEvent, useRoomEngineEvent, useRoomSessionManagerEvent } from '../../hooks'; -import { TABS, TAB_BADGES, TAB_BOTS, TAB_FURNITURE, TAB_PETS, UNSEEN_CATEGORIES } from './constants'; -import { InventoryCategoryFilterView } from './views/InventoryCategoryFilterView'; +import { useInventoryTrade, useInventoryUnseenTracker, useMessageEvent, useRoomEngineEvent, useRoomSessionManagerEvent } from '../../hooks'; import { InventoryBadgeView } from './views/badge/InventoryBadgeView'; import { InventoryBotView } from './views/bot/InventoryBotView'; import { InventoryFurnitureView } from './views/furniture/InventoryFurnitureView'; @@ -12,6 +10,12 @@ import { InventoryTradeView } from './views/furniture/InventoryTradeView'; import { InventoryPetView } from './views/pet/InventoryPetView'; import { InventoryFurnitureDeleteView } from './views/furniture/InventoryFurnitureDeleteView'; +const TAB_FURNITURE: string = 'inventory.furni'; +const TAB_BOTS: string = 'inventory.bots'; +const TAB_PETS: string = 'inventory.furni.tab.pets'; +const TAB_BADGES: string = 'inventory.badges'; +const TABS = [ TAB_FURNITURE, TAB_BOTS, TAB_PETS, TAB_BADGES ]; +const UNSEEN_CATEGORIES = [ UnseenItemCategory.FURNI, UnseenItemCategory.BOT, UnseenItemCategory.PET, UnseenItemCategory.BADGE ]; export const InventoryView: FC<{}> = props => { @@ -19,12 +23,8 @@ export const InventoryView: FC<{}> = props => const [ currentTab, setCurrentTab ] = useState(TABS[0]); const [ roomSession, setRoomSession ] = useState(null); const [ roomPreviewer, setRoomPreviewer ] = useState(null); - const [ filteredGroupItems, setFilteredGroupItems ] = useState([]); - const [ filteredBadgeCodes, setFilteredBadgeCodes ] = useState([]); const { isTrading = false, stopTrading = null } = useInventoryTrade(); - const { getCount = null } = useInventoryUnseenTracker(); - const { groupItems = [] } = useInventoryFurni(); - const { badgeCodes = [] } = useInventoryBadges(); + const { getCount = null, resetCategory = null } = useInventoryUnseenTracker(); const onClose = () => { @@ -119,34 +119,36 @@ export const InventoryView: FC<{}> = props => if(!isVisible) return null; return ( - + - <> - - { TABS.map((name, index) => - { - return ( - setCurrentTab(name) } count={ getCount(UNSEEN_CATEGORIES[index]) }> - { LocalizeText(name) } - - ); - }) } - - - { (currentTab !== TAB_PETS && currentTab !== TAB_BOTS) && } - { (currentTab === TAB_FURNITURE ) && - } - { (currentTab === TAB_PETS ) && - } - { (currentTab === TAB_BADGES ) && - } - { (currentTab === TAB_BOTS ) && - } - - { isTrading && setCurrentTab(e) } cancelTrade={ onClose } /> } - + { !isTrading && + <> + + { TABS.map((name, index) => + { + return ( + setCurrentTab(name) } count={ getCount(UNSEEN_CATEGORIES[index]) }> + { LocalizeText(name) } + + ); + }) } + + + { (currentTab === TAB_FURNITURE ) && + } + { (currentTab === TAB_BOTS ) && + } + { (currentTab === TAB_PETS ) && + } + { (currentTab === TAB_BADGES ) && + } + + } + { isTrading && + + + } - - - ); -} \ No newline at end of file + + ); +} diff --git a/src/components/inventory/views/InventoryCategoryEmptyView.tsx b/src/components/inventory/views/InventoryCategoryEmptyView.tsx index b3b92ee..f250364 100644 --- a/src/components/inventory/views/InventoryCategoryEmptyView.tsx +++ b/src/components/inventory/views/InventoryCategoryEmptyView.tsx @@ -1,41 +1,26 @@ import { FC } from 'react'; -import { CreateLinkEvent, LocalizeText } from '../../../api'; -import { Button, Column, Flex, Grid, GridProps, Text } from '../../../common'; +import { Column, Grid, GridProps, Text } from '../../../common'; export interface InventoryCategoryEmptyViewProps extends GridProps { title: string; desc: string; - isTrading?: boolean; } export const InventoryCategoryEmptyView: FC = props => { - const { title = '', desc = '', isTrading = false, children = null, ...rest } = props; + const { title = '', desc = '', children = null, ...rest } = props; return ( - - -
- - -
- - {title} - - - {" "} - {desc} - -
-
- { !isTrading && - - - - } - - {children} - - ); -}; \ No newline at end of file + + +
+ + + { title } + { desc } + + { children } + + ); +} diff --git a/src/components/inventory/views/InventoryCategoryEmptyViewBots.tsx b/src/components/inventory/views/InventoryCategoryEmptyViewBots.tsx deleted file mode 100644 index bbb89bf..0000000 --- a/src/components/inventory/views/InventoryCategoryEmptyViewBots.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { FC } from 'react'; -import { CreateLinkEvent, LocalizeText } from '../../../api'; -import { Button, Column, Flex, Grid, GridProps, Text } from '../../../common'; - -export interface InventoryCategoryEmptyViewBots extends GridProps -{ - title: string; - desc: string; - isTrading?: boolean; -} - -export const InventoryCategoryEmptyViewBots: FC< InventoryCategoryEmptyViewBotsProps> = (props) => { - const { title = '', desc = '', isTrading = false, children = null, ...rest } = props; - - return ( - - -
- - -
- - {title} - - - {" "} - {desc} - -
-
- { !isTrading && - - - - } - - {children} - - ); -}; diff --git a/src/components/inventory/views/InventoryCategoryEmptyViewPets.tsx b/src/components/inventory/views/InventoryCategoryEmptyViewPets.tsx deleted file mode 100644 index ba9221e..0000000 --- a/src/components/inventory/views/InventoryCategoryEmptyViewPets.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { FC } from 'react'; -import { CreateLinkEvent, LocalizeText } from '../../../api'; -import { Button, Column, Flex, Grid, GridProps, Text } from '../../../common'; - -export interface InventoryCategoryEmptyViewPets extends GridProps -{ - title: string; - desc: string; - isTrading?: boolean; -} - -export const InventoryCategoryEmptyViewPets: FC< InventoryCategoryEmptyViewBotsProps> = (props) => { - const { title = '', desc = '', isTrading = false, children = null, ...rest } = props; - - return ( - - -
- - -
- - {title} - - - {" "} - {desc} - -
-
- { !isTrading && - - - - } - - {children} - - ); -}; \ No newline at end of file diff --git a/src/components/inventory/views/InventoryCategoryFilterView.tsx b/src/components/inventory/views/InventoryCategoryFilterView.tsx deleted file mode 100644 index 6f9552d..0000000 --- a/src/components/inventory/views/InventoryCategoryFilterView.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { Dispatch, FC, SetStateAction, useEffect, useState } from 'react'; -import { GroupItem, LocalizeBadgeName, LocalizeText } from '../../../api'; -import { Flex } from '../../../common'; -import { InventoryFilterType, TAB_BADGES, TAB_FURNITURE } from '../constants'; - -export interface InventoryCategoryFilterViewProps -{ - currentTab: string; - groupItems: GroupItem[]; - badgeCodes: string[]; - setGroupItems: Dispatch>; - setBadgeCodes: Dispatch>; -} - -export const InventoryCategoryFilterView: FC = props => -{ - const { currentTab = null, groupItems = [], badgeCodes = [], setGroupItems = null, setBadgeCodes = null } = props; - const [ filterType, setFilterType ] = useState(InventoryFilterType.EVERYTHING); - const [ filterPlace, setFilterPlace ] = useState(InventoryFilterType.IN_INVENTORY); - const [ searchValue, setSearchValue ] = useState(''); - - useEffect(() => - { - if (currentTab !== TAB_BADGES) return; - - let filteredBadgeCodes = [ ...badgeCodes ]; - - const filteredBadges = badgeCodes.filter( badge => badge.startsWith('ACH_') ); - - const numberMap = {}; - - filteredBadges.forEach(badge => - { - const name = badge.split(/[\d]+/)[0]; - const number = Number(badge.replace(name, '')); - - if (numberMap[name] === undefined || number > numberMap[name]) - { - numberMap[name] = number; - } - }); - - const allBadges = Object.keys(numberMap).map( name => `${ name }${ numberMap[name] }` ).concat( badgeCodes.filter( badge => !badge.startsWith('ACH_') ) ); - - filteredBadgeCodes = allBadges.filter(badgeCode => - { - return LocalizeBadgeName(badgeCode).toLocaleLowerCase().includes(searchValue?.toLocaleLowerCase().replace(' ', '')); - }); - - setBadgeCodes(filteredBadgeCodes); - - }, [ badgeCodes, currentTab, searchValue, setBadgeCodes ]); - - useEffect(() => - { - if (currentTab !== TAB_FURNITURE) return; - - let filteredGroupItems = [ ...groupItems ]; - - const comparison = searchValue.toLocaleLowerCase(); - - if (filterType === InventoryFilterType.EVERYTHING) return setGroupItems(groupItems.filter( item => item.name.toLocaleLowerCase().includes(comparison) )); - - filteredGroupItems = groupItems.filter(item => - { - const isWallFilter = (filterType === InventoryFilterType.WALL) ? item.isWallItem : false; - const isFloorFilter = (filterType === InventoryFilterType.FLOOR) ? !item.isWallItem : false; - const isSearchFilter = (item.name.toLocaleLowerCase().includes(comparison)) ? true : false; - - return comparison && comparison.length ? (isSearchFilter && (isWallFilter || isFloorFilter)) : isWallFilter || isFloorFilter; - }); - - setGroupItems(filteredGroupItems); - }, [ groupItems, setGroupItems, searchValue, filterType, currentTab ]); - - useEffect(() => - { - setFilterType(InventoryFilterType.EVERYTHING); - setFilterPlace(InventoryFilterType.IN_INVENTORY); - setSearchValue(''); - }, [ currentTab ]); - - return ( - - - - setSearchValue(event.target.value) } /> - - { (searchValue && !!searchValue.length) && setSearchValue('') } /> } - - { (currentTab !== TAB_BADGES) && - <> - - - - - - - - } - - ); -} diff --git a/src/components/inventory/views/badge/InventoryBadgeItemView.tsx b/src/components/inventory/views/badge/InventoryBadgeItemView.tsx index 198c13d..bb6c54a 100644 --- a/src/components/inventory/views/badge/InventoryBadgeItemView.tsx +++ b/src/components/inventory/views/badge/InventoryBadgeItemView.tsx @@ -11,7 +11,7 @@ export const InventoryBadgeItemView: FC const unseen = isUnseen(UnseenItemCategory.BADGE, getBadgeId(badgeCode)); return ( - setSelectedBadgeCode(badgeCode) } onDoubleClick={ event => toggleBadge(selectedBadgeCode) } { ...rest }> + setSelectedBadgeCode(badgeCode) } onDoubleClick={ event => toggleBadge(selectedBadgeCode) } { ...rest }> { children } diff --git a/src/components/inventory/views/badge/InventoryBadgeView.tsx b/src/components/inventory/views/badge/InventoryBadgeView.tsx index 0ffc885..96da219 100644 --- a/src/components/inventory/views/badge/InventoryBadgeView.tsx +++ b/src/components/inventory/views/badge/InventoryBadgeView.tsx @@ -1,21 +1,14 @@ import { FC, useEffect, useState } from 'react'; import { LocalizeBadgeName, LocalizeText, UnseenItemCategory } from '../../../../api'; import { AutoGrid, Button, Column, Flex, Grid, LayoutBadgeImageView, Text } from '../../../../common'; -import { useAchievements, useInventoryBadges, useInventoryUnseenTracker } from '../../../../hooks'; +import { useInventoryBadges, useInventoryUnseenTracker } from '../../../../hooks'; import { InventoryBadgeItemView } from './InventoryBadgeItemView'; -interface InventoryBadgeViewProps +export const InventoryBadgeView: FC<{}> = props => { - filteredBadgeCodes: string[]; -} - -export const InventoryBadgeView: FC = props => -{ - const { filteredBadgeCodes = [] } = props; const [ isVisible, setIsVisible ] = useState(false); - const { activeBadgeCodes = [], selectedBadgeCode = null, isWearingBadge = null, canWearBadges = null, toggleBadge = null, getBadgeId = null, activate = null, deactivate = null } = useInventoryBadges(); + const { badgeCodes = [], activeBadgeCodes = [], selectedBadgeCode = null, isWearingBadge = null, canWearBadges = null, toggleBadge = null, getBadgeId = null, activate = null, deactivate = null } = useInventoryBadges(); const { isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker(); - const { achievementScore = 0 } = useAchievements(); useEffect(() => { @@ -41,41 +34,33 @@ export const InventoryBadgeView: FC = props => }, []); return ( -
- - - - { filteredBadgeCodes && filteredBadgeCodes.length > 0 && filteredBadgeCodes.map((badgeCode, index) => - { - if (isWearingBadge(badgeCode)) return null; + + + + { badgeCodes && (badgeCodes.length > 0) && badgeCodes.map((badgeCode, index) => + { + if(isWearingBadge(badgeCode)) return null; - return ; - }) } + return + }) } + + + + + { LocalizeText('inventory.badges.activebadges') } + + { activeBadgeCodes && (activeBadgeCodes.length > 0) && activeBadgeCodes.map((badgeCode, index) => ) } - - - { LocalizeText('inventory.badges.activebadges') } - - { activeBadgeCodes && (activeBadgeCodes.length > 0) && activeBadgeCodes.map((badgeCode, index) => ) } - - - - - { !!selectedBadgeCode && - - + + - { LocalizeBadgeName(selectedBadgeCode) } + { LocalizeBadgeName(selectedBadgeCode) } - - - } -
- { LocalizeText('achievements.categories.score', [ 'score' ], [ achievementScore.toString() ]) } -
+ +
}
-
+ ); } diff --git a/src/components/inventory/views/bot/InventoryBotItemView.tsx b/src/components/inventory/views/bot/InventoryBotItemView.tsx index 9bc89a2..d213069 100644 --- a/src/components/inventory/views/bot/InventoryBotItemView.tsx +++ b/src/components/inventory/views/bot/InventoryBotItemView.tsx @@ -1,58 +1,43 @@ -import { MouseEventType } from "@nitrots/nitro-renderer"; -import { FC, MouseEvent, PropsWithChildren, useState } from "react"; -import { - attemptBotPlacement, - IBotItem, - UnseenItemCategory, -} from "../../../../api"; -import { LayoutAvatarImageView, LayoutGridItem } from "../../../../common"; -import { useInventoryBots, useInventoryUnseenTracker } from "../../../../hooks"; +import { MouseEventType } from '@nitrots/nitro-renderer'; +import { FC, MouseEvent, PropsWithChildren, useState } from 'react'; +import { attemptBotPlacement, IBotItem, UnseenItemCategory } from '../../../../api'; +import { LayoutAvatarImageView, LayoutGridItem } from '../../../../common'; +import { useInventoryBots, useInventoryUnseenTracker } from '../../../../hooks'; -export const InventoryBotItemView: FC< - PropsWithChildren<{ botItem: IBotItem }> -> = (props) => { - const { botItem = null, children = null, ...rest } = props; - const [isMouseDown, setMouseDown] = useState(false); - const { selectedBot = null, setSelectedBot = null } = useInventoryBots(); - const { isUnseen = null } = useInventoryUnseenTracker(); - const unseen = isUnseen(UnseenItemCategory.BOT, botItem.botData.id); +export const InventoryBotItemView: FC> = props => +{ + const { botItem = null, children = null, ...rest } = props; + const [ isMouseDown, setMouseDown ] = useState(false); + const { selectedBot = null, setSelectedBot = null } = useInventoryBots(); + const { isUnseen = null } = useInventoryUnseenTracker(); + const unseen = isUnseen(UnseenItemCategory.BOT, botItem.botData.id); - const onMouseEvent = (event: MouseEvent) => { - switch (event.type) { - case MouseEventType.MOUSE_DOWN: - setSelectedBot(botItem); - setMouseDown(true); - return; - case MouseEventType.MOUSE_UP: - setMouseDown(false); - return; - case MouseEventType.ROLL_OUT: - if (!isMouseDown || selectedBot !== botItem) return; + const onMouseEvent = (event: MouseEvent) => + { + switch(event.type) + { + case MouseEventType.MOUSE_DOWN: + setSelectedBot(botItem); + setMouseDown(true); + return; + case MouseEventType.MOUSE_UP: + setMouseDown(false); + return; + case MouseEventType.ROLL_OUT: + if(!isMouseDown || (selectedBot !== botItem)) return; - attemptBotPlacement(botItem); - return; - case "dblclick": - attemptBotPlacement(botItem); - return; + attemptBotPlacement(botItem); + return; + case 'dblclick': + attemptBotPlacement(botItem); + return; + } } - }; - return ( - - - {children} - - ); -}; + return ( + + + { children } + + ); +} diff --git a/src/components/inventory/views/bot/InventoryBotView.tsx b/src/components/inventory/views/bot/InventoryBotView.tsx index 7977190..8ea90d3 100644 --- a/src/components/inventory/views/bot/InventoryBotView.tsx +++ b/src/components/inventory/views/bot/InventoryBotView.tsx @@ -1,21 +1,20 @@ import { IRoomSession, RoomObjectVariable, RoomPreviewer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; -import { GetRoomEngine, LocalizeText, UnseenItemCategory, attemptBotPlacement } from '../../../../api'; +import { attemptBotPlacement, GetRoomEngine, LocalizeText, UnseenItemCategory } from '../../../../api'; import { AutoGrid, Button, Column, Grid, LayoutRoomPreviewerView, Text } from '../../../../common'; import { useInventoryBots, useInventoryUnseenTracker } from '../../../../hooks'; -import { InventoryCategoryEmptyViewBots } from '../InventoryCategoryEmptyViewBots'; +import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView'; import { InventoryBotItemView } from './InventoryBotItemView'; interface InventoryBotViewProps { roomSession: IRoomSession; roomPreviewer: RoomPreviewer; - isTrading: boolean; } export const InventoryBotView: FC = props => { - const { roomSession = null, roomPreviewer = null, isTrading = false } = props; + const { roomSession = null, roomPreviewer = null } = props; const [ isVisible, setIsVisible ] = useState(false); const { botItems = [], selectedBot = null, activate = null, deactivate = null } = useInventoryBots(); const { isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker(); @@ -65,7 +64,7 @@ export const InventoryBotView: FC = props => return () => setIsVisible(false); }, []); - if(!botItems || !botItems.length) return ; + if(!botItems || !botItems.length) return ; return ( @@ -82,11 +81,11 @@ export const InventoryBotView: FC = props => { selectedBot.botData.name } { !!roomSession && - } } ); -} \ No newline at end of file +} diff --git a/src/components/inventory/views/furniture/InventoryFurnitureItemView.tsx b/src/components/inventory/views/furniture/InventoryFurnitureItemView.tsx index cb91302..f5e8481 100644 --- a/src/components/inventory/views/furniture/InventoryFurnitureItemView.tsx +++ b/src/components/inventory/views/furniture/InventoryFurnitureItemView.tsx @@ -1,12 +1,12 @@ import { MouseEventType } from '@nitrots/nitro-renderer'; import { FC, MouseEvent, useState } from 'react'; -import { GroupItem, attemptItemPlacement } from '../../../../api'; +import { attemptItemPlacement, GroupItem } from '../../../../api'; import { LayoutGridItem } from '../../../../common'; import { useInventoryFurni } from '../../../../hooks'; -export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem, isTrading: boolean, attemptItemOffer: (count: number) => void, setGroupItem: (item: GroupItem) => void }> = props => +export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props => { - const { groupItem = null, isTrading = null, attemptItemOffer = null, setGroupItem = null, ...rest } = props; + const { groupItem = null, ...rest } = props; const [ isMouseDown, setMouseDown ] = useState(false); const { selectedItem = null, setSelectedItem = null } = useInventoryFurni(); @@ -24,16 +24,15 @@ export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem, isTrading: b case MouseEventType.ROLL_OUT: if(!isMouseDown || !(groupItem === selectedItem)) return; - if (!isTrading) attemptItemPlacement(groupItem); + attemptItemPlacement(groupItem); return; case 'dblclick': - if (!isTrading) attemptItemPlacement(groupItem); - if (isTrading) (setGroupItem(groupItem), attemptItemOffer(1)) + attemptItemPlacement(groupItem); return; } } const count = groupItem.getUnlockedCount(); - - return (count && setGroupItem(groupItem)) } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } onDoubleClick={ onMouseEvent } { ...rest } />; + + return ; } diff --git a/src/components/inventory/views/furniture/InventoryTradeView.tsx b/src/components/inventory/views/furniture/InventoryTradeView.tsx index 85bf28d..27382cf 100644 --- a/src/components/inventory/views/furniture/InventoryTradeView.tsx +++ b/src/components/inventory/views/furniture/InventoryTradeView.tsx @@ -1,49 +1,158 @@ -import { AdvancedMap } from '@nitrots/nitro-renderer'; +import { IObjectData, TradingListAddItemComposer, TradingListAddItemsComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; -import { GroupItem, LocalizeText, TradeState } from '../../../../api'; +import { FaChevronLeft, FaChevronRight, FaLock, FaUnlock } from 'react-icons/fa'; +import { FurniCategory, getGuildFurniType, GroupItem, IFurnitureItem, LocalizeText, NotificationAlertType, SendMessageComposer, TradeState } from '../../../../api'; import { AutoGrid, Base, Button, Column, Flex, Grid, LayoutGridItem, Text } from '../../../../common'; -import { useInventoryTrade } from '../../../../hooks'; -import { MAX_ITEMS_TO_TRADE, TABS, TAB_FURNITURE } from '../../constants'; +import { useInventoryTrade, useNotification } from '../../../../hooks'; +import { InventoryFurnitureSearchView } from './InventoryFurnitureSearchView'; interface InventoryTradeViewProps { - currentTab: string; - setCurrentTab: (value: string) => void; cancelTrade: () => void; } +const MAX_ITEMS_TO_TRADE: number = 9; + export const InventoryTradeView: FC = props => { - const { currentTab = null, setCurrentTab = null, cancelTrade = null } = props; + const { cancelTrade = null } = props; + const [ groupItem, setGroupItem ] = useState(null); const [ ownGroupItem, setOwnGroupItem ] = useState(null); const [ otherGroupItem, setOtherGroupItem ] = useState(null); + const [ filteredGroupItems, setFilteredGroupItems ] = useState(null); const [ countdownTick, setCountdownTick ] = useState(3); - const { ownUser = null, otherUser = null, tradeState = TradeState.TRADING_STATE_READY, progressTrade = null, removeItem = null, setTradeState = null } = useInventoryTrade(); + const [ quantity, setQuantity ] = useState(1); + const { ownUser = null, otherUser = null, groupItems = [], tradeState = TradeState.TRADING_STATE_READY, progressTrade = null, removeItem = null, setTradeState = null } = useInventoryTrade(); + const { simpleAlert = null } = useNotification(); + + const canTradeItem = (isWallItem: boolean, spriteId: number, category: number, groupable: boolean, stuffData: IObjectData) => + { + if(!ownUser || ownUser.accepts || !ownUser.userItems) return false; + + if(ownUser.userItems.length < MAX_ITEMS_TO_TRADE) return true; + + if(!groupable) return false; + + let type = spriteId.toString(); + + if(category === FurniCategory.POSTER) + { + type = ((type + 'poster') + stuffData.getLegacyString()); + } + else + { + if(category === FurniCategory.GUILD_FURNI) + { + type = getGuildFurniType(spriteId, stuffData); + } + else + { + type = (((isWallItem) ? 'I' : 'S') + type); + } + } + + return !!ownUser.userItems.getValue(type); + } + + const attemptItemOffer = (count: number) => + { + if(!groupItem) return; + + const tradeItems = groupItem.getTradeItems(count); + + if(!tradeItems || !tradeItems.length) return; + + let coreItem: IFurnitureItem = null; + const itemIds: number[] = []; + + for(const item of tradeItems) + { + itemIds.push(item.id); + + if(!coreItem) coreItem = item; + } + + const ownItemCount = ownUser.userItems.length; + + if((ownItemCount + itemIds.length) <= 1500) + { + if(!coreItem.isGroupable && (itemIds.length)) + { + SendMessageComposer(new TradingListAddItemComposer(itemIds.pop())); + } + else + { + const tradeIds: number[] = []; + + for(const itemId of itemIds) + { + if(canTradeItem(coreItem.isWallItem, coreItem.type, coreItem.category, coreItem.isGroupable, coreItem.stuffData)) + { + tradeIds.push(itemId); + } + } + + if(tradeIds.length) + { + if(tradeIds.length === 1) + { + SendMessageComposer(new TradingListAddItemComposer(tradeIds.pop())); + } + else + { + SendMessageComposer(new TradingListAddItemsComposer(...tradeIds)); + } + } + } + } + else + { + simpleAlert(LocalizeText('trading.items.too_many_items.desc'), NotificationAlertType.DEFAULT, null, null, LocalizeText('trading.items.too_many_items.title')); + } + } const getLockIcon = (accepts: boolean) => { if(accepts) { - return + return } else { - return + return } } - const getTotalCredits = (items: AdvancedMap): number => + const updateQuantity = (value: number, totalItemCount: number) => { - return items.getValues().map( item => Number(item.iconUrl.split('/')[item.iconUrl.split('/').length - 1]?.split('_')[1]) * item.items.length ).reduce((acc, cur) => acc + (isNaN(cur) ? 0 : cur), 0); + if(isNaN(Number(value)) || Number(value) < 0 || !value) value = 1; + + value = Math.max(Number(value), 1); + value = Math.min(Number(value), totalItemCount); + + if(value === quantity) return; + + setQuantity(value); } + const changeCount = (totalItemCount: number) => + { + updateQuantity(quantity, totalItemCount); + attemptItemOffer(quantity); + } + + useEffect(() => + { + setQuantity(1); + }, [ groupItem ]); + useEffect(() => { if(tradeState !== TradeState.TRADING_STATE_COUNTDOWN) return; setCountdownTick(3); - const interval = window.setInterval(() => + const interval = setInterval(() => { setCountdownTick(prevValue => { @@ -69,93 +178,102 @@ export const InventoryTradeView: FC = props => return ( - - { currentTab === TAB_FURNITURE && - <> - { LocalizeText('inventory.trading.info.add') } - - - - { (ownUser.accepts) && } - { LocalizeText('inventory.trading.you') } { LocalizeText('inventory.trading.areoffering') } - - - { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => - { - const item = (ownUser.userItems.getWithIndex(i) || null); + + + + + + { filteredGroupItems && (filteredGroupItems.length > 0) && filteredGroupItems.map((item, index) => + { + const count = item.getUnlockedCount(); - if(!item) return ; - - return ( - setOwnGroupItem(item) } onDoubleClick={ event => removeItem(item) }> - { (ownGroupItem === item) && - removeItem(item) } /> } - - ); - }) } - - - { LocalizeText('inventory.trading.info.itemcount', [ 'value' ], [ ownUser.itemCount.toString() ]) } - { LocalizeText('inventory.trading.info.creditvalue.own', [ 'value' ], [ getTotalCredits(ownUser.userItems).toString() ]) } - + return ( + (count && setGroupItem(item)) } onDoubleClick={ event => attemptItemOffer(1) }> + { ((count > 0) && (groupItem === item)) && + + } + + ); + }) } + + + + + setQuantity(event.target.valueAsNumber) } /> - - { getLockIcon(ownUser.accepts) } - - - - - { (otherUser.accepts) && } - { otherUser.userName } { LocalizeText('inventory.trading.isoffering') } - - - { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => - { - const item = (otherUser.userItems.getWithIndex(i) || null); - - if(!item) return ; - - return setOtherGroupItem(item) } />; - }) } - - - { LocalizeText('inventory.trading.info.itemcount', [ 'value' ], [ otherUser.itemCount.toString() ]) } - { LocalizeText('inventory.trading.info.creditvalue', [ 'value' ], [ getTotalCredits(otherUser.userItems).toString() ]) } - + + - - { getLockIcon(otherUser.accepts) } - - - } - { currentTab !== TAB_FURNITURE && - <> - - - { LocalizeText('inventory.trading.minimized.trade_in_progress') } + + { groupItem ? groupItem.name : LocalizeText('catalog_selectproduct') } + + + + + + + + + + { LocalizeText('inventory.trading.you') } { LocalizeText('inventory.trading.areoffering') }: - - } + + { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => + { + const item = (ownUser.userItems.getWithIndex(i) || null); + + if(!item) return ; + + return ( + setOwnGroupItem(item) } onDoubleClick={ event => removeItem(item) }> + { (ownGroupItem === item) && + } + + ); + }) } + + + { ownGroupItem ? ownGroupItem.name : LocalizeText('catalog_selectproduct') } + + + { getLockIcon(ownUser.accepts) } + + + { otherUser.userName } { LocalizeText('inventory.trading.isoffering') }: + + + { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => + { + const item = (otherUser.userItems.getWithIndex(i) || null); + + if(!item) return ; + + return setOtherGroupItem(item) } />; + }) } + + + { otherGroupItem ? otherGroupItem.name : LocalizeText('catalog_selectproduct') } + + + { getLockIcon(otherUser.accepts) } + - { (currentTab === TAB_FURNITURE) && - <> - { (tradeState === TradeState.TRADING_STATE_READY) && - } - { (tradeState === TradeState.TRADING_STATE_RUNNING) && - } - { (tradeState === TradeState.TRADING_STATE_COUNTDOWN) && - } - { (tradeState === TradeState.TRADING_STATE_CONFIRMING) && - } - { (tradeState === TradeState.TRADING_STATE_CONFIRMED) && - } - - } - { (currentTab !== TAB_FURNITURE) && - - } + { (tradeState === TradeState.TRADING_STATE_READY) && + } + { (tradeState === TradeState.TRADING_STATE_RUNNING) && + } + { (tradeState === TradeState.TRADING_STATE_COUNTDOWN) && + } + { (tradeState === TradeState.TRADING_STATE_CONFIRMING) && + } + { (tradeState === TradeState.TRADING_STATE_CONFIRMED) && + } diff --git a/src/components/inventory/views/pet/InventoryPetItemView.tsx b/src/components/inventory/views/pet/InventoryPetItemView.tsx index e0088f9..aad45f9 100644 --- a/src/components/inventory/views/pet/InventoryPetItemView.tsx +++ b/src/components/inventory/views/pet/InventoryPetItemView.tsx @@ -1,58 +1,43 @@ -import { MouseEventType } from "@nitrots/nitro-renderer"; -import { FC, MouseEvent, PropsWithChildren, useState } from "react"; -import { - attemptPetPlacement, - IPetItem, - UnseenItemCategory, -} from "../../../../api"; -import { LayoutGridItem, LayoutPetImageView } from "../../../../common"; -import { useInventoryPets, useInventoryUnseenTracker } from "../../../../hooks"; +import { MouseEventType } from '@nitrots/nitro-renderer'; +import { FC, MouseEvent, PropsWithChildren, useState } from 'react'; +import { attemptPetPlacement, IPetItem, UnseenItemCategory } from '../../../../api'; +import { LayoutGridItem, LayoutPetImageView } from '../../../../common'; +import { useInventoryPets, useInventoryUnseenTracker } from '../../../../hooks'; -export const InventoryPetItemView: FC< - PropsWithChildren<{ petItem: IPetItem }> -> = (props) => { - const { petItem = null, children = null, ...rest } = props; - const [isMouseDown, setMouseDown] = useState(false); - const { selectedPet = null, setSelectedPet = null } = useInventoryPets(); - const { isUnseen } = useInventoryUnseenTracker(); - const unseen = isUnseen(UnseenItemCategory.PET, petItem.petData.id); +export const InventoryPetItemView: FC> = props => +{ + const { petItem = null, children = null, ...rest } = props; + const [ isMouseDown, setMouseDown ] = useState(false); + const { selectedPet = null, setSelectedPet = null } = useInventoryPets(); + const { isUnseen } = useInventoryUnseenTracker(); + const unseen = isUnseen(UnseenItemCategory.PET, petItem.petData.id); - const onMouseEvent = (event: MouseEvent) => { - switch (event.type) { - case MouseEventType.MOUSE_DOWN: - setSelectedPet(petItem); - setMouseDown(true); - return; - case MouseEventType.MOUSE_UP: - setMouseDown(false); - return; - case MouseEventType.ROLL_OUT: - if (!isMouseDown || !(petItem === selectedPet)) return; + const onMouseEvent = (event: MouseEvent) => + { + switch(event.type) + { + case MouseEventType.MOUSE_DOWN: + setSelectedPet(petItem); + setMouseDown(true); + return; + case MouseEventType.MOUSE_UP: + setMouseDown(false); + return; + case MouseEventType.ROLL_OUT: + if(!isMouseDown || !(petItem === selectedPet)) return; - attemptPetPlacement(petItem); - return; - case "dblclick": - attemptPetPlacement(petItem); - return; + attemptPetPlacement(petItem); + return; + case 'dblclick': + attemptPetPlacement(petItem); + return; + } } - }; - return ( - - - {children} - - ); -}; + return ( + + + { children } + + ); +} diff --git a/src/components/inventory/views/pet/InventoryPetView.tsx b/src/components/inventory/views/pet/InventoryPetView.tsx index c90276b..0855c98 100644 --- a/src/components/inventory/views/pet/InventoryPetView.tsx +++ b/src/components/inventory/views/pet/InventoryPetView.tsx @@ -1,21 +1,20 @@ import { IRoomSession, RoomObjectVariable, RoomPreviewer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; -import { GetRoomEngine, LocalizeText, UnseenItemCategory, attemptPetPlacement } from '../../../../api'; +import { attemptPetPlacement, GetRoomEngine, LocalizeText, UnseenItemCategory } from '../../../../api'; import { AutoGrid, Button, Column, Grid, LayoutRoomPreviewerView, Text } from '../../../../common'; import { useInventoryPets, useInventoryUnseenTracker } from '../../../../hooks'; -import { InventoryCategoryEmptyViewPets } from '../InventoryCategoryEmptyViewPets'; +import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView'; import { InventoryPetItemView } from './InventoryPetItemView'; interface InventoryPetViewProps { roomSession: IRoomSession; roomPreviewer: RoomPreviewer; - isTrading: boolean; } export const InventoryPetView: FC = props => { - const { roomSession = null, roomPreviewer = null, isTrading = false } = props; + const { roomSession = null, roomPreviewer = null } = props; const [ isVisible, setIsVisible ] = useState(false); const { petItems = null, selectedPet = null, activate = null, deactivate = null } = useInventoryPets(); const { isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker(); @@ -64,7 +63,7 @@ export const InventoryPetView: FC = props => return () => setIsVisible(false); }, []); - if(!petItems || !petItems.length) return ; + if(!petItems || !petItems.length) return ; return ( @@ -81,11 +80,11 @@ export const InventoryPetView: FC = props => { selectedPet.petData.name } { !!roomSession && - } } ); -} \ No newline at end of file +}