mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
🆙 Added delete Furni / Pets in inventory
This commit is contained in:
@@ -12,7 +12,6 @@
|
|||||||
@import './hc-center/HcCenterView';
|
@import './hc-center/HcCenterView';
|
||||||
@import './help/HelpView';
|
@import './help/HelpView';
|
||||||
@import './hotel-view/HotelView';
|
@import './hotel-view/HotelView';
|
||||||
@import './inventory/InventoryView';
|
|
||||||
@import './loading/LoadingView';
|
@import './loading/LoadingView';
|
||||||
@import './mod-tools/ModToolsView';
|
@import './mod-tools/ModToolsView';
|
||||||
@import './navigator/NavigatorView';
|
@import './navigator/NavigatorView';
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { NitroCard } from '@layout/NitroCard';
|
|
||||||
import { AddLinkEventTracker, BadgePointLimitsEvent, GetLocalizationManager, GetRoomEngine, ILinkEventTracker, IRoomSession, RemoveLinkEventTracker, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent } from '@nitrots/nitro-renderer';
|
import { AddLinkEventTracker, BadgePointLimitsEvent, GetLocalizationManager, GetRoomEngine, ILinkEventTracker, IRoomSession, RemoveLinkEventTracker, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { LocalizeText, UnseenItemCategory, isObjectMoverRequested, setObjectMoverRequested } from '../../api';
|
import { GroupItem, LocalizeText, UnseenItemCategory, isObjectMoverRequested, setObjectMoverRequested } from '../../api';
|
||||||
import { useInventoryTrade, useInventoryUnseenTracker, useMessageEvent, useNitroEvent } from '../../hooks';
|
import { NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
|
||||||
|
import { useInventoryBadges, useInventoryFurni, useInventoryTrade, useInventoryUnseenTracker, useMessageEvent, useNitroEvent } from '../../hooks';
|
||||||
|
import { InventoryCategoryFilterView } from './views/InventoryCategoryFilterView';
|
||||||
import { InventoryBadgeView } from './views/badge/InventoryBadgeView';
|
import { InventoryBadgeView } from './views/badge/InventoryBadgeView';
|
||||||
import { InventoryBotView } from './views/bot/InventoryBotView';
|
import { InventoryBotView } from './views/bot/InventoryBotView';
|
||||||
|
import { InventoryFurnitureDeleteView } from './views/furniture/InventoryFurnitureDeleteView';
|
||||||
import { InventoryFurnitureView } from './views/furniture/InventoryFurnitureView';
|
import { InventoryFurnitureView } from './views/furniture/InventoryFurnitureView';
|
||||||
import { InventoryTradeView } from './views/furniture/InventoryTradeView';
|
import { InventoryTradeView } from './views/furniture/InventoryTradeView';
|
||||||
import { InventoryPetView } from './views/pet/InventoryPetView';
|
import { InventoryPetView } from './views/pet/InventoryPetView';
|
||||||
@@ -13,8 +15,8 @@ const TAB_FURNITURE: string = 'inventory.furni';
|
|||||||
const TAB_BOTS: string = 'inventory.bots';
|
const TAB_BOTS: string = 'inventory.bots';
|
||||||
const TAB_PETS: string = 'inventory.furni.tab.pets';
|
const TAB_PETS: string = 'inventory.furni.tab.pets';
|
||||||
const TAB_BADGES: string = 'inventory.badges';
|
const TAB_BADGES: string = 'inventory.badges';
|
||||||
const TABS = [ TAB_FURNITURE, TAB_BOTS, TAB_PETS, TAB_BADGES ];
|
const TABS = [ TAB_FURNITURE, TAB_PETS, TAB_BADGES, TAB_BOTS ];
|
||||||
const UNSEEN_CATEGORIES = [ UnseenItemCategory.FURNI, UnseenItemCategory.BOT, UnseenItemCategory.PET, UnseenItemCategory.BADGE ];
|
const UNSEEN_CATEGORIES = [ UnseenItemCategory.FURNI, UnseenItemCategory.PET, UnseenItemCategory.BADGE, UnseenItemCategory.BOT ];
|
||||||
|
|
||||||
export const InventoryView: FC<{}> = props =>
|
export const InventoryView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
@@ -22,8 +24,12 @@ export const InventoryView: FC<{}> = props =>
|
|||||||
const [ currentTab, setCurrentTab ] = useState<string>(TABS[0]);
|
const [ currentTab, setCurrentTab ] = useState<string>(TABS[0]);
|
||||||
const [ roomSession, setRoomSession ] = useState<IRoomSession>(null);
|
const [ roomSession, setRoomSession ] = useState<IRoomSession>(null);
|
||||||
const [ roomPreviewer, setRoomPreviewer ] = useState<RoomPreviewer>(null);
|
const [ roomPreviewer, setRoomPreviewer ] = useState<RoomPreviewer>(null);
|
||||||
|
const [ filteredGroupItems, setFilteredGroupItems ] = useState<GroupItem[]>([]);
|
||||||
|
const [ filteredBadgeCodes, setFilteredBadgeCodes ] = useState<string[]>([]);
|
||||||
const { isTrading = false, stopTrading = null } = useInventoryTrade();
|
const { isTrading = false, stopTrading = null } = useInventoryTrade();
|
||||||
const { getCount = null, resetCategory = null } = useInventoryUnseenTracker();
|
const { getCount = null } = useInventoryUnseenTracker();
|
||||||
|
const { groupItems = [] } = useInventoryFurni();
|
||||||
|
const { badgeCodes = [] } = useInventoryBadges();
|
||||||
|
|
||||||
const onClose = () =>
|
const onClose = () =>
|
||||||
{
|
{
|
||||||
@@ -117,44 +123,59 @@ export const InventoryView: FC<{}> = props =>
|
|||||||
|
|
||||||
if(!isVisible) return null;
|
if(!isVisible) return null;
|
||||||
|
|
||||||
|
const showFilter = !isTrading && (currentTab === TAB_FURNITURE || currentTab === TAB_BADGES);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCard
|
<>
|
||||||
className="w-inventory-w h-inventory-h min-w-inventory-w min-h-inventory-h"
|
<NitroCardView className="nitro-inventory" uniqueKey="inventory">
|
||||||
uniqueKey="inventory">
|
<NitroCardHeaderView
|
||||||
<NitroCard.Header
|
headerText={ LocalizeText('inventory.title') }
|
||||||
headerText={ LocalizeText('inventory.title') }
|
onCloseClick={ onClose } />
|
||||||
onCloseClick={ onClose } />
|
{ !isTrading &&
|
||||||
{ !isTrading &&
|
<>
|
||||||
<>
|
<NitroCardTabsView>
|
||||||
<NitroCard.Tabs>
|
{ TABS.map((name, index) =>
|
||||||
{ TABS.map((name, index) =>
|
{
|
||||||
{
|
return (
|
||||||
return (
|
<NitroCardTabsItemView
|
||||||
<NitroCard.TabItem
|
key={ index }
|
||||||
key={ index }
|
count={ getCount(UNSEEN_CATEGORIES[index]) }
|
||||||
count={ getCount(UNSEEN_CATEGORIES[index]) }
|
isActive={ (currentTab === name) }
|
||||||
isActive={ (currentTab === name) }
|
onClick={ event => setCurrentTab(name) }>
|
||||||
onClick={ event => setCurrentTab(name) }>
|
{ LocalizeText(name) }
|
||||||
{ LocalizeText(name) }
|
</NitroCardTabsItemView>
|
||||||
</NitroCard.TabItem>
|
);
|
||||||
);
|
}) }
|
||||||
}) }
|
</NitroCardTabsView>
|
||||||
</NitroCard.Tabs>
|
<div className="flex flex-col overflow-hidden bg-[#DFDFDF] p-2 h-full gap-2">
|
||||||
<NitroCard.Content>
|
{ showFilter &&
|
||||||
{ (currentTab === TAB_FURNITURE ) &&
|
<InventoryCategoryFilterView
|
||||||
<InventoryFurnitureView roomPreviewer={ roomPreviewer } roomSession={ roomSession } /> }
|
badgeCodes={ badgeCodes }
|
||||||
{ (currentTab === TAB_BOTS ) &&
|
currentTab={ currentTab }
|
||||||
<InventoryBotView roomPreviewer={ roomPreviewer } roomSession={ roomSession } /> }
|
groupItems={ groupItems }
|
||||||
{ (currentTab === TAB_PETS ) &&
|
setBadgeCodes={ setFilteredBadgeCodes }
|
||||||
<InventoryPetView roomPreviewer={ roomPreviewer } roomSession={ roomSession } /> }
|
setGroupItems={ setFilteredGroupItems } /> }
|
||||||
{ (currentTab === TAB_BADGES ) &&
|
<div className="flex-1 overflow-hidden">
|
||||||
<InventoryBadgeView /> }
|
{ (currentTab === TAB_FURNITURE) &&
|
||||||
</NitroCard.Content>
|
<InventoryFurnitureView
|
||||||
</> }
|
filteredGroupItems={ filteredGroupItems }
|
||||||
{ isTrading &&
|
roomPreviewer={ roomPreviewer }
|
||||||
<NitroCard.Content>
|
roomSession={ roomSession } /> }
|
||||||
<InventoryTradeView cancelTrade={ onClose } />
|
{ (currentTab === TAB_PETS) &&
|
||||||
</NitroCard.Content> }
|
<InventoryPetView roomPreviewer={ roomPreviewer } roomSession={ roomSession } /> }
|
||||||
</NitroCard>
|
{ (currentTab === TAB_BADGES) &&
|
||||||
|
<InventoryBadgeView filteredBadgeCodes={ filteredBadgeCodes } /> }
|
||||||
|
{ (currentTab === TAB_BOTS) &&
|
||||||
|
<InventoryBotView roomPreviewer={ roomPreviewer } roomSession={ roomSession } /> }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</> }
|
||||||
|
{ isTrading &&
|
||||||
|
<div className="flex flex-col overflow-hidden bg-[#DFDFDF] p-2 h-full">
|
||||||
|
<InventoryTradeView cancelTrade={ onClose } />
|
||||||
|
</div> }
|
||||||
|
</NitroCardView>
|
||||||
|
<InventoryFurnitureDeleteView />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import { Dispatch, FC, SetStateAction, useEffect, useState } from 'react';
|
||||||
|
import { GroupItem, LocalizeBadgeName, LocalizeText } from '../../../api';
|
||||||
|
import { NitroInput } from '../../../layout';
|
||||||
|
|
||||||
|
const FILTER_EVERYTHING = 'inventory.filter.option.everything';
|
||||||
|
const FILTER_FLOOR = 'inventory.furni.tab.floor';
|
||||||
|
const FILTER_WALL = 'inventory.furni.tab.wall';
|
||||||
|
|
||||||
|
const TAB_BADGES = 'inventory.badges';
|
||||||
|
const TAB_FURNITURE = 'inventory.furni';
|
||||||
|
|
||||||
|
interface InventoryCategoryFilterViewProps
|
||||||
|
{
|
||||||
|
currentTab: string;
|
||||||
|
groupItems: GroupItem[];
|
||||||
|
badgeCodes: string[];
|
||||||
|
setGroupItems: Dispatch<SetStateAction<GroupItem[]>>;
|
||||||
|
setBadgeCodes: Dispatch<SetStateAction<string[]>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const InventoryCategoryFilterView: FC<InventoryCategoryFilterViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { currentTab = null, groupItems = [], badgeCodes = [], setGroupItems = null, setBadgeCodes = null } = props;
|
||||||
|
const [ filterType, setFilterType ] = useState<string>(FILTER_EVERYTHING);
|
||||||
|
const [ searchValue, setSearchValue ] = useState('');
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(currentTab !== TAB_BADGES) return;
|
||||||
|
|
||||||
|
const comparison = searchValue.toLocaleLowerCase().replace(' ', '');
|
||||||
|
|
||||||
|
const filteredBadges = badgeCodes.filter(badge => badge.startsWith('ACH_'));
|
||||||
|
const numberMap: { [key: string]: number } = {};
|
||||||
|
|
||||||
|
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 deduped = Object.keys(numberMap)
|
||||||
|
.map(name => `${ name }${ numberMap[name] }`)
|
||||||
|
.concat(badgeCodes.filter(badge => !badge.startsWith('ACH_')));
|
||||||
|
|
||||||
|
const filtered = deduped.filter(badgeCode =>
|
||||||
|
LocalizeBadgeName(badgeCode).toLocaleLowerCase().includes(comparison)
|
||||||
|
);
|
||||||
|
|
||||||
|
setBadgeCodes(filtered);
|
||||||
|
}, [ badgeCodes, currentTab, searchValue, setBadgeCodes ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(currentTab !== TAB_FURNITURE) return;
|
||||||
|
|
||||||
|
const comparison = searchValue.toLocaleLowerCase();
|
||||||
|
|
||||||
|
if(filterType === FILTER_EVERYTHING)
|
||||||
|
{
|
||||||
|
setGroupItems(groupItems.filter(item => item.name.toLocaleLowerCase().includes(comparison)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filtered = groupItems.filter(item =>
|
||||||
|
{
|
||||||
|
const isWall = filterType === FILTER_WALL ? item.isWallItem : false;
|
||||||
|
const isFloor = filterType === FILTER_FLOOR ? !item.isWallItem : false;
|
||||||
|
const matchesSearch = item.name.toLocaleLowerCase().includes(comparison);
|
||||||
|
|
||||||
|
return comparison.length ? (matchesSearch && (isWall || isFloor)) : (isWall || isFloor);
|
||||||
|
});
|
||||||
|
|
||||||
|
setGroupItems(filtered);
|
||||||
|
}, [ groupItems, setGroupItems, searchValue, filterType, currentTab ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
setFilterType(FILTER_EVERYTHING);
|
||||||
|
setSearchValue('');
|
||||||
|
}, [ currentTab ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex gap-1 rounded p-1 bg-[#C9C9C9] shrink-0"
|
||||||
|
style={ { width: currentTab === TAB_BADGES ? '320px' : '100%' } }>
|
||||||
|
<div className="relative flex flex-1 items-center">
|
||||||
|
<NitroInput
|
||||||
|
className="w-full"
|
||||||
|
placeholder={ LocalizeText('catalog.search') }
|
||||||
|
value={ searchValue }
|
||||||
|
onChange={ event => setSearchValue(event.target.value) } />
|
||||||
|
{ (searchValue && searchValue.length > 0) &&
|
||||||
|
<i
|
||||||
|
className="icon icon-clear absolute cursor-pointer right-1 top-1"
|
||||||
|
onClick={ () => setSearchValue('') } /> }
|
||||||
|
</div>
|
||||||
|
{ currentTab !== TAB_BADGES &&
|
||||||
|
<select
|
||||||
|
className="form-select text-xs rounded px-1 py-0 border border-gray-400 bg-white cursor-pointer"
|
||||||
|
value={ filterType }
|
||||||
|
onChange={ event => setFilterType(event.target.value) }>
|
||||||
|
{ [ FILTER_EVERYTHING, FILTER_FLOOR, FILTER_WALL ].map((type, index) =>
|
||||||
|
<option key={ index } value={ type }>{ LocalizeText(type) }</option>
|
||||||
|
) }
|
||||||
|
</select> }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -5,12 +5,15 @@ import { useInventoryBadges, useInventoryUnseenTracker } from '../../../../hooks
|
|||||||
import { InfiniteGrid, NitroButton } from '../../../../layout';
|
import { InfiniteGrid, NitroButton } from '../../../../layout';
|
||||||
import { InventoryBadgeItemView } from './InventoryBadgeItemView';
|
import { InventoryBadgeItemView } from './InventoryBadgeItemView';
|
||||||
|
|
||||||
export const InventoryBadgeView: FC<{}> = props =>
|
export const InventoryBadgeView: FC<{ filteredBadgeCodes?: string[] }> = props =>
|
||||||
{
|
{
|
||||||
|
const { filteredBadgeCodes = null } = props;
|
||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
const { badgeCodes = [], 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 { isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker();
|
||||||
|
|
||||||
|
const displayCodes = (filteredBadgeCodes !== null ? filteredBadgeCodes : badgeCodes);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!selectedBadgeCode || !isUnseen(UnseenItemCategory.BADGE, getBadgeId(selectedBadgeCode))) return;
|
if(!selectedBadgeCode || !isUnseen(UnseenItemCategory.BADGE, getBadgeId(selectedBadgeCode))) return;
|
||||||
@@ -41,7 +44,7 @@ export const InventoryBadgeView: FC<{}> = props =>
|
|||||||
columnCount={ 5 }
|
columnCount={ 5 }
|
||||||
estimateSize={ 50 }
|
estimateSize={ 50 }
|
||||||
itemRender={ item => <InventoryBadgeItemView badgeCode={ item } /> }
|
itemRender={ item => <InventoryBadgeItemView badgeCode={ item } /> }
|
||||||
items={ badgeCodes.filter(code => !isWearingBadge(code)) } />
|
items={ displayCodes.filter(code => !isWearingBadge(code)) } />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col justify-between col-span-5 overflow-auto">
|
<div className="flex flex-col justify-between col-span-5 overflow-auto">
|
||||||
<div className="flex flex-col gap-2 overflow-hidden">
|
<div className="flex flex-col gap-2 overflow-hidden">
|
||||||
@@ -54,7 +57,7 @@ export const InventoryBadgeView: FC<{}> = props =>
|
|||||||
</div>
|
</div>
|
||||||
{ !!selectedBadgeCode &&
|
{ !!selectedBadgeCode &&
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<div className="items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<LayoutBadgeImageView shrink badgeCode={ selectedBadgeCode } />
|
<LayoutBadgeImageView shrink badgeCode={ selectedBadgeCode } />
|
||||||
<span className="text-sm truncate grow">{ LocalizeBadgeName(selectedBadgeCode) }</span>
|
<span className="text-sm truncate grow">{ LocalizeBadgeName(selectedBadgeCode) }</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
import { DeleteItemMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useState } from 'react';
|
||||||
|
import { FaCaretLeft, FaCaretRight } from 'react-icons/fa';
|
||||||
|
import { FurnitureItem, LocalizeText, ProductTypeEnum, SendMessageComposer } from '../../../../api';
|
||||||
|
import { LayoutFurniImageView, NitroCardHeaderView, NitroCardView } from '../../../../common';
|
||||||
|
import { DeleteItemConfirmEvent } from '../../../../events';
|
||||||
|
import { useNotification, useUiEvent } from '../../../../hooks';
|
||||||
|
import { NitroButton, NitroInput } from '../../../../layout';
|
||||||
|
|
||||||
|
export const InventoryFurnitureDeleteView: FC<{}> = props =>
|
||||||
|
{
|
||||||
|
const [ item, setItem ] = useState<FurnitureItem>(null);
|
||||||
|
const [ amount, setAmount ] = useState(1);
|
||||||
|
const [ maxAmount, setMaxAmount ] = useState(1);
|
||||||
|
const { showConfirm = null } = useNotification();
|
||||||
|
|
||||||
|
const onClose = () =>
|
||||||
|
{
|
||||||
|
setItem(null);
|
||||||
|
setAmount(1);
|
||||||
|
setMaxAmount(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateAmount = (value: string) =>
|
||||||
|
{
|
||||||
|
let newValue = parseInt(value);
|
||||||
|
|
||||||
|
if(isNaN(newValue)) newValue = 1;
|
||||||
|
|
||||||
|
newValue = Math.max(newValue, 1);
|
||||||
|
newValue = Math.min(newValue, maxAmount);
|
||||||
|
|
||||||
|
setAmount(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteItem = () =>
|
||||||
|
{
|
||||||
|
if(!item) return;
|
||||||
|
|
||||||
|
const furniTitle = LocalizeText(item.isWallItem ? 'wallItem.name.' + item.type : 'roomItem.name.' + item.type);
|
||||||
|
|
||||||
|
showConfirm(
|
||||||
|
LocalizeText('inventory.delete.confirm_delete.info', [ 'furniname', 'amount' ], [ furniTitle, amount.toString() ]),
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
SendMessageComposer(new DeleteItemMessageComposer(item.id, amount));
|
||||||
|
onClose();
|
||||||
|
},
|
||||||
|
() => onClose(),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
LocalizeText('inventory.delete.confirm_delete.title')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
useUiEvent<DeleteItemConfirmEvent>(DeleteItemConfirmEvent.DELETE_ITEM_CONFIRM, event =>
|
||||||
|
{
|
||||||
|
setItem(event.item);
|
||||||
|
setMaxAmount(event.amount);
|
||||||
|
setAmount(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!item) return null;
|
||||||
|
|
||||||
|
const furniTitle = LocalizeText(item.isWallItem ? 'wallItem.name.' + item.type : 'roomItem.name.' + item.type);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardView className="w-[340px]" uniqueKey="inventory-delete">
|
||||||
|
<NitroCardHeaderView
|
||||||
|
headerText={ LocalizeText('inventory.delete.confirm_delete.title') }
|
||||||
|
onCloseClick={ onClose } />
|
||||||
|
<div className="bg-[#DFDFDF] p-2">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="shrink-0 w-[64px] h-[64px] bg-white rounded flex items-center justify-center">
|
||||||
|
<LayoutFurniImageView
|
||||||
|
extraData={ item.extra.toString() }
|
||||||
|
productClassId={ item.type }
|
||||||
|
productType={ item.isWallItem ? ProductTypeEnum.WALL : ProductTypeEnum.FLOOR } />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-1.5 flex-1 min-w-0">
|
||||||
|
<span className="font-bold text-sm truncate">{ furniTitle }</span>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<FaCaretLeft
|
||||||
|
className="cursor-pointer text-black fa-icon shrink-0"
|
||||||
|
onClick={ () => updateAmount((amount - 1).toString()) } />
|
||||||
|
<NitroInput
|
||||||
|
className="quantity-input text-center !py-0.5"
|
||||||
|
type="number"
|
||||||
|
min={ 1 }
|
||||||
|
max={ maxAmount }
|
||||||
|
value={ amount }
|
||||||
|
onChange={ event => updateAmount(event.target.value) } />
|
||||||
|
<FaCaretRight
|
||||||
|
className="cursor-pointer text-black fa-icon shrink-0"
|
||||||
|
onClick={ () => updateAmount((amount + 1).toString()) } />
|
||||||
|
<NitroButton className="text-xs py-0.5 px-1 shrink-0" onClick={ () => updateAmount(maxAmount.toString()) }>
|
||||||
|
{ LocalizeText('inventory.delete.max_amount.button') }
|
||||||
|
</NitroButton>
|
||||||
|
</div>
|
||||||
|
<NitroButton
|
||||||
|
className="!bg-danger hover:!bg-danger/80 w-full"
|
||||||
|
disabled={ amount > maxAmount }
|
||||||
|
onClick={ deleteItem }>
|
||||||
|
{ LocalizeText('inventory.delete.confirm_delete.button') }
|
||||||
|
</NitroButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</NitroCardView>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import { InfiniteGrid } from '@layout/InfiniteGrid';
|
import { InfiniteGrid } from '@layout/InfiniteGrid';
|
||||||
import { GetRoomEngine, GetSessionDataManager, IRoomSession, RoomObjectVariable, RoomPreviewer, Vector3d } from '@nitrots/nitro-renderer';
|
import { GetRoomEngine, GetSessionDataManager, IRoomSession, RoomObjectVariable, RoomPreviewer, Vector3d } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
|
import { FaTrashAlt } from 'react-icons/fa';
|
||||||
import { DispatchUiEvent, FurniCategory, GroupItem, LocalizeText, UnseenItemCategory, attemptItemPlacement } from '../../../../api';
|
import { DispatchUiEvent, FurniCategory, GroupItem, LocalizeText, UnseenItemCategory, attemptItemPlacement } from '../../../../api';
|
||||||
import { LayoutLimitedEditionCompactPlateView, LayoutRarityLevelView, LayoutRoomPreviewerView } from '../../../../common';
|
import { LayoutLimitedEditionCompactPlateView, LayoutRarityLevelView, LayoutRoomPreviewerView } from '../../../../common';
|
||||||
import { CatalogPostMarketplaceOfferEvent } from '../../../../events';
|
import { CatalogPostMarketplaceOfferEvent, DeleteItemConfirmEvent } from '../../../../events';
|
||||||
import { useInventoryFurni, useInventoryUnseenTracker } from '../../../../hooks';
|
import { useInventoryFurni, useInventoryUnseenTracker } from '../../../../hooks';
|
||||||
import { NitroButton } from '../../../../layout';
|
import { NitroButton } from '../../../../layout';
|
||||||
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
|
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
|
||||||
import { InventoryFurnitureItemView } from './InventoryFurnitureItemView';
|
import { InventoryFurnitureItemView } from './InventoryFurnitureItemView';
|
||||||
import { InventoryFurnitureSearchView } from './InventoryFurnitureSearchView';
|
|
||||||
|
|
||||||
const attemptPlaceMarketplaceOffer = (groupItem: GroupItem) =>
|
const attemptPlaceMarketplaceOffer = (groupItem: GroupItem) =>
|
||||||
{
|
{
|
||||||
@@ -21,14 +21,23 @@ const attemptPlaceMarketplaceOffer = (groupItem: GroupItem) =>
|
|||||||
DispatchUiEvent(new CatalogPostMarketplaceOfferEvent(item));
|
DispatchUiEvent(new CatalogPostMarketplaceOfferEvent(item));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const attemptDeleteItem = (groupItem: GroupItem) =>
|
||||||
|
{
|
||||||
|
const item = groupItem.getLastItem();
|
||||||
|
|
||||||
|
if(!item) return;
|
||||||
|
|
||||||
|
DispatchUiEvent(new DeleteItemConfirmEvent(item, groupItem.getTotalCount()));
|
||||||
|
};
|
||||||
|
|
||||||
export const InventoryFurnitureView: FC<{
|
export const InventoryFurnitureView: FC<{
|
||||||
roomSession: IRoomSession;
|
roomSession: IRoomSession;
|
||||||
roomPreviewer: RoomPreviewer;
|
roomPreviewer: RoomPreviewer;
|
||||||
|
filteredGroupItems: GroupItem[];
|
||||||
}> = props =>
|
}> = props =>
|
||||||
{
|
{
|
||||||
const { roomSession = null, roomPreviewer = null } = props;
|
const { roomSession = null, roomPreviewer = null, filteredGroupItems = [] } = props;
|
||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
const [ filteredGroupItems, setFilteredGroupItems ] = useState<GroupItem[]>([]);
|
|
||||||
const { groupItems = [], selectedItem = null, activate = null, deactivate = null } = useInventoryFurni();
|
const { groupItems = [], selectedItem = null, activate = null, deactivate = null } = useInventoryFurni();
|
||||||
const { resetItems = null } = useInventoryUnseenTracker();
|
const { resetItems = null } = useInventoryUnseenTracker();
|
||||||
|
|
||||||
@@ -112,7 +121,6 @@ export const InventoryFurnitureView: FC<{
|
|||||||
return (
|
return (
|
||||||
<div className="grid h-full grid-cols-12 gap-2">
|
<div className="grid h-full grid-cols-12 gap-2">
|
||||||
<div className="flex flex-col col-span-7 gap-1 overflow-hidden">
|
<div className="flex flex-col col-span-7 gap-1 overflow-hidden">
|
||||||
<InventoryFurnitureSearchView groupItems={ groupItems } setGroupItems={ setFilteredGroupItems } />
|
|
||||||
<InfiniteGrid<GroupItem>
|
<InfiniteGrid<GroupItem>
|
||||||
columnCount={ 6 }
|
columnCount={ 6 }
|
||||||
itemRender={ item => <InventoryFurnitureItemView groupItem={ item } /> }
|
itemRender={ item => <InventoryFurnitureItemView groupItem={ item } /> }
|
||||||
@@ -121,25 +129,33 @@ export const InventoryFurnitureView: FC<{
|
|||||||
<div className="flex flex-col col-span-5">
|
<div className="flex flex-col col-span-5">
|
||||||
<div className="relative flex flex-col">
|
<div className="relative flex flex-col">
|
||||||
<LayoutRoomPreviewerView height={ 140 } roomPreviewer={ roomPreviewer } />
|
<LayoutRoomPreviewerView height={ 140 } roomPreviewer={ roomPreviewer } />
|
||||||
|
{ selectedItem &&
|
||||||
|
<NitroButton
|
||||||
|
className="!bg-danger hover:!bg-danger/80 absolute bottom-2 end-2 p-1"
|
||||||
|
onClick={ () => attemptDeleteItem(selectedItem) }>
|
||||||
|
<FaTrashAlt className="fa-icon" />
|
||||||
|
</NitroButton> }
|
||||||
{ selectedItem && selectedItem.stuffData.isUnique &&
|
{ selectedItem && selectedItem.stuffData.isUnique &&
|
||||||
<LayoutLimitedEditionCompactPlateView className="top-2 end-2" position="absolute" uniqueNumber={ selectedItem.stuffData.uniqueNumber } uniqueSeries={ selectedItem.stuffData.uniqueSeries } /> }
|
<LayoutLimitedEditionCompactPlateView className="top-2 end-2" position="absolute" uniqueNumber={ selectedItem.stuffData.uniqueNumber } uniqueSeries={ selectedItem.stuffData.uniqueSeries } /> }
|
||||||
{ (selectedItem && selectedItem.stuffData.rarityLevel > -1) &&
|
{ (selectedItem && selectedItem.stuffData.rarityLevel > -1) &&
|
||||||
<LayoutRarityLevelView className="top-2 end-2" level={ selectedItem.stuffData.rarityLevel } position="absolute" /> }
|
<LayoutRarityLevelView className="top-2 end-2" level={ selectedItem.stuffData.rarityLevel } position="absolute" /> }
|
||||||
</div>
|
</div>
|
||||||
{ selectedItem &&
|
{ selectedItem &&
|
||||||
<div className="flex flex-col justify-between gap-2 grow">
|
<div className="flex flex-col justify-between gap-2 grow">
|
||||||
<span className="text-sm truncate grow">{ selectedItem.name }</span>
|
<span className="text-sm truncate grow">{ selectedItem.name }</span>
|
||||||
<div className="flex flex-col gap-1">
|
{ selectedItem.description &&
|
||||||
{ !!roomSession &&
|
<span className="text-xs truncate">{ selectedItem.description }</span> }
|
||||||
<NitroButton onClick={ event => attemptItemPlacement(selectedItem) }>
|
<div className="flex flex-col gap-1">
|
||||||
{ LocalizeText('inventory.furni.placetoroom') }
|
{ !!roomSession &&
|
||||||
</NitroButton> }
|
<NitroButton onClick={ event => attemptItemPlacement(selectedItem) }>
|
||||||
{ (selectedItem && selectedItem.isSellable) &&
|
{ LocalizeText('inventory.furni.placetoroom') }
|
||||||
<NitroButton onClick={ event => attemptPlaceMarketplaceOffer(selectedItem) }>
|
</NitroButton> }
|
||||||
{ LocalizeText('inventory.marketplace.sell') }
|
{ selectedItem.isSellable &&
|
||||||
</NitroButton> }
|
<NitroButton onClick={ event => attemptPlaceMarketplaceOffer(selectedItem) }>
|
||||||
</div>
|
{ LocalizeText('inventory.marketplace.sell') }
|
||||||
</div> }
|
</NitroButton> }
|
||||||
|
</div>
|
||||||
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { GetRoomEngine, IRoomSession, RoomObjectVariable, RoomPreviewer } from '@nitrots/nitro-renderer';
|
import { DeletePetMessageComposer, GetRoomEngine, IRoomSession, RoomObjectVariable, RoomPreviewer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { IPetItem, LocalizeText, UnseenItemCategory, attemptPetPlacement } from '../../../../api';
|
import { FaTrashAlt } from 'react-icons/fa';
|
||||||
|
import { IPetItem, LocalizeText, SendMessageComposer, UnseenItemCategory, attemptPetPlacement } from '../../../../api';
|
||||||
import { LayoutRoomPreviewerView } from '../../../../common';
|
import { LayoutRoomPreviewerView } from '../../../../common';
|
||||||
import { useInventoryPets, useInventoryUnseenTracker } from '../../../../hooks';
|
import { useInventoryPets, useInventoryUnseenTracker, useNotification } from '../../../../hooks';
|
||||||
import { InfiniteGrid, NitroButton } from '../../../../layout';
|
import { InfiniteGrid, NitroButton } from '../../../../layout';
|
||||||
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
|
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
|
||||||
import { InventoryPetItemView } from './InventoryPetItemView';
|
import { InventoryPetItemView } from './InventoryPetItemView';
|
||||||
@@ -16,6 +17,21 @@ export const InventoryPetView: FC<{
|
|||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
const { petItems = null, selectedPet = null, activate = null, deactivate = null } = useInventoryPets();
|
const { petItems = null, selectedPet = null, activate = null, deactivate = null } = useInventoryPets();
|
||||||
const { isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker();
|
const { isUnseen = null, removeUnseen = null } = useInventoryUnseenTracker();
|
||||||
|
const { showConfirm = null } = useNotification();
|
||||||
|
|
||||||
|
const attemptDeletePet = () =>
|
||||||
|
{
|
||||||
|
if(!selectedPet?.petData) return;
|
||||||
|
|
||||||
|
showConfirm(
|
||||||
|
LocalizeText('inventory.delete.confirm_delete.info', [ 'furniname', 'amount' ], [ selectedPet.petData.name, '1' ]),
|
||||||
|
() => SendMessageComposer(new DeletePetMessageComposer(selectedPet.petData.id)),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
LocalizeText('inventory.delete.confirm_delete.title')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@@ -74,6 +90,12 @@ export const InventoryPetView: FC<{
|
|||||||
<div className="flex flex-col col-span-5">
|
<div className="flex flex-col col-span-5">
|
||||||
<div className="relative flex flex-col">
|
<div className="relative flex flex-col">
|
||||||
<LayoutRoomPreviewerView height={ 140 } roomPreviewer={ roomPreviewer } />
|
<LayoutRoomPreviewerView height={ 140 } roomPreviewer={ roomPreviewer } />
|
||||||
|
{ selectedPet &&
|
||||||
|
<NitroButton
|
||||||
|
className="!bg-danger hover:!bg-danger/80 absolute bottom-2 end-2 p-1"
|
||||||
|
onClick={ attemptDeletePet }>
|
||||||
|
<FaTrashAlt className="fa-icon" />
|
||||||
|
</NitroButton> }
|
||||||
</div>
|
</div>
|
||||||
{ selectedPet && selectedPet.petData &&
|
{ selectedPet && selectedPet.petData &&
|
||||||
<div className="flex flex-col justify-between gap-2 grow">
|
<div className="flex flex-col justify-between gap-2 grow">
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
:root {
|
||||||
|
--inventory-width: 528px;
|
||||||
|
--inventory-height: 420px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nitro-inventory {
|
||||||
|
width: var(--inventory-width);
|
||||||
|
height: var(--inventory-height);
|
||||||
|
min-width: var(--inventory-width);
|
||||||
|
min-height: var(--inventory-height);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-image {
|
||||||
|
background: url("@/assets/images/inventory/empty.png");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
width: 129px;
|
||||||
|
height: 181px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trade-button {
|
||||||
|
min-height: 0;
|
||||||
|
font-size: 8px;
|
||||||
|
padding: 1px 2px;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quantity-input {
|
||||||
|
width: 49px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { NitroEvent } from '@nitrots/nitro-renderer';
|
||||||
|
import { FurnitureItem } from '../../api';
|
||||||
|
|
||||||
|
export class DeleteItemConfirmEvent extends NitroEvent
|
||||||
|
{
|
||||||
|
public static DELETE_ITEM_CONFIRM: string = 'DICE_DELETE_ITEM_CONFIRM';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly item: FurnitureItem,
|
||||||
|
public readonly amount: number)
|
||||||
|
{
|
||||||
|
super(DeleteItemConfirmEvent.DELETE_ITEM_CONFIRM);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
|
export * from './DeleteItemConfirmEvent';
|
||||||
export * from './InventoryFurniAddedEvent';
|
export * from './InventoryFurniAddedEvent';
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import './css/hotelview/HotelView.css';
|
|||||||
|
|
||||||
import './css/icons/icons.css';
|
import './css/icons/icons.css';
|
||||||
|
|
||||||
|
import './css/inventory/Inventory.css';
|
||||||
|
|
||||||
import './css/layout/LayoutTrophy.css';
|
import './css/layout/LayoutTrophy.css';
|
||||||
|
|
||||||
import './css/loading/loading.css';
|
import './css/loading/loading.css';
|
||||||
|
|||||||
Reference in New Issue
Block a user