diff --git a/src/views/catalog/common/AttemptCatalogPlacement.ts b/src/views/catalog/common/AttemptCatalogPlacement.ts
new file mode 100644
index 00000000..af342ee3
--- /dev/null
+++ b/src/views/catalog/common/AttemptCatalogPlacement.ts
@@ -0,0 +1,30 @@
+import { CatalogPageMessageOfferData, RoomObjectCategory, RoomObjectPlacementSource } from '@nitrots/nitro-renderer';
+import { GetRoomEngine } from '../../../api';
+import { IsCatalogOfferDraggable } from './IsCatalogOfferDraggable';
+import { ProductTypeEnum } from './ProductTypeEnum';
+
+export const AttemptCatalogPlacement = (offer: CatalogPageMessageOfferData) =>
+{
+ if(!IsCatalogOfferDraggable(offer)) return;
+
+ const product = offer.products[0];
+
+ let category: number = -1;
+
+ switch(product.productType)
+ {
+ case ProductTypeEnum.FLOOR:
+ category = RoomObjectCategory.FLOOR;
+ break;
+ case ProductTypeEnum.WALL:
+ category = RoomObjectCategory.WALL;
+ break;
+ }
+
+ if(category === -1) return;
+
+ if(GetRoomEngine().processRoomObjectPlacement(RoomObjectPlacementSource.CATALOG, -(offer.offerId), category, product.furniClassId, (product.extraParam) ? product.extraParam.toString() : null))
+ {
+
+ }
+}
diff --git a/src/views/catalog/common/GetProuductIconUrl.ts b/src/views/catalog/common/GetProuductIconUrl.ts
new file mode 100644
index 00000000..c775dd37
--- /dev/null
+++ b/src/views/catalog/common/GetProuductIconUrl.ts
@@ -0,0 +1,47 @@
+import { FurnitureType } from '@nitrots/nitro-renderer';
+import { GetConfiguration, GetRoomEngine, GetSessionDataManager } from '../../../api';
+
+export const GetProductIconUrl = (furniClassId: number, productType: string, customParams: string = null) =>
+{
+ switch(productType.toUpperCase())
+ {
+ case FurnitureType.BADGE:
+ return GetSessionDataManager().getBadgeUrl(customParams);
+ case FurnitureType.ROBOT:
+ return undefined;
+ case FurnitureType.FLOOR:
+ return GetRoomEngine().getFurnitureFloorIconUrl(furniClassId);
+ case FurnitureType.WALL: {
+ const furniData = GetSessionDataManager().getWallItemData(furniClassId);
+
+ let iconName = '';
+
+ if(furniData)
+ {
+ switch(furniData.className)
+ {
+ case 'floor':
+ iconName = [ 'th', furniData.className, customParams ].join('_');
+ break;
+ case 'wallpaper':
+ iconName = [ 'th', 'wall', customParams ].join('_');
+ break;
+ case 'landscape':
+ iconName = [ 'th', furniData.className, customParams.replace('.', '_'), '001' ].join('_');
+ break;
+ }
+
+ if(iconName !== '')
+ {
+ const assetUrl = GetConfiguration
('catalog.asset.url');
+
+ return `${ assetUrl }/${ iconName }.png`;
+ }
+ }
+
+ return GetRoomEngine().getFurnitureWallIconUrl(furniClassId, customParams);
+ }
+ }
+
+ return null;
+}
diff --git a/src/views/catalog/common/IsCatalogOfferDraggable.ts b/src/views/catalog/common/IsCatalogOfferDraggable.ts
new file mode 100644
index 00000000..174ce4d0
--- /dev/null
+++ b/src/views/catalog/common/IsCatalogOfferDraggable.ts
@@ -0,0 +1,8 @@
+import { CatalogPageMessageOfferData, RoomControllerLevel } from '@nitrots/nitro-renderer';
+import { GetRoomSession } from '../../../api';
+import { ProductTypeEnum } from './ProductTypeEnum';
+
+export const IsCatalogOfferDraggable = (offer: CatalogPageMessageOfferData) =>
+{
+ return ((GetRoomSession().isRoomOwner || (GetRoomSession().isGuildRoom && (GetRoomSession().controllerLevel >= RoomControllerLevel.GUILD_MEMBER))) && (offer.products.length === 1) && (offer.products[0].productType !== ProductTypeEnum.EFFECT) && (offer.products[0].productType !== ProductTypeEnum.HABBO_CLUB))
+}
diff --git a/src/views/catalog/views/CatalogViews.scss b/src/views/catalog/views/CatalogViews.scss
index 0a5f6295..f6973ade 100644
--- a/src/views/catalog/views/CatalogViews.scss
+++ b/src/views/catalog/views/CatalogViews.scss
@@ -1,5 +1,4 @@
@import './catalog-icon/CatalogIconView';
+@import './gift/CatalogGiftView';
@import './navigation/CatalogNavigationView';
@import './page/CatalogPageView';
-@import './search/CatalogSearchView';
-@import './gift/CatalogGiftView';
diff --git a/src/views/catalog/views/gift/CatalogGiftView.scss b/src/views/catalog/views/gift/CatalogGiftView.scss
index 9f43a086..db61d248 100644
--- a/src/views/catalog/views/gift/CatalogGiftView.scss
+++ b/src/views/catalog/views/gift/CatalogGiftView.scss
@@ -1,4 +1,5 @@
.nitro-catalog-gift {
+ width: 325px;
.gift-preview {
width: 80px;
diff --git a/src/views/catalog/views/navigation/CatalogNavigationView.scss b/src/views/catalog/views/navigation/CatalogNavigationView.scss
index e094aaac..cd6cc820 100644
--- a/src/views/catalog/views/navigation/CatalogNavigationView.scss
+++ b/src/views/catalog/views/navigation/CatalogNavigationView.scss
@@ -1,11 +1,21 @@
-.nitro-catalog-navigation {
- border-color: $grid-border-color !important;
- background-color: $grid-bg-color !important;
+.nitro-catalog-navigation-grid {
+ border-radius: 0.25rem;
+ border-color: #B6BEC5 !important;
+ background-color: #CDD3D9;
+ border: 2px solid;
- .navigation-container {
- overflow-y: auto;
+ .grid-item {
+ font-size: $font-size-sm;
+ height: 23px !important;
+ border-color: unset !important;
+ background-color: #CDD3D9;
+ border: 0 !important;
+ padding: 1px 3px;
+
+ i.fas {
+ color: $black;
+ font-size: 10px;
+ padding: 1px;
+ }
}
}
-
-@import './item/CatalogNavigationItemView';
-@import './set/CatalogNavigationSetView';
diff --git a/src/views/catalog/views/navigation/CatalogNavigationView.tsx b/src/views/catalog/views/navigation/CatalogNavigationView.tsx
index ac636961..cb8efe9c 100644
--- a/src/views/catalog/views/navigation/CatalogNavigationView.tsx
+++ b/src/views/catalog/views/navigation/CatalogNavigationView.tsx
@@ -1,5 +1,6 @@
import { INodeData } from '@nitrots/nitro-renderer';
import { FC, useEffect } from 'react';
+import { NitroCardGridView } from '../../../../layout';
import { CatalogSearchView } from '../search/CatalogSearchView';
import { CatalogNavigationViewProps } from './CatalogNavigationView.types';
import { CatalogNavigationSetView } from './set/CatalogNavigationSetView';
@@ -23,13 +24,15 @@ export const CatalogNavigationView: FC = props =>
}, [ page ]);
return (
- <>
-
-
-
-
+
);
}
diff --git a/src/views/catalog/views/navigation/item/CatalogNavigationItemView.scss b/src/views/catalog/views/navigation/item/CatalogNavigationItemView.scss
deleted file mode 100644
index b5adfc1c..00000000
--- a/src/views/catalog/views/navigation/item/CatalogNavigationItemView.scss
+++ /dev/null
@@ -1,18 +0,0 @@
-.catalog-navigation-item-container {
-
- .catalog-navigation-item {
- font-size: $font-size-sm;
- border-radius: $border-radius;
-
- i.fas {
- color: $black;
- font-size: 10px;
- padding: 1px;
- }
-
- &.active {
- padding: 1px 2px;
- background-color: $grid-active-bg-color;
- }
- }
-}
diff --git a/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx b/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx
index 42344628..f618c0e1 100644
--- a/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx
+++ b/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx
@@ -1,6 +1,7 @@
import { GetCatalogPageComposer, INodeData } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { SendMessageHook } from '../../../../../hooks/messages/message-event';
+import { NitroCardGridItemView } from '../../../../../layout';
import { CatalogMode } from '../../../CatalogView.types';
import { CatalogIconView } from '../../catalog-icon/CatalogIconView';
import { ACTIVE_PAGES } from '../CatalogNavigationView';
@@ -70,16 +71,14 @@ export const CatalogNavigationItemView: FC
= pro
}, [ isActive, page ]);
return (
-
-
select(page) }>
+ <>
+
select(page) }>
- { page.localization }
+ { page.localization }
{ (page.children.length > 0) && }
-
+
{ isActive && isExpanded && page.children && (page.children.length > 0) &&
-
-
-
}
-
+ }
+ >
);
}
diff --git a/src/views/catalog/views/navigation/set/CatalogNavigationSetView.scss b/src/views/catalog/views/navigation/set/CatalogNavigationSetView.scss
deleted file mode 100644
index 56d8034c..00000000
--- a/src/views/catalog/views/navigation/set/CatalogNavigationSetView.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-.catalog-navigation-set-container {
-
- .catalog-navigation-set-container {
- padding-left: 5px;
-
- .catalog-navigation-item-container {
- padding-right: 0px !important;
- }
- }
-
- > :last-child {
- padding-bottom: 0px !important;
- }
-}
diff --git a/src/views/catalog/views/navigation/set/CatalogNavigationSetView.tsx b/src/views/catalog/views/navigation/set/CatalogNavigationSetView.tsx
index 966fbfd4..3d6199a1 100644
--- a/src/views/catalog/views/navigation/set/CatalogNavigationSetView.tsx
+++ b/src/views/catalog/views/navigation/set/CatalogNavigationSetView.tsx
@@ -26,13 +26,13 @@ export const CatalogNavigationSetView: FC = props
}, [ page, isFirstSet, activeChild, pendingTree ]);
return (
-
+ <>
{ page && (page.children.length > 0) && page.children.map((page, index) =>
{
if(!page.visible) return null;
return
}) }
-
+ >
);
}
diff --git a/src/views/catalog/views/page-details/CatalogPageDetailsView.tsx b/src/views/catalog/views/page-details/CatalogPageDetailsView.tsx
new file mode 100644
index 00000000..390aed62
--- /dev/null
+++ b/src/views/catalog/views/page-details/CatalogPageDetailsView.tsx
@@ -0,0 +1,19 @@
+import { FC } from 'react';
+import { GetCatalogPageImage, GetCatalogPageText } from '../../common/CatalogUtilities';
+import { CatalogPageDetailsViewProps } from './CatalogPageDetailsView.types';
+
+export const CatalogPageDetailsView: FC = props =>
+{
+ const { pageParser = null } = props;
+
+ if(!pageParser) return null;
+
+ const imageUrl = GetCatalogPageImage(pageParser, 1);
+
+ return (
+
+ { imageUrl &&
}
+
+
+ );
+}
diff --git a/src/views/catalog/views/page-details/CatalogPageDetailsView.types.ts b/src/views/catalog/views/page-details/CatalogPageDetailsView.types.ts
new file mode 100644
index 00000000..a02c3b6c
--- /dev/null
+++ b/src/views/catalog/views/page-details/CatalogPageDetailsView.types.ts
@@ -0,0 +1,6 @@
+import { CatalogPageMessageParser } from '@nitrots/nitro-renderer';
+
+export interface CatalogPageDetailsViewProps
+{
+ pageParser: CatalogPageMessageParser;
+}
diff --git a/src/views/catalog/views/page/CatalogPageView.scss b/src/views/catalog/views/page/CatalogPageView.scss
index 7a00d29e..7a24edf7 100644
--- a/src/views/catalog/views/page/CatalogPageView.scss
+++ b/src/views/catalog/views/page/CatalogPageView.scss
@@ -1,6 +1,2 @@
@import './layout/CatalogLayout';
-@import './offer/CatalogPageOfferView';
-@import './offers/CatalogPageOffersView';
-@import './product/CatalogProductView';
@import './purchase/CatalogPurchaseView';
-@import './search-result/CatalogLayoutSearchResultView';
diff --git a/src/views/catalog/views/page/layout/CatalogLayout.scss b/src/views/catalog/views/page/layout/CatalogLayout.scss
index ff111f8a..d71c9f8a 100644
--- a/src/views/catalog/views/page/layout/CatalogLayout.scss
+++ b/src/views/catalog/views/page/layout/CatalogLayout.scss
@@ -1,10 +1,3 @@
-@import './badge-display/CatalogLayoutBadgeDisplayView';
-@import './default/CatalogLayoutDefaultView';
@import './frontpage4/CatalogLayoutFrontpage4View';
-@import './pets/CatalogLayoutPetView';
-@import './pets3/CatalogLayoutPets3View';
-@import './single-bundle/CatalogLayoutSingleBundleView';
-@import './spaces-new/CatalogLayoutSpacesView';
-@import './trophies/CatalogLayoutTrophiesView';
-@import './vip-buy/CatalogLayoutVipBuyView';
@import './info-loyalty/CatalogLayoutInfoLoyaltyView.scss';
+@import './vip-buy/CatalogLayoutVipBuyView';
diff --git a/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.scss b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.scss
deleted file mode 100644
index 1229e018..00000000
--- a/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-.nitro-catalog-layout-badge-display {
-
- .inventory-badge-grid {
- height: 200px;
- max-height: 200px;
- }
-}
diff --git a/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx
index 4cb90755..1826c10a 100644
--- a/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx
+++ b/src/views/catalog/views/page/layout/badge-display/CatalogLayoutBadgeDisplayView.tsx
@@ -1,5 +1,5 @@
import { StringDataType } from '@nitrots/nitro-renderer';
-import { FC, useCallback, useEffect, useMemo, useState } from 'react';
+import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../../api';
import { InventoryBadgesUpdatedEvent, SetRoomPreviewerStuffDataEvent } from '../../../../../../events';
import { InventoryBadgesRequestEvent } from '../../../../../../events/inventory/InventoryBadgesRequestEvent';
@@ -7,11 +7,9 @@ import { dispatchUiEvent, useUiEvent } from '../../../../../../hooks';
import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView';
import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView';
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView';
-import { GetOfferName } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext';
-import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
-import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView';
+import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
import { CatalogLayoutBadgeDisplayViewProps } from './CatalogLayoutBadgeDisplayView.types';
export const CatalogLayoutBadgeDisplayView: FC = props =>
@@ -32,18 +30,6 @@ export const CatalogLayoutBadgeDisplayView: FC
- {
- return badges.map(code =>
- {
- return (
- setCurrentBadge(code) }>
-
-
- );
- });
- }, [ badges, currentBadge ]);
-
useEffect(() =>
{
dispatchUiEvent(new InventoryBadgesRequestEvent(InventoryBadgesRequestEvent.REQUEST_BADGES));
@@ -67,22 +53,26 @@ export const CatalogLayoutBadgeDisplayView: FC
-
-
-
+
+
+
+
{ LocalizeText('catalog_selectbadge') }
-
- { badgeElements }
+
+ { badges && (badges.length > 0) && badges.map(code =>
+ {
+ return (
+ setCurrentBadge(code) }>
+
+
+ );
+ }) }
- { product &&
-
-
-
{ GetOfferName(activeOffer) }
-
-
}
+
+
+
);
}
diff --git a/src/views/catalog/views/page/layout/default/CatalogLayoutDefaultView.scss b/src/views/catalog/views/page/layout/default/CatalogLayoutDefaultView.scss
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/views/catalog/views/page/layout/default/CatalogLayoutDefaultView.tsx b/src/views/catalog/views/page/layout/default/CatalogLayoutDefaultView.tsx
index db599364..86d2bd1b 100644
--- a/src/views/catalog/views/page/layout/default/CatalogLayoutDefaultView.tsx
+++ b/src/views/catalog/views/page/layout/default/CatalogLayoutDefaultView.tsx
@@ -1,10 +1,7 @@
import { FC } from 'react';
-import { LimitedEditionCompletePlateView } from '../../../../../shared/limited-edition/complete-plate/LimitedEditionCompletePlateView';
-import { GetCatalogPageImage, GetCatalogPageText, GetOfferName } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext';
-import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
-import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView';
+import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
import { CatalogLayoutDefaultViewProps } from './CatalogLayoutDefaultView.types';
export const CatalogLayoutDefaultView: FC
= props =>
@@ -17,24 +14,12 @@ export const CatalogLayoutDefaultView: FC = props
return (
-
+
- { !product &&
-
-
-
-
-
{ GetCatalogPageText(pageParser, 0) }
-
}
- { product &&
-
-
- { product.uniqueLimitedItem &&
-
}
-
{ GetOfferName(activeOffer) }
-
-
}
+
+
+
);
}
diff --git a/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.scss b/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.scss
deleted file mode 100644
index 268769fb..00000000
--- a/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.scss
+++ /dev/null
@@ -1,10 +0,0 @@
-.nitro-catalog-layout-pets {
-
- .color-button {
- position: absolute;
- left: 5px;
- bottom: 5px;
- }
-
- @import './name-approval/CatalogPetNameApprovalView';
-}
diff --git a/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx b/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx
index f70afb5d..edf293c2 100644
--- a/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx
+++ b/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx
@@ -2,11 +2,13 @@ import { ColorConverter, GetSellablePetPalettesComposer, SellablePetPaletteData
import { FC, useEffect, useMemo, useState } from 'react';
import { GetProductDataForLocalization, LocalizeText } from '../../../../../../api';
import { SendMessageHook } from '../../../../../../hooks/messages/message-event';
+import { NitroCardGridItemView, NitroCardGridView } from '../../../../../../layout';
import { PetImageView } from '../../../../../shared/pet-image/PetImageView';
-import { GetCatalogPageImage, GetCatalogPageText, GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../common/CatalogUtilities';
+import { GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogActions } from '../../../../reducers/CatalogReducer';
import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
+import { CatalogPageDetailsView } from '../../../page-details/CatalogPageDetailsView';
import { CatalogLayoutPetViewProps } from './CatalogLayoutPetView.types';
import { CatalogLayoutPetPurchaseView } from './purchase/CatalogLayoutPetPurchaseView';
@@ -139,44 +141,40 @@ export const CatalogLayoutPetView: FC
= props =>
if(!activeOffer) return null;
return (
-
-
-
- { colorsShowing && (sellableColors.length > 0) && sellableColors.map((colorSet, index) =>
- {
- return
-
setSelectedColorIndex(index) }>
-
-
;
- })}
+
+
+
{ !colorsShowing && (sellablePalettes.length > 0) && sellablePalettes.map((palette, index) =>
{
- return
-
setSelectedPaletteIndex(index) }>
+ return (
+
setSelectedPaletteIndex(index) }>
-
-
;
- }) }
-
+
+ );
+ })}
+ { colorsShowing && (sellableColors.length > 0) && sellableColors.map((colorSet, index) =>
+ {
+ return (
+
setSelectedColorIndex(index) } />
+ );
+ })}
+
+
+
+ { (petIndex === -1) &&
+
}
+ { (petIndex >= 0) &&
+ <>
+
+ { (petIndex > -1 && petIndex <= 7) &&
+ }
+
+
{ petBreedName }
+
+ > }
- { (petIndex === -1) &&
-
-
-
-
-
{ GetCatalogPageText(pageParser, 0) }
-
}
- { (petIndex >= 0) &&
-
-
- { (petIndex > -1 && petIndex <= 7) &&
- }
-
-
{ petBreedName }
-
-
}
);
}
diff --git a/src/views/catalog/views/page/layout/pets/name-approval/CatalogPetNameApprovalView.scss b/src/views/catalog/views/page/layout/pets/name-approval/CatalogPetNameApprovalView.scss
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/views/catalog/views/page/layout/pets/purchase/CatalogLayoutPetPurchaseView.tsx b/src/views/catalog/views/page/layout/pets/purchase/CatalogLayoutPetPurchaseView.tsx
index 9f1ebb31..c7b02518 100644
--- a/src/views/catalog/views/page/layout/pets/purchase/CatalogLayoutPetPurchaseView.tsx
+++ b/src/views/catalog/views/page/layout/pets/purchase/CatalogLayoutPetPurchaseView.tsx
@@ -6,6 +6,7 @@ import { useUiEvent } from '../../../../../../../hooks/events/ui/ui-event';
import { SendMessageHook } from '../../../../../../../hooks/messages/message-event';
import { CurrencyIcon } from '../../../../../../shared/currency-icon/CurrencyIcon';
import { CatalogPurchaseButtonView } from '../../../purchase/purchase-button/CatalogPurchaseButtonView';
+import { CatalogPurchaseGiftButtonView } from '../../../purchase/purchase-gift-button/CatalogPurchaseGiftButtonView';
import { CatalogPetNameApprovalView } from '../name-approval/CatalogPetNameApprovalView';
import { CatalogLayoutPetPurchaseViewProps } from './CatalogLayoutPetPurchaseView.types';
@@ -59,6 +60,8 @@ export const CatalogLayoutPetPurchaseView: FC
+ { offer.giftable &&
+ }
>
diff --git a/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.scss b/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.scss
deleted file mode 100644
index 1b85077d..00000000
--- a/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.scss
+++ /dev/null
@@ -1,2 +0,0 @@
-.nitro-catalog-layout-pets2 {
-}
diff --git a/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.tsx b/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.tsx
index 3e901711..06dd970c 100644
--- a/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.tsx
+++ b/src/views/catalog/views/page/layout/pets2/CatalogLayoutPets2View.tsx
@@ -1,23 +1,8 @@
import { FC } from 'react';
-import { GetCatalogPageImage, GetCatalogPageText } from '../../../../common/CatalogUtilities';
+import { CatalogLayoutPets3View } from '../pets3/CatalogLayoutPets3View';
import { CatalogLayoutPets2ViewProps } from './CatalogLayoutPets2View.types';
export const CatalogLayoutPets2View: FC = props =>
{
- const { pageParser = null } = props;
-
- return (
-
-
-
-
-
-
-
{ GetCatalogPageText(pageParser, 1) }
-
-
- {GetCatalogPageText(pageParser, 3) &&
}
-
-
- );
+ return
}
diff --git a/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.scss b/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.scss
deleted file mode 100644
index 2f2bc31c..00000000
--- a/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.scss
+++ /dev/null
@@ -1,2 +0,0 @@
-.nitro-catalog-layout-pets3 {
-}
diff --git a/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.tsx b/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.tsx
index 23fa4048..94ab0a81 100644
--- a/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.tsx
+++ b/src/views/catalog/views/page/layout/pets3/CatalogLayoutPets3View.tsx
@@ -5,18 +5,24 @@ import { CatalogLayoutPets3ViewProps } from './CatalogLayoutPets3View.types';
export const CatalogLayoutPets3View: FC = props =>
{
const { pageParser = null } = props;
+
+ const imageUrl = GetCatalogPageImage(pageParser, 1);
return (
-
-
-
-
-
+
+
+
+
+ { imageUrl &&
}
+
+
+
+
-
{ GetCatalogPageText(pageParser, 1) }
-
- {GetCatalogPageText(pageParser, 3) &&
}
);
diff --git a/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.scss b/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.scss
deleted file mode 100644
index 664041a9..00000000
--- a/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-.nitro-catalog-layout-single-bundle {
-
- .single-bundle-items-container {
-
- }
-}
diff --git a/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.tsx b/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.tsx
index c85baeae..bab6711f 100644
--- a/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.tsx
+++ b/src/views/catalog/views/page/layout/single-bundle/CatalogLayoutSingleBundleView.tsx
@@ -1,6 +1,7 @@
import { FC } from 'react';
-import { GetCatalogPageImage, GetCatalogPageText } from '../../../../common/CatalogUtilities';
+import { NitroCardGridView } from '../../../../../../layout';
import { useCatalogContext } from '../../../../context/CatalogContext';
+import { CatalogPageDetailsView } from '../../../page-details/CatalogPageDetailsView';
import { CatalogProductView } from '../../product/CatalogProductView';
import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView';
import { CatalogLayoutSingleBundleViewProps } from './CatalogLayoutSingleBundleView.types';
@@ -12,20 +13,17 @@ export const CatalogLayoutSingleBundleView: FC
-
-
+
+
+
{ activeOffer && activeOffer.products && (activeOffer.products.length > 0) && activeOffer.products.map((product, index) =>
{
return
}) }
-
+
-
-
-
-
-
{ GetCatalogPageText(pageParser, 0) }
+
+
{ activeOffer && }
diff --git a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.scss b/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.scss
deleted file mode 100644
index ce1e1c03..00000000
--- a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.nitro-catalog-layout-spaces {
-
-}
diff --git a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx b/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx
index c2c15a26..65da4622 100644
--- a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx
+++ b/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx
@@ -1,12 +1,10 @@
import { CatalogPageMessageOfferData, IFurnitureData } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { GetSessionDataManager, LocalizeText } from '../../../../../../api';
-import { GetCatalogPageImage, GetCatalogPageText, GetOfferName } from '../../../../common/CatalogUtilities';
import { ProductTypeEnum } from '../../../../common/ProductTypeEnum';
import { useCatalogContext } from '../../../../context/CatalogContext';
-import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
-import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView';
+import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
import { CatalogLayoutSpacesViewProps } from './CatalogLayoutSpacesView.types';
export const CatalogLayoutSpacesView: FC
= props =>
@@ -68,9 +66,9 @@ export const CatalogLayoutSpacesView: FC = props =
const product = ((activeOffer && activeOffer.products[0]) || null);
return (
-
-
-
+
+
+
{ groupNames.map((name, index) =>
{
return
@@ -78,19 +76,9 @@ export const CatalogLayoutSpacesView: FC = props =
- { !product &&
-
-
-
-
-
{ GetCatalogPageText(pageParser, 0) }
-
}
- { product &&
-
-
-
{ GetOfferName(activeOffer) }
-
-
}
+
+
+
);
}
diff --git a/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.scss b/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.scss
deleted file mode 100644
index 58637ed9..00000000
--- a/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-.nitro-catalog-layout-trophies {
-
- textarea {
- height: 119px;
- resize: none;
- }
-
-}
diff --git a/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx b/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx
index 471001a1..03379cf0 100644
--- a/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx
+++ b/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx
@@ -1,9 +1,7 @@
import { FC, useState } from 'react';
-import { GetOfferName } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext';
-import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
-import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView';
+import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
import { CatalogLayoutTrophiesViewProps } from './CatalogLayoutTrophiesView.types';
export const CatalogLayoutTrophiesView: FC
= props =>
@@ -16,19 +14,14 @@ export const CatalogLayoutTrophiesView: FC = pro
const product = ((activeOffer && activeOffer.products[0]) || null);
return (
-
-
+
+
+
+
- { product &&
-
-
-
{ GetOfferName(activeOffer) }
-
-
}
);
}
diff --git a/src/views/catalog/views/page/offer/CatalogPageOfferView.scss b/src/views/catalog/views/page/offer/CatalogPageOfferView.scss
deleted file mode 100644
index 7008f0e2..00000000
--- a/src/views/catalog/views/page/offer/CatalogPageOfferView.scss
+++ /dev/null
@@ -1,33 +0,0 @@
-.catalog-offer-item-container {
- height: 48px;
- max-height: 48px;
-
- .catalog-offer-item {
- width: 100%;
- height: 100%;
- border-color: $grid-border-color !important;
- background-color: $grid-bg-color;
- background-position: center;
- background-repeat: no-repeat;
- overflow: hidden;
-
- &.active {
- border-color: $grid-active-border-color !important;
- background-color: $grid-active-bg-color;
- }
-
- .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;
- }
- }
-}
diff --git a/src/views/catalog/views/page/offer/CatalogPageOfferView.tsx b/src/views/catalog/views/page/offer/CatalogPageOfferView.tsx
index 89f6b90f..fb2fae74 100644
--- a/src/views/catalog/views/page/offer/CatalogPageOfferView.tsx
+++ b/src/views/catalog/views/page/offer/CatalogPageOfferView.tsx
@@ -1,5 +1,5 @@
import { MouseEventType } from '@nitrots/nitro-renderer';
-import { FC, MouseEvent, useCallback } from 'react';
+import { FC, MouseEvent, useCallback, useState } from 'react';
import { useCatalogContext } from '../../../context/CatalogContext';
import { CatalogActions } from '../../../reducers/CatalogReducer';
import { CatalogProductView } from '../product/CatalogProductView';
@@ -8,6 +8,7 @@ import { CatalogPageOfferViewProps } from './CatalogPageOfferView.types';
export const CatalogPageOfferView: FC
= props =>
{
const { isActive = false, offer = null } = props;
+ const [ isMouseDown, setMouseDown ] = useState(false);
const { dispatchCatalogState = null } = useCatalogContext();
const onMouseEvent = useCallback((event: MouseEvent) =>
@@ -24,12 +25,21 @@ export const CatalogPageOfferView: FC = props =>
}
});
return;
+ case MouseEventType.MOUSE_DOWN:
+ setMouseDown(true);
+ return;
+ case MouseEventType.MOUSE_UP:
+ setMouseDown(false);
+ return;
+ case MouseEventType.ROLL_OUT:
+ if(!isMouseDown || !isActive) return;
+ return;
}
- }, [ isActive, offer, dispatchCatalogState ]);
+ }, [ isActive, offer, isMouseDown, dispatchCatalogState ]);
const product = ((offer.products && offer.products[0]) || null);
if(!product) return null;
- return
+ return
}
diff --git a/src/views/catalog/views/page/offers/CatalogPageOffersView.scss b/src/views/catalog/views/page/offers/CatalogPageOffersView.scss
deleted file mode 100644
index 28192aa4..00000000
--- a/src/views/catalog/views/page/offers/CatalogPageOffersView.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.catalog-offers-container {
- overflow-y: auto;
-}
diff --git a/src/views/catalog/views/page/offers/CatalogPageOffersView.tsx b/src/views/catalog/views/page/offers/CatalogPageOffersView.tsx
index 5fd81480..994bb7d7 100644
--- a/src/views/catalog/views/page/offers/CatalogPageOffersView.tsx
+++ b/src/views/catalog/views/page/offers/CatalogPageOffersView.tsx
@@ -1,32 +1,21 @@
-import { FC, useEffect } from 'react';
+import { FC } from 'react';
+import { NitroCardGridView } from '../../../../../layout';
import { useCatalogContext } from '../../../context/CatalogContext';
import { CatalogPageOfferView } from '../offer/CatalogPageOfferView';
import { CatalogPageOffersViewProps } from './CatalogPageOffersView.types';
export const CatalogPageOffersView: FC = props =>
{
- const { offers = [] } = props;
+ const { offers = [], ...rest } = props;
const { catalogState = null, dispatchCatalogState = null } = useCatalogContext();
const { activeOffer = null } = catalogState;
- useEffect(() =>
- {
- if(!offers || !offers.length) return;
-
- // dispatchCatalogState({
- // type: CatalogActions.SET_CATALOG_ACTIVE_OFFER,
- // payload: {
- // activeOffer: offers[0]
- // }
- // });
- }, [ offers, dispatchCatalogState ]);
-
return (
-
+
{ offers && (offers.length > 0) && offers.map((offer, index) =>
{
return
- })}
-
+ })}
+
);
}
diff --git a/src/views/catalog/views/page/offers/CatalogPageOffersView.types.ts b/src/views/catalog/views/page/offers/CatalogPageOffersView.types.ts
index 9f7945d0..451510cc 100644
--- a/src/views/catalog/views/page/offers/CatalogPageOffersView.types.ts
+++ b/src/views/catalog/views/page/offers/CatalogPageOffersView.types.ts
@@ -1,6 +1,7 @@
import { CatalogPageMessageOfferData } from '@nitrots/nitro-renderer';
+import { DetailsHTMLAttributes } from 'react';
-export interface CatalogPageOffersViewProps
+export interface CatalogPageOffersViewProps extends DetailsHTMLAttributes
{
offers: CatalogPageMessageOfferData[];
}
diff --git a/src/views/catalog/views/page/product-preview/CatalogProductPreviewView.tsx b/src/views/catalog/views/page/product-preview/CatalogProductPreviewView.tsx
new file mode 100644
index 00000000..1e278f58
--- /dev/null
+++ b/src/views/catalog/views/page/product-preview/CatalogProductPreviewView.tsx
@@ -0,0 +1,31 @@
+import { FC } from 'react';
+import { LimitedEditionCompletePlateView } from '../../../../shared/limited-edition/complete-plate/LimitedEditionCompletePlateView';
+import { GetOfferName } from '../../../common/CatalogUtilities';
+import { CatalogRoomPreviewerView } from '../../catalog-room-previewer/CatalogRoomPreviewerView';
+import { CatalogPageDetailsView } from '../../page-details/CatalogPageDetailsView';
+import { CatalogPurchaseView } from '../purchase/CatalogPurchaseView';
+import { CatalogProductPreviewViewProps } from './CatalogProductPreviewView.types';
+
+export const CatalogProductPreviewView: FC = props =>
+{
+ const { pageParser = null, activeOffer = null, roomPreviewer = null, extra = '', disabled = false, children = null } = props;
+
+ const product = ((activeOffer && activeOffer.products[0]) || null);
+
+ if(!product) return ;
+
+ return (
+ <>
+
+
+ { product.uniqueLimitedItem &&
+ }
+
+
+
{ GetOfferName(activeOffer) }
+ { children }
+
+
+ >
+ );
+}
diff --git a/src/views/catalog/views/page/product-preview/CatalogProductPreviewView.types.ts b/src/views/catalog/views/page/product-preview/CatalogProductPreviewView.types.ts
new file mode 100644
index 00000000..249d05ff
--- /dev/null
+++ b/src/views/catalog/views/page/product-preview/CatalogProductPreviewView.types.ts
@@ -0,0 +1,10 @@
+import { CatalogPageMessageOfferData, CatalogPageMessageParser, RoomPreviewer } from '@nitrots/nitro-renderer';
+
+export interface CatalogProductPreviewViewProps
+{
+ pageParser: CatalogPageMessageParser;
+ activeOffer: CatalogPageMessageOfferData;
+ roomPreviewer: RoomPreviewer;
+ extra?: string;
+ disabled?: boolean;
+}
diff --git a/src/views/catalog/views/page/product/CatalogProductView.scss b/src/views/catalog/views/page/product/CatalogProductView.scss
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/views/catalog/views/page/product/CatalogProductView.tsx b/src/views/catalog/views/page/product/CatalogProductView.tsx
index 684488d0..406f6e21 100644
--- a/src/views/catalog/views/page/product/CatalogProductView.tsx
+++ b/src/views/catalog/views/page/product/CatalogProductView.tsx
@@ -1,79 +1,36 @@
-import { FurnitureType } from '@nitrots/nitro-renderer';
import { FC, useMemo } from 'react';
-import { GetConfiguration, GetRoomEngine, GetSessionDataManager } from '../../../../../api';
+import { NitroCardGridItemView } from '../../../../../layout';
import { AvatarImageView } from '../../../../shared/avatar-image/AvatarImageView';
-import { LimitedEditionStyledNumberView } from '../../../../shared/limited-edition/styled-number/LimitedEditionStyledNumberView';
+import { GetProductIconUrl } from '../../../common/GetProuductIconUrl';
import { ProductTypeEnum } from '../../../common/ProductTypeEnum';
import { CatalogProductViewProps } from './CatalogProductView.types';
export const CatalogProductView: FC = props =>
{
- const { isActive = false, product = null, onMouseEvent = null } = props;
+ const { isActive = false, product = null, ...rest } = props;
const iconUrl = useMemo(() =>
{
if(!product) return null;
+
+ return GetProductIconUrl(product.furniClassId, product.productType, product.extraParam);
+ }, [ product ]);
- const productType = product.productType.toUpperCase();
+ const getUniqueNumber = useMemo(() =>
+ {
+ if(!product.uniqueLimitedItem) return 0;
- switch(productType)
- {
- case FurnitureType.BADGE:
- return GetSessionDataManager().getBadgeUrl(product.extraParam);
- case FurnitureType.ROBOT:
- return null;
- case FurnitureType.FLOOR:
- return GetRoomEngine().getFurnitureFloorIconUrl(product.furniClassId);
- case FurnitureType.WALL: {
- const furniData = GetSessionDataManager().getWallItemData(product.furniClassId);
-
- let iconName = '';
+ if(!product.uniqueLimitedItemsLeft) return -1;
- if(furniData)
- {
- switch(furniData.className)
- {
- case 'floor':
- iconName = ['th', furniData.className, product.extraParam].join('_');
- break;
- case 'wallpaper':
- iconName = ['th', 'wall', product.extraParam].join('_');
- break;
- case 'landscape':
- iconName = ['th', furniData.className, product.extraParam.replace('.', '_'), '001'].join('_');
- break;
- }
-
- if(iconName !== '')
- {
- const assetUrl = GetConfiguration('catalog.asset.url');
-
- return `${ assetUrl }/${ iconName }.png`;
- }
- }
-
- return GetRoomEngine().getFurnitureWallIconUrl(product.furniClassId, product.extraParam);
- }
- }
-
- return null;
+ return product.uniqueLimitedSeriesSize;
}, [ product ]);
if(!product) return null;
- const imageUrl = (iconUrl && iconUrl.length) ? `url(${ iconUrl })` : null;
-
return (
-
-
- { !imageUrl && (product.productType === ProductTypeEnum.ROBOT) &&
-
}
- { (product.productCount > 1) &&
{ product.productCount } }
- { product.uniqueLimitedItem &&
-
-
-
}
-
-
+
+ { (product.productType === ProductTypeEnum.ROBOT) &&
+ }
+
);
}
diff --git a/src/views/catalog/views/page/product/CatalogProductView.types.ts b/src/views/catalog/views/page/product/CatalogProductView.types.ts
index e059ecf5..b2d94bde 100644
--- a/src/views/catalog/views/page/product/CatalogProductView.types.ts
+++ b/src/views/catalog/views/page/product/CatalogProductView.types.ts
@@ -1,9 +1,8 @@
import { CatalogPageMessageProductData } from '@nitrots/nitro-renderer';
-import { MouseEventHandler } from 'react';
+import { DetailsHTMLAttributes } from 'react';
-export interface CatalogProductViewProps
+export interface CatalogProductViewProps extends DetailsHTMLAttributes
{
isActive: boolean;
product: CatalogPageMessageProductData;
- onMouseEvent?: MouseEventHandler;
}
diff --git a/src/views/catalog/views/page/purchase/CatalogPurchaseView.scss b/src/views/catalog/views/page/purchase/CatalogPurchaseView.scss
index 4559e425..e4a2a26f 100644
--- a/src/views/catalog/views/page/purchase/CatalogPurchaseView.scss
+++ b/src/views/catalog/views/page/purchase/CatalogPurchaseView.scss
@@ -4,5 +4,3 @@
width: 29px;
padding: 3px 5px;
}
-
-@import './purchase-button/CatalogPurchaseButtonView';
diff --git a/src/views/catalog/views/page/purchase/purchase-button/CatalogPurchaseButtonView.scss b/src/views/catalog/views/page/purchase/purchase-button/CatalogPurchaseButtonView.scss
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.scss b/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.scss
deleted file mode 100644
index ce60508f..00000000
--- a/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.scss
+++ /dev/null
@@ -1,2 +0,0 @@
-@import './offer/CatalogSearchResultOfferView';
-@import './offers/CatalogSearchResultOffersView';
diff --git a/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.tsx b/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.tsx
index a234f840..00e30a25 100644
--- a/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.tsx
+++ b/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.tsx
@@ -17,7 +17,7 @@ export const CatalogLayoutSearchResultView: FC
-
+
{ product &&
diff --git a/src/views/catalog/views/page/search-result/offer/CatalogSearchResultOfferView.scss b/src/views/catalog/views/page/search-result/offer/CatalogSearchResultOfferView.scss
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/views/catalog/views/page/search-result/offer/CatalogSearchResultOfferView.tsx b/src/views/catalog/views/page/search-result/offer/CatalogSearchResultOfferView.tsx
index 28290cf9..b7ff3534 100644
--- a/src/views/catalog/views/page/search-result/offer/CatalogSearchResultOfferView.tsx
+++ b/src/views/catalog/views/page/search-result/offer/CatalogSearchResultOfferView.tsx
@@ -1,7 +1,10 @@
-import { FurnitureType, GetProductOfferComposer, MouseEventType } from '@nitrots/nitro-renderer';
-import { FC, MouseEvent, useCallback } from 'react';
-import { GetConfiguration, GetRoomEngine, GetSessionDataManager } from '../../../../../../api';
+import { GetProductOfferComposer, MouseEventType } from '@nitrots/nitro-renderer';
+import { FC, MouseEvent, useCallback, useMemo } from 'react';
import { SendMessageHook } from '../../../../../../hooks/messages/message-event';
+import { NitroCardGridItemView } from '../../../../../../layout';
+import { AvatarImageView } from '../../../../../shared/avatar-image/AvatarImageView';
+import { GetProductIconUrl } from '../../../../common/GetProuductIconUrl';
+import { ProductTypeEnum } from '../../../../common/ProductTypeEnum';
import { CatalogSearchResultOfferViewProps } from './CatalogSearchResultOfferView.types';
export const CatalogSearchResultOfferView: FC
= props =>
@@ -15,62 +18,22 @@ export const CatalogSearchResultOfferView: FC
case MouseEventType.MOUSE_DOWN:
SendMessageHook(new GetProductOfferComposer(offer.purchaseOfferId));
return;
- case MouseEventType.MOUSE_UP:
- return;
- case MouseEventType.ROLL_OUT:
- return;
}
}, [ offer ]);
- function getIconUrl(): string
+ const iconUrl = useMemo(() =>
{
- const productType = offer.type.toUpperCase();
+ if(!offer) return null;
+
+ return GetProductIconUrl(offer.id, offer.type, offer.customParams);
+ }, [ offer ]);
- switch(productType)
- {
- case FurnitureType.BADGE:
- return GetSessionDataManager().getBadgeUrl(offer.customParams);
- case FurnitureType.FLOOR:
- return GetRoomEngine().getFurnitureFloorIconUrl(offer.id);
- case FurnitureType.WALL:
- const furniData = GetSessionDataManager().getWallItemData(offer.id);
-
- let iconName = '';
-
- if(furniData)
- {
- switch(furniData.className)
- {
- case 'floor':
- iconName = ['th', furniData.className, offer.customParams ].join('_');
- break;
- case 'wallpaper':
- iconName = ['th', 'wall', offer.customParams ].join('_');
- break;
- case 'landscape':
- iconName = ['th', furniData.className, ((offer.customParams && offer.customParams.replace('.', '_')) || null), '001'].join('_');
- break;
- }
-
- if(iconName !== '')
- {
- const assetUrl = GetConfiguration('catalog.asset.url');
-
- return `${ assetUrl }/${ iconName }.png`;
- }
- }
-
- return GetRoomEngine().getFurnitureWallIconUrl(offer.id, offer.customParams);
- }
-
- return '';
- }
-
- const imageUrl = `url(${ getIconUrl() })`;
+ if(!offer) return null;
return (
-
+
+ { (offer.type === ProductTypeEnum.ROBOT) &&
+ }
+
);
}
diff --git a/src/views/catalog/views/page/search-result/offers/CatalogSearchResultOffersView.scss b/src/views/catalog/views/page/search-result/offers/CatalogSearchResultOffersView.scss
deleted file mode 100644
index 28192aa4..00000000
--- a/src/views/catalog/views/page/search-result/offers/CatalogSearchResultOffersView.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.catalog-offers-container {
- overflow-y: auto;
-}
diff --git a/src/views/catalog/views/page/search-result/offers/CatalogSearchResultOffersView.tsx b/src/views/catalog/views/page/search-result/offers/CatalogSearchResultOffersView.tsx
index ae260892..213aade1 100644
--- a/src/views/catalog/views/page/search-result/offers/CatalogSearchResultOffersView.tsx
+++ b/src/views/catalog/views/page/search-result/offers/CatalogSearchResultOffersView.tsx
@@ -1,14 +1,15 @@
import { GetProductOfferComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect } from 'react';
import { SendMessageHook } from '../../../../../../hooks/messages/message-event';
+import { NitroCardGridView } from '../../../../../../layout';
import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogSearchResultOfferView } from '../offer/CatalogSearchResultOfferView';
import { CatalogSearchResultOffersViewProps } from './CatalogSearchResultOffersView.types';
export const CatalogSearchResultOffersView: FC = props =>
{
- const { offers = [] } = props;
- const { catalogState } = useCatalogContext();
+ const { offers = [], ...rest } = props;
+ const { catalogState = null } = useCatalogContext();
const { activeOffer = null } = catalogState;
useEffect(() =>
@@ -19,13 +20,13 @@ export const CatalogSearchResultOffersView: FC
+
{ offers && (offers.length > 0) && offers.map((offer, index) =>
{
const isActive = (activeOffer && (activeOffer.products[0].furniClassId === offer.id));
return
- }) }
-
+ })}
+
);
}
diff --git a/src/views/catalog/views/search/CatalogSearchView.scss b/src/views/catalog/views/search/CatalogSearchView.scss
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/views/catalog/views/search/CatalogSearchView.tsx b/src/views/catalog/views/search/CatalogSearchView.tsx
index af6ffb41..ecb9b430 100644
--- a/src/views/catalog/views/search/CatalogSearchView.tsx
+++ b/src/views/catalog/views/search/CatalogSearchView.tsx
@@ -110,7 +110,7 @@ export const CatalogSearchView: FC = props =>
}, [ searchValue, processSearch ]);
return (
-
+
setSearchValue(event.target.value) } />
diff --git a/src/views/friends/FriendListMessageHandler.types.ts b/src/views/friends/FriendListMessageHandler.types.ts
deleted file mode 100644
index 2a810612..00000000
--- a/src/views/friends/FriendListMessageHandler.types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-
-export interface FriendListMessageHandlerProps
-{
-
-}
diff --git a/src/views/friends/FriendListMessageHandler.tsx b/src/views/friends/FriendsMessageHandler.tsx
similarity index 54%
rename from src/views/friends/FriendListMessageHandler.tsx
rename to src/views/friends/FriendsMessageHandler.tsx
index e84e72a5..ce84725e 100644
--- a/src/views/friends/FriendListMessageHandler.tsx
+++ b/src/views/friends/FriendsMessageHandler.tsx
@@ -2,20 +2,19 @@ import { FriendListFragmentEvent, FriendListUpdateEvent, FriendRequestsEvent, Ge
import { FC, useCallback } from 'react';
import { CreateMessageHook, SendMessageHook } from '../../hooks/messages/message-event';
import { MessengerSettings } from './common/MessengerSettings';
-import { useFriendListContext } from './context/FriendListContext';
-import { FriendListMessageHandlerProps } from './FriendListMessageHandler.types';
-import { FriendListActions } from './reducers/FriendListReducer';
+import { useFriendsContext } from './context/FriendsContext';
+import { FriendsActions } from './reducers/FriendsReducer';
-export const FriendListMessageHandler: FC
= props =>
+export const FriendsMessageHandler: FC<{}> = props =>
{
- const { friendListState = null, dispatchFriendListState = null } = useFriendListContext();
+ const { friendsState = null, dispatchFriendsState = null } = useFriendsContext();
const onMessengerInitEvent = useCallback((event: MessengerInitEvent) =>
{
const parser = event.getParser();
- dispatchFriendListState({
- type: FriendListActions.UPDATE_SETTINGS,
+ dispatchFriendsState({
+ type: FriendsActions.UPDATE_SETTINGS,
payload: {
settings: new MessengerSettings(
parser.userFriendLimit,
@@ -26,47 +25,47 @@ export const FriendListMessageHandler: FC = props
});
SendMessageHook(new GetFriendRequestsComposer());
- }, [ dispatchFriendListState ]);
+ }, [ dispatchFriendsState ]);
- const onFriendListFragmentEvent = useCallback((event: FriendListFragmentEvent) =>
+ const onFriendsFragmentEvent = useCallback((event: FriendListFragmentEvent) =>
{
const parser = event.getParser();
- dispatchFriendListState({
- type: FriendListActions.PROCESS_FRAGMENT,
+ dispatchFriendsState({
+ type: FriendsActions.PROCESS_FRAGMENT,
payload: {
fragment: parser.fragment
}
});
- }, [ dispatchFriendListState ]);
+ }, [ dispatchFriendsState ]);
- const onFriendListUpdateEvent = useCallback((event: FriendListUpdateEvent) =>
+ const onFriendsUpdateEvent = useCallback((event: FriendListUpdateEvent) =>
{
const parser = event.getParser();
- dispatchFriendListState({
- type: FriendListActions.PROCESS_UPDATE,
+ dispatchFriendsState({
+ type: FriendsActions.PROCESS_UPDATE,
payload: {
update: parser
}
});
- }, [ dispatchFriendListState ]);
+ }, [ dispatchFriendsState ]);
const onFriendRequestsEvent = useCallback((event: FriendRequestsEvent) =>
{
const parser = event.getParser();
- dispatchFriendListState({
- type: FriendListActions.PROCESS_REQUESTS,
+ dispatchFriendsState({
+ type: FriendsActions.PROCESS_REQUESTS,
payload: {
requests: parser.requests
}
});
- }, [ dispatchFriendListState ]);
+ }, [ dispatchFriendsState ]);
CreateMessageHook(MessengerInitEvent, onMessengerInitEvent);
- CreateMessageHook(FriendListFragmentEvent, onFriendListFragmentEvent);
- CreateMessageHook(FriendListUpdateEvent, onFriendListUpdateEvent);
+ CreateMessageHook(FriendListFragmentEvent, onFriendsFragmentEvent);
+ CreateMessageHook(FriendListUpdateEvent, onFriendsUpdateEvent);
CreateMessageHook(FriendRequestsEvent, onFriendRequestsEvent);
return null;
diff --git a/src/views/friends/FriendsView.scss b/src/views/friends/FriendsView.scss
index 1d882087..3d55929f 100644
--- a/src/views/friends/FriendsView.scss
+++ b/src/views/friends/FriendsView.scss
@@ -1,5 +1,6 @@
-.nitro-friend-list {
+.nitro-friends {
width: 250px;
}
@import './views/friend-bar/FriendBarView';
+@import './views/messenger/FriendsMessengerView';
diff --git a/src/views/friends/FriendsView.tsx b/src/views/friends/FriendsView.tsx
index 6e2d74eb..0c9415f7 100644
--- a/src/views/friends/FriendsView.tsx
+++ b/src/views/friends/FriendsView.tsx
@@ -1,54 +1,62 @@
import { MessengerInitComposer, RoomEngineObjectEvent, RoomObjectCategory, RoomObjectUserType } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useReducer, useState } from 'react';
import { createPortal } from 'react-dom';
-import { GetRoomSession, LocalizeText } from '../../api';
-import { FriendEnteredRoomEvent, FriendListEvent } from '../../events';
-import { FriendListContentEvent } from '../../events/friend-list/FriendListContentEvent';
-import { FriendListSendFriendRequestEvent } from '../../events/friend-list/FriendListSendFriendRequestEvent';
+import { GetRoomSession } from '../../api';
+import { FriendEnteredRoomEvent, FriendListContentEvent, FriendsEvent } from '../../events';
+import { FriendsSendFriendRequestEvent } from '../../events/friends/FriendsSendFriendRequestEvent';
import { useRoomEngineEvent } from '../../hooks/events';
import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event';
import { SendMessageHook } from '../../hooks/messages/message-event';
-import { NitroCardAccordionItemView, NitroCardAccordionView, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout';
-import { FriendListContextProvider } from './context/FriendListContext';
-import { FriendListMessageHandler } from './FriendListMessageHandler';
-import { FriendListReducer, initialFriendList } from './reducers/FriendListReducer';
+import { FriendsContextProvider } from './context/FriendsContext';
+import { FriendsMessageHandler } from './FriendsMessageHandler';
+import { FriendsReducer, initialFriends } from './reducers/FriendsReducer';
import { FriendBarView } from './views/friend-bar/FriendBarView';
-import { FriendsListView } from './views/list/FriendsListView';
-
-const TABS: string[] = ['friendlist.friends', 'generic.search'];
+import { FriendsListView } from './views/friends-list/FriendsListView';
+import { FriendsMessengerView } from './views/messenger/FriendsMessengerView';
export const FriendsView: FC<{}> = props =>
{
- const [ friendListState, dispatchFriendListState ] = useReducer(FriendListReducer, initialFriendList);
- const { friends = null, requests = null, settings = null } = friendListState;
+ const [ friendsState, dispatchFriendsState ] = useReducer(FriendsReducer, initialFriends);
+ const { friends = [], requests = [], settings = null } = friendsState;
- const [ isVisible, setIsVisible ] = useState(false);
const [ isReady, setIsReady ] = useState(false);
- const [ currentTab, setCurrentTab ] = useState(0);
+ const [ isListVisible, setIsListVisible ] = useState(false);
- const onFriendListEvent = useCallback((event: FriendListEvent) =>
+ useEffect(() =>
+ {
+ SendMessageHook(new MessengerInitComposer());
+ }, []);
+
+ useEffect(() =>
+ {
+ if(!settings) return;
+
+ setIsReady(true);
+ }, [ settings ]);
+
+ const onFriendsEvent = useCallback((event: FriendsEvent) =>
{
switch(event.type)
{
- case FriendListEvent.SHOW_FRIEND_LIST:
- setIsVisible(true);
+ case FriendsEvent.SHOW_FRIEND_LIST:
+ setIsListVisible(true);
return;
- case FriendListEvent.TOGGLE_FRIEND_LIST:
- setIsVisible(value => !value);
+ case FriendsEvent.TOGGLE_FRIEND_LIST:
+ setIsListVisible(value => !value);
return;
- case FriendListSendFriendRequestEvent.SEND_FRIEND_REQUEST:
- const requestEvent = (event as FriendListSendFriendRequestEvent);
+ case FriendsSendFriendRequestEvent.SEND_FRIEND_REQUEST:
+ const requestEvent = (event as FriendsSendFriendRequestEvent);
return;
- case FriendListEvent.REQUEST_FRIEND_LIST:
- dispatchUiEvent(new FriendListContentEvent(friendListState.friends));
+ case FriendsEvent.REQUEST_FRIEND_LIST:
+ dispatchUiEvent(new FriendListContentEvent(friendsState.friends));
return;
}
- }, [friendListState.friends]);
+ }, [ friendsState.friends ]);
- useUiEvent(FriendListEvent.SHOW_FRIEND_LIST, onFriendListEvent);
- useUiEvent(FriendListEvent.TOGGLE_FRIEND_LIST, onFriendListEvent);
- useUiEvent(FriendListSendFriendRequestEvent.SEND_FRIEND_REQUEST, onFriendListEvent);
- useUiEvent(FriendListEvent.REQUEST_FRIEND_LIST, onFriendListEvent);
+ useUiEvent(FriendsEvent.SHOW_FRIEND_LIST, onFriendsEvent);
+ useUiEvent(FriendsEvent.TOGGLE_FRIEND_LIST, onFriendsEvent);
+ useUiEvent(FriendsSendFriendRequestEvent.SEND_FRIEND_REQUEST, onFriendsEvent);
+ useUiEvent(FriendsEvent.REQUEST_FRIEND_LIST, onFriendsEvent);
const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) =>
{
@@ -62,7 +70,7 @@ export const FriendsView: FC<{}> = props =>
if(!userData || (userData.type !== RoomObjectUserType.getTypeNumber(RoomObjectUserType.USER))) return;
- const friend = friendListState.friends.find(friend =>
+ const friend = friendsState.friends.find(friend =>
{
return (friend.id === userData.webID);
});
@@ -70,67 +78,26 @@ export const FriendsView: FC<{}> = props =>
if(!friend) return;
dispatchUiEvent(new FriendEnteredRoomEvent(userData.roomIndex, RoomObjectCategory.UNIT, userData.webID, userData.name, userData.type));
- }, [ friendListState.friends ]);
+ }, [ friendsState.friends ]);
useRoomEngineEvent(RoomEngineObjectEvent.ADDED, onRoomEngineObjectEvent);
- useEffect(() =>
- {
- if(!settings) return;
-
- setIsReady(true);
- }, [ settings ]);
-
- useEffect(() =>
- {
- SendMessageHook(new MessengerInitComposer());
- }, []);
-
const onlineFriends = useMemo(() =>
{
- if(!friends) return [];
-
return friends.filter(f => f.online);
}, [ friends ]);
const offlineFriends = useMemo(() =>
{
- if(!friends) return [];
-
return friends.filter(f => !f.online);
}, [ friends ]);
return (
-
-
- { isReady && createPortal(, document.getElementById('toolbar-friend-bar-container')) }
- { isVisible &&
-
- setIsVisible(false) } />
-
-
- { TABS.map((tab, index) =>
- {
- return ( setCurrentTab(index) }>
- { LocalizeText(tab) }
- );
- }) }
-
-
- { currentTab === 0 &&
-
-
-
-
-
-
- { requests.length > 0 &&
-
- }
- }
-
-
- }
-
+
+
+ { isReady && createPortal(, document.getElementById('toolbar-friend-bar-container')) }
+ { isListVisible && setIsListVisible(false) } /> }
+
+
);
}
diff --git a/src/views/friends/common/MessengerThread.ts b/src/views/friends/common/MessengerThread.ts
new file mode 100644
index 00000000..a2ee75e1
--- /dev/null
+++ b/src/views/friends/common/MessengerThread.ts
@@ -0,0 +1,83 @@
+import { LocalizeText } from '../../../api';
+import { MessengerFriend } from './MessengerFriend';
+import { MessengerThreadChat } from './MessengerThreadChat';
+import { MessengerThreadChatGroup } from './MessengerThreadChatGroup';
+
+export class MessengerThread
+{
+ public static MESSAGE_RECEIVED: string = 'MT_MESSAGE_RECEIVED';
+
+ private _participant: MessengerFriend;
+ private _groups: MessengerThreadChatGroup[];
+ private _lastUpdated: Date;
+ private _unread: boolean;
+
+ constructor(participant: MessengerFriend, isNew: boolean = true)
+ {
+ this._participant = participant;
+ this._groups = [];
+ this._lastUpdated = new Date();
+ this._unread = false;
+
+ if(isNew)
+ {
+ this.addMessage(-1, LocalizeText('messenger.moderationinfo'), 0, null, MessengerThreadChat.SECURITY_NOTIFICATION);
+
+ this._unread = false;
+ }
+ }
+
+ public addMessage(senderId: number, message: string, secondsSinceSent: number = 0, extraData: string = null, type: number = 0): MessengerThreadChat
+ {
+ const group = this.getLastGroup(senderId);
+
+ if(!group) return;
+
+ const chat = new MessengerThreadChat(senderId, message, secondsSinceSent, extraData, type);
+
+ group.addChat(chat);
+
+ this._lastUpdated = new Date();
+ this._unread = true;
+
+ return chat;
+ }
+
+ private getLastGroup(userId: number): MessengerThreadChatGroup
+ {
+ let group = this._groups[(this._groups.length - 1)];
+
+ if(group && (group.userId === userId)) return group;
+
+ group = new MessengerThreadChatGroup(userId);
+
+ this._groups.push(group);
+
+ return group;
+ }
+
+ public setRead(): void
+ {
+ this._unread = false;
+ }
+
+ public get participant(): MessengerFriend
+ {
+ return this._participant;
+ }
+
+ public get groups(): MessengerThreadChatGroup[]
+ {
+ return this._groups;
+ }
+
+ public get lastUpdated(): Date
+ {
+ return this._lastUpdated;
+ }
+
+ public get unread(): boolean
+ {
+ return this._unread;
+ }
+}
diff --git a/src/views/friends/common/MessengerThreadChat.ts b/src/views/friends/common/MessengerThreadChat.ts
new file mode 100644
index 00000000..2927fecc
--- /dev/null
+++ b/src/views/friends/common/MessengerThreadChat.ts
@@ -0,0 +1,54 @@
+export class MessengerThreadChat
+{
+ public static CHAT: number = 0;
+ public static ROOM_INVITE: number = 1;
+ public static STATUS_NOTIFICATION: number = 2;
+ public static SECURITY_NOTIFICATION: number = 3;
+
+ private _type: number;
+ private _senderId: number;
+ private _message: string;
+ private _secondsSinceSent: number;
+ private _extraData: string;
+ private _date: Date;
+
+ constructor(senderId: number, message: string, secondsSinceSent: number = 0, extraData: string = null, type: number = 0)
+ {
+ this._type = type;
+ this._senderId = senderId;
+ this._message = message;
+ this._secondsSinceSent = secondsSinceSent;
+ this._extraData = extraData;
+ this._date = new Date();
+ }
+
+ public get type(): number
+ {
+ return this._type;
+ }
+
+ public get senderId(): number
+ {
+ return this._senderId;
+ }
+
+ public get message(): string
+ {
+ return this._message;
+ }
+
+ public get secondsSinceSent(): number
+ {
+ return this._secondsSinceSent;
+ }
+
+ public get extraData(): string
+ {
+ return this._extraData;
+ }
+
+ public get date(): Date
+ {
+ return this._date;
+ }
+}
diff --git a/src/views/friends/common/MessengerThreadChatGroup.ts b/src/views/friends/common/MessengerThreadChatGroup.ts
new file mode 100644
index 00000000..661dcb07
--- /dev/null
+++ b/src/views/friends/common/MessengerThreadChatGroup.ts
@@ -0,0 +1,28 @@
+import { MessengerThreadChat } from './MessengerThreadChat';
+
+export class MessengerThreadChatGroup
+{
+ private _userId: number;
+ private _chats: MessengerThreadChat[];
+
+ constructor(userId: number)
+ {
+ this._userId = userId;
+ this._chats = [];
+ }
+
+ public addChat(message: MessengerThreadChat): void
+ {
+ this._chats.push(message);
+ }
+
+ public get userId(): number
+ {
+ return this._userId;
+ }
+
+ public get chats(): MessengerThreadChat[]
+ {
+ return this._chats;
+ }
+}
diff --git a/src/views/friends/context/FriendListContext.tsx b/src/views/friends/context/FriendListContext.tsx
deleted file mode 100644
index 39d23764..00000000
--- a/src/views/friends/context/FriendListContext.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { createContext, FC, useContext } from 'react';
-import { FriendListContextProps, IFriendListContext } from './FriendListContext.type';
-
-const FriendListContext = createContext({
- friendListState: null,
- dispatchFriendListState: null
-});
-
-export const FriendListContextProvider: FC = props =>
-{
- return { props.children }
-}
-
-export const useFriendListContext = () => useContext(FriendListContext);
diff --git a/src/views/friends/context/FriendListContext.type.ts b/src/views/friends/context/FriendListContext.type.ts
deleted file mode 100644
index 6e74c4cb..00000000
--- a/src/views/friends/context/FriendListContext.type.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Dispatch, ProviderProps } from 'react';
-import { IFriendListAction, IFriendListState } from '../reducers/FriendListReducer';
-
-export interface IFriendListContext
-{
- friendListState: IFriendListState;
- dispatchFriendListState: Dispatch;
-}
-
-export interface FriendListContextProps extends ProviderProps
-{
-
-}
diff --git a/src/views/friends/context/FriendsContext.tsx b/src/views/friends/context/FriendsContext.tsx
new file mode 100644
index 00000000..5b551102
--- /dev/null
+++ b/src/views/friends/context/FriendsContext.tsx
@@ -0,0 +1,14 @@
+import { createContext, FC, useContext } from 'react';
+import { FriendsContextProps, IFriendsContext } from './FriendsContext.type';
+
+const FriendsContext = createContext({
+ friendsState: null,
+ dispatchFriendsState: null
+});
+
+export const FriendsContextProvider: FC = props =>
+{
+ return { props.children }
+}
+
+export const useFriendsContext = () => useContext(FriendsContext);
diff --git a/src/views/friends/context/FriendsContext.type.ts b/src/views/friends/context/FriendsContext.type.ts
new file mode 100644
index 00000000..a61ef776
--- /dev/null
+++ b/src/views/friends/context/FriendsContext.type.ts
@@ -0,0 +1,13 @@
+import { Dispatch, ProviderProps } from 'react';
+import { IFriendsAction, IFriendsState } from '../reducers/FriendsReducer';
+
+export interface IFriendsContext
+{
+ friendsState: IFriendsState;
+ dispatchFriendsState: Dispatch;
+}
+
+export interface FriendsContextProps extends ProviderProps
+{
+
+}
diff --git a/src/views/friends/reducers/FriendListReducer.tsx b/src/views/friends/reducers/FriendsReducer.tsx
similarity index 76%
rename from src/views/friends/reducers/FriendListReducer.tsx
rename to src/views/friends/reducers/FriendsReducer.tsx
index 3139d735..1901bb49 100644
--- a/src/views/friends/reducers/FriendListReducer.tsx
+++ b/src/views/friends/reducers/FriendsReducer.tsx
@@ -11,14 +11,14 @@ function compareName(a, b)
return 0;
}
-export interface IFriendListState
+export interface IFriendsState
{
settings: MessengerSettings;
friends: MessengerFriend[];
requests: MessengerRequest[];
}
-export interface IFriendListAction
+export interface IFriendsAction
{
type: string;
payload: {
@@ -26,34 +26,36 @@ export interface IFriendListAction
fragment?: FriendParser[];
update?: FriendListUpdateParser;
requests?: FriendRequestData[];
+ numberValue?: number;
+ boolValue?: boolean;
}
}
-export class FriendListActions
+export class FriendsActions
{
- public static RESET_STATE: string = 'FLA_RESET_STATE';
- public static UPDATE_SETTINGS: string = 'FLA_UPDATE_SETTINGS';
- public static PROCESS_FRAGMENT: string = 'FLA_PROCESS_FRAGMENT';
- public static PROCESS_UPDATE: string = 'FLA_PROCESS_UPDATE';
- public static PROCESS_REQUESTS: string = 'FLA_PROCESS_REQUESTS';
+ public static RESET_STATE: string = 'FA_RESET_STATE';
+ public static UPDATE_SETTINGS: string = 'FA_UPDATE_SETTINGS';
+ public static PROCESS_FRAGMENT: string = 'FA_PROCESS_FRAGMENT';
+ public static PROCESS_UPDATE: string = 'FA_PROCESS_UPDATE';
+ public static PROCESS_REQUESTS: string = 'FA_PROCESS_REQUESTS';
}
-export const initialFriendList: IFriendListState = {
+export const initialFriends: IFriendsState = {
settings: null,
friends: [],
requests: []
}
-export const FriendListReducer: Reducer = (state, action) =>
+export const FriendsReducer: Reducer = (state, action) =>
{
switch(action.type)
{
- case FriendListActions.UPDATE_SETTINGS: {
+ case FriendsActions.UPDATE_SETTINGS: {
const settings = (action.payload.settings || state.settings || null);
return { ...state, settings };
}
- case FriendListActions.PROCESS_FRAGMENT: {
+ case FriendsActions.PROCESS_FRAGMENT: {
const fragment = (action.payload.fragment || null);
let friends = [ ...state.friends ];
@@ -85,7 +87,7 @@ export const FriendListReducer: Reducer = (
return { ...state, friends };
}
- case FriendListActions.PROCESS_UPDATE: {
+ case FriendsActions.PROCESS_UPDATE: {
const update = (action.payload.update || null);
let friends = [ ...state.friends ];
@@ -95,11 +97,17 @@ export const FriendListReducer: Reducer = (
{
const index = friends.findIndex(existingFriend => (existingFriend.id === friend.id));
- const newFriend = new MessengerFriend();
- newFriend.populate(friend);
+ if(index === -1)
+ {
+ const newFriend = new MessengerFriend();
+ newFriend.populate(friend);
- if(index > -1) friends[index] = newFriend;
- else friends.unshift(newFriend);
+ friends.unshift(newFriend);
+ }
+ else
+ {
+ friends[index].populate(friend);
+ }
}
for(const friend of update.addedFriends) processUpdate(friend);
@@ -118,7 +126,7 @@ export const FriendListReducer: Reducer = (
return { ...state, friends };
}
- case FriendListActions.PROCESS_REQUESTS: {
+ case FriendsActions.PROCESS_REQUESTS: {
const newRequests = (action.payload.requests || null);
let requests = [ ...state.requests ];
diff --git a/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx b/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx
index b845f530..40873386 100644
--- a/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx
+++ b/src/views/friends/views/friend-bar-item/FriendBarItemView.tsx
@@ -1,6 +1,6 @@
import { FollowFriendMessageComposer, MouseEventType, UserProfileComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
-import { LocalizeText } from '../../../../api';
+import { LocalizeText, OpenMessengerChat } from '../../../../api';
import { SendMessageHook } from '../../../../hooks/messages';
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
import { FriendBarItemViewProps } from './FriendBarItemView.types';
@@ -16,6 +16,13 @@ export const FriendBarItemView: FC = props =>
SendMessageHook(new FollowFriendMessageComposer(friend.id));
}, [ friend ]);
+ const openMessengerChat = useCallback(() =>
+ {
+ if(!friend) return;
+
+ OpenMessengerChat(friend.id);
+ }, [ friend ]);
+
const openProfile = useCallback(() =>
{
SendMessageHook(new UserProfileComposer(friend.id));
@@ -59,7 +66,7 @@ export const FriendBarItemView: FC = props =>
{ friend.name }
{ isVisible &&
-
+
{ friend.followingAllowed && }
}
diff --git a/src/views/friends/views/friend-bar/FriendBarView.tsx b/src/views/friends/views/friend-bar/FriendBarView.tsx
index 3931c4f4..a0347c94 100644
--- a/src/views/friends/views/friend-bar/FriendBarView.tsx
+++ b/src/views/friends/views/friend-bar/FriendBarView.tsx
@@ -1,20 +1,14 @@
import { FC, useMemo, useState } from 'react';
-import { useFriendListContext } from '../../context/FriendListContext';
import { FriendBarItemView } from '../friend-bar-item/FriendBarItemView';
import { FriendBarViewProps } from './FriendBarView.types';
export const FriendBarView: FC = props =>
{
- const { friendListState = null } = useFriendListContext();
- const { friends = null } = friendListState;
+ const { onlineFriends = null } = props;
+
const [ indexOffset, setIndexOffset ] = useState(0);
const [ maxDisplayCount, setMaxDisplayCount ] = useState(3);
- const onlineFriends = useMemo(() =>
- {
- return friends.filter(friend => friend.online);
- }, [ friends ]);
-
const canDecreaseIndex = useMemo(() =>
{
if(indexOffset === 0) return false;
diff --git a/src/views/friends/views/friend-bar/FriendBarView.types.ts b/src/views/friends/views/friend-bar/FriendBarView.types.ts
index f47af57f..61a040ce 100644
--- a/src/views/friends/views/friend-bar/FriendBarView.types.ts
+++ b/src/views/friends/views/friend-bar/FriendBarView.types.ts
@@ -1,4 +1,5 @@
+import { MessengerFriend } from './../../common/MessengerFriend';
export interface FriendBarViewProps
{
-
+ onlineFriends: MessengerFriend[];
}
diff --git a/src/views/friends/views/friend-item/FriendsListItemView.tsx b/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx
similarity index 85%
rename from src/views/friends/views/friend-item/FriendsListItemView.tsx
rename to src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx
index bac0415d..60b2066a 100644
--- a/src/views/friends/views/friend-item/FriendsListItemView.tsx
+++ b/src/views/friends/views/friends-group-item/FriendsGroupItemView.tsx
@@ -1,12 +1,12 @@
import { FollowFriendMessageComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
-import { LocalizeText } from '../../../../api';
+import { LocalizeText, OpenMessengerChat } from '../../../../api';
import { SendMessageHook } from '../../../../hooks';
import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView';
import { MessengerFriend } from '../../common/MessengerFriend';
-import { FriendsListItemViewProps } from './FriendsListItemView.types';
+import { FriendsGroupItemViewProps } from './FriendsGroupItemView.types';
-export const FriendsListItemView: FC = props =>
+export const FriendsGroupItemView: FC = props =>
{
const { friend = null } = props;
@@ -19,6 +19,13 @@ export const FriendsListItemView: FC = props =>
SendMessageHook(new FollowFriendMessageComposer(friend.id));
}, [ friend ]);
+ const openMessengerChat = useCallback(() =>
+ {
+ if(!friend) return;
+
+ OpenMessengerChat(friend.id);
+ }, [ friend ]);
+
const getCurrentRelationshipName = useCallback(() =>
{
if(!friend) return 'none';
@@ -48,7 +55,7 @@ export const FriendsListItemView: FC = props =>
{ !isExpanded && <>
{ friend.followingAllowed &&
}
- { friend.online &&
}
+ { friend.online &&
}
setIsExpanded(true) } title={ LocalizeText('infostand.link.relationship') } />
> }
{ isExpanded && <>
diff --git a/src/views/friends/views/friend-item/FriendsListItemView.types.ts b/src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts
similarity index 69%
rename from src/views/friends/views/friend-item/FriendsListItemView.types.ts
rename to src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts
index df44d3b5..345532b1 100644
--- a/src/views/friends/views/friend-item/FriendsListItemView.types.ts
+++ b/src/views/friends/views/friends-group-item/FriendsGroupItemView.types.ts
@@ -1,6 +1,6 @@
import { MessengerFriend } from '../../common/MessengerFriend';
-export interface FriendsListItemViewProps
+export interface FriendsGroupItemViewProps
{
friend: MessengerFriend;
}
diff --git a/src/views/friends/views/list/FriendsListView.tsx b/src/views/friends/views/friends-group/FriendsGroupView.tsx
similarity index 58%
rename from src/views/friends/views/list/FriendsListView.tsx
rename to src/views/friends/views/friends-group/FriendsGroupView.tsx
index 86ed2707..c5eb989b 100644
--- a/src/views/friends/views/list/FriendsListView.tsx
+++ b/src/views/friends/views/friends-group/FriendsGroupView.tsx
@@ -1,11 +1,11 @@
import React, { FC } from 'react';
import { MessengerFriend } from '../../common/MessengerFriend';
import { MessengerRequest } from '../../common/MessengerRequest';
-import { FriendsListItemView } from '../friend-item/FriendsListItemView';
-import { FriendsRequestItemView } from '../request-item/FriendsRequestItemView';
-import { FriendsListViewProps } from './FriendsListView.types';
+import { FriendsGroupItemView } from '../friends-group-item/FriendsGroupItemView';
+import { FriendsRequestItemView } from '../friends-request-item/FriendsRequestItemView';
+import { FriendsGroupViewProps } from './FriendsGroupView.types';
-export const FriendsListView: FC = props =>
+export const FriendsGroupView: FC = props =>
{
const { list = null } = props;
@@ -15,7 +15,7 @@ export const FriendsListView: FC = props =>
{ list.map((item, index) =>
{
if(item instanceof MessengerFriend)
- return
+ return
else if(item instanceof MessengerRequest)
return
else
diff --git a/src/views/friends/views/list/FriendsListView.types.ts b/src/views/friends/views/friends-group/FriendsGroupView.types.ts
similarity index 82%
rename from src/views/friends/views/list/FriendsListView.types.ts
rename to src/views/friends/views/friends-group/FriendsGroupView.types.ts
index 8a4c4bc9..48bc5ee6 100644
--- a/src/views/friends/views/list/FriendsListView.types.ts
+++ b/src/views/friends/views/friends-group/FriendsGroupView.types.ts
@@ -1,7 +1,7 @@
import { MessengerFriend } from '../../common/MessengerFriend';
import { MessengerRequest } from '../../common/MessengerRequest';
-export interface FriendsListViewProps
+export interface FriendsGroupViewProps
{
list: MessengerFriend[] | MessengerRequest[];
}
diff --git a/src/views/friends/views/friends-list/FriendsListView.tsx b/src/views/friends/views/friends-list/FriendsListView.tsx
new file mode 100644
index 00000000..fd796044
--- /dev/null
+++ b/src/views/friends/views/friends-list/FriendsListView.tsx
@@ -0,0 +1,43 @@
+import { FC, useState } from 'react';
+import { LocalizeText } from '../../../../api';
+import { NitroCardAccordionItemView, NitroCardAccordionView, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout';
+import { FriendsGroupView } from '../friends-group/FriendsGroupView';
+import { FriendsListViewProps } from './FriendsListView.types';
+
+const TABS: string[] = ['friendlist.friends', 'generic.search'];
+
+export const FriendsListView: FC = props =>
+{
+ const { onlineFriends = [], offlineFriends = [], friendRequests = [], onCloseClick = null } = props;
+
+ const [ currentTab, setCurrentTab ] = useState(0);
+
+ return (
+
+
+
+
+ { TABS.map((tab, index) =>
+ {
+ return ( setCurrentTab(index) }>
+ { LocalizeText(tab) }
+ );
+ }) }
+
+
+ { currentTab === 0 &&
+
+
+
+
+
+
+ { friendRequests.length > 0 &&
+
+ }
+ }
+
+
+
+ );
+};
diff --git a/src/views/friends/views/friends-list/FriendsListView.types.ts b/src/views/friends/views/friends-list/FriendsListView.types.ts
new file mode 100644
index 00000000..01bfcc84
--- /dev/null
+++ b/src/views/friends/views/friends-list/FriendsListView.types.ts
@@ -0,0 +1,9 @@
+import { MessengerFriend } from './../../common/MessengerFriend';
+import { MessengerRequest } from './../../common/MessengerRequest';
+export interface FriendsListViewProps
+{
+ onCloseClick: () => void;
+ onlineFriends: MessengerFriend[];
+ offlineFriends: MessengerFriend[];
+ friendRequests: MessengerRequest[];
+}
diff --git a/src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx b/src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx
new file mode 100644
index 00000000..f25c42f9
--- /dev/null
+++ b/src/views/friends/views/friends-request-item/FriendsRequestItemView.tsx
@@ -0,0 +1,37 @@
+import { AcceptFriendMessageComposer, DeclineFriendMessageComposer } from '@nitrots/nitro-renderer';
+import { FC, useCallback } from 'react';
+import { SendMessageHook } from '../../../../hooks/messages/message-event';
+import { UserProfileIconView } from '../../../shared/user-profile-icon/UserProfileIconView';
+import { FriendsRequestItemViewProps } from './FriendsRequestItemView.types';
+
+export const FriendsRequestItemView: FC = props =>
+{
+ const { request = null } = props;
+
+ const accept = useCallback(() =>
+ {
+ if(!request) return;
+
+ SendMessageHook(new AcceptFriendMessageComposer(request.id));
+ }, [ request ]);
+
+ const decline = useCallback(() =>
+ {
+ if(!request) return;
+
+ SendMessageHook(new DeclineFriendMessageComposer(false, request.id));
+ }, [ request ]);
+
+ if(!request) return null;
+
+ return (
+
+
+
{ request.name }
+
+
+
+
+
+ );
+};
diff --git a/src/views/friends/views/friends-request-item/FriendsRequestItemView.types.ts b/src/views/friends/views/friends-request-item/FriendsRequestItemView.types.ts
new file mode 100644
index 00000000..4f5c38d5
--- /dev/null
+++ b/src/views/friends/views/friends-request-item/FriendsRequestItemView.types.ts
@@ -0,0 +1,6 @@
+import { MessengerRequest } from '../../common/MessengerRequest';
+
+export interface FriendsRequestItemViewProps
+{
+ request: MessengerRequest;
+}
diff --git a/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx b/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx
new file mode 100644
index 00000000..b0d30ea7
--- /dev/null
+++ b/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.tsx
@@ -0,0 +1,48 @@
+import { FC } from 'react';
+import { GetSessionDataManager } from '../../../../api';
+import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
+import { MessengerThreadChat } from '../../common/MessengerThreadChat';
+import { FriendsMessengerThreadGroupProps } from './FriendsMessengerThreadGroup.types';
+
+export const FriendsMessengerThreadGroup: FC = props =>
+{
+ const { thread = null, group = null } = props;
+
+ if(!thread || !group) return null;
+
+ if(group.userId === -1)
+ {
+ return (
+
+ { group.chats.map((chat, index) =>
+ {
+ return (
+
+ { chat.type === MessengerThreadChat.SECURITY_NOTIFICATION &&
+
}
+
+ );
+ }) }
+
+ );
+ }
+
+ return (
+
+ { (group.userId > 0) &&
+
}
+
+ { group.chats.map((chat, index) =>
{ chat.message }
) }
+
+ { (group.userId === 0) &&
+
}
+
+ );
+}
diff --git a/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.types.ts b/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.types.ts
new file mode 100644
index 00000000..12a0ed17
--- /dev/null
+++ b/src/views/friends/views/messenger-thread-group/FriendsMessengerThreadGroup.types.ts
@@ -0,0 +1,8 @@
+import { MessengerThread } from '../../common/MessengerThread';
+import { MessengerThreadChatGroup } from '../../common/MessengerThreadChatGroup';
+
+export interface FriendsMessengerThreadGroupProps
+{
+ thread: MessengerThread;
+ group: MessengerThreadChatGroup;
+}
diff --git a/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.tsx b/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.tsx
new file mode 100644
index 00000000..3bf6326a
--- /dev/null
+++ b/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.tsx
@@ -0,0 +1,17 @@
+import { FC } from 'react';
+import { FriendsMessengerThreadGroup } from '../messenger-thread-group/FriendsMessengerThreadGroup';
+import { FriendsMessengerThreadViewProps } from './FriendsMessengerThreadView.types';
+
+export const FriendsMessengerThreadView: FC = props =>
+{
+ const { thread = null } = props;
+
+ return (
+ <>
+ { (thread.groups.length > 0) && thread.groups.map((group, index) =>
+ {
+ return ;
+ }) }
+ >
+ );
+}
diff --git a/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.types.ts b/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.types.ts
new file mode 100644
index 00000000..a6e0f4c4
--- /dev/null
+++ b/src/views/friends/views/messenger-thread/FriendsMessengerThreadView.types.ts
@@ -0,0 +1,6 @@
+import { MessengerThread } from '../../common/MessengerThread';
+
+export interface FriendsMessengerThreadViewProps
+{
+ thread: MessengerThread;
+}
diff --git a/src/views/friends/views/messenger/FriendsMessengerView.scss b/src/views/friends/views/messenger/FriendsMessengerView.scss
new file mode 100644
index 00000000..596ab19f
--- /dev/null
+++ b/src/views/friends/views/messenger/FriendsMessengerView.scss
@@ -0,0 +1,79 @@
+.nitro-friends-messenger {
+ width: 280px;
+ resize: both;
+
+ .friend-head {
+ position: relative;
+ width: 40px;
+ height: 40px;
+ overflow: hidden;
+
+ .icon {
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ z-index: 10;
+ }
+
+ .avatar-image {
+ position: absolute;
+ margin-left: -27px;
+ margin-top: -27px;
+ }
+ }
+
+ .chat-title {
+ margin-top: -21px;
+ }
+
+ .chat-messages {
+ height: 200px;
+ min-height: 200px;
+ overflow-y: auto;
+
+ .message-avatar {
+ position: relative;
+ overflow: hidden;
+ width: 50px;
+ height: 50px;
+
+ .avatar-image {
+ position: absolute;
+ margin-left: -22px;
+ margin-top: -25px;
+ }
+ }
+
+ .messages-group-left {
+ position: relative;
+
+ &:before {
+ position: absolute;
+ content: ' ';
+ width: 0;
+ height: 0;
+ border-right: 8px solid rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important;
+ border-top: 8px solid transparent;
+ border-bottom: 8px solid transparent;
+ top: 10px;
+ left: -8px;
+ }
+ }
+
+ .messages-group-right {
+ position: relative;
+
+ &:before {
+ position: absolute;
+ content: ' ';
+ width: 0;
+ height: 0;
+ border-left: 8px solid rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important;
+ border-top: 8px solid transparent;
+ border-bottom: 8px solid transparent;
+ top: 10px;
+ right: -8px;
+ }
+ }
+ }
+}
diff --git a/src/views/friends/views/messenger/FriendsMessengerView.tsx b/src/views/friends/views/messenger/FriendsMessengerView.tsx
new file mode 100644
index 00000000..dac6a7a5
--- /dev/null
+++ b/src/views/friends/views/messenger/FriendsMessengerView.tsx
@@ -0,0 +1,281 @@
+import { FollowFriendMessageComposer, ILinkEventTracker, NewConsoleMessageEvent, SendMessageComposer, UserProfileComposer } from '@nitrots/nitro-renderer';
+import { FC, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../../../api';
+import { FriendsMessengerIconEvent } from '../../../../events';
+import { BatchUpdates, CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../hooks';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
+import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
+import { MessengerThread } from '../../common/MessengerThread';
+import { MessengerThreadChat } from '../../common/MessengerThreadChat';
+import { useFriendsContext } from '../../context/FriendsContext';
+import { FriendsMessengerThreadView } from '../messenger-thread/FriendsMessengerThreadView';
+
+export const FriendsMessengerView: FC<{}> = props =>
+{
+ const [ isVisible, setIsVisible ] = useState(false);
+ const [ messageThreads, setMessageThreads ] = useState([]);
+ const [ activeThreadIndex, setActiveThreadIndex ] = useState(-1);
+ const [ hiddenThreadIndexes, setHiddenThreadIndexes ] = useState([]);
+ const [ messageText, setMessageText ] = useState('');
+ const { friendsState = null } = useFriendsContext();
+ const { friends = [] } = friendsState;
+ const messagesBox = useRef();
+ const [ updateValue, setUpdateValue ] = useState({});
+
+ const followFriend = useCallback(() =>
+ {
+ SendMessageHook(new FollowFriendMessageComposer(messageThreads[activeThreadIndex].participant.id));
+ }, [ messageThreads, activeThreadIndex ]);
+
+ const openProfile = useCallback(() =>
+ {
+ SendMessageHook(new UserProfileComposer(messageThreads[activeThreadIndex].participant.id));
+ }, [ messageThreads, activeThreadIndex ]);
+
+ const getFriend = useCallback((userId: number) =>
+ {
+ return ((friends.find(friend => (friend.id === userId))) || null);
+ }, [ friends ]);
+
+ const visibleThreads = useMemo(() =>
+ {
+ return messageThreads.filter((thread, index) =>
+ {
+ if(hiddenThreadIndexes.indexOf(index) >= 0) return false;
+
+ return true;
+ });
+ }, [ messageThreads, hiddenThreadIndexes ]);
+
+ const getMessageThreadWithIndex = useCallback<(userId: number) => [ number, MessengerThread ]>((userId: number) =>
+ {
+ if(messageThreads.length > 0)
+ {
+ for(let i = 0; i < messageThreads.length; i++)
+ {
+ const thread = messageThreads[i];
+
+ if(thread.participant && (thread.participant.id === userId))
+ {
+ const hiddenIndex = hiddenThreadIndexes.indexOf(i);
+
+ if(hiddenIndex >= 0)
+ {
+ setHiddenThreadIndexes(prevValue =>
+ {
+ const newIndexes = [ ...prevValue ];
+
+ newIndexes.splice(hiddenIndex, 1);
+
+ return newIndexes;
+ });
+ }
+
+ return [ i, thread ];
+ }
+ }
+ }
+
+ const friend = getFriend(userId);
+
+ if(!friend) return [ -1, null ];
+
+ const thread = new MessengerThread(friend);
+ const newThreads = [ ...messageThreads, thread ];
+
+ setMessageThreads(newThreads);
+
+ return [ (newThreads.length - 1), thread ];
+ }, [ messageThreads, hiddenThreadIndexes, getFriend ]);
+
+ const onNewConsoleMessageEvent = useCallback((event: NewConsoleMessageEvent) =>
+ {
+ const parser = event.getParser();
+ const [ threadIndex, thread ] = getMessageThreadWithIndex(parser.senderId);
+
+ if((threadIndex === -1) || !thread) return;
+
+ thread.addMessage(parser.senderId, parser.messageText, parser.secondsSinceSent, parser.extraData);
+
+ setMessageThreads(prevValue => [ ...prevValue ]);
+ }, [ getMessageThreadWithIndex ]);
+
+ CreateMessageHook(NewConsoleMessageEvent, onNewConsoleMessageEvent);
+
+ const sendMessage = useCallback(() =>
+ {
+ if(!messageText || !messageText.length) return;
+
+ if(activeThreadIndex === -1) return;
+
+ const thread = messageThreads[activeThreadIndex];
+
+ if(!thread) return;
+
+ SendMessageHook(new SendMessageComposer(thread.participant.id, messageText));
+
+ thread.addMessage(0, messageText, 0, null, MessengerThreadChat.CHAT);
+
+ BatchUpdates(() =>
+ {
+ setMessageThreads(prevValue => [ ...prevValue ]);
+ setMessageText('');
+ });
+ }, [ messageThreads, activeThreadIndex, messageText ]);
+
+ const onKeyDown = useCallback((event: KeyboardEvent) =>
+ {
+ if(event.key !== 'Enter') return;
+
+ sendMessage();
+ }, [ sendMessage ]);
+
+ const linkReceived = useCallback((url: string) =>
+ {
+ const parts = url.split('/');
+
+ if(parts.length < 3) return;
+
+ if(parts[2] === 'open')
+ {
+ setIsVisible(true);
+
+ return;
+ }
+
+ const [ threadIndex ] = getMessageThreadWithIndex(parseInt(parts[2]));
+
+ if(threadIndex === -1) return;
+
+ BatchUpdates(() =>
+ {
+ setActiveThreadIndex(threadIndex);
+ setIsVisible(true);
+ });
+ }, [ getMessageThreadWithIndex ]);
+
+ const closeThread = useCallback((threadIndex: number) =>
+ {
+ setHiddenThreadIndexes(prevValue =>
+ {
+ const values = [ ...prevValue ];
+
+ if(values.indexOf(threadIndex) === -1) values.push(threadIndex);
+
+ return values;
+ });
+ }, []);
+
+ useEffect(() =>
+ {
+ const linkTracker: ILinkEventTracker = {
+ linkReceived,
+ eventUrlPrefix: 'friends/messenger/'
+ };
+
+ AddEventLinkTracker(linkTracker);
+
+ return () => RemoveLinkEventTracker(linkTracker);
+ }, [ linkReceived ]);
+
+ useEffect(() =>
+ {
+ if(!isVisible) return;
+
+ if(activeThreadIndex === -1) setActiveThreadIndex(0);
+ }, [ isVisible, activeThreadIndex ]);
+
+ useEffect(() =>
+ {
+ if(hiddenThreadIndexes.indexOf(activeThreadIndex) >= 0) setActiveThreadIndex(0);
+ }, [ activeThreadIndex, hiddenThreadIndexes ]);
+
+ useEffect(() =>
+ {
+ if(!isVisible || (activeThreadIndex === -1)) return;
+
+ const activeThread = messageThreads[activeThreadIndex];
+
+ if(activeThread.unread)
+ {
+ messagesBox.current.scrollTop = messagesBox.current.scrollHeight;
+ activeThread.setRead();
+ setUpdateValue({});
+ }
+ }, [ isVisible, messageThreads, activeThreadIndex ]);
+
+ useEffect(() =>
+ {
+ if(!visibleThreads.length)
+ {
+ setIsVisible(false);
+
+ dispatchUiEvent(new FriendsMessengerIconEvent(FriendsMessengerIconEvent.UPDATE_ICON, FriendsMessengerIconEvent.HIDE_ICON));
+
+ return;
+ }
+
+ let isUnread = false;
+
+ for(const thread of visibleThreads)
+ {
+ if(thread.unread)
+ {
+ isUnread = true;
+
+ break;
+ }
+ }
+
+ dispatchUiEvent(new FriendsMessengerIconEvent(FriendsMessengerIconEvent.UPDATE_ICON, isUnread ? FriendsMessengerIconEvent.UNREAD_ICON : FriendsMessengerIconEvent.SHOW_ICON));
+ }, [ visibleThreads, updateValue ]);
+
+ if(!isVisible) return null;
+
+ return (
+
+ setIsVisible(false) } />
+
+
+ { visibleThreads && (visibleThreads.length > 0) && visibleThreads.map((thread, index) =>
+ {
+ const messageThreadIndex = messageThreads.indexOf(thread);
+
+ return (
+
setActiveThreadIndex(messageThreadIndex) }>
+ { thread.unread &&
}
+
+
+ );
+ }) }
+
+
+ { (activeThreadIndex >= 0) &&
+ <>
+
+ { LocalizeText('messenger.window.separator', [ 'FRIEND_NAME' ], [ messageThreads[activeThreadIndex].participant.name ]) }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setMessageText(event.target.value) } onKeyDown={ onKeyDown } />
+
+
+ > }
+
+
+ );
+}
diff --git a/src/views/friends/views/request-item/FriendsRequestItemView.types.ts b/src/views/friends/views/request-item/FriendsRequestItemView.types.ts
index 4f5c38d5..bc01f938 100644
--- a/src/views/friends/views/request-item/FriendsRequestItemView.types.ts
+++ b/src/views/friends/views/request-item/FriendsRequestItemView.types.ts
@@ -1,5 +1,4 @@
-import { MessengerRequest } from '../../common/MessengerRequest';
-
+import { MessengerRequest } from './../../common/MessengerRequest';
export interface FriendsRequestItemViewProps
{
request: MessengerRequest;
diff --git a/src/views/inventory/InventoryView.scss b/src/views/inventory/InventoryView.scss
index 2da93ac4..e01335a2 100644
--- a/src/views/inventory/InventoryView.scss
+++ b/src/views/inventory/InventoryView.scss
@@ -1,11 +1,6 @@
.nitro-inventory {
- width: 475px;
-
- .content-area {
- min-height: 240px;
- height: 240px;
- resize: vertical;
- }
+ width: $inventory-width;
+ height: $inventory-height;
.empty-image {
background: url('../../assets/images/inventory/empty.png');
@@ -13,6 +8,3 @@
height: 181px;
}
}
-
-
-@import './views/InventoryViews';
diff --git a/src/views/inventory/views/InventoryViews.scss b/src/views/inventory/views/InventoryViews.scss
deleted file mode 100644
index cd28a3b0..00000000
--- a/src/views/inventory/views/InventoryViews.scss
+++ /dev/null
@@ -1,2 +0,0 @@
-@import './badge/InventoryBadgeView';
-@import './furniture/InventoryFurnitureView';
diff --git a/src/views/inventory/views/badge/InventoryBadgeView.scss b/src/views/inventory/views/badge/InventoryBadgeView.scss
deleted file mode 100644
index fc975ace..00000000
--- a/src/views/inventory/views/badge/InventoryBadgeView.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-.current-badge-container {
-
- .badge-image {
- width: 45px;
- height: 45px;
- }
-}
-
-.inventory-badge-overflow {
- height: calc(100% - 91px);
-}
-
-@import './item/InventoryBadgeItemView';
diff --git a/src/views/inventory/views/badge/InventoryBadgeView.tsx b/src/views/inventory/views/badge/InventoryBadgeView.tsx
index 58ce4a56..47f2fe62 100644
--- a/src/views/inventory/views/badge/InventoryBadgeView.tsx
+++ b/src/views/inventory/views/badge/InventoryBadgeView.tsx
@@ -2,6 +2,11 @@ import { RequestBadgesComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect } from 'react';
import { LocalizeBadgeName, LocalizeText } from '../../../../api';
import { SendMessageHook } from '../../../../hooks/messages/message-event';
+import { NitroLayoutButton, NitroLayoutFlex } from '../../../../layout';
+import { NitroLayoutBase } from '../../../../layout/base';
+import { NitroLayoutFlexColumn } from '../../../../layout/flex-column/NitroLayoutFlexColumn';
+import { NitroLayoutGridColumn } from '../../../../layout/grid/column/NitroLayoutGridColumn';
+import { NitroLayoutGrid } from '../../../../layout/grid/NitroLayoutGrid';
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
import { useInventoryContext } from '../../context/InventoryContext';
import { InventoryBadgeActions } from '../../reducers/InventoryBadgeReducer';
@@ -74,33 +79,26 @@ export const InventoryBadgeView: FC = props =>
}
return (
- <>
-
-
-
-
-
-
-
{ LocalizeText('inventory.badges.activebadges') }
-
-
-
-
- { badge && badge.length &&
-
-
+
+
+
+
+
+
+ { LocalizeText('inventory.badges.activebadges') }
+
+
+ { badge && (badge.length > 0) &&
+
+
+
-
-
{ LocalizeBadgeName(badge) }
-
-
-
-
}
-
-
{ LocalizeText('achievements_score_description', [ 'score' ], [ '0' ]) }
-
-
-
- >
+ { LocalizeBadgeName(badge) }
+
+
+ { LocalizeText(isWearingBadge(badge) ? 'inventory.badges.clearbadge' : 'inventory.badges.wearbadge') }
+ }
+
+
);
}
diff --git a/src/views/inventory/views/badge/item/InventoryBadgeItemView.scss b/src/views/inventory/views/badge/item/InventoryBadgeItemView.scss
deleted file mode 100644
index d17f5451..00000000
--- a/src/views/inventory/views/badge/item/InventoryBadgeItemView.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-.inventory-badge-item-container {
- height: 48px;
- max-height: 48px;
-
- .inventory-badge-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;
- }
- }
-}
diff --git a/src/views/inventory/views/bot/InventoryBotView.tsx b/src/views/inventory/views/bot/InventoryBotView.tsx
index 5ea3ef84..59c02571 100644
--- a/src/views/inventory/views/bot/InventoryBotView.tsx
+++ b/src/views/inventory/views/bot/InventoryBotView.tsx
@@ -2,10 +2,16 @@ import { GetBotInventoryComposer, RoomObjectVariable } from '@nitrots/nitro-rend
import { FC, useEffect } from 'react';
import { GetRoomEngine, LocalizeText } from '../../../../api';
import { SendMessageHook } from '../../../../hooks/messages/message-event';
+import { NitroLayoutButton } from '../../../../layout';
+import { NitroLayoutBase } from '../../../../layout/base';
+import { NitroLayoutFlexColumn } from '../../../../layout/flex-column/NitroLayoutFlexColumn';
+import { NitroLayoutGridColumn } from '../../../../layout/grid/column/NitroLayoutGridColumn';
+import { NitroLayoutGrid } from '../../../../layout/grid/NitroLayoutGrid';
import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerView';
import { attemptBotPlacement } from '../../common/BotUtilities';
import { useInventoryContext } from '../../context/InventoryContext';
import { InventoryBotActions } from '../../reducers/InventoryBotReducer';
+import { InventoryCategoryEmptyView } from '../category-empty/InventoryCategoryEmptyView';
import { InventoryBotViewProps } from './InventoryBotView.types';
import { InventoryBotResultsView } from './results/InventoryBotResultsView';
@@ -62,35 +68,26 @@ export const InventoryBotView: FC = props =>
roomPreviewer.addAvatarIntoRoom(botData.figure, 0);
}, [ roomPreviewer, botItem ]);
- if(!botItems || !botItems.length)
- {
- return (
-
-
-
-
- { LocalizeText('inventory.empty.bots.title') }
-
-
{ LocalizeText('inventory.empty.bots.desc') }
-
-
- );
- }
+ if(!botItems || !botItems.length) return ;
return (
-
-
-
-
-
-
- { botItem &&
-
{ botItem.botData.name }
- { !!roomSession &&
}
-
}
-
-
+
+
+
+
+
+
+
+
+ { botItem &&
+
+ { botItem.botData.name }
+ { !!roomSession &&
+ attemptBotPlacement(botItem) }>
+ { LocalizeText('inventory.furni.placetoroom') }
+ }
+ }
+
+
);
}
diff --git a/src/views/inventory/views/category-empty/InventoryCategoryEmptyView.tsx b/src/views/inventory/views/category-empty/InventoryCategoryEmptyView.tsx
new file mode 100644
index 00000000..2fe5b4aa
--- /dev/null
+++ b/src/views/inventory/views/category-empty/InventoryCategoryEmptyView.tsx
@@ -0,0 +1,21 @@
+import { FC } from 'react';
+import { NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../layout';
+import { NitroLayoutBase } from '../../../../layout/base';
+import { InventoryCategoryEmptyViewProps } from './InventoryCategoryEmptyView.types';
+
+export const InventoryCategoryEmptyView: FC = props =>
+{
+ const { title = '', desc = '', ...rest } = props;
+
+ return (
+
+
+
+
+
+ { title }
+ { desc }
+
+
+ );
+}
diff --git a/src/views/inventory/views/category-empty/InventoryCategoryEmptyView.types.ts b/src/views/inventory/views/category-empty/InventoryCategoryEmptyView.types.ts
new file mode 100644
index 00000000..0d57173b
--- /dev/null
+++ b/src/views/inventory/views/category-empty/InventoryCategoryEmptyView.types.ts
@@ -0,0 +1,7 @@
+import { NitroLayoutGridProps } from '../../../../layout';
+
+export interface InventoryCategoryEmptyViewProps extends NitroLayoutGridProps
+{
+ title: string;
+ desc: string;
+}
diff --git a/src/views/inventory/views/furniture/InventoryFurnitureView.scss b/src/views/inventory/views/furniture/InventoryFurnitureView.scss
deleted file mode 100644
index 089af5ef..00000000
--- a/src/views/inventory/views/furniture/InventoryFurnitureView.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-.stuffdata-extra-container {
- position: absolute;
- top: 5px;
- right: 15px;
-}
diff --git a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx
index 67878baa..05e3afb7 100644
--- a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx
+++ b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx
@@ -2,6 +2,11 @@ import { FurnitureListComposer, RoomObjectVariable, Vector3d } from '@nitrots/ni
import { FC, useEffect, useState } from 'react';
import { GetRoomEngine, GetSessionDataManager, LocalizeText } from '../../../../api';
import { SendMessageHook } from '../../../../hooks/messages';
+import { NitroLayoutButton } from '../../../../layout';
+import { NitroLayoutBase } from '../../../../layout/base';
+import { NitroLayoutFlexColumn } from '../../../../layout/flex-column/NitroLayoutFlexColumn';
+import { NitroLayoutGridColumn } from '../../../../layout/grid/column/NitroLayoutGridColumn';
+import { NitroLayoutGrid } from '../../../../layout/grid/NitroLayoutGrid';
import { LimitedEditionCompactPlateView } from '../../../shared/limited-edition/compact-plate/LimitedEditionCompactPlateView';
import { RarityLevelView } from '../../../shared/rarity-level/RarityLevelView';
import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerView';
@@ -10,6 +15,7 @@ import { attemptItemPlacement } from '../../common/FurnitureUtilities';
import { GroupItem } from '../../common/GroupItem';
import { useInventoryContext } from '../../context/InventoryContext';
import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer';
+import { InventoryCategoryEmptyView } from '../category-empty/InventoryCategoryEmptyView';
import { InventoryFurnitureViewProps } from './InventoryFurnitureView.types';
import { InventoryFurnitureResultsView } from './results/InventoryFurnitureResultsView';
import { InventoryFurnitureSearchView } from './search/InventoryFurnitureSearchView';
@@ -98,46 +104,35 @@ export const InventoryFurnitureView: FC = props =>
}
}, [ roomPreviewer, groupItem ]);
- if(!groupItems || !groupItems.length)
- {
- return (
-
-
-
-
- { LocalizeText('inventory.empty.title') }
-
-
{ LocalizeText('inventory.empty.desc') }
-
-
- );
- }
+ if(!groupItems || !groupItems.length) return ;
return (
-
-
+
+
-
-
-
- { groupItem && groupItem.stuffData.isUnique &&
-
-
-
}
- { (groupItem && groupItem.stuffData.rarityLevel > -1) &&
-
-
-
}
+
+
+
+
+ { groupItem && groupItem.stuffData.isUnique &&
+
+
+ }
+ { (groupItem && groupItem.stuffData.rarityLevel > -1) &&
+
+
+ }
+
{ groupItem &&
-
-
{ groupItem.name }
+
+ { groupItem.name }
{ !!roomSession &&
- }
- }
-
-
+ attemptItemPlacement(groupItem) }>
+ { LocalizeText('inventory.furni.placetoroom') }
+ }
+ }
+
+
);
}
diff --git a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx
index 4b49d6a3..a75cf789 100644
--- a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx
+++ b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx
@@ -46,5 +46,5 @@ export const InventoryFurnitureItemView: FC = p
const count = groupItem.getUnlockedCount();
- return ;
+ return ;
}
diff --git a/src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.tsx b/src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.tsx
index 599214cd..f7934a19 100644
--- a/src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.tsx
+++ b/src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.tsx
@@ -30,7 +30,7 @@ export const InventoryFurnitureSearchView: FC
}, [ groupItems, setGroupItems, searchValue ]);
return (
-
+
setSearchValue(event.target.value) } />
diff --git a/src/views/inventory/views/pet/InventoryPetView.tsx b/src/views/inventory/views/pet/InventoryPetView.tsx
index 5d8d8d90..b9949c95 100644
--- a/src/views/inventory/views/pet/InventoryPetView.tsx
+++ b/src/views/inventory/views/pet/InventoryPetView.tsx
@@ -2,10 +2,15 @@ import { RequestPetsComposer, RoomObjectVariable } from '@nitrots/nitro-renderer
import { FC, useEffect } from 'react';
import { GetRoomEngine, LocalizeText } from '../../../../api';
import { SendMessageHook } from '../../../../hooks/messages/message-event';
+import { NitroLayoutBase } from '../../../../layout/base';
+import { NitroLayoutFlexColumn } from '../../../../layout/flex-column/NitroLayoutFlexColumn';
+import { NitroLayoutGridColumn } from '../../../../layout/grid/column/NitroLayoutGridColumn';
+import { NitroLayoutGrid } from '../../../../layout/grid/NitroLayoutGrid';
import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerView';
import { attemptPetPlacement } from '../../common/PetUtilities';
import { useInventoryContext } from '../../context/InventoryContext';
import { InventoryPetActions } from '../../reducers/InventoryPetReducer';
+import { InventoryCategoryEmptyView } from '../category-empty/InventoryCategoryEmptyView';
import { InventoryPetViewProps } from './InventoryPetView.types';
import { InventoryPetResultsView } from './results/InventoryPetResultsView';
@@ -62,35 +67,23 @@ export const InventoryPetView: FC
= props =>
roomPreviewer.addPetIntoRoom(petData.figureString);
}, [ roomPreviewer, petItem ]);
- if(!petItems || !petItems.length)
- {
- return (
-
-
-
-
- { LocalizeText('inventory.empty.pets.title') }
-
-
{ LocalizeText('inventory.empty.pets.desc') }
-
-
- );
- }
+ if(!petItems || !petItems.length) return ;
return (
-
-
+
+
-
-
-
- { petItem &&
-
{ petItem.petData.name }
- { !!roomSession &&
}
-
}
-
-
+
+
+
+
+
+ { petItem &&
+
+ { petItem.petData.name }
+ { !!roomSession && }
+ }
+
+
);
}
diff --git a/src/views/inventory/views/trade/InventoryTradeView.tsx b/src/views/inventory/views/trade/InventoryTradeView.tsx
index 5969daec..f376e890 100644
--- a/src/views/inventory/views/trade/InventoryTradeView.tsx
+++ b/src/views/inventory/views/trade/InventoryTradeView.tsx
@@ -2,8 +2,12 @@ import { FurnitureListComposer, IObjectData, TradingAcceptComposer, TradingConfi
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { LocalizeText } from '../../../../api';
import { SendMessageHook } from '../../../../hooks/messages';
+import { NitroLayoutButton, NitroLayoutFlex, NitroLayoutFlexColumn } from '../../../../layout';
+import { NitroLayoutBase } from '../../../../layout/base';
import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView';
import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView';
+import { NitroLayoutGridColumn } from '../../../../layout/grid/column/NitroLayoutGridColumn';
+import { NitroLayoutGrid } from '../../../../layout/grid/NitroLayoutGrid';
import { FurniCategory } from '../../common/FurniCategory';
import { GroupItem } from '../../common/GroupItem';
import { IFurnitureItem } from '../../common/IFurnitureItem';
@@ -224,67 +228,81 @@ export const InventoryTradeView: FC = props =>
}, [ tradeData, dispatchFurnitureState ]);
return (
-
-
-
-
- { filteredGroupItems && (filteredGroupItems.length > 0) && filteredGroupItems.map((item, index) =>
- {
- const count = item.getUnlockedCount();
-
- return (
- (count && setGroupItem(item)) }>
- { ((count > 0) && (groupItem === item)) &&
- }
-
- );
- }) }
-
-
{ groupItem ? groupItem.name : LocalizeText('catalog_selectproduct') }
-
-
-
-
{ LocalizeText('inventory.trading.you') } { LocalizeText('inventory.trading.areoffering') }:
+
+
+
+
- { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) =>
+ { filteredGroupItems && (filteredGroupItems.length > 0) && filteredGroupItems.map((item, index) =>
{
- const item = (tradeData.ownUser.items.getWithIndex(i) || null);
-
- if(!item) return ;
+ const count = item.getUnlockedCount();
return (
- setOwnGroupItem(item) }>
- { (ownGroupItem === item) &&
-
-
-
-
{ tradeData.otherUser.userName } { LocalizeText('inventory.trading.isoffering') }:
-
- { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) =>
- {
- const item = (tradeData.otherUser.items.getWithIndex(i) || null);
+
+
+ { 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 = (tradeData.ownUser.items.getWithIndex(i) || null);
- if(!item) return ;
+ if(!item) return ;
- return setOtherGroupItem(item) } />;
- }) }
- { otherGroupItem ? otherGroupItem.name : LocalizeText('catalog_selectproduct') }
-
-
-
- { LocalizeText('generic.cancel') }
+ return (
+ setOwnGroupItem(item) }>
+ { (ownGroupItem === item) &&
+ removeItem(item) }>
+
+ }
+
+ );
+ }) }
+
+
+
+ { ownGroupItem ? ownGroupItem.name : LocalizeText('catalog_selectproduct') }
+
+
+
+
+ { tradeData.otherUser.userName } { LocalizeText('inventory.trading.isoffering') }:
+
+ { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) =>
+ {
+ const item = (tradeData.otherUser.items.getWithIndex(i) || null);
+
+ if(!item) return ;
+
+ return setOtherGroupItem(item) } />;
+ }) }
+
+
+
+ { otherGroupItem ? otherGroupItem.name : LocalizeText('catalog_selectproduct') }
+
+
+
+
+ { LocalizeText('generic.cancel') }
{ getTradeButton }
-
-
-
+
+
+
);
}
diff --git a/src/views/navigator/NavigatorView.scss b/src/views/navigator/NavigatorView.scss
index d29e353b..a438267d 100644
--- a/src/views/navigator/NavigatorView.scss
+++ b/src/views/navigator/NavigatorView.scss
@@ -1,11 +1,6 @@
.nitro-navigator {
- width: 400px;
-
- .content-area {
- min-height: 400px;
- height: 400px;
- resize: vertical;
- }
+ width: $navigator-width;
+ height: $navigator-height;
}
.nitro-navigator-doorbell {
diff --git a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx
index 385a0a4f..8fe49ce2 100644
--- a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx
+++ b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx
@@ -1,8 +1,8 @@
import { RoomBannedUsersComposer, RoomBannedUsersEvent, RoomSettingsEvent, RoomUsersWithRightsComposer, RoomUsersWithRightsEvent, SaveRoomSettingsComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../api';
-import { FriendListEvent } from '../../../../events';
-import { FriendListContentEvent } from '../../../../events/friend-list/FriendListContentEvent';
+import { FriendsEvent } from '../../../../events';
+import { FriendListContentEvent } from '../../../../events/friends/FriendListContentEvent';
import { dispatchUiEvent, useUiEvent } from '../../../../hooks';
import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout';
@@ -87,7 +87,7 @@ export const NavigatorRoomSettingsView: FC<{}> = props =>
useEffect(() =>
{
- if(roomSettingsData) dispatchUiEvent(new FriendListEvent(FriendListEvent.REQUEST_FRIEND_LIST));
+ if(roomSettingsData) dispatchUiEvent(new FriendsEvent(FriendsEvent.REQUEST_FRIEND_LIST));
}, [roomSettingsData])
const save = useCallback((data: RoomSettingsData) =>
diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx
index d949cfaa..a12d17bc 100644
--- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx
+++ b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx
@@ -1,6 +1,6 @@
import { RoomEnterEffect, RoomObjectCategory } from '@nitrots/nitro-renderer';
import { FC, useCallback, useMemo, useState } from 'react';
-import { GetRoomSession, GetSessionDataManager, RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectMessage, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../../../../api';
+import { GetRoomSession, GetSessionDataManager, RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectMessage, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateDecorateModeEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../../../../api';
import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispatcher.base';
import { useRoomContext } from '../../context/RoomContext';
import { AvatarInfoWidgetAvatarView } from './views/avatar/AvatarInfoWidgetAvatarView';
@@ -264,6 +264,13 @@ export const AvatarInfoWidgetView: FC<{}> = props =>
// useUiEvent(FriendEnteredRoomEvent.ENTERED, onFriendEnteredRoomEvent);
+ const onRoomWidgetUpdateDecorateModeEvent = useCallback((event: RoomWidgetUpdateDecorateModeEvent) =>
+ {
+ setIsDecorating(event.isDecorating);
+ }, []);
+
+ CreateEventDispatcherHook(RoomWidgetUpdateDecorateModeEvent.UPDATE_DECORATE, eventDispatcher, onRoomWidgetUpdateDecorateModeEvent);
+
const decorateView = useMemo(() =>
{
GetRoomSession().isDecorating = isDecorating;
@@ -274,7 +281,7 @@ export const AvatarInfoWidgetView: FC<{}> = props =>
const userName = GetSessionDataManager().userName;
const roomIndex = GetRoomSession().ownRoomIndex;
- return ;
+ return ;
}, [ isDecorating ]);
const currentView = useMemo(() =>
@@ -316,7 +323,7 @@ export const AvatarInfoWidgetView: FC<{}> = props =>
{
if(RoomEnterEffect.isRunning()) return null;
- return ;
+ return ;
}
return ;
diff --git a/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.tsx b/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.tsx
index 5a365394..95b752b0 100644
--- a/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.tsx
+++ b/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.tsx
@@ -1,6 +1,7 @@
import { RoomObjectCategory } from '@nitrots/nitro-renderer';
-import { FC } from 'react';
-import { LocalizeText } from '../../../../../../api';
+import { FC, useCallback } from 'react';
+import { LocalizeText, RoomWidgetUpdateDecorateModeEvent } from '../../../../../../api';
+import { useRoomContext } from '../../../../context/RoomContext';
import { ContextMenuView } from '../../../context-menu/ContextMenuView';
import { ContextMenuListItemView } from '../../../context-menu/views/list-item/ContextMenuListItemView';
import { ContextMenuListView } from '../../../context-menu/views/list/ContextMenuListView';
@@ -8,12 +9,18 @@ import { AvatarInfoWidgetDecorateViewProps } from './AvatarInfoWidgetDecorateVie
export const AvatarInfoWidgetDecorateView: FC = props =>
{
- const { userId = -1, userName = '', roomIndex = -1, setIsDecorating = null } = props;
+ const { userId = -1, userName = '', roomIndex = -1 } = props;
+ const { eventDispatcher = null } = useRoomContext();
+
+ const stopDecorating = useCallback(() =>
+ {
+ eventDispatcher.dispatchEvent(new RoomWidgetUpdateDecorateModeEvent(false));
+ }, [ eventDispatcher ]);
return (
- setIsDecorating(false) }>
+
{ LocalizeText('widget.avatar.stop_decorating') }
diff --git a/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.types.ts b/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.types.ts
index 2440f17a..86c19e35 100644
--- a/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.types.ts
+++ b/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.types.ts
@@ -1,9 +1,7 @@
-import { Dispatch, SetStateAction } from 'react';
export interface AvatarInfoWidgetDecorateViewProps
{
userId: number;
userName: string;
roomIndex: number;
- setIsDecorating: Dispatch>;
}
diff --git a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx
index c5555ec3..1fa8c8e0 100644
--- a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx
+++ b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx
@@ -1,6 +1,6 @@
import { AvatarAction, AvatarExpressionEnum, RoomObjectCategory, UserProfileComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
-import { GetCanStandUp, GetCanUseExpression, GetOwnPosture, HasHabboClub, HasHabboVip, IsRidingHorse, LocalizeText, RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetUserActionMessage } from '../../../../../../api';
+import { GetCanStandUp, GetCanUseExpression, GetOwnPosture, HasHabboClub, HasHabboVip, IsRidingHorse, LocalizeText, RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetUpdateDecorateModeEvent, RoomWidgetUserActionMessage } from '../../../../../../api';
import { AvatarEditorEvent } from '../../../../../../events';
import { dispatchUiEvent, SendMessageHook } from '../../../../../../hooks';
import { CurrencyIcon } from '../../../../../shared/currency-icon/CurrencyIcon';
@@ -18,9 +18,9 @@ const MODE_SIGNS = 4;
export const AvatarInfoWidgetOwnAvatarView: FC = props =>
{
- const { userData = null, isDancing = false, setIsDecorating = null, close = null } = props;
+ const { userData = null, isDancing = false, close = null } = props;
const [ mode, setMode ] = useState((isDancing && HasHabboClub()) ? MODE_CLUB_DANCES : MODE_NORMAL);
- const { roomSession = null, widgetHandler = null } = useRoomContext();
+ const { roomSession = null, eventDispatcher = null, widgetHandler = null } = useRoomContext();
const processAction = useCallback((name: string) =>
{
@@ -40,7 +40,7 @@ export const AvatarInfoWidgetOwnAvatarView: FC
{
diff --git a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.types.ts b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.types.ts
index e462efa6..00db768e 100644
--- a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.types.ts
+++ b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.types.ts
@@ -1,10 +1,8 @@
-import { Dispatch, SetStateAction } from 'react';
import { RoomWidgetUpdateInfostandUserEvent } from '../../../../../../api';
export interface AvatarInfoWidgetOwnAvatarViewProps
{
userData: RoomWidgetUpdateInfostandUserEvent;
isDancing: boolean;
- setIsDecorating: Dispatch>;
close: () => void;
}
diff --git a/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss b/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss
index 9bdbcb6b..9337ed85 100644
--- a/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss
+++ b/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss
@@ -696,7 +696,6 @@
justify-content: center;
height: 100%;
max-height: 24px;
- image-rendering: -webkit-optimize-contrast;
overflow: hidden;
.user-image {
@@ -707,8 +706,9 @@
height: 130px;
background-repeat: no-repeat;
background-position: center;
- transform: scale(0.5) translateZ(0);
+ transform: scale(0.5);
overflow: hidden;
+ image-rendering: -webkit-optimize-contrast;
}
}
diff --git a/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx b/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx
index d7b60d69..33752c8f 100644
--- a/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx
+++ b/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx
@@ -1,36 +1,17 @@
import { RoomObjectOperationType } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
-import { ProcessRoomObjectOperation, RoomWidgetRoomObjectUpdateEvent } from '../../../../../api';
+import { ProcessRoomObjectOperation, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDecorateModeEvent } from '../../../../../api';
+import { BatchUpdates } from '../../../../../hooks';
import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base';
import { useRoomContext } from '../../../context/RoomContext';
import { ObjectLocationView } from '../../object-location/ObjectLocationView';
export const FurnitureManipulationMenuView: FC<{}> = props =>
{
- const { eventDispatcher = null, widgetHandler = null } = useRoomContext();
const [ isVisible, setIsVisible ] = useState(false);
const [ objectId, setObjectId ] = useState(-1);
const [ objectType, setObjectType ] = useState(-1);
-
- const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) =>
- {
- switch(event.type)
- {
- case RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION: {
- setIsVisible(true);
- setObjectId(event.id);
- setObjectType(event.category);
- return;
- }
- case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: {
- return;
- }
- case RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED: {
- setIsVisible(false);
- return;
- }
- }
- }, []);
+ const { roomSession = null, eventDispatcher = null, widgetHandler = null } = useRoomContext();
const rotateFurniture = useCallback(() =>
{
@@ -42,22 +23,87 @@ export const FurnitureManipulationMenuView: FC<{}> = props =>
ProcessRoomObjectOperation(objectId, objectType, RoomObjectOperationType.OBJECT_MOVE);
}, [ objectId, objectType ]);
- useEffect(() =>
+ const pickupFurniture = useCallback(() =>
{
- if(!isVisible) return;
+ ProcessRoomObjectOperation(objectId, objectType, RoomObjectOperationType.OBJECT_PICKUP);
+ }, [ objectId, objectType ]);
- moveFurniture();
- }, [ isVisible, moveFurniture ]);
+ const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) =>
+ {
+ switch(event.type)
+ {
+ case RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION: {
+ BatchUpdates(() =>
+ {
+ setIsVisible(true);
+ setObjectId(event.id);
+ setObjectType(event.category);
+ });
+ return;
+ }
+ case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: {
+ if(event.id === objectId)
+ {
+ BatchUpdates(() =>
+ {
+ setIsVisible(false);
+ setObjectId(-1);
+ setObjectType(-1);
+ });
+ }
+ return;
+ }
+ case RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED: {
+ BatchUpdates(() =>
+ {
+ setIsVisible(false);
+ setObjectId(-1);
+ setObjectType(-1);
+ });
+ return;
+ }
+ }
+ }, [ objectId ]);
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent);
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent);
+ const onRoomWidgetUpdateDecorateModeEvent = useCallback((event: RoomWidgetUpdateDecorateModeEvent) =>
+ {
+ if(event.isDecorating) return;
+
+ moveFurniture();
+
+ BatchUpdates(() =>
+ {
+ setIsVisible(false);
+ setObjectId(-1);
+ setObjectType(-1);
+ });
+ }, [ moveFurniture ]);
+
+ CreateEventDispatcherHook(RoomWidgetUpdateDecorateModeEvent.UPDATE_DECORATE, eventDispatcher, onRoomWidgetUpdateDecorateModeEvent);
+
+ useEffect(() =>
+ {
+ if(!isVisible)
+ {
+ eventDispatcher.dispatchEvent(new RoomWidgetUpdateDecorateModeEvent(false));
+
+ return;
+ }
+
+ eventDispatcher.dispatchEvent(new RoomWidgetUpdateDecorateModeEvent(true));
+
+ moveFurniture();
+ }, [ eventDispatcher, isVisible, moveFurniture ]);
+
if(!isVisible) return null;
return (
-
+
diff --git a/src/views/shared/avatar-image/AvatarImage.scss b/src/views/shared/avatar-image/AvatarImage.scss
index f85ca9c4..07022cae 100644
--- a/src/views/shared/avatar-image/AvatarImage.scss
+++ b/src/views/shared/avatar-image/AvatarImage.scss
@@ -3,7 +3,12 @@
width: 90px;
height: 130px;
background-repeat: no-repeat;
- background-position-x: center;
- background-position-y: -8px !important;
+ background-position: center -8px;
pointer-events: none;
+ image-rendering: pixelated;
+
+ &.scale-0-5,
+ &.scale-0-75 {
+ image-rendering: -webkit-optimize-contrast;
+ }
}
diff --git a/src/views/shared/avatar-image/AvatarImageView.tsx b/src/views/shared/avatar-image/AvatarImageView.tsx
index 5d2a2a33..94ffac65 100644
--- a/src/views/shared/avatar-image/AvatarImageView.tsx
+++ b/src/views/shared/avatar-image/AvatarImageView.tsx
@@ -1,5 +1,5 @@
import { AvatarScaleType, AvatarSetType } from '@nitrots/nitro-renderer';
-import { FC, useEffect, useRef, useState } from 'react';
+import { FC, useEffect, useMemo, useRef, useState } from 'react';
import { GetAvatarRenderManager } from '../../../api';
import { AvatarImageViewProps } from './AvatarImageView.types';
@@ -10,6 +10,19 @@ export const AvatarImageView: FC = props =>
const [ randomValue, setRandomValue ] = useState(-1);
const isDisposed = useRef(false);
+ const getScaleStyle = useMemo(() =>
+ {
+ if(scale === .5) return '0-5';
+
+ if(scale === .75) return '0-75';
+
+ if(scale === 1.25) return '1-25';
+
+ if(scale === 1.50) return '1-50';
+
+ return scale.toString();
+ }, [ scale ]);
+
useEffect(() =>
{
const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, gender, {
@@ -50,5 +63,5 @@ export const AvatarImageView: FC = props =>
const url = `url('${ avatarUrl }')`;
- return ;
+ return ;
}
diff --git a/src/views/shared/badge-image/BadgeImage.scss b/src/views/shared/badge-image/BadgeImage.scss
index d7067045..b08e2de8 100644
--- a/src/views/shared/badge-image/BadgeImage.scss
+++ b/src/views/shared/badge-image/BadgeImage.scss
@@ -1,7 +1,7 @@
.badge-image {
position: relative;
- width: 100%;
- height: 100%;
+ width: 45px;
+ height: 45px;
background-repeat: no-repeat;
background-position: center;
diff --git a/src/views/shared/room-previewer/RoomPreviewerView.scss b/src/views/shared/room-previewer/RoomPreviewerView.scss
index 55328299..e6192624 100644
--- a/src/views/shared/room-previewer/RoomPreviewerView.scss
+++ b/src/views/shared/room-previewer/RoomPreviewerView.scss
@@ -12,7 +12,6 @@
background-color: $light;
background-repeat: no-repeat;
background-position: center;
- image-rendering: auto;
&.border-0 {
&::after {
diff --git a/src/views/shared/room-previewer/RoomPreviewerView.tsx b/src/views/shared/room-previewer/RoomPreviewerView.tsx
index d30bdb54..4691fd45 100644
--- a/src/views/shared/room-previewer/RoomPreviewerView.tsx
+++ b/src/views/shared/room-previewer/RoomPreviewerView.tsx
@@ -6,9 +6,7 @@ import { RoomPreviewerViewProps } from './RoomPreviewerView.types';
export const RoomPreviewerView: FC = props =>
{
const { roomPreviewer = null, height = 0 } = props;
-
const [ renderingCanvas, setRenderingCanvas ] = useState(null);
-
const elementRef = useRef();
const update = useCallback((time: number) =>
@@ -41,9 +39,6 @@ export const RoomPreviewerView: FC = props =>
const canvas = roomPreviewer.getRenderingCanvas();
- elementRef.current.style.width = `${ width }px`;
- elementRef.current.style.height = `${ height }px`;
-
setRenderingCanvas(canvas);
canvas.canvasUpdated = true;
@@ -59,34 +54,31 @@ export const RoomPreviewerView: FC = props =>
GetNitroInstance().ticker.add(update);
- function resize(): void
- {
- if(!roomPreviewer) return;
+ const resizeObserver = new ResizeObserver(() =>
+ {
+ if(!roomPreviewer || !elementRef.current) return;
- const width = elementRef.current.parentElement.offsetWidth;
+ const width = elementRef.current.parentElement.offsetWidth;
- elementRef.current.style.width = `${ width }px`;
- elementRef.current.style.height = `${ height }px`;
+ roomPreviewer.modifyRoomCanvas(width, height);
- roomPreviewer.modifyRoomCanvas(width, height);
-
- update(-1);
- }
-
- window.addEventListener('resize', resize);
+ update(-1);
+ });
+
+ resizeObserver.observe(elementRef.current);
return () =>
{
- GetNitroInstance().ticker.remove(update);
+ resizeObserver.disconnect();
- window.removeEventListener('resize', resize);
+ GetNitroInstance().ticker.remove(update);
}
}, [ renderingCanvas, roomPreviewer, elementRef, height, setupPreviewer, update ]);
return (
);
diff --git a/src/views/toolbar/ToolbarView.scss b/src/views/toolbar/ToolbarView.scss
index 44abb043..57401e81 100644
--- a/src/views/toolbar/ToolbarView.scss
+++ b/src/views/toolbar/ToolbarView.scss
@@ -29,31 +29,28 @@
align-items: center;
justify-content: center;
cursor: pointer;
- width: 50px;
- margin: 0 1px;
+ //margin: 0 1px;
position: relative;
- .toolbar-avatar {
- height: 50px;
+ &.item-avatar {
+ width: 50px;
+ height: 45px;
+ overflow: hidden;
.avatar-image {
margin-left: -5px;
- margin-top: -30px;
- }
-
- &:hover, &.active {
- height: 53px;
+ margin-top: 25px;
}
}
.icon,
- .toolbar-avatar {
+ &.item-avatar {
position: relative;
- transition: transform .2s ease-out;
+ //transition: transform .2s ease-out;
&:hover, &.active {
- -webkit-transform: translate(0, -3px);
- transform: translate(0, -3px);
+ -webkit-transform: translate(-1px, -1px);
+ transform: translate(-1px, -1px);
filter: drop-shadow(2px 2px 0 rgba($black, 0.8));
}
}
@@ -68,7 +65,7 @@
.count {
top: 0rem;
- right: 5px;
+ right: 2px;
font-size: 10px;
}
}
diff --git a/src/views/toolbar/ToolbarView.tsx b/src/views/toolbar/ToolbarView.tsx
index 74b22062..3dcd3322 100644
--- a/src/views/toolbar/ToolbarView.tsx
+++ b/src/views/toolbar/ToolbarView.tsx
@@ -1,7 +1,7 @@
import { Dispose, DropBounce, EaseOut, FigureUpdateEvent, JumpBy, Motions, NitroToolbarAnimateIconEvent, Queue, UserInfoDataParser, UserInfoEvent, UserProfileComposer, Wait } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
-import { GetRoomSession, GetRoomSessionManager, GetSessionDataManager, GoToDesktop } from '../../api';
-import { AvatarEditorEvent, CatalogEvent, FriendListEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events';
+import { GetRoomSession, GetRoomSessionManager, GetSessionDataManager, GoToDesktop, OpenMessengerChat } from '../../api';
+import { AvatarEditorEvent, CatalogEvent, FriendsEvent, FriendsMessengerIconEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events';
import { AchievementsUIEvent } from '../../events/achievements';
import { UnseenItemTrackerUpdateEvent } from '../../events/inventory/UnseenItemTrackerUpdateEvent';
import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent';
@@ -14,6 +14,10 @@ import { AvatarImageView } from '../shared/avatar-image/AvatarImageView';
import { ToolbarMeView } from './me/ToolbarMeView';
import { ToolbarViewItems, ToolbarViewProps } from './ToolbarView.types';
+const CHAT_ICON_HIDDEN: number = 0;
+const CHAT_ICON_SHOWING: number = 1;
+const CHAT_ICON_UNREAD: number = 2;
+
export const ToolbarView: FC = props =>
{
const { isInRoom } = props;
@@ -21,6 +25,7 @@ export const ToolbarView: FC = props =>
const [ userInfo, setUserInfo ] = useState(null);
const [ userFigure, setUserFigure ] = useState(null);
const [ isMeExpanded, setMeExpanded ] = useState(false);
+ const [ chatIconType, setChatIconType ] = useState(CHAT_ICON_HIDDEN);
const [ unseenInventoryCount, setUnseenInventoryCount ] = useState(0);
const unseenFriendListCount = 0;
@@ -45,6 +50,13 @@ export const ToolbarView: FC = props =>
CreateMessageHook(FigureUpdateEvent, onUserFigureEvent);
+ const onFriendsMessengerIconEvent = useCallback((event: FriendsMessengerIconEvent) =>
+ {
+ setChatIconType(event.iconType);
+ }, []);
+
+ useUiEvent(FriendsMessengerIconEvent.UPDATE_ICON, onFriendsMessengerIconEvent);
+
const onUnseenItemTrackerUpdateEvent = useCallback((event: UnseenItemTrackerUpdateEvent) =>
{
setUnseenInventoryCount(event.count);
@@ -107,7 +119,7 @@ export const ToolbarView: FC = props =>
dispatchUiEvent(new CatalogEvent(CatalogEvent.TOGGLE_CATALOG));
return;
case ToolbarViewItems.FRIEND_LIST_ITEM:
- dispatchUiEvent(new CatalogEvent(FriendListEvent.TOGGLE_FRIEND_LIST));
+ dispatchUiEvent(new CatalogEvent(FriendsEvent.TOGGLE_FRIEND_LIST));
return;
case ToolbarViewItems.CAMERA_ITEM:
dispatchUiEvent(new RoomWidgetCameraEvent(RoomWidgetCameraEvent.TOGGLE_CAMERA));
@@ -131,6 +143,9 @@ export const ToolbarView: FC = props =>
dispatchUiEvent(new UserSettingsUIEvent(UserSettingsUIEvent.TOGGLE_USER_SETTINGS));
setMeExpanded(false);
return;
+ case ToolbarViewItems.FRIEND_CHAT_ITEM:
+ OpenMessengerChat();
+ return;
}
}, []);
@@ -143,25 +158,21 @@ export const ToolbarView: FC = props =>
}, []);
return (
-
+
-
-
-
-
setMeExpanded(!isMeExpanded) }>
-
-
+
+
+
setMeExpanded(!isMeExpanded) }>
+
+ { (unseenAchievementsCount > 0) &&
+
{ unseenAchievementsCount }
}
- { (unseenAchievementsCount > 0) && (
-
{ unseenAchievementsCount }
) }
-
-
{ isInRoom && (
-
+
) }
{ !isInRoom && (
@@ -188,13 +199,20 @@ export const ToolbarView: FC = props =>
-
-
+
+
handleToolbarItemClick(ToolbarViewItems.FRIEND_LIST_ITEM) }>
{ (unseenFriendListCount > 0) && (
{ unseenFriendListCount }
) }
+ { ((chatIconType === CHAT_ICON_SHOWING) || (chatIconType === CHAT_ICON_UNREAD)) &&
+
handleToolbarItemClick(ToolbarViewItems.FRIEND_CHAT_ITEM) }>
+ { (chatIconType === CHAT_ICON_SHOWING) &&
}
+ { (chatIconType === CHAT_ICON_UNREAD) &&
}
+ { (unseenFriendListCount > 0) &&
+
{ unseenFriendListCount }
}
+
}
diff --git a/src/views/toolbar/ToolbarView.types.ts b/src/views/toolbar/ToolbarView.types.ts
index 0670bca7..48a376d1 100644
--- a/src/views/toolbar/ToolbarView.types.ts
+++ b/src/views/toolbar/ToolbarView.types.ts
@@ -9,6 +9,7 @@ export class ToolbarViewItems
public static INVENTORY_ITEM: string = 'TVI_INVENTORY_ITEM';
public static CATALOG_ITEM: string = 'TVI_CATALOG_ITEM';
public static FRIEND_LIST_ITEM: string = 'TVI_FRIEND_LIST_ITEM';
+ public static FRIEND_CHAT_ITEM: string = 'TVI_FRIEND_CHAT_ITEM';
public static CLOTHING_ITEM: string = 'TVI_CLOTHING_ITEM';
public static CAMERA_ITEM: string = 'TVI_CAMERA_ITEM';
public static MOD_TOOLS_ITEM: string = 'TVI_MOD_TOOLS_ITEM';
diff --git a/src/views/user-profile/views/badges-container/BadgesContainerView.tsx b/src/views/user-profile/views/badges-container/BadgesContainerView.tsx
index cba4e091..13e84199 100644
--- a/src/views/user-profile/views/badges-container/BadgesContainerView.tsx
+++ b/src/views/user-profile/views/badges-container/BadgesContainerView.tsx
@@ -1,4 +1,5 @@
import { FC } from 'react';
+import { NitroCardGridItemView, NitroCardGridView } from '../../../../layout';
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
import { BadgesContainerViewProps } from './BadgesContainerView.types';
@@ -7,21 +8,36 @@ export const BadgesContainerView: FC
= props =>
const { badges = null } = props;
return (
-
-
-
- {
- badges.map( (badge, index) =>
-{
- return (
-
-
-
- )
- })
- }
-
-
+
+
+ { badges && (badges.length > 0) && badges.map((badge, index) =>
+ {
+ return (
+
+
+
+ )
+ }) }
+
- );
+ )
+
+// return (
+//
+//
+//
+// {
+// badges.map( (badge, index) =>
+// {
+// return (
+//
+//
+//
+// )
+// })
+// }
+//
+//
+//
+// );
}
diff --git a/tsconfig.json b/tsconfig.json
index df4dcf04..ac2a9fd7 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -24,6 +24,6 @@
},
"include": [
"src",
- "node_modules/@nitrots/nitro-renderer/**/*.ts",
+ "node_modules/@nitrots/nitro-renderer/src/**/*.ts",
]
}