Merge remote-tracking branch 'origin/dev' into feature/messenger

This commit is contained in:
MyNameIsBatman 2021-09-18 13:51:11 -03:00
commit cc33ba3e36
60 changed files with 573 additions and 571 deletions

View File

@ -126,6 +126,7 @@ export const App: FC<{}> = props =>
return (
<div className="nitro-app">
<div id="nitro-alerts-container" />
{ (!isReady || isError) && <LoadingView isError={ isError } message={ message } /> }
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ (isReady && !isError) } timeout={ 300 }>
<MainView />

View File

@ -1,29 +1,36 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
export class SimpleAlertUIEvent extends NitroEvent
export class NotificationAlertEvent extends NitroEvent
{
public static ALERT: string = 'SAUE_ALERT';
public static ALERT: string = 'NAE_ALERT';
private _message: string;
private _messages: string[];
private _alertType: string;
private _clickUrl: string;
private _clickUrlText: string;
private _title: string;
private _imageUrl: string;
constructor(message: string, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null)
constructor(messages: string[], alertType: string = null, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null)
{
super(SimpleAlertUIEvent.ALERT);
super(NotificationAlertEvent.ALERT);
this._message = message;
this._messages = messages;
this._alertType = alertType;
this._clickUrl = clickUrl;
this._clickUrlText = clickUrlText;
this._title = title;
this._imageUrl = imageUrl;
}
public get message(): string
public get messages(): string[]
{
return this._message;
return this._messages;
}
public get alertType(): string
{
return this._alertType;
}
public get clickUrl(): string

View File

@ -2,7 +2,7 @@ import { NitroEvent } from '@nitrots/nitro-renderer';
export class NotificationBubbleEvent extends NitroEvent
{
public static NEW_BUBBLE: string = 'NNBE_NEW_BUBBLE';
public static NEW_BUBBLE: string = 'NBE_NEW_BUBBLE';
private _message: string;
private _notificationType: string;

View File

@ -1,19 +0,0 @@
import { NitroNotification } from '../../views/notification-center/common/Notification';
import { NotificationCenterEvent } from './NotificationCenterEvent';
export class NotificationCenterAddNotificationEvent extends NotificationCenterEvent
{
private _notification: NitroNotification;
constructor(notification: NitroNotification)
{
super(NotificationCenterEvent.ADD_NOTIFICATION);
this._notification = notification;
}
public get notification(): NitroNotification
{
return this._notification;
}
}

View File

@ -1,4 +1,4 @@
export * from './NotificationCenterAddNotificationEvent';
export * from './NotificationAlertEvent';
export * from './NotificationBubbleEvent';
export * from './NotificationCenterAlertEvent';
export * from './NotificationCenterEvent';
export * from './SimpleAlertUIEvent';

View File

@ -27,6 +27,7 @@
@import './loading-habbos/LoadingHabbosView';
@import './loading-spinner/LoadingSpinnerView';
@import './mini-camera/NitroLayoutMiniCameraView';
@import './notification-alert/NotificationAlertView';
@import './notification-bubble/NotificationBubbleView';
@import './trophy/NitroLayoutTrophyView';
@import './gift-card/NitroLayoutGiftCardView';

View File

@ -3,6 +3,7 @@ export * from './draggable-window';
export * from './gift-card';
export * from './loading-spinner';
export * from './mini-camera';
export * from './notification-alert';
export * from './notification-bubble';
export * from './transitions';
export * from './trophy';

View File

@ -0,0 +1,8 @@
.nitro-alert {
width: 350px;
.content-area {
min-height: 125px;
max-height: 300px;
}
}

View File

@ -0,0 +1,17 @@
import { FC } from 'react';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../card';
import { NotificationAlertViewProps } from './NotificationAlertView.types';
export const NotificationAlertView: FC<NotificationAlertViewProps> = props =>
{
const { title = '', close = null, className = '', children = null, ...rest } = props;
return (
<NitroCardView className={ 'nitro-alert ' + className } simple={ true } { ...rest }>
<NitroCardHeaderView headerText={ title } onCloseClick={ close } />
<NitroCardContentView className="d-flex flex-column justify-content-between text-black">
{ children }
</NitroCardContentView>
</NitroCardView>
);
}

View File

@ -0,0 +1,7 @@
import { DetailsHTMLAttributes } from 'react';
export interface NotificationAlertViewProps extends DetailsHTMLAttributes<HTMLDivElement>
{
title: string;
close: () => void;
}

View File

@ -0,0 +1,2 @@
export * from './NotificationAlertView';
export * from './NotificationAlertView.types';

View File

@ -10,7 +10,7 @@ import { CatalogMode, CatalogViewProps } from './CatalogView.types';
import { BuildCatalogPageTree } from './common/CatalogUtilities';
import { CatalogContextProvider } from './context/CatalogContext';
import { CatalogReducer, initialCatalog } from './reducers/CatalogReducer';
import { CatalogPageGiftView } from './views/gift/CatalogPageGiftView';
import { CatalogGiftView } from './views/gift/CatalogGiftView';
import { ACTIVE_PAGES, CatalogNavigationView } from './views/navigation/CatalogNavigationView';
import { CatalogPageView } from './views/page/CatalogPageView';
@ -214,7 +214,7 @@ export const CatalogView: FC<CatalogViewProps> = props =>
</div>
</NitroCardContentView>
</NitroCardView> }
<CatalogPageGiftView />
<CatalogGiftView />
</CatalogContextProvider>
);
}

View File

@ -2,4 +2,4 @@
@import './navigation/CatalogNavigationView';
@import './page/CatalogPageView';
@import './search/CatalogSearchView';
@import './gift/CatalogPageGiftView';
@import './gift/CatalogGiftView';

View File

@ -10,7 +10,7 @@ import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon';
import { FurniImageView } from '../../../shared/furni-image/FurniImageView';
import { useCatalogContext } from '../../context/CatalogContext';
export const CatalogPageGiftView: FC<{}> = props =>
export const CatalogGiftView: FC<{}> = props =>
{
const { catalogState = null } = useCatalogContext();
const { giftConfiguration = null } = catalogState;

View File

@ -63,8 +63,6 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutBadgeDisplayViewProp
const stringDataType = new StringDataType();
stringDataType.setValue(productData);
console.log(stringDataType);
dispatchUiEvent(new SetRoomPreviewerStuffDataEvent(activeOffer, stringDataType));
}, [ currentBadge, activeOffer, roomPreviewer ]);

View File

@ -0,0 +1,27 @@
import { CallForHelpResultMessageEvent, FurnitureListItemParser, PetData } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react';
import { LocalizeText } from '../../api';
import { CreateMessageHook } from '../../hooks/messages/message-event';
import { NotificationAlertType } from '../notification-center/common/NotificationAlertType';
import { NotificationUtilities } from '../notification-center/common/NotificationUtilities';
import { GetCloseReasonKey } from './common/GetCloseReasonKey';
let furniMsgFragments: Map<number, FurnitureListItemParser>[] = null;
let petMsgFragments: Map<number, PetData>[] = null;
export const HelpMessageHandler: FC<{}> = props =>
{
const onCallForHelpResultMessageEvent = useCallback((event: CallForHelpResultMessageEvent) =>
{
const parser = event.getParser();
let message = parser.messageText;
if(!message || !message.length) message = LocalizeText('help.cfh.closed.' + GetCloseReasonKey(parser.resultType))
NotificationUtilities.simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('mod.alert.title'));
}, []);
CreateMessageHook(CallForHelpResultMessageEvent, onCallForHelpResultMessageEvent);
return null;
}

View File

@ -0,0 +1,11 @@
import { FC } from 'react';
import { HelpMessageHandler } from './HelpMessageHandler';
export const HelpView: FC<{}> = props =>
{
return (
<>
<HelpMessageHandler />
</>
);
}

View File

@ -0,0 +1,8 @@
export const GetCloseReasonKey = (code: number) =>
{
if(code === 1) return 'useless';
if(code === 2) return 'abusive';
return 'resolved';
}

View File

@ -9,6 +9,7 @@ import { CameraWidgetView } from '../camera/CameraWidgetView';
import { CatalogView } from '../catalog/CatalogView';
import { FriendsView } from '../friends/FriendsView';
import { GroupsView } from '../groups/GroupsView';
import { HelpView } from '../help/HelpView';
import { HotelView } from '../hotel-view/HotelView';
import { InventoryView } from '../inventory/InventoryView';
import { ModToolsView } from '../mod-tools/ModToolsView';
@ -69,6 +70,7 @@ export const MainView: FC<MainViewProps> = props =>
<UserProfileView />
<GroupsView />
<CameraWidgetView />
<HelpView />
</div>
);
}

View File

@ -1,20 +1,14 @@
import { AchievementNotificationMessageEvent, ActivityPointNotificationMessageEvent, ClubGiftNotificationEvent, HabboBroadcastMessageEvent, HotelClosesAndWillOpenAtEvent, HotelWillShutdownEvent, ModeratorMessageEvent, MOTDNotificationEvent, NotificationDialogMessageEvent, PetAddedToInventoryEvent, RespectReceivedEvent, RoomEnterEvent, Vector3d } from '@nitrots/nitro-renderer';
import { AchievementNotificationMessageEvent, ActivityPointNotificationMessageEvent, ClubGiftNotificationEvent, ClubGiftSelectedEvent, HabboBroadcastMessageEvent, HotelClosedAndOpensEvent, HotelClosesAndWillOpenAtEvent, HotelWillCloseInMinutesEvent, InfoFeedEnableMessageEvent, MaintenanceStatusMessageEvent, ModeratorCautionEvent, ModeratorMessageEvent, MOTDNotificationEvent, NotificationDialogMessageEvent, PetLevelNotificationEvent, PetReceivedMessageEvent, RespectReceivedEvent, RoomEnterEvent, UserBannedMessageEvent, Vector3d } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react';
import { GetRoomEngine, GetSessionDataManager, LocalizeBadgeName, LocalizeText } from '../../api';
import { NotificationCenterAlertEvent } from '../../events';
import { dispatchUiEvent } from '../../hooks/events';
import { GetConfiguration, GetRoomEngine, GetSessionDataManager, LocalizeBadgeName, LocalizeText } from '../../api';
import { CreateMessageHook } from '../../hooks/messages';
import { HotelWillShutdownNotification } from './common/HotelWillShutdownNotification';
import { NotificationType } from './common/NotificationType';
import { NotificationBubbleType } from './common/NotificationBubbleType';
import { NotificationUtilities } from './common/NotificationUtilities';
import { useNotificationCenterContext } from './context/NotificationCenterContext';
import { ProductImageUtility } from './common/ProductImageUtility';
import { INotificationCenterMessageHandlerProps } from './NotificationCenterMessageHandler.types';
import { NotificationCenterActions } from './reducers/NotificationCenterReducer';
export const NotificationCenterMessageHandler: FC<INotificationCenterMessageHandlerProps> = props =>
{
const { dispatchNotificationCenterState = null } = useNotificationCenterContext();
const onRespectReceivedEvent = useCallback((event: RespectReceivedEvent) =>
{
const parser = event.getParser();
@ -24,8 +18,8 @@ export const NotificationCenterMessageHandler: FC<INotificationCenterMessageHand
const text1 = LocalizeText('notifications.text.respect.1');
const text2 = LocalizeText('notifications.text.respect.2', [ 'count' ], [ parser.respectsReceived.toString() ]);
NotificationUtilities.showSingleBubble(text1, NotificationType.RESPECT);
NotificationUtilities.showSingleBubble(text2, NotificationType.RESPECT);
NotificationUtilities.showSingleBubble(text1, NotificationBubbleType.RESPECT);
NotificationUtilities.showSingleBubble(text2, NotificationBubbleType.RESPECT);
}, []);
CreateMessageHook(RespectReceivedEvent, onRespectReceivedEvent);
@ -34,7 +28,7 @@ export const NotificationCenterMessageHandler: FC<INotificationCenterMessageHand
{
const parser = event.getParser();
NotificationUtilities.simpleAlert(parser.message.replace(/\\r/g, '\r'));
NotificationUtilities.simpleAlert(parser.message.replace(/\\r/g, '\r'), null, null, LocalizeText('notifications.broadcast.title'));
}, []);
CreateMessageHook(HabboBroadcastMessageEvent, onHabboBroadcastMessageEvent);
@ -48,7 +42,7 @@ export const NotificationCenterMessageHandler: FC<INotificationCenterMessageHand
const badgeImage = GetSessionDataManager().getBadgeUrl(parser.data.badgeCode);
const internalLink = 'questengine/achievements/' + parser.data.category;
NotificationUtilities.showSingleBubble((text1 + ' ' + badgeName), NotificationType.ACHIEVEMENT, badgeImage, internalLink);
NotificationUtilities.showSingleBubble((text1 + ' ' + badgeName), NotificationBubbleType.ACHIEVEMENT, badgeImage, internalLink);
}, []);
CreateMessageHook(AchievementNotificationMessageEvent, onAchievementNotificationMessageEvent);
@ -66,7 +60,7 @@ export const NotificationCenterMessageHandler: FC<INotificationCenterMessageHand
{
const parser = event.getParser();
dispatchUiEvent(new NotificationCenterAlertEvent(NotificationCenterAlertEvent.HOTEL_ALERT, [ parser.message ], parser.link));
NotificationUtilities.handleModeratorMessage(parser.message, parser.link);
}, []);
CreateMessageHook(ModeratorMessageEvent, onModeratorMessageEvent);
@ -75,11 +69,31 @@ export const NotificationCenterMessageHandler: FC<INotificationCenterMessageHand
{
const parser = event.getParser();
// bubble for loyalty
if(parser.amountChanged <= 0) return;
let imageUrl: string = null;
switch(parser.type)
{
case 5:
imageUrl = GetConfiguration<string>('currency.asset.icon.url', '').replace('%type%', parser.type.toString());
break;
}
NotificationUtilities.showSingleBubble(LocalizeText('notifications.text.loyalty.received', [ 'amount' ], [ parser.amountChanged.toString() ]), NotificationBubbleType.INFO, imageUrl);
}, []);
CreateMessageHook(ActivityPointNotificationMessageEvent, onActivityPointNotificationMessageEvent);
const onUserBannedMessageEvent = useCallback((event: UserBannedMessageEvent) =>
{
const parser = event.getParser();
NotificationUtilities.handleUserBannedMessage(parser.message);
}, []);
CreateMessageHook(UserBannedMessageEvent, onUserBannedMessageEvent);
const onHotelClosesAndWillOpenAtEvent = useCallback((event: HotelClosesAndWillOpenAtEvent) =>
{
const parser = event.getParser();
@ -89,7 +103,7 @@ export const NotificationCenterMessageHandler: FC<INotificationCenterMessageHand
CreateMessageHook(HotelClosesAndWillOpenAtEvent, onHotelClosesAndWillOpenAtEvent);
const onPetAddedToInventoryEvent = useCallback((event: PetAddedToInventoryEvent) =>
const onPetReceivedMessageEvent = useCallback((event: PetReceivedMessageEvent) =>
{
const parser = event.getParser();
@ -101,10 +115,10 @@ export const NotificationCenterMessageHandler: FC<INotificationCenterMessageHand
if(imageResult) imageUrl = imageResult.getImage().src;
NotificationUtilities.showSingleBubble(text, NotificationType.PETLEVEL, imageUrl);
NotificationUtilities.showSingleBubble(text, NotificationBubbleType.PETLEVEL, imageUrl);
}, []);
CreateMessageHook(PetAddedToInventoryEvent, onPetAddedToInventoryEvent);
CreateMessageHook(PetReceivedMessageEvent, onPetReceivedMessageEvent);
const onRoomEnterEvent = useCallback((event: RoomEnterEvent) =>
{
@ -119,24 +133,67 @@ export const NotificationCenterMessageHandler: FC<INotificationCenterMessageHand
{
const parser = event.getParser();
dispatchUiEvent(new NotificationCenterAlertEvent(NotificationCenterAlertEvent.HOTEL_ALERT, parser.messages));
NotificationUtilities.handleMOTD(parser.messages);
}, []);
CreateMessageHook(MOTDNotificationEvent, onMOTDNotificationEvent);
const onHotelWillShutdownEvent = useCallback((event: HotelWillShutdownEvent) =>
const onPetLevelNotificationEvent = useCallback((event: PetLevelNotificationEvent) =>
{
const parser = event.getParser();
dispatchNotificationCenterState({
type: NotificationCenterActions.ADD_NOTIFICATION,
payload: {
notification: new HotelWillShutdownNotification(parser.minutes)
}
});
}, [ dispatchNotificationCenterState ]);
let imageUrl: string = null;
CreateMessageHook(HotelWillShutdownEvent, onHotelWillShutdownEvent);
const imageResult = GetRoomEngine().getRoomObjectPetImage(parser.figureData.typeId, parser.figureData.paletteId, parseInt(parser.figureData.color, 16), new Vector3d(45 * 3), 64, null, true);
if(imageResult) imageUrl = imageResult.getImage().src;
NotificationUtilities.showSingleBubble(LocalizeText('notifications.text.petlevel', [ 'pet_name', 'level' ], [ parser.petName, parser.level.toString() ]), NotificationBubbleType.PETLEVEL, imageUrl);
}, []);
CreateMessageHook(PetLevelNotificationEvent, onPetLevelNotificationEvent);
const onInfoFeedEnableMessageEvent = useCallback((event: InfoFeedEnableMessageEvent) =>
{
const parser = event.getParser();
NotificationUtilities.BUBBLES_DISABLED = !(parser.enabled);
}, []);
CreateMessageHook(InfoFeedEnableMessageEvent, onInfoFeedEnableMessageEvent);
const onClubGiftSelectedEvent = useCallback((event: ClubGiftSelectedEvent) =>
{
const parser = event.getParser();
if(!parser.products || !parser.products.length) return;
const productData = parser.products[0];
if(!productData) return;
NotificationUtilities.showSingleBubble(LocalizeText('notifications.text.club_gift.selected'), NotificationBubbleType.INFO, ProductImageUtility.getProductImageUrl(productData.productType, productData.furniClassId, productData.extraParam))
}, []);
CreateMessageHook(ClubGiftSelectedEvent, onClubGiftSelectedEvent);
const onMaintenanceStatusMessageEvent = useCallback((event: MaintenanceStatusMessageEvent) =>
{
const parser = event.getParser();
NotificationUtilities.handleHotelMaintenanceMessage(parser.minutesUntilMaintenance, parser.duration);
}, []);
CreateMessageHook(MaintenanceStatusMessageEvent, onMaintenanceStatusMessageEvent);
const onModeratorCautionEvent = useCallback((event: ModeratorCautionEvent) =>
{
const parser = event.getParser();
NotificationUtilities.handleModeratorCaution(parser.message, parser.url);
}, []);
CreateMessageHook(ModeratorCautionEvent, onModeratorCautionEvent);
const onNotificationDialogMessageEvent = useCallback((event: NotificationDialogMessageEvent) =>
{
@ -147,5 +204,23 @@ export const NotificationCenterMessageHandler: FC<INotificationCenterMessageHand
CreateMessageHook(NotificationDialogMessageEvent, onNotificationDialogMessageEvent);
const onHotelWillCloseInMinutesEvent = useCallback((event: HotelWillCloseInMinutesEvent) =>
{
const parser = event.getParser();
NotificationUtilities.handleHotelClosingMessage(parser.openMinute);
}, []);
CreateMessageHook(HotelWillCloseInMinutesEvent, onHotelWillCloseInMinutesEvent);
const onHotelClosedAndOpensEvent = useCallback((event: HotelClosedAndOpensEvent) =>
{
const parser = event.getParser();
NotificationUtilities.handleLoginFailedHotelClosedMessage(parser.openHour, parser.openMinute);
}, []);
CreateMessageHook(HotelClosedAndOpensEvent, onHotelClosedAndOpensEvent);
return null;
}

View File

@ -1,12 +1,3 @@
.nitro-alert {
width: 350px;
.content-area {
min-height: 125px;
max-height: 300px;
}
}
.nitro-notification-center-container {
position: absolute;
top: 0;

View File

@ -1,40 +1,42 @@
import { FC, ReactNode, useCallback, useMemo, useState } from 'react';
import { NotificationCenterAlertEvent } from '../../events';
import { createPortal } from 'react-dom';
import { NotificationAlertEvent } from '../../events';
import { NotificationBubbleEvent } from '../../events/notification-center/NotificationBubbleEvent';
import { useUiEvent } from '../../hooks/events';
import { NotificationItem } from './common/NotificationItem';
import { NotificationType } from './common/NotificationType';
import { NotificationAlertItem } from './common/NotificationAlertItem';
import { NotificationBubbleItem } from './common/NotificationBubbleItem';
import { NotificationBubbleType } from './common/NotificationBubbleType';
import { NotificationCenterMessageHandler } from './NotificationCenterMessageHandler';
import { NotificationCenterViewProps } from './NotificationCenterView.types';
import { NotificationCenterBroadcastMessageView } from './views/broadcast-message/NotificationCenterBroadcastMessageView';
import { GetAlertLayout } from './views/alert-layouts/GetAlertLayout';
import { GetBubbleLayout } from './views/bubble-layouts/GetBubbleLayout';
export const NotificationCenterView: FC<NotificationCenterViewProps> = props =>
{
const [ alerts, setAlerts ] = useState<NotificationCenterAlertEvent[]>([]);
const [ bubbleAlerts, setBubbleAlerts ] = useState<NotificationItem[]>([]);
const [ alerts, setAlerts ] = useState<NotificationAlertItem[]>([]);
const [ bubbleAlerts, setBubbleAlerts ] = useState<NotificationBubbleItem[]>([]);
const onNotificationCenterAlertEvent = useCallback((event: NotificationCenterAlertEvent) =>
const onNotificationAlertEvent = useCallback((event: NotificationAlertEvent) =>
{
setAlerts(prevValue =>
{
return [ ...prevValue, event ];
});
console.log(event);
const alertItem = new NotificationAlertItem(event.messages, event.alertType, event.clickUrl, event.clickUrlText, event.title, event.imageUrl);
setAlerts(prevValue => [ alertItem, ...prevValue ]);
}, []);
useUiEvent(NotificationCenterAlertEvent.HOTEL_ALERT, onNotificationCenterAlertEvent);
useUiEvent(NotificationAlertEvent.ALERT, onNotificationAlertEvent);
const onNotificationBubbleEvent = useCallback((event: NotificationBubbleEvent) =>
{
console.log(event);
const notificationItem = new NotificationItem(event.message, event.notificationType, event.imageUrl, event.linkUrl);
const notificationItem = new NotificationBubbleItem(event.message, event.notificationType, event.imageUrl, event.linkUrl);
setBubbleAlerts(prevValue => [ notificationItem, ...prevValue ]);
}, []);
useUiEvent(NotificationBubbleEvent.NEW_BUBBLE, onNotificationBubbleEvent);
const closeAlert = useCallback((alert: NotificationCenterAlertEvent) =>
const closeAlert = useCallback((alert: NotificationAlertItem) =>
{
setAlerts(prevValue =>
{
@ -47,7 +49,7 @@ export const NotificationCenterView: FC<NotificationCenterViewProps> = props =>
});
}, []);
const closeBubbleAlert = useCallback((item: NotificationItem) =>
const closeBubbleAlert = useCallback((item: NotificationBubbleItem) =>
{
setBubbleAlerts(prevValue =>
{
@ -60,6 +62,22 @@ export const NotificationCenterView: FC<NotificationCenterViewProps> = props =>
})
}, []);
const getAlerts = useMemo(() =>
{
if(!alerts || !alerts.length) return null;
const elements: ReactNode[] = [];
for(const alert of alerts)
{
const element = GetAlertLayout(alert, () => closeAlert(alert));
elements.push(element);
}
return elements;
}, [ alerts, closeAlert ]);
const getBubbleAlerts = useMemo(() =>
{
if(!bubbleAlerts || !bubbleAlerts.length) return null;
@ -70,7 +88,7 @@ export const NotificationCenterView: FC<NotificationCenterViewProps> = props =>
{
const element = GetBubbleLayout(alert, () => closeBubbleAlert(alert));
if(alert.notificationType === NotificationType.CLUBGIFT)
if(alert.notificationType === NotificationBubbleType.CLUBGIFT)
{
elements.unshift(element);
@ -89,15 +107,7 @@ export const NotificationCenterView: FC<NotificationCenterViewProps> = props =>
<div className="nitro-notification-center">
{ getBubbleAlerts }
</div>
{ (alerts.length > 0) && alerts.map((alert, index) =>
{
switch(alert.type)
{
case NotificationCenterAlertEvent.HOTEL_ALERT:
default:
return <NotificationCenterBroadcastMessageView key={ index } notification={ alert } onClose={ () => closeAlert(alert) } />;
}
})}
{ createPortal(getAlerts, document.getElementById('nitro-alerts-container')) }
</>
);
}

View File

@ -1,4 +0,0 @@
import { NitroNotification } from './Notification';
export class BroadcastMessageNotification extends NitroNotification
{}

View File

@ -1,24 +0,0 @@
import { NitroNotification } from './Notification';
export class DialogMessageNotification extends NitroNotification
{
private _type: string;
private _parameters: Map<string, string>;
constructor(type: string, parameters: Map<string, string>)
{
super();
this._type = type;
this._parameters = parameters;
}
public get type(): string
{
return this._type;
}
public get parameters(): Map<string, string>
{
return this._parameters;
}
}

View File

@ -1,17 +0,0 @@
import { NitroNotification } from './Notification';
export class HotelWillShutdownNotification extends NitroNotification
{
private _minutes: number;
constructor(minutes: number)
{
super();
this._minutes = minutes;
}
public get minutes(): number
{
return this._minutes;
}
}

View File

@ -1,19 +0,0 @@
import { NitroNotification } from './Notification';
export class MOTDNotification extends NitroNotification
{
private _messages: string[];
constructor(messages: string[])
{
super();
this._messages = [];
for(const message of messages) this._messages.push(message.replace(/\r\n|\r|\n/g, '<br />'));
}
public get messages(): string[]
{
return this._messages;
}
}

View File

@ -1,17 +0,0 @@
import { NitroNotification } from './Notification';
export class ModeratorMessageNotification extends NitroNotification
{
private _link: string;
constructor(message: string, link: string)
{
super(message);
this._link = link;
}
public get link(): string
{
return this._link;
}
}

View File

@ -1,49 +0,0 @@
export class NitroNotification
{
public static CURRENT_ID: number = 0;
private _id: number;
private _title: string;
private _message: string;
private _dismissed: boolean = false;
private _timestamp: number;
constructor(message: string = null, title: string = null)
{
this._id = ++NitroNotification.CURRENT_ID;
this._title = title;
this._timestamp = Date.now();
if(message) this._message = message.replace(/\r\n|\r|\n/g, '<br />');
}
public dismiss(): void
{
this._dismissed = true;
}
public get id(): number
{
return this._id;
}
public get title(): string
{
return this._title;
}
public get message(): string
{
return this._message;
}
public get dismissed(): boolean
{
return this._dismissed;
}
public get timestamp(): number
{
return this._timestamp;
}
}

View File

@ -0,0 +1,62 @@
import { NotificationBubbleType } from './NotificationBubbleType';
export class NotificationAlertItem
{
private static ITEM_ID: number = -1;
private _id: number;
private _messages: string[];
private _alertType: string;
private _clickUrl: string;
private _clickUrlText: string;
private _title: string;
private _imageUrl: string;
constructor(messages: string[], alertType: string = NotificationBubbleType.INFO, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null)
{
NotificationAlertItem.ITEM_ID += 1;
this._id = NotificationAlertItem.ITEM_ID;
this._messages = messages;
this._alertType = alertType;
this._clickUrl = clickUrl;
this._clickUrlText = clickUrlText;
this._title = title;
this._imageUrl = imageUrl;
}
public get id(): number
{
return this._id;
}
public get messages(): string[]
{
return this._messages;
}
public get alertType(): string
{
return this._alertType;
}
public get clickUrl(): string
{
return this._clickUrl;
}
public get clickUrlText(): string
{
return this._clickUrlText;
}
public get title(): string
{
return this._title;
}
public get imageUrl(): string
{
return this._imageUrl;
}
}

View File

@ -0,0 +1,7 @@
export class NotificationAlertType
{
public static DEFAULT: string = 'default';
public static MOTD: string = 'motd';
public static MODERATION: string = 'moderation';
public static EVENT: string = 'event';
}

View File

@ -1,6 +1,6 @@
import { NotificationType } from './NotificationType';
import { NotificationBubbleType } from './NotificationBubbleType';
export class NotificationItem
export class NotificationBubbleItem
{
private static ITEM_ID: number = -1;
@ -10,11 +10,11 @@ export class NotificationItem
private _iconUrl: string;
private _linkUrl: string;
constructor(message: string, notificationType: string = NotificationType.INFO, iconUrl: string = null, linkUrl: string = null)
constructor(message: string, notificationType: string = NotificationBubbleType.INFO, iconUrl: string = null, linkUrl: string = null)
{
NotificationItem.ITEM_ID += 1;
NotificationBubbleItem.ITEM_ID += 1;
this._id = NotificationItem.ITEM_ID;
this._id = NotificationBubbleItem.ITEM_ID;
this._message = message;
this._notificationType = notificationType;
this._iconUrl = iconUrl;

View File

@ -1,4 +1,4 @@
export class NotificationType
export class NotificationBubbleType
{
public static FRIENDOFFLINE: string = 'friendoffline';
public static FRIENDONLINE: string = 'friendonline';

View File

@ -1,10 +1,11 @@
import { HabboWebTools, RoomEnterEffect } from '@nitrots/nitro-renderer';
import { CreateLinkEvent, GetConfiguration, GetNitroInstance, LocalizeText } from '../../../api';
import { SimpleAlertUIEvent } from '../../../events';
import { NotificationAlertEvent } from '../../../events';
import { NotificationBubbleEvent } from '../../../events/notification-center/NotificationBubbleEvent';
import { dispatchUiEvent } from '../../../hooks';
import { CatalogPageName } from '../../catalog/common/CatalogPageName';
import { NotificationType } from './NotificationType';
import { NotificationAlertType } from './NotificationAlertType';
import { NotificationBubbleType } from './NotificationBubbleType';
export class NotificationUtilities
{
@ -12,6 +13,8 @@ export class NotificationUtilities
private static MODERATION_DISCLAIMER_DELAY_MS: number = 5000;
private static MODERATION_DISCLAIMER_TIMEOUT: ReturnType<typeof setTimeout> = null;
public static BUBBLES_DISABLED: boolean = false;
private static cleanText(text: string): string
{
return text.replace(/\\r/g, '\r')
@ -68,62 +71,92 @@ export class NotificationUtilities
const configuration = this.getNotificationConfig(('notification.' + type));
if(configuration)
{
for(const key in configuration) options.set(key, configuration[key]);
}
if(configuration) for(const key in configuration) options.set(key, configuration[key]);
console.log(options);
const title = this.getNotificationPart(options, type, 'title', true);
const message = this.getNotificationPart(options, type, 'message', true).replace(/\\r/g, '\r');
const linkTitle = this.getNotificationPart(options, type, 'linkTitle', false);
const linkUrl = this.getNotificationPart(options, type, 'linkUrl', false);
const image = this.getNotificationImageUrl(options, type);
if(options.get('display') === 'BUBBLE')
{
const message = this.getNotificationPart(options, type, 'message', true);
const linkUrl = this.getNotificationPart(options, type, 'linkUrl', false);
const isEventLink = (linkUrl && linkUrl.substr(0, 6) === 'event');
const image = this.getNotificationImageUrl(options, type);
dispatchUiEvent(new NotificationBubbleEvent(LocalizeText(message), NotificationType.INFO, LocalizeText(image), (isEventLink ? linkUrl.substr(6) : linkUrl)));
this.showSingleBubble(LocalizeText(message), NotificationBubbleType.INFO, LocalizeText(image), linkUrl);
}
else
{
this.simpleAlert(message, NotificationAlertType.EVENT, linkUrl, linkTitle, title, image);
}
}
public static showSingleBubble(message: string, type: string, imageUrl: string = null, internalLink: string = null): void
{
if(this.BUBBLES_DISABLED) return;
dispatchUiEvent(new NotificationBubbleEvent(message, type, imageUrl, internalLink));
}
public static simpleAlert(message: string, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null): void
{
if(!title || !title.length) title = LocalizeText('notifications.broadcast.title');
dispatchUiEvent(new SimpleAlertUIEvent(message, clickUrl, clickUrlText, title, imageUrl));
}
public static alert(title: string, message: string): void
{
dispatchUiEvent(new SimpleAlertUIEvent(message, null, null, title, null));
}
public static showClubGiftNotification(numGifts: number): void
{
if(numGifts <= 0) return;
dispatchUiEvent(new NotificationBubbleEvent(numGifts.toString(), NotificationType.CLUBGIFT, null, 'catalog/open/' + CatalogPageName.CLUB_GIFTS));
this.showSingleBubble(numGifts.toString(), NotificationBubbleType.CLUBGIFT, null, ('catalog/open/' + CatalogPageName.CLUB_GIFTS));
}
public static showModeratorMessage(message: string, url: string = null): void
public static handleMOTD(messages: string[]): void
{
this.simpleAlert(this.cleanText(message), url, LocalizeText('mod.alert.link'), LocalizeText('mod.alert.title'));
messages = messages.map(message => this.cleanText(message));
dispatchUiEvent(new NotificationAlertEvent(messages, NotificationAlertType.MOTD, null, null, LocalizeText('notifications.motd.title')));
}
public static simpleAlert(message: string, type: string, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null): void
{
if(!title || !title.length) title = LocalizeText('notifications.broadcast.title');
dispatchUiEvent(new NotificationAlertEvent([ this.cleanText(message) ], type, clickUrl, clickUrlText, title, imageUrl));
}
public static showModeratorMessage(message: string, url: string = null, showHabboWay: boolean = true): void
{
this.simpleAlert(message, NotificationAlertType.MODERATION, url, LocalizeText('mod.alert.link'), LocalizeText('mod.alert.title'));
}
public static handleModeratorCaution(message: string, url: string = null): void
{
this.showModeratorMessage(message, url);
}
public static handleModeratorMessage(message: string, url: string = null): void
{
this.showModeratorMessage(message, url, false);
}
public static handleUserBannedMessage(message: string): void
{
this.showModeratorMessage(message);
}
public static handleHotelClosedMessage(open: number, minute: number, thrownOut: boolean): void
{
const text: string = LocalizeText(('opening.hours.' + (thrownOut ? 'disconnected' : 'closed')), [ 'h', 'm'], [ this.getTimeZeroPadded(open), this.getTimeZeroPadded(minute) ]);;
this.simpleAlert( LocalizeText(('opening.hours.' + (thrownOut ? 'disconnected' : 'closed')), [ 'h', 'm'], [ this.getTimeZeroPadded(open), this.getTimeZeroPadded(minute) ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title'));
}
this.alert(LocalizeText('opening.hours.title'), text);
public static handleHotelMaintenanceMessage(minutesUntilMaintenance: number, duration: number): void
{
this.simpleAlert(LocalizeText('maintenance.shutdown', [ 'm', 'd' ], [ minutesUntilMaintenance.toString(), duration.toString() ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title'));
}
public static handleHotelClosingMessage(minutes: number): void
{
this.simpleAlert(LocalizeText('opening.hours.shutdown', [ 'm' ], [ minutes.toString() ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title'));
}
public static handleLoginFailedHotelClosedMessage(openHour: number, openMinutes: number): void
{
this.simpleAlert(LocalizeText('opening.hours.disconnected', [ 'h', 'm' ], [ openHour.toString(), openMinutes.toString() ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title'));
}
public static openUrl(url: string): void
@ -134,7 +167,7 @@ export class NotificationUtilities
}
else
{
CreateLinkEvent(url);
CreateLinkEvent(url.substring(6));
}
}
@ -153,7 +186,7 @@ export class NotificationUtilities
{
if(this.MODERATION_DISCLAIMER_SHOWN) return;
this.showSingleBubble(LocalizeText('mod.chatdisclaimer'), NotificationType.INFO);
this.showSingleBubble(LocalizeText('mod.chatdisclaimer'), NotificationBubbleType.INFO);
this.MODERATION_DISCLAIMER_SHOWN = true;
}

View File

@ -0,0 +1,59 @@
import { CatalogPageMessageProductData } from '@nitrots/nitro-renderer';
import { GetRoomEngine } from '../../../api';
import { FurniCategory } from '../../catalog/common/FurniCategory';
export class ProductImageUtility
{
public static getProductImageUrl(productType: string, furniClassId: number, extraParam: string): string
{
let imageUrl: string = null;
switch(productType)
{
case CatalogPageMessageProductData.S:
imageUrl = GetRoomEngine().getFurnitureFloorIconUrl(furniClassId);
break;
case CatalogPageMessageProductData.I:
const productCategory = this.getProductCategory(CatalogPageMessageProductData.I, furniClassId);
if(productCategory === 1)
{
imageUrl = GetRoomEngine().getFurnitureWallIconUrl(furniClassId, extraParam);
}
else
{
switch(productCategory)
{
case FurniCategory.WALL_PAPER:
break;
case FurniCategory.LANDSCAPE:
break;
case FurniCategory.FLOOR:
break;
}
}
break;
case CatalogPageMessageProductData.E:
// fx_icon_furniClassId_png
break;
}
return imageUrl;
}
private static getProductCategory(productType: string, furniClassId: number): number
{
if(productType === CatalogPageMessageProductData.S) return 1;
if(productType === CatalogPageMessageProductData.I)
{
if(furniClassId === 3001) return FurniCategory.WALL_PAPER;
if(furniClassId === 3002) return FurniCategory.FLOOR;
if(furniClassId === 4057) return FurniCategory.LANDSCAPE;
}
return 1;
}
}

View File

@ -1,14 +0,0 @@
import { createContext, FC, useContext } from 'react';
import { INotificationCenterContext, NotificationCenterContextProps } from './NotificationCenterContext.types';
const NotificationCenterContext = createContext<INotificationCenterContext>({
notificationCenterState: null,
dispatchNotificationCenterState: null
});
export const NotificationCenterContextProvider: FC<NotificationCenterContextProps> = props =>
{
return <NotificationCenterContext.Provider value={ props.value }>{ props.children }</NotificationCenterContext.Provider>
}
export const useNotificationCenterContext = () => useContext(NotificationCenterContext);

View File

@ -1,13 +0,0 @@
import { Dispatch, ProviderProps } from 'react';
import { INotificationCenterAction, INotificationCenterState } from '../reducers/NotificationCenterReducer';
export interface INotificationCenterContext
{
notificationCenterState: INotificationCenterState;
dispatchNotificationCenterState: Dispatch<INotificationCenterAction>;
}
export interface NotificationCenterContextProps extends ProviderProps<INotificationCenterContext>
{
}

View File

@ -1,77 +0,0 @@
import { Reducer } from 'react';
import { NitroNotification } from '../common/Notification';
export interface INotificationCenterState
{
notifications: NitroNotification[];
}
export interface INotificationCenterAction
{
type: string;
payload: {
id?: number;
notification?: NitroNotification;
};
}
export class NotificationCenterActions
{
public static ADD_NOTIFICATION: string = 'NCA_ADD_NOTIFICATION';
public static REMOVE_NOTIFICATION: string = 'NCA_REMOVE_NOTIFICATION';
public static DISMISS_NOTIFICATION: string = 'NCA_DISMISS_NOTIFICATION';
}
export const initialNotificationCenter: INotificationCenterState = {
notifications: []
}
export const NotificationCenterReducer: Reducer<INotificationCenterState, INotificationCenterAction> = (state, action) =>
{
switch(action.type)
{
case NotificationCenterActions.ADD_NOTIFICATION: {
const notification = (action.payload.notification || null);
if(!notification) return state;
const notifications = [ ...state.notifications, notification ];
return { ...state, notifications };
}
case NotificationCenterActions.REMOVE_NOTIFICATION: {
const id = (action.payload.id || null);
if(!id) return state;
if(!state.notifications) return state;
const notifications = Array.from(state.notifications);
const notificationIndex = notifications.findIndex(notification => notification.id === id);
if(notificationIndex === -1) return state;
notifications.splice(notificationIndex, 1);
return { ...state, notifications };
}
case NotificationCenterActions.DISMISS_NOTIFICATION: {
const id = (action.payload.id || null);
if(!id) return state;
if(!state.notifications) return state;
const notifications = Array.from(state.notifications);
const notificationIndex = notifications.findIndex(notification => notification.id === id);
if(notificationIndex === -1) return state;
notifications[notificationIndex].dismiss();
return { ...state, notifications };
}
default:
return state;
}
}

View File

@ -1,19 +0,0 @@
import { FC } from 'react';
import { LocalizeText } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
import { NotificationCenterAlertBaseProps } from './NotificationCenterAlertBase.types';
export const NotificationCenterAlertBase: FC<NotificationCenterAlertBaseProps> = props =>
{
const { headerText = LocalizeText('mod.alert.title'), onClose = null, children = null } = props;
return (
<NitroCardView className="nitro-alert" simple={ true }>
<NitroCardHeaderView headerText={ headerText } onCloseClick={ onClose } />
<NitroCardContentView className="d-flex flex-column justify-content-between text-black">
{ children }
</NitroCardContentView>
</NitroCardView>
);
}

View File

@ -1,5 +0,0 @@
export interface NotificationCenterAlertBaseProps
{
headerText?: string;
onClose: () => void;
}

View File

@ -0,0 +1,19 @@
import { NotificationAlertItem } from '../../common/NotificationAlertItem';
import { NotificationAlertType } from '../../common/NotificationAlertType';
import { NotificationDefaultAlertView } from './default/NotificationDefaultAlertView';
import { NotificationEventAlertView } from './event/NotificationEventAlertView';
export const GetAlertLayout = (item: NotificationAlertItem, close: () => void) =>
{
if(!item) return null;
const props = { key: item.id, item, close };
switch(item.alertType)
{
case NotificationAlertType.EVENT:
return <NotificationEventAlertView { ...props } />
default:
return <NotificationDefaultAlertView { ...props } />
}
}

View File

@ -0,0 +1,7 @@
import { NotificationAlertItem } from '../../common/NotificationAlertItem';
export interface NotificationAlertLayoutViewProps
{
item: NotificationAlertItem;
close: () => void;
}

View File

@ -0,0 +1,35 @@
import { FC, useCallback } from 'react';
import { LocalizeText } from '../../../../../api';
import { NotificationAlertView } from '../../../../../layout';
import { NotificationUtilities } from '../../../common/NotificationUtilities';
import { NotificationDefaultAlertViewProps } from './NotificationDefaultAlertView.types';
export const NotificationDefaultAlertView: FC<NotificationDefaultAlertViewProps> = props =>
{
const { item = null, close = null, ...rest } = props;
const visitUrl = useCallback(() =>
{
NotificationUtilities.openUrl(item.clickUrl);
close();
}, [ item, close ]);
return (
<NotificationAlertView title={ item.title } close={ close } { ...rest }>
{ (item.messages.length > 0) && item.messages.map((message, index) =>
{
const htmlText = message.replace(/\r\n|\r|\n/g, '<br />');
return (
<div key={ index } dangerouslySetInnerHTML={ { __html: htmlText } } />
);
}) }
<div className="d-flex justify-content-center align-items-center mt-1">
<button type="button" className="btn btn-primary" onClick={ close }>{ LocalizeText('generic.close') }</button>
</div>
{ item.clickUrl && item.clickUrl.length &&
<button type="button" className="btn btn-link" onClick={ visitUrl }>{ LocalizeText(item.clickUrlText) }</button> }
</NotificationAlertView>
);
}

View File

@ -0,0 +1,7 @@
import { DetailsHTMLAttributes } from 'react';
import { NotificationAlertLayoutViewProps } from '../NotificationAlertLayoutView.types';
export interface NotificationDefaultAlertViewProps extends NotificationAlertLayoutViewProps, DetailsHTMLAttributes<HTMLDivElement>
{
}

View File

@ -0,0 +1,33 @@
import { FC, useCallback } from 'react';
import { LocalizeText } from '../../../../../api';
import { NotificationAlertView } from '../../../../../layout';
import { NotificationUtilities } from '../../../common/NotificationUtilities';
import { NotificationEventAlertViewProps } from './NotificationEventAlertView.types';
export const NotificationEventAlertView: FC<NotificationEventAlertViewProps> = props =>
{
const { item = null, close = null, ...rest } = props;
const visitUrl = useCallback(() =>
{
NotificationUtilities.openUrl(item.clickUrl);
close();
}, [ item, close ]);
return (
<NotificationAlertView title={ item.title } close={ close } { ...rest }>
{ (item.messages.length > 0) && item.messages.map((message, index) =>
{
const htmlText = message.replace(/\r\n|\r|\n/g, '<br />');
return (
<div key={ index } dangerouslySetInnerHTML={ { __html: htmlText } } />
);
}) }
<div className="d-flex justify-content-center align-items-center mt-1">
<button type="button" className="btn btn-primary" onClick={ visitUrl }>{ LocalizeText(item.clickUrlText) }</button>
</div>
</NotificationAlertView>
);
}

View File

@ -0,0 +1,7 @@
import { DetailsHTMLAttributes } from 'react';
import { NotificationAlertLayoutViewProps } from '../NotificationAlertLayoutView.types';
export interface NotificationEventAlertViewProps extends NotificationAlertLayoutViewProps, DetailsHTMLAttributes<HTMLDivElement>
{
}

View File

@ -1,30 +0,0 @@
import { FC, useMemo } from 'react';
import { LocalizeText } from '../../../../api';
import { NotificationCenterAlertBase } from '../alert-base/NotificationCenterAlertBase';
import { NotificationCenterBroadcastMessageViewProps } from './NotificationCenterBroadcastMessageView.types';
export const NotificationCenterBroadcastMessageView: FC<NotificationCenterBroadcastMessageViewProps> = props =>
{
const { notification = null, onClose = null } = props;
const message = useMemo(() =>
{
let finalMessage = '';
notification.message.forEach(message =>
{
finalMessage += message.replace(/\r\n|\r|\n/g, '<br />');
});
return finalMessage;
}, [ notification ]);
return (
<NotificationCenterAlertBase onClose={ onClose }>
<div dangerouslySetInnerHTML={ { __html: message } } />
<div className="d-flex justify-content-center align-items-center">
<button type="button" className="btn btn-primary" onClick={ onClose }>{ LocalizeText('generic.close') }</button>
</div>
</NotificationCenterAlertBase>
);
};

View File

@ -1,7 +0,0 @@
import { NotificationCenterAlertEvent } from '../../../../events';
export class NotificationCenterBroadcastMessageViewProps
{
notification: NotificationCenterAlertEvent;
onClose: () => void;
}

View File

@ -1,9 +1,9 @@
import { NotificationItem } from '../../common/NotificationItem';
import { NotificationType } from '../../common/NotificationType';
import { NotificationBubbleItem } from '../../common/NotificationBubbleItem';
import { NotificationBubbleType } from '../../common/NotificationBubbleType';
import { NotificationClubGiftBubbleView } from './club-gift/NotificationClubGiftBubbleView';
import { NotificationDefaultBubbleView } from './default/NotificationDefaultBubbleView';
export const GetBubbleLayout = (item: NotificationItem, close: () => void) =>
export const GetBubbleLayout = (item: NotificationBubbleItem, close: () => void) =>
{
if(!item) return null;
@ -11,7 +11,7 @@ export const GetBubbleLayout = (item: NotificationItem, close: () => void) =>
switch(item.notificationType)
{
case NotificationType.CLUBGIFT:
case NotificationBubbleType.CLUBGIFT:
return <NotificationClubGiftBubbleView { ...props } />
default:
return <NotificationDefaultBubbleView { ...props } />

View File

@ -1,7 +1,7 @@
import { NotificationItem } from '../../common/NotificationItem';
import { NotificationBubbleItem } from '../../common/NotificationBubbleItem';
export interface NotificationBubbleLayoutViewProps
{
item: NotificationItem;
item: NotificationBubbleItem;
close: () => void;
}

View File

@ -1,28 +0,0 @@
import { FC } from 'react';
import { LocalizeText } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
import { NotificationTrayItemView } from '../tray-item/NotificationTrayItemView';
import { HotelWillShutdownViewProps } from './HotelWillShutdownView.types';
export const HotelWillShutdownView: FC<HotelWillShutdownViewProps> = props =>
{
const { notification = null, inTray = null, onButtonClick = null } = props;
if(!notification) return null;
const content = <>{ LocalizeText('opening.hours.shutdown', ['m'], [notification.minutes.toString()]) }</>;
if(inTray)
return (
<NotificationTrayItemView title={ LocalizeText('mod.alert.title') } content={ content } timestamp={ notification.timestamp } onCloseClick={ () => onButtonClick('remove_notification') } />
);
return (
<NitroCardView className="nitro-notification" simple={ true }>
<NitroCardHeaderView headerText={ LocalizeText('mod.alert.title') } onCloseClick={ () => onButtonClick('dismiss_notification') } />
<NitroCardContentView className="text-black">
{ content }
</NitroCardContentView>
</NitroCardView>
);
};

View File

@ -1,7 +0,0 @@
import { HotelWillShutdownNotification } from '../../common/HotelWillShutdownNotification';
import { NotificationViewProps } from '../../NotificationCenterView.types';
export class HotelWillShutdownViewProps extends NotificationViewProps
{
notification: HotelWillShutdownNotification;
}

View File

@ -1,33 +0,0 @@
import { FC } from 'react';
import { LocalizeText } from '../../../../api';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout';
import { NotificationTrayItemView } from '../tray-item/NotificationTrayItemView';
import { ModeratorMessageViewProps } from './ModeratorMessageView.types';
export const ModeratorMessageView: FC<ModeratorMessageViewProps> = props =>
{
const { notification = null, inTray = null, onButtonClick = null } = props;
if(!notification) return null;
const content = <>
<div dangerouslySetInnerHTML={ { __html: notification.message } } />
<div className="fw-bold text-center">
<a href={ notification.link } rel="noreferrer" target="_blank" onClick={ () => onButtonClick('dismiss_notification') }>{ LocalizeText('mod.alert.link') }</a>
</div>
</>;
if(inTray)
return (
<NotificationTrayItemView title={ LocalizeText('mod.alert.title') } content={ content } timestamp={ notification.timestamp } onCloseClick={ () => onButtonClick('remove_notification') } />
);
return (
<NitroCardView className="nitro-notification" simple={ true }>
<NitroCardHeaderView headerText={ LocalizeText('mod.alert.title') } onCloseClick={ () => onButtonClick('dismiss_notification') } />
<NitroCardContentView className="text-black">
{ content }
</NitroCardContentView>
</NitroCardView>
);
};

View File

@ -1,7 +0,0 @@
import { ModeratorMessageNotification } from '../../common/ModeratorMessageNotification';
import { NotificationViewProps } from '../../NotificationCenterView.types';
export class ModeratorMessageViewProps extends NotificationViewProps
{
notification: ModeratorMessageNotification;
}

View File

@ -1,10 +0,0 @@
import { FC } from 'react';
import { NotificationCenterBroadcastMessageView } from '../broadcast-message/NotificationCenterBroadcastMessageView';
import { NotificationCenterMotdViewProps } from './NotificationCenterMotdView.types';
export const NotificationCenterMotdView: FC<NotificationCenterMotdViewProps> = props =>
{
const { notification = null, onClose = null } = props;
return <NotificationCenterBroadcastMessageView notification={ notification } onClose={ onClose } />;
}

View File

@ -1,7 +0,0 @@
import { NotificationCenterAlertEvent } from '../../../../events';
export interface NotificationCenterMotdViewProps
{
notification: NotificationCenterAlertEvent;
onClose: () => void;
}

View File

@ -1,22 +0,0 @@
import { FC } from 'react';
import { NotificationTrayItemViewProps } from './NotificationTrayItemView.types';
export const NotificationTrayItemView: FC<NotificationTrayItemViewProps> = props =>
{
const { title = null, content = null, timestamp = null, onCloseClick = null } = props;
return (
<div className="rounded bg-muted mb-2 text-black">
<div className="py-1 px-2 fw-bold d-flex justify-content-between align-items-center">
<div className="me-2">{ title }</div>
<i className="fas fa-times cursor-pointer" onClick={ onCloseClick }></i>
</div>
<div className="py-1 px-2">
{ content }
</div>
<div className="py-1 px-2">
<i className="far fa-clock"></i> { timestamp }
</div>
</div>
);
};

View File

@ -1,7 +0,0 @@
export class NotificationTrayItemViewProps
{
title: string;
content: any;
timestamp: number;
onCloseClick: () => void;
}

View File

@ -260,11 +260,18 @@ export const ChatInputView: FC<{}> = props =>
}
}, [ onKeyDownEvent ]);
useEffect(() =>
{
if(!inputRef.current) return;
inputRef.current.parentElement.dataset.value = chatValue;
}, [ chatValue ]);
return (
createPortal(
<div className="nitro-chat-input-container">
<div className="input-sizer">
<input ref={ inputRef } type="text" className="chat-input" placeholder={ LocalizeText('widgets.chatinput.default') } value={ chatValue } maxLength={ maxChatLength } onChange={ event => { event.target.parentElement.dataset.value = event.target.value; updateChatInput(event.target.value) } } onMouseDown={ event => setInputFocus() } />
<input ref={ inputRef } type="text" className="chat-input" placeholder={ LocalizeText('widgets.chatinput.default') } value={ chatValue } maxLength={ maxChatLength } onChange={ event => updateChatInput(event.target.value) } onMouseDown={ event => setInputFocus() } />
</div>
<ChatInputStyleSelectorView onStyleSelected={ onStyleSelected } />
</div>, document.getElementById('toolbar-chat-input-container'))

View File

@ -55,16 +55,8 @@ export const FurnitureDimmerView: FC<{}> = props =>
BatchUpdates(() =>
{
let prevDimmerState = 0;
setDimmerState(prevValue =>
{
setLastDimmerState(prevValue);
return widgetEvent.state;
});
setLastDimmerState(prevDimmerState);
setLastDimmerState(dimmerState);
setDimmerState(widgetEvent.state);
setSelectedPresetId(widgetEvent.presetId);
setEffectId(widgetEvent.effectId);
setSelectedEffectId(widgetEvent.effectId);
@ -73,10 +65,11 @@ export const FurnitureDimmerView: FC<{}> = props =>
setBrightness(widgetEvent.brightness);
setSelectedBrightness(widgetEvent.brightness);
});
return;
}
}
}, []);
}, [ dimmerState ]);
CreateEventDispatcherHook(RoomWidgetUpdateDimmerEvent.PRESETS, eventDispatcher, onNitroEvent);
CreateEventDispatcherHook(RoomWidgetUpdateDimmerEvent.HIDE, eventDispatcher, onNitroEvent);
@ -144,6 +137,8 @@ export const FurnitureDimmerView: FC<{}> = props =>
{
if((dimmerState === 0) && (lastDimmerState === 0)) return;
console.log('ye')
widgetHandler.processWidgetMessage(new RoomWidgetDimmerPreviewMessage(selectedColor, selectedBrightness, (selectedEffectId === 2)));
}, [ widgetHandler, dimmerState, lastDimmerState, selectedColor, selectedBrightness, selectedEffectId ]);