This commit is contained in:
Layne 2022-03-23 03:10:06 -04:00
commit 1c8c404d3e
97 changed files with 556 additions and 537 deletions

View File

@ -19,7 +19,7 @@ $grid-active-border-color: $white;
$toolbar-height: 55px; $toolbar-height: 55px;
$achievement-width: 375px; $achievement-width: 375px;
$achievement-height: 425px; $achievement-height: 415px;
$avatar-editor-width: 620px; $avatar-editor-width: 620px;
$avatar-editor-height: 374px; $avatar-editor-height: 374px;

View File

@ -0,0 +1,13 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { GetLocalization } from '..';
export const GetAchievementBadgeCode = (achievement: AchievementData) =>
{
if(!achievement) return null;
let badgeId = achievement.badgeId;
if(!achievement.finalLevel) badgeId = GetLocalization().getPreviousLevelBadgeId(badgeId);
return badgeId;
}

View File

@ -0,0 +1,10 @@
import { AchievementData } from '@nitrots/nitro-renderer';
export const GetAchievementHasStarted = (achievement: AchievementData) =>
{
if(!achievement) return false;
if(achievement.finalLevel || ((achievement.level - 1) > 0)) return true;
return false;
}

View File

@ -0,0 +1,15 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { GetConfiguration } from '..';
export const GetAchievementIsIgnored = (achievement: AchievementData) =>
{
if(!achievement) return false;
const ignored = GetConfiguration<string[]>('achievements.unseen.ignored');
const value = achievement.badgeId.replace(/[0-9]/g, '');
const index = ignored.indexOf(value);
if(index >= 0) return true;
return false;
}

View File

@ -0,0 +1,5 @@
export * from './AchievementCategory';
export * from './GetAchievementBadgeCode';
export * from './GetAchievementHasStarted';
export * from './GetAchievementIsIgnored';
export * from './GetAchievementLevel';

View File

@ -1,3 +1,4 @@
export * from './achievements';
export * from './common'; export * from './common';
export * from './core'; export * from './core';
export * from './friends'; export * from './friends';

View File

@ -0,0 +1,31 @@
import { FC, useMemo } from 'react';
import { Base, BaseProps, Flex } from '..';
interface LayoutProgressBarProps extends BaseProps<HTMLDivElement>
{
text: string;
progress: number;
maxProgress?: number;
}
export const LayoutProgressBar: FC<LayoutProgressBarProps> = props =>
{
const { text = '', progress = 0, maxProgress = 0, position = 'relative', classNames = [], children = null, ...rest } = props;
const getClassNames = useMemo(() =>
{
const newClassNames: string[] = [ 'progress', 'text-black' ];
if(classNames.length) newClassNames.push(...classNames);
return newClassNames;
}, [ classNames ]);
return (
<Base position={ position } classNames={ getClassNames } { ...rest }>
<Flex fit center position="absolute">{ text }</Flex>
<Base className="progress-bar bg-success" style={ { width: (~~((((progress - 0) * (100 - 0)) / (maxProgress - 0)) + 0) + '%') }} />
{ children }
</Base>
);
}

View File

@ -11,6 +11,7 @@ export * from './LayoutMiniCameraView';
export * from './LayoutNotificationAlertView'; export * from './LayoutNotificationAlertView';
export * from './LayoutNotificationBubbleView'; export * from './LayoutNotificationBubbleView';
export * from './LayoutPetImageView'; export * from './LayoutPetImageView';
export * from './LayoutProgressBar';
export * from './LayoutRarityLevelView'; export * from './LayoutRarityLevelView';
export * from './LayoutRoomPreviewerView'; export * from './LayoutRoomPreviewerView';
export * from './LayoutRoomThumbnailView'; export * from './LayoutRoomThumbnailView';

View File

@ -1,13 +1,11 @@
import { AchievementData, AchievementEvent, AchievementsEvent, AchievementsScoreEvent, RequestAchievementsMessageComposer } from '@nitrots/nitro-renderer'; import { AchievementData, AchievementEvent, AchievementsEvent, AchievementsScoreEvent, ILinkEventTracker, RequestAchievementsMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { GetConfiguration, LocalizeText, SendMessageComposer } from '../../api'; import { AchievementCategory, AddEventLinkTracker, GetAchievementIsIgnored, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
import { Base, Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, Text } from '../../common'; import { Base, Column, LayoutProgressBar, NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, Text } from '../../common';
import { AchievementsUIEvent, AchievementsUIUnseenCountEvent } from '../../events'; import { AchievementsUIUnseenCountEvent } from '../../events';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook, UseUiEvent } from '../../hooks'; import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../hooks';
import { AchievementCategory } from './common/AchievementCategory'; import { AchievementCategoryView } from './views/AchievementCategoryView';
import { AchievementUtilities } from './common/AchievementUtilities';
import { AchievementsCategoryListView } from './views/category-list/AchievementsCategoryListView'; import { AchievementsCategoryListView } from './views/category-list/AchievementsCategoryListView';
import { AchievementCategoryView } from './views/category/AchievementCategoryView';
export const AchievementsView: FC<{}> = props => export const AchievementsView: FC<{}> = props =>
{ {
@ -17,33 +15,16 @@ export const AchievementsView: FC<{}> = props =>
const [ selectedCategoryCode, setSelectedCategoryCode ] = useState<string>(null); const [ selectedCategoryCode, setSelectedCategoryCode ] = useState<string>(null);
const [ achievementScore, setAchievementScore ] = useState(0); const [ achievementScore, setAchievementScore ] = useState(0);
const onAchievementsUIEvent = useCallback((event: AchievementsUIEvent) =>
{
switch(event.type)
{
case AchievementsUIEvent.SHOW_ACHIEVEMENTS:
setIsVisible(true);
return;
case AchievementsUIEvent.HIDE_ACHIEVEMENTS:
setIsVisible(false);
return;
case AchievementsUIEvent.TOGGLE_ACHIEVEMENTS:
setIsVisible(value => !value);
return;
}
}, []);
UseUiEvent(AchievementsUIEvent.SHOW_ACHIEVEMENTS, onAchievementsUIEvent);
UseUiEvent(AchievementsUIEvent.HIDE_ACHIEVEMENTS, onAchievementsUIEvent);
UseUiEvent(AchievementsUIEvent.TOGGLE_ACHIEVEMENTS, onAchievementsUIEvent);
const onAchievementEvent = useCallback((event: AchievementEvent) => const onAchievementEvent = useCallback((event: AchievementEvent) =>
{ {
const parser = event.getParser(); const parser = event.getParser();
const achievement = parser.achievement; const achievement = parser.achievement;
const newCategories = [ ...achievementCategories ];
const categoryName = achievement.category; const categoryName = achievement.category;
const categoryIndex = newCategories.findIndex(existing => (existing.code === categoryName));
setAchievementCategories(prevValue =>
{
const newValue = [ ...prevValue ];
const categoryIndex = newValue.findIndex(existing => (existing.code === categoryName));
if(categoryIndex === -1) if(categoryIndex === -1)
{ {
@ -51,11 +32,11 @@ export const AchievementsView: FC<{}> = props =>
category.achievements.push(achievement); category.achievements.push(achievement);
newCategories.push(category); newValue.push(category);
} }
else else
{ {
const category = newCategories[categoryIndex]; const category = newValue[categoryIndex];
const newAchievements = [ ...category.achievements ]; const newAchievements = [ ...category.achievements ];
const achievementIndex = newAchievements.findIndex(existing => (existing.achievementId === achievement.achievementId)); const achievementIndex = newAchievements.findIndex(existing => (existing.achievementId === achievement.achievementId));
let previousAchievement: AchievementData = null; let previousAchievement: AchievementData = null;
@ -71,7 +52,7 @@ export const AchievementsView: FC<{}> = props =>
newAchievements[achievementIndex] = achievement; newAchievements[achievementIndex] = achievement;
} }
if(!AchievementUtilities.isIgnoredAchievement(achievement)) if(!GetAchievementIsIgnored(achievement))
{ {
achievement.unseen++; achievement.unseen++;
@ -81,8 +62,9 @@ export const AchievementsView: FC<{}> = props =>
category.achievements = newAchievements; category.achievements = newAchievements;
} }
setAchievementCategories(newCategories); return newValue;
}, [ achievementCategories ]); });
}, []);
UseMessageEventHook(AchievementEvent, onAchievementEvent); UseMessageEventHook(AchievementEvent, onAchievementEvent);
@ -95,6 +77,7 @@ export const AchievementsView: FC<{}> = props =>
for(const achievement of parser.achievements) for(const achievement of parser.achievements)
{ {
const categoryName = achievement.category; const categoryName = achievement.category;
let existing = categories.find(category => (category.code === categoryName)); let existing = categories.find(category => (category.code === categoryName));
if(!existing) if(!existing)
@ -167,20 +150,13 @@ export const AchievementsView: FC<{}> = props =>
return achievementCategories.find(existing => (existing.code === selectedCategoryCode)); return achievementCategories.find(existing => (existing.code === selectedCategoryCode));
}, [ achievementCategories, selectedCategoryCode ]); }, [ achievementCategories, selectedCategoryCode ]);
const getCategoryIcon = useMemo(() =>
{
if(!getSelectedCategory) return null;
const imageUrl = GetConfiguration<string>('achievements.images.url');
return imageUrl.replace('%image%', `achicon_${ getSelectedCategory.code }`);
}, [ getSelectedCategory ]);
const setAchievementSeen = useCallback((code: string, achievementId: number) => const setAchievementSeen = useCallback((code: string, achievementId: number) =>
{ {
const newCategories = [ ...achievementCategories ]; setAchievementCategories(prevValue =>
{
const newValue = [ ...prevValue ];
for(const category of newCategories) for(const category of newValue)
{ {
if(category.code !== code) continue; if(category.code !== code) continue;
@ -192,8 +168,41 @@ export const AchievementsView: FC<{}> = props =>
} }
} }
setAchievementCategories(newCategories); return newValue;
}, [ achievementCategories ]); });
}, []);
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: 'achievements/'
};
AddEventLinkTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, [ linkReceived ]);
useEffect(() => useEffect(() =>
{ {
@ -220,15 +229,12 @@ export const AchievementsView: FC<{}> = props =>
<Text>{ LocalizeText('achievements.details.categoryprogress', [ 'progress', 'limit' ], [ getSelectedCategory.getProgress().toString(), getSelectedCategory.getMaxProgress().toString() ]) }</Text> <Text>{ LocalizeText('achievements.details.categoryprogress', [ 'progress', 'limit' ], [ getSelectedCategory.getProgress().toString(), getSelectedCategory.getMaxProgress().toString() ]) }</Text>
</Column> </Column>
</NitroCardSubHeaderView> } </NitroCardSubHeaderView> }
<NitroCardContentView> <NitroCardContentView gap={ 1 }>
{ !getSelectedCategory && { !getSelectedCategory &&
<> <>
<AchievementsCategoryListView categories={ achievementCategories } selectedCategoryCode={ selectedCategoryCode } setSelectedCategoryCode={ setSelectedCategoryCode } /> <AchievementsCategoryListView categories={ achievementCategories } selectedCategoryCode={ selectedCategoryCode } setSelectedCategoryCode={ setSelectedCategoryCode } />
<Column grow justifyContent="end"> <Column grow justifyContent="end">
<Base className="progress" position="relative"> <LayoutProgressBar text={ LocalizeText('achievements.categories.totalprogress', [ 'progress', 'limit' ], [ getProgress.toString(), getMaxProgress.toString() ]) } progress={ getProgress } maxProgress={ getMaxProgress } />
<Flex fit center position="absolute" className="text-black">{ LocalizeText('achievements.categories.totalprogress', [ 'progress', 'limit' ], [ getProgress.toString(), getMaxProgress.toString() ]) }</Flex>
<Base className="progress-bar bg-success" style={ { width: (scaledProgressPercent + '%') }} />
</Base>
<Text className="bg-muted rounded p-1" center>{ LocalizeText('achievements.categories.score', [ 'score' ], [ achievementScore.toString() ]) }</Text> <Text className="bg-muted rounded p-1" center>{ LocalizeText('achievements.categories.score', [ 'score' ], [ achievementScore.toString() ]) }</Text>
</Column> </Column>
</> } </> }

View File

@ -1,38 +0,0 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { GetConfiguration, GetLocalization } from '../../../api';
export class AchievementUtilities
{
public static hasStarted(achievement: AchievementData): boolean
{
if(!achievement) return false;
if(achievement.finalLevel || ((achievement.level - 1) > 0)) return true;
return false;
}
public static getBadgeCode(achievement: AchievementData): string
{
if(!achievement) return null;
let badgeId = achievement.badgeId;
if(!achievement.finalLevel) badgeId = GetLocalization().getPreviousLevelBadgeId(badgeId);
return badgeId;
}
public static isIgnoredAchievement(achievement: AchievementData): boolean
{
if(!achievement) return false;
const ignored = GetConfiguration<string[]>('achievements.unseen.ignored');
const value = achievement.badgeId.replace(/[0-9]/g, '');
const index = ignored.indexOf(value);
if(index >= 0) return true;
return false;
}
}

View File

@ -1,8 +0,0 @@
import { AchievementData } from '@nitrots/nitro-renderer';
export const GetScaledProgressPercent = (achievement: AchievementData) =>
{
if(!achievement) return 0;
return ~~(((((achievement.currentPoints + achievement.scoreAtStartOfLevel) - 0) * (100 - 0)) / ((achievement.scoreLimit + achievement.scoreAtStartOfLevel) - 0)) + 0);
}

View File

@ -0,0 +1,19 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { GetAchievementBadgeCode, GetAchievementHasStarted } from '../../../api';
import { BaseProps, LayoutBadgeImageView } from '../../../common';
interface AchievementBadgeViewProps extends BaseProps<HTMLDivElement>
{
achievement: AchievementData;
scale?: number;
}
export const AchievementBadgeView: FC<AchievementBadgeViewProps> = props =>
{
const { achievement = null, scale = 1, ...rest } = props;
if(!achievement) return null;
return <LayoutBadgeImageView badgeCode={ GetAchievementBadgeCode(achievement) } isGrayscale={ !GetAchievementHasStarted(achievement) } scale={ scale } { ...rest } />;
}

View File

@ -1,10 +1,10 @@
import { FC, useEffect, useMemo, useState } from 'react'; import { FC, useEffect, useMemo, useState } from 'react';
import { Column } from '../../../../common/Column'; import { AchievementCategory } from '../../../api';
import { AchievementCategory } from '../../common/AchievementCategory'; import { Column } from '../../../common';
import { AchievementDetailsView } from '../achievement-details/AchievementDetailsView'; import { AchievementListView } from './achievement-list/AchievementListView';
import { AchievementListView } from '../achievement-list/AchievementListView'; import { AchievementDetailsView } from './AchievementDetailsView';
export class AchievementCategoryViewProps interface AchievementCategoryViewProps
{ {
category: AchievementCategory; category: AchievementCategory;
setAchievementSeen: (code: string, achievementId: number) => void; setAchievementSeen: (code: string, achievementId: number) => void;

View File

@ -1,13 +1,11 @@
import { AchievementData } from '@nitrots/nitro-renderer'; import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react'; import { FC } from 'react';
import { LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../../../api'; import { GetAchievementBadgeCode, LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../../api';
import { Base, Column, Flex, LayoutCurrencyIcon, Text } from '../../../../common'; import { GetAchievementLevel } from '../../../api/achievements/GetAchievementLevel';
import { AchievementUtilities } from '../../common/AchievementUtilities'; import { Column, Flex, LayoutCurrencyIcon, LayoutProgressBar, Text } from '../../../common';
import { GetAchievementLevel } from '../../common/GetAchievementLevel'; import { AchievementBadgeView } from './AchievementBadgeView';
import { GetScaledProgressPercent } from '../../common/GetScaledProgressPercent';
import { AchievementBadgeView } from '../achievement-badge/AchievementBadgeView';
export interface AchievementDetailsViewProps interface AchievementDetailsViewProps
{ {
achievement: AchievementData; achievement: AchievementData;
} }
@ -19,7 +17,6 @@ export const AchievementDetailsView: FC<AchievementDetailsViewProps> = props =>
if(!achievement) return null; if(!achievement) return null;
const achievementLevel = GetAchievementLevel(achievement); const achievementLevel = GetAchievementLevel(achievement);
const scaledProgressPercent = GetScaledProgressPercent(achievement);
return ( return (
<Flex shrink className="bg-muted rounded p-2 text-black" gap={ 2 } overflow="hidden"> <Flex shrink className="bg-muted rounded p-2 text-black" gap={ 2 } overflow="hidden">
@ -32,10 +29,10 @@ export const AchievementDetailsView: FC<AchievementDetailsViewProps> = props =>
<Column fullWidth justifyContent="center" overflow="hidden"> <Column fullWidth justifyContent="center" overflow="hidden">
<Column gap={ 1 }> <Column gap={ 1 }>
<Text fontWeight="bold" truncate> <Text fontWeight="bold" truncate>
{ LocalizeBadgeName(AchievementUtilities.getBadgeCode(achievement)) } { LocalizeBadgeName(GetAchievementBadgeCode(achievement)) }
</Text> </Text>
<Text truncate> <Text textBreak>
{ LocalizeBadgeDescription(AchievementUtilities.getBadgeCode(achievement)) } { LocalizeBadgeDescription(GetAchievementBadgeCode(achievement)) }
</Text> </Text>
</Column> </Column>
{ ((achievement.levelRewardPoints > 0) || (achievement.scoreLimit > 0)) && { ((achievement.levelRewardPoints > 0) || (achievement.scoreLimit > 0)) &&
@ -51,10 +48,7 @@ export const AchievementDetailsView: FC<AchievementDetailsViewProps> = props =>
</Flex> </Flex>
</Flex> } </Flex> }
{ (achievement.scoreLimit > 0) && { (achievement.scoreLimit > 0) &&
<Base className="progress" position="relative"> <LayoutProgressBar text={ LocalizeText('achievements.details.progress', [ 'progress', 'limit' ], [ (achievement.currentPoints + achievement.scoreAtStartOfLevel).toString(), (achievement.scoreLimit + achievement.scoreAtStartOfLevel).toString() ]) } progress={ (achievement.currentPoints + achievement.scoreAtStartOfLevel) } maxProgress={ (achievement.scoreLimit + achievement.scoreAtStartOfLevel) } /> }
<Flex fit center position="absolute" className="text-black"> { LocalizeText('achievements.details.progress', [ 'progress', 'limit' ], [ (achievement.currentPoints + achievement.scoreAtStartOfLevel).toString(), (achievement.scoreLimit + achievement.scoreAtStartOfLevel).toString() ]) }</Flex>
<Base className="progress-bar" style={ { width: (scaledProgressPercent + '%') }} />
</Base> }
</Column> } </Column> }
</Column> </Column>
</Flex> </Flex>

View File

@ -1,21 +0,0 @@
import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { BaseProps, LayoutBadgeImageView } from '../../../../common';
import { AchievementUtilities } from '../../common/AchievementUtilities';
export interface AchievementBadgeViewProps extends BaseProps<HTMLDivElement>
{
achievement: AchievementData;
scale?: number;
}
export const AchievementBadgeView: FC<AchievementBadgeViewProps> = props =>
{
const { achievement = null, scale = 1, ...rest } = props;
if(!achievement) return null;
return (
<LayoutBadgeImageView badgeCode={ AchievementUtilities.getBadgeCode(achievement) } isGrayscale={ !AchievementUtilities.hasStarted(achievement) } scale={ scale } { ...rest } />
);
}

View File

@ -1,9 +1,9 @@
import { AchievementData } from '@nitrots/nitro-renderer'; import { AchievementData } from '@nitrots/nitro-renderer';
import { FC } from 'react'; import { FC } from 'react';
import { LayoutGridItem, LayoutGridItemProps } from '../../../../common/layout/LayoutGridItem'; import { LayoutGridItem, LayoutGridItemProps } from '../../../../common';
import { AchievementBadgeView } from '../achievement-badge/AchievementBadgeView'; import { AchievementBadgeView } from '../AchievementBadgeView';
export interface AchievementListItemViewProps extends LayoutGridItemProps interface AchievementListItemViewProps extends LayoutGridItemProps
{ {
achievement: AchievementData; achievement: AchievementData;
} }

View File

@ -1,6 +1,6 @@
import { AchievementData } from '@nitrots/nitro-renderer'; import { AchievementData } from '@nitrots/nitro-renderer';
import { Dispatch, FC, SetStateAction } from 'react'; import { Dispatch, FC, SetStateAction } from 'react';
import { AutoGrid } from '../../../../common/AutoGrid'; import { AutoGrid } from '../../../../common';
import { AchievementListItemView } from './AchievementListItemView'; import { AchievementListItemView } from './AchievementListItemView';
export interface AchievementListViewProps export interface AchievementListViewProps

View File

@ -1,9 +1,6 @@
import { FC, useCallback, useMemo } from 'react'; import { FC, useCallback, useMemo } from 'react';
import { GetConfiguration, LocalizeText } from '../../../../api'; import { AchievementCategory, GetConfiguration, LocalizeText } from '../../../../api';
import { LayoutGridItem, LayoutGridItemProps } from '../../../../common/layout/LayoutGridItem'; import { LayoutGridItem, LayoutGridItemProps, LayoutImage, Text } from '../../../../common';
import { LayoutImage } from '../../../../common/layout/LayoutImage';
import { Text } from '../../../../common/Text';
import { AchievementCategory } from '../../common/AchievementCategory';
export interface AchievementCategoryListItemViewProps extends LayoutGridItemProps export interface AchievementCategoryListItemViewProps extends LayoutGridItemProps
{ {

View File

@ -1,6 +1,6 @@
import { Dispatch, FC, SetStateAction } from 'react'; import { Dispatch, FC, SetStateAction } from 'react';
import { AutoGrid } from '../../../../common/AutoGrid'; import { AchievementCategory } from '../../../../api';
import { AchievementCategory } from '../../common/AchievementCategory'; import { AutoGrid } from '../../../../common';
import { AchievementsCategoryListItemView } from './AchievementsCategoryListItemView'; import { AchievementsCategoryListItemView } from './AchievementsCategoryListItemView';
export interface AchievementsCategoryListViewProps export interface AchievementsCategoryListViewProps

View File

@ -48,6 +48,8 @@ export const InventoryMessageHandler: FC<{}> = props =>
type: InventoryFurnitureActions.PROCESS_FRAGMENT, type: InventoryFurnitureActions.PROCESS_FRAGMENT,
payload: { fragment, unseenTracker } payload: { fragment, unseenTracker }
}); });
furniMsgFragments = null;
}, [ unseenTracker, dispatchFurnitureState ]); }, [ unseenTracker, dispatchFurnitureState ]);
const onFurnitureListInvalidateEvent = useCallback((event: FurnitureListInvalidateEvent) => const onFurnitureListInvalidateEvent = useCallback((event: FurnitureListInvalidateEvent) =>

View File

@ -1,4 +1,4 @@
import { NavigatorCategoryDataParser, NavigatorSearchResultSet, NavigatorTopLevelContext } from '@nitrots/nitro-renderer'; import { NavigatorCategoryDataParser, NavigatorSearchResultSet, NavigatorTopLevelContext, RoomDataParser } from '@nitrots/nitro-renderer';
import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react'; import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react';
import { NavigatorData } from './common/NavigatorData'; import { NavigatorData } from './common/NavigatorData';
@ -12,6 +12,8 @@ interface INavigatorContext
setTopLevelContexts: Dispatch<SetStateAction<NavigatorTopLevelContext[]>>; setTopLevelContexts: Dispatch<SetStateAction<NavigatorTopLevelContext[]>>;
navigatorData: NavigatorData; navigatorData: NavigatorData;
setNavigatorData: Dispatch<SetStateAction<NavigatorData>>; setNavigatorData: Dispatch<SetStateAction<NavigatorData>>;
doorData: { roomInfo: RoomDataParser, state: number };
setDoorData: Dispatch<SetStateAction<{ roomInfo: RoomDataParser, state: number }>>;
searchResult: NavigatorSearchResultSet; searchResult: NavigatorSearchResultSet;
setSearchResult: Dispatch<SetStateAction<NavigatorSearchResultSet>>; setSearchResult: Dispatch<SetStateAction<NavigatorSearchResultSet>>;
} }
@ -25,6 +27,8 @@ const NavigatorContext = createContext<INavigatorContext>({
setTopLevelContexts: null, setTopLevelContexts: null,
navigatorData: null, navigatorData: null,
setNavigatorData: null, setNavigatorData: null,
doorData: null,
setDoorData: null,
searchResult: null, searchResult: null,
setSearchResult: null setSearchResult: null
}); });

View File

@ -1,13 +1,13 @@
import { CanCreateRoomEventEvent, CantConnectMessageParser, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomResultEvent, HabboWebTools, LegacyExternalInterface, NavigatorCategoriesComposer, NavigatorCategoriesEvent, NavigatorHomeRoomEvent, NavigatorMetadataEvent, NavigatorOpenRoomCreatorEvent, NavigatorSearchEvent, NavigatorSettingsComposer, RoomCreatedEvent, RoomDataParser, RoomDoorbellAcceptedEvent, RoomDoorbellEvent, RoomDoorbellRejectedEvent, RoomEnterErrorEvent, RoomEntryInfoMessageEvent, RoomForwardEvent, RoomInfoComposer, RoomScoreEvent, RoomSettingsUpdatedEvent, SecurityLevel, UserInfoEvent, UserPermissionsEvent } from '@nitrots/nitro-renderer'; import { CanCreateRoomEventEvent, CantConnectMessageParser, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomResultEvent, HabboWebTools, LegacyExternalInterface, NavigatorCategoriesComposer, NavigatorCategoriesEvent, NavigatorHomeRoomEvent, NavigatorMetadataEvent, NavigatorOpenRoomCreatorEvent, NavigatorSearchEvent, NavigatorSettingsComposer, RoomCreatedEvent, RoomDataParser, RoomDoorbellAcceptedEvent, RoomDoorbellEvent, RoomDoorbellRejectedEvent, RoomEnterErrorEvent, RoomEntryInfoMessageEvent, RoomForwardEvent, RoomInfoComposer, RoomScoreEvent, RoomSettingsUpdatedEvent, SecurityLevel, UserInfoEvent, UserPermissionsEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react'; import { FC, useCallback } from 'react';
import { CreateLinkEvent, CreateRoomSession, GetConfiguration, GetSessionDataManager, LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer, TryVisitRoom, VisitDesktop } from '../../api'; import { CreateLinkEvent, CreateRoomSession, GetConfiguration, GetSessionDataManager, LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer, TryVisitRoom, VisitDesktop } from '../../api';
import { UpdateDoorStateEvent } from '../../events'; import { BatchUpdates, UseMessageEventHook } from '../../hooks';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../hooks'; import { DoorStateType } from './common/DoorStateType';
import { useNavigatorContext } from './NavigatorContext'; import { useNavigatorContext } from './NavigatorContext';
export const NavigatorMessageHandler: FC<{}> = props => export const NavigatorMessageHandler: FC<{}> = props =>
{ {
const { setCategories = null, setTopLevelContext = null, topLevelContexts = null, setTopLevelContexts = null, setNavigatorData = null, setSearchResult = null } = useNavigatorContext(); const { setCategories = null, setTopLevelContext = null, topLevelContexts = null, setTopLevelContexts = null, setNavigatorData = null, setDoorData = null, setSearchResult = null } = useNavigatorContext();
const onRoomSettingsUpdatedEvent = useCallback((event: RoomSettingsUpdatedEvent) => const onRoomSettingsUpdatedEvent = useCallback((event: RoomSettingsUpdatedEvent) =>
{ {
@ -92,6 +92,8 @@ export const NavigatorMessageHandler: FC<{}> = props =>
if(parser.roomEnter) if(parser.roomEnter)
{ {
setDoorData({ roomInfo: null, state: DoorStateType.NONE });
setNavigatorData(prevValue => setNavigatorData(prevValue =>
{ {
const newValue = { ...prevValue }; const newValue = { ...prevValue };
@ -123,10 +125,26 @@ export const NavigatorMessageHandler: FC<{}> = props =>
switch(parser.data.doorMode) switch(parser.data.doorMode)
{ {
case RoomDataParser.DOORBELL_STATE: case RoomDataParser.DOORBELL_STATE:
DispatchUiEvent(new UpdateDoorStateEvent(UpdateDoorStateEvent.START_DOORBELL, parser.data)); setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.roomInfo = parser.data;
newValue.state = DoorStateType.START_DOORBELL;
return newValue;
});
return; return;
case RoomDataParser.PASSWORD_STATE: case RoomDataParser.PASSWORD_STATE:
DispatchUiEvent(new UpdateDoorStateEvent(UpdateDoorStateEvent.START_PASSWORD, parser.data)); setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.roomInfo = parser.data;
newValue.state = DoorStateType.START_PASSWORD;
return newValue;
});
return; return;
} }
} }
@ -147,7 +165,7 @@ export const NavigatorMessageHandler: FC<{}> = props =>
return newValue; return newValue;
}); });
} }
}, [ setNavigatorData ]); }, [ setNavigatorData, setDoorData ]);
const onRoomScoreEvent = useCallback((event: RoomScoreEvent) => const onRoomScoreEvent = useCallback((event: RoomScoreEvent) =>
{ {
@ -170,9 +188,16 @@ export const NavigatorMessageHandler: FC<{}> = props =>
if(!parser.userName || (parser.userName.length === 0)) if(!parser.userName || (parser.userName.length === 0))
{ {
DispatchUiEvent(new UpdateDoorStateEvent(UpdateDoorStateEvent.STATE_WAITING)); setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.state = DoorStateType.STATE_WAITING;
return newValue;
});
} }
}, []); }, [ setDoorData ]);
const onRoomDoorbellAcceptedEvent = useCallback((event: RoomDoorbellAcceptedEvent) => const onRoomDoorbellAcceptedEvent = useCallback((event: RoomDoorbellAcceptedEvent) =>
{ {
@ -180,9 +205,16 @@ export const NavigatorMessageHandler: FC<{}> = props =>
if(!parser.userName || (parser.userName.length === 0)) if(!parser.userName || (parser.userName.length === 0))
{ {
DispatchUiEvent(new UpdateDoorStateEvent(UpdateDoorStateEvent.STATE_ACCEPTED)); setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.state = DoorStateType.STATE_ACCEPTED;
return newValue;
});
} }
}, []); }, [ setDoorData ]);
const onRoomDoorbellRejectedEvent = useCallback((event: RoomDoorbellRejectedEvent) => const onRoomDoorbellRejectedEvent = useCallback((event: RoomDoorbellRejectedEvent) =>
{ {
@ -190,9 +222,16 @@ export const NavigatorMessageHandler: FC<{}> = props =>
if(!parser.userName || (parser.userName.length === 0)) if(!parser.userName || (parser.userName.length === 0))
{ {
DispatchUiEvent(new UpdateDoorStateEvent(UpdateDoorStateEvent.STATE_NO_ANSWER)); setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.state = DoorStateType.STATE_NO_ANSWER;
return newValue;
});
} }
}, []); }, [ setDoorData ]);
const onGenericErrorEvent = useCallback((event: GenericErrorEvent) => const onGenericErrorEvent = useCallback((event: GenericErrorEvent) =>
{ {
@ -201,10 +240,33 @@ export const NavigatorMessageHandler: FC<{}> = props =>
switch(parser.errorCode) switch(parser.errorCode)
{ {
case -100002: case -100002:
DispatchUiEvent(new UpdateDoorStateEvent(UpdateDoorStateEvent.STATE_WRONG_PASSWORD)); setDoorData(prevValue =>
break; {
const newValue = { ...prevValue };
newValue.state = DoorStateType.STATE_WRONG_PASSWORD;
return newValue;
});
return;
case 4009:
NotificationUtilities.simpleAlert(LocalizeText('navigator.alert.need.to.be.vip'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title'));
return;
case 4010:
NotificationUtilities.simpleAlert(LocalizeText('navigator.alert.invalid_room_name'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title'));
return;
case 4011:
NotificationUtilities.simpleAlert(LocalizeText('navigator.alert.cannot_perm_ban'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title'));
return;
case 4013:
NotificationUtilities.simpleAlert(LocalizeText('navigator.alert.room_in_maintenance'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title'));
return;
} }
}, []); }, [ setDoorData ]);
const onNavigatorMetadataEvent = useCallback((event: NavigatorMetadataEvent) => const onNavigatorMetadataEvent = useCallback((event: NavigatorMetadataEvent) =>
{ {
@ -296,7 +358,7 @@ export const NavigatorMessageHandler: FC<{}> = props =>
let forwardType = -1; let forwardType = -1;
let forwardId = -1; let forwardId = -1;
if(GetConfiguration<string>('friend.id') !== undefined) if((GetConfiguration<string>('friend.id') !== undefined) && (parseInt(GetConfiguration<string>('friend.id')) > 0))
{ {
forwardType = 0; forwardType = 0;
SendMessageComposer(new FollowFriendMessageComposer(parseInt(GetConfiguration<string>('friend.id')))); SendMessageComposer(new FollowFriendMessageComposer(parseInt(GetConfiguration<string>('friend.id'))));
@ -316,16 +378,13 @@ export const NavigatorMessageHandler: FC<{}> = props =>
else if((forwardType === -1) && (parser.roomIdToEnter > 0)) else if((forwardType === -1) && (parser.roomIdToEnter > 0))
{ {
CreateLinkEvent('navigator/close'); CreateLinkEvent('navigator/close');
CreateRoomSession(parser.roomIdToEnter);
if(parser.roomIdToEnter !== parser.homeRoomId) if(parser.roomIdToEnter !== parser.homeRoomId)
{ {
CreateLinkEvent('navigator/close');
CreateRoomSession(parser.roomIdToEnter); CreateRoomSession(parser.roomIdToEnter);
} }
else else
{ {
CreateLinkEvent('navigator/close');
CreateRoomSession(parser.homeRoomId); CreateRoomSession(parser.homeRoomId);
} }
} }

View File

@ -1,18 +1,17 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { ConvertGlobalRoomIdMessageComposer, HabboWebTools, ILinkEventTracker, LegacyExternalInterface, NavigatorCategoryDataParser, NavigatorInitComposer, NavigatorSearchComposer, NavigatorSearchResultSet, NavigatorTopLevelContext, RoomDataParser, RoomSessionEvent } from '@nitrots/nitro-renderer'; import { ConvertGlobalRoomIdMessageComposer, HabboWebTools, ILinkEventTracker, LegacyExternalInterface, NavigatorCategoryDataParser, NavigatorInitComposer, NavigatorSearchComposer, NavigatorSearchResultSet, NavigatorTopLevelContext, RoomDataParser, RoomSessionEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { AddEventLinkTracker, GoToDesktop, LocalizeText, RemoveLinkEventTracker, SendMessageComposer, TryVisitRoom } from '../../api'; import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker, SendMessageComposer, TryVisitRoom } from '../../api';
import { Base, Column, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common'; import { Base, Column, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
import { UpdateDoorStateEvent } from '../../events'; import { BatchUpdates, UseRoomSessionManagerEvent, useSharedState } from '../../hooks';
import { BatchUpdates, UseRoomSessionManagerEvent, useSharedState, UseUiEvent } from '../../hooks'; import { DoorStateType } from './common/DoorStateType';
import { NavigatorData } from './common/NavigatorData'; import { NavigatorData } from './common/NavigatorData';
import { NavigatorContextProvider } from './NavigatorContext'; import { NavigatorContextProvider } from './NavigatorContext';
import { NavigatorMessageHandler } from './NavigatorMessageHandler'; import { NavigatorMessageHandler } from './NavigatorMessageHandler';
import { NavigatorDoorStateView } from './views/NavigatorDoorStateView';
import { NavigatorRoomCreatorView } from './views/NavigatorRoomCreatorView'; import { NavigatorRoomCreatorView } from './views/NavigatorRoomCreatorView';
import { NavigatorRoomDoorbellView } from './views/NavigatorRoomDoorbellView';
import { NavigatorRoomInfoView } from './views/NavigatorRoomInfoView'; import { NavigatorRoomInfoView } from './views/NavigatorRoomInfoView';
import { NavigatorRoomLinkView } from './views/NavigatorRoomLinkView'; import { NavigatorRoomLinkView } from './views/NavigatorRoomLinkView';
import { NavigatorRoomPasswordView } from './views/NavigatorRoomPasswordView';
import { NavigatorRoomSettingsView } from './views/room-settings/NavigatorRoomSettingsView'; import { NavigatorRoomSettingsView } from './views/room-settings/NavigatorRoomSettingsView';
import { NavigatorSearchResultView } from './views/search/NavigatorSearchResultView'; import { NavigatorSearchResultView } from './views/search/NavigatorSearchResultView';
import { NavigatorSearchView } from './views/search/NavigatorSearchView'; import { NavigatorSearchView } from './views/search/NavigatorSearchView';
@ -44,53 +43,10 @@ export const NavigatorView: FC<{}> = props =>
currentRoomRating: 0, currentRoomRating: 0,
canRate: true canRate: true
}); });
const [ doorData, setDoorData ] = useState<{ roomInfo: RoomDataParser, state: number }>({ roomInfo: null, state: DoorStateType.NONE });
const [ searchResult, setSearchResult ] = useState<NavigatorSearchResultSet>(null); const [ searchResult, setSearchResult ] = useState<NavigatorSearchResultSet>(null);
const [ pendingDoorState, setPendingDoorState ] = useState<{ roomData: RoomDataParser, state: string }>(null);
const pendingSearch = useRef<{ value: string, code: string }>(null); const pendingSearch = useRef<{ value: string, code: string }>(null);
const onUpdateDoorStateEvent = useCallback((event: UpdateDoorStateEvent) =>
{
switch(event.type)
{
case UpdateDoorStateEvent.START_DOORBELL:
setPendingDoorState({ roomData: event.roomData, state: event.type });
return;
case UpdateDoorStateEvent.START_PASSWORD:
setPendingDoorState({ roomData: event.roomData, state: event.type });
return;
case UpdateDoorStateEvent.STATE_WAITING:
setPendingDoorState(prevValue =>
{
return { roomData: prevValue.roomData, state: event.type }
});
return;
case UpdateDoorStateEvent.STATE_NO_ANSWER:
setPendingDoorState(prevValue =>
{
if(prevValue.state === UpdateDoorStateEvent.STATE_WAITING) GoToDesktop();
return { roomData: prevValue.roomData, state: event.type }
});
return;
case UpdateDoorStateEvent.STATE_WRONG_PASSWORD:
setPendingDoorState(prevValue =>
{
return { roomData: prevValue.roomData, state: event.type }
});
return;
case UpdateDoorStateEvent.STATE_ACCEPTED:
setPendingDoorState(null);
return;
}
}, []);
UseUiEvent(UpdateDoorStateEvent.START_DOORBELL, onUpdateDoorStateEvent);
UseUiEvent(UpdateDoorStateEvent.START_PASSWORD, onUpdateDoorStateEvent);
UseUiEvent(UpdateDoorStateEvent.STATE_WAITING, onUpdateDoorStateEvent);
UseUiEvent(UpdateDoorStateEvent.STATE_NO_ANSWER, onUpdateDoorStateEvent);
UseUiEvent(UpdateDoorStateEvent.STATE_WRONG_PASSWORD, onUpdateDoorStateEvent);
UseUiEvent(UpdateDoorStateEvent.STATE_ACCEPTED, onUpdateDoorStateEvent);
const onRoomSessionEvent = useCallback((event: RoomSessionEvent) => const onRoomSessionEvent = useCallback((event: RoomSessionEvent) =>
{ {
switch(event.type) switch(event.type)
@ -107,18 +63,6 @@ export const NavigatorView: FC<{}> = props =>
UseRoomSessionManagerEvent(RoomSessionEvent.CREATED, onRoomSessionEvent); UseRoomSessionManagerEvent(RoomSessionEvent.CREATED, onRoomSessionEvent);
const closePendingDoorState = useCallback((state: string) =>
{
if(state !== null)
{
setPendingDoorState(prevValue =>
{
return { ...prevValue, state };
});
}
else setPendingDoorState(null);
}, []);
const sendSearch = useCallback((searchValue: string, contextCode: string) => const sendSearch = useCallback((searchValue: string, contextCode: string) =>
{ {
setCreatorOpen(false); setCreatorOpen(false);
@ -292,28 +236,9 @@ export const NavigatorView: FC<{}> = props =>
LegacyExternalInterface.addCallback(HabboWebTools.OPENROOM, (k: string, _arg_2: boolean = false, _arg_3: string = null) => SendMessageComposer(new ConvertGlobalRoomIdMessageComposer(k))); LegacyExternalInterface.addCallback(HabboWebTools.OPENROOM, (k: string, _arg_2: boolean = false, _arg_3: string = null) => SendMessageComposer(new ConvertGlobalRoomIdMessageComposer(k)));
}, []); }, []);
const getRoomDoorState = useMemo(() =>
{
if(!pendingDoorState) return null;
switch(pendingDoorState.state)
{
case UpdateDoorStateEvent.START_DOORBELL:
case UpdateDoorStateEvent.STATE_WAITING:
case UpdateDoorStateEvent.STATE_NO_ANSWER:
return <NavigatorRoomDoorbellView roomData={ pendingDoorState.roomData } state={ pendingDoorState.state } onClose={ closePendingDoorState } />;
case UpdateDoorStateEvent.START_PASSWORD:
case UpdateDoorStateEvent.STATE_WRONG_PASSWORD:
return <NavigatorRoomPasswordView roomData={ pendingDoorState.roomData } state={ pendingDoorState.state } onClose={ closePendingDoorState } />;
}
return null;
}, [ pendingDoorState, closePendingDoorState ]);
return ( return (
<NavigatorContextProvider value={ { categories, setCategories, topLevelContext, setTopLevelContext, topLevelContexts, setTopLevelContexts, navigatorData, setNavigatorData, searchResult, setSearchResult } }> <NavigatorContextProvider value={ { categories, setCategories, topLevelContext, setTopLevelContext, topLevelContexts, setTopLevelContexts, navigatorData, setNavigatorData, doorData, setDoorData, searchResult, setSearchResult } }>
<NavigatorMessageHandler /> <NavigatorMessageHandler />
{ getRoomDoorState }
{ isVisible && { isVisible &&
<NitroCardView uniqueKey="navigator" className="nitro-navigator"> <NitroCardView uniqueKey="navigator" className="nitro-navigator">
<NitroCardHeaderView headerText={ LocalizeText(isCreatorOpen ? 'navigator.createroom.title' : 'navigator.title') } onCloseClick={ event => setIsVisible(false) } /> <NitroCardHeaderView headerText={ LocalizeText(isCreatorOpen ? 'navigator.createroom.title' : 'navigator.title') } onCloseClick={ event => setIsVisible(false) } />
@ -343,6 +268,7 @@ export const NavigatorView: FC<{}> = props =>
{ isCreatorOpen && <NavigatorRoomCreatorView /> } { isCreatorOpen && <NavigatorRoomCreatorView /> }
</NitroCardContentView> </NitroCardContentView>
</NitroCardView> } </NitroCardView> }
<NavigatorDoorStateView />
{ isRoomInfoOpen && <NavigatorRoomInfoView onCloseClick={ () => setRoomInfoOpen(false) } /> } { isRoomInfoOpen && <NavigatorRoomInfoView onCloseClick={ () => setRoomInfoOpen(false) } /> }
{ isRoomLinkOpen && <NavigatorRoomLinkView onCloseClick={ () => setRoomLinkOpen(false) } /> } { isRoomLinkOpen && <NavigatorRoomLinkView onCloseClick={ () => setRoomLinkOpen(false) } /> }
<NavigatorRoomSettingsView /> <NavigatorRoomSettingsView />

View File

@ -0,0 +1,12 @@
export class DoorStateType
{
public static NONE: number = 0;
public static START_DOORBELL: number = 1;
public static START_PASSWORD: number = 2;
public static STATE_PENDING_SERVER: number = 3;
public static UPDATE_STATE: number = 4;
public static STATE_WAITING: number = 5;
public static STATE_NO_ANSWER: number = 6;
public static STATE_WRONG_PASSWORD: number = 7;
public static STATE_ACCEPTED: number = 8;
}

View File

@ -0,0 +1,111 @@
import { FC, useEffect, useState } from 'react';
import { CreateRoomSession, GoToDesktop, LocalizeText } from '../../../api';
import { Button, Column, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common';
import { DoorStateType } from '../common/DoorStateType';
import { useNavigatorContext } from '../NavigatorContext';
const VISIBLE_STATES = [ DoorStateType.START_DOORBELL, DoorStateType.STATE_WAITING, DoorStateType.STATE_NO_ANSWER, DoorStateType.START_PASSWORD, DoorStateType.STATE_WRONG_PASSWORD ];
const DOORBELL_STATES = [ DoorStateType.START_DOORBELL, DoorStateType.STATE_WAITING, DoorStateType.STATE_NO_ANSWER ];
const PASSWORD_STATES = [ DoorStateType.START_PASSWORD, DoorStateType.STATE_WRONG_PASSWORD ];
export const NavigatorDoorStateView: FC<{}> = props =>
{
const [ password, setPassword ] = useState('');
const { doorData = null, setDoorData = null } = useNavigatorContext();
const close = () =>
{
if(doorData && (doorData.state === DoorStateType.STATE_WAITING)) GoToDesktop();
setDoorData(null);
}
const ring = () =>
{
if(!doorData || !doorData.roomInfo) return;
CreateRoomSession(doorData.roomInfo.roomId);
setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.state = DoorStateType.STATE_PENDING_SERVER;
return newValue;
});
}
const tryEntering = () =>
{
if(!doorData || !doorData.roomInfo) return;
CreateRoomSession(doorData.roomInfo.roomId, password);
setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.state = DoorStateType.STATE_PENDING_SERVER;
return newValue;
});
}
useEffect(() =>
{
if(!doorData || (doorData.state !== DoorStateType.STATE_NO_ANSWER)) return;
GoToDesktop();
}, [ doorData ]);
if(!doorData || (doorData.state === DoorStateType.NONE) || (VISIBLE_STATES.indexOf(doorData.state) === -1)) return null;
const isDoorbell = (DOORBELL_STATES.indexOf(doorData.state) >= 0);
return (
<NitroCardView className="nitro-navigator-doorbell" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText(isDoorbell ? 'navigator.doorbell.title' : 'navigator.password.title') } onCloseClick={ close } />
<NitroCardContentView>
<Column gap={ 1 }>
<Text bold>{ doorData && doorData.roomInfo && doorData.roomInfo.roomName }</Text>
{ (doorData.state === DoorStateType.START_DOORBELL) &&
<Text>{ LocalizeText('navigator.doorbell.info') }</Text> }
{ (doorData.state === DoorStateType.STATE_WAITING) &&
<Text>{ LocalizeText('navigator.doorbell.waiting') }</Text> }
{ (doorData.state === DoorStateType.STATE_NO_ANSWER) &&
<Text>{ LocalizeText('navigator.doorbell.no.answer') }</Text> }
{ (doorData.state === DoorStateType.START_PASSWORD) &&
<Text>{ LocalizeText('navigator.password.info') }</Text> }
{ (doorData.state === DoorStateType.STATE_WRONG_PASSWORD) &&
<Text>{ LocalizeText('navigator.password.retryinfo') }</Text> }
</Column>
{ isDoorbell &&
<Column gap={ 1 }>
{ (doorData.state === DoorStateType.START_DOORBELL) &&
<Button variant="success" onClick={ ring }>
{ LocalizeText('navigator.doorbell.button.ring') }
</Button> }
<Button variant="danger" onClick={ close }>
{ LocalizeText('generic.cancel') }
</Button>
</Column> }
{ !isDoorbell &&
<>
<Column gap={ 1 }>
<Text>{ LocalizeText('navigator.password.enter') }</Text>
<input type="password" className="form-control form-control-sm" onChange={ event => setPassword(event.target.value) } />
</Column>
<Column gap={ 1 }>
<Button variant="success" onClick={ tryEntering }>
{ LocalizeText('navigator.password.button.try') }
</Button>
<Button variant="danger" onClick={ close }>
{ LocalizeText('generic.cancel') }
</Button>
</Column>
</> }
</NitroCardContentView>
</NitroCardView>
);
}

View File

@ -1,63 +0,0 @@
import { RoomDataParser } from '@nitrots/nitro-renderer';
import { FC } from 'react';
import { CreateRoomSession, GoToDesktop, LocalizeText } from '../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../common';
import { Button } from '../../../common/Button';
import { Column } from '../../../common/Column';
import { Text } from '../../../common/Text';
import { UpdateDoorStateEvent } from '../../../events';
export interface NavigatorRoomDoorbellViewProps
{
roomData: RoomDataParser;
state: string;
onClose: (state: string) => void;
}
export const NavigatorRoomDoorbellView: FC<NavigatorRoomDoorbellViewProps> = props =>
{
const { roomData = null, state = null, onClose = null } = props;
const close = () =>
{
if(state === UpdateDoorStateEvent.STATE_WAITING) GoToDesktop();
onClose(null);
}
const ring = () =>
{
if(!roomData) return;
CreateRoomSession(roomData.roomId);
onClose(UpdateDoorStateEvent.STATE_PENDING_SERVER);
}
return (
<NitroCardView className="nitro-navigator-doorbell" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText('navigator.doorbell.title') } onCloseClick={ close } />
<NitroCardContentView>
<Column gap={ 1 }>
{ roomData &&
<Text bold>{ roomData.roomName }</Text> }
{ (state === UpdateDoorStateEvent.START_DOORBELL) &&
<Text>{ LocalizeText('navigator.doorbell.info') }</Text> }
{ (state === UpdateDoorStateEvent.STATE_WAITING) &&
<Text>{ LocalizeText('navigator.doorbell.waiting') }</Text> }
{ (state === UpdateDoorStateEvent.STATE_NO_ANSWER) &&
<Text>{ LocalizeText('navigator.doorbell.no.answer') }</Text> }
</Column>
<Column gap={ 1 }>
{ (state === UpdateDoorStateEvent.START_DOORBELL) &&
<Button variant="success" onClick={ ring }>
{ LocalizeText('navigator.doorbell.button.ring') }
</Button> }
<Button variant="danger" onClick={ close }>
{ LocalizeText('generic.cancel') }
</Button>
</Column>
</NitroCardContentView>
</NitroCardView>
);
}

View File

@ -1,60 +0,0 @@
import { RoomDataParser } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { CreateRoomSession, LocalizeText } from '../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../common';
import { Button } from '../../../common/Button';
import { Column } from '../../../common/Column';
import { Text } from '../../../common/Text';
import { UpdateDoorStateEvent } from '../../../events';
export interface NavigatorRoomPasswordViewProps
{
roomData: RoomDataParser;
state: string;
onClose: (state: string) => void;
}
export const NavigatorRoomPasswordView: FC<NavigatorRoomPasswordViewProps> = props =>
{
const { roomData = null, state = null, onClose = null } = props;
const [ password, setPassword ] = useState('');
const close = () =>
{
onClose(null);
}
const tryEntering = useCallback(() =>
{
if(!roomData) return;
CreateRoomSession(roomData.roomId, password);
onClose(UpdateDoorStateEvent.STATE_PENDING_SERVER);
}, [ roomData, password, onClose ]);
return (
<NitroCardView className="nitro-navigator-password" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText('navigator.password.title') } onCloseClick={ close } />
<NitroCardContentView>
<Column gap={ 1 }>
{ roomData &&
<Text bold>{ roomData.roomName }</Text> }
{ (state === UpdateDoorStateEvent.START_PASSWORD) &&
<Text>{ LocalizeText('navigator.password.info') }</Text> }
{ (state === UpdateDoorStateEvent.STATE_WRONG_PASSWORD) &&
<Text>{ LocalizeText('navigator.password.retryinfo') }</Text> }
</Column>
<Column gap={ 1 }>
<Text>{ LocalizeText('navigator.password.enter') }</Text>
<input type="password" className="form-control form-control-sm" onChange={ event => setPassword(event.target.value) } />
</Column>
<Button variant="success" onClick={ tryEntering }>
{ LocalizeText('navigator.password.button.try') }</Button>
<Button variant="danger" onClick={ close }>
{ LocalizeText('generic.cancel') }
</Button>
</NitroCardContentView>
</NitroCardView>
);
}

View File

@ -3,8 +3,8 @@ import { RoomDataParser } from '@nitrots/nitro-renderer';
import { FC, MouseEvent } from 'react'; import { FC, MouseEvent } from 'react';
import { CreateRoomSession, GetSessionDataManager, TryVisitRoom } from '../../../../api'; import { CreateRoomSession, GetSessionDataManager, TryVisitRoom } from '../../../../api';
import { Column, Flex, LayoutBadgeImageView, LayoutGridItemProps, LayoutRoomThumbnailView, Text } from '../../../../common'; import { Column, Flex, LayoutBadgeImageView, LayoutGridItemProps, LayoutRoomThumbnailView, Text } from '../../../../common';
import { UpdateDoorStateEvent } from '../../../../events'; import { DoorStateType } from '../../common/DoorStateType';
import { DispatchUiEvent } from '../../../../hooks'; import { useNavigatorContext } from '../../NavigatorContext';
import { NavigatorSearchResultItemInfoView } from './NavigatorSearchResultItemInfoView'; import { NavigatorSearchResultItemInfoView } from './NavigatorSearchResultItemInfoView';
export interface NavigatorSearchResultItemViewProps extends LayoutGridItemProps export interface NavigatorSearchResultItemViewProps extends LayoutGridItemProps
@ -16,6 +16,7 @@ export interface NavigatorSearchResultItemViewProps extends LayoutGridItemProps
export const NavigatorSearchResultItemView: FC<NavigatorSearchResultItemViewProps> = props => export const NavigatorSearchResultItemView: FC<NavigatorSearchResultItemViewProps> = props =>
{ {
const { roomData = null, children = null, thumbnail = false, ...rest } = props; const { roomData = null, children = null, thumbnail = false, ...rest } = props;
const { setDoorData = null } = useNavigatorContext();
function getUserCounterColor(): string function getUserCounterColor(): string
{ {
@ -53,10 +54,26 @@ export const NavigatorSearchResultItemView: FC<NavigatorSearchResultItemViewProp
switch(roomData.doorMode) switch(roomData.doorMode)
{ {
case RoomDataParser.DOORBELL_STATE: case RoomDataParser.DOORBELL_STATE:
DispatchUiEvent(new UpdateDoorStateEvent(UpdateDoorStateEvent.START_DOORBELL, roomData)); setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.roomInfo = roomData;
newValue.state = DoorStateType.START_DOORBELL;
return newValue;
});
return; return;
case RoomDataParser.PASSWORD_STATE: case RoomDataParser.PASSWORD_STATE:
DispatchUiEvent(new UpdateDoorStateEvent(UpdateDoorStateEvent.START_PASSWORD, roomData)); setDoorData(prevValue =>
{
const newValue = { ...prevValue };
newValue.roomInfo = roomData;
newValue.state = DoorStateType.START_PASSWORD;
return newValue;
});
return; return;
} }
} }

View File

@ -2,7 +2,7 @@ import { Dispose, DropBounce, EaseOut, FigureUpdateEvent, JumpBy, Motions, Nitro
import { FC, useCallback, useState } from 'react'; import { FC, useCallback, useState } from 'react';
import { CreateLinkEvent, GetSessionDataManager, GetUserProfile, OpenMessengerChat, VisitDesktop } from '../../api'; import { CreateLinkEvent, GetSessionDataManager, GetUserProfile, OpenMessengerChat, VisitDesktop } from '../../api';
import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common'; import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common';
import { AchievementsUIEvent, AchievementsUIUnseenCountEvent, FriendsEvent, FriendsMessengerIconEvent, FriendsRequestCountEvent, GuideToolEvent, InventoryEvent, ModToolsEvent, UnseenItemTrackerUpdateEvent, UserSettingsUIEvent } from '../../events'; import { AchievementsUIUnseenCountEvent, FriendsEvent, FriendsMessengerIconEvent, FriendsRequestCountEvent, GuideToolEvent, InventoryEvent, ModToolsEvent, UnseenItemTrackerUpdateEvent, UserSettingsUIEvent } from '../../events';
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook, UseRoomEngineEvent, UseUiEvent } from '../../hooks'; import { BatchUpdates, DispatchUiEvent, UseMessageEventHook, UseRoomEngineEvent, UseUiEvent } from '../../hooks';
import { ToolbarViewItems } from './common/ToolbarViewItems'; import { ToolbarViewItems } from './common/ToolbarViewItems';
import { ToolbarMeView } from './ToolbarMeView'; import { ToolbarMeView } from './ToolbarMeView';
@ -157,7 +157,7 @@ export const ToolbarView: FC<ToolbarViewProps> = props =>
DispatchUiEvent(new ModToolsEvent(ModToolsEvent.TOGGLE_MOD_TOOLS)); DispatchUiEvent(new ModToolsEvent(ModToolsEvent.TOGGLE_MOD_TOOLS));
return; return;
case ToolbarViewItems.ACHIEVEMENTS_ITEM: case ToolbarViewItems.ACHIEVEMENTS_ITEM:
DispatchUiEvent(new AchievementsUIEvent(AchievementsUIEvent.TOGGLE_ACHIEVEMENTS)); CreateLinkEvent('achievements/toggle');
setMeExpanded(false); setMeExpanded(false);
return; return;
case ToolbarViewItems.PROFILE_ITEM: case ToolbarViewItems.PROFILE_ITEM:

View File

@ -57,11 +57,22 @@ export const UserProfileView: FC<{}> = props =>
{ {
const parser = event.getParser(); const parser = event.getParser();
let isSameProfile = false;
BatchUpdates(() => BatchUpdates(() =>
{ {
setUserProfile(parser); setUserProfile(prevValue =>
{
if(prevValue && prevValue.id) isSameProfile = (prevValue.id === parser.id);
return parser;
});
if(!isSameProfile)
{
setUserBadges([]); setUserBadges([]);
setUserRelationships(null); setUserRelationships(null);
}
}); });
SendMessageComposer(new UserCurrentBadgesComposer(parser.id)); SendMessageComposer(new UserCurrentBadgesComposer(parser.id));

View File

@ -1,5 +1,6 @@
import { WiredFurniActionEvent, WiredFurniConditionEvent, WiredFurniTriggerEvent, WiredOpenEvent, WiredRewardResultMessageEvent, WiredSaveSuccessEvent, WiredValidationErrorEvent } from '@nitrots/nitro-renderer'; import { WiredFurniActionEvent, WiredFurniConditionEvent, WiredFurniTriggerEvent, WiredOpenEvent, WiredRewardResultMessageEvent, WiredSaveSuccessEvent, WiredValidationErrorEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react'; import { FC, useCallback } from 'react';
import { LocalizeText, NotificationAlertType, NotificationUtilities } from '../../api';
import { UseMessageEventHook } from '../../hooks/messages'; import { UseMessageEventHook } from '../../hooks/messages';
import { useWiredContext } from './context/WiredContext'; import { useWiredContext } from './context/WiredContext';
@ -51,6 +52,7 @@ export const WiredMessageHandler: FC<{}> = props =>
{ {
const parser = event.getParser(); const parser = event.getParser();
NotificationUtilities.simpleAlert(parser.info, NotificationAlertType.DEFAULT, null, null, LocalizeText('error.title'));
console.log(parser); console.log(parser);
}, []); }, []);

View File

@ -10,8 +10,8 @@ import { WiredMessageHandler } from './WiredMessageHandler';
export const WiredView: FC<{}> = props => export const WiredView: FC<{}> = props =>
{ {
const [ trigger, setTrigger ] = useState<Triggerable>(null); const [ trigger, setTrigger ] = useState<Triggerable>(null);
const [ intParams, setIntParams ] = useState<number[]>(null); const [ intParams, setIntParams ] = useState<number[]>([]);
const [ stringParam, setStringParam ] = useState<string>(null); const [ stringParam, setStringParam ] = useState<string>('');
const [ furniIds, setFurniIds ] = useState<number[]>([]); const [ furniIds, setFurniIds ] = useState<number[]>([]);
const [ actionDelay, setActionDelay ] = useState<number>(null); const [ actionDelay, setActionDelay ] = useState<number>(null);

View File

@ -12,13 +12,14 @@ export interface WiredBaseViewProps
{ {
wiredType: string; wiredType: string;
requiresFurni: number; requiresFurni: number;
hasSpecialInput: boolean;
save: () => void; save: () => void;
validate?: () => boolean; validate?: () => boolean;
} }
export const WiredBaseView: FC<WiredBaseViewProps> = props => export const WiredBaseView: FC<WiredBaseViewProps> = props =>
{ {
const { wiredType = '', requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, children = null } = props; const { wiredType = '', requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, children = null, hasSpecialInput = false } = props;
const [ wiredName, setWiredName ] = useState<string>(null); const [ wiredName, setWiredName ] = useState<string>(null);
const [ wiredDescription, setWiredDescription ] = useState<string>(null); const [ wiredDescription, setWiredDescription ] = useState<string>(null);
const { trigger = null, setTrigger = null, setIntParams = null, setStringParam = null, setFurniIds = null } = useWiredContext(); const { trigger = null, setTrigger = null, setIntParams = null, setStringParam = null, setFurniIds = null } = useWiredContext();
@ -57,8 +58,14 @@ export const WiredBaseView: FC<WiredBaseViewProps> = props =>
setWiredDescription(furniData.description); setWiredDescription(furniData.description);
} }
if(hasSpecialInput)
{
setIntParams(trigger.intData); setIntParams(trigger.intData);
setStringParam(trigger.stringData); setStringParam(trigger.stringData);
}
if(requiresFurni > WiredFurniType.STUFF_SELECTION_OPTION_NONE)
{
setFurniIds(prevValue => setFurniIds(prevValue =>
{ {
if(prevValue && prevValue.length) WiredSelectionVisualizer.clearSelectionShaderFromFurni(prevValue); if(prevValue && prevValue.length) WiredSelectionVisualizer.clearSelectionShaderFromFurni(prevValue);
@ -72,8 +79,9 @@ export const WiredBaseView: FC<WiredBaseViewProps> = props =>
return []; return [];
}); });
}
}); });
}, [ trigger, setIntParams, setStringParam, setFurniIds ]); }, [trigger, setIntParams, setStringParam, setFurniIds, hasSpecialInput, requiresFurni]);
return ( return (
<NitroCardView uniqueKey="nitro-wired" className="nitro-wired" theme="primary-slim"> <NitroCardView uniqueKey="nitro-wired" className="nitro-wired" theme="primary-slim">

View File

@ -11,13 +11,14 @@ import { WiredBaseView } from '../WiredBaseView';
export interface WiredActionBaseViewProps export interface WiredActionBaseViewProps
{ {
hasSpecialInput: boolean;
requiresFurni: number; requiresFurni: number;
save: () => void; save: () => void;
} }
export const WiredActionBaseView: FC<WiredActionBaseViewProps> = props => export const WiredActionBaseView: FC<WiredActionBaseViewProps> = props =>
{ {
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, children = null } = props; const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null } = props;
const [ delay, setDelay ] = useState(-1); const [ delay, setDelay ] = useState(-1);
const { trigger = null, setActionDelay = null } = useWiredContext(); const { trigger = null, setActionDelay = null } = useWiredContext();
@ -34,7 +35,7 @@ export const WiredActionBaseView: FC<WiredActionBaseViewProps> = props =>
}, [ delay, save, setActionDelay ]); }, [ delay, save, setActionDelay ]);
return ( return (
<WiredBaseView wiredType="action" requiresFurni={ requiresFurni } save={ onSave }> <WiredBaseView wiredType="action" requiresFurni={ requiresFurni } save={ onSave } hasSpecialInput={ hasSpecialInput }>
{ children } { children }
{ !!children && <hr className="m-0 bg-dark" /> } { !!children && <hr className="m-0 bg-dark" /> }
<Column> <Column>

View File

@ -37,7 +37,7 @@ export const WiredActionBotChangeFigureView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } /> <input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />

View File

@ -33,7 +33,7 @@ export const WiredActionBotFollowAvatarView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label> <label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } /> <input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />

View File

@ -34,7 +34,7 @@ export const WiredActionBotGiveHandItemView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } /> <input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />

View File

@ -22,7 +22,7 @@ export const WiredActionBotMoveView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } /> <input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />

View File

@ -39,7 +39,7 @@ export const WiredActionBotTalkToAvatarView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } /> <input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />

View File

@ -39,7 +39,7 @@ export const WiredActionBotTalkView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } /> <input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />

View File

@ -22,7 +22,7 @@ export const WiredActionBotTeleportView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } /> <input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />

View File

@ -4,5 +4,5 @@ import { WiredActionBaseView } from './WiredActionBaseView';
export const WiredActionCallAnotherStackView: FC<{}> = props => export const WiredActionCallAnotherStackView: FC<{}> = props =>
{ {
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />; return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -4,5 +4,5 @@ import { WiredActionBaseView } from './WiredActionBaseView';
export const WiredActionChaseView: FC<{}> = props => export const WiredActionChaseView: FC<{}> = props =>
{ {
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />; return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -22,7 +22,7 @@ export const WiredActionChatView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } maxLength={ 100 } /> <input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } maxLength={ 100 } />

View File

@ -4,5 +4,5 @@ import { WiredActionBaseView } from './WiredActionBaseView';
export const WiredActionFleeView: FC<{}> = props => export const WiredActionFleeView: FC<{}> = props =>
{ {
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />; return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -106,7 +106,7 @@ export const WiredActionGiveRewardView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>
<input className="form-check-input" type="checkbox" id="limitEnabled" onChange={ event => setLimitEnabled(event.target.checked)} /> <input className="form-check-input" type="checkbox" id="limitEnabled" onChange={ event => setLimitEnabled(event.target.checked)} />
<Text>{ LocalizeText('wiredfurni.params.prizelimit', ['amount'], [limitEnabled ? rewardsLimit.toString() : '']) }</Text> <Text>{ LocalizeText('wiredfurni.params.prizelimit', ['amount'], [limitEnabled ? rewardsLimit.toString() : '']) }</Text>

View File

@ -41,7 +41,7 @@ export const WiredActionGiveScoreToPredefinedTeamView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.setpoints', [ 'points' ], [ points.toString() ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.setpoints', [ 'points' ], [ points.toString() ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -37,7 +37,7 @@ export const WiredActionGiveScoreView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.setpoints', [ 'points' ], [ points.toString() ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.setpoints', [ 'points' ], [ points.toString() ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -23,7 +23,7 @@ export const WiredActionJoinTeamView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.team') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.team') }</Text>
{ [1, 2, 3, 4].map(team => { [1, 2, 3, 4].map(team =>

View File

@ -22,7 +22,7 @@ export const WiredActionKickFromRoomView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.message') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.message') }</Text>
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } maxLength={ 100 } /> <input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } maxLength={ 100 } />

View File

@ -4,5 +4,5 @@ import { WiredActionBaseView } from './WiredActionBaseView';
export const WiredActionLeaveTeamView: FC<{}> = props => export const WiredActionLeaveTeamView: FC<{}> = props =>
{ {
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />; return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -58,7 +58,7 @@ export const WiredActionMoveAndRotateFurniView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.startdir') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.startdir') }</Text>
<Flex gap={ 1 }> <Flex gap={ 1 }>

View File

@ -57,7 +57,7 @@ export const WiredActionMoveFurniToView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.emptytiles', [ 'tiles' ], [ spacing.toString() ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.emptytiles', [ 'tiles' ], [ spacing.toString() ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -70,7 +70,7 @@ export const WiredActionMoveFurniView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.movefurni') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.movefurni') }</Text>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>

View File

@ -33,7 +33,7 @@ export const WiredActionMuteUserView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.length.minutes', ['minutes'], [ time.toString() ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.length.minutes', ['minutes'], [ time.toString() ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -4,5 +4,5 @@ import { WiredActionBaseView } from './WiredActionBaseView';
export const WiredActionResetView: FC<{}> = props => export const WiredActionResetView: FC<{}> = props =>
{ {
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />; return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -31,7 +31,7 @@ export const WiredActionSetFurniStateToView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }> <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.conditions') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.conditions') }</Text>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>

View File

@ -4,5 +4,5 @@ import { WiredActionBaseView } from './WiredActionBaseView';
export const WiredActionTeleportView: FC<{}> = props => export const WiredActionTeleportView: FC<{}> = props =>
{ {
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />; return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -4,5 +4,5 @@ import { WiredActionBaseView } from './WiredActionBaseView';
export const WiredActionToggleFurniStateView: FC<{}> = props => export const WiredActionToggleFurniStateView: FC<{}> = props =>
{ {
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />; return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -24,7 +24,7 @@ export const WiredConditionActorHasHandItemView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.handitem') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.handitem') }</Text>
<select className="form-select form-select-sm" value={ handItemId } onChange={ event => setHandItemId(parseInt(event.target.value)) }> <select className="form-select form-select-sm" value={ handItemId } onChange={ event => setHandItemId(parseInt(event.target.value)) }>

View File

@ -4,5 +4,5 @@ import { WiredConditionBaseView } from './WiredConditionBaseView';
export const WiredConditionActorIsGroupMemberView: FC<{}> = props => export const WiredConditionActorIsGroupMemberView: FC<{}> = props =>
{ {
return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />; return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -4,5 +4,5 @@ import { WiredConditionBaseView } from './WiredConditionBaseView';
export const WiredConditionActorIsOnFurniView: FC<{}> = props => export const WiredConditionActorIsOnFurniView: FC<{}> = props =>
{ {
return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ null } />; return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -25,7 +25,7 @@ export const WiredConditionActorIsTeamMemberView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.team') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.team') }</Text>
{ teamIds.map(value => { teamIds.map(value =>

View File

@ -22,7 +22,7 @@ export const WiredConditionActorIsWearingBadgeView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.badgecode') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.badgecode') }</Text>
<input type="text" className="form-control form-control-sm" value={ badge } onChange={ event => setBadge(event.target.value) } /> <input type="text" className="form-control form-control-sm" value={ badge } onChange={ event => setBadge(event.target.value) } />

View File

@ -22,7 +22,7 @@ export const WiredConditionActorIsWearingEffectView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.effectid') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.effectid') }</Text>
<input type="number" className="form-control form-control-sm" value={ effect } onChange={ event => setEffect(parseInt(event.target.value)) } /> <input type="number" className="form-control form-control-sm" value={ effect } onChange={ event => setEffect(parseInt(event.target.value)) } />

View File

@ -4,13 +4,14 @@ import { WiredBaseView } from '../WiredBaseView';
export interface WiredConditionBaseViewProps export interface WiredConditionBaseViewProps
{ {
hasSpecialInput: boolean;
requiresFurni: number; requiresFurni: number;
save: () => void; save: () => void;
} }
export const WiredConditionBaseView: FC<WiredConditionBaseViewProps> = props => export const WiredConditionBaseView: FC<WiredConditionBaseViewProps> = props =>
{ {
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, children = null } = props; const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null } = props;
const onSave = useCallback(() => const onSave = useCallback(() =>
{ {
@ -18,7 +19,7 @@ export const WiredConditionBaseView: FC<WiredConditionBaseViewProps> = props =>
}, [ save ]); }, [ save ]);
return ( return (
<WiredBaseView wiredType="condition" requiresFurni={ requiresFurni } save={ onSave }> <WiredBaseView wiredType="condition" requiresFurni={ requiresFurni } hasSpecialInput={ hasSpecialInput } save={ onSave }>
{ children } { children }
</WiredBaseView> </WiredBaseView>
); );

View File

@ -55,7 +55,7 @@ export const WiredConditionDateRangeView: FC<{}> = props =>
}, [ trigger, dateToString ]); }, [ trigger, dateToString ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.startdate') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.startdate') }</Text>
<input type="text" className="form-control form-control-sm" value={ startDate } onChange={ (e) => setStartDate(e.target.value) } /> <input type="text" className="form-control form-control-sm" value={ startDate } onChange={ (e) => setStartDate(e.target.value) } />

View File

@ -4,5 +4,5 @@ import { WiredConditionBaseView } from './WiredConditionBaseView';
export const WiredConditionFurniHasAvatarOnView: FC<{}> = props => export const WiredConditionFurniHasAvatarOnView: FC<{}> = props =>
{ {
return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ null } />; return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -23,7 +23,7 @@ export const WiredConditionFurniHasFurniOnView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.requireall') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.requireall') }</Text>
{ [0, 1].map(value => { [0, 1].map(value =>

View File

@ -23,7 +23,7 @@ export const WiredConditionFurniHasNotFurniOnView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.not_requireall') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.not_requireall') }</Text>
{ [0, 1].map(value => { [0, 1].map(value =>

View File

@ -4,5 +4,5 @@ import { WiredConditionBaseView } from './WiredConditionBaseView';
export const WiredConditionFurniIsOfTypeView: FC<{}> = props => export const WiredConditionFurniIsOfTypeView: FC<{}> = props =>
{ {
return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ null } />; return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -31,7 +31,7 @@ export const WiredConditionFurniMatchesSnapshotView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.conditions') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.conditions') }</Text>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>

View File

@ -24,7 +24,7 @@ export const WiredConditionTimeElapsedLessView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.allowbefore', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.allowbefore', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -24,7 +24,7 @@ export const WiredConditionTimeElapsedMoreView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.allowafter', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.allowafter', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -37,7 +37,7 @@ export const WiredConditionUserCountInRoomView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.usercountmin', [ 'value' ], [ min.toString() ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.usercountmin', [ 'value' ], [ min.toString() ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -30,7 +30,7 @@ export const WiredTriggerAvatarEnterRoomView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.picktriggerer') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.picktriggerer') }</Text>
<Flex alignItems="center" gap={ 1 }> <Flex alignItems="center" gap={ 1 }>

View File

@ -33,7 +33,7 @@ export const WiredTriggerAvatarSaysSomethingView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.whatissaid') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.whatissaid') }</Text>
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } /> <input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } />

View File

@ -4,5 +4,5 @@ import { WiredTriggerBaseView } from './WiredTriggerBaseView';
export const WiredTriggerAvatarWalksOffFurniView: FC<{}> = props => export const WiredTriggerAvatarWalksOffFurniView: FC<{}> = props =>
{ {
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ null } />; return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -4,5 +4,5 @@ import { WiredTriggerBaseView } from './WiredTriggerBaseView';
export const WiredTriggerAvatarWalksOnFurniView: FC<{}> = props => export const WiredTriggerAvatarWalksOnFurniView: FC<{}> = props =>
{ {
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ null } />; return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -4,13 +4,14 @@ import { WiredBaseView } from '../WiredBaseView';
export interface WiredTriggerBaseViewProps export interface WiredTriggerBaseViewProps
{ {
hasSpecialInput: boolean;
requiresFurni: number; requiresFurni: number;
save: () => void; save: () => void;
} }
export const WiredTriggerBaseView: FC<WiredTriggerBaseViewProps> = props => export const WiredTriggerBaseView: FC<WiredTriggerBaseViewProps> = props =>
{ {
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, children = null } = props; const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null } = props;
const onSave = useCallback(() => const onSave = useCallback(() =>
{ {
@ -18,7 +19,7 @@ export const WiredTriggerBaseView: FC<WiredTriggerBaseViewProps> = props =>
}, [ save ]); }, [ save ]);
return ( return (
<WiredBaseView wiredType="trigger" requiresFurni={ requiresFurni } save={ onSave }> <WiredBaseView wiredType="trigger" requiresFurni={ requiresFurni } hasSpecialInput={ hasSpecialInput } save={ onSave }>
{ children } { children }
</WiredBaseView> </WiredBaseView>
); );

View File

@ -22,7 +22,7 @@ export const WiredTriggerBotReachedAvatarView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } /> <input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />

View File

@ -22,7 +22,7 @@ export const WiredTriggerBotReachedStuffView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text> <Text bold>{ LocalizeText('wiredfurni.params.bot.name') }</Text>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } /> <input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />

View File

@ -4,5 +4,5 @@ import { WiredTriggerBaseView } from './WiredTriggerBaseView';
export const WiredTriggerCollisionView: FC<{}> = props => export const WiredTriggerCollisionView: FC<{}> = props =>
{ {
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />; return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -24,7 +24,7 @@ export const WiredTriggeExecuteOnceView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.settime', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.settime', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -24,7 +24,7 @@ export const WiredTriggeExecutePeriodicallyLongView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.setlongtime', [ 'time' ], [ FriendlyTime.format(time * 5).toString() ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.setlongtime', [ 'time' ], [ FriendlyTime.format(time * 5).toString() ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -24,7 +24,7 @@ export const WiredTriggeExecutePeriodicallyView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.settime', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.settime', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -4,5 +4,5 @@ import { WiredTriggerBaseView } from './WiredTriggerBaseView';
export const WiredTriggerGameEndsView: FC<{}> = props => export const WiredTriggerGameEndsView: FC<{}> = props =>
{ {
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />; return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -4,5 +4,5 @@ import { WiredTriggerBaseView } from './WiredTriggerBaseView';
export const WiredTriggerGameStartsView: FC<{}> = props => export const WiredTriggerGameStartsView: FC<{}> = props =>
{ {
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />; return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -23,7 +23,7 @@ export const WiredTriggeScoreAchievedView: FC<{}> = props =>
}, [ trigger ]); }, [ trigger ]);
return ( return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }> <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } hasSpecialInput={ true } save={ save }>
<Column gap={ 1 }> <Column gap={ 1 }>
<Text bold>{ LocalizeText('wiredfurni.params.setscore', [ 'points' ], [ points.toString() ]) }</Text> <Text bold>{ LocalizeText('wiredfurni.params.setscore', [ 'points' ], [ points.toString() ]) }</Text>
<ReactSlider <ReactSlider

View File

@ -4,5 +4,5 @@ import { WiredTriggerBaseView } from './WiredTriggerBaseView';
export const WiredTriggerToggleFurniView: FC<{}> = props => export const WiredTriggerToggleFurniView: FC<{}> = props =>
{ {
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ null } />; return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } hasSpecialInput={ false } save={ null } />;
} }

View File

@ -1,8 +0,0 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
export class AchievementsUIEvent extends NitroEvent
{
public static SHOW_ACHIEVEMENTS: string = 'AE_SHOW_ACHIEVEMENTS';
public static HIDE_ACHIEVEMENTS: string = 'AE_HIDE_ACHIEVEMENTS';
public static TOGGLE_ACHIEVEMENTS: string = 'AE_TOGGLE_ACHIEVEMENTS';
}

View File

@ -1,2 +1 @@
export * from './AchievementsUIEvent';
export * from './AchievementsUIUnseenCountEvent'; export * from './AchievementsUIUnseenCountEvent';

View File

@ -7,7 +7,6 @@ export * from './hc-center';
export * from './help'; export * from './help';
export * from './inventory'; export * from './inventory';
export * from './mod-tools'; export * from './mod-tools';
export * from './navigator';
export * from './notification-center'; export * from './notification-center';
export * from './room-widgets'; export * from './room-widgets';
export * from './room-widgets/thumbnail'; export * from './room-widgets/thumbnail';

View File

@ -1,27 +0,0 @@
import { NitroEvent, RoomDataParser } from '@nitrots/nitro-renderer';
export class UpdateDoorStateEvent extends NitroEvent
{
public static START_DOORBELL: string = 'UDSE_START_DOORBELL';
public static START_PASSWORD: string = 'UDSE_START_PASSWORD';
public static STATE_PENDING_SERVER: string = 'UDSE_STATE_PENDING_SERVER';
public static UPDATE_STATE: string = 'UDSE_UPDATE_STATE';
public static STATE_WAITING: string = 'UDSE_STATE_WAITING';
public static STATE_NO_ANSWER: string = 'UDSE_STATE_NO_ANSWER';
public static STATE_WRONG_PASSWORD: string = 'UDSE_STATE_WRONG_PASSWORD';
public static STATE_ACCEPTED: string = 'UDSE_STATE_ACCEPTED';
private _roomData: RoomDataParser
constructor(type: string, roomData: RoomDataParser = null)
{
super(type);
this._roomData = roomData;
}
public get roomData(): RoomDataParser
{
return this._roomData;
}
}

View File

@ -1 +0,0 @@
export * from './UpdateDoorStateEvent';