mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-23 14:40:50 +01:00
Trading
This commit is contained in:
parent
86233806f2
commit
a907b85514
@ -1,25 +1,21 @@
|
||||
::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
height: 5px;
|
||||
width: 0.5rem;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: $border-radius;
|
||||
background: rgba($black,.1);
|
||||
box-shadow:inset 0 0 1px 1px rgba($black,.1);
|
||||
padding-top:3px;
|
||||
background-clip: padding-box;
|
||||
border-right: 0.25rem solid rgba($black, .1);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: $border-radius;
|
||||
background: rgba($primary,.4);
|
||||
width: 4px;
|
||||
background-clip: padding-box;
|
||||
border-right: 0.25rem solid rgba($primary, .4);
|
||||
|
||||
&:hover {
|
||||
border-right: 0.25rem solid rgba($primary, .8);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba($primary,.8);
|
||||
&:active {
|
||||
border-right: 0.25rem solid $secondary;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:active {
|
||||
background: $secondary;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ $nitro-card-tabs-height: 33px;
|
||||
|
||||
@import './accordion/NitroCardAccordionView';
|
||||
@import './content/NitroCardContentView';
|
||||
@import './grid/NitroCardGridView';
|
||||
@import './header/NitroCardHeaderView';
|
||||
@import './tabs/NitroCardTabsView';
|
||||
}
|
||||
|
26
src/layout/card/grid/NitroCardGridView.scss
Normal file
26
src/layout/card/grid/NitroCardGridView.scss
Normal file
@ -0,0 +1,26 @@
|
||||
.nitro-card-grid {
|
||||
|
||||
.row-cols-3 {
|
||||
|
||||
.col {
|
||||
padding-right: 0.25rem;
|
||||
|
||||
&:nth-child(3n+3) {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.row-cols-5 {
|
||||
|
||||
.col {
|
||||
padding-right: 0.25rem;
|
||||
|
||||
&:nth-child(5n+5) {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@import './item/NitroCardGridItemView.scss';
|
||||
}
|
15
src/layout/card/grid/NitroCardGridView.tsx
Normal file
15
src/layout/card/grid/NitroCardGridView.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { FC } from 'react';
|
||||
import { NitroCardGridViewProps } from './NitroCardGridView.types';
|
||||
|
||||
export const NitroCardGridView: FC<NitroCardGridViewProps> = props =>
|
||||
{
|
||||
const { columns = 5, children = null } = props;
|
||||
|
||||
return (
|
||||
<div className="h-100 overflow-hidden nitro-card-grid">
|
||||
<div className={ `row row-cols-${ columns } align-content-start g-0 w-100 h-100 overflow-auto` }>
|
||||
{ children }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
4
src/layout/card/grid/NitroCardGridView.types.ts
Normal file
4
src/layout/card/grid/NitroCardGridView.types.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface NitroCardGridViewProps
|
||||
{
|
||||
columns?: number;
|
||||
}
|
47
src/layout/card/grid/item/NitroCardGridItemView.scss
Normal file
47
src/layout/card/grid/item/NitroCardGridItemView.scss
Normal file
@ -0,0 +1,47 @@
|
||||
.grid-item-container {
|
||||
height: 48px;
|
||||
max-height: 48px;
|
||||
|
||||
.grid-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-color: $grid-border-color !important;
|
||||
background-color: $grid-bg-color !important;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
overflow: hidden;
|
||||
|
||||
&.active {
|
||||
border-color: $grid-active-border-color !important;
|
||||
background-color: $grid-active-bg-color !important;
|
||||
}
|
||||
|
||||
.badge {
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
.avatar-image {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-position-y: -32px !important;
|
||||
}
|
||||
|
||||
.trade-button {
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
right: 2px;
|
||||
font-size: 5px;
|
||||
padding: 3px;
|
||||
min-height: unset;
|
||||
|
||||
&.left {
|
||||
right: unset;
|
||||
left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
src/layout/card/grid/item/NitroCardGridItemView.tsx
Normal file
24
src/layout/card/grid/item/NitroCardGridItemView.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { FC } from 'react';
|
||||
import { LimitedEditionStyledNumberView } from '../../../../views/shared/limited-edition/styled-number/LimitedEditionStyledNumberView';
|
||||
import { NitroCardGridItemViewProps } from './NitroCardGridItemView.types';
|
||||
|
||||
export const NitroCardGridItemView: FC<NitroCardGridItemViewProps> = props =>
|
||||
{
|
||||
const { itemActive = false, itemCount = 1, itemUnique = false, itemUniqueNumber = 0, itemImage = null, className = '', style = {}, children = null, ...rest } = props;
|
||||
|
||||
const imageUrl = `url(${ itemImage })`;
|
||||
|
||||
return (
|
||||
<div className="col pb-1 grid-item-container">
|
||||
<div className={ `position-relative border border-2 rounded grid-item cursor-pointer${ itemActive ? ' active' : '' }${ itemUnique ? ' unique-item' : '' } ${ className || '' }` } style={ itemImage ? { ...style, backgroundImage: imageUrl } : style } { ...rest }>
|
||||
{ (itemCount > 1) &&
|
||||
<span className="position-absolute badge border bg-danger px-1 rounded-circle">{ itemCount }</span> }
|
||||
{ itemUnique &&
|
||||
<div className="position-absolute unique-item-counter">
|
||||
<LimitedEditionStyledNumberView value={ itemUniqueNumber } />
|
||||
</div> }
|
||||
{ children }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
10
src/layout/card/grid/item/NitroCardGridItemView.types.ts
Normal file
10
src/layout/card/grid/item/NitroCardGridItemView.types.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { DetailsHTMLAttributes } from 'react';
|
||||
|
||||
export interface NitroCardGridItemViewProps extends DetailsHTMLAttributes<HTMLDivElement>
|
||||
{
|
||||
itemImage?: string;
|
||||
itemActive?: boolean;
|
||||
itemCount?: number;
|
||||
itemUnique?: boolean;
|
||||
itemUniqueNumber?: number;
|
||||
}
|
@ -103,18 +103,23 @@ export const InventoryView: FC<InventoryViewProps> = props =>
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!furnitureState.tradeData) return;
|
||||
|
||||
setIsVisible(true);
|
||||
}, [ furnitureState.tradeData ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible)
|
||||
{
|
||||
if(furnitureState.tradeData)
|
||||
{
|
||||
setIsVisible(true);
|
||||
|
||||
if(currentTab !== InventoryTabs.FURNITURE) setCurrentTab(InventoryTabs.FURNITURE);
|
||||
// cancel the trade
|
||||
}
|
||||
}
|
||||
}, [ furnitureState.tradeData, isVisible, currentTab ]);
|
||||
}, [ furnitureState.tradeData, isVisible ]);
|
||||
|
||||
return (
|
||||
<InventoryContextProvider value={ { furnitureState, dispatchFurnitureState, botState, dispatchBotState, petState, dispatchPetState, badgeState, dispatchBadgeState } }>
|
||||
@ -122,6 +127,8 @@ export const InventoryView: FC<InventoryViewProps> = props =>
|
||||
{ isVisible &&
|
||||
<NitroCardView className="nitro-inventory">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('inventory.title') } onCloseClick={ event => setIsVisible(false) } />
|
||||
{ !furnitureState.tradeData &&
|
||||
<>
|
||||
<NitroCardTabsView>
|
||||
{ tabs.map((name, index) =>
|
||||
{
|
||||
@ -141,8 +148,12 @@ export const InventoryView: FC<InventoryViewProps> = props =>
|
||||
<InventoryPetView roomSession={ roomSession } roomPreviewer={ roomPreviewer } /> }
|
||||
{ (currentTab === InventoryTabs.BADGES ) &&
|
||||
<InventoryBadgeView /> }
|
||||
{ furnitureState.tradeData && <InventoryTradeView isInFurnitureView={ (currentTab === InventoryTabs.FURNITURE ) } /> }
|
||||
</NitroCardContentView>
|
||||
</> }
|
||||
{ furnitureState.tradeData &&
|
||||
<NitroCardContentView>
|
||||
<InventoryTradeView />
|
||||
</NitroCardContentView> }
|
||||
</NitroCardView> }
|
||||
</InventoryContextProvider>
|
||||
);
|
||||
|
@ -261,7 +261,6 @@ export const InventoryFurnitureReducer: Reducer<IInventoryFurnitureState, IInven
|
||||
}
|
||||
|
||||
for(const groupItem of groupItems) groupItem.lockItemIds(tradeIds);
|
||||
|
||||
}
|
||||
|
||||
return { ...state, groupItems, tradeData };
|
||||
|
@ -1,4 +1,2 @@
|
||||
@import './badge/InventoryBadgeView';
|
||||
@import './bot/InventoryBotView';
|
||||
@import './furniture/InventoryFurnitureView';
|
||||
@import './pet/InventoryPetView';
|
||||
|
@ -5,5 +5,9 @@
|
||||
height: 45px;
|
||||
}
|
||||
}
|
||||
|
||||
.inventory-badge-overflow {
|
||||
height: calc(100% - 86px);
|
||||
}
|
||||
|
||||
@import './item/InventoryBadgeItemView';
|
||||
@import './results/InventoryBadgeResultsView';
|
||||
|
@ -1,2 +0,0 @@
|
||||
.badge-item-container {
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { NitroCardGridView } from '../../../../../layout/card/grid/NitroCardGridView';
|
||||
import { InventoryBadgeItemView } from '../item/InventoryBadgeItemView';
|
||||
import { InventoryActiveBadgeResultsViewProps } from './InventoryActiveBadgeResultsView.types';
|
||||
|
||||
@ -7,11 +8,11 @@ export const InventoryActiveBadgeResultsView: FC<InventoryActiveBadgeResultsView
|
||||
const { badges = [] } = props;
|
||||
|
||||
return (
|
||||
<div className="row row-cols-3 align-content-start g-0">
|
||||
<NitroCardGridView columns={ 3 }>
|
||||
{ badges && (badges.length > 0) && badges.map(code =>
|
||||
{
|
||||
return <InventoryBadgeItemView key={ code } badge={ code } />
|
||||
}) }
|
||||
</div>
|
||||
</NitroCardGridView>
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { MouseEventType } from 'nitro-renderer';
|
||||
import { FC, MouseEvent, useCallback } from 'react';
|
||||
import { NitroCardGridItemView } from '../../../../../layout/card/grid/item/NitroCardGridItemView';
|
||||
import { BadgeImageView } from '../../../../shared/badge-image/BadgeImageView';
|
||||
import { useInventoryContext } from '../../../context/InventoryContext';
|
||||
import { InventoryBadgeActions } from '../../../reducers/InventoryBadgeReducer';
|
||||
@ -24,10 +25,8 @@ export const InventoryBadgeItemView: FC<InventoryBadgeItemViewProps> = props =>
|
||||
}, [ badge, dispatchBadgeState ]);
|
||||
|
||||
return (
|
||||
<div className="col pe-1 pb-1 inventory-badge-item-container">
|
||||
<div className={ 'position-relative border border-2 rounded inventory-badge-item cursor-pointer ' + (isActive ? 'active' : '') } onMouseDown={ onMouseEvent }>
|
||||
<NitroCardGridItemView itemActive={ isActive }>
|
||||
<BadgeImageView badgeCode={ badge } />
|
||||
</div>
|
||||
</div>
|
||||
</NitroCardGridItemView>
|
||||
);
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
.badge-item-container {
|
||||
height: 139px;
|
||||
max-height: 139px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.inventory-badge-overflow {
|
||||
height:calc(100% - 86px)
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { NitroCardGridView } from '../../../../../layout/card/grid/NitroCardGridView';
|
||||
import { InventoryBadgeItemView } from '../item/InventoryBadgeItemView';
|
||||
import { InventoryBadgeResultsViewProps } from './InventoryBadgeResultsView.types';
|
||||
|
||||
@ -7,15 +8,13 @@ export const InventoryBadgeResultsView: FC<InventoryBadgeResultsViewProps> = pro
|
||||
const { badges = [], activeBadges = [] } = props;
|
||||
|
||||
return (
|
||||
<div className="h-100 overflow-hidden">
|
||||
<div className="row row-cols-5 align-content-start g-0 w-100 h-100 overflow-auto">
|
||||
<NitroCardGridView>
|
||||
{ badges && (badges.length > 0) && badges.map(code =>
|
||||
{
|
||||
if(activeBadges.indexOf(code) >= 0) return null;
|
||||
|
||||
return <InventoryBadgeItemView key={ code } badge={ code } />
|
||||
}) }
|
||||
</div>
|
||||
</div>
|
||||
</NitroCardGridView>
|
||||
);
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
@import './item/InventoryBotItemView';
|
||||
@import './results/InventoryBotResultsView';
|
@ -1,25 +0,0 @@
|
||||
.inventory-bot-item-container {
|
||||
height: 48px;
|
||||
max-height: 48px;
|
||||
|
||||
.inventory-bot-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-color: $grid-border-color !important;
|
||||
background-color: $grid-bg-color;
|
||||
overflow: hidden;
|
||||
|
||||
&.active {
|
||||
border-color: $grid-active-border-color !important;
|
||||
background-color: $grid-active-bg-color;
|
||||
}
|
||||
|
||||
.avatar-image {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-position-y: -32px !important;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { MouseEventType } from 'nitro-renderer';
|
||||
import { FC, MouseEvent, useCallback, useState } from 'react';
|
||||
import { NitroCardGridItemView } from '../../../../../layout/card/grid/item/NitroCardGridItemView';
|
||||
import { AvatarImageView } from '../../../../shared/avatar-image/AvatarImageView';
|
||||
import { attemptBotPlacement } from '../../../common/BotUtilities';
|
||||
import { useInventoryContext } from '../../../context/InventoryContext';
|
||||
@ -37,10 +38,8 @@ export const InventoryBotItemView: FC<InventoryBotItemViewProps> = props =>
|
||||
}, [ isActive, isMouseDown, botItem, dispatchBotState ]);
|
||||
|
||||
return (
|
||||
<div className="col pe-1 pb-1 inventory-bot-item-container">
|
||||
<div className={ 'position-relative border border-2 rounded inventory-bot-item cursor-pointer ' + (isActive ? 'active' : '') } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent }>
|
||||
<NitroCardGridItemView itemActive={ isActive } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent }>
|
||||
<AvatarImageView figure={ botItem.botData.figure } direction={ 3 } headOnly={ true } />
|
||||
</div>
|
||||
</div>
|
||||
</NitroCardGridItemView>
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
.bot-item-container {
|
||||
height: 220px;
|
||||
max-height: 220px;
|
||||
overflow-y: auto;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { NitroCardGridView } from '../../../../../layout/card/grid/NitroCardGridView';
|
||||
import { InventoryBotItemView } from '../item/InventoryBotItemView';
|
||||
import { InventoryBotResultsViewProps } from './InventoryBotResultsView.types';
|
||||
|
||||
@ -7,13 +8,11 @@ export const InventoryBotResultsView: FC<InventoryBotResultsViewProps> = props =
|
||||
const { botItems = [] } = props;
|
||||
|
||||
return (
|
||||
<div className="h-100 overflow-hidden">
|
||||
<div className="row row-cols-5 align-content-start g-0 w-100 h-100 overflow-auto">
|
||||
<NitroCardGridView>
|
||||
{ botItems && (botItems.length > 0) && botItems.map(item =>
|
||||
{
|
||||
return <InventoryBotItemView key={ item.id } botItem={ item } />
|
||||
}) }
|
||||
</div>
|
||||
</div>
|
||||
</NitroCardGridView>
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,3 @@
|
||||
top: 5px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
@import './item/InventoryFurnitureItemView';
|
||||
@import './results/InventoryFurnitureResultsView';
|
||||
@import './search/InventoryFurnitureSearchView';
|
||||
|
@ -1,129 +1,26 @@
|
||||
import { FurnitureListComposer, IObjectData, RoomObjectVariable, TradingListAddItemComposer, TradingListAddItemsComposer, Vector3d } from 'nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { GetConnection, GetRoomEngine } from '../../../../api';
|
||||
import { SendMessageHook } from '../../../../hooks/messages/message-event';
|
||||
import { FurnitureListComposer, RoomObjectVariable, Vector3d } from 'nitro-renderer';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { GetRoomEngine } from '../../../../api';
|
||||
import { SendMessageHook } from '../../../../hooks/messages';
|
||||
import { LocalizeText } from '../../../../utils/LocalizeText';
|
||||
import { LimitedEditionCompactPlateView } from '../../../shared/limited-edition/compact-plate/LimitedEditionCompactPlateView';
|
||||
import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerView';
|
||||
import { FurniCategory } from '../../common/FurniCategory';
|
||||
import { attemptItemPlacement } from '../../common/FurnitureUtilities';
|
||||
import { GroupItem } from '../../common/GroupItem';
|
||||
import { IFurnitureItem } from '../../common/IFurnitureItem';
|
||||
import { TradeState } from '../../common/TradeState';
|
||||
import { _Str_16998 } from '../../common/TradingUtilities';
|
||||
import { useInventoryContext } from '../../context/InventoryContext';
|
||||
import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer';
|
||||
import { InventoryFurnitureViewProps } from './InventoryFurnitureView.types';
|
||||
import { InventoryFurnitureResultsView } from './results/InventoryFurnitureResultsView';
|
||||
import { InventoryFurnitureSearchView } from './search/InventoryFurnitureSearchView';
|
||||
|
||||
const MAX_ITEMS_TO_TRADE: number = 3;
|
||||
|
||||
export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
|
||||
{
|
||||
const { roomSession = null, roomPreviewer = null } = props;
|
||||
const { furnitureState = null, dispatchFurnitureState = null } = useInventoryContext();
|
||||
const { needsFurniUpdate = false, groupItem = null, groupItems = [], tradeData = null } = furnitureState;
|
||||
const { needsFurniUpdate = false, groupItem = null, groupItems = [] } = furnitureState;
|
||||
const [ filteredGroupItems, setFilteredGroupItems ] = useState<GroupItem[]>(groupItems);
|
||||
|
||||
const isTrading = useMemo(() =>
|
||||
{
|
||||
if(!tradeData) return false;
|
||||
|
||||
return (tradeData.state >= TradeState.TRADING_STATE_RUNNING);
|
||||
}, [ tradeData ]);
|
||||
|
||||
const canTradeItem = useCallback((isWallItem: boolean, spriteId: number, category: number, groupable: boolean, stuffData: IObjectData) =>
|
||||
{
|
||||
if(!tradeData || !tradeData.ownUser || tradeData.ownUser.accepts || !tradeData.ownUser.items) return false;
|
||||
|
||||
if(tradeData.ownUser.items.length < MAX_ITEMS_TO_TRADE) return true;
|
||||
|
||||
if(!groupable) return false;
|
||||
|
||||
let type = spriteId.toString();
|
||||
|
||||
if(category === FurniCategory._Str_5186)
|
||||
{
|
||||
type = ((type + 'poster') + stuffData.getLegacyString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(category === FurniCategory._Str_12454)
|
||||
{
|
||||
type = _Str_16998(spriteId, stuffData);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = (((isWallItem) ? 'I' : 'S') + type);
|
||||
}
|
||||
}
|
||||
|
||||
return !!tradeData.ownUser.items.getValue(type);
|
||||
}, [ tradeData ]);
|
||||
|
||||
const attemptItemOffer = useCallback((count: number) =>
|
||||
{
|
||||
if(!tradeData || !groupItem || !isTrading) 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 tradedIds: number[] = [];
|
||||
|
||||
if(isTrading)
|
||||
{
|
||||
const ownItemCount = tradeData.ownUser.items.length;
|
||||
|
||||
if((ownItemCount + itemIds.length) <= 1500)
|
||||
{
|
||||
if(!coreItem.isGroupable && (itemIds.length))
|
||||
{
|
||||
GetConnection().send(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))
|
||||
{
|
||||
tradedIds.push(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
if(tradedIds.length)
|
||||
{
|
||||
if(tradedIds.length === 1)
|
||||
{
|
||||
GetConnection().send(new TradingListAddItemComposer(tradedIds.pop()));
|
||||
}
|
||||
else
|
||||
{
|
||||
GetConnection().send(new TradingListAddItemsComposer(...tradedIds));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//this._notificationService.alert('${trading.items.too_many_items.desc}', '${trading.items.too_many_items.title}');
|
||||
}
|
||||
}
|
||||
}, [ canTradeItem, groupItem, isTrading, tradeData ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(needsFurniUpdate)
|
||||
@ -233,10 +130,8 @@ export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
|
||||
{ groupItem &&
|
||||
<div className="d-flex flex-column flex-grow-1">
|
||||
<p className="flex-grow-1 fs-6 text-black my-2">{ groupItem.name }</p>
|
||||
{ !!roomSession && !isTrading &&
|
||||
{ !!roomSession &&
|
||||
<button type="button" className="btn btn-success btn-sm" onClick={ event => attemptItemPlacement(groupItem) }>{ LocalizeText('inventory.furni.placetoroom') }</button> }
|
||||
{ isTrading &&
|
||||
<button type="button" className="btn btn-primary btn-sm" onClick={ event => attemptItemOffer(1) }>{ LocalizeText('inventory.trading.offer') }</button> }
|
||||
</div> }
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,25 +0,0 @@
|
||||
.inventory-furniture-item-container {
|
||||
height: 48px;
|
||||
max-height: 48px;
|
||||
|
||||
.inventory-furniture-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-color: $grid-border-color !important;
|
||||
background-color: $grid-bg-color !important;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
overflow: hidden;
|
||||
|
||||
&.active {
|
||||
border-color: $grid-active-border-color !important;
|
||||
background-color: $grid-active-bg-color !important;
|
||||
}
|
||||
|
||||
.badge {
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
font-size: 8px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { MouseEventType } from 'nitro-renderer';
|
||||
import { FC, MouseEvent, useCallback, useState } from 'react';
|
||||
import { LimitedEditionStyledNumberView } from '../../../../shared/limited-edition/styled-number/LimitedEditionStyledNumberView';
|
||||
import { NitroCardGridItemView } from '../../../../../layout/card/grid/item/NitroCardGridItemView';
|
||||
import { attemptItemPlacement } from '../../../common/FurnitureUtilities';
|
||||
import { useInventoryContext } from '../../../context/InventoryContext';
|
||||
import { InventoryFurnitureActions } from '../../../reducers/InventoryFurnitureReducer';
|
||||
@ -37,18 +37,7 @@ export const InventoryFurnitureItemView: FC<InventoryFurnitureItemViewProps> = p
|
||||
}
|
||||
}, [ isActive, isMouseDown, groupItem, dispatchFurnitureState ]);
|
||||
|
||||
const imageUrl = `url(${ groupItem.iconUrl })`;
|
||||
const count = groupItem.getUnlockedCount();
|
||||
|
||||
return (
|
||||
<div className="col pe-1 pb-1 inventory-furniture-item-container">
|
||||
<div className={ 'position-relative border border-2 rounded inventory-furniture-item cursor-pointer ' + (isActive ? 'active ' : '') + (groupItem.stuffData.isUnique ? 'unique-item ' : '') + (!groupItem.getUnlockedCount() ? 'opacity-0-5 ' : '') } style={ { backgroundImage: imageUrl }} onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent }>
|
||||
{groupItem.getUnlockedCount() > 1 &&
|
||||
<span className="position-absolute badge border bg-danger px-1 rounded-circle">{groupItem.getUnlockedCount()}</span> }
|
||||
{ groupItem.stuffData.isUnique &&
|
||||
<div className="position-absolute unique-item-counter">
|
||||
<LimitedEditionStyledNumberView value={ groupItem.stuffData.uniqueNumber } />
|
||||
</div> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <NitroCardGridItemView className={ !count ? 'opacity-0-5 ' : '' } itemImage={ groupItem.iconUrl } itemCount={ count } itemActive={ isActive } itemUnique={ groupItem.stuffData.isUnique } itemUniqueNumber={ groupItem.stuffData.uniqueNumber } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent } />;
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
.furni-item-container {
|
||||
}
|
@ -1,19 +1,18 @@
|
||||
import { FC } from 'react';
|
||||
import { NitroCardGridView } from '../../../../../layout/card/grid/NitroCardGridView';
|
||||
import { InventoryFurnitureItemView } from '../item/InventoryFurnitureItemView';
|
||||
import { InventoryFurnitureResultsViewProps } from './InventoryFurnitureResultsView.types';
|
||||
|
||||
export const InventoryFurnitureResultsView: FC<InventoryFurnitureResultsViewProps> = props =>
|
||||
{
|
||||
const { groupItems = [] } = props;
|
||||
const { groupItems = [], columns = 5 } = props;
|
||||
|
||||
return (
|
||||
<div className="h-100 overflow-hidden">
|
||||
<div className="row row-cols-5 align-content-start g-0 w-100 h-100 overflow-auto">
|
||||
<NitroCardGridView columns={ columns }>
|
||||
{ groupItems && (groupItems.length > 0) && groupItems.map((item, index) =>
|
||||
{
|
||||
return <InventoryFurnitureItemView key={ index } groupItem={ item } />
|
||||
}) }
|
||||
</div>
|
||||
</div>
|
||||
</NitroCardGridView>
|
||||
);
|
||||
}
|
||||
|
@ -3,4 +3,5 @@ import { GroupItem } from '../../../common/GroupItem';
|
||||
export interface InventoryFurnitureResultsViewProps
|
||||
{
|
||||
groupItems: GroupItem[];
|
||||
columns?: number;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ export const InventoryFurnitureSearchView: FC<InventoryFurnitureSearchViewProps>
|
||||
{
|
||||
const comparison = searchValue.toLocaleLowerCase();
|
||||
|
||||
filteredGroupItems = filteredGroupItems.filter(item =>
|
||||
filteredGroupItems = groupItems.filter(item =>
|
||||
{
|
||||
if(comparison && comparison.length)
|
||||
{
|
||||
|
@ -1,2 +0,0 @@
|
||||
@import './item/InventoryPetItemView';
|
||||
@import './results/InventoryPetResultsView';
|
@ -1,17 +0,0 @@
|
||||
.inventory-pet-item-container {
|
||||
height: 48px;
|
||||
max-height: 48px;
|
||||
|
||||
.inventory-pet-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-color: $grid-border-color !important;
|
||||
background-color: $grid-bg-color;
|
||||
overflow: hidden;
|
||||
|
||||
&.active {
|
||||
border-color: $grid-active-border-color!important;
|
||||
background-color: $grid-active-bg-color;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { MouseEventType } from 'nitro-renderer';
|
||||
import { FC, MouseEvent, useCallback, useState } from 'react';
|
||||
import { NitroCardGridItemView } from '../../../../../layout/card/grid/item/NitroCardGridItemView';
|
||||
import { PetImageView } from '../../../../shared/pet-image/PetImageView';
|
||||
import { attemptPetPlacement } from '../../../common/PetUtilities';
|
||||
import { useInventoryContext } from '../../../context/InventoryContext';
|
||||
@ -37,10 +38,8 @@ export const InventoryPetItemView: FC<InventoryPetItemViewProps> = props =>
|
||||
}, [ isActive, isMouseDown, petItem, dispatchPetState ]);
|
||||
|
||||
return (
|
||||
<div className="col pe-1 pb-1 inventory-pet-item-container">
|
||||
<div className={ 'position-relative border border-2 rounded inventory-pet-item cursor-pointer ' + (isActive ? 'active' : '') } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent }>
|
||||
<NitroCardGridItemView itemActive={ isActive } onMouseDown={ onMouseEvent } onMouseUp={ onMouseEvent } onMouseOut={ onMouseEvent }>
|
||||
<PetImageView figure={ petItem.petData.figureData.figuredata } direction={ 3 } headOnly={ true } />
|
||||
</div>
|
||||
</div>
|
||||
</NitroCardGridItemView>
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
.pet-item-container {
|
||||
height: 220px;
|
||||
max-height: 220px;
|
||||
overflow-y: auto;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { NitroCardGridView } from '../../../../../layout/card/grid/NitroCardGridView';
|
||||
import { InventoryPetItemView } from '../item/InventoryPetItemView';
|
||||
import { InventoryPetResultsViewProps } from './InventoryPetResultsView.types';
|
||||
|
||||
@ -7,13 +8,11 @@ export const InventoryPetResultsView: FC<InventoryPetResultsViewProps> = props =
|
||||
const { petItems = [] } = props;
|
||||
|
||||
return (
|
||||
<div className="h-100 overflow-hidden">
|
||||
<div className="row row-cols-5 align-content-start g-0 w-100 h-100 overflow-auto">
|
||||
<NitroCardGridView>
|
||||
{ petItems && (petItems.length > 0) && petItems.map(item =>
|
||||
{
|
||||
return <InventoryPetItemView key={ item.id } petItem={ item } />
|
||||
}) }
|
||||
</div>
|
||||
</div>
|
||||
</NitroCardGridView>
|
||||
);
|
||||
}
|
||||
|
@ -1,36 +1,203 @@
|
||||
import { FC } from 'react';
|
||||
import { FurnitureListComposer, IObjectData, TradingListAddItemComposer, TradingListAddItemsComposer, TradingListItemRemoveComposer } from 'nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { SendMessageHook } from '../../../../hooks/messages';
|
||||
import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView';
|
||||
import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView';
|
||||
import { LocalizeText } from '../../../../utils/LocalizeText';
|
||||
import { FurniCategory } from '../../common/FurniCategory';
|
||||
import { GroupItem } from '../../common/GroupItem';
|
||||
import { IFurnitureItem } from '../../common/IFurnitureItem';
|
||||
import { _Str_16998 } from '../../common/TradingUtilities';
|
||||
import { useInventoryContext } from '../../context/InventoryContext';
|
||||
import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer';
|
||||
import { InventoryFurnitureSearchView } from '../furniture/search/InventoryFurnitureSearchView';
|
||||
import { InventoryTradeViewProps } from './InventoryTradeView.types';
|
||||
import { InventoryTradeItemView } from './item/InventoryTradeItemView';
|
||||
|
||||
const MAX_ITEMS_COUNT: number = 9;
|
||||
const MAX_ITEMS_TO_TRADE: number = 9;
|
||||
|
||||
export const InventoryTradeView: FC<InventoryTradeViewProps> = props =>
|
||||
{
|
||||
const { isInFurnitureView = false } = props;
|
||||
const { furnitureState = null } = useInventoryContext();
|
||||
const { tradeData = null } = furnitureState;
|
||||
const { furnitureState = null, dispatchFurnitureState = null } = useInventoryContext();
|
||||
const { needsFurniUpdate = false, groupItems = [], tradeData = null } = furnitureState;
|
||||
const [ groupItem, setGroupItem ] = useState<GroupItem>(null);
|
||||
const [ selectedGroupItem, setSelectedGroupItem ] = useState<GroupItem>(null);
|
||||
const [ filteredGroupItems, setFilteredGroupItems ] = useState<GroupItem[]>(null);
|
||||
|
||||
const close = useCallback(() =>
|
||||
{
|
||||
|
||||
}, []);
|
||||
|
||||
const canTradeItem = useCallback((isWallItem: boolean, spriteId: number, category: number, groupable: boolean, stuffData: IObjectData) =>
|
||||
{
|
||||
if(!tradeData || !tradeData.ownUser || tradeData.ownUser.accepts || !tradeData.ownUser.items) return false;
|
||||
|
||||
if(tradeData.ownUser.items.length < MAX_ITEMS_TO_TRADE) return true;
|
||||
|
||||
if(!groupable) return false;
|
||||
|
||||
let type = spriteId.toString();
|
||||
|
||||
if(category === FurniCategory._Str_5186)
|
||||
{
|
||||
type = ((type + 'poster') + stuffData.getLegacyString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(category === FurniCategory._Str_12454)
|
||||
{
|
||||
type = _Str_16998(spriteId, stuffData);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = (((isWallItem) ? 'I' : 'S') + type);
|
||||
}
|
||||
}
|
||||
|
||||
return !!tradeData.ownUser.items.getValue(type);
|
||||
}, [ tradeData ]);
|
||||
|
||||
const attemptItemOffer = useCallback((count: number) =>
|
||||
{
|
||||
if(!tradeData || !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 = tradeData.ownUser.items.length;
|
||||
|
||||
if((ownItemCount + itemIds.length) <= 1500)
|
||||
{
|
||||
if(!coreItem.isGroupable && (itemIds.length))
|
||||
{
|
||||
SendMessageHook(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)
|
||||
{
|
||||
SendMessageHook(new TradingListAddItemComposer(tradeIds.pop()));
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessageHook(new TradingListAddItemsComposer(...tradeIds));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//this._notificationService.alert('${trading.items.too_many_items.desc}', '${trading.items.too_many_items.title}');
|
||||
}
|
||||
}, [ groupItem, tradeData, canTradeItem ]);
|
||||
|
||||
const removeItem = useCallback((group: GroupItem) =>
|
||||
{
|
||||
const item = group.getLastItem();
|
||||
|
||||
if(!item) return;
|
||||
|
||||
SendMessageHook(new TradingListItemRemoveComposer(item.id));
|
||||
}, []);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(needsFurniUpdate)
|
||||
{
|
||||
dispatchFurnitureState({
|
||||
type: InventoryFurnitureActions.SET_NEEDS_UPDATE,
|
||||
payload: {
|
||||
flag: false
|
||||
}
|
||||
});
|
||||
|
||||
SendMessageHook(new FurnitureListComposer());
|
||||
}
|
||||
else
|
||||
{
|
||||
setFilteredGroupItems(groupItems);
|
||||
}
|
||||
|
||||
}, [ needsFurniUpdate, groupItems, dispatchFurnitureState ]);
|
||||
|
||||
return (
|
||||
<div className="row h-100 mt-2">
|
||||
<div className="d-flex flex-column col-6">
|
||||
<div className="row h-100">
|
||||
<div className="d-flex flex-column col-4 h-100">
|
||||
<InventoryFurnitureSearchView groupItems={ groupItems } setGroupItems={ setFilteredGroupItems } />
|
||||
<NitroCardGridView columns={ 3 }>
|
||||
{ filteredGroupItems && (filteredGroupItems.length > 0) && filteredGroupItems.map((item, index) =>
|
||||
{
|
||||
const count = item.getUnlockedCount();
|
||||
|
||||
return (
|
||||
<NitroCardGridItemView key={ index } className={ !count ? 'opacity-0-5 ' : '' } itemImage={ item.iconUrl } itemCount={ count } itemActive={ (groupItem === item) } itemUnique={ item.stuffData.isUnique } itemUniqueNumber={ item.stuffData.uniqueNumber } onClick={ event => (count && setGroupItem(item)) }>
|
||||
{ ((count > 0) && (groupItem === item)) &&
|
||||
<button className="btn btn-success btn-sm trade-button" onClick={ event => attemptItemOffer(1) }>
|
||||
<i className="fas fa-chevron-right" />
|
||||
</button> }
|
||||
</NitroCardGridItemView>
|
||||
);
|
||||
}) }
|
||||
</NitroCardGridView>
|
||||
</div>
|
||||
<div className="d-flex flex-column col-4">
|
||||
<div className="badge bg-primary w-100 p-1 mb-1 me-1">{ LocalizeText('inventory.trading.you') }</div>
|
||||
<div className="row row-cols-3 align-content-start g-0 w-100 h-100">
|
||||
{ Array.from(Array(MAX_ITEMS_COUNT), (e, i) =>
|
||||
<NitroCardGridView columns={ 3 }>
|
||||
{ Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) =>
|
||||
{
|
||||
return <InventoryTradeItemView key={ i } groupItem={ (tradeData.ownUser.items.getWithIndex(i) || null) } />;
|
||||
const item = (tradeData.ownUser.items.getWithIndex(i) || null);
|
||||
|
||||
if(!item) return <NitroCardGridItemView key={ i } />;
|
||||
|
||||
return (
|
||||
<NitroCardGridItemView key={ i } itemActive={ (item === selectedGroupItem) } itemImage={ item.iconUrl } itemCount={ item.getTotalCount() } itemUnique={ item.stuffData.isUnique } itemUniqueNumber={ item.stuffData.uniqueNumber } onClick={ event => setSelectedGroupItem(item) }>
|
||||
{ (item === selectedGroupItem) &&
|
||||
<button className="btn btn-danger btn-sm trade-button left" onClick={ event => removeItem(item) }>
|
||||
<i className="fas fa-chevron-left" />
|
||||
</button> }
|
||||
</NitroCardGridItemView>
|
||||
);
|
||||
}) }
|
||||
</NitroCardGridView>
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex flex-column col-6">
|
||||
<div className="d-flex flex-column col-4">
|
||||
<div className="badge bg-primary w-100 p-1 mb-1 me-1">{ tradeData.otherUser.userName }</div>
|
||||
<div className="row row-cols-3 align-content-start g-0 w-100 h-100">
|
||||
{ Array.from(Array(MAX_ITEMS_COUNT), (e, i) =>
|
||||
<NitroCardGridView columns={ 3 }>
|
||||
{ Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) =>
|
||||
{
|
||||
return <InventoryTradeItemView key={ i } groupItem={ (tradeData.otherUser.items.getWithIndex(i) || null) } />;
|
||||
const item = (tradeData.otherUser.items.getWithIndex(i) || null);
|
||||
|
||||
if(!item) return <NitroCardGridItemView key={ i } />;
|
||||
|
||||
return <NitroCardGridItemView key={ i } itemActive={ (item === selectedGroupItem) } itemImage={ item.iconUrl } itemCount={ item.getTotalCount() } itemUnique={ item.stuffData.isUnique } itemUniqueNumber={ item.stuffData.uniqueNumber } onClick={ event => setSelectedGroupItem(item) } />;
|
||||
}) }
|
||||
</NitroCardGridView>
|
||||
</div>
|
||||
<div className="d-flex col-8 offset-4">
|
||||
plz
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,4 +1,3 @@
|
||||
export interface InventoryTradeViewProps
|
||||
{
|
||||
isInFurnitureView: boolean;
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
import { FC, useCallback } from 'react';
|
||||
import { LimitedEditionStyledNumberView } from '../../../../shared/limited-edition/styled-number/LimitedEditionStyledNumberView';
|
||||
import { InventoryTradeItemViewProps } from './InventoryTradeItemView.types';
|
||||
|
||||
export const InventoryTradeItemView: FC<InventoryTradeItemViewProps> = props =>
|
||||
{
|
||||
const { groupItem = null } = props;
|
||||
|
||||
const onClick = useCallback(() =>
|
||||
{
|
||||
|
||||
}, []);
|
||||
|
||||
if(!groupItem)
|
||||
{
|
||||
return (
|
||||
<div className="col pe-1 pb-1 inventory-furniture-item-container">
|
||||
<div className="position-relative border border-2 rounded inventory-furniture-item cursor-pointer" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const imageUrl = `url(${ groupItem.iconUrl })`;
|
||||
|
||||
return (
|
||||
<div className="col pe-1 pb-1 inventory-furniture-item-container">
|
||||
<div className="position-relative border border-2 rounded inventory-furniture-item cursor-pointer" style={ { backgroundImage: imageUrl }} onClick={ onClick }>
|
||||
{ groupItem.getUnlockedCount() > 1 &&
|
||||
<span className="position-absolute badge border bg-danger px-1 rounded-circle">{ groupItem.getUnlockedCount() }</span> }
|
||||
{ groupItem.stuffData.isUnique &&
|
||||
<div className="position-absolute unique-item-counter">
|
||||
<LimitedEditionStyledNumberView value={ groupItem.stuffData.uniqueNumber } />
|
||||
</div> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import { GroupItem } from '../../../common/GroupItem';
|
||||
|
||||
export interface InventoryTradeItemViewProps
|
||||
{
|
||||
groupItem: GroupItem;
|
||||
}
|
Loading…
Reference in New Issue
Block a user