diff --git a/public/ui-config.json.example b/public/ui-config.json.example
index 70135a75..9f648474 100644
--- a/public/ui-config.json.example
+++ b/public/ui-config.json.example
@@ -8,6 +8,7 @@
"habbopages.url": "https://website.com/habbopages/",
"chat.viewer.height.percentage": 0.40,
"widget.dimmer.colorwheel": false,
+ "avatar.wardrobe.max.slots": 10,
"hotelview": {
"widgets": {
"slot.1.widget": "promoarticle",
diff --git a/src/App.scss b/src/App.scss
index f7e61f8e..7dc98e83 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -70,6 +70,7 @@ $camera-checkout-width: 350px;
$room-info-width: 325px;
$nitro-group-creator-width: 383px;
+$nitro-mod-tools-width: 175px;
.nitro-app {
width: 100%;
diff --git a/src/App.tsx b/src/App.tsx
index f1fb127b..cbc78aac 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,13 +1,14 @@
import { ConfigurationEvent, HabboWebTools, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, NitroVersion, RoomEngineEvent, WebGL } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { GetCommunication, GetConfiguration, GetNitroInstance } from './api';
+import { Base } from './common';
+import { LoadingView } from './components/loading/LoadingView';
+import { MainView } from './components/main/MainView';
import { useConfigurationEvent } from './hooks/events/core/configuration/configuration-event';
import { useLocalizationEvent } from './hooks/events/nitro/localization/localization-event';
import { dispatchMainEvent, useMainEvent } from './hooks/events/nitro/main-event';
import { useRoomEngineEvent } from './hooks/events/nitro/room/room-engine-event';
import { TransitionAnimation, TransitionAnimationTypes } from './layout';
-import { LoadingView } from './views/loading/LoadingView';
-import { MainView } from './views/main/MainView';
export const App: FC<{}> = props =>
{
@@ -127,12 +128,13 @@ export const App: FC<{}> = props =>
}
return (
-
- { (!isReady || isError) &&
}
+
+ { (!isReady || isError) &&
+
}
-
-
+
+
);
}
diff --git a/src/assets/styles/bootstrap/_buttons.scss b/src/assets/styles/bootstrap/_buttons.scss
index ee4287c9..3c2cba9c 100644
--- a/src/assets/styles/bootstrap/_buttons.scss
+++ b/src/assets/styles/bootstrap/_buttons.scss
@@ -79,6 +79,11 @@
font-weight: $font-weight-normal;
color: $btn-link-color;
text-decoration: $link-decoration;
+ box-shadow: none !important;
+
+ &:active {
+ color: $btn-link-color !important;
+ }
&:hover {
color: $btn-link-hover-color;
diff --git a/src/assets/styles/bootstrap/_variables.scss b/src/assets/styles/bootstrap/_variables.scss
index 6062e840..1fe7c21c 100644
--- a/src/assets/styles/bootstrap/_variables.scss
+++ b/src/assets/styles/bootstrap/_variables.scss
@@ -732,7 +732,7 @@ $table-cell-padding-x-sm: .25rem !default;
$table-cell-vertical-align: top !default;
-$table-color: $body-color !default;
+$table-color: $black !default;
$table-bg: transparent !default;
$table-accent-bg: transparent !default;
diff --git a/src/assets/styles/utils.scss b/src/assets/styles/utils.scss
index c22e7cd2..029f054e 100644
--- a/src/assets/styles/utils.scss
+++ b/src/assets/styles/utils.scss
@@ -90,3 +90,10 @@ ul {
.flex-basis-max-content {
flex-basis: max-content;
}
+
+.striped-children {
+
+ > :nth-child(1) {
+ background-color: $table-striped-bg;
+ }
+}
diff --git a/src/common/Base.tsx b/src/common/Base.tsx
index 630f5417..f5fd00fe 100644
--- a/src/common/Base.tsx
+++ b/src/common/Base.tsx
@@ -1,5 +1,5 @@
import { CSSProperties, DetailedHTMLProps, FC, HTMLAttributes, LegacyRef, useMemo } from 'react';
-import { ColorVariantType, OverflowType, PositionType } from './types';
+import { ColorVariantType, FloatType, OverflowType, PositionType } from './types';
export interface BaseProps extends DetailedHTMLProps, T>
{
@@ -11,6 +11,7 @@ export interface BaseProps extends DetailedHTMLProps extends DetailedHTMLProps> = props =>
{
- const { ref = null, innerRef = null, fit = false, grow = false, shrink = false, fullWidth = false, fullHeight = false, overflow = null, position = null, pointer = false, textColor = null, classNames = [], className = '', style = {}, ...rest } = props;
+ const { ref = null, innerRef = null, fit = false, grow = false, shrink = false, fullWidth = false, fullHeight = false, overflow = null, position = null, float = null, pointer = false, textColor = null, classNames = [], className = '', style = {}, ...rest } = props;
const getClassNames = useMemo(() =>
{
@@ -36,6 +37,8 @@ export const Base: FC> = props =>
if(position) newClassNames.push('position-' + position);
+ if(float) newClassNames.push('float-' + float);
+
if(pointer) newClassNames.push('cursor-pointer');
if(textColor) newClassNames.push('text-' + textColor);
@@ -43,7 +46,7 @@ export const Base: FC> = props =>
if(classNames.length) newClassNames.push(...classNames);
return newClassNames;
- }, [ fit, grow, shrink, fullWidth, fullHeight, overflow, position, pointer, textColor, classNames ]);
+ }, [ fit, grow, shrink, fullWidth, fullHeight, overflow, position, float, pointer, textColor, classNames ]);
const getClassName = useMemo(() =>
{
@@ -51,7 +54,7 @@ export const Base: FC> = props =>
if(className.length) newClassName += (' ' + className);
- return newClassName;
+ return newClassName.trim();
}, [ getClassNames, className ]);
const getStyle = useMemo(() =>
diff --git a/src/common/Grid.tsx b/src/common/Grid.tsx
index 504a48d1..ed59d47a 100644
--- a/src/common/Grid.tsx
+++ b/src/common/Grid.tsx
@@ -2,7 +2,7 @@ import { FC, useMemo } from 'react';
import { CSSProperties } from 'styled-components';
import { Base, BaseProps } from './Base';
import { GridContextProvider } from './GridContext';
-import { SpacingType } from './types';
+import { AlignItemType, AlignSelfType, JustifyContentType, SpacingType } from './types';
export interface GridProps extends BaseProps
{
@@ -10,11 +10,15 @@ export interface GridProps extends BaseProps
gap?: SpacingType;
maxContent?: boolean;
columnCount?: number;
+ center?: boolean;
+ alignSelf?: AlignSelfType;
+ alignItems?: AlignItemType;
+ justifyContent?: JustifyContentType;
}
export const Grid: FC = props =>
{
- const { inline = false, gap = 2, maxContent = false, columnCount = 0, fullHeight = true, classNames = [], style = {}, ...rest } = props;
+ const { inline = false, gap = 2, maxContent = false, columnCount = 0, center = false, alignSelf = null, alignItems = null, justifyContent = null, fullHeight = true, classNames = [], style = {}, ...rest } = props;
const getClassNames = useMemo(() =>
{
@@ -28,10 +32,18 @@ export const Grid: FC = props =>
if(maxContent) newClassNames.push('flex-basis-max-content');
+ if(alignSelf) newClassNames.push('align-self-' + alignSelf);
+
+ if(alignItems) newClassNames.push('align-items-' + alignItems);
+
+ if(justifyContent) newClassNames.push('justify-content-' + justifyContent);
+
+ if(!alignItems && !justifyContent && center) newClassNames.push('align-items-center', 'justify-content-center');
+
if(classNames.length) newClassNames.push(...classNames);
return newClassNames;
- }, [ inline, gap, maxContent, classNames ]);
+ }, [ inline, gap, maxContent, alignSelf, alignItems, justifyContent, center, classNames ]);
const getStyle = useMemo(() =>
{
diff --git a/src/common/Text.tsx b/src/common/Text.tsx
index d81b5f76..62cd91ce 100644
--- a/src/common/Text.tsx
+++ b/src/common/Text.tsx
@@ -1,12 +1,13 @@
import { FC, useMemo } from 'react';
import { Base, BaseProps } from './Base';
-import { ColorVariantType, FontSizeType, FontWeightType } from './types';
+import { ColorVariantType, FontSizeType, FontWeightType, TextAlignType } from './types';
export interface TextProps extends BaseProps
{
variant?: ColorVariantType;
fontWeight?: FontWeightType;
fontSize?: FontSizeType;
+ align?: TextAlignType;
bold?: boolean;
underline?: boolean;
italics?: boolean;
@@ -14,11 +15,14 @@ export interface TextProps extends BaseProps
center?: boolean;
textEnd?: boolean;
small?: boolean;
+ wrap?: boolean;
+ noWrap?: boolean;
+ textBreak?: boolean;
}
export const Text: FC = props =>
{
- const { variant = 'black', fontWeight = null, fontSize = 0, bold = false, underline = false, italics = false, truncate = false, center = false, textEnd = false, small = false, ...rest } = props;
+ const { variant = 'black', fontWeight = null, fontSize = 0, align = null, bold = false, underline = false, italics = false, truncate = false, center = false, textEnd = false, small = false, wrap = false, noWrap = false, textBreak = false, ...rest } = props;
const getClassNames = useMemo(() =>
{
@@ -32,6 +36,8 @@ export const Text: FC = props =>
if(fontSize) newClassNames.push('fs-' + fontSize);
+ if(align) newClassNames.push('text-' + align);
+
if(underline) newClassNames.push('text-decoration-underline');
if(italics) newClassNames.push('fst-italic');
@@ -44,8 +50,14 @@ export const Text: FC = props =>
if(small) newClassNames.push('small');
+ if(wrap) newClassNames.push('text-wrap');
+
+ if(noWrap) newClassNames.push('text-nowrap');
+
+ if(textBreak) newClassNames.push('text-break');
+
return newClassNames;
- }, [ variant, fontWeight, fontSize, bold, underline, italics, truncate, center, textEnd, small ]);
+ }, [ variant, fontWeight, fontSize, align, bold, underline, italics, truncate, center, textEnd, small, wrap, noWrap, textBreak ]);
return ;
}
diff --git a/src/common/index.scss b/src/common/index.scss
index be5d045f..cc85242b 100644
--- a/src/common/index.scss
+++ b/src/common/index.scss
@@ -6,7 +6,7 @@
&.active {
border-color: $grid-active-border-color !important;
- background-color: $grid-active-bg-color !important;
+ background-color: $grid-active-bg-color;
}
&.disabled {
@@ -25,4 +25,19 @@
.avatar-image {
background-position-y: -35px;
}
+
+ &.has-highlight {
+
+ &:after {
+ content: "";
+ z-index: 2;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 50%;
+ background-color: $white;
+ opacity: 0.1;
+ }
+ }
}
diff --git a/src/common/layout/LayoutGridItem.tsx b/src/common/layout/LayoutGridItem.tsx
index 07a081c2..531ac483 100644
--- a/src/common/layout/LayoutGridItem.tsx
+++ b/src/common/layout/LayoutGridItem.tsx
@@ -14,12 +14,13 @@ export interface LayoutGridItemProps extends ColumnProps
itemUniqueSoldout?: boolean;
itemUniqueNumber?: number;
itemUnseen?: boolean;
+ itemHighlight?: boolean;
disabled?: boolean;
}
export const LayoutGridItem: FC = props =>
{
- const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemCountMinimum = 1, itemUniqueSoldout = false, itemUniqueNumber = -2, itemUnseen = false, disabled = false, center = true, column = true, style = {}, classNames = [], position = 'relative', overflow = 'hidden', children = null, ...rest } = props;
+ const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemCountMinimum = 1, itemUniqueSoldout = false, itemUniqueNumber = -2, itemUnseen = false, itemHighlight = false, disabled = false, center = true, column = true, style = {}, classNames = [], position = 'relative', overflow = 'hidden', children = null, ...rest } = props;
const getClassNames = useMemo(() =>
{
@@ -33,6 +34,8 @@ export const LayoutGridItem: FC = props =>
if(itemUnseen) newClassNames.push('unseen');
+ if(itemHighlight) newClassNames.push('has-highlight');
+
if(disabled) newClassNames.push('disabled')
if(itemImage === null) newClassNames.push('icon', 'loading-icon');
@@ -40,7 +43,7 @@ export const LayoutGridItem: FC = props =>
if(classNames.length) newClassNames.push(...classNames);
return newClassNames;
- }, [ itemActive, itemUniqueSoldout, itemUniqueNumber, itemUnseen, disabled, itemImage, classNames ]);
+ }, [ itemActive, itemUniqueSoldout, itemUniqueNumber, itemUnseen, itemHighlight, disabled, itemImage, classNames ]);
const getStyle = useMemo(() =>
{
diff --git a/src/common/types/FloatType.ts b/src/common/types/FloatType.ts
new file mode 100644
index 00000000..63e495fe
--- /dev/null
+++ b/src/common/types/FloatType.ts
@@ -0,0 +1 @@
+export type FloatType = 'start' | 'end' | 'none';
diff --git a/src/common/types/FontSizeType.ts b/src/common/types/FontSizeType.ts
index a6b28c93..120c11c9 100644
--- a/src/common/types/FontSizeType.ts
+++ b/src/common/types/FontSizeType.ts
@@ -1 +1 @@
-export type FontSizeType = 1 | 2 | 3 | 4 | 5;
+export type FontSizeType = 1 | 2 | 3 | 4 | 5 | 6;
diff --git a/src/common/types/TextAlignType.ts b/src/common/types/TextAlignType.ts
new file mode 100644
index 00000000..cb826480
--- /dev/null
+++ b/src/common/types/TextAlignType.ts
@@ -0,0 +1 @@
+export type TextAlignType = 'start' | 'center' | 'end';
diff --git a/src/common/types/index.ts b/src/common/types/index.ts
index 011ab11e..9fcf00b4 100644
--- a/src/common/types/index.ts
+++ b/src/common/types/index.ts
@@ -3,9 +3,11 @@ export * from './AlignSelfType';
export * from './ButtonSizeType';
export * from './ColorVariantType';
export * from './ColumnSizesType';
+export * from './FloatType';
export * from './FontSizeType';
export * from './FontWeightType';
export * from './JustifyContentType';
export * from './OverflowType';
export * from './PositionType';
export * from './SpacingType';
+export * from './TextAlignType';
diff --git a/src/components/avatar-editor/AvatarEditorView.tsx b/src/components/avatar-editor/AvatarEditorView.tsx
index a0cb113e..55d8479f 100644
--- a/src/components/avatar-editor/AvatarEditorView.tsx
+++ b/src/components/avatar-editor/AvatarEditorView.tsx
@@ -1,7 +1,7 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { AvatarEditorFigureCategory, FigureSetIdsMessageEvent, GetWardrobeMessageComposer, IAvatarFigureContainer, UserFigureComposer, UserWardrobePageEvent } from '@nitrots/nitro-renderer';
-import { FC, useCallback, useEffect, useState } from 'react';
-import { GetAvatarRenderManager, GetClubMemberLevel, GetSessionDataManager, LocalizeText } from '../../api';
+import { FC, useCallback, useEffect, useMemo, useState } from 'react';
+import { GetAvatarRenderManager, GetClubMemberLevel, GetConfiguration, GetSessionDataManager, LocalizeText } from '../../api';
import { Button } from '../../common/Button';
import { ButtonGroup } from '../../common/ButtonGroup';
import { Column } from '../../common/Column';
@@ -25,7 +25,6 @@ import { AvatarEditorWardrobeView } from './views/wardrobe/AvatarEditorWardrobeV
const DEFAULT_MALE_FIGURE: string = 'hr-100.hd-180-7.ch-215-66.lg-270-79.sh-305-62.ha-1002-70.wa-2007';
const DEFAULT_FEMALE_FIGURE: string = 'hr-515-33.hd-600-1.ch-635-70.lg-716-66-62.sh-735-68';
-const MAX_SAVED_FIGURES: number = 10;
export const AvatarEditorView: FC<{}> = props =>
{
@@ -36,13 +35,15 @@ export const AvatarEditorView: FC<{}> = props =>
const [ activeCategory, setActiveCategory ] = useState(null);
const [ figureSetIds, setFigureSetIds ] = useState([]);
const [ boundFurnitureNames, setBoundFurnitureNames ] = useState([]);
- const [ savedFigures, setSavedFigures ] = useState<[ IAvatarFigureContainer, string ][]>(new Array(MAX_SAVED_FIGURES));
+ const [ savedFigures, setSavedFigures ] = useState<[ IAvatarFigureContainer, string ][]>([]);
const [ isWardrobeVisible, setIsWardrobeVisible ] = useState(false);
const [ lastFigure, setLastFigure ] = useState(null);
const [ lastGender, setLastGender ] = useState(null);
const [ needsReset, setNeedsReset ] = useState(false);
const [ isInitalized, setIsInitalized ] = useState(false);
+ const maxWardrobeSlots = useMemo(() => GetConfiguration('avatar.wardrobe.max.slots', 10), []);
+
const onAvatarEditorEvent = useCallback((event: AvatarEditorEvent) =>
{
switch(event.type)
@@ -88,7 +89,7 @@ export const AvatarEditorView: FC<{}> = props =>
let i = 0;
- while(i < MAX_SAVED_FIGURES)
+ while(i < maxWardrobeSlots)
{
savedFigures.push([ null, null ]);
@@ -103,7 +104,7 @@ export const AvatarEditorView: FC<{}> = props =>
}
setSavedFigures(savedFigures)
- }, []);
+ }, [ maxWardrobeSlots ]);
CreateMessageHook(UserWardrobePageEvent, onUserWardrobePageEvent);
@@ -194,6 +195,11 @@ export const AvatarEditorView: FC<{}> = props =>
setFigureData(figures.get(gender));
}, [ figures ]);
+ useEffect(() =>
+ {
+ setSavedFigures(new Array(maxWardrobeSlots));
+ }, [ maxWardrobeSlots ]);
+
useEffect(() =>
{
if(!isWardrobeVisible) return;
diff --git a/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetItemView.tsx b/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetItemView.tsx
index dd45397a..0e01ee28 100644
--- a/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetItemView.tsx
+++ b/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetItemView.tsx
@@ -26,7 +26,7 @@ export const AvatarEditorPaletteSetItem: FC = p
});
return (
-
+
{ colorItem.isHC && }
{ children }
diff --git a/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx b/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx
index 377ac8c6..6b715127 100644
--- a/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx
+++ b/src/components/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx
@@ -27,7 +27,7 @@ export const AvatarEditorPaletteSetView: FC = p
}, [ model, category, paletteSet, paletteIndex ]);
return (
-
+
{ (paletteSet.length > 0) && paletteSet.map((item, index) =>
selectColor(item) } />) }
diff --git a/src/components/catalog/CatalogView.scss b/src/components/catalog/CatalogView.scss
index e95ec83b..039460be 100644
--- a/src/components/catalog/CatalogView.scss
+++ b/src/components/catalog/CatalogView.scss
@@ -44,7 +44,6 @@
}
.nitro-catalog-navigation-grid-container {
- border-radius: 0.25rem;
border-color: #B6BEC5 !important;
background-color: #CDD3D9;
border: 2px solid;
diff --git a/src/components/catalog/views/navigation/CatalogNavigationView.tsx b/src/components/catalog/views/navigation/CatalogNavigationView.tsx
index 685f2d73..7f8ef439 100644
--- a/src/components/catalog/views/navigation/CatalogNavigationView.tsx
+++ b/src/components/catalog/views/navigation/CatalogNavigationView.tsx
@@ -20,7 +20,7 @@ export const CatalogNavigationView: FC = props =>
return (
<>
-
+
{ searchResult && (searchResult.filteredNodes.length > 0) && searchResult.filteredNodes.map((n, index) =>
{
diff --git a/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx b/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx
index 01616a57..ef613c85 100644
--- a/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx
+++ b/src/components/catalog/views/page/layout/CatalogLayoutVipBuyView.tsx
@@ -13,9 +13,9 @@ import { CatalogEvent } from '../../../../../events/catalog/CatalogEvent';
import { useUiEvent } from '../../../../../hooks';
import { SendMessageHook } from '../../../../../hooks/messages/message-event';
import { LoadingSpinnerView } from '../../../../../layout/loading-spinner/LoadingSpinnerView';
-import { GetCurrencyAmount } from '../../../../../views/purse/common/CurrencyHelper';
-import { GLOBAL_PURSE } from '../../../../../views/purse/PurseView';
import { CurrencyIcon } from '../../../../../views/shared/currency-icon/CurrencyIcon';
+import { GetCurrencyAmount } from '../../../../purse/common/CurrencyHelper';
+import { GLOBAL_PURSE } from '../../../../purse/PurseView';
import { useCatalogContext } from '../../../CatalogContext';
import { CatalogPurchaseState } from '../../../common/CatalogPurchaseState';
import { CatalogLayoutProps } from './CatalogLayout.types';
diff --git a/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplacePublicItemsView.tsx b/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplacePublicItemsView.tsx
index 2ad20abb..4a4f4fb9 100644
--- a/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplacePublicItemsView.tsx
+++ b/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplacePublicItemsView.tsx
@@ -9,7 +9,7 @@ import { Text } from '../../../../../../common/Text';
import { BatchUpdates, CreateMessageHook, SendMessageHook } from '../../../../../../hooks';
import { NotificationAlertType } from '../../../../../../views/notification-center/common/NotificationAlertType';
import { NotificationUtilities } from '../../../../../../views/notification-center/common/NotificationUtilities';
-import { GetCurrencyAmount } from '../../../../../../views/purse/common/CurrencyHelper';
+import { GetCurrencyAmount } from '../../../../../purse/common/CurrencyHelper';
import { CatalogLayoutProps } from '../CatalogLayout.types';
import { CatalogLayoutMarketplaceItemView, PUBLIC_OFFER } from './CatalogLayoutMarketplaceItemView';
import { SearchFormView } from './CatalogLayoutMarketplaceSearchFormView';
diff --git a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx
index a9d4280a..9b05d88f 100644
--- a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx
+++ b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx
@@ -8,7 +8,7 @@ import { CatalogInitPurchaseEvent } from '../../../../../events/catalog/CatalogI
import { CatalogWidgetEvent } from '../../../../../events/catalog/CatalogWidgetEvent';
import { dispatchUiEvent, SendMessageHook, useUiEvent } from '../../../../../hooks';
import { LoadingSpinnerView } from '../../../../../layout';
-import { GetCurrencyAmount } from '../../../../../views/purse/common/CurrencyHelper';
+import { GetCurrencyAmount } from '../../../../purse/common/CurrencyHelper';
import { useCatalogContext } from '../../../CatalogContext';
import { CatalogPurchaseState } from '../../../common/CatalogPurchaseState';
import { Offer } from '../../../common/Offer';
diff --git a/src/components/chat-history/ChatHistoryContext.tsx b/src/components/chat-history/ChatHistoryContext.tsx
new file mode 100644
index 00000000..086fcfe5
--- /dev/null
+++ b/src/components/chat-history/ChatHistoryContext.tsx
@@ -0,0 +1,21 @@
+import { createContext, FC, ProviderProps, useContext } from 'react';
+import { IChatHistoryState } from './common/IChatHistoryState';
+import { IRoomHistoryState } from './common/IRoomHistoryState';
+
+export interface IChatHistoryContext
+{
+ chatHistoryState: IChatHistoryState;
+ roomHistoryState: IRoomHistoryState;
+}
+
+const ChatHistoryContext = createContext({
+ chatHistoryState: null,
+ roomHistoryState: null
+});
+
+export const ChatHistoryContextProvider: FC> = props =>
+{
+ return { props.children }
+}
+
+export const useChatHistoryContext = () => useContext(ChatHistoryContext);
diff --git a/src/views/chat-history/ChatHistoryMessageHandler.tsx b/src/components/chat-history/ChatHistoryMessageHandler.tsx
similarity index 91%
rename from src/views/chat-history/ChatHistoryMessageHandler.tsx
rename to src/components/chat-history/ChatHistoryMessageHandler.tsx
index a482a36a..89d38a12 100644
--- a/src/views/chat-history/ChatHistoryMessageHandler.tsx
+++ b/src/components/chat-history/ChatHistoryMessageHandler.tsx
@@ -2,9 +2,14 @@ import { GetGuestRoomResultEvent, RoomSessionChatEvent, RoomSessionEvent } from
import { FC, useCallback, useState } from 'react';
import { GetRoomSession } from '../../api';
import { CreateMessageHook, useRoomSessionManagerEvent } from '../../hooks';
-import { useChatHistoryContext } from './context/ChatHistoryContext';
-import { ChatEntryType, CHAT_HISTORY_MAX, IChatEntry, IRoomHistoryEntry, ROOM_HISTORY_MAX } from './context/ChatHistoryContext.types';
-import { currentDate } from './utils/Utilities';
+import { useChatHistoryContext } from './ChatHistoryContext';
+import { ChatEntryType } from './common/ChatEntryType';
+import { IChatEntry } from './common/IChatEntry';
+import { IRoomHistoryEntry } from './common/IRoomHistoryEntry';
+import { currentDate } from './common/Utilities';
+
+const CHAT_HISTORY_MAX = 1000;
+const ROOM_HISTORY_MAX = 10;
export const ChatHistoryMessageHandler: FC<{}> = props =>
{
diff --git a/src/components/chat-history/ChatHistoryView.scss b/src/components/chat-history/ChatHistoryView.scss
new file mode 100644
index 00000000..8c3838e4
--- /dev/null
+++ b/src/components/chat-history/ChatHistoryView.scss
@@ -0,0 +1,8 @@
+.nitro-chat-history {
+ width: $chat-history-width;
+ height: $chat-history-height;
+
+ .content-area {
+ min-height: 200px;
+ }
+}
diff --git a/src/components/chat-history/ChatHistoryView.tsx b/src/components/chat-history/ChatHistoryView.tsx
new file mode 100644
index 00000000..a048826c
--- /dev/null
+++ b/src/components/chat-history/ChatHistoryView.tsx
@@ -0,0 +1,155 @@
+import { ILinkEventTracker } from '@nitrots/nitro-renderer';
+import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { AutoSizer, CellMeasurer, CellMeasurerCache, List, ListRowProps, ListRowRenderer, Size } from 'react-virtualized';
+import { RenderedRows } from 'react-virtualized/dist/es/List';
+import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../api';
+import { Flex, Text } from '../../common';
+import { BatchUpdates } from '../../hooks';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
+import { ChatHistoryContextProvider } from './ChatHistoryContext';
+import { ChatHistoryMessageHandler } from './ChatHistoryMessageHandler';
+import { ChatEntryType } from './common/ChatEntryType';
+import { ChatHistoryState } from './common/ChatHistoryState';
+import { SetChatHistory } from './common/GetChatHistory';
+import { RoomHistoryState } from './common/RoomHistoryState';
+
+export const ChatHistoryView: FC<{}> = props =>
+{
+ const [ isVisible, setIsVisible ] = useState(false);
+ const [ needsScroll, setNeedsScroll ] = useState(false);
+ const [ chatHistoryUpdateId, setChatHistoryUpdateId ] = useState(-1);
+ const [ roomHistoryUpdateId, setRoomHistoryUpdateId ] = useState(-1);
+ const [ chatHistoryState, setChatHistoryState ] = useState(new ChatHistoryState());
+ const [ roomHistoryState, setRoomHistoryState ] = useState(new RoomHistoryState());
+ const elementRef = useRef(null);
+
+ const cache = useMemo(() => new CellMeasurerCache({ defaultHeight: 25, fixedWidth: true }), []);
+
+ const RowRenderer: ListRowRenderer = (props: ListRowProps) =>
+ {
+ const item = chatHistoryState.chats[props.index];
+
+ const isDark = (props.index % 2 === 0);
+
+ return (
+
+
+ { item.timestamp }
+ { (item.type === ChatEntryType.TYPE_CHAT) &&
+ <>
+
+ { item.message }
+ > }
+ { (item.type === ChatEntryType.TYPE_ROOM_INFO) &&
+ <>
+
+ { item.name }
+ > }
+
+
+ );
+ };
+
+ const onResize = (info: Size) => cache.clearAll();
+
+ const onRowsRendered = (info: RenderedRows) =>
+ {
+ if(elementRef && elementRef.current && isVisible && needsScroll)
+ {
+ elementRef.current.scrollToRow(chatHistoryState.chats.length);
+
+ setNeedsScroll(false);
+ }
+ }
+
+ const linkReceived = useCallback((url: string) =>
+ {
+ const parts = url.split('/');
+
+ if(parts.length < 2) return;
+
+ switch(parts[1])
+ {
+ case 'show':
+ setIsVisible(true);
+ return;
+ case 'hide':
+ setIsVisible(false);
+ return;
+ case 'toggle':
+ setIsVisible(prevValue => !prevValue);
+ return;
+ }
+ }, []);
+
+ useEffect(() =>
+ {
+ const linkTracker: ILinkEventTracker = {
+ linkReceived,
+ eventUrlPrefix: 'chat-history/'
+ };
+
+ AddEventLinkTracker(linkTracker);
+
+ return () => RemoveLinkEventTracker(linkTracker);
+ }, [ linkReceived ]);
+
+ useEffect(() =>
+ {
+ const chatState = new ChatHistoryState();
+ const roomState = new RoomHistoryState();
+
+ SetChatHistory(chatState);
+
+ chatState.notifier = () => setChatHistoryUpdateId(prevValue => (prevValue + 1));
+ roomState.notifier = () => setRoomHistoryUpdateId(prevValue => (prevValue + 1));
+
+ BatchUpdates(() =>
+ {
+ setChatHistoryState(chatState);
+ setRoomHistoryState(roomState);
+ });
+
+ return () =>
+ {
+ chatState.notifier = null;
+ roomState.notifier = null;
+ };
+ }, []);
+
+ useEffect(() =>
+ {
+ if(elementRef && elementRef.current && isVisible) elementRef.current.scrollToRow(chatHistoryState.chats.length);
+
+ setNeedsScroll(true);
+ }, [ isVisible, chatHistoryState.chats, chatHistoryUpdateId ]);
+
+ return (
+
+
+ { isVisible &&
+
+ setIsVisible(false) }/>
+
+
+ { ({ height, width }) =>
+ {
+ return (
+
+ )
+ } }
+
+
+ }
+
+ );
+}
diff --git a/src/components/chat-history/common/ChatEntryType.ts b/src/components/chat-history/common/ChatEntryType.ts
new file mode 100644
index 00000000..c49cd0ea
--- /dev/null
+++ b/src/components/chat-history/common/ChatEntryType.ts
@@ -0,0 +1,5 @@
+export class ChatEntryType
+{
+ public static TYPE_CHAT = 1;
+ public static TYPE_ROOM_INFO = 2;
+}
diff --git a/src/views/chat-history/common/ChatHistoryState.ts b/src/components/chat-history/common/ChatHistoryState.ts
similarity index 79%
rename from src/views/chat-history/common/ChatHistoryState.ts
rename to src/components/chat-history/common/ChatHistoryState.ts
index 895c00a1..53c96ef4 100644
--- a/src/views/chat-history/common/ChatHistoryState.ts
+++ b/src/components/chat-history/common/ChatHistoryState.ts
@@ -1,4 +1,5 @@
-import { IChatEntry, IChatHistoryState } from '../context/ChatHistoryContext.types';
+import { IChatEntry } from './IChatEntry';
+import { IChatHistoryState } from './IChatHistoryState';
export class ChatHistoryState implements IChatHistoryState
{
@@ -10,6 +11,11 @@ export class ChatHistoryState implements IChatHistoryState
this._chats = [];
}
+ public notify(): void
+ {
+ if(this._notifier) this._notifier();
+ }
+
public get chats(): IChatEntry[]
{
return this._chats;
@@ -24,9 +30,4 @@ export class ChatHistoryState implements IChatHistoryState
{
this._notifier = notifier;
}
-
- notify(): void
- {
- if(this._notifier) this._notifier();
- }
}
diff --git a/src/views/chat-history/common/GetChatHistory.ts b/src/components/chat-history/common/GetChatHistory.ts
similarity index 72%
rename from src/views/chat-history/common/GetChatHistory.ts
rename to src/components/chat-history/common/GetChatHistory.ts
index d39ef584..dbf546b1 100644
--- a/src/views/chat-history/common/GetChatHistory.ts
+++ b/src/components/chat-history/common/GetChatHistory.ts
@@ -1,4 +1,4 @@
-import { IChatHistoryState } from '../context/ChatHistoryContext.types';
+import { IChatHistoryState } from './IChatHistoryState';
let GLOBAL_CHATS: IChatHistoryState = null;
diff --git a/src/components/chat-history/common/IChatEntry.ts b/src/components/chat-history/common/IChatEntry.ts
new file mode 100644
index 00000000..472a5dbe
--- /dev/null
+++ b/src/components/chat-history/common/IChatEntry.ts
@@ -0,0 +1,12 @@
+export interface IChatEntry
+{
+ id: number;
+ entityId: number;
+ name: string;
+ look?: string;
+ message?: string;
+ entityType?: number;
+ roomId: number;
+ timestamp: string;
+ type: number;
+}
diff --git a/src/components/chat-history/common/IChatHistoryState.ts b/src/components/chat-history/common/IChatHistoryState.ts
new file mode 100644
index 00000000..4fecbae8
--- /dev/null
+++ b/src/components/chat-history/common/IChatHistoryState.ts
@@ -0,0 +1,8 @@
+import { IChatEntry } from './IChatEntry';
+
+export interface IChatHistoryState
+{
+ chats: IChatEntry[];
+ notifier: () => void
+ notify(): void;
+}
diff --git a/src/components/chat-history/common/IRoomHistoryEntry.ts b/src/components/chat-history/common/IRoomHistoryEntry.ts
new file mode 100644
index 00000000..19e6f917
--- /dev/null
+++ b/src/components/chat-history/common/IRoomHistoryEntry.ts
@@ -0,0 +1,4 @@
+export interface IRoomHistoryEntry {
+ id: number;
+ name: string;
+}
diff --git a/src/components/chat-history/common/IRoomHistoryState.ts b/src/components/chat-history/common/IRoomHistoryState.ts
new file mode 100644
index 00000000..64192f88
--- /dev/null
+++ b/src/components/chat-history/common/IRoomHistoryState.ts
@@ -0,0 +1,8 @@
+import { IRoomHistoryEntry } from './IRoomHistoryEntry';
+
+export interface IRoomHistoryState
+{
+ roomHistory: IRoomHistoryEntry[];
+ notifier: () => void;
+ notify: () => void;
+}
diff --git a/src/views/chat-history/common/RoomHistoryState.ts b/src/components/chat-history/common/RoomHistoryState.ts
similarity index 83%
rename from src/views/chat-history/common/RoomHistoryState.ts
rename to src/components/chat-history/common/RoomHistoryState.ts
index d3002b81..c59ac73e 100644
--- a/src/views/chat-history/common/RoomHistoryState.ts
+++ b/src/components/chat-history/common/RoomHistoryState.ts
@@ -1,4 +1,5 @@
-import { IRoomHistoryEntry, IRoomHistoryState } from '../context/ChatHistoryContext.types';
+import { IRoomHistoryEntry } from './IRoomHistoryEntry';
+import { IRoomHistoryState } from './IRoomHistoryState';
export class RoomHistoryState implements IRoomHistoryState
{
diff --git a/src/views/chat-history/utils/Utilities.ts b/src/components/chat-history/common/Utilities.ts
similarity index 100%
rename from src/views/chat-history/utils/Utilities.ts
rename to src/components/chat-history/common/Utilities.ts
diff --git a/src/components/help/common/IHelpReportState.ts b/src/components/help/common/IHelpReportState.ts
index eba3d2b6..26aba823 100644
--- a/src/components/help/common/IHelpReportState.ts
+++ b/src/components/help/common/IHelpReportState.ts
@@ -1,6 +1,7 @@
-import { IChatEntry } from '../../../views/chat-history/context/ChatHistoryContext.types';
+import { IChatEntry } from '../../chat-history/common/IChatEntry';
-export interface IHelpReportState {
+export interface IHelpReportState
+{
reportedUserId: number;
reportedChats: IChatEntry[];
cfhCategory: number;
diff --git a/src/components/help/views/SelectReportedChatsView.tsx b/src/components/help/views/SelectReportedChatsView.tsx
index 2adb4930..489a7e3a 100644
--- a/src/components/help/views/SelectReportedChatsView.tsx
+++ b/src/components/help/views/SelectReportedChatsView.tsx
@@ -2,8 +2,9 @@ import { RoomObjectType } from '@nitrots/nitro-renderer';
import { FC, useMemo, useState } from 'react';
import { LocalizeText } from '../../../api';
import { Button, Column, Flex, Grid, LayoutGridItem, Text } from '../../../common';
-import { GetChatHistory } from '../../../views/chat-history/common/GetChatHistory';
-import { ChatEntryType, IChatEntry } from '../../../views/chat-history/context/ChatHistoryContext.types';
+import { ChatEntryType } from '../../chat-history/common/ChatEntryType';
+import { GetChatHistory } from '../../chat-history/common/GetChatHistory';
+import { IChatEntry } from '../../chat-history/common/IChatEntry';
import { useHelpContext } from '../HelpContext';
export const SelectReportedChatsView: FC<{}> = props =>
diff --git a/src/components/help/views/SelectReportedUserView.tsx b/src/components/help/views/SelectReportedUserView.tsx
index fbb627f5..6cd25281 100644
--- a/src/components/help/views/SelectReportedUserView.tsx
+++ b/src/components/help/views/SelectReportedUserView.tsx
@@ -2,8 +2,8 @@ import { RoomObjectType } from '@nitrots/nitro-renderer';
import { FC, useMemo, useState } from 'react';
import { GetSessionDataManager, LocalizeText } from '../../../api';
import { Button, Column, Flex, Grid, LayoutGridItem, Text } from '../../../common';
-import { GetChatHistory } from '../../../views/chat-history/common/GetChatHistory';
-import { ChatEntryType } from '../../../views/chat-history/context/ChatHistoryContext.types';
+import { ChatEntryType } from '../../chat-history/common/ChatEntryType';
+import { GetChatHistory } from '../../chat-history/common/GetChatHistory';
import { IReportedUser } from '../common/IReportedUser';
import { useHelpContext } from '../HelpContext';
diff --git a/src/components/help/views/SelectTopicView.tsx b/src/components/help/views/SelectTopicView.tsx
index b8250ef4..c5672596 100644
--- a/src/components/help/views/SelectTopicView.tsx
+++ b/src/components/help/views/SelectTopicView.tsx
@@ -1,7 +1,7 @@
import { FC, useMemo, useState } from 'react';
import { LocalizeText } from '../../../api';
import { Button, Column, Flex, Text } from '../../../common';
-import { GetCfhCategories } from '../../../views/mod-tools/common/GetCFHCategories';
+import { GetCfhCategories } from '../../mod-tools/common/GetCFHCategories';
import { useHelpContext } from '../HelpContext';
export const SelectTopicView: FC<{}> = props =>
diff --git a/src/components/index.scss b/src/components/index.scss
index 730773fc..0a8601ce 100644
--- a/src/components/index.scss
+++ b/src/components/index.scss
@@ -2,10 +2,16 @@
@import './avatar-editor/AvatarEditorView';
@import './camera/CameraWidgetView';
@import './catalog/CatalogView';
+@import './chat-history/ChatHistoryView';
@import './groups/GroupView';
@import './help/HelpView';
@import './inventory/InventoryView';
+@import './loading/LoadingView';
+@import './mod-tools/ModToolsView';
@import './navigator/NavigatorView';
+@import './purse/PurseView';
+@import './right-side/RightSideView';
@import './toolbar/ToolbarView';
+@import './user-profile/UserProfileVew';
@import './user-settings/UserSettingsView';
@import './wired/WiredView';
diff --git a/src/views/loading/LoadingView.scss b/src/components/loading/LoadingView.scss
similarity index 100%
rename from src/views/loading/LoadingView.scss
rename to src/components/loading/LoadingView.scss
diff --git a/src/components/loading/LoadingView.tsx b/src/components/loading/LoadingView.tsx
new file mode 100644
index 00000000..ecf4fc75
--- /dev/null
+++ b/src/components/loading/LoadingView.tsx
@@ -0,0 +1,37 @@
+import { FC, useEffect, useState } from 'react';
+import { Base, Column } from '../../common';
+import { NotificationUtilities } from '../../views/notification-center/common/NotificationUtilities';
+
+interface LoadingViewProps
+{
+ isError: boolean;
+ message: string;
+}
+
+export const LoadingView: FC = props =>
+{
+ const { isError = false, message = '' } = props;
+ const [ loadingShowing, setLoadingShowing ] = useState(false);
+
+ useEffect(() =>
+ {
+ if(!isError) return;
+
+ NotificationUtilities.simpleAlert(message, null, null, null, 'Connection Error');
+ }, [ isError, message ]);
+
+ useEffect(() =>
+ {
+ const timeout = setTimeout(() => setLoadingShowing(true), 500);
+
+ return () => clearTimeout(timeout);
+ }, []);
+
+ return (
+
+
+ { isError && (message && message.length) &&
+ { message } }
+
+ );
+}
diff --git a/src/views/main/MainView.tsx b/src/components/main/MainView.tsx
similarity index 72%
rename from src/views/main/MainView.tsx
rename to src/components/main/MainView.tsx
index ccf77590..50821cdc 100644
--- a/src/views/main/MainView.tsx
+++ b/src/components/main/MainView.tsx
@@ -1,33 +1,33 @@
import { HabboWebTools, RoomSessionEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
import { AddEventLinkTracker, GetCommunication, RemoveLinkEventTracker } from '../../api';
-import { AchievementsView } from '../../components/achievements/AchievementsView';
-import { AvatarEditorView } from '../../components/avatar-editor/AvatarEditorView';
-import { CameraWidgetView } from '../../components/camera/CameraWidgetView';
-import { CatalogView } from '../../components/catalog/CatalogView';
-import { GroupsView } from '../../components/groups/GroupsView';
-import { HelpView } from '../../components/help/HelpView';
-import { InventoryView } from '../../components/inventory/InventoryView';
-import { NavigatorView } from '../../components/navigator/NavigatorView';
-import { ToolbarView } from '../../components/toolbar/ToolbarView';
-import { UserSettingsView } from '../../components/user-settings/UserSettingsView';
-import { WiredView } from '../../components/wired/WiredView';
+import { Base } from '../../common';
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
import { TransitionAnimation, TransitionAnimationTypes } from '../../layout';
-import { CampaignView } from '../campaign/CampaignView';
+import { CampaignView } from '../../views/campaign/CampaignView';
+import { FloorplanEditorView } from '../../views/floorplan-editor/FloorplanEditorView';
+import { FriendsView } from '../../views/friends/FriendsView';
+import { HcCenterView } from '../../views/hc-center/HcCenterView';
+import { HotelView } from '../../views/hotel-view/HotelView';
+import { NitropediaView } from '../../views/nitropedia/NitropediaView';
+import { AchievementsView } from '../achievements/AchievementsView';
+import { AvatarEditorView } from '../avatar-editor/AvatarEditorView';
+import { CameraWidgetView } from '../camera/CameraWidgetView';
+import { CatalogView } from '../catalog/CatalogView';
import { ChatHistoryView } from '../chat-history/ChatHistoryView';
-import { FloorplanEditorView } from '../floorplan-editor/FloorplanEditorView';
-import { FriendsView } from '../friends/FriendsView';
-import { HcCenterView } from '../hc-center/HcCenterView';
-import { HotelView } from '../hotel-view/HotelView';
+import { GroupsView } from '../groups/GroupsView';
+import { HelpView } from '../help/HelpView';
+import { InventoryView } from '../inventory/InventoryView';
import { ModToolsView } from '../mod-tools/ModToolsView';
-import { NitropediaView } from '../nitropedia/NitropediaView';
+import { NavigatorView } from '../navigator/NavigatorView';
import { RightSideView } from '../right-side/RightSideView';
import { RoomHostView } from '../room-host/RoomHostView';
+import { ToolbarView } from '../toolbar/ToolbarView';
import { UserProfileView } from '../user-profile/UserProfileView';
-import { MainViewProps } from './MainView.types';
+import { UserSettingsView } from '../user-settings/UserSettingsView';
+import { WiredView } from '../wired/WiredView';
-export const MainView: FC = props =>
+export const MainView: FC<{}> = props =>
{
const [ isReady, setIsReady ] = useState(false);
const [ landingViewVisible, setLandingViewVisible ] = useState(true);
@@ -93,7 +93,7 @@ export const MainView: FC = props =>
}, [onLinkReceived]);
return (
-
+
@@ -118,6 +118,6 @@ export const MainView: FC = props =>
-
+
);
}
diff --git a/src/components/mod-tools/ModToolsContext.tsx b/src/components/mod-tools/ModToolsContext.tsx
new file mode 100644
index 00000000..1ab06b4c
--- /dev/null
+++ b/src/components/mod-tools/ModToolsContext.tsx
@@ -0,0 +1,20 @@
+import { createContext, Dispatch, FC, ProviderProps, useContext } from 'react';
+import { IModToolsAction, IModToolsState } from './reducers/ModToolsReducer';
+
+export interface IModToolsContext
+{
+ modToolsState: IModToolsState;
+ dispatchModToolsState: Dispatch;
+}
+
+const ModToolsContext = createContext({
+ modToolsState: null,
+ dispatchModToolsState: null
+});
+
+export const ModToolsContextProvider: FC> = props =>
+{
+ return { props.children }
+}
+
+export const useModToolsContext = () => useContext(ModToolsContext);
diff --git a/src/views/mod-tools/ModToolsMessageHandler.tsx b/src/components/mod-tools/ModToolsMessageHandler.tsx
similarity index 97%
rename from src/views/mod-tools/ModToolsMessageHandler.tsx
rename to src/components/mod-tools/ModToolsMessageHandler.tsx
index 3863bdb7..82820610 100644
--- a/src/views/mod-tools/ModToolsMessageHandler.tsx
+++ b/src/components/mod-tools/ModToolsMessageHandler.tsx
@@ -7,10 +7,10 @@ import { ModToolsOpenRoomInfoEvent } from '../../events/mod-tools/ModToolsOpenRo
import { ModToolsOpenUserChatlogEvent } from '../../events/mod-tools/ModToolsOpenUserChatlogEvent';
import { ModToolsOpenUserInfoEvent } from '../../events/mod-tools/ModToolsOpenUserInfoEvent';
import { CreateMessageHook, useRoomEngineEvent, useUiEvent } from '../../hooks';
-import { NotificationAlertType } from '../notification-center/common/NotificationAlertType';
-import { NotificationUtilities } from '../notification-center/common/NotificationUtilities';
+import { NotificationAlertType } from '../../views/notification-center/common/NotificationAlertType';
+import { NotificationUtilities } from '../../views/notification-center/common/NotificationUtilities';
import { SetCfhCategories } from './common/GetCFHCategories';
-import { useModToolsContext } from './context/ModToolsContext';
+import { useModToolsContext } from './ModToolsContext';
import { ModToolsActions } from './reducers/ModToolsReducer';
export const ModToolsMessageHandler: FC<{}> = props =>
diff --git a/src/components/mod-tools/ModToolsView.scss b/src/components/mod-tools/ModToolsView.scss
new file mode 100644
index 00000000..ac9a58da
--- /dev/null
+++ b/src/components/mod-tools/ModToolsView.scss
@@ -0,0 +1,93 @@
+.nitro-mod-tools {
+ width: $nitro-mod-tools-width;
+}
+
+.nitro-mod-tools-room {
+ width: 240px;
+
+ .username {
+ color: #1E7295;
+ text-decoration: underline;
+ }
+}
+
+.nitro-mod-tools-user {
+ width: 350px;
+ height: 370px;
+
+ .username {
+ color: #1E7295;
+ text-decoration: underline;
+ }
+
+ .table {
+ color: $black;
+
+ > :not(caption) > * > * {
+ box-shadow: none;
+ border-bottom: 1px solid rgba(0, 0, 0, .2);
+ }
+
+ &.table-striped > tbody > tr:nth-of-type(odd) {
+ color: $black;
+ background: rgba(0, 0, 0, .05);
+ }
+ }
+}
+
+.nitro-mod-tools-user-visits {
+ min-width: 300px;
+
+ .user-visits {
+ min-height: 200px;
+
+ .roomvisits-container {
+ div.room-visit {
+ }
+ }
+
+ }
+}
+
+.nitro-mod-tools-chatlog {
+ width: 400px;
+}
+
+.nitro-mod-tools-user-visits {
+ width: 250px;
+}
+
+.nitro-mod-tools-tickets {
+ width: 400px;
+ height: 200px;
+}
+
+.nitro-mod-tools-handle-issue {
+ width: 400px;
+}
+
+.nitro-mod-tools-chatlog,
+.nitro-mod-tools-user-visits {
+
+ .log-container {
+ min-height: 200px;
+
+ .log-entry-container {
+
+ .log-entry {
+
+ &.highlighted {
+ border: 1px solid $red;
+ }
+ }
+
+ &.highlighted {
+ border: 1px solid $red;
+ }
+ }
+
+ &:first-child {
+ padding-top: 0;
+ }
+ }
+}
diff --git a/src/views/mod-tools/ModToolsView.tsx b/src/components/mod-tools/ModToolsView.tsx
similarity index 85%
rename from src/views/mod-tools/ModToolsView.tsx
rename to src/components/mod-tools/ModToolsView.tsx
index 902ec5b9..3991c705 100644
--- a/src/views/mod-tools/ModToolsView.tsx
+++ b/src/components/mod-tools/ModToolsView.tsx
@@ -1,6 +1,8 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { RoomEngineObjectEvent, RoomObjectCategory } from '@nitrots/nitro-renderer';
import { FC, useCallback, useReducer, useState } from 'react';
import { GetRoomSession } from '../../api';
+import { Button } from '../../common';
import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent';
import { ModToolsOpenRoomChatlogEvent } from '../../events/mod-tools/ModToolsOpenRoomChatlogEvent';
import { ModToolsOpenRoomInfoEvent } from '../../events/mod-tools/ModToolsOpenRoomInfoEvent';
@@ -8,24 +10,23 @@ import { ModToolsOpenUserInfoEvent } from '../../events/mod-tools/ModToolsOpenUs
import { useRoomEngineEvent } from '../../hooks/events';
import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
-import { ModToolsContextProvider } from './context/ModToolsContext';
+import { ModToolsContextProvider } from './ModToolsContext';
import { ModToolsMessageHandler } from './ModToolsMessageHandler';
-import { ModToolsViewProps } from './ModToolsView.types';
import { initialModTools, ModToolsActions, ModToolsReducer } from './reducers/ModToolsReducer';
import { ISelectedUser } from './utils/ISelectedUser';
-import { ModToolsChatlogView } from './views/room/room-chatlog/ModToolsChatlogView';
-import { ModToolsRoomView } from './views/room/room-tools/ModToolsRoomView';
+import { ModToolsChatlogView } from './views/room/ModToolsChatlogView';
+import { ModToolsRoomView } from './views/room/ModToolsRoomView';
import { ModToolsTicketsView } from './views/tickets/ModToolsTicketsView';
-import { ModToolsUserChatlogView } from './views/user/user-chatlog/ModToolsUserChatlogView';
-import { ModToolsUserView } from './views/user/user-info/ModToolsUserView';
+import { ModToolsUserChatlogView } from './views/user/ModToolsUserChatlogView';
+import { ModToolsUserView } from './views/user/ModToolsUserView';
-export const ModToolsView: FC = props =>
+export const ModToolsView: FC<{}> = props =>
{
const [ isVisible, setIsVisible ] = useState(false);
- const [ modToolsState, dispatchModToolsState ] = useReducer(ModToolsReducer, initialModTools);
- const { currentRoomId = null, openRooms = null, openRoomChatlogs = null, openUserChatlogs = null, openUserInfo = null } = modToolsState;
const [ selectedUser, setSelectedUser] = useState(null);
const [ isTicketsVisible, setIsTicketsVisible ] = useState(false);
+ const [ modToolsState, dispatchModToolsState ] = useReducer(ModToolsReducer, initialModTools);
+ const { currentRoomId = null, openRooms = null, openRoomChatlogs = null, openUserChatlogs = null, openUserInfo = null } = modToolsState;
const onModToolsEvent = useCallback((event: ModToolsEvent) =>
{
@@ -191,11 +192,19 @@ export const ModToolsView: FC = props =>
{ isVisible &&
setIsVisible(false) } />
-
-
-
-
-
+
+
+
+
+
}
{ openRooms && openRooms.map(roomId =>
diff --git a/src/views/mod-tools/common/GetCFHCategories.ts b/src/components/mod-tools/common/GetCFHCategories.ts
similarity index 100%
rename from src/views/mod-tools/common/GetCFHCategories.ts
rename to src/components/mod-tools/common/GetCFHCategories.ts
diff --git a/src/views/mod-tools/common/IssueCategoryNames.ts b/src/components/mod-tools/common/IssueCategoryNames.ts
similarity index 100%
rename from src/views/mod-tools/common/IssueCategoryNames.ts
rename to src/components/mod-tools/common/IssueCategoryNames.ts
diff --git a/src/views/mod-tools/reducers/ModToolsReducer.tsx b/src/components/mod-tools/reducers/ModToolsReducer.tsx
similarity index 100%
rename from src/views/mod-tools/reducers/ModToolsReducer.tsx
rename to src/components/mod-tools/reducers/ModToolsReducer.tsx
diff --git a/src/views/mod-tools/utils/ISelectedUser.ts b/src/components/mod-tools/utils/ISelectedUser.ts
similarity index 100%
rename from src/views/mod-tools/utils/ISelectedUser.ts
rename to src/components/mod-tools/utils/ISelectedUser.ts
diff --git a/src/views/mod-tools/utils/IUserInfo.ts b/src/components/mod-tools/utils/IUserInfo.ts
similarity index 100%
rename from src/views/mod-tools/utils/IUserInfo.ts
rename to src/components/mod-tools/utils/IUserInfo.ts
diff --git a/src/views/mod-tools/utils/ModActionDefinition.ts b/src/components/mod-tools/utils/ModActionDefinition.ts
similarity index 100%
rename from src/views/mod-tools/utils/ModActionDefinition.ts
rename to src/components/mod-tools/utils/ModActionDefinition.ts
diff --git a/src/components/mod-tools/views/chatlog/ChatlogView.tsx b/src/components/mod-tools/views/chatlog/ChatlogView.tsx
new file mode 100644
index 00000000..b6887dec
--- /dev/null
+++ b/src/components/mod-tools/views/chatlog/ChatlogView.tsx
@@ -0,0 +1,158 @@
+import { ChatRecordData, UserProfileComposer } from '@nitrots/nitro-renderer';
+import { CSSProperties, FC, Key, useCallback } from 'react';
+import { AutoSizer, CellMeasurer, CellMeasurerCache, List, ListRowProps } from 'react-virtualized';
+import { TryVisitRoom } from '../../../../api';
+import { Base, Button, Column, Flex, Grid, Text } from '../../../../common';
+import { ModToolsOpenRoomInfoEvent } from '../../../../events/mod-tools/ModToolsOpenRoomInfoEvent';
+import { dispatchUiEvent, SendMessageHook } from '../../../../hooks';
+
+interface ChatlogViewProps
+{
+ records: ChatRecordData[];
+}
+
+export const ChatlogView: FC = props =>
+{
+ const { records = null } = props;
+
+ const rowRenderer = (props: ListRowProps) =>
+ {
+ let chatlogEntry = records[0].chatlog[props.index];
+
+ return (
+
+
+ { chatlogEntry.timestamp }
+ SendMessageHook(new UserProfileComposer(chatlogEntry.userId)) }>{ chatlogEntry.userName }
+ { chatlogEntry.message }
+
+
+ );
+ };
+
+ const advancedRowRenderer = (props: ListRowProps) =>
+ {
+ let chatlogEntry = null;
+ let currentRecord: ChatRecordData = null;
+ let isRoomInfo = false;
+ let totalIndex = 0;
+
+ for(let i = 0; i < records.length; i++)
+ {
+ currentRecord = records[i];
+
+ totalIndex++; // row for room info
+ totalIndex = (totalIndex + currentRecord.chatlog.length);
+
+ if(props.index > (totalIndex - 1)) continue;
+
+ if((props.index + 1) === (totalIndex - currentRecord.chatlog.length))
+ {
+ isRoomInfo = true;
+
+ break;
+ }
+
+ const index = (props.index - (totalIndex - currentRecord.chatlog.length));
+
+ chatlogEntry = currentRecord.chatlog[index];
+
+ break;
+ }
+
+ return (
+
+ { (isRoomInfo && currentRecord) &&
+ }
+ { !isRoomInfo &&
+
+ { chatlogEntry.timestamp }
+ SendMessageHook(new UserProfileComposer(chatlogEntry.userId)) }>{ chatlogEntry.userName }
+ { chatlogEntry.message }
+ }
+
+ );
+ }
+
+ const getNumRowsForAdvanced = useCallback(() =>
+ {
+ let count = 0;
+
+ for(let i = 0; i < records.length; i++)
+ {
+ count++; // add room info row
+ count = count + records[i].chatlog.length;
+ }
+
+ return count;
+ }, [records]);
+
+ const RoomInfo = (props: { roomId: number, roomName: string, uniqueKey: Key, style: CSSProperties }) =>
+ {
+ return (
+
+
+ Room name:
+ { props.roomName }
+
+
+
+
+
+
+ );
+ }
+
+ const cache = new CellMeasurerCache({
+ defaultHeight: 25,
+ fixedWidth: true
+ });
+
+ return (
+ <>
+ { (records && (records.length === 1)) &&
+ }
+
+
+
+ Time
+ User
+ Message
+
+
+ { (records && (records.length > 0)) &&
+
+
+ { ({ height, width }) =>
+ {
+ cache.clearAll();
+
+ return (
+ 1) ? getNumRowsForAdvanced() : records[0].chatlog.length }
+ rowHeight={ cache.rowHeight }
+ className={ 'log-entry-container' }
+ rowRenderer={ (records.length > 1) ? advancedRowRenderer : rowRenderer }
+ deferredMeasurementCache={ cache } />
+ );
+ } }
+
+ }
+
+ >
+ );
+}
diff --git a/src/views/mod-tools/views/room/room-chatlog/ModToolsChatlogView.tsx b/src/components/mod-tools/views/room/ModToolsChatlogView.tsx
similarity index 59%
rename from src/views/mod-tools/views/room/room-chatlog/ModToolsChatlogView.tsx
rename to src/components/mod-tools/views/room/ModToolsChatlogView.tsx
index 96d11aba..b42dafa9 100644
--- a/src/views/mod-tools/views/room/room-chatlog/ModToolsChatlogView.tsx
+++ b/src/components/mod-tools/views/room/ModToolsChatlogView.tsx
@@ -1,20 +1,19 @@
import { ChatRecordData, GetRoomChatlogMessageComposer, RoomChatlogEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
-import { CreateMessageHook, SendMessageHook } from '../../../../../hooks/messages';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
-import { ChatlogView } from '../../chatlog/ChatlogView';
-import { ModToolsChatlogViewProps } from './ModToolsChatlogView.types';
+import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
+import { ChatlogView } from '../chatlog/ChatlogView';
+
+interface ModToolsChatlogViewProps
+{
+ roomId: number;
+ onCloseClick: () => void;
+}
export const ModToolsChatlogView: FC = props =>
{
const { roomId = null, onCloseClick = null } = props;
-
- const [roomChatlog, setRoomChatlog] = useState(null);
-
- useEffect(() =>
- {
- SendMessageHook(new GetRoomChatlogMessageComposer(roomId));
- }, [roomId]);
+ const [ roomChatlog, setRoomChatlog ] = useState(null);
const onModtoolRoomChatlogEvent = useCallback((event: RoomChatlogEvent) =>
{
@@ -23,17 +22,23 @@ export const ModToolsChatlogView: FC = props =>
if(!parser || parser.data.roomId !== roomId) return;
setRoomChatlog(parser.data);
- }, [roomId, setRoomChatlog]);
+ }, [ roomId ]);
CreateMessageHook(RoomChatlogEvent, onModtoolRoomChatlogEvent);
+ useEffect(() =>
+ {
+ SendMessageHook(new GetRoomChatlogMessageComposer(roomId));
+ }, [ roomId ]);
+
+ if(!roomChatlog) return null;
+
return (
-
- onCloseClick()} />
+
+
- {roomChatlog &&
-
- }
+ { roomChatlog &&
+ }
);
diff --git a/src/components/mod-tools/views/room/ModToolsRoomView.tsx b/src/components/mod-tools/views/room/ModToolsRoomView.tsx
new file mode 100644
index 00000000..97a22c8c
--- /dev/null
+++ b/src/components/mod-tools/views/room/ModToolsRoomView.tsx
@@ -0,0 +1,128 @@
+import { GetModeratorRoomInfoMessageComposer, ModerateRoomMessageComposer, ModeratorActionMessageComposer, ModeratorRoomInfoEvent } from '@nitrots/nitro-renderer';
+import { FC, useCallback, useEffect, useState } from 'react';
+import { TryVisitRoom } from '../../../../api';
+import { Button, Column, Flex, Text } from '../../../../common';
+import { ModToolsOpenRoomChatlogEvent } from '../../../../events/mod-tools/ModToolsOpenRoomChatlogEvent';
+import { BatchUpdates, dispatchUiEvent } from '../../../../hooks';
+import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
+
+interface ModToolsRoomViewProps
+{
+ roomId: number;
+ onCloseClick: () => void;
+}
+
+export const ModToolsRoomView: FC = props =>
+{
+ const { roomId = null, onCloseClick = null } = props;
+
+ const [ infoRequested, setInfoRequested ] = useState(false);
+ const [ loadedRoomId, setLoadedRoomId ] = useState(null);
+
+ const [ name, setName ] = useState(null);
+ const [ ownerId, setOwnerId ] = useState(null);
+ const [ ownerName, setOwnerName ] = useState(null);
+ const [ ownerInRoom, setOwnerInRoom ] = useState(false);
+ const [ usersInRoom, setUsersInRoom ] = useState(0);
+
+ //form data
+ const [ kickUsers, setKickUsers ] = useState(false);
+ const [ lockRoom, setLockRoom ] = useState(false);
+ const [ changeRoomName, setChangeRoomName ] = useState(false);
+ const [ message, setMessage ] = useState('');
+
+ const onModtoolRoomInfoEvent = useCallback((event: ModeratorRoomInfoEvent) =>
+ {
+ const parser = event.getParser();
+
+ if(!parser || parser.data.flatId !== roomId) return;
+
+ BatchUpdates(() =>
+ {
+ setLoadedRoomId(parser.data.flatId);
+ setName(parser.data.room.name);
+ setOwnerId(parser.data.ownerId);
+ setOwnerName(parser.data.ownerName);
+ setOwnerInRoom(parser.data.ownerInRoom);
+ setUsersInRoom(parser.data.userCount);
+ });
+ }, [ roomId ]);
+
+ CreateMessageHook(ModeratorRoomInfoEvent, onModtoolRoomInfoEvent);
+
+ const handleClick = useCallback((action: string, value?: string) =>
+ {
+ if(!action) return;
+
+ switch(action)
+ {
+ case 'alert_only':
+ if(message.trim().length === 0) return;
+
+ SendMessageHook(new ModeratorActionMessageComposer(ModeratorActionMessageComposer.ACTION_ALERT, message, ''));
+ return;
+ case 'send_message':
+ if(message.trim().length === 0) return;
+
+ SendMessageHook(new ModeratorActionMessageComposer(ModeratorActionMessageComposer.ACTION_MESSAGE, message, ''));
+ SendMessageHook(new ModerateRoomMessageComposer(roomId, lockRoom ? 1 : 0, changeRoomName ? 1 : 0, kickUsers ? 1 : 0))
+ return;
+ }
+ }, [ changeRoomName, kickUsers, lockRoom, message, roomId ]);
+
+ useEffect(() =>
+ {
+ if(infoRequested) return;
+
+ SendMessageHook(new GetModeratorRoomInfoMessageComposer(roomId));
+ setInfoRequested(true);
+ }, [ roomId, infoRequested, setInfoRequested ]);
+
+ return (
+
+ onCloseClick() } />
+
+
+
+
+ Room Owner:
+ { ownerName }
+
+
+ Users in room:
+ { usersInRoom }
+
+
+ Owner in room:
+ { ownerInRoom ? 'Yes' : 'No' }
+
+
+
+
+
+
+
+
+
+ setKickUsers(event.target.checked) } />
+ Kick everyone out
+
+
+ setLockRoom(event.target.checked) } />
+ Enable the doorbell
+
+
+ setChangeRoomName(event.target.checked) }/>
+ Change room name
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/views/mod-tools/views/tickets/issue-info/CfhChatlogView.tsx b/src/components/mod-tools/views/tickets/CfhChatlogView.tsx
similarity index 88%
rename from src/views/mod-tools/views/tickets/issue-info/CfhChatlogView.tsx
rename to src/components/mod-tools/views/tickets/CfhChatlogView.tsx
index fdb4c28e..de2bba64 100644
--- a/src/views/mod-tools/views/tickets/issue-info/CfhChatlogView.tsx
+++ b/src/components/mod-tools/views/tickets/CfhChatlogView.tsx
@@ -1,9 +1,14 @@
import { CfhChatlogData, CfhChatlogEvent, GetCfhChatlogMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
-import { CreateMessageHook, SendMessageHook } from '../../../../../hooks';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
-import { ChatlogView } from '../../chatlog/ChatlogView';
-import { CfhChatlogViewProps } from './CfhChatlogView.types';
+import { CreateMessageHook, SendMessageHook } from '../../../../hooks';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
+import { ChatlogView } from '../chatlog/ChatlogView';
+
+interface CfhChatlogViewProps
+{
+ issueId: number;
+ onCloseClick(): void;
+}
export const CfhChatlogView: FC = props =>
{
diff --git a/src/components/mod-tools/views/tickets/ModToolsIssueInfoView.tsx b/src/components/mod-tools/views/tickets/ModToolsIssueInfoView.tsx
new file mode 100644
index 00000000..6fa92c1e
--- /dev/null
+++ b/src/components/mod-tools/views/tickets/ModToolsIssueInfoView.tsx
@@ -0,0 +1,99 @@
+import { CloseIssuesMessageComposer, ReleaseIssuesMessageComposer } from '@nitrots/nitro-renderer';
+import { FC, useMemo, useState } from 'react';
+import { LocalizeText } from '../../../../api';
+import { Button, Column, Grid, Text } from '../../../../common';
+import { ModToolsOpenUserInfoEvent } from '../../../../events/mod-tools/ModToolsOpenUserInfoEvent';
+import { dispatchUiEvent, SendMessageHook } from '../../../../hooks';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
+import { getSourceName } from '../../common/IssueCategoryNames';
+import { useModToolsContext } from '../../ModToolsContext';
+import { CfhChatlogView } from './CfhChatlogView';
+
+interface IssueInfoViewProps
+{
+ issueId: number;
+ onIssueInfoClosed(issueId: number): void;
+}
+
+export const ModToolsIssueInfoView: FC = props =>
+{
+ const { issueId = null, onIssueInfoClosed = null } = props;
+ const { modToolsState = null } = useModToolsContext();
+ const { tickets = null } = modToolsState;
+ const [ cfhChatlogOpen, setcfhChatlogOpen ] = useState(false);
+
+ const ticket = useMemo(() =>
+ {
+ if(!tickets || !tickets.length) return null;
+
+ return tickets.find(issue => issue.issueId === issueId);
+ }, [ issueId, tickets ]);
+
+ const releaseIssue = (issueId: number) =>
+ {
+ SendMessageHook(new ReleaseIssuesMessageComposer([ issueId ]));
+
+ onIssueInfoClosed(issueId);
+ }
+
+ const closeIssue = (resolutionType: number) =>
+ {
+ SendMessageHook(new CloseIssuesMessageComposer([ issueId ], resolutionType));
+
+ onIssueInfoClosed(issueId)
+ }
+
+ const openUserInfo = (userId: number) => dispatchUiEvent(new ModToolsOpenUserInfoEvent(userId));
+
+ return (
+ <>
+
+ onIssueInfoClosed(issueId)} />
+
+ Issue Information
+
+
+
+
+
+ Source |
+ { getSourceName(ticket.categoryId) } |
+
+
+ Category |
+ { LocalizeText('help.cfh.topic.' + ticket.reportedCategoryId) } |
+
+
+ Description |
+ { ticket.message } |
+
+
+ Caller |
+
+ openUserInfo(ticket.reporterUserId) }>{ ticket.reporterUserName }
+ |
+
+
+ Reported User |
+
+ openUserInfo(ticket.reportedUserId) }>{ ticket.reportedUserName }
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { cfhChatlogOpen &&
+ setcfhChatlogOpen(false) }/> }
+ >
+ );
+}
diff --git a/src/components/mod-tools/views/tickets/ModToolsMyIssuesTabView.tsx b/src/components/mod-tools/views/tickets/ModToolsMyIssuesTabView.tsx
new file mode 100644
index 00000000..bba92740
--- /dev/null
+++ b/src/components/mod-tools/views/tickets/ModToolsMyIssuesTabView.tsx
@@ -0,0 +1,49 @@
+import { IssueMessageData, ReleaseIssuesMessageComposer } from '@nitrots/nitro-renderer';
+import { FC } from 'react';
+import { Base, Button, Column, Grid } from '../../../../common';
+import { SendMessageHook } from '../../../../hooks';
+
+interface ModToolsMyIssuesTabViewProps
+{
+ myIssues: IssueMessageData[];
+ onIssueHandleClick(issueId: number): void;
+}
+
+export const ModToolsMyIssuesTabView: FC = props =>
+{
+ const { myIssues = null, onIssueHandleClick = null } = props;
+
+ const onReleaseIssue = (issueId: number) => SendMessageHook(new ReleaseIssuesMessageComposer([issueId]));
+
+ return (
+
+
+
+ Type
+ Room/Player
+ Opened
+
+
+
+
+
+ { myIssues && (myIssues.length > 0) && myIssues.map(issue =>
+ {
+ return (
+
+ { issue.categoryId }
+ { issue.reportedUserName }
+ { new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString() }
+
+
+
+
+
+
+
+ );
+ }) }
+
+
+ );
+}
diff --git a/src/components/mod-tools/views/tickets/ModToolsOpenIssuesTabView.tsx b/src/components/mod-tools/views/tickets/ModToolsOpenIssuesTabView.tsx
new file mode 100644
index 00000000..1d980631
--- /dev/null
+++ b/src/components/mod-tools/views/tickets/ModToolsOpenIssuesTabView.tsx
@@ -0,0 +1,44 @@
+import { IssueMessageData, PickIssuesMessageComposer } from '@nitrots/nitro-renderer';
+import { FC } from 'react';
+import { Base, Button, Column, Grid } from '../../../../common';
+import { SendMessageHook } from '../../../../hooks';
+
+interface ModToolsOpenIssuesTabViewProps
+{
+ openIssues: IssueMessageData[];
+}
+
+export const ModToolsOpenIssuesTabView: FC = props =>
+{
+ const { openIssues = null } = props;
+
+ const onPickIssue = (issueId: number) => SendMessageHook(new PickIssuesMessageComposer([issueId], false, 0, 'pick issue button'));
+
+ return (
+
+
+
+ Type
+ Room/Player
+ Opened
+
+
+
+
+ { openIssues && (openIssues.length > 0) && openIssues.map(issue =>
+ {
+ return (
+
+ { issue.categoryId }
+ { issue.reportedUserName }
+ { new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString() }
+
+
+
+
+ );
+ }) }
+
+
+ );
+}
diff --git a/src/components/mod-tools/views/tickets/ModToolsPickedIssuesTabView.tsx b/src/components/mod-tools/views/tickets/ModToolsPickedIssuesTabView.tsx
new file mode 100644
index 00000000..6f155971
--- /dev/null
+++ b/src/components/mod-tools/views/tickets/ModToolsPickedIssuesTabView.tsx
@@ -0,0 +1,39 @@
+import { IssueMessageData } from '@nitrots/nitro-renderer';
+import { FC } from 'react';
+import { Base, Column, Grid } from '../../../../common';
+
+interface ModToolsPickedIssuesTabViewProps
+{
+ pickedIssues: IssueMessageData[];
+}
+
+export const ModToolsPickedIssuesTabView: FC = props =>
+{
+ const { pickedIssues = null } = props;
+
+ return (
+
+
+
+ Type
+ Room/Player
+ Opened
+ Picker
+
+
+
+ { pickedIssues && (pickedIssues.length > 0) && pickedIssues.map(issue =>
+ {
+ return (
+
+ { issue.categoryId }
+ { issue.reportedUserName }
+ { new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString() }
+ { issue.pickerUserName }
+
+ );
+ }) }
+
+
+ );
+}
diff --git a/src/views/mod-tools/views/tickets/ModToolsTicketsView.tsx b/src/components/mod-tools/views/tickets/ModToolsTicketsView.tsx
similarity index 66%
rename from src/views/mod-tools/views/tickets/ModToolsTicketsView.tsx
rename to src/components/mod-tools/views/tickets/ModToolsTicketsView.tsx
index e2ccea90..e6b91996 100644
--- a/src/views/mod-tools/views/tickets/ModToolsTicketsView.tsx
+++ b/src/components/mod-tools/views/tickets/ModToolsTicketsView.tsx
@@ -2,12 +2,16 @@ import { IssueMessageData } from '@nitrots/nitro-renderer';
import { FC, useCallback, useMemo, useState } from 'react';
import { GetSessionDataManager } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout';
-import { useModToolsContext } from '../../context/ModToolsContext';
-import { IssueInfoView } from './issue-info/IssueInfoView';
-import { ModToolsTicketsViewProps } from './ModToolsTicketsView.types';
-import { ModToolsMyIssuesTabView } from './my-issues/ModToolsMyIssuesTabView';
-import { ModToolsOpenIssuesTabView } from './open-issues/ModToolsOpenIssuesTabView';
-import { ModToolsPickedIssuesTabView } from './picked-issues/ModToolsPickedIssuesTabView';
+import { useModToolsContext } from '../../ModToolsContext';
+import { ModToolsIssueInfoView } from './ModToolsIssueInfoView';
+import { ModToolsMyIssuesTabView } from './ModToolsMyIssuesTabView';
+import { ModToolsOpenIssuesTabView } from './ModToolsOpenIssuesTabView';
+import { ModToolsPickedIssuesTabView } from './ModToolsPickedIssuesTabView';
+
+interface ModToolsTicketsViewProps
+{
+ onCloseClick: () => void;
+}
const TABS: string[] = [
'Open Issues',
@@ -82,25 +86,21 @@ export const ModToolsTicketsView: FC = props =>
return (
<>
-
-
-
-
- { TABS.map((tab, index) =>
- {
- return ( setCurrentTab(index) }>
- { tab }
- );
- }) }
-
-
+
+
+
+ { TABS.map((tab, index) =>
+ {
+ return ( setCurrentTab(index) }>
+ { tab }
+ );
+ }) }
+
+
-
-
-
- {
- issueInfoWindows && issueInfoWindows.map(issueId => )
- }
+
+
+ { issueInfoWindows && (issueInfoWindows.length > 0) && issueInfoWindows.map(issueId => ) }
>
);
}
diff --git a/src/views/mod-tools/views/user/user-chatlog/ModToolsUserChatlogView.tsx b/src/components/mod-tools/views/user/ModToolsUserChatlogView.tsx
similarity index 50%
rename from src/views/mod-tools/views/user/user-chatlog/ModToolsUserChatlogView.tsx
rename to src/components/mod-tools/views/user/ModToolsUserChatlogView.tsx
index 705cc690..6a4f9d8a 100644
--- a/src/views/mod-tools/views/user/user-chatlog/ModToolsUserChatlogView.tsx
+++ b/src/components/mod-tools/views/user/ModToolsUserChatlogView.tsx
@@ -1,20 +1,20 @@
import { ChatRecordData, GetUserChatlogMessageComposer, UserChatlogEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react';
-import { CreateMessageHook, SendMessageHook } from '../../../../../hooks';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
-import { ChatlogView } from '../../chatlog/ChatlogView';
-import { ModToolsUserChatlogViewProps } from './ModToolsUserChatlogView.types';
+import { BatchUpdates, CreateMessageHook, SendMessageHook } from '../../../../hooks';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
+import { ChatlogView } from '../chatlog/ChatlogView';
+
+interface ModToolsUserChatlogViewProps
+{
+ userId: number;
+ onCloseClick: () => void;
+}
export const ModToolsUserChatlogView: FC = props =>
{
const { userId = null, onCloseClick = null } = props;
- const [userChatlog, setUserChatlog] = useState(null);
- const [username, setUsername] = useState(null);
-
- useEffect(() =>
- {
- SendMessageHook(new GetUserChatlogMessageComposer(userId));
- }, [userId]);
+ const [ userChatlog, setUserChatlog ] = useState(null);
+ const [ username, setUsername ] = useState(null);
const onModtoolUserChatlogEvent = useCallback((event: UserChatlogEvent) =>
{
@@ -22,19 +22,26 @@ export const ModToolsUserChatlogView: FC = props =
if(!parser || parser.data.userId !== userId) return;
- setUsername(parser.data.username);
- setUserChatlog(parser.data.roomChatlogs);
- }, [setUsername, setUserChatlog, userId]);
+ BatchUpdates(() =>
+ {
+ setUsername(parser.data.username);
+ setUserChatlog(parser.data.roomChatlogs);
+ });
+ }, [ userId ]);
CreateMessageHook(UserChatlogEvent, onModtoolUserChatlogEvent);
+ useEffect(() =>
+ {
+ SendMessageHook(new GetUserChatlogMessageComposer(userId));
+ }, [ userId ]);
+
return (
-
- onCloseClick()} />
+
+
- {userChatlog &&
-
- }
+ { userChatlog &&
+ }
);
diff --git a/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx b/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx
new file mode 100644
index 00000000..ba291fe4
--- /dev/null
+++ b/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx
@@ -0,0 +1,182 @@
+import { CallForHelpTopicData, DefaultSanctionMessageComposer, ModAlertMessageComposer, ModBanMessageComposer, ModKickMessageComposer, ModMessageMessageComposer, ModMuteMessageComposer, ModTradingLockMessageComposer } from '@nitrots/nitro-renderer';
+import { FC, useMemo, useState } from 'react';
+import { LocalizeText } from '../../../../api';
+import { Button, Column, Flex, Text } from '../../../../common';
+import { SendMessageHook } from '../../../../hooks';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
+import { NotificationAlertType } from '../../../../views/notification-center/common/NotificationAlertType';
+import { NotificationUtilities } from '../../../../views/notification-center/common/NotificationUtilities';
+import { useModToolsContext } from '../../ModToolsContext';
+import { ISelectedUser } from '../../utils/ISelectedUser';
+import { ModActionDefinition } from '../../utils/ModActionDefinition';
+
+interface ModToolsUserModActionViewProps
+{
+ user: ISelectedUser;
+ onCloseClick: () => void;
+}
+
+const MOD_ACTION_DEFINITIONS = [
+ new ModActionDefinition(1, 'Alert', ModActionDefinition.ALERT, 1, 0),
+ new ModActionDefinition(2, 'Mute 1h', ModActionDefinition.MUTE, 2, 0),
+ new ModActionDefinition(4, 'Ban 7 days', ModActionDefinition.BAN, 4, 0),
+ new ModActionDefinition(3, 'Ban 18h', ModActionDefinition.BAN, 3, 0),
+ new ModActionDefinition(5, 'Ban 30 days (step 1)', ModActionDefinition.BAN, 5, 0),
+ new ModActionDefinition(7, 'Ban 30 days (step 2)', ModActionDefinition.BAN, 7, 0),
+ new ModActionDefinition(6, 'Ban 100 years', ModActionDefinition.BAN, 6, 0),
+ new ModActionDefinition(106, 'Ban avatar-only 100 years', ModActionDefinition.BAN, 6, 0),
+ new ModActionDefinition(101, 'Kick', ModActionDefinition.KICK, 0, 0),
+ new ModActionDefinition(102, 'Lock trade 1 week', ModActionDefinition.TRADE_LOCK, 0, 168),
+ new ModActionDefinition(104, 'Lock trade permanent', ModActionDefinition.TRADE_LOCK, 0, 876000),
+ new ModActionDefinition(105, 'Message', ModActionDefinition.MESSAGE, 0, 0),
+];
+
+export const ModToolsUserModActionView: FC = props =>
+{
+ const { user = null, onCloseClick = null } = props;
+ const [ selectedTopic, setSelectedTopic ] = useState(-1);
+ const [ selectedAction, setSelectedAction ] = useState(-1);
+ const [ message, setMessage ] = useState('');
+ const { modToolsState = null } = useModToolsContext();
+ const { cfhCategories = null, settings = null } = modToolsState;
+
+ const topics = useMemo(() =>
+ {
+ const values: CallForHelpTopicData[] = [];
+
+ if(cfhCategories && cfhCategories.length)
+ {
+ for(const category of cfhCategories)
+ {
+ for(const topic of category.topics) values.push(topic);
+ }
+ }
+
+ return values;
+ }, [ cfhCategories ]);
+
+ const sendAlert = (message: string) =>
+ {
+ NotificationUtilities.simpleAlert(message, NotificationAlertType.DEFAULT, null, null, 'Error');
+ }
+
+ const sendDefaultSanction = () =>
+ {
+ SendMessageHook(new DefaultSanctionMessageComposer(user.userId, selectedTopic, message));
+
+ onCloseClick();
+ }
+
+ const sendSanction = () =>
+ {
+ let errorMessage: string = null;
+
+ const category = topics[selectedTopic];
+ const sanction = MOD_ACTION_DEFINITIONS[selectedAction];
+
+ if((selectedTopic === -1) || (selectedAction === -1)) errorMessage = 'You must select a CFH topic and Sanction';
+ else if(!settings || !settings.cfhPermission) errorMessage = 'You do not have permission to do this';
+ else if(!category) errorMessage = 'You must select a CFH topic';
+ else if(!sanction) errorMessage = 'You must select a sanction';
+
+ if(errorMessage)
+ {
+ sendAlert('You must select a sanction');
+
+ return;
+ }
+
+ const messageOrDefault = (message.trim().length === 0) ? LocalizeText(`help.cfh.topic.${ category.id }`) : message;
+
+ switch(sanction.actionType)
+ {
+ case ModActionDefinition.ALERT: {
+ if(!settings.alertPermission)
+ {
+ sendAlert('You have insufficient permissions');
+
+ return;
+ }
+
+ if(message.trim().length === 0)
+ {
+ sendAlert('Please write a message to user');
+
+ return;
+ }
+
+ SendMessageHook(new ModAlertMessageComposer(user.userId, message, category.id));
+ break;
+ }
+ case ModActionDefinition.MUTE:
+ SendMessageHook(new ModMuteMessageComposer(user.userId, messageOrDefault, category.id));
+ break;
+ case ModActionDefinition.BAN: {
+ if(!settings.banPermission)
+ {
+ sendAlert('You have insufficient permissions');
+
+ return;
+ }
+
+ SendMessageHook(new ModBanMessageComposer(user.userId, messageOrDefault, category.id, selectedAction, (sanction.actionId === 106)));
+ break;
+ }
+ case ModActionDefinition.KICK: {
+ if(!settings.kickPermission)
+ {
+ sendAlert('You have insufficient permissions');
+ return;
+ }
+
+ SendMessageHook(new ModKickMessageComposer(user.userId, messageOrDefault, category.id));
+ break;
+ }
+ case ModActionDefinition.TRADE_LOCK: {
+ const numSeconds = (sanction.actionLengthHours * 60);
+
+ SendMessageHook(new ModTradingLockMessageComposer(user.userId, messageOrDefault, numSeconds, category.id));
+ break;
+ }
+ case ModActionDefinition.MESSAGE: {
+ if(message.trim().length === 0)
+ {
+ sendAlert('Please write a message to user');
+
+ return;
+ }
+
+ SendMessageHook(new ModMessageMessageComposer(user.userId, message, category.id));
+ break;
+ }
+ }
+
+ onCloseClick();
+ }
+
+ if(!user) return null;
+
+ return (
+
+ onCloseClick() } />
+
+
+
+
+ Optional message type, overrides default
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/mod-tools/views/user/ModToolsUserRoomVisitsView.tsx b/src/components/mod-tools/views/user/ModToolsUserRoomVisitsView.tsx
new file mode 100644
index 00000000..2797bb38
--- /dev/null
+++ b/src/components/mod-tools/views/user/ModToolsUserRoomVisitsView.tsx
@@ -0,0 +1,85 @@
+import { GetRoomVisitsMessageComposer, RoomVisitsData, RoomVisitsEvent } from '@nitrots/nitro-renderer';
+import { FC, useCallback, useEffect, useState } from 'react';
+import { AutoSizer, List, ListRowProps } from 'react-virtualized';
+import { TryVisitRoom } from '../../../../api';
+import { Base, Column, Grid, Text } from '../../../../common';
+import { CreateMessageHook, SendMessageHook } from '../../../../hooks';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
+
+interface ModToolsUserRoomVisitsViewProps
+{
+ userId: number;
+ onCloseClick: () => void;
+}
+
+export const ModToolsUserRoomVisitsView: FC = props =>
+{
+ const { userId = null, onCloseClick = null } = props;
+ const [ roomVisitData, setRoomVisitData ] = useState(null);
+
+ const onModtoolReceivedRoomsUserEvent = useCallback((event: RoomVisitsEvent) =>
+ {
+ const parser = event.getParser();
+
+ if(!parser || (parser.data.userId !== userId)) return;
+
+ setRoomVisitData(parser.data);
+ }, [ userId ]);
+
+ CreateMessageHook(RoomVisitsEvent, onModtoolReceivedRoomsUserEvent);
+
+ const RowRenderer = (props: ListRowProps) =>
+ {
+ const item = roomVisitData.rooms[props.index];
+
+ return (
+
+ { item.enterHour.toString().padStart(2, '0') }: { item.enterMinute.toString().padStart(2, '0') }
+ { item.roomName }
+ TryVisitRoom(item.roomId) }>Visit Room
+
+ );
+ }
+
+ useEffect(() =>
+ {
+ SendMessageHook(new GetRoomVisitsMessageComposer(userId));
+ }, [userId]);
+
+ if(!userId) return null;
+
+ return (
+
+
+
+
+
+
+ Time
+ Room name
+ Visit
+
+
+
+ { roomVisitData &&
+
+ { ({ height, width }) =>
+ {
+ return (
+
+ );
+ } }
+ }
+
+
+
+
+ );
+}
diff --git a/src/components/mod-tools/views/user/ModToolsUserSendMessageView.tsx b/src/components/mod-tools/views/user/ModToolsUserSendMessageView.tsx
new file mode 100644
index 00000000..11473850
--- /dev/null
+++ b/src/components/mod-tools/views/user/ModToolsUserSendMessageView.tsx
@@ -0,0 +1,46 @@
+import { ModMessageMessageComposer } from '@nitrots/nitro-renderer';
+import { FC, useCallback, useState } from 'react';
+import { Button, Text } from '../../../../common';
+import { NotificationAlertEvent } from '../../../../events';
+import { dispatchUiEvent, SendMessageHook } from '../../../../hooks';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
+import { ISelectedUser } from '../../utils/ISelectedUser';
+
+interface ModToolsUserSendMessageViewProps
+{
+ user: ISelectedUser;
+ onCloseClick: () => void;
+}
+
+export const ModToolsUserSendMessageView: FC = props =>
+{
+ const { user = null, onCloseClick = null } = props;
+ const [ message, setMessage ] = useState('');
+
+ const sendMessage = useCallback(() =>
+ {
+ if(message.trim().length === 0)
+ {
+ dispatchUiEvent(new NotificationAlertEvent([ 'Please write a message to user.' ], null, null, null, 'Error', null));
+
+ return;
+ }
+
+ SendMessageHook(new ModMessageMessageComposer(user.userId, message, -999));
+
+ onCloseClick();
+ }, [ message, user, onCloseClick ]);
+
+ if(!user) return null;
+
+ return (
+
+ onCloseClick() } />
+
+ Message To: { user.username }
+
+
+
+
+ );
+}
diff --git a/src/views/mod-tools/views/user/user-info/ModToolsUserView.tsx b/src/components/mod-tools/views/user/ModToolsUserView.tsx
similarity index 72%
rename from src/views/mod-tools/views/user/user-info/ModToolsUserView.tsx
rename to src/components/mod-tools/views/user/ModToolsUserView.tsx
index 24f8c876..3203658f 100644
--- a/src/views/mod-tools/views/user/user-info/ModToolsUserView.tsx
+++ b/src/components/mod-tools/views/user/ModToolsUserView.tsx
@@ -1,13 +1,19 @@
import { FriendlyTime, GetModeratorUserInfoMessageComposer, ModeratorUserInfoData, ModeratorUserInfoEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
-import { LocalizeText } from '../../../../../api';
-import { ModToolsOpenUserChatlogEvent } from '../../../../../events/mod-tools/ModToolsOpenUserChatlogEvent';
-import { CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../../hooks';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutButton, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../../layout';
-import { ModToolsUserModActionView } from '../user-mod-action/ModToolsUserModActionView';
-import { ModToolsUserRoomVisitsView } from '../user-room-visits/ModToolsUserRoomVisitsView';
-import { ModToolsSendUserMessageView } from '../user-sendmessage/ModToolsSendUserMessageView';
-import { ModToolsUserViewProps } from './ModToolsUserView.types';
+import { LocalizeText } from '../../../../api';
+import { Button, Column, Grid } from '../../../../common';
+import { ModToolsOpenUserChatlogEvent } from '../../../../events/mod-tools/ModToolsOpenUserChatlogEvent';
+import { CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../hooks';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
+import { ModToolsUserModActionView } from './ModToolsUserModActionView';
+import { ModToolsUserRoomVisitsView } from './ModToolsUserRoomVisitsView';
+import { ModToolsUserSendMessageView } from './ModToolsUserSendMessageView';
+
+interface ModToolsUserViewProps
+{
+ userId: number;
+ onCloseClick: () => void;
+}
export const ModToolsUserView: FC = props =>
{
@@ -17,11 +23,6 @@ export const ModToolsUserView: FC = props =>
const [ modActionVisible, setModActionVisible ] = useState(false);
const [ roomVisitsVisible, setRoomVisitsVisible ] = useState(false);
- useEffect(() =>
- {
- SendMessageHook(new GetModeratorUserInfoMessageComposer(userId));
- }, [ userId ]);
-
const onModtoolUserInfoEvent = useCallback((event: ModeratorUserInfoEvent) =>
{
const parser = event.getParser();
@@ -29,7 +30,7 @@ export const ModToolsUserView: FC = props =>
if(!parser || parser.data.userId !== userId) return;
setUserInfo(parser.data);
- }, [setUserInfo, userId]);
+ }, [ userId ]);
CreateMessageHook(ModeratorUserInfoEvent, onModtoolUserInfoEvent);
@@ -98,52 +99,58 @@ export const ModToolsUserView: FC = props =>
];
}, [ userInfo ]);
+ useEffect(() =>
+ {
+ SendMessageHook(new GetModeratorUserInfoMessageComposer(userId));
+ }, [ userId ]);
+
if(!userInfo) return null;
return (
<>
-
+
onCloseClick() } />
-
-
+
+
{ userProperties.map( (property, index) =>
{
return (
-
+
{ LocalizeText(property.localeKey) } |
{ property.value }
- { property.showOnline && }
- |
+ { property.showOnline &&
+ }
+
);
}) }
-
-
- dispatchUiEvent(new ModToolsOpenUserChatlogEvent(userId)) }>
+
+
+
+
+
+
+
+
{ sendMessageVisible &&
- setSendMessageVisible(false) } /> }
+ setSendMessageVisible(false) } /> }
{ modActionVisible &&
setModActionVisible(false) } /> }
{ roomVisitsVisible &&
diff --git a/src/views/purse/context/PurseContext.tsx b/src/components/purse/PurseContext.tsx
similarity index 50%
rename from src/views/purse/context/PurseContext.tsx
rename to src/components/purse/PurseContext.tsx
index b843f42c..1999abdd 100644
--- a/src/views/purse/context/PurseContext.tsx
+++ b/src/components/purse/PurseContext.tsx
@@ -1,11 +1,16 @@
-import { createContext, FC, useContext } from 'react';
-import { IPurseContext, PurseContextProps } from './PurseContext.types';
+import { createContext, FC, ProviderProps, useContext } from 'react';
+import { IPurse } from './common/IPurse';
+
+interface IPurseContext
+{
+ purse: IPurse;
+}
const PurseContext = createContext({
purse: null
});
-export const PurseContextProvider: FC = props =>
+export const PurseContextProvider: FC> = props =>
{
return { props.children }
}
diff --git a/src/views/purse/PurseMessageHandler.tsx b/src/components/purse/PurseMessageHandler.tsx
similarity index 92%
rename from src/views/purse/PurseMessageHandler.tsx
rename to src/components/purse/PurseMessageHandler.tsx
index 07ca8f09..3002b26a 100644
--- a/src/views/purse/PurseMessageHandler.tsx
+++ b/src/components/purse/PurseMessageHandler.tsx
@@ -2,10 +2,9 @@ import { ActivityPointNotificationMessageEvent, UserCreditsEvent, UserCurrencyEv
import { FC, useCallback } from 'react';
import { CREDITS, DUCKETS, PlaySound } from '../../api/utils/PlaySound';
import { CreateMessageHook } from '../../hooks/messages/message-event';
-import { usePurseContext } from './context/PurseContext';
-import { PurseMessageHandlerProps } from './PurseMessageHandler.types';
+import { usePurseContext } from './PurseContext';
-export const PurseMessageHandler: FC = props =>
+export const PurseMessageHandler: FC<{}> = props =>
{
const { purse = null } = usePurseContext();
diff --git a/src/components/purse/PurseView.scss b/src/components/purse/PurseView.scss
new file mode 100644
index 00000000..a860c41a
--- /dev/null
+++ b/src/components/purse/PurseView.scss
@@ -0,0 +1,26 @@
+.nitro-purse-container {
+ font-size: $font-size-sm;
+ pointer-events: all;
+
+ .nitro-purse {
+ background-color: rgba($dark, 0.95);
+ box-shadow: inset 0px 5px lighten(rgba($dark, 0.6), 2.5), inset 0 -4px darken(rgba($dark, 0.6), 4);
+
+ .nitro-purse-subscription {
+ background-color: rgba($light, 0.1);
+ }
+
+ .nitro-purse-button {
+ padding: 3px 2px;
+
+ &:hover {
+ background-color: rgba($light, 0.1);
+ }
+ }
+ }
+
+ .nitro-purse-seasonal-currency {
+ background-color: rgba($dark, .95);
+ box-shadow: inset 0px 5px lighten(rgba($dark, .6),2.5), inset 0 -4px darken(rgba($dark, .6), 4);
+ }
+}
diff --git a/src/components/purse/PurseView.tsx b/src/components/purse/PurseView.tsx
new file mode 100644
index 00000000..6c7cc299
--- /dev/null
+++ b/src/components/purse/PurseView.tsx
@@ -0,0 +1,137 @@
+import { FriendlyTime, HabboClubLevelEnum, UserCurrencyComposer, UserSubscriptionComposer } from '@nitrots/nitro-renderer';
+import { FC, useCallback, useEffect, useMemo, useState } from 'react';
+import { CreateLinkEvent, GetConfiguration, LocalizeText } from '../../api';
+import { Column, Flex, Grid, Text } from '../../common';
+import { HcCenterEvent } from '../../events/hc-center/HcCenterEvent';
+import { UserSettingsUIEvent } from '../../events/user-settings/UserSettingsUIEvent';
+import { dispatchUiEvent } from '../../hooks';
+import { SendMessageHook } from '../../hooks/messages/message-event';
+import { CurrencyIcon } from '../../views/shared/currency-icon/CurrencyIcon';
+import { IPurse } from './common/IPurse';
+import { Purse } from './common/Purse';
+import { PurseContextProvider } from './PurseContext';
+import { PurseMessageHandler } from './PurseMessageHandler';
+import { CurrencyView } from './views/CurrencyView';
+import { SeasonalView } from './views/SeasonalView';
+
+export let GLOBAL_PURSE: IPurse = null;
+
+export const PurseView: FC<{}> = props =>
+{
+ const [ purse, setPurse ] = useState(new Purse());
+ const [ updateId, setUpdateId ] = useState(-1);
+
+ const handleUserSettingsClick = () => dispatchUiEvent(new UserSettingsUIEvent(UserSettingsUIEvent.TOGGLE_USER_SETTINGS));
+
+ const handleHelpCenterClick = () => CreateLinkEvent('help/show');
+
+ const handleHcCenterClick = () => dispatchUiEvent(new HcCenterEvent(HcCenterEvent.TOGGLE_HC_CENTER));
+
+ const displayedCurrencies = useMemo(() => GetConfiguration('system.currency.types', []), []);
+
+ const currencyDisplayNumberShort = useMemo(() => GetConfiguration('currency.display.number.short', false), []);
+
+ const getClubText = useMemo(() =>
+ {
+ const totalDays = ((purse.clubPeriods * 31) + purse.clubDays);
+ const minutesUntilExpiration = purse.minutesUntilExpiration;
+
+ if(purse.clubLevel === HabboClubLevelEnum.NO_CLUB) return LocalizeText('purse.clubdays.zero.amount.text');
+
+ else if((minutesUntilExpiration > -1) && (minutesUntilExpiration < (60 * 24))) return FriendlyTime.shortFormat(minutesUntilExpiration * 60);
+
+ else return FriendlyTime.shortFormat(totalDays * 86400);
+ }, [ purse ]);
+
+ const getCurrencyElements = useCallback((offset: number, limit: number = -1, seasonal: boolean = false) =>
+ {
+ if(!purse.activityPoints.size) return null;
+
+ const types = Array.from(purse.activityPoints.keys()).filter(type => (displayedCurrencies.indexOf(type) >= 0));
+
+ let count = 0;
+
+ while(count < offset)
+ {
+ types.shift();
+
+ count++;
+ }
+
+ count = 0;
+
+ const elements: JSX.Element[] = [];
+
+ for(const type of types)
+ {
+ if((limit > -1) && (count === limit)) break;
+
+ if(seasonal) elements.push();
+ else elements.push();
+
+ count++;
+ }
+
+ return elements;
+ }, [ purse, displayedCurrencies, currencyDisplayNumberShort ]);
+
+ useEffect(() =>
+ {
+ const purse = new Purse();
+
+ GLOBAL_PURSE = purse;
+
+ purse.notifier = () => setUpdateId(prevValue => (prevValue + 1));
+
+ setPurse(purse);
+
+ return () => (purse.notifier = null);
+ }, []);
+
+ useEffect(() =>
+ {
+ if(!purse) return;
+
+ SendMessageHook(new UserCurrencyComposer());
+ }, [ purse ]);
+
+ useEffect(() =>
+ {
+ SendMessageHook(new UserSubscriptionComposer('habbo_club'));
+
+ const interval = setInterval(() => SendMessageHook(new UserSubscriptionComposer('habbo_club')), 50000);
+
+ return () => clearInterval(interval);
+ }, [ purse ]);
+
+ if(!purse) return null;
+
+ return (
+
+
+
+
+
+
+
+ { getCurrencyElements(0, 2) }
+
+
+
+ { getClubText }
+
+
+
+
+
+
+
+
+
+
+
+ { getCurrencyElements(2, -1, true) }
+
+
+ );
+}
diff --git a/src/views/purse/common/CurrencyHelper.ts b/src/components/purse/common/CurrencyHelper.ts
similarity index 100%
rename from src/views/purse/common/CurrencyHelper.ts
rename to src/components/purse/common/CurrencyHelper.ts
diff --git a/src/views/purse/common/IPurse.ts b/src/components/purse/common/IPurse.ts
similarity index 100%
rename from src/views/purse/common/IPurse.ts
rename to src/components/purse/common/IPurse.ts
diff --git a/src/views/purse/common/Purse.ts b/src/components/purse/common/Purse.ts
similarity index 100%
rename from src/views/purse/common/Purse.ts
rename to src/components/purse/common/Purse.ts
diff --git a/src/components/purse/views/CurrencyView.tsx b/src/components/purse/views/CurrencyView.tsx
new file mode 100644
index 00000000..27004784
--- /dev/null
+++ b/src/components/purse/views/CurrencyView.tsx
@@ -0,0 +1,40 @@
+import { FC, useMemo } from 'react';
+import { OverlayTrigger, Tooltip } from 'react-bootstrap';
+import { LocalizeFormattedNumber, LocalizeShortNumber } from '../../../api';
+import { Flex, Text } from '../../../common';
+import { CurrencyIcon } from '../../../views/shared/currency-icon/CurrencyIcon';
+
+interface CurrencyViewProps
+{
+ type: number;
+ amount: number;
+ short: boolean;
+}
+
+export const CurrencyView: FC = props =>
+{
+ const { type = -1, amount = -1, short = false } = props;
+
+ const element = useMemo(() =>
+ {
+ return (
+
+ { short ? LocalizeShortNumber(amount) : LocalizeFormattedNumber(amount) }
+
+ );
+ }, [ amount, short, type ]);
+
+ if(!short) return element;
+
+ return (
+
+ { LocalizeFormattedNumber(amount) }
+
+ }>
+ { element }
+
+ );
+}
diff --git a/src/components/purse/views/SeasonalView.tsx b/src/components/purse/views/SeasonalView.tsx
new file mode 100644
index 00000000..49cc8930
--- /dev/null
+++ b/src/components/purse/views/SeasonalView.tsx
@@ -0,0 +1,25 @@
+import { FC } from 'react';
+import { LocalizeFormattedNumber, LocalizeText } from '../../../api';
+import { Flex, Text } from '../../../common';
+import { CurrencyIcon } from '../../../views/shared/currency-icon/CurrencyIcon';
+
+interface SeasonalViewProps
+{
+ type: number;
+ amount: number;
+}
+
+export const SeasonalView: FC = props =>
+{
+ const { type = -1, amount = -1 } = props;
+
+ return (
+
+ { LocalizeText(`purse.seasonal.currency.${ type }`) }
+
+ { LocalizeFormattedNumber(amount) }
+
+
+
+ );
+}
diff --git a/src/views/right-side/RightSideView.scss b/src/components/right-side/RightSideView.scss
similarity index 100%
rename from src/views/right-side/RightSideView.scss
rename to src/components/right-side/RightSideView.scss
diff --git a/src/components/right-side/RightSideView.tsx b/src/components/right-side/RightSideView.tsx
new file mode 100644
index 00000000..51a1eae8
--- /dev/null
+++ b/src/components/right-side/RightSideView.tsx
@@ -0,0 +1,18 @@
+import { FC } from 'react';
+import { Column } from '../../common';
+import { NotificationCenterView } from '../../views/notification-center/NotificationCenterView';
+import { GroupRoomInformationView } from '../groups/views/room-information/GroupRoomInformationView';
+import { PurseView } from '../purse/PurseView';
+
+export const RightSideView: FC<{}> = props =>
+{
+ return (
+
+ );
+}
diff --git a/src/views/room-host/RoomHostView.tsx b/src/components/room-host/RoomHostView.tsx
similarity index 93%
rename from src/views/room-host/RoomHostView.tsx
rename to src/components/room-host/RoomHostView.tsx
index 5e1d15f6..5fee567f 100644
--- a/src/views/room-host/RoomHostView.tsx
+++ b/src/components/room-host/RoomHostView.tsx
@@ -1,10 +1,11 @@
import { IRoomSession, RoomEngineEvent, RoomId, RoomSessionEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { GetRoomSession, SetActiveRoomId, StartRoomSession } from '../../api';
+import { Base } from '../../common';
import { useRoomEngineEvent } from '../../hooks/events/nitro/room/room-engine-event';
import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event';
import { TransitionAnimation, TransitionAnimationTypes } from '../../layout';
-import { RoomView } from '../room/RoomView';
+import { RoomView } from '../../views/room/RoomView';
export const RoomHostView: FC<{}> = props =>
{
@@ -51,9 +52,9 @@ export const RoomHostView: FC<{}> = props =>
return (
-
+
-
+
);
}
diff --git a/src/components/toolbar/ToolbarMeView.tsx b/src/components/toolbar/ToolbarMeView.tsx
index 4d9f3e4d..25253509 100644
--- a/src/components/toolbar/ToolbarMeView.tsx
+++ b/src/components/toolbar/ToolbarMeView.tsx
@@ -1,6 +1,7 @@
import { RoomObjectCategory } from '@nitrots/nitro-renderer';
import { FC, useEffect } from 'react';
import { GetRoomEngine, GetRoomSession } from '../../api';
+import { Base, Flex } from '../../common';
import { ItemCountView } from '../../views/shared/item-count/ItemCountView';
import { ToolbarViewItems } from './common/ToolbarViewItems';
@@ -24,35 +25,15 @@ export const ToolbarMeView: FC = props =>
}, []);
return (
-
-
-
-
-
-
-
-
-
handleToolbarItemClick(ToolbarViewItems.ACHIEVEMENTS_ITEM) }>
-
- { (unseenAchievementCount > 0) &&
- }
-
-
handleToolbarItemClick(ToolbarViewItems.PROFILE_ITEM) }>
-
-
-
-
-
-
handleToolbarItemClick(ToolbarViewItems.CLOTHING_ITEM) }>
-
-
-
-
-
-
handleToolbarItemClick(ToolbarViewItems.SETTINGS_ITEM) }>
-
-
-
-
+
+ handleToolbarItemClick(ToolbarViewItems.ACHIEVEMENTS_ITEM) }>
+ { (unseenAchievementCount > 0) &&
+ }
+
+ handleToolbarItemClick(ToolbarViewItems.PROFILE_ITEM) } />
+
+ handleToolbarItemClick(ToolbarViewItems.CLOTHING_ITEM) } />
+ handleToolbarItemClick(ToolbarViewItems.SETTINGS_ITEM) } />
+
);
}
diff --git a/src/components/toolbar/ToolbarView.scss b/src/components/toolbar/ToolbarView.scss
index 0b7fb99a..ad910648 100644
--- a/src/components/toolbar/ToolbarView.scss
+++ b/src/components/toolbar/ToolbarView.scss
@@ -1,111 +1,67 @@
-.nitro-toolbar-container {
+.nitro-toolbar {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: $toolbar-height;
z-index: $toolbar-zindex;
+ pointer-events: all;
+ background: rgba($dark, 0.95);
+ box-shadow: inset 0px 5px lighten(rgba($dark, 0.6), 2.5),
+ inset 0 -4px darken(rgba($dark, 0.6), 4);
- .nitro-toolbar {
- height: 100%;
- pointer-events: all;
- background: rgba($dark, 0.95);
- box-shadow: inset 0px 5px lighten(rgba($dark, 0.6), 2.5),
- inset 0 -4px darken(rgba($dark, 0.6), 4);
+ .navigation-item {
- #toolbar-chat-input-container {
- margin: 0 10px;
-
- @include media-breakpoint-down(sm) {
- width: 0px;
- height: 0px;
+ &.item-avatar {
+ width: 50px;
+ height: 45px;
+ overflow: hidden;
+
+ .avatar-image {
+ margin-left: -5px;
+ margin-top: 25px;
}
}
- .navigation-items {
- display: flex;
- align-items: center;
-
- &.navigation-avatar {
- border-right: 1px solid rgba(0, 0, 0, 0.3);
- }
-
- .navigation-item {
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- //margin: 0 1px;
- position: relative;
-
- &.item-avatar {
- width: 50px;
- height: 45px;
- overflow: hidden;
-
- .avatar-image {
- margin-left: -5px;
- margin-top: 25px;
- }
- }
-
- .icon,
- &.item-avatar {
- position: relative;
- //transition: transform .2s ease-out;
-
- &:hover,
- &.active {
- -webkit-transform: translate(-1px, -1px);
- transform: translate(-1px, -1px);
- filter: drop-shadow(2px 2px 0 rgba($black, 0.8));
- }
- }
-
- .avatar-image {
- pointer-events: none;
- }
-
- .chat-input-container {
- left: 60px;
- }
- }
+ &:hover {
+ -webkit-transform: translate(-1px, -1px);
+ transform: translate(-1px, -1px);
+ filter: drop-shadow(2px 2px 0 rgba($black, 0.8));
}
- .nitro-toolbar-me-menu {
- bottom: 77px;
- left: 200px;
- position: absolute;
- font-size: 12px;
- z-index: $toolbar-memenu-zindex;
+ &.active,
+ &:active {
+ -webkit-transform: translate(0px, 0px);
+ transform: translate(0px, 0px);
+ filter: drop-shadow(2px 2px 0 rgba($black, 0.8));
+ }
+ }
- .list-group {
- .list-group-item {
- min-width: 70px;
- transition: all 0.3s;
- font-size: 10px;
- text-align: center;
+ #toolbar-chat-input-container {
- i {
- filter: grayscale(1);
- }
+ @include media-breakpoint-down(sm) {
+ width: 0px;
+ height: 0px;
+ }
+ }
+}
- &:hover {
- color: $cyan;
- text-decoration: underline;
+.nitro-toolbar-me {
+ position: absolute;
+ bottom: 60px;
+ left: 15px;
+ z-index: $toolbar-memenu-zindex;
+ background: rgba(20, 20, 20, .95);
+ border: 1px solid #101010;
+ box-shadow: inset 2px 2px rgba(255, 255, 255, .1), inset -2px -2px rgba(255, 255, 255, .1);
+ border-radius: $border-radius;
- i {
- filter: grayscale(0);
- }
- }
+ .navigation-item {
+ transition: filter .2s ease-out;
+ filter: grayscale(1);
- .count {
- top: 0px;
- right: 5px;
- font-size: 10px;
- }
- }
- }
+ &:hover {
+ filter: grayscale(0) drop-shadow(2px 2px 0 rgba($black, 0.8));
}
}
}
@@ -122,45 +78,3 @@
drop-shadow(-2px 1px 0 rgba($white, 1))
drop-shadow(0 -2px 0 rgba($white, 1));
}
-
-.nitro-toolbar-me {
- position: absolute;
- bottom: 65px;
- left: 15px;
- z-index: $toolbar-me-zindex;
- background: rgba(20, 20, 20, .95);
- border: 1px solid #101010;
- box-shadow: inset 2px 2px rgba(255, 255, 255, .1), inset -2px -2px rgba(255, 255, 255, .1);
- border-radius: $border-radius;
-
- .navigation-items {
- display: flex;
- align-items: center;
-
- &.navigation-avatar {
- border-right: 1px solid rgba(0, 0, 0, .3);
- }
-
- .navigation-item {
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-direction: column;
- cursor: pointer;
- width: 50px;
- font-size: 11px;
-
- .icon {
- transition: filter .2s ease-out;
- filter: grayscale(1);
- }
-
- &:hover {
- .icon {
- filter: grayscale(0) drop-shadow(2px 2px 0 rgba($black, 0.8));
- }
- }
- }
- }
-}
diff --git a/src/components/toolbar/ToolbarView.tsx b/src/components/toolbar/ToolbarView.tsx
index 4b52ac03..3c72e368 100644
--- a/src/components/toolbar/ToolbarView.tsx
+++ b/src/components/toolbar/ToolbarView.tsx
@@ -1,6 +1,7 @@
import { Dispose, DropBounce, EaseOut, FigureUpdateEvent, JumpBy, Motions, NitroToolbarAnimateIconEvent, Queue, UserInfoDataParser, UserInfoEvent, Wait } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { CreateLinkEvent, GetRoomSession, GetRoomSessionManager, GetSessionDataManager, GetUserProfile, GoToDesktop, OpenMessengerChat } from '../../api';
+import { Base, Flex } from '../../common';
import { AvatarEditorEvent, FriendsEvent, FriendsMessengerIconEvent, FriendsRequestCountEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events';
import { AchievementsUIEvent, AchievementsUIUnseenCountEvent } from '../../events/achievements';
import { UnseenItemTrackerUpdateEvent } from '../../events/inventory/UnseenItemTrackerUpdateEvent';
@@ -181,64 +182,47 @@ export const ToolbarView: FC = props =>
}, []);
return (
-
+ <>
-
-
-
-
setMeExpanded(!isMeExpanded) }>
+
+
+
+ setMeExpanded(!isMeExpanded) }>
{ (unseenAchievementCount > 0) &&
}
-
- { isInRoom && (
-
-
-
) }
- { !isInRoom && (
-
CreateLinkEvent('navigator/goto/home') }>
-
-
) }
-
handleToolbarItemClick(ToolbarViewItems.NAVIGATOR_ITEM) }>
-
-
-
handleToolbarItemClick(ToolbarViewItems.CATALOG_ITEM) }>
-
-
-
handleToolbarItemClick(ToolbarViewItems.INVENTORY_ITEM) }>
-
+
+ { isInRoom &&
+ }
+ { !isInRoom &&
+ CreateLinkEvent('navigator/goto/home') } /> }
+ handleToolbarItemClick(ToolbarViewItems.NAVIGATOR_ITEM) } />
+ handleToolbarItemClick(ToolbarViewItems.CATALOG_ITEM) } />
+ handleToolbarItemClick(ToolbarViewItems.INVENTORY_ITEM) }>
{ (unseenInventoryCount > 0) &&
}
-
- { isInRoom && (
-
handleToolbarItemClick(ToolbarViewItems.CAMERA_ITEM) }>
-
-
) }
- { isMod && (
-
handleToolbarItemClick(ToolbarViewItems.MOD_TOOLS_ITEM) }>
-
-
) }
-
-
-
-
-
-
handleToolbarItemClick(ToolbarViewItems.FRIEND_LIST_ITEM) }>
-
+
+ { isInRoom &&
+ handleToolbarItemClick(ToolbarViewItems.CAMERA_ITEM) } /> }
+ { isMod &&
+ handleToolbarItemClick(ToolbarViewItems.MOD_TOOLS_ITEM) } /> }
+
+
+
+
+
+ handleToolbarItemClick(ToolbarViewItems.FRIEND_LIST_ITEM) }>
{ (unseenFriendRequestCount > 0) &&
}
-
+
{ ((chatIconType === CHAT_ICON_SHOWING) || (chatIconType === CHAT_ICON_UNREAD)) &&
-
handleToolbarItemClick(ToolbarViewItems.FRIEND_CHAT_ITEM) }>
- { (chatIconType === CHAT_ICON_SHOWING) && }
- { (chatIconType === CHAT_ICON_UNREAD) && }
-
}
-
-
-
-
-
+ handleToolbarItemClick(ToolbarViewItems.FRIEND_CHAT_ITEM) } /> }
+
+
+
+
+ >
);
}
diff --git a/src/components/toolbar/common/ToolbarViewItems.ts b/src/components/toolbar/common/ToolbarViewItems.ts
index 48a376d1..b527f531 100644
--- a/src/components/toolbar/common/ToolbarViewItems.ts
+++ b/src/components/toolbar/common/ToolbarViewItems.ts
@@ -1,8 +1,3 @@
-export interface ToolbarViewProps
-{
- isInRoom: boolean;
-}
-
export class ToolbarViewItems
{
public static NAVIGATOR_ITEM: string = 'TVI_NAVIGATOR_ITEM';
diff --git a/src/components/user-profile/UserProfileVew.scss b/src/components/user-profile/UserProfileVew.scss
new file mode 100644
index 00000000..5adc408a
--- /dev/null
+++ b/src/components/user-profile/UserProfileVew.scss
@@ -0,0 +1,106 @@
+.user-profile {
+ width: 560px;
+
+ .content-area {
+ color: black;
+ }
+
+ .user-container {
+ border-right: 1px solid gray;
+
+ .avatar-image {
+ left: -10px;
+ }
+
+ .add-friend {
+ margin: 5px;
+ margin-left: 10px;
+ }
+ }
+
+ .badge-container {
+ min-height: 50px;
+ background: rgba(0, 0, 0, 0.1);
+ border-radius: 5px;
+ margin: 0px;
+ margin-bottom: 2px;
+ }
+
+ .rooms-button-container {
+ border-top: 1px solid gray;
+ border-bottom: 1px solid gray;
+ padding: 1px;
+
+ .rooms-button {
+ display: inline-block;
+ text-align: center;
+ height: 100%;
+ text-decoration: underline;
+ margin-left: 10px;
+ }
+ }
+
+ .friends-container {
+ height: 100%;
+ }
+}
+
+.profile-groups {
+ height: 219px;
+
+ .profile-groups-item {
+ width: 50px;
+ height: 50px;
+ border-radius: $border-radius;
+ border-color: $grid-border-color !important;
+ background-color: $grid-bg-color;
+ border: nth(map-values($border-widths), 2) solid;
+
+ &.active {
+ border-color: $grid-active-border-color !important;
+ background-color: $grid-active-bg-color !important;
+ }
+
+ .icon {
+ z-index: 1;
+ top: 0px;
+ right: 0px;
+ }
+ }
+}
+
+.relationships-container {
+
+ .relationship-container {
+
+ .relationship
+ {
+ position: relative;
+
+ &.advanced {
+ background-color: white;
+ padding: 5px;
+ border-radius: 5px;
+ }
+
+ .relationship-text {
+ text-decoration: underline;
+ }
+
+ .avatar-image {
+ position: absolute;
+ width: 50px;
+ height: 80px;
+ right: 0;
+ margin-top: -60px;
+ }
+ }
+
+ .others-text {
+ margin-left: 20px;
+ height: 21px;
+ color: #939392;
+ }
+ }
+
+}
diff --git a/src/components/user-profile/UserProfileView.tsx b/src/components/user-profile/UserProfileView.tsx
new file mode 100644
index 00000000..30f2d9c6
--- /dev/null
+++ b/src/components/user-profile/UserProfileView.tsx
@@ -0,0 +1,104 @@
+import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, UserCurrentBadgesComposer, UserCurrentBadgesEvent, UserProfileEvent, UserProfileParser, UserRelationshipsComposer } from '@nitrots/nitro-renderer';
+import { FC, useCallback, useState } from 'react';
+import { GetSessionDataManager, GetUserProfile, LocalizeText } from '../../api';
+import { Column, Flex, Grid } from '../../common';
+import { BatchUpdates, CreateMessageHook, SendMessageHook } from '../../hooks';
+import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
+import { BadgesContainerView } from './views/BadgesContainerView';
+import { FriendsContainerView } from './views/FriendsContainerView';
+import { GroupsContainerView } from './views/GroupsContainerView';
+import { UserContainerView } from './views/UserContainerView';
+
+export const UserProfileView: FC<{}> = props =>
+{
+ const [ userProfile, setUserProfile ] = useState(null);
+ const [ userBadges, setUserBadges ] = useState([]);
+ const [ userRelationships, setUserRelationships ] = useState(null);
+
+ const onClose = () =>
+ {
+ BatchUpdates(() =>
+ {
+ setUserProfile(null);
+ setUserBadges([]);
+ setUserRelationships(null);
+ });
+ }
+
+ const onLeaveGroup = useCallback(() =>
+ {
+ if(userProfile && userProfile.id === GetSessionDataManager().userId)
+ {
+ GetUserProfile(userProfile.id);
+ }
+ }, [ userProfile ]);
+
+ const onUserCurrentBadgesEvent = useCallback((event: UserCurrentBadgesEvent) =>
+ {
+ const parser = event.getParser();
+
+ if(!userProfile || (parser.userId !== userProfile.id)) return;
+
+ setUserBadges(parser.badges);
+ }, [ userProfile ]);
+
+ CreateMessageHook(UserCurrentBadgesEvent, onUserCurrentBadgesEvent);
+
+ const OnUserRelationshipsEvent = useCallback((event: RelationshipStatusInfoEvent) =>
+ {
+ const parser = event.getParser();
+
+ if(!userProfile || (parser.userId !== userProfile.id)) return;
+
+ setUserRelationships(parser);
+ }, [ userProfile ]);
+
+ CreateMessageHook(RelationshipStatusInfoEvent, OnUserRelationshipsEvent);
+
+ const onUserProfileEvent = useCallback((event: UserProfileEvent) =>
+ {
+ const parser = event.getParser();
+
+ if(userProfile)
+ {
+ BatchUpdates(() =>
+ {
+ setUserProfile(null);
+ setUserBadges([]);
+ setUserRelationships(null);
+ });
+ }
+
+ setUserProfile(parser);
+
+ SendMessageHook(new UserCurrentBadgesComposer(parser.id));
+ SendMessageHook(new UserRelationshipsComposer(parser.id));
+ }, [ userProfile ]);
+
+ CreateMessageHook(UserProfileEvent, onUserProfileEvent);
+
+ if(!userProfile) return null;
+
+ return (
+
+
+
+
+
+
+
+
+
+ {
+ userRelationships &&
+ }
+
+
+
+ {LocalizeText('extendedprofile.rooms')}
+
+
+
+
+ )
+}
diff --git a/src/views/user-profile/views/badges-container/BadgesContainerView.tsx b/src/components/user-profile/views/BadgesContainerView.tsx
similarity index 81%
rename from src/views/user-profile/views/badges-container/BadgesContainerView.tsx
rename to src/components/user-profile/views/BadgesContainerView.tsx
index 982058f8..14794c30 100644
--- a/src/views/user-profile/views/badges-container/BadgesContainerView.tsx
+++ b/src/components/user-profile/views/BadgesContainerView.tsx
@@ -1,7 +1,11 @@
import { FC } from 'react';
-import { NitroCardGridItemView, NitroCardGridView } from '../../../../layout';
-import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
-import { BadgesContainerViewProps } from './BadgesContainerView.types';
+import { NitroCardGridItemView, NitroCardGridView } from '../../../layout';
+import { BadgeImageView } from '../../../views/shared/badge-image/BadgeImageView';
+
+interface BadgesContainerViewProps
+{
+ badges: string[];
+}
export const BadgesContainerView: FC = props =>
{
diff --git a/src/views/user-profile/views/friends-container/FriendsContainerView.tsx b/src/components/user-profile/views/FriendsContainerView.tsx
similarity index 68%
rename from src/views/user-profile/views/friends-container/FriendsContainerView.tsx
rename to src/components/user-profile/views/FriendsContainerView.tsx
index b76457ac..b206fc80 100644
--- a/src/views/user-profile/views/friends-container/FriendsContainerView.tsx
+++ b/src/components/user-profile/views/FriendsContainerView.tsx
@@ -1,7 +1,13 @@
+import { RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer';
import { FC } from 'react';
-import { LocalizeText } from '../../../../api';
-import { RelationshipsContainerView } from '../relationships-container/RelationshipsContainerView';
-import { FriendsContainerViewProps } from './FriendsContainerView.types';
+import { LocalizeText } from '../../../api';
+import { RelationshipsContainerView } from './RelationshipsContainerView';
+
+interface FriendsContainerViewProps
+{
+ relationships: RelationshipStatusInfoMessageParser;
+ friendsCount: number;
+}
export const FriendsContainerView: FC = props =>
{
diff --git a/src/views/user-profile/views/groups-container/GroupsContainerView.tsx b/src/components/user-profile/views/GroupsContainerView.tsx
similarity index 84%
rename from src/views/user-profile/views/groups-container/GroupsContainerView.tsx
rename to src/components/user-profile/views/GroupsContainerView.tsx
index d5afa3c9..ce4b6870 100644
--- a/src/views/user-profile/views/groups-container/GroupsContainerView.tsx
+++ b/src/components/user-profile/views/GroupsContainerView.tsx
@@ -1,10 +1,16 @@
-import { GroupFavoriteComposer, GroupInformationComposer, GroupInformationEvent, GroupInformationParser } from '@nitrots/nitro-renderer';
+import { GroupFavoriteComposer, GroupInformationComposer, GroupInformationEvent, GroupInformationParser, HabboGroupEntryData } from '@nitrots/nitro-renderer';
import classNames from 'classnames';
import { FC, useCallback, useEffect, useState } from 'react';
-import { GroupInformationView } from '../../../../components/groups/views/information/GroupInformationView';
-import { CreateMessageHook, SendMessageHook } from '../../../../hooks';
-import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
-import { GroupsContainerViewProps } from './GroupsContainerView.types';
+import { CreateMessageHook, SendMessageHook } from '../../../hooks';
+import { BadgeImageView } from '../../../views/shared/badge-image/BadgeImageView';
+import { GroupInformationView } from '../../groups/views/information/GroupInformationView';
+
+interface GroupsContainerViewProps
+{
+ itsMe: boolean;
+ groups: HabboGroupEntryData[];
+ onLeaveGroup: () => void;
+}
export const GroupsContainerView: FC = props =>
{
diff --git a/src/views/user-profile/views/relationships-container/RelationshipsContainerView.tsx b/src/components/user-profile/views/RelationshipsContainerView.tsx
similarity index 89%
rename from src/views/user-profile/views/relationships-container/RelationshipsContainerView.tsx
rename to src/components/user-profile/views/RelationshipsContainerView.tsx
index 4f1745cb..7f89d42d 100644
--- a/src/views/user-profile/views/relationships-container/RelationshipsContainerView.tsx
+++ b/src/components/user-profile/views/RelationshipsContainerView.tsx
@@ -1,8 +1,13 @@
-import { RelationshipStatusEnum, RelationshipStatusInfo } from '@nitrots/nitro-renderer';
+import { RelationshipStatusEnum, RelationshipStatusInfo, RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react';
-import { GetUserProfile, LocalizeText } from '../../../../api';
-import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
-import { RelationshipsContainerViewProps } from './RelationshipsContainerView.types';
+import { GetUserProfile, LocalizeText } from '../../../api';
+import { AvatarImageView } from '../../../views/shared/avatar-image/AvatarImageView';
+
+interface RelationshipsContainerViewProps
+{
+ relationships: RelationshipStatusInfoMessageParser;
+ simple?: boolean;
+}
export const RelationshipsContainerView: FC = props =>
{
diff --git a/src/views/user-profile/views/user-container/UserContainerView.tsx b/src/components/user-profile/views/UserContainerView.tsx
similarity index 87%
rename from src/views/user-profile/views/user-container/UserContainerView.tsx
rename to src/components/user-profile/views/UserContainerView.tsx
index cd48bb4c..bcd3e359 100644
--- a/src/views/user-profile/views/user-container/UserContainerView.tsx
+++ b/src/components/user-profile/views/UserContainerView.tsx
@@ -1,8 +1,12 @@
-import { FriendlyTime } from '@nitrots/nitro-renderer';
+import { FriendlyTime, UserProfileParser } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react';
-import { GetSessionDataManager, LocalizeText } from '../../../../api';
-import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
-import { UserContainerViewProps } from './UserContainerView.types';
+import { GetSessionDataManager, LocalizeText } from '../../../api';
+import { AvatarImageView } from '../../../views/shared/avatar-image/AvatarImageView';
+
+interface UserContainerViewProps
+{
+ userProfile: UserProfileParser;
+}
export const UserContainerView: FC = props =>
{
diff --git a/src/events/chat-history/ChatHistoryEvent.ts b/src/events/chat-history/ChatHistoryEvent.ts
deleted file mode 100644
index e038f22e..00000000
--- a/src/events/chat-history/ChatHistoryEvent.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { NitroEvent } from '@nitrots/nitro-renderer';
-
-export class ChatHistoryEvent extends NitroEvent
-{
- public static SHOW_CHAT_HISTORY: string = 'CHE_SHOW_CHAT_HISTORY';
- public static HIDE_CHAT_HISTORY: string = 'CHE_HIDE_CHAT_HISTORY';
- public static TOGGLE_CHAT_HISTORY: string = 'CHE_TOGGLE_CHAT_HISTORY';
-}
diff --git a/src/index.scss b/src/index.scss
index d655fc16..82b5446d 100644
--- a/src/index.scss
+++ b/src/index.scss
@@ -9,6 +9,7 @@ body {
user-select: none;
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
+ scrollbar-width: thin;
}
img {
diff --git a/src/layout/card/content/NitroCardContentView.tsx b/src/layout/card/content/NitroCardContentView.tsx
index e8662783..2ada5f99 100644
--- a/src/layout/card/content/NitroCardContentView.tsx
+++ b/src/layout/card/content/NitroCardContentView.tsx
@@ -1,12 +1,11 @@
import { FC, useMemo } from 'react';
-import { Column } from '../../../common/Column';
+import { Column, ColumnProps } from '../../../common';
import { useNitroCardContext } from '../context';
-import { NitroCardContentViewProps } from './NitroCardContextView.types';
-export const NitroCardContentView: FC = props =>
+export const NitroCardContentView: FC = props =>
{
- const { theme = 'primary', classNames = [], ...rest } = props;
- const { simple = false } = useNitroCardContext();
+ const { classNames = [], ...rest } = props;
+ const { theme = 'primary', simple = false } = useNitroCardContext();
const getClassNames = useMemo(() =>
{
diff --git a/src/layout/card/content/NitroCardContextView.types.ts b/src/layout/card/content/NitroCardContextView.types.ts
deleted file mode 100644
index 829c149d..00000000
--- a/src/layout/card/content/NitroCardContextView.types.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { ColumnProps } from '../../../common/Column';
-
-
-export interface NitroCardContentViewProps extends ColumnProps
-{
- theme?: string;
-}
diff --git a/src/layout/card/content/index.ts b/src/layout/card/content/index.ts
index b5d35b45..b0862136 100644
--- a/src/layout/card/content/index.ts
+++ b/src/layout/card/content/index.ts
@@ -1,2 +1 @@
export * from './NitroCardContentView';
-export * from './NitroCardContextView.types';
diff --git a/src/layout/card/header/NitroCardHeaderView.tsx b/src/layout/card/header/NitroCardHeaderView.tsx
index 17c580e8..bf40be1c 100644
--- a/src/layout/card/header/NitroCardHeaderView.tsx
+++ b/src/layout/card/header/NitroCardHeaderView.tsx
@@ -5,8 +5,8 @@ import { NitroCardHeaderViewProps } from './NitroCardHeaderView.types';
export const NitroCardHeaderView: FC = props =>
{
- const { headerText = null, onCloseClick = null, theme = 'primary' } = props;
- const { simple = false } = useNitroCardContext();
+ const { headerText = null, onCloseClick = null } = props;
+ const { theme = 'primary', simple = false } = useNitroCardContext();
const onMouseDown = useCallback((event: MouseEvent) =>
{
diff --git a/src/views/Styles.scss b/src/views/Styles.scss
index dd4f6217..52fbdfd8 100644
--- a/src/views/Styles.scss
+++ b/src/views/Styles.scss
@@ -1,16 +1,8 @@
@import "./shared/Shared";
@import "./friends/FriendsView";
@import "./hotel-view/HotelView";
-@import "./loading/LoadingView";
-@import "./main/MainView";
@import "./notification-center/NotificationCenterView";
-@import "./purse/PurseView";
-@import "./right-side/RightSideView";
@import "./room/RoomView";
-@import "./room-host/RoomHostView";
-@import "./mod-tools/ModToolsView";
-@import "./user-profile/UserProfileVew";
-@import "./chat-history/ChatHistoryView";
@import "./floorplan-editor/FloorplanEditorView";
@import "./nitropedia/NitropediaView";
@import "./hc-center/HcCenterView.scss";
diff --git a/src/views/chat-history/ChatHistoryView.scss b/src/views/chat-history/ChatHistoryView.scss
deleted file mode 100644
index 84bafc9f..00000000
--- a/src/views/chat-history/ChatHistoryView.scss
+++ /dev/null
@@ -1,31 +0,0 @@
-.nitro-chat-history {
- width: $chat-history-width;
- height: $chat-history-height;
-
- background-color: #1C323F;
- border: 2px solid rgba(255, 255, 255, 0.5);
- border-radius: 0.25rem;
-
- .nitro-card-header-container {
- background-color: #3d5f6e;
- color: #fff;
- }
-
- .chat-history-content {
- .chat-history-container {
- min-height: 200px;
-
- .chat-history-list {
- .chathistory-entry {
- .light {
- background-color: #121f27;
- }
-
- .dark {
- background-color: #0d171d;
- }
- }
- }
- }
- }
-}
diff --git a/src/views/chat-history/ChatHistoryView.tsx b/src/views/chat-history/ChatHistoryView.tsx
deleted file mode 100644
index acb432ea..00000000
--- a/src/views/chat-history/ChatHistoryView.tsx
+++ /dev/null
@@ -1,167 +0,0 @@
-import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
-import { AutoSizer, CellMeasurer, CellMeasurerCache, List, ListRowProps, ListRowRenderer, Size } from 'react-virtualized';
-import { RenderedRows } from 'react-virtualized/dist/es/List';
-import { ChatHistoryEvent } from '../../events/chat-history/ChatHistoryEvent';
-import { useUiEvent } from '../../hooks';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
-import { ChatHistoryMessageHandler } from './ChatHistoryMessageHandler';
-import { ChatHistoryState } from './common/ChatHistoryState';
-import { SetChatHistory } from './common/GetChatHistory';
-import { RoomHistoryState } from './common/RoomHistoryState';
-import { ChatHistoryContextProvider } from './context/ChatHistoryContext';
-import { ChatEntryType } from './context/ChatHistoryContext.types';
-
-export const ChatHistoryView: FC<{}> = props =>
-{
- const [ isVisible, setIsVisible ] = useState(false);
- const [ needsScroll, setNeedsScroll ] = useState(false);
- const [ chatHistoryUpdateId, setChatHistoryUpdateId ] = useState(-1);
- const [ roomHistoryUpdateId, setRoomHistoryUpdateId ] = useState(-1);
- const [ chatHistoryState, setChatHistoryState ] = useState(new ChatHistoryState());
- const [ roomHistoryState, setRoomHistoryState ] = useState(new RoomHistoryState());
- const elementRef = useRef(null);
-
- useEffect(() =>
- {
- const chatState = new ChatHistoryState();
- const roomState = new RoomHistoryState();
-
- SetChatHistory(chatState);
-
- chatState.notifier = () => setChatHistoryUpdateId(prevValue => (prevValue + 1));
- roomState.notifier = () => setRoomHistoryUpdateId(prevValue => (prevValue + 1));
-
- setChatHistoryState(chatState);
- setRoomHistoryState(roomState);
-
- return () => {chatState.notifier = null; roomState.notifier = null;};
- }, []);
-
- const onChatHistoryEvent = useCallback((event: ChatHistoryEvent) =>
- {
- switch(event.type)
- {
- case ChatHistoryEvent.SHOW_CHAT_HISTORY:
- setIsVisible(true);
- break;
- case ChatHistoryEvent.HIDE_CHAT_HISTORY:
- setIsVisible(false);
- break;
- case ChatHistoryEvent.TOGGLE_CHAT_HISTORY:
- setIsVisible(!isVisible);
- break;
- }
- }, [isVisible]);
-
- useUiEvent(ChatHistoryEvent.HIDE_CHAT_HISTORY, onChatHistoryEvent);
- useUiEvent(ChatHistoryEvent.SHOW_CHAT_HISTORY, onChatHistoryEvent);
- useUiEvent(ChatHistoryEvent.TOGGLE_CHAT_HISTORY, onChatHistoryEvent);
-
- const cache = useMemo(() =>
- {
- return new CellMeasurerCache({
- defaultHeight: 25,
- fixedWidth: true,
- //keyMapper: (index) => chatHistoryState.chats[index].id
- });
- }, []);
-
- const RowRenderer: ListRowRenderer = (props: ListRowProps) =>
- {
- const item = chatHistoryState.chats[props.index];
-
- const isDark = (props.index % 2 === 0);
-
- return (
-
-
- {(item.type === ChatEntryType.TYPE_CHAT) &&
-
-
{item.timestamp}
-
-
{item.message}
-
- }
- {(item.type === ChatEntryType.TYPE_ROOM_INFO) &&
-
-
{item.timestamp}
-
-
{item.name}
-
- }
-
-
-
- );
- };
-
- const onResize = useCallback((info: Size) =>
- {
- cache.clearAll();
- }, [cache]);
-
- const onRowsRendered = useCallback((info: RenderedRows) =>
- {
- if(elementRef && elementRef.current && isVisible && needsScroll)
- {
- console.log('stop ' + info.stopIndex);
- //if(chatHistoryState.chats.length > 0) elementRef.current.measureAllRows();
- elementRef.current.scrollToRow(chatHistoryState.chats.length);
- console.log('scroll')
- setNeedsScroll(false);
- }
- }, [chatHistoryState.chats.length, isVisible, needsScroll]);
-
- useEffect(() =>
- {
-
- if(elementRef && elementRef.current && isVisible)
- {
- //if(chatHistoryState.chats.length > 0) elementRef.current.measureAllRows();
- elementRef.current.scrollToRow(chatHistoryState.chats.length);
- }
- //console.log(chatHistoryState.chats.length);
-
- setNeedsScroll(true);
- }, [chatHistoryState.chats, isVisible, chatHistoryUpdateId]);
-
- return (
-
-
- {isVisible &&
-
- setIsVisible(false) } theme={'dark'}/>
-
-
-
- {({ height, width }) =>
- {
- return (
-
- )
- }
- }
-
-
-
-
- }
-
- );
-}
diff --git a/src/views/chat-history/context/ChatHistoryContext.tsx b/src/views/chat-history/context/ChatHistoryContext.tsx
deleted file mode 100644
index 981d6007..00000000
--- a/src/views/chat-history/context/ChatHistoryContext.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { createContext, FC, useContext } from 'react';
-import { ChatHistoryContextProps, IChatHistoryContext } from './ChatHistoryContext.types';
-
-const ChatHistoryContext = createContext({
- chatHistoryState: null,
- roomHistoryState: null
-});
-
-export const ChatHistoryContextProvider: FC = props =>
-{
- return { props.children }
-}
-
-export const useChatHistoryContext = () => useContext(ChatHistoryContext);
diff --git a/src/views/chat-history/context/ChatHistoryContext.types.ts b/src/views/chat-history/context/ChatHistoryContext.types.ts
deleted file mode 100644
index 51cd19cf..00000000
--- a/src/views/chat-history/context/ChatHistoryContext.types.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { ProviderProps } from 'react';
-
-export interface IChatHistoryContext
-{
- chatHistoryState: IChatHistoryState;
- roomHistoryState: IRoomHistoryState;
-}
-
-export interface IChatHistoryState {
- chats: IChatEntry[];
- notifier: () => void
- notify(): void;
-}
-
-export interface IRoomHistoryState {
- roomHistory: IRoomHistoryEntry[];
- notifier: () => void
- notify(): void;
-}
-
-export interface IChatEntry {
- id: number;
- entityId: number;
- name: string;
- look?: string;
- message?: string;
- entityType?: number;
- roomId: number;
- timestamp: string;
- type: number;
-}
-
-export interface IRoomHistoryEntry {
- id: number;
- name: string;
-}
-
-export class ChatEntryType
-{
- public static TYPE_CHAT = 1;
- public static TYPE_ROOM_INFO = 2;
-}
-
-export const CHAT_HISTORY_MAX = 1000;
-export const ROOM_HISTORY_MAX = 10;
-
-export interface ChatHistoryContextProps extends ProviderProps
-{
-
-}
diff --git a/src/views/loading/LoadingView.tsx b/src/views/loading/LoadingView.tsx
deleted file mode 100644
index 4d498951..00000000
--- a/src/views/loading/LoadingView.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { FC, useEffect, useState } from 'react';
-import { NitroLayoutFlexColumn } from '../../layout';
-import { NitroLayoutBase } from '../../layout/base';
-import { NotificationUtilities } from '../notification-center/common/NotificationUtilities';
-import { LoadingViewProps } from './LoadingView.types';
-
-export const LoadingView: FC = props =>
-{
- const { isError = false, message = '' } = props;
- const [ loadingShowing, setLoadingShowing ] = useState(false);
-
- useEffect(() =>
- {
- if(!isError) return;
-
- NotificationUtilities.simpleAlert(message, null, null, null, 'Connection Error');
- }, [ isError, message ]);
-
- useEffect(() =>
- {
- const timeout = setTimeout(() =>
- {
- setLoadingShowing(true);
- }, 500);
-
- return () =>
- {
- clearTimeout(timeout);
- }
- }, []);
-
- return (
-
-
- {/*
-
- */}
- {/*
-
- */}
- { isError && (message && message.length) &&
- { message } }
-
- );
-}
diff --git a/src/views/loading/LoadingView.types.ts b/src/views/loading/LoadingView.types.ts
deleted file mode 100644
index 2dd560e4..00000000
--- a/src/views/loading/LoadingView.types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface LoadingViewProps
-{
- isError: boolean;
- message: string;
-}
diff --git a/src/views/main/MainView.scss b/src/views/main/MainView.scss
deleted file mode 100644
index 3ff415d7..00000000
--- a/src/views/main/MainView.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-.nitro-main {
- width: 100%;
- height: 100%;
-}
diff --git a/src/views/main/MainView.types.ts b/src/views/main/MainView.types.ts
deleted file mode 100644
index e0fd1650..00000000
--- a/src/views/main/MainView.types.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface MainViewProps
-{
-
-}
diff --git a/src/views/mod-tools/ModToolsView.scss b/src/views/mod-tools/ModToolsView.scss
deleted file mode 100644
index e8fb9e18..00000000
--- a/src/views/mod-tools/ModToolsView.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-.nitro-mod-tools {
- width: 200px;
-}
-
-@import './views/room/room-tools/ModToolsRoomView';
-@import './views/chatlog/ChatlogView';
-@import './views/user/user-info/ModToolsUserView';
-@import './views/user/user-room-visits/ModToolsUserRoomVisitsView';
-@import './views/tickets/ModToolsTicketView';
diff --git a/src/views/mod-tools/ModToolsView.types.ts b/src/views/mod-tools/ModToolsView.types.ts
deleted file mode 100644
index 3aa7691f..00000000
--- a/src/views/mod-tools/ModToolsView.types.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export interface ModToolsViewProps
-{}
diff --git a/src/views/mod-tools/context/ModToolsContext.tsx b/src/views/mod-tools/context/ModToolsContext.tsx
deleted file mode 100644
index 97873603..00000000
--- a/src/views/mod-tools/context/ModToolsContext.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { createContext, FC, useContext } from 'react';
-import { IModToolsContext, ModToolsContextProps } from './ModToolsContext.types';
-
-const ModToolsContext = createContext({
- modToolsState: null,
- dispatchModToolsState: null
-});
-
-export const ModToolsContextProvider: FC = props =>
-{
- return { props.children }
-}
-
-export const useModToolsContext = () => useContext(ModToolsContext);
diff --git a/src/views/mod-tools/context/ModToolsContext.types.ts b/src/views/mod-tools/context/ModToolsContext.types.ts
deleted file mode 100644
index 46c6a9b8..00000000
--- a/src/views/mod-tools/context/ModToolsContext.types.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { Dispatch, ProviderProps } from 'react';
-import { IModToolsAction, IModToolsState } from '../reducers/ModToolsReducer';
-
-export interface IModToolsContext
-{
- modToolsState: IModToolsState;
- dispatchModToolsState: Dispatch;
-}
-
-export interface ModToolsContextProps extends ProviderProps
-{
-
-}
diff --git a/src/views/mod-tools/views/chatlog/ChatlogView.scss b/src/views/mod-tools/views/chatlog/ChatlogView.scss
deleted file mode 100644
index 5d5f7d04..00000000
--- a/src/views/mod-tools/views/chatlog/ChatlogView.scss
+++ /dev/null
@@ -1,40 +0,0 @@
-.chatlog-messages {
- color: $black;
- min-width: 400px;
-
- $username-col-width: 100px;
-
- .username-label {
- width: $username-col-width;
- }
-
- .chatlog {
- min-height: 200px;
-
- .chatlog-container {
- color: $black;
-
- div.chatlog-entry {
- border-bottom: 1px solid rgba(0, 0, 0, 0.2);
- .username {
- color: #1E7295;
- text-decoration: underline;
- width: $username-col-width;
- }
-
- &.highlighted {
- border: 1px solid $red;
- }
-
- .message {
- word-break: break-all;
- }
- }
-
- .room-info {
- border-bottom: 1px solid rgba(0, 0, 0, 0.2);
- background: rgba(0, 0, 0, .05);
- }
- }
- }
-}
diff --git a/src/views/mod-tools/views/chatlog/ChatlogView.tsx b/src/views/mod-tools/views/chatlog/ChatlogView.tsx
deleted file mode 100644
index c2394526..00000000
--- a/src/views/mod-tools/views/chatlog/ChatlogView.tsx
+++ /dev/null
@@ -1,150 +0,0 @@
-import { ChatlineData, ChatRecordData, UserProfileComposer } from '@nitrots/nitro-renderer';
-import { FC, useCallback } from 'react';
-import { AutoSizer, CellMeasurer, CellMeasurerCache, List, ListRowProps, ListRowRenderer } from 'react-virtualized';
-import { TryVisitRoom } from '../../../../api';
-import { ModToolsOpenRoomInfoEvent } from '../../../../events/mod-tools/ModToolsOpenRoomInfoEvent';
-import { dispatchUiEvent, SendMessageHook } from '../../../../hooks';
-import { ChatlogViewProps } from './ChatlogView.types';
-
-export const ChatlogView: FC = props =>
-{
- const { records = null } = props;
-
- const simpleRowRenderer: ListRowRenderer = (props: ListRowProps) =>
- {
- const item = records[0].chatlog[props.index];
-
- return (
-
-
-
{item.timestamp}
-
SendMessageHook(new UserProfileComposer(item.userId))}>{item.userName}
-
{item.message}
-
-
- );
- };
-
- const advancedRowRenderer: ListRowRenderer = (props: ListRowProps) =>
- {
- let chatlogEntry: ChatlineData;
- let currentRecord: ChatRecordData;
- let isRoomInfo = false;
-
- let totalIndex = 0;
- for(let i = 0; i < records.length; i++)
- {
- currentRecord = records[i];
-
- totalIndex++; // row for room info
- totalIndex = totalIndex + currentRecord.chatlog.length;
-
- if(props.index > (totalIndex - 1))
- {
- continue; // it is not in current one
- }
-
- if( (props.index + 1) === (totalIndex - currentRecord.chatlog.length))
- {
- isRoomInfo = true;
- break;
- }
- const index = props.index - (totalIndex - currentRecord.chatlog.length);
- chatlogEntry = currentRecord.chatlog[index];
- break;
- }
-
- return (
-
- {isRoomInfo && }
- {!isRoomInfo &&
-
-
{chatlogEntry.timestamp}
-
SendMessageHook(new UserProfileComposer(chatlogEntry.userId))}>{chatlogEntry.userName}
-
{chatlogEntry.message}
-
- }
-
-
- );
- }
-
- const getNumRowsForAdvanced = useCallback(() =>
- {
- let count = 0;
-
- for(let i = 0; i < records.length; i++)
- {
- count++; // add room info row
- count = count + records[i].chatlog.length;
- }
-
- return count;
- }, [records]);
-
- const cache = new CellMeasurerCache({
- defaultHeight: 25,
- fixedWidth: true
- });
-
- const RoomInfo = useCallback(({ roomId, roomName, uniqueKey, style }) =>
- {
- return (
-
-
Room: {roomName}
-
-
-
- );
- }, []);
-
- return (
- <>
- {
- (records && records.length) &&
- <>
- {(records.length === 1) && }
-
-
-
Time
-
User
-
Message
-
-
-
- {({ height, width }) =>
- {
- cache.clearAll();
-
- return (
- 1 ? getNumRowsForAdvanced() : records[0].chatlog.length}
- rowHeight={cache.rowHeight}
- className={'chatlog-container'}
- rowRenderer={records.length > 1 ? advancedRowRenderer : simpleRowRenderer}
- deferredMeasurementCache={cache} />
- )
- }
- }
-
-
-
- >
- }
- >
- );
-}
diff --git a/src/views/mod-tools/views/chatlog/ChatlogView.types.ts b/src/views/mod-tools/views/chatlog/ChatlogView.types.ts
deleted file mode 100644
index f307109f..00000000
--- a/src/views/mod-tools/views/chatlog/ChatlogView.types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { ChatRecordData } from '@nitrots/nitro-renderer';
-
-export interface ChatlogViewProps
-{
- records: ChatRecordData[];
-}
diff --git a/src/views/mod-tools/views/room/room-chatlog/ModToolsChatlogView.types.ts b/src/views/mod-tools/views/room/room-chatlog/ModToolsChatlogView.types.ts
deleted file mode 100644
index 0589cd02..00000000
--- a/src/views/mod-tools/views/room/room-chatlog/ModToolsChatlogView.types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface ModToolsChatlogViewProps
-{
- roomId: number;
- onCloseClick: () => void;
-}
diff --git a/src/views/mod-tools/views/room/room-tools/ModToolsRoomView.scss b/src/views/mod-tools/views/room/room-tools/ModToolsRoomView.scss
deleted file mode 100644
index 4faa2b33..00000000
--- a/src/views/mod-tools/views/room/room-tools/ModToolsRoomView.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-.nitro-mod-tools-room {
- width: 240px;
-
- .username {
- color: #1E7295;
- text-decoration: underline;
- }
-}
diff --git a/src/views/mod-tools/views/room/room-tools/ModToolsRoomView.tsx b/src/views/mod-tools/views/room/room-tools/ModToolsRoomView.tsx
deleted file mode 100644
index 3f40c1c6..00000000
--- a/src/views/mod-tools/views/room/room-tools/ModToolsRoomView.tsx
+++ /dev/null
@@ -1,120 +0,0 @@
-import { GetModeratorRoomInfoMessageComposer, ModerateRoomMessageComposer, ModeratorActionMessageComposer, ModeratorRoomInfoEvent } from '@nitrots/nitro-renderer';
-import { FC, useCallback, useEffect, useState } from 'react';
-import { TryVisitRoom } from '../../../../../api';
-import { ModToolsOpenRoomChatlogEvent } from '../../../../../events/mod-tools/ModToolsOpenRoomChatlogEvent';
-import { dispatchUiEvent } from '../../../../../hooks';
-import { CreateMessageHook, SendMessageHook } from '../../../../../hooks/messages';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
-import { ModToolsRoomViewProps } from './ModToolsRoomView.types';
-
-export const ModToolsRoomView: FC = props =>
-{
- const { roomId = null, onCloseClick = null } = props;
-
- const [ infoRequested, setInfoRequested ] = useState(false);
- const [ loadedRoomId, setLoadedRoomId ] = useState(null);
-
- const [ name, setName ] = useState(null);
- const [ ownerId, setOwnerId ] = useState(null);
- const [ ownerName, setOwnerName ] = useState(null);
- const [ ownerInRoom, setOwnerInRoom ] = useState(false);
- const [ usersInRoom, setUsersInRoom ] = useState(0);
-
- //form data
- const [kickUsers, setKickUsers] = useState(false);
- const [lockRoom, setLockRoom] = useState(false);
- const [changeRoomName, setChangeRoomName] = useState(false);
- const [message, setMessage] = useState('');
-
- useEffect(() =>
- {
- if(infoRequested) return;
-
- SendMessageHook(new GetModeratorRoomInfoMessageComposer(roomId));
- setInfoRequested(true);
- }, [ roomId, infoRequested, setInfoRequested ]);
-
- const onModtoolRoomInfoEvent = useCallback((event: ModeratorRoomInfoEvent) =>
- {
- const parser = event.getParser();
-
- if(!parser || parser.data.flatId !== roomId) return;
-
- setLoadedRoomId(parser.data.flatId);
- setName(parser.data.room.name);
- setOwnerId(parser.data.ownerId);
- setOwnerName(parser.data.ownerName);
- setOwnerInRoom(parser.data.ownerInRoom);
- setUsersInRoom(parser.data.userCount);
- }, [ setLoadedRoomId, setName, setOwnerId, setOwnerName, setOwnerInRoom, setUsersInRoom, roomId ]);
-
- CreateMessageHook(ModeratorRoomInfoEvent, onModtoolRoomInfoEvent);
-
- const handleClick = useCallback((action: string, value?: string) =>
- {
- if(!action) return;
-
- switch(action)
- {
- case 'alert_only':
- if(message.trim().length === 0) return;
- SendMessageHook(new ModeratorActionMessageComposer(ModeratorActionMessageComposer.ACTION_ALERT, message, ''));
- return;
- case 'send_message':
- if(message.trim().length === 0) return;
- SendMessageHook(new ModeratorActionMessageComposer(ModeratorActionMessageComposer.ACTION_MESSAGE, message, ''));
- SendMessageHook(new ModerateRoomMessageComposer(roomId, lockRoom ? 1 : 0, changeRoomName ? 1 : 0, kickUsers ? 1 : 0))
- return;
- }
- }, [changeRoomName, kickUsers, lockRoom, message, roomId]);
-
- return (
-
- onCloseClick() } />
-
-
-
- Room Owner: { ownerName }
-
-
-
-
-
- Users in room: { usersInRoom }
-
-
-
-
-
- Owner in room: { ownerInRoom ? 'Yes' : 'No' }
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/views/mod-tools/views/room/room-tools/ModToolsRoomView.types.ts b/src/views/mod-tools/views/room/room-tools/ModToolsRoomView.types.ts
deleted file mode 100644
index d096fcbe..00000000
--- a/src/views/mod-tools/views/room/room-tools/ModToolsRoomView.types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface ModToolsRoomViewProps
-{
- roomId: number;
- onCloseClick: () => void;
-}
diff --git a/src/views/mod-tools/views/tickets/ModToolsTicketView.scss b/src/views/mod-tools/views/tickets/ModToolsTicketView.scss
deleted file mode 100644
index f2459483..00000000
--- a/src/views/mod-tools/views/tickets/ModToolsTicketView.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-.nitro-mod-tools-tickets
-{
- width: 400px;
- height: 200px;
-}
-
-.nitro-mod-tools-handle-issue
-{
- width: 400px;
- height: 300px;
-}
diff --git a/src/views/mod-tools/views/tickets/ModToolsTicketsView.types.ts b/src/views/mod-tools/views/tickets/ModToolsTicketsView.types.ts
deleted file mode 100644
index 16495592..00000000
--- a/src/views/mod-tools/views/tickets/ModToolsTicketsView.types.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface ModToolsTicketsViewProps
-{
- onCloseClick: () => void;
-}
diff --git a/src/views/mod-tools/views/tickets/issue-info/CfhChatlogView.types.ts b/src/views/mod-tools/views/tickets/issue-info/CfhChatlogView.types.ts
deleted file mode 100644
index c40c18ad..00000000
--- a/src/views/mod-tools/views/tickets/issue-info/CfhChatlogView.types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface CfhChatlogViewProps
-{
- issueId: number;
- onCloseClick(): void;
-}
diff --git a/src/views/mod-tools/views/tickets/issue-info/IssueInfoView.tsx b/src/views/mod-tools/views/tickets/issue-info/IssueInfoView.tsx
deleted file mode 100644
index 8030cc7f..00000000
--- a/src/views/mod-tools/views/tickets/issue-info/IssueInfoView.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import { CloseIssuesMessageComposer, ReleaseIssuesMessageComposer } from '@nitrots/nitro-renderer';
-import { FC, useCallback, useMemo, useState } from 'react';
-import { LocalizeText } from '../../../../../api';
-import { ModToolsOpenUserInfoEvent } from '../../../../../events/mod-tools/ModToolsOpenUserInfoEvent';
-import { dispatchUiEvent, SendMessageHook } from '../../../../../hooks';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
-import { getSourceName } from '../../../common/IssueCategoryNames';
-import { useModToolsContext } from '../../../context/ModToolsContext';
-import { CfhChatlogView } from './CfhChatlogView';
-import { IssueInfoViewProps } from './IssueInfoView.types';
-
-export const IssueInfoView: FC = props =>
-{
- const { issueId = null, onIssueInfoClosed = null } = props;
- const { modToolsState = null } = useModToolsContext();
- const { tickets= null } = modToolsState;
- const [ cfhChatlogOpen, setcfhChatlogOpen ] = useState(false);
-
- const ticket = useMemo(() =>
- {
- return tickets.find( issue => issue.issueId === issueId);
- }, [issueId, tickets]);
-
- const onReleaseIssue = useCallback((issueId: number) =>
- {
- SendMessageHook(new ReleaseIssuesMessageComposer([issueId]));
- onIssueInfoClosed(issueId);
- }, [onIssueInfoClosed]);
-
- const openUserInfo = useCallback((userId: number) =>
- {
- dispatchUiEvent(new ModToolsOpenUserInfoEvent(userId));
- }, []);
-
- const closeIssue = useCallback((resolutionType: number) =>
- {
- SendMessageHook(new CloseIssuesMessageComposer([issueId], resolutionType));
- onIssueInfoClosed(issueId)
- }, [issueId, onIssueInfoClosed]);
-
- return (
- <>
-
- onIssueInfoClosed(issueId)} />
-
-
-
-
Issue Information
-
Source: {getSourceName(ticket.categoryId)}
-
Category: {LocalizeText('help.cfh.topic.' + ticket.reportedCategoryId)}
-
Description: {ticket.message}
-
Caller:
-
Reported User:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { cfhChatlogOpen && setcfhChatlogOpen(false) }/>}
- >
- );
-}
diff --git a/src/views/mod-tools/views/tickets/issue-info/IssueInfoView.types.ts b/src/views/mod-tools/views/tickets/issue-info/IssueInfoView.types.ts
deleted file mode 100644
index 1b28d803..00000000
--- a/src/views/mod-tools/views/tickets/issue-info/IssueInfoView.types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface IssueInfoViewProps
-{
- issueId: number;
- onIssueInfoClosed(issueId: number): void;
-}
diff --git a/src/views/mod-tools/views/tickets/my-issues/ModToolsMyIssuesTabView.tsx b/src/views/mod-tools/views/tickets/my-issues/ModToolsMyIssuesTabView.tsx
deleted file mode 100644
index 1a3fcde3..00000000
--- a/src/views/mod-tools/views/tickets/my-issues/ModToolsMyIssuesTabView.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { ReleaseIssuesMessageComposer } from '@nitrots/nitro-renderer';
-import { FC, useCallback } from 'react';
-import { SendMessageHook } from '../../../../../hooks';
-import { ModToolsMyIssuesTabViewProps } from './ModToolsMyIssuesTabView.types';
-
-export const ModToolsMyIssuesTabView: FC = props =>
-{
- const { myIssues = null, onIssueHandleClick = null } = props;
-
-
- const onReleaseIssue = useCallback((issueId: number) =>
- {
- SendMessageHook(new ReleaseIssuesMessageComposer([issueId]));
- }, []);
-
- return (
- <>
-
-
-
- Type |
- Room/Player |
- Opened |
- |
- |
-
-
-
- {myIssues.map(issue =>
- {
- return (
-
- {issue.categoryId} |
- {issue.reportedUserName} |
- {new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString()} |
- |
- |
-
)
- })
- }
-
-
- >
- );
-}
diff --git a/src/views/mod-tools/views/tickets/my-issues/ModToolsMyIssuesTabView.types.ts b/src/views/mod-tools/views/tickets/my-issues/ModToolsMyIssuesTabView.types.ts
deleted file mode 100644
index 6d03fbf8..00000000
--- a/src/views/mod-tools/views/tickets/my-issues/ModToolsMyIssuesTabView.types.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { IssueMessageData } from '@nitrots/nitro-renderer';
-
-export interface ModToolsMyIssuesTabViewProps
-{
- myIssues: IssueMessageData[];
- onIssueHandleClick(issueId: number): void;
-}
diff --git a/src/views/mod-tools/views/tickets/open-issues/ModToolsOpenIssuesTabView.tsx b/src/views/mod-tools/views/tickets/open-issues/ModToolsOpenIssuesTabView.tsx
deleted file mode 100644
index 4f8bb6d6..00000000
--- a/src/views/mod-tools/views/tickets/open-issues/ModToolsOpenIssuesTabView.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import { PickIssuesMessageComposer } from '@nitrots/nitro-renderer';
-import { FC, useCallback } from 'react';
-import { SendMessageHook } from '../../../../../hooks';
-import { ModToolsOpenIssuesTabViewProps } from './ModToolsOpenIssuesTabView.types';
-
-export const ModToolsOpenIssuesTabView: FC = props =>
-{
- const { openIssues = null } = props;
-
- const onPickIssue = useCallback((issueId: number) =>
- {
- SendMessageHook(new PickIssuesMessageComposer([issueId], false, 0, 'pick issue button'));
- }, []);
-
- return (
- <>
-
-
-
- Type |
- Room/Player |
- Opened |
- |
-
-
-
- {openIssues.map(issue =>
- {
- return (
-
- {issue.categoryId} |
- {issue.reportedUserName} |
- {new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString()} |
- |
-
)
- })
- }
-
-
- >
- );
-}
diff --git a/src/views/mod-tools/views/tickets/open-issues/ModToolsOpenIssuesTabView.types.ts b/src/views/mod-tools/views/tickets/open-issues/ModToolsOpenIssuesTabView.types.ts
deleted file mode 100644
index 45a80d7d..00000000
--- a/src/views/mod-tools/views/tickets/open-issues/ModToolsOpenIssuesTabView.types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { IssueMessageData } from '@nitrots/nitro-renderer';
-
-export interface ModToolsOpenIssuesTabViewProps
-{
- openIssues: IssueMessageData[];
-}
diff --git a/src/views/mod-tools/views/tickets/picked-issues/ModToolsPickedIssuesTabView.tsx b/src/views/mod-tools/views/tickets/picked-issues/ModToolsPickedIssuesTabView.tsx
deleted file mode 100644
index 988a0fd9..00000000
--- a/src/views/mod-tools/views/tickets/picked-issues/ModToolsPickedIssuesTabView.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { FC } from 'react';
-import { ModToolsPickedIssuesTabViewProps } from './ModToolsPickedIssuesTabView.types';
-
-export const ModToolsPickedIssuesTabView: FC = props =>
-{
- const { pickedIssues = null } = props;
-
- return (
- <>
-
-
-
- Type |
- Room/Player |
- Opened |
- Picker |
-
-
-
- {pickedIssues.map(issue =>
- {
- return (
-
- {issue.categoryId} |
- {issue.reportedUserName} |
- {new Date(Date.now() - issue.issueAgeInMilliseconds).toLocaleTimeString()} |
- {issue.pickerUserName} |
-
)
- })
- }
-
-
- >
- );
-}
diff --git a/src/views/mod-tools/views/tickets/picked-issues/ModToolsPickedIssuesTabView.types.ts b/src/views/mod-tools/views/tickets/picked-issues/ModToolsPickedIssuesTabView.types.ts
deleted file mode 100644
index c69b1772..00000000
--- a/src/views/mod-tools/views/tickets/picked-issues/ModToolsPickedIssuesTabView.types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { IssueMessageData } from '@nitrots/nitro-renderer';
-
-export interface ModToolsPickedIssuesTabViewProps
-{
- pickedIssues: IssueMessageData[];
-}
diff --git a/src/views/mod-tools/views/user/user-chatlog/ModToolsUserChatlogView.types.ts b/src/views/mod-tools/views/user/user-chatlog/ModToolsUserChatlogView.types.ts
deleted file mode 100644
index c8eea569..00000000
--- a/src/views/mod-tools/views/user/user-chatlog/ModToolsUserChatlogView.types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface ModToolsUserChatlogViewProps
-{
- userId: number;
- onCloseClick: () => void;
-}
diff --git a/src/views/mod-tools/views/user/user-info/ModToolsUserView.scss b/src/views/mod-tools/views/user/user-info/ModToolsUserView.scss
deleted file mode 100644
index ddc24350..00000000
--- a/src/views/mod-tools/views/user/user-info/ModToolsUserView.scss
+++ /dev/null
@@ -1,23 +0,0 @@
-.nitro-mod-tools-user {
- width: 350px;
- height: 370px;
-
- .username {
- color: #1E7295;
- text-decoration: underline;
- }
-
- .table {
- color: $black;
-
- > :not(caption) > * > * {
- box-shadow: none;
- border-bottom: 1px solid rgba(0, 0, 0, .2);
- }
-
- &.table-striped > tbody > tr:nth-of-type(odd) {
- color: $black;
- background: rgba(0, 0, 0, .05);
- }
- }
-}
diff --git a/src/views/mod-tools/views/user/user-info/ModToolsUserView.types.ts b/src/views/mod-tools/views/user/user-info/ModToolsUserView.types.ts
deleted file mode 100644
index 534d647d..00000000
--- a/src/views/mod-tools/views/user/user-info/ModToolsUserView.types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface ModToolsUserViewProps
-{
- userId: number;
- onCloseClick: () => void;
-}
diff --git a/src/views/mod-tools/views/user/user-mod-action/ModToolsUserModActionView.tsx b/src/views/mod-tools/views/user/user-mod-action/ModToolsUserModActionView.tsx
deleted file mode 100644
index 88bcbac1..00000000
--- a/src/views/mod-tools/views/user/user-mod-action/ModToolsUserModActionView.tsx
+++ /dev/null
@@ -1,202 +0,0 @@
-import { CallForHelpTopicData, DefaultSanctionMessageComposer, ModAlertMessageComposer, ModBanMessageComposer, ModKickMessageComposer, ModMessageMessageComposer, ModMuteMessageComposer, ModTradingLockMessageComposer } from '@nitrots/nitro-renderer';
-import { FC, useCallback, useMemo, useState } from 'react';
-import { LocalizeText } from '../../../../../api';
-import { SendMessageHook } from '../../../../../hooks';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
-import { NotificationAlertType } from '../../../../notification-center/common/NotificationAlertType';
-import { NotificationUtilities } from '../../../../notification-center/common/NotificationUtilities';
-import { useModToolsContext } from '../../../context/ModToolsContext';
-import { ModActionDefinition } from '../../../utils/ModActionDefinition';
-import { ModToolsUserModActionViewProps } from './ModToolsUserModActionView.types';
-
-const actions = [
- new ModActionDefinition(1, 'Alert', ModActionDefinition.ALERT, 1, 0),
- new ModActionDefinition(2, 'Mute 1h', ModActionDefinition.MUTE, 2, 0),
- new ModActionDefinition(4, 'Ban 7 days', ModActionDefinition.BAN, 4, 0),
- new ModActionDefinition(3, 'Ban 18h', ModActionDefinition.BAN, 3, 0),
- new ModActionDefinition(5, 'Ban 30 days (step 1)', ModActionDefinition.BAN, 5, 0),
- new ModActionDefinition(7, 'Ban 30 days (step 2)', ModActionDefinition.BAN, 7, 0),
- new ModActionDefinition(6, 'Ban 100 years', ModActionDefinition.BAN, 6, 0),
- new ModActionDefinition(106, 'Ban avatar-only 100 years', ModActionDefinition.BAN, 6, 0),
- new ModActionDefinition(101, 'Kick', ModActionDefinition.KICK, 0, 0),
- new ModActionDefinition(102, 'Lock trade 1 week', ModActionDefinition.TRADE_LOCK, 0, 168),
- new ModActionDefinition(104, 'Lock trade permanent', ModActionDefinition.TRADE_LOCK, 0, 876000),
- new ModActionDefinition(105, 'Message', ModActionDefinition.MESSAGE, 0, 0),
-];
-
-export const ModToolsUserModActionView: FC = props =>
-{
- const { user = null, onCloseClick = null } = props;
- const { modToolsState = null, dispatchModToolsState = null } = useModToolsContext();
- const { cfhCategories = null, settings = null } = modToolsState;
- const [ selectedTopic, setSelectedTopic ] = useState(-1);
- const [ selectedAction, setSelectedAction ] = useState(-1);
- const [ message, setMessage ] = useState('');
-
- const topics = useMemo(() =>
- {
- const values: CallForHelpTopicData[] = [];
-
- if(!cfhCategories) return values;
-
- for(let category of cfhCategories)
- {
- for(let topic of category.topics)
- {
- values.push(topic)
- }
- }
-
- return values;
- }, [cfhCategories]);
-
- const sendDefaultSanction = useCallback(() =>
- {
- SendMessageHook(new DefaultSanctionMessageComposer(user.userId, selectedTopic, message));
- onCloseClick();
- }, [message, onCloseClick, selectedTopic, user.userId]);
-
- const sendSanction = useCallback(() =>
- {
- if( (selectedTopic === -1) || (selectedAction === -1) )
- {
- NotificationUtilities.simpleAlert('You must select a CFH topic and Sanction', NotificationAlertType.DEFAULT, null, null, 'Error');
- return;
- }
-
- if(!settings || !settings.cfhPermission)
- {
- NotificationUtilities.simpleAlert('You do not have permission to do this', NotificationAlertType.DEFAULT, null, null, 'Error');
- return;
- }
-
- const category = topics[selectedTopic];
- const sanction = actions[selectedAction];
-
- if(!category)
- {
- NotificationUtilities.simpleAlert('You must select a CFH topic', NotificationAlertType.DEFAULT, null, null, 'Error');
- return;
- }
-
- if(!sanction)
- {
- NotificationUtilities.simpleAlert('You must select a sanction', NotificationAlertType.DEFAULT, null, null, 'Error');
- return;
- }
-
- const messageOrDefault = message.trim().length === 0 ? LocalizeText('help.cfh.topic.' + category.id) : message;
-
- switch(sanction.actionType)
- {
- case ModActionDefinition.ALERT:
-
- if(!settings.alertPermission)
- {
- NotificationUtilities.simpleAlert('You have insufficient permissions', NotificationAlertType.DEFAULT, null, null, 'Error');
- return;
- }
-
- if(message.trim().length === 0)
- {
- NotificationUtilities.simpleAlert('Please write a message to user', NotificationAlertType.DEFAULT, null, null, 'Error');
- return;
- }
-
- SendMessageHook(new ModAlertMessageComposer(user.userId, message, category.id));
-
- break;
- case ModActionDefinition.MUTE:
- SendMessageHook(new ModMuteMessageComposer(user.userId, messageOrDefault, category.id));
-
- break;
- case ModActionDefinition.BAN:
-
- if(!settings.banPermission)
- {
- NotificationUtilities.simpleAlert('You have insufficient permissions', NotificationAlertType.DEFAULT, null, null, 'Error');
- return;
- }
-
- SendMessageHook(new ModBanMessageComposer(user.userId, messageOrDefault, category.id, selectedAction, (sanction.actionId === 106)));
-
- break;
-
- case ModActionDefinition.KICK:
-
- if(!settings.kickPermission)
- {
- NotificationUtilities.simpleAlert('You have insufficient permissions', NotificationAlertType.DEFAULT, null, null, 'Error');
- return;
- }
-
- SendMessageHook(new ModKickMessageComposer(user.userId, messageOrDefault, category.id));
-
- break;
-
- case ModActionDefinition.TRADE_LOCK:
- {
- const numSeconds = sanction.actionLengthHours * 60;
- SendMessageHook(new ModTradingLockMessageComposer(user.userId, messageOrDefault, numSeconds, category.id));
- }
- break;
-
- case ModActionDefinition.MESSAGE:
-
- if(message.trim().length === 0)
- {
- NotificationUtilities.simpleAlert('Please write a message to user', NotificationAlertType.DEFAULT, null, null, 'Error');
- return;
- }
-
- SendMessageHook(new ModMessageMessageComposer(user.userId, message, category.id));
-
- break;
- }
-
- onCloseClick();
- }, [message, onCloseClick, selectedAction, selectedTopic, settings, topics, user.userId]);
-
- return (
-
- onCloseClick() } />
-
- { user &&
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- }
-
-
- );
-}
diff --git a/src/views/mod-tools/views/user/user-mod-action/ModToolsUserModActionView.types.ts b/src/views/mod-tools/views/user/user-mod-action/ModToolsUserModActionView.types.ts
deleted file mode 100644
index 2025d10d..00000000
--- a/src/views/mod-tools/views/user/user-mod-action/ModToolsUserModActionView.types.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { ISelectedUser } from '../../../utils/ISelectedUser';
-
-export interface ModToolsUserModActionViewProps
-{
- user: ISelectedUser;
- onCloseClick: () => void;
-}
diff --git a/src/views/mod-tools/views/user/user-room-visits/ModToolsUserRoomVisitsView.scss b/src/views/mod-tools/views/user/user-room-visits/ModToolsUserRoomVisitsView.scss
deleted file mode 100644
index 46efbaa5..00000000
--- a/src/views/mod-tools/views/user/user-room-visits/ModToolsUserRoomVisitsView.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-.nitro-mod-tools-user-visits {
- min-width: 300px;
-
- .user-visits {
- min-height: 200px;
-
- .roomvisits-container {
- div.room-visit {
- border-bottom: 1px solid rgba(0, 0, 0, 0.2);
- }
- }
-
- }
-}
diff --git a/src/views/mod-tools/views/user/user-room-visits/ModToolsUserRoomVisitsView.tsx b/src/views/mod-tools/views/user/user-room-visits/ModToolsUserRoomVisitsView.tsx
deleted file mode 100644
index ac414847..00000000
--- a/src/views/mod-tools/views/user/user-room-visits/ModToolsUserRoomVisitsView.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { GetRoomVisitsMessageComposer, RoomVisitsData, RoomVisitsEvent } from '@nitrots/nitro-renderer';
-import { FC, useCallback, useEffect, useState } from 'react';
-import { AutoSizer, List, ListRowProps, ListRowRenderer } from 'react-virtualized';
-import { TryVisitRoom } from '../../../../../api';
-import { CreateMessageHook, SendMessageHook } from '../../../../../hooks';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
-import { ModToolsUserRoomVisitsViewProps } from './ModToolsUserRoomVisitsView.types';
-
-export const ModToolsUserRoomVisitsView: FC = props =>
-{
- const { userId = null, onCloseClick = null } = props;
-
- const [roomVisitData, setRoomVisitData] = useState(null);
-
- useEffect(() =>
- {
- SendMessageHook(new GetRoomVisitsMessageComposer(userId));
- }, [userId]);
-
- const onModtoolReceivedRoomsUserEvent = useCallback((event: RoomVisitsEvent) =>
- {
- const parser = event.getParser();
-
- if(!parser || parser.data.userId !== userId) return;
-
- setRoomVisitData(parser.data);
- }, [userId]);
-
- CreateMessageHook(RoomVisitsEvent, onModtoolReceivedRoomsUserEvent);
-
- const RowRenderer: ListRowRenderer = (props: ListRowProps) =>
- {
- const item = roomVisitData.rooms[props.index];
-
- return (
-
-
{item.enterHour.toString().padStart(2, '0')}:{item.enterMinute.toString().padStart(2, '0')}
-
Room: {item.roomName}
-
-
);
- }
-
- return (
-
- onCloseClick() } />
-
- {roomVisitData &&
-
-
- {({ height, width }) =>
- {
- return (
-
- )
- }}
-
-
- }
-
-
- );
-}
diff --git a/src/views/mod-tools/views/user/user-room-visits/ModToolsUserRoomVisitsView.types.ts b/src/views/mod-tools/views/user/user-room-visits/ModToolsUserRoomVisitsView.types.ts
deleted file mode 100644
index a5188a3c..00000000
--- a/src/views/mod-tools/views/user/user-room-visits/ModToolsUserRoomVisitsView.types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-
-export interface ModToolsUserRoomVisitsViewProps
-{
- userId: number;
- onCloseClick: () => void;
-}
diff --git a/src/views/mod-tools/views/user/user-sendmessage/ModToolsSendUserMessage.types.ts b/src/views/mod-tools/views/user/user-sendmessage/ModToolsSendUserMessage.types.ts
deleted file mode 100644
index 617945f0..00000000
--- a/src/views/mod-tools/views/user/user-sendmessage/ModToolsSendUserMessage.types.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { ISelectedUser } from '../../../utils/ISelectedUser';
-
-export interface ModToolsSendUserMessageViewProps
-{
- user: ISelectedUser;
- onCloseClick: () => void;
-}
diff --git a/src/views/mod-tools/views/user/user-sendmessage/ModToolsSendUserMessageView.tsx b/src/views/mod-tools/views/user/user-sendmessage/ModToolsSendUserMessageView.tsx
deleted file mode 100644
index a332b426..00000000
--- a/src/views/mod-tools/views/user/user-sendmessage/ModToolsSendUserMessageView.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { ModMessageMessageComposer } from '@nitrots/nitro-renderer';
-import { FC, useCallback, useState } from 'react';
-import { NotificationAlertEvent } from '../../../../../events';
-import { dispatchUiEvent, SendMessageHook } from '../../../../../hooks';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
-import { ModToolsSendUserMessageViewProps } from './ModToolsSendUserMessage.types';
-
-export const ModToolsSendUserMessageView: FC = props =>
-{
- const { user = null, onCloseClick = null } = props;
- const [message, setMessage] = useState('');
-
-
- const sendMessage = useCallback(() =>
- {
- if(message.trim().length === 0)
- {
- dispatchUiEvent(new NotificationAlertEvent(['Please write a message to user.'], null, null, null, 'Error', null));
- return;
- }
-
- SendMessageHook(new ModMessageMessageComposer(user.userId, message, -999));
-
- onCloseClick();
- }, [message, onCloseClick, user.userId]);
-
- return (
-
- onCloseClick() } />
-
- {user && <>
- Message To: {user.username}
-
-
-
-
-
-
-
- >}
-
-
- );
-}
diff --git a/src/views/purse/PurseMessageHandler.types.ts b/src/views/purse/PurseMessageHandler.types.ts
deleted file mode 100644
index f9787398..00000000
--- a/src/views/purse/PurseMessageHandler.types.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface PurseMessageHandlerProps
-{
-
-}
diff --git a/src/views/purse/PurseView.scss b/src/views/purse/PurseView.scss
deleted file mode 100644
index 30ac9bff..00000000
--- a/src/views/purse/PurseView.scss
+++ /dev/null
@@ -1,39 +0,0 @@
-.nitro-purse {
- background-color: rgba($dark, 0.95);
- font-size: $font-size-sm;
- pointer-events: all;
- margin-bottom: 5px;
- padding: 6px 5px;
- box-shadow: inset 0px 5px lighten(rgba($dark, 0.6), 2.5),
- inset 0 -4px darken(rgba($dark, 0.6), 4);
-
- .notification-button {
- color: lighten($dark, 20);
- cursor: pointer;
- font-size: 0.9rem;
- pointer-events: all;
- display: none;
- }
-
- .nitro-purse-hc {
- background-color: rgba($light, 0.1);
- margin: 0 5px;
- }
-
- .nitro-purse-button {
- border-bottom: 1px solid rgba(0, 0, 0, 0.3);
- padding: 2px 3px;
- border-radius: $border-radius;
-
- &:last-child {
- border-bottom: none;
- }
-
- &:hover {
- background-color: rgba($light, 0.1);
- cursor: pointer;
- }
- }
-}
-
-@import "./views";
diff --git a/src/views/purse/PurseView.tsx b/src/views/purse/PurseView.tsx
deleted file mode 100644
index 5fd95166..00000000
--- a/src/views/purse/PurseView.tsx
+++ /dev/null
@@ -1,167 +0,0 @@
-import { FriendlyTime, HabboClubLevelEnum, UserCurrencyComposer, UserSubscriptionComposer } from '@nitrots/nitro-renderer';
-import { FC, useCallback, useEffect, useMemo, useState } from 'react';
-import { CreateLinkEvent, GetConfiguration, LocalizeText } from '../../api';
-import { HcCenterEvent } from '../../events/hc-center/HcCenterEvent';
-import { UserSettingsUIEvent } from '../../events/user-settings/UserSettingsUIEvent';
-import { dispatchUiEvent } from '../../hooks';
-import { SendMessageHook } from '../../hooks/messages/message-event';
-import { CurrencyIcon } from '../shared/currency-icon/CurrencyIcon';
-import { IPurse } from './common/IPurse';
-import { Purse } from './common/Purse';
-import { PurseContextProvider } from './context/PurseContext';
-import { PurseMessageHandler } from './PurseMessageHandler';
-import { CurrencyView } from './views/currency/CurrencyView';
-import { SeasonalView } from './views/seasonal/SeasonalView';
-
-export let GLOBAL_PURSE: IPurse = null;
-
-export const PurseView: FC<{}> = props =>
-{
- const [ purse, setPurse ] = useState(new Purse());
- const [ updateId, setUpdateId ] = useState(-1);
-
- const handleUserSettingsClick = useCallback(() =>
- {
- dispatchUiEvent(new UserSettingsUIEvent(UserSettingsUIEvent.TOGGLE_USER_SETTINGS));
- }, []);
-
- const handleHelpCenterClick = useCallback(() =>
- {
- CreateLinkEvent('help/show');
- }, []);
-
- const handleHcCenterClick = useCallback(() =>
- {
- dispatchUiEvent(new HcCenterEvent(HcCenterEvent.TOGGLE_HC_CENTER));
- }, []);
-
- const displayedCurrencies = useMemo(() =>
- {
- return GetConfiguration('system.currency.types', []);
- }, []);
-
- const currencyDisplayNumberShort = useMemo(() =>
- {
- return GetConfiguration('currency.display.number.short', false);
- }, []);
-
- const getCurrencyElements = useCallback((offset: number, limit: number = -1, seasonal: boolean = false) =>
- {
- if(!purse.activityPoints.size) return null;
-
- const types = Array.from(purse.activityPoints.keys()).filter(type => (displayedCurrencies.indexOf(type) >= 0));
-
- let count = 0;
-
- while(count < offset)
- {
- types.shift();
-
- count++;
- }
-
- count = 0;
-
- const elements: JSX.Element[] = [];
-
- for(const type of types)
- {
- if((limit > -1) && (count === limit)) break;
-
- if(seasonal) elements.push();
- else elements.push();
-
- count++;
- }
-
- return elements;
- }, [ purse, displayedCurrencies, currencyDisplayNumberShort ]);
-
- const getClubText = useCallback(() =>
- {
- const totalDays = ((purse.clubPeriods * 31) + purse.clubDays);
- const minutesUntilExpiration = purse.minutesUntilExpiration;
-
- if(purse.clubLevel === HabboClubLevelEnum.NO_CLUB)
- {
- return LocalizeText('purse.clubdays.zero.amount.text');
- }
-
- else if((minutesUntilExpiration > -1) && (minutesUntilExpiration < (60 * 24)))
- {
- return FriendlyTime.shortFormat(minutesUntilExpiration * 60);
- }
-
- else
- {
- return FriendlyTime.shortFormat(totalDays * 86400);
- }
- }, [ purse ]);
-
- useEffect(() =>
- {
- const purse = new Purse();
-
- GLOBAL_PURSE = purse;
-
- purse.notifier = () => setUpdateId(prevValue => (prevValue + 1));
-
- setPurse(purse);
-
- return () => (purse.notifier = null);
- }, []);
-
- useEffect(() =>
- {
- if(!purse) return;
-
- SendMessageHook(new UserCurrencyComposer());
- }, [ purse ]);
-
- useEffect(() =>
- {
- SendMessageHook(new UserSubscriptionComposer('habbo_club'));
-
- const interval = setInterval(() =>
- {
- SendMessageHook(new UserSubscriptionComposer('habbo_club'));
- }, 50000);
-
- return () => clearInterval(interval);
- }, [ purse ]);
-
- if(!purse) return null;
-
- return (
-
-
-
-
-
-
-
- { getCurrencyElements(0, 2) }
-
-
-
-
-
- { getClubText() }
-
-
-
-
- {/*
-
-
*/}
-
- { getCurrencyElements(2, -1, true) }
-
- );
-}
diff --git a/src/views/purse/context/PurseContext.types.ts b/src/views/purse/context/PurseContext.types.ts
deleted file mode 100644
index 7470b465..00000000
--- a/src/views/purse/context/PurseContext.types.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { ProviderProps } from 'react';
-import { IPurse } from '../common/IPurse';
-
-export interface IPurseContext
-{
- purse: IPurse;
-}
-
-export interface PurseContextProps extends ProviderProps
-{
-
-}
diff --git a/src/views/purse/views/currency/CurrencyView.scss b/src/views/purse/views/currency/CurrencyView.scss
deleted file mode 100644
index eb77390d..00000000
--- a/src/views/purse/views/currency/CurrencyView.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-.nitro-currency {
- pointer-events: all;
- position: relative;
-}
diff --git a/src/views/purse/views/currency/CurrencyView.tsx b/src/views/purse/views/currency/CurrencyView.tsx
deleted file mode 100644
index 589eb03e..00000000
--- a/src/views/purse/views/currency/CurrencyView.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { FC, useMemo } from 'react';
-import { OverlayTrigger, Tooltip } from 'react-bootstrap';
-import { LocalizeFormattedNumber, LocalizeShortNumber } from '../../../../api';
-import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon';
-import { CurrencyViewProps } from './CurrencyView.types';
-
-export const CurrencyView: FC = props =>
-{
- const { type = -1, amount = -1, short = false } = props;
-
- const element = useMemo(() =>
- {
- return (
-
{ short ? LocalizeShortNumber(amount) : LocalizeFormattedNumber(amount) }
-
-
);
- }, [ amount, short, type ]);
-
- if(!short) return element;
-
- return (
-
- { LocalizeFormattedNumber(amount) }
-
- }>
- { element }
-
- );
-}
diff --git a/src/views/purse/views/currency/CurrencyView.types.ts b/src/views/purse/views/currency/CurrencyView.types.ts
deleted file mode 100644
index fc6684f8..00000000
--- a/src/views/purse/views/currency/CurrencyView.types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export interface CurrencyViewProps
-{
- type: number;
- amount: number;
- short: boolean;
-}
diff --git a/src/views/purse/views/index.scss b/src/views/purse/views/index.scss
deleted file mode 100644
index 52330b9e..00000000
--- a/src/views/purse/views/index.scss
+++ /dev/null
@@ -1,2 +0,0 @@
-@import "./currency/CurrencyView";
-@import "./seasonal/SeasonalView";
diff --git a/src/views/purse/views/seasonal/SeasonalView.scss b/src/views/purse/views/seasonal/SeasonalView.scss
deleted file mode 100644
index 901c0d8d..00000000
--- a/src/views/purse/views/seasonal/SeasonalView.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-.nitro-seasonal-currency {
- pointer-events: all;
- padding: 6px 5px;
- background-color: rgba($dark,.95);
- box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
- font-size: $font-size-sm;
- margin-bottom: 5px;
-
- .seasonal-text {
- color: rgba($light,.5);
- }
-}
diff --git a/src/views/purse/views/seasonal/SeasonalView.tsx b/src/views/purse/views/seasonal/SeasonalView.tsx
deleted file mode 100644
index 804b15b4..00000000
--- a/src/views/purse/views/seasonal/SeasonalView.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import { FC } from 'react';
-import { LocalizeFormattedNumber, LocalizeText } from '../../../../api';
-import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon';
-import { SeasonalViewProps } from './SeasonalView.types';
-
-export const SeasonalView: FC = props =>
-{
- const { type = -1, amount = -1 } = props;
-
- return (
-
-
- { LocalizeText(`purse.seasonal.currency.${ type }`) }
- { LocalizeFormattedNumber(amount) }
-
-
-
-
-
- );
-}
diff --git a/src/views/purse/views/seasonal/SeasonalView.types.ts b/src/views/purse/views/seasonal/SeasonalView.types.ts
deleted file mode 100644
index c7b8db5a..00000000
--- a/src/views/purse/views/seasonal/SeasonalView.types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-
-export interface SeasonalViewProps
-{
- type: number;
- amount: number;
-}
diff --git a/src/views/right-side/RightSideView.tsx b/src/views/right-side/RightSideView.tsx
deleted file mode 100644
index 49b4ebca..00000000
--- a/src/views/right-side/RightSideView.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { FC } from 'react';
-import { GroupRoomInformationView } from '../../components/groups/views/room-information/GroupRoomInformationView';
-import { NotificationCenterView } from '../notification-center/NotificationCenterView';
-import { PurseView } from '../purse/PurseView';
-import { RightSideProps } from './RightSideView.types';
-
-export const RightSideView: FC = props =>
-{
- return (
-
- );
-}
diff --git a/src/views/right-side/RightSideView.types.ts b/src/views/right-side/RightSideView.types.ts
deleted file mode 100644
index 25427597..00000000
--- a/src/views/right-side/RightSideView.types.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface RightSideProps
-{
-
-}
diff --git a/src/views/room-host/RoomHostView.scss b/src/views/room-host/RoomHostView.scss
deleted file mode 100644
index 7f2365ed..00000000
--- a/src/views/room-host/RoomHostView.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.nitro-room-host {
-
-}
diff --git a/src/views/room/widgets/chat-input/ChatInputView.scss b/src/views/room/widgets/chat-input/ChatInputView.scss
index 650a2e73..734dbcd2 100644
--- a/src/views/room/widgets/chat-input/ChatInputView.scss
+++ b/src/views/room/widgets/chat-input/ChatInputView.scss
@@ -4,7 +4,7 @@
align-items: center;
position: relative;
height: 40px;
- border-radius: 8px;
+ border-radius: $border-radius;
border: 2px solid rgb(0, 0, 0);
background: #EDEDED;
padding-right: 10px;
@@ -23,7 +23,7 @@
position: absolute;
width: 98%;
height: 5px;
- border-radius: 8px;
+ border-radius: $border-radius;
top: 1px;
left: 0;
right: 0;
diff --git a/src/views/room/widgets/infostand/InfoStandWidgetView.scss b/src/views/room/widgets/infostand/InfoStandWidgetView.scss
index 404b6a93..53ad09d5 100644
--- a/src/views/room/widgets/infostand/InfoStandWidgetView.scss
+++ b/src/views/room/widgets/infostand/InfoStandWidgetView.scss
@@ -27,7 +27,7 @@
background-color: rgba($light-dark, 1);
width: 100%;
max-width: 68px;
- border-radius: 3px;
+ border-radius: $border-radius;
margin-right: 5px;
&.pet {
diff --git a/src/views/room/widgets/infostand/views/user/InfoStandWidgetUserView.tsx b/src/views/room/widgets/infostand/views/user/InfoStandWidgetUserView.tsx
index 2a3d5320..44e90e40 100644
--- a/src/views/room/widgets/infostand/views/user/InfoStandWidgetUserView.tsx
+++ b/src/views/room/widgets/infostand/views/user/InfoStandWidgetUserView.tsx
@@ -5,12 +5,12 @@ import { FC, FocusEvent, KeyboardEvent, useCallback, useEffect, useState } from
import { GetGroupInformation, LocalizeText, RoomWidgetChangeMottoMessage, RoomWidgetUpdateInfostandUserEvent } from '../../../../../../api';
import { Base } from '../../../../../../common/Base';
import { Flex } from '../../../../../../common/Flex';
+import { RelationshipsContainerView } from '../../../../../../components/user-profile/views/RelationshipsContainerView';
import { CreateMessageHook, SendMessageHook } from '../../../../../../hooks';
import { CreateEventDispatcherHook } from '../../../../../../hooks/events';
import { UserProfileIconView } from '../../../../../../layout';
import { AvatarImageView } from '../../../../../shared/avatar-image/AvatarImageView';
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView';
-import { RelationshipsContainerView } from '../../../../../user-profile/views/relationships-container/RelationshipsContainerView';
import { useRoomContext } from '../../../../context/RoomContext';
import { InfoStandWidgetUserViewProps } from './InfoStandWidgetUserView.types';
diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx
index b5e9079d..6bf17ef8 100644
--- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx
+++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx
@@ -1,10 +1,9 @@
import { GetGuestRoomResultEvent, RoomLikeRoomComposer } from '@nitrots/nitro-renderer';
import classNames from 'classnames';
import { FC, useCallback, useEffect, useState } from 'react';
-import { LocalizeText, RoomWidgetZoomToggleMessage } from '../../../../api';
+import { CreateLinkEvent, LocalizeText, RoomWidgetZoomToggleMessage } from '../../../../api';
import { Base, Column, Flex, Text } from '../../../../common';
import { NavigatorEvent } from '../../../../events';
-import { ChatHistoryEvent } from '../../../../events/chat-history/ChatHistoryEvent';
import { dispatchUiEvent } from '../../../../hooks/events';
import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages';
import { useRoomContext } from '../../context/RoomContext';
@@ -33,7 +32,7 @@ export const RoomToolsWidgetView: FC<{}> = props =>
setIsZoomedIn(value => !value);
return;
case 'chat_history':
- dispatchUiEvent(new ChatHistoryEvent(ChatHistoryEvent.TOGGLE_CHAT_HISTORY));
+ CreateLinkEvent('chat-history/toggle');
return;
case 'like_room':
if(isLiked) return;
diff --git a/src/views/user-profile/UserProfileVew.scss b/src/views/user-profile/UserProfileVew.scss
deleted file mode 100644
index d335cddd..00000000
--- a/src/views/user-profile/UserProfileVew.scss
+++ /dev/null
@@ -1,49 +0,0 @@
-.user-profile {
- width: 560px;
-
- .content-area {
- color: black;
- }
-
- .user-container {
- border-right: 1px solid gray;
-
- .avatar-image {
- left: -10px;
- }
-
- .add-friend {
- margin: 5px;
- margin-left: 10px;
- }
- }
-
- .badge-container {
- min-height: 50px;
- background: rgba(0, 0, 0, 0.1);
- border-radius: 5px;
- margin: 0px;
- margin-bottom: 2px;
- }
-
- .rooms-button-container {
- border-top: 1px solid gray;
- border-bottom: 1px solid gray;
- padding: 1px;
-
- .rooms-button {
- display: inline-block;
- text-align: center;
- height: 100%;
- text-decoration: underline;
- margin-left: 10px;
- }
- }
-
- .friends-container {
- height: 100%;
- }
-}
-
-@import './views/relationships-container/RelationshipsContainerView';
-@import './views/groups-container/GroupsContainerView';
diff --git a/src/views/user-profile/UserProfileView.tsx b/src/views/user-profile/UserProfileView.tsx
deleted file mode 100644
index 33cfb22e..00000000
--- a/src/views/user-profile/UserProfileView.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, UserCurrentBadgesComposer, UserCurrentBadgesEvent, UserProfileEvent, UserProfileParser, UserRelationshipsComposer } from '@nitrots/nitro-renderer';
-import { FC, useCallback, useState } from 'react';
-import { GetSessionDataManager, GetUserProfile, LocalizeText } from '../../api';
-import { CreateMessageHook, SendMessageHook } from '../../hooks';
-import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
-import { BadgesContainerView } from './views/badges-container/BadgesContainerView';
-import { FriendsContainerView } from './views/friends-container/FriendsContainerView';
-import { GroupsContainerView } from './views/groups-container/GroupsContainerView';
-import { UserContainerView } from './views/user-container/UserContainerView';
-
-export const UserProfileView: FC = props =>
-{
- const [userProfile, setUserProfile] = useState(null);
- const [userBadges, setUserBadges] = useState([]);
- const [userRelationships, setUserRelationships] = useState(null);
-
- const OnClose = useCallback(() =>
- {
- setUserProfile(null);
- setUserBadges([]);
- setUserRelationships(null);
- }, []);
-
- const onLeaveGroup = useCallback(() =>
- {
- if(userProfile && userProfile.id === GetSessionDataManager().userId)
- {
- GetUserProfile(userProfile.id);
- }
- }, [ userProfile ]);
-
- const OnUserCurrentBadgesEvent = useCallback((event: UserCurrentBadgesEvent) =>
- {
- const parser = event.getParser();
-
- if(userProfile && parser.userId === userProfile.id)
- setUserBadges(parser.badges);
- }, [userProfile, setUserBadges]);
-
- CreateMessageHook(UserCurrentBadgesEvent, OnUserCurrentBadgesEvent);
-
- const OnUserRelationshipsEvent = useCallback((event: RelationshipStatusInfoEvent) =>
- {
- const parser = event.getParser();
-
- if(userProfile && parser.userId === userProfile.id)
- setUserRelationships(parser);
- }, [userProfile, setUserRelationships]);
-
- CreateMessageHook(RelationshipStatusInfoEvent, OnUserRelationshipsEvent);
-
- const OnUserProfileEvent = useCallback((event: UserProfileEvent) =>
- {
- const parser = event.getParser();
-
- if(userProfile)
- {
- setUserProfile(null);
- setUserBadges([]);
- setUserRelationships(null);
- }
-
- setUserProfile(parser);
- SendMessageHook(new UserCurrentBadgesComposer(parser.id));
- SendMessageHook(new UserRelationshipsComposer(parser.id));
- }, [userProfile]);
-
- CreateMessageHook(UserProfileEvent, OnUserProfileEvent);
-
- if(!userProfile) return null;
-
- return (
-
-
-
-
-
-
-
-
-
- {
- userRelationships &&
- }
-
-
-
-
- {LocalizeText('extendedprofile.rooms')}
-
-
-
-
-
- )
-}
diff --git a/src/views/user-profile/views/badges-container/BadgesContainerView.types.ts b/src/views/user-profile/views/badges-container/BadgesContainerView.types.ts
deleted file mode 100644
index d57276ab..00000000
--- a/src/views/user-profile/views/badges-container/BadgesContainerView.types.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export interface BadgesContainerViewProps {
- badges: string[];
-}
diff --git a/src/views/user-profile/views/friends-container/FriendsContainerView.types.ts b/src/views/user-profile/views/friends-container/FriendsContainerView.types.ts
deleted file mode 100644
index 99ba31df..00000000
--- a/src/views/user-profile/views/friends-container/FriendsContainerView.types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer';
-
-export interface FriendsContainerViewProps {
- relationships: RelationshipStatusInfoMessageParser;
- friendsCount: number;
-}
diff --git a/src/views/user-profile/views/groups-container/GroupsContainerView.scss b/src/views/user-profile/views/groups-container/GroupsContainerView.scss
deleted file mode 100644
index c4d8b17e..00000000
--- a/src/views/user-profile/views/groups-container/GroupsContainerView.scss
+++ /dev/null
@@ -1,23 +0,0 @@
-.profile-groups {
- height: 219px;
-
- .profile-groups-item {
- width: 50px;
- height: 50px;
- border-radius: $border-radius;
- border-color: $grid-border-color !important;
- background-color: $grid-bg-color;
- border: nth(map-values($border-widths), 2) solid;
-
- &.active {
- border-color: $grid-active-border-color !important;
- background-color: $grid-active-bg-color !important;
- }
-
- .icon {
- z-index: 1;
- top: 0px;
- right: 0px;
- }
- }
-}
diff --git a/src/views/user-profile/views/groups-container/GroupsContainerView.types.ts b/src/views/user-profile/views/groups-container/GroupsContainerView.types.ts
deleted file mode 100644
index 0bfdf75e..00000000
--- a/src/views/user-profile/views/groups-container/GroupsContainerView.types.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { HabboGroupEntryData } from '@nitrots/nitro-renderer';
-
-export interface GroupsContainerViewProps
-{
- itsMe: boolean;
- groups: HabboGroupEntryData[];
- onLeaveGroup: () => void;
-}
diff --git a/src/views/user-profile/views/relationships-container/RelationshipsContainerView.scss b/src/views/user-profile/views/relationships-container/RelationshipsContainerView.scss
deleted file mode 100644
index 631424c4..00000000
--- a/src/views/user-profile/views/relationships-container/RelationshipsContainerView.scss
+++ /dev/null
@@ -1,35 +0,0 @@
-.relationships-container {
-
- .relationship-container {
-
- .relationship
- {
- position: relative;
-
- &.advanced {
- background-color: white;
- padding: 5px;
- border-radius: 5px;
- }
-
- .relationship-text {
- text-decoration: underline;
- }
-
- .avatar-image {
- position: absolute;
- width: 50px;
- height: 80px;
- right: 0;
- margin-top: -60px;
- }
- }
-
- .others-text {
- margin-left: 20px;
- height: 21px;
- color: #939392;
- }
- }
-
-}
diff --git a/src/views/user-profile/views/relationships-container/RelationshipsContainerView.types.ts b/src/views/user-profile/views/relationships-container/RelationshipsContainerView.types.ts
deleted file mode 100644
index 2bf0d119..00000000
--- a/src/views/user-profile/views/relationships-container/RelationshipsContainerView.types.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { RelationshipStatusInfoMessageParser } from '@nitrots/nitro-renderer';
-
-export interface RelationshipsContainerViewProps
-{
- relationships: RelationshipStatusInfoMessageParser;
- simple?: boolean;
-}
diff --git a/src/views/user-profile/views/user-container/UserContainerView.types.ts b/src/views/user-profile/views/user-container/UserContainerView.types.ts
deleted file mode 100644
index 88df91d4..00000000
--- a/src/views/user-profile/views/user-container/UserContainerView.types.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { UserProfileParser } from '@nitrots/nitro-renderer';
-
-export interface UserContainerViewProps
-{
- userProfile: UserProfileParser;
-}