From 1461f43a6d0dc933a84fdae54d803d3bc7ece6a4 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 23 Jul 2022 22:58:34 -0400 Subject: [PATCH] Update notification system --- .../inventory/TradingNotificationMessage.ts | 27 -- src/api/inventory/index.ts | 1 - src/api/nitro/OpenUrl.ts | 16 + src/api/nitro/index.ts | 1 + src/api/notification/NotificationUtilities.ts | 213 ---------- src/api/notification/index.ts | 1 - .../camera/views/CameraWidgetCaptureView.tsx | 9 +- .../page/common/CatalogRedeemVoucherView.tsx | 13 +- .../CatalogLayoutMarketplaceOwnItemsView.tsx | 9 +- ...atalogLayoutMarketplacePublicItemsView.tsx | 19 +- .../marketplace/MarketplacePostOfferView.tsx | 7 +- .../vip-gifts/CatalogLayoutVipGiftsView.tsx | 9 +- .../groups/views/GroupInformationView.tsx | 6 +- .../groups/views/GroupMembersView.tsx | 9 +- .../groups/views/GroupRoomInformationView.tsx | 7 +- .../views/tabs/GroupTabIdentityView.tsx | 6 +- src/components/help/HelpMessageHandler.tsx | 29 +- .../promo-article/PromoArticleWidgetView.tsx | 4 +- .../widget-container/WidgetContainerView.tsx | 4 +- .../views/furniture/InventoryTradeView.tsx | 7 +- src/components/loading/LoadingView.tsx | 10 +- .../mod-tools/ModToolsMessageHandler.tsx | 15 +- .../views/user/ModToolsUserModActionView.tsx | 6 +- .../navigator/NavigatorMessageHandler.tsx | 29 +- .../NavigatorRoomSettingsBasicTabView.tsx | 6 +- src/components/nitropedia/NitropediaView.tsx | 4 +- .../NotificationCenterMessageHandler.tsx | 215 ---------- .../NotificationCenterView.tsx | 79 +--- .../NotificationDefaultAlertView.tsx | 4 +- .../NotificationSearchAlertView.tsx | 4 +- .../NotificationClubGiftBubbleView.tsx | 4 +- .../NotificationDefaultBubbleView.tsx | 4 +- .../room/widgets/RoomWidgetsView.tsx | 7 +- src/hooks/catalog/useCatalog.ts | 12 +- src/hooks/friends/useMessenger.ts | 24 +- src/hooks/index.ts | 1 + src/hooks/inventory/useInventoryTrade.ts | 16 +- src/hooks/notification/index.ts | 1 + src/hooks/notification/useNotification.ts | 386 ++++++++++++++++++ .../useFurnitureBadgeDisplayWidget.ts | 6 +- src/hooks/rooms/widgets/useChatInputWidget.ts | 8 +- src/hooks/wired/useWired.ts | 6 +- 42 files changed, 569 insertions(+), 675 deletions(-) delete mode 100644 src/api/inventory/TradingNotificationMessage.ts create mode 100644 src/api/nitro/OpenUrl.ts delete mode 100644 src/api/notification/NotificationUtilities.ts delete mode 100644 src/components/notification-center/NotificationCenterMessageHandler.tsx create mode 100644 src/hooks/notification/index.ts create mode 100644 src/hooks/notification/useNotification.ts diff --git a/src/api/inventory/TradingNotificationMessage.ts b/src/api/inventory/TradingNotificationMessage.ts deleted file mode 100644 index 44e18634..00000000 --- a/src/api/inventory/TradingNotificationMessage.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { NotificationUtilities } from '../notification'; -import { LocalizeText } from '../utils'; -import { TradingNotificationType } from './TradingNotificationType'; - -export const TradingNotificationMessage = (type: number, otherUsername: string = '') => -{ - switch(type) - { - case TradingNotificationType.ALERT_SCAM: - NotificationUtilities.simpleAlert(LocalizeText('inventory.trading.warning.other_not_offering'), null, null, null, LocalizeText('inventory.trading.notification.title')); - return; - case TradingNotificationType.HOTEL_TRADING_DISABLED: - case TradingNotificationType.YOU_NOT_ALLOWED: - case TradingNotificationType.THEY_NOT_ALLOWED: - case TradingNotificationType.ROOM_DISABLED: - case TradingNotificationType.YOU_OPEN: - case TradingNotificationType.THEY_OPEN: - NotificationUtilities.simpleAlert(LocalizeText(`inventory.trading.openfail.${ type }`, [ 'otherusername' ], [ otherUsername ]), null, null, null, LocalizeText('inventory.trading.openfail.title')); - return; - case TradingNotificationType.ERROR_WHILE_COMMIT: - NotificationUtilities.simpleAlert(`${ LocalizeText('inventory.trading.notification.caption') }, ${ LocalizeText('inventory.trading.notification.commiterror.info') }`, null, null, null, LocalizeText('inventory.trading.notification.title')); - return; - case TradingNotificationType.THEY_CANCELLED: - NotificationUtilities.simpleAlert(LocalizeText('inventory.trading.info.closed'), null, null, null, LocalizeText('inventory.trading.notification.title')); - return; - } -} diff --git a/src/api/inventory/index.ts b/src/api/inventory/index.ts index 370696bc..76962cfe 100644 --- a/src/api/inventory/index.ts +++ b/src/api/inventory/index.ts @@ -10,7 +10,6 @@ export * from './IUnseenItemTracker'; export * from './PetUtilities'; export * from './TradeState'; export * from './TradeUserData'; -export * from './TradingNotificationMessage'; export * from './TradingNotificationType'; export * from './TradingUtilities'; export * from './UnseenItemCategory'; diff --git a/src/api/nitro/OpenUrl.ts b/src/api/nitro/OpenUrl.ts new file mode 100644 index 00000000..096776d7 --- /dev/null +++ b/src/api/nitro/OpenUrl.ts @@ -0,0 +1,16 @@ +import { HabboWebTools } from '@nitrots/nitro-renderer'; +import { CreateLinkEvent } from './CreateLinkEvent'; + +export const OpenUrl = (url: string) => +{ + if(!url || !url.length) return; + + if(url.startsWith('http')) + { + HabboWebTools.openWebPage(url); + } + else + { + CreateLinkEvent(url); + } +} diff --git a/src/api/nitro/index.ts b/src/api/nitro/index.ts index f3d75671..c5af3a30 100644 --- a/src/api/nitro/index.ts +++ b/src/api/nitro/index.ts @@ -10,6 +10,7 @@ export * from './GetConnection'; export * from './GetLocalization'; export * from './GetNitroInstance'; export * from './GetTicker'; +export * from './OpenUrl'; export * from './RemoveLinkEventTracker'; export * from './RemoveWorkerEventTracker'; export * from './room'; diff --git a/src/api/notification/NotificationUtilities.ts b/src/api/notification/NotificationUtilities.ts deleted file mode 100644 index c243e325..00000000 --- a/src/api/notification/NotificationUtilities.ts +++ /dev/null @@ -1,213 +0,0 @@ -import { HabboWebTools, RoomEnterEffect } from '@nitrots/nitro-renderer'; -import { NotificationAlertEvent, NotificationConfirmEvent } from '../../events'; -import { NotificationBubbleEvent } from '../../events/notification-center/NotificationBubbleEvent'; -import { DispatchUiEvent } from '../events'; -import { CreateLinkEvent, GetConfiguration, GetNitroInstance } from '../nitro'; -import { LocalizeText, PlaySound } from '../utils'; -import { NotificationAlertType } from './NotificationAlertType'; -import { NotificationBubbleType } from './NotificationBubbleType'; - -export class NotificationUtilities -{ - private static MODERATION_DISCLAIMER_SHOWN: boolean = false; - private static MODERATION_DISCLAIMER_DELAY_MS: number = 5000; - private static MODERATION_DISCLAIMER_TIMEOUT: ReturnType = null; - - public static BUBBLES_DISABLED: boolean = false; - - private static cleanText(text: string): string - { - return text.replace(/\\r/g, '\r') - } - - private static getTimeZeroPadded(time: number): string - { - const text = ('0' + time); - - return text.substr((text.length - 2), text.length); - } - - private static getMainNotificationConfig(): { [key: string]: { delivery?: string, display?: string; title?: string; image?: string }} - { - return GetConfiguration<{ [key: string]: { delivery?: string, display?: string; title?: string; image?: string }}>('notification', {}); - } - - private static getNotificationConfig(key: string): { delivery?: string, display?: string; title?: string; image?: string } - { - const mainConfig = this.getMainNotificationConfig(); - - if(!mainConfig) return null; - - return mainConfig[key]; - } - - public static getNotificationPart(options: Map, type: string, key: string, localize: boolean): string - { - if(options.has(key)) return options.get(key); - - const localizeKey = [ 'notification', type, key ].join('.'); - - if(GetNitroInstance().localization.hasValue(localizeKey) || localize) - { - return LocalizeText(localizeKey, Array.from(options.keys()), Array.from(options.values())); - } - - return null; - } - - public static getNotificationImageUrl(options: Map, type: string): string - { - let imageUrl = options.get('image'); - - if(!imageUrl) imageUrl = GetConfiguration('image.library.notifications.url', '').replace('%image%', type.replace(/\./g, '_')); - - return LocalizeText(imageUrl); - } - - public static showNotification(type: string, options: Map = null): void - { - if(!options) options = new Map(); - - const configuration = this.getNotificationConfig(('notification.' + type)); - - if(configuration) for(const key in configuration) options.set(key, configuration[key]); - - 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') - { - this.showSingleBubble(LocalizeText(message), NotificationBubbleType.INFO, image, linkUrl); - } - else - { - this.simpleAlert(message, type, linkUrl, linkTitle, title, image); - } - - if(options.get('sound')) PlaySound(options.get('sound')); - } - - 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 showClubGiftNotification(numGifts: number): void - { - if(numGifts <= 0) return; - - this.showSingleBubble(numGifts.toString(), NotificationBubbleType.CLUBGIFT, null, ('catalog/open/' + GetConfiguration('catalog.links')['hc.hc_gifts'])); - } - - public static handleMOTD(messages: string[]): void - { - messages = messages.map(message => this.cleanText(message)); - - DispatchUiEvent(new NotificationAlertEvent(messages, NotificationAlertType.MOTD, null, null, LocalizeText('notifications.motd.title'))); - } - - public static confirm(message: string, onConfirm: Function, onCancel: Function, confirmText: string = null, cancelText: string = null, title: string = null, type: string = null): void - { - if(!confirmText || !confirmText.length) confirmText = LocalizeText('generic.confirm'); - - if(!cancelText || !cancelText.length) cancelText = LocalizeText('generic.cancel'); - - if(!title || !title.length) title = LocalizeText('notifications.broadcast.title'); - - DispatchUiEvent(new NotificationConfirmEvent(type, this.cleanText(message), onConfirm, onCancel, confirmText, cancelText, title)); - } - - public static simpleAlert(message: string, type: string = null, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null): void - { - if(!title || !title.length) title = LocalizeText('notifications.broadcast.title'); - - if(!type || !type.length) type = NotificationAlertType.DEFAULT; - - DispatchUiEvent(new NotificationAlertEvent([ this.cleanText(message) ], type, clickUrl, clickUrlText, title, imageUrl)); - } - - public static showNitroAlert(): void - { - DispatchUiEvent(new NotificationAlertEvent(null, NotificationAlertType.NITRO)); - } - - public static showModeratorMessage(message: string, url: string = null, showHabboWay: boolean = true): void - { - this.simpleAlert(message, NotificationAlertType.DEFAULT, 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 - { - this.simpleAlert( LocalizeText(('opening.hours.' + (thrownOut ? 'disconnected' : 'closed')), [ 'h', 'm' ], [ this.getTimeZeroPadded(open), this.getTimeZeroPadded(minute) ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title')); - } - - 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 - { - if(!url || !url.length) return; - - if(url.startsWith('http')) - { - HabboWebTools.openWebPage(url); - } - else - { - CreateLinkEvent(url); - } - } - - public static showModerationDisclaimer(): void - { - if(RoomEnterEffect.isRunning()) - { - if(this.MODERATION_DISCLAIMER_TIMEOUT) return; - - this.MODERATION_DISCLAIMER_TIMEOUT = setTimeout(() => - { - this.showModerationDisclaimer(); - }, (RoomEnterEffect.totalRunningTime + this.MODERATION_DISCLAIMER_DELAY_MS)); - } - else - { - if(this.MODERATION_DISCLAIMER_SHOWN) return; - - this.showSingleBubble(LocalizeText('mod.chatdisclaimer'), NotificationBubbleType.INFO); - - this.MODERATION_DISCLAIMER_SHOWN = true; - } - } -} diff --git a/src/api/notification/index.ts b/src/api/notification/index.ts index 6489b87f..23476d35 100644 --- a/src/api/notification/index.ts +++ b/src/api/notification/index.ts @@ -4,4 +4,3 @@ export * from './NotificationBubbleItem'; export * from './NotificationBubbleType'; export * from './NotificationConfirmItem'; export * from './NotificationConfirmType'; -export * from './NotificationUtilities'; diff --git a/src/components/camera/views/CameraWidgetCaptureView.tsx b/src/components/camera/views/CameraWidgetCaptureView.tsx index 51df7484..e6c6a3fa 100644 --- a/src/components/camera/views/CameraWidgetCaptureView.tsx +++ b/src/components/camera/views/CameraWidgetCaptureView.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { NitroRectangle, TextureUtils } from '@nitrots/nitro-renderer'; import { FC, useCallback, useRef } from 'react'; -import { CameraPicture, GetRoomEngine, GetRoomSession, LocalizeText, NotificationUtilities, PlaySound, SoundNames } from '../../../api'; +import { CameraPicture, GetRoomEngine, GetRoomSession, LocalizeText, PlaySound, SoundNames } from '../../../api'; import { Column, DraggableWindow, Flex } from '../../../common'; -import { useCamera } from '../../../hooks'; +import { useCamera, useNotification } from '../../../hooks'; export interface CameraWidgetCaptureViewProps { @@ -18,6 +18,7 @@ export const CameraWidgetCaptureView: FC = props = { const { onClose = null, onEdit = null, onDelete = null } = props; const { cameraRoll = null, setCameraRoll = null, selectedPictureIndex = -1, setSelectedPictureIndex = null } = useCamera(); + const { simpleAlert = null } = useNotification(); const elementRef = useRef(); const selectedPicture = ((selectedPictureIndex > -1) ? cameraRoll[selectedPictureIndex] : null); @@ -45,7 +46,7 @@ export const CameraWidgetCaptureView: FC = props = if(clone.length >= CAMERA_ROLL_LIMIT) { - NotificationUtilities.simpleAlert(LocalizeText('camera.full.body')); + simpleAlert(LocalizeText('camera.full.body')); clone.pop(); } @@ -54,7 +55,7 @@ export const CameraWidgetCaptureView: FC = props = clone.push(new CameraPicture(texture, TextureUtils.generateImageUrl(texture))); setCameraRoll(clone); - }, [ cameraRoll, selectedPictureIndex, getCameraBounds, setCameraRoll, setSelectedPictureIndex ]); + }, [ cameraRoll, selectedPictureIndex, getCameraBounds, setCameraRoll, setSelectedPictureIndex, simpleAlert ]); return ( diff --git a/src/components/catalog/views/page/common/CatalogRedeemVoucherView.tsx b/src/components/catalog/views/page/common/CatalogRedeemVoucherView.tsx index 5757ae77..23fb9088 100644 --- a/src/components/catalog/views/page/common/CatalogRedeemVoucherView.tsx +++ b/src/components/catalog/views/page/common/CatalogRedeemVoucherView.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { RedeemVoucherMessageComposer, VoucherRedeemErrorMessageEvent, VoucherRedeemOkMessageEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../../api'; +import { LocalizeText, SendMessageComposer } from '../../../../../api'; import { Button, Flex } from '../../../../../common'; -import { useMessageEvent } from '../../../../../hooks'; +import { useMessageEvent, useNotification } from '../../../../../hooks'; export interface CatalogRedeemVoucherViewProps { @@ -15,6 +15,7 @@ export const CatalogRedeemVoucherView: FC = props const { text = null } = props; const [ voucher, setVoucher ] = useState(''); const [ isWaiting, setIsWaiting ] = useState(false); + const { simpleAlert = null } = useNotification(); const redeemVoucher = () => { @@ -33,11 +34,11 @@ export const CatalogRedeemVoucherView: FC = props if(parser.productName) message = LocalizeText('catalog.alert.voucherredeem.ok.description.furni', [ 'productName', 'productDescription' ], [ parser.productName, parser.productDescription ]); - NotificationUtilities.simpleAlert(message, null, null, null, LocalizeText('catalog.alert.voucherredeem.ok.title')); + simpleAlert(message, null, null, null, LocalizeText('catalog.alert.voucherredeem.ok.title')); setIsWaiting(false); setVoucher(''); - }, []); + }, [ simpleAlert ]); useMessageEvent(VoucherRedeemOkMessageEvent, onVoucherRedeemOkMessageEvent); @@ -45,10 +46,10 @@ export const CatalogRedeemVoucherView: FC = props { const parser = event.getParser(); - NotificationUtilities.simpleAlert(LocalizeText(`catalog.alert.voucherredeem.error.description.${ parser.errorCode }`), null, null, null, LocalizeText('catalog.alert.voucherredeem.error.title')); + simpleAlert(LocalizeText(`catalog.alert.voucherredeem.error.description.${ parser.errorCode }`), null, null, null, LocalizeText('catalog.alert.voucherredeem.error.title')); setIsWaiting(false); - }, []); + }, [ simpleAlert ]); useMessageEvent(VoucherRedeemErrorMessageEvent, onVoucherRedeemErrorMessageEvent); diff --git a/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplaceOwnItemsView.tsx b/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplaceOwnItemsView.tsx index 81c9d7fd..b2314ede 100644 --- a/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplaceOwnItemsView.tsx +++ b/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplaceOwnItemsView.tsx @@ -1,8 +1,8 @@ import { CancelMarketplaceOfferMessageComposer, GetMarketplaceOwnOffersMessageComposer, MarketplaceCancelOfferResultEvent, MarketplaceOwnOffersEvent, RedeemMarketplaceOfferCreditsMessageComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import { LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer } from '../../../../../../api'; +import { LocalizeText, NotificationAlertType, SendMessageComposer } from '../../../../../../api'; import { Button, Column, Text } from '../../../../../../common'; -import { useMessageEvent } from '../../../../../../hooks'; +import { useMessageEvent, useNotification } from '../../../../../../hooks'; import { CatalogLayoutProps } from '../CatalogLayout.types'; import { CatalogLayoutMarketplaceItemView, OWN_OFFER } from './CatalogLayoutMarketplaceItemView'; import { MarketplaceOfferData } from './common/MarketplaceOfferData'; @@ -12,6 +12,7 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC = prop { const [ creditsWaiting, setCreditsWaiting ] = useState(0); const [ offers, setOffers ] = useState([]); + const { simpleAlert = null } = useNotification(); const onMarketPlaceOwnOffersEvent = useCallback((event: MarketplaceOwnOffersEvent) => { @@ -42,13 +43,13 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC = prop if(!parser.success) { - NotificationUtilities.simpleAlert(LocalizeText('catalog.marketplace.cancel_failed'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.marketplace.operation_failed.topic')); + simpleAlert(LocalizeText('catalog.marketplace.cancel_failed'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.marketplace.operation_failed.topic')); return; } setOffers(prevValue => prevValue.filter(value => (value.offerId !== parser.offerId))); - }, []); + }, [ simpleAlert ]); useMessageEvent(MarketplaceCancelOfferResultEvent, onMarketplaceCancelOfferResultEvent); diff --git a/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplacePublicItemsView.tsx b/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplacePublicItemsView.tsx index d705f5c9..9f6b6560 100644 --- a/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplacePublicItemsView.tsx +++ b/src/components/catalog/views/page/layout/marketplace/CatalogLayoutMarketplacePublicItemsView.tsx @@ -1,8 +1,8 @@ import { BuyMarketplaceOfferMessageComposer, GetMarketplaceOffersMessageComposer, MarketplaceBuyOfferResultEvent, MarketPlaceOffersEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback, useMemo, useState } from 'react'; -import { LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer } from '../../../../../../api'; +import { LocalizeText, NotificationAlertType, SendMessageComposer } from '../../../../../../api'; import { Button, ButtonGroup, Column, Text } from '../../../../../../common'; -import { useMessageEvent, usePurse } from '../../../../../../hooks'; +import { useMessageEvent, useNotification, usePurse } from '../../../../../../hooks'; import { CatalogLayoutProps } from '../CatalogLayout.types'; import { CatalogLayoutMarketplaceItemView, PUBLIC_OFFER } from './CatalogLayoutMarketplaceItemView'; import { SearchFormView } from './CatalogLayoutMarketplaceSearchFormView'; @@ -25,6 +25,7 @@ export const CatalogLayoutMarketplacePublicItemsView: FC()); const [ lastSearch, setLastSearch ] = useState({ minPrice: -1, maxPrice: -1, query: '', type: 3 }); const { getCurrencyAmount = null } = usePurse(); + const { simpleAlert = null, showConfirm = null } = useNotification(); const requestOffers = useCallback((options: IMarketplaceSearchOptions) => { @@ -50,18 +51,18 @@ export const CatalogLayoutMarketplacePublicItemsView: FC getCurrencyAmount(-1)) { - NotificationUtilities.simpleAlert(LocalizeText('catalog.alert.notenough.credits.description'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.alert.notenough.title')); + simpleAlert(LocalizeText('catalog.alert.notenough.credits.description'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.alert.notenough.title')); return; } const offerId = offerData.offerId; - NotificationUtilities.confirm(LocalizeText('catalog.marketplace.confirm_header'), () => + showConfirm(LocalizeText('catalog.marketplace.confirm_header'), () => { SendMessageComposer(new BuyMarketplaceOfferMessageComposer(offerId)); }, null, null, null, LocalizeText('catalog.marketplace.confirm_title')); - }, [ getCurrencyAmount ]); + }, [ getCurrencyAmount, simpleAlert, showConfirm ]); const onMarketPlaceOffersEvent = useCallback( (event: MarketPlaceOffersEvent) => { @@ -99,7 +100,7 @@ export const CatalogLayoutMarketplacePublicItemsView: FC { SendMessageComposer(new BuyMarketplaceOfferMessageComposer(parser.offerId)); @@ -129,10 +130,10 @@ export const CatalogLayoutMarketplacePublicItemsView: FC = props => { @@ -11,6 +11,7 @@ export const MarketplacePostOfferView : FC<{}> = props => const [ askingPrice, setAskingPrice ] = useState(0); const { catalogOptions = null, setCatalogOptions = null } = useCatalog(); const { marketplaceConfiguration = null } = catalogOptions; + const { showConfirm = null } = useNotification(); const onMarketplaceConfigurationEvent = useCallback((event: MarketplaceConfigurationEvent) => { @@ -58,7 +59,7 @@ export const MarketplacePostOfferView : FC<{}> = props => { if(!item || (askingPrice <= marketplaceConfiguration.minimumPrice)) return; - NotificationUtilities.confirm(LocalizeText('inventory.marketplace.confirm_offer.info', [ 'furniname', 'price' ], [ getFurniTitle, askingPrice.toString() ]), () => + showConfirm(LocalizeText('inventory.marketplace.confirm_offer.info', [ 'furniname', 'price' ], [ getFurniTitle, askingPrice.toString() ]), () => { SendMessageComposer(new MakeOfferMessageComposer(askingPrice, item.isWallItem ? 2 : 1, item.id)); setItem(null); diff --git a/src/components/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx b/src/components/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx index e339ec80..5aa5f96f 100644 --- a/src/components/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx +++ b/src/components/catalog/views/page/layout/vip-gifts/CatalogLayoutVipGiftsView.tsx @@ -1,8 +1,8 @@ import { SelectClubGiftComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; -import { LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../../../api'; +import { LocalizeText, SendMessageComposer } from '../../../../../../api'; import { AutoGrid, Text } from '../../../../../../common'; -import { useCatalog, usePurse } from '../../../../../../hooks'; +import { useCatalog, useNotification, usePurse } from '../../../../../../hooks'; import { CatalogLayoutProps } from '../CatalogLayout.types'; import { VipGiftItem } from './VipGiftItemView'; @@ -11,6 +11,7 @@ export const CatalogLayoutVipGiftsView: FC = props => const { purse = null } = usePurse(); const { catalogOptions = null, setCatalogOptions = null } = useCatalog(); const { clubGifts = null } = catalogOptions; + const { showConfirm = null } = useNotification(); const giftsAvailable = useCallback(() => { @@ -27,7 +28,7 @@ export const CatalogLayoutVipGiftsView: FC = props => const selectGift = useCallback((localizationId: string) => { - NotificationUtilities.confirm(LocalizeText('catalog.club_gift.confirm'), () => + showConfirm(LocalizeText('catalog.club_gift.confirm'), () => { SendMessageComposer(new SelectClubGiftComposer(localizationId)); @@ -38,7 +39,7 @@ export const CatalogLayoutVipGiftsView: FC = props => return { ...prevValue }; }); }, null); - }, [ setCatalogOptions ]); + }, [ setCatalogOptions, showConfirm ]); return ( <> diff --git a/src/components/groups/views/GroupInformationView.tsx b/src/components/groups/views/GroupInformationView.tsx index 6488e31e..ce7469e5 100644 --- a/src/components/groups/views/GroupInformationView.tsx +++ b/src/components/groups/views/GroupInformationView.tsx @@ -1,7 +1,8 @@ import { GroupInformationParser, GroupRemoveMemberComposer } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; -import { CatalogPageName, CreateLinkEvent, GetGroupManager, GetGroupMembers, GetSessionDataManager, GroupMembershipType, GroupType, LocalizeText, NotificationUtilities, SendMessageComposer, TryJoinGroup, TryVisitRoom } from '../../../api'; +import { CatalogPageName, CreateLinkEvent, GetGroupManager, GetGroupMembers, GetSessionDataManager, GroupMembershipType, GroupType, LocalizeText, SendMessageComposer, TryJoinGroup, TryVisitRoom } from '../../../api'; import { Button, Column, Flex, Grid, GridProps, LayoutBadgeImageView, Text } from '../../../common'; +import { useNotification } from '../../../hooks'; const STATES: string[] = [ 'regular', 'exclusive', 'private' ]; @@ -15,6 +16,7 @@ interface GroupInformationViewProps extends GridProps export const GroupInformationView: FC = props => { const { groupInformation = null, onClose = null, overflow = 'hidden', ...rest } = props; + const { showConfirm = null } = useNotification(); const isRealOwner = (groupInformation && (groupInformation.ownerName === GetSessionDataManager().userName)); @@ -22,7 +24,7 @@ export const GroupInformationView: FC = props => const leaveGroup = () => { - NotificationUtilities.confirm(LocalizeText('group.leaveconfirm.desc'), () => + showConfirm(LocalizeText('group.leaveconfirm.desc'), () => { SendMessageComposer(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId)); diff --git a/src/components/groups/views/GroupMembersView.tsx b/src/components/groups/views/GroupMembersView.tsx index 4b937425..ef7241ae 100644 --- a/src/components/groups/views/GroupMembersView.tsx +++ b/src/components/groups/views/GroupMembersView.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { GroupAdminGiveComposer, GroupAdminTakeComposer, GroupConfirmMemberRemoveEvent, GroupConfirmRemoveMemberComposer, GroupMemberParser, GroupMembersComposer, GroupMembersEvent, GroupMembershipAcceptComposer, GroupMembershipDeclineComposer, GroupMembersParser, GroupRank, GroupRemoveMemberComposer, ILinkEventTracker } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; -import { AddEventLinkTracker, GetSessionDataManager, GetUserProfile, LocalizeText, NotificationUtilities, RemoveLinkEventTracker, SendMessageComposer } from '../../../api'; +import { AddEventLinkTracker, GetSessionDataManager, GetUserProfile, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../../api'; import { Base, Button, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common'; -import { useMessageEvent } from '../../../hooks'; +import { useMessageEvent, useNotification } from '../../../hooks'; export const GroupMembersView: FC<{}> = props => { @@ -14,6 +14,7 @@ export const GroupMembersView: FC<{}> = props => const [ totalPages, setTotalPages ] = useState(0); const [ searchQuery, setSearchQuery ] = useState(''); const [ removingMemberName, setRemovingMemberName ] = useState(null); + const { showConfirm = null } = useNotification(); const getRankDescription = (member: GroupMemberParser) => { @@ -87,7 +88,7 @@ export const GroupMembersView: FC<{}> = props => { const parser = event.getParser(); - NotificationUtilities.confirm(LocalizeText(((parser.furnitureCount > 0) ? 'group.kickconfirm.desc' : 'group.kickconfirm_nofurni.desc'), [ 'user', 'amount' ], [ removingMemberName, parser.furnitureCount.toString() ]), () => + showConfirm(LocalizeText(((parser.furnitureCount > 0) ? 'group.kickconfirm.desc' : 'group.kickconfirm_nofurni.desc'), [ 'user', 'amount' ], [ removingMemberName, parser.furnitureCount.toString() ]), () => { SendMessageComposer(new GroupRemoveMemberComposer(membersData.groupId, parser.userId)); @@ -95,7 +96,7 @@ export const GroupMembersView: FC<{}> = props => }, null); setRemovingMemberName(null); - }, [ membersData, removingMemberName, refreshMembers ]); + }, [ membersData, removingMemberName, refreshMembers, showConfirm ]); useMessageEvent(GroupConfirmMemberRemoveEvent, onGroupConfirmMemberRemoveEvent); diff --git a/src/components/groups/views/GroupRoomInformationView.tsx b/src/components/groups/views/GroupRoomInformationView.tsx index 2fea613f..5f7e4433 100644 --- a/src/components/groups/views/GroupRoomInformationView.tsx +++ b/src/components/groups/views/GroupRoomInformationView.tsx @@ -1,15 +1,16 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { DesktopViewEvent, GetGuestRoomResultEvent, GroupInformationComposer, GroupInformationEvent, GroupInformationParser, GroupRemoveMemberComposer, HabboGroupDeactivatedMessageEvent, RoomEntryInfoMessageEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { GetGroupInformation, GetGroupManager, GetSessionDataManager, GroupMembershipType, GroupType, LocalizeText, NotificationUtilities, SendMessageComposer, TryJoinGroup } from '../../../api'; +import { GetGroupInformation, GetGroupManager, GetSessionDataManager, GroupMembershipType, GroupType, LocalizeText, SendMessageComposer, TryJoinGroup } from '../../../api'; import { Base, Button, Column, Flex, LayoutBadgeImageView, Text } from '../../../common'; -import { useMessageEvent } from '../../../hooks'; +import { useMessageEvent, useNotification } from '../../../hooks'; export const GroupRoomInformationView: FC<{}> = props => { const [ expectedGroupId, setExpectedGroupId ] = useState(0); const [ groupInformation, setGroupInformation ] = useState(null); const [ isOpen, setIsOpen ] = useState(true); + const { showConfirm = null } = useNotification(); const onDesktopViewEvent = useCallback((event: DesktopViewEvent) => { @@ -72,7 +73,7 @@ export const GroupRoomInformationView: FC<{}> = props => const leaveGroup = () => { - NotificationUtilities.confirm(LocalizeText('group.leaveconfirm.desc'), () => + showConfirm(LocalizeText('group.leaveconfirm.desc'), () => { SendMessageComposer(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId)); }, null); diff --git a/src/components/groups/views/tabs/GroupTabIdentityView.tsx b/src/components/groups/views/tabs/GroupTabIdentityView.tsx index 6d911791..110d3ef5 100644 --- a/src/components/groups/views/tabs/GroupTabIdentityView.tsx +++ b/src/components/groups/views/tabs/GroupTabIdentityView.tsx @@ -1,7 +1,8 @@ import { GroupDeleteComposer, GroupSaveInformationComposer } from '@nitrots/nitro-renderer'; import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react'; -import { CreateLinkEvent, IGroupData, LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../api'; +import { CreateLinkEvent, IGroupData, LocalizeText, SendMessageComposer } from '../../../../api'; import { Base, Button, Column, Flex, Text } from '../../../../common'; +import { useNotification } from '../../../../hooks'; interface GroupTabIdentityViewProps { @@ -19,12 +20,13 @@ export const GroupTabIdentityView: FC = props => const [ groupName, setGroupName ] = useState(''); const [ groupDescription, setGroupDescription ] = useState(''); const [ groupHomeroomId, setGroupHomeroomId ] = useState(-1); + const { showConfirm = null } = useNotification(); const deleteGroup = () => { if(!groupData || (groupData.groupId <= 0)) return; - NotificationUtilities.confirm(LocalizeText('group.deleteconfirm.desc'), () => + showConfirm(LocalizeText('group.deleteconfirm.desc'), () => { SendMessageComposer(new GroupDeleteComposer(groupData.groupId)); diff --git a/src/components/help/HelpMessageHandler.tsx b/src/components/help/HelpMessageHandler.tsx index 52ec1af7..a72481ce 100644 --- a/src/components/help/HelpMessageHandler.tsx +++ b/src/components/help/HelpMessageHandler.tsx @@ -1,11 +1,13 @@ import { CallForHelpResultMessageEvent, GetPendingCallsForHelpMessageComposer, IssueCloseNotificationMessageEvent } from '@nitrots/nitro-renderer'; -import { FC, useCallback } from 'react'; -import { CallForHelpResult, GetCloseReasonKey, LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer } from '../../api'; -import { useMessageEvent } from '../../hooks'; +import { FC } from 'react'; +import { CallForHelpResult, GetCloseReasonKey, LocalizeText, NotificationAlertType, SendMessageComposer } from '../../api'; +import { useMessageEvent, useNotification } from '../../hooks'; export const HelpMessageHandler: FC<{}> = props => { - const onCallForHelpResultMessageEvent = useCallback((event: CallForHelpResultMessageEvent) => + const { simpleAlert = null } = useNotification(); + + useMessageEvent(CallForHelpResultMessageEvent, event => { const parser = event.getParser(); @@ -15,32 +17,29 @@ export const HelpMessageHandler: FC<{}> = props => { case CallForHelpResult.TOO_MANY_PENDING_CALLS_CODE: SendMessageComposer(new GetPendingCallsForHelpMessageComposer()); - NotificationUtilities.simpleAlert(LocalizeText('help.cfh.error.pending'), NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.error.title')); + simpleAlert(LocalizeText('help.cfh.error.pending'), NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.error.title')); break; case CallForHelpResult.HAS_ABUSIVE_CALL_CODE: - NotificationUtilities.simpleAlert(LocalizeText('help.cfh.error.abusive'), NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.error.title')); + simpleAlert(LocalizeText('help.cfh.error.abusive'), NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.error.title')); break; default: if(message.trim().length === 0) { message = LocalizeText('help.cfh.sent.text'); } - NotificationUtilities.simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.sent.title')); + + simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('help.cfh.sent.title')); } - }, []); + }); - useMessageEvent(CallForHelpResultMessageEvent, onCallForHelpResultMessageEvent); - - const onIssueCloseNotificationMessageEvent = useCallback((event: IssueCloseNotificationMessageEvent) => + useMessageEvent(IssueCloseNotificationMessageEvent, event => { const parser = event.getParser(); const message = parser.messageText.length === 0 ? LocalizeText('help.cfh.closed.' + GetCloseReasonKey(parser.closeReason)) : parser.messageText; - NotificationUtilities.simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('mod.alert.title')); - }, []); - - useMessageEvent(IssueCloseNotificationMessageEvent, onIssueCloseNotificationMessageEvent); + simpleAlert(message, NotificationAlertType.MODERATION, null, null, LocalizeText('mod.alert.title')); + }); return null; } diff --git a/src/components/hotel-view/views/widgets/promo-article/PromoArticleWidgetView.tsx b/src/components/hotel-view/views/widgets/promo-article/PromoArticleWidgetView.tsx index 75b30c85..e434ed25 100644 --- a/src/components/hotel-view/views/widgets/promo-article/PromoArticleWidgetView.tsx +++ b/src/components/hotel-view/views/widgets/promo-article/PromoArticleWidgetView.tsx @@ -1,6 +1,6 @@ import { GetPromoArticlesComposer, PromoArticleData, PromoArticlesMessageEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; -import { LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../../api'; +import { LocalizeText, OpenUrl, SendMessageComposer } from '../../../../../api'; import { useMessageEvent } from '../../../../../hooks'; export const PromoArticleWidgetView: FC<{}> = props => @@ -40,7 +40,7 @@ export const PromoArticleWidgetView: FC<{}> = props =>

{ articles[index].title }

{ articles[index].bodyText } - +
} diff --git a/src/components/hotel-view/views/widgets/widget-container/WidgetContainerView.tsx b/src/components/hotel-view/views/widgets/widget-container/WidgetContainerView.tsx index 5e583562..699d812d 100644 --- a/src/components/hotel-view/views/widgets/widget-container/WidgetContainerView.tsx +++ b/src/components/hotel-view/views/widgets/widget-container/WidgetContainerView.tsx @@ -1,5 +1,5 @@ import { FC, useCallback } from 'react'; -import { GetConfigurationManager, LocalizeText, NotificationUtilities } from '../../../../../api'; +import { GetConfigurationManager, LocalizeText, OpenUrl } from '../../../../../api'; export interface WidgetContainerViewProps { @@ -31,7 +31,7 @@ export const WidgetContainerView: FC = props =>

{ LocalizeText(`landing.view.${ getOption('texts') }.header`) }

{ LocalizeText(`landing.view.${ getOption('texts') }.body`) } - +
); diff --git a/src/components/inventory/views/furniture/InventoryTradeView.tsx b/src/components/inventory/views/furniture/InventoryTradeView.tsx index 2f0a7d0e..3de9eef8 100644 --- a/src/components/inventory/views/furniture/InventoryTradeView.tsx +++ b/src/components/inventory/views/furniture/InventoryTradeView.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IObjectData, TradingListAddItemComposer, TradingListAddItemsComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; -import { FurniCategory, getGuildFurniType, GroupItem, IFurnitureItem, LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer, TradeState } from '../../../../api'; +import { FurniCategory, getGuildFurniType, GroupItem, IFurnitureItem, LocalizeText, NotificationAlertType, SendMessageComposer, TradeState } from '../../../../api'; import { AutoGrid, Base, Button, Column, Flex, Grid, LayoutGridItem, Text } from '../../../../common'; -import { useInventoryTrade } from '../../../../hooks'; +import { useInventoryTrade, useNotification } from '../../../../hooks'; import { InventoryFurnitureSearchView } from './InventoryFurnitureSearchView'; interface InventoryTradeViewProps @@ -22,6 +22,7 @@ export const InventoryTradeView: FC = props => const [ filteredGroupItems, setFilteredGroupItems ] = useState(null); const [ countdownTick, setCountdownTick ] = useState(3); const { ownUser = null, otherUser = null, groupItems = [], tradeState = TradeState.TRADING_STATE_READY, progressTrade = null, removeItem = null, setTradeState = null } = useInventoryTrade(); + const { simpleAlert = null } = useNotification(); const canTradeItem = (isWallItem: boolean, spriteId: number, category: number, groupable: boolean, stuffData: IObjectData) => { @@ -105,7 +106,7 @@ export const InventoryTradeView: FC = props => } else { - NotificationUtilities.simpleAlert(LocalizeText('trading.items.too_many_items.desc'), NotificationAlertType.DEFAULT, null, null, LocalizeText('trading.items.too_many_items.title')); + simpleAlert(LocalizeText('trading.items.too_many_items.desc'), NotificationAlertType.DEFAULT, null, null, LocalizeText('trading.items.too_many_items.title')); } } diff --git a/src/components/loading/LoadingView.tsx b/src/components/loading/LoadingView.tsx index a803e9aa..ee3a0369 100644 --- a/src/components/loading/LoadingView.tsx +++ b/src/components/loading/LoadingView.tsx @@ -1,5 +1,4 @@ -import { FC, useEffect } from 'react'; -import { NotificationUtilities } from '../../api'; +import { FC } from 'react'; import { Base, Column, LayoutProgressBar, Text } from '../../common'; interface LoadingViewProps @@ -12,13 +11,6 @@ interface LoadingViewProps export const LoadingView: FC = props => { const { isError = false, message = '', percent = 0 } = props; - - useEffect(() => - { - if(!isError) return; - - NotificationUtilities.simpleAlert(message, null, null, null, 'Connection Error'); - }, [ isError, message ]); return ( diff --git a/src/components/mod-tools/ModToolsMessageHandler.tsx b/src/components/mod-tools/ModToolsMessageHandler.tsx index fafb9281..d9e76485 100644 --- a/src/components/mod-tools/ModToolsMessageHandler.tsx +++ b/src/components/mod-tools/ModToolsMessageHandler.tsx @@ -1,8 +1,8 @@ import { CfhSanctionMessageEvent, CfhTopicsInitEvent, IssueDeletedMessageEvent, IssueInfoMessageEvent, IssuePickFailedMessageEvent, ModeratorActionResultMessageEvent, ModeratorInitMessageEvent, ModeratorToolPreferencesEvent, RoomEngineEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; -import { NotificationAlertType, NotificationUtilities, PlaySound, SoundNames } from '../../api'; +import { NotificationAlertType, PlaySound, SoundNames } from '../../api'; import { ModToolsEvent, ModToolsOpenRoomChatlogEvent, ModToolsOpenRoomInfoEvent, ModToolsOpenUserChatlogEvent, ModToolsOpenUserInfoEvent } from '../../events'; -import { useMessageEvent, useRoomEngineEvent, useUiEvent } from '../../hooks'; +import { useMessageEvent, useNotification, useRoomEngineEvent, useUiEvent } from '../../hooks'; import { SetCfhCategories } from './common/GetCFHCategories'; import { useModToolsContext } from './ModToolsContext'; import { ModToolsActions } from './reducers/ModToolsReducer'; @@ -11,6 +11,7 @@ export const ModToolsMessageHandler: FC<{}> = props => { const { modToolsState = null, dispatchModToolsState = null } = useModToolsContext(); const { openRooms = null, openRoomChatlogs = null, openUserChatlogs = null, openUserInfo = null, tickets= null } = modToolsState; + const { simpleAlert = null } = useNotification(); const onModeratorInitMessageEvent = useCallback((event: ModeratorInitMessageEvent) => { @@ -78,8 +79,8 @@ export const ModToolsMessageHandler: FC<{}> = props => if(!parser) return; - NotificationUtilities.simpleAlert('Failed to pick issue', NotificationAlertType.DEFAULT, null, null, 'Error') - }, []); + simpleAlert('Failed to pick issue', NotificationAlertType.DEFAULT, null, null, 'Error') + }, [ simpleAlert ]); const onIssueDeletedMessageEvent = useCallback((event: IssueDeletedMessageEvent) => { @@ -110,13 +111,13 @@ export const ModToolsMessageHandler: FC<{}> = props => if(parser.success) { - NotificationUtilities.simpleAlert('Moderation action was successfull', NotificationAlertType.MODERATION, null, null, 'Success'); + simpleAlert('Moderation action was successfull', NotificationAlertType.MODERATION, null, null, 'Success'); } else { - NotificationUtilities.simpleAlert('There was a problem applying tht moderation action', NotificationAlertType.MODERATION, null, null, 'Error'); + simpleAlert('There was a problem applying tht moderation action', NotificationAlertType.MODERATION, null, null, 'Error'); } - }, []); + }, [ simpleAlert ]); const onCfhTopicsInitEvent = useCallback((event: CfhTopicsInitEvent) => { diff --git a/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx b/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx index 91d1f57a..b8235709 100644 --- a/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx +++ b/src/components/mod-tools/views/user/ModToolsUserModActionView.tsx @@ -1,7 +1,8 @@ import { CallForHelpTopicData, DefaultSanctionMessageComposer, ModAlertMessageComposer, ModBanMessageComposer, ModKickMessageComposer, ModMessageMessageComposer, ModMuteMessageComposer, ModTradingLockMessageComposer } from '@nitrots/nitro-renderer'; import { FC, useMemo, useState } from 'react'; -import { LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer } from '../../../../api'; +import { LocalizeText, NotificationAlertType, SendMessageComposer } from '../../../../api'; import { Button, Column, DraggableWindowPosition, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; +import { useNotification } from '../../../../hooks'; import { ISelectedUser } from '../../common/ISelectedUser'; import { ModActionDefinition } from '../../common/ModActionDefinition'; import { useModToolsContext } from '../../ModToolsContext'; @@ -35,6 +36,7 @@ export const ModToolsUserModActionView: FC = pro const [ message, setMessage ] = useState(''); const { modToolsState = null } = useModToolsContext(); const { cfhCategories = null, settings = null } = modToolsState; + const { simpleAlert = null } = useNotification(); const topics = useMemo(() => { @@ -53,7 +55,7 @@ export const ModToolsUserModActionView: FC = pro const sendAlert = (message: string) => { - NotificationUtilities.simpleAlert(message, NotificationAlertType.DEFAULT, null, null, 'Error'); + simpleAlert(message, NotificationAlertType.DEFAULT, null, null, 'Error'); } const sendDefaultSanction = () => diff --git a/src/components/navigator/NavigatorMessageHandler.tsx b/src/components/navigator/NavigatorMessageHandler.tsx index 331ee8f0..6543b5e7 100644 --- a/src/components/navigator/NavigatorMessageHandler.tsx +++ b/src/components/navigator/NavigatorMessageHandler.tsx @@ -1,12 +1,13 @@ import { CanCreateRoomEventEvent, CantConnectMessageParser, DoorbellMessageEvent, FlatAccessDeniedMessageEvent, FlatCreatedEvent, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomMessageComposer, GetGuestRoomResultEvent, GetUserEventCatsMessageComposer, GetUserFlatCatsMessageComposer, HabboWebTools, LegacyExternalInterface, NavigatorHomeRoomEvent, NavigatorMetadataEvent, NavigatorOpenRoomCreatorEvent, NavigatorSearchEvent, RoomDataParser, RoomDoorbellAcceptedEvent, RoomEnterErrorEvent, RoomEntryInfoMessageEvent, RoomForwardEvent, RoomScoreEvent, RoomSettingsUpdatedEvent, SecurityLevel, UserEventCatsEvent, UserFlatCatsEvent, UserInfoEvent, UserPermissionsEvent } from '@nitrots/nitro-renderer'; import { FC, useCallback } from 'react'; -import { CreateLinkEvent, CreateRoomSession, DoorStateType, GetConfiguration, GetSessionDataManager, LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer, TryVisitRoom, VisitDesktop } from '../../api'; -import { useMessageEvent } from '../../hooks'; +import { CreateLinkEvent, CreateRoomSession, DoorStateType, GetConfiguration, GetSessionDataManager, LocalizeText, NotificationAlertType, SendMessageComposer, TryVisitRoom, VisitDesktop } from '../../api'; +import { useMessageEvent, useNotification } from '../../hooks'; import { useNavigatorContext } from './NavigatorContext'; export const NavigatorMessageHandler: FC<{}> = props => { const { setCategories = null, setEventCategories = null, setTopLevelContext = null, topLevelContexts = null, setTopLevelContexts = null, setNavigatorData = null, setDoorData = null, setSearchResult = null } = useNavigatorContext(); + const { simpleAlert = null } = useNotification(); const onRoomSettingsUpdatedEvent = useCallback((event: RoomSettingsUpdatedEvent) => { @@ -28,8 +29,8 @@ export const NavigatorMessageHandler: FC<{}> = props => return; } - NotificationUtilities.simpleAlert(LocalizeText(`navigator.cannotcreateevent.error.${ parser.errorCode }`), null, null, null, LocalizeText('navigator.cannotcreateevent.title')); - }, []); + simpleAlert(LocalizeText(`navigator.cannotcreateevent.error.${ parser.errorCode }`), null, null, null, LocalizeText('navigator.cannotcreateevent.title')); + }, [ simpleAlert ]); useMessageEvent(CanCreateRoomEventEvent, onCanCreateRoomEventEvent); @@ -249,23 +250,23 @@ export const NavigatorMessageHandler: FC<{}> = props => }); return; case 4009: - NotificationUtilities.simpleAlert(LocalizeText('navigator.alert.need.to.be.vip'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title')); + 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')); + 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')); + 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')); + simpleAlert(LocalizeText('navigator.alert.room_in_maintenance'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title')); return; } - }, [ setDoorData ]); + }, [ setDoorData, simpleAlert ]); const onNavigatorMetadataEvent = useCallback((event: NavigatorMetadataEvent) => { @@ -397,25 +398,25 @@ export const NavigatorMessageHandler: FC<{}> = props => switch(parser.reason) { case CantConnectMessageParser.REASON_FULL: - NotificationUtilities.simpleAlert(LocalizeText('navigator.guestroomfull.text'), NotificationAlertType.DEFAULT, null, null, LocalizeText('navigator.guestroomfull.title')); + simpleAlert(LocalizeText('navigator.guestroomfull.text'), NotificationAlertType.DEFAULT, null, null, LocalizeText('navigator.guestroomfull.title')); break; case CantConnectMessageParser.REASON_QUEUE_ERROR: - NotificationUtilities.simpleAlert(LocalizeText(`room.queue.error.${ parser.parameter }`), NotificationAlertType.DEFAULT, null, null, LocalizeText('room.queue.error.title')); + simpleAlert(LocalizeText(`room.queue.error.${ parser.parameter }`), NotificationAlertType.DEFAULT, null, null, LocalizeText('room.queue.error.title')); break; case CantConnectMessageParser.REASON_BANNED: - NotificationUtilities.simpleAlert(LocalizeText('navigator.banned.text'), NotificationAlertType.DEFAULT, null, null, LocalizeText('navigator.banned.title')); + simpleAlert(LocalizeText('navigator.banned.text'), NotificationAlertType.DEFAULT, null, null, LocalizeText('navigator.banned.title')); break; default: - NotificationUtilities.simpleAlert(LocalizeText('room.queue.error.title'), NotificationAlertType.DEFAULT, null, null, LocalizeText('room.queue.error.title')); + simpleAlert(LocalizeText('room.queue.error.title'), NotificationAlertType.DEFAULT, null, null, LocalizeText('room.queue.error.title')); break; } VisitDesktop(); - }, []); + }, [ simpleAlert ]); const onRoomCreatorEvent = useCallback((event: NavigatorOpenRoomCreatorEvent) => { diff --git a/src/components/navigator/views/room-settings/NavigatorRoomSettingsBasicTabView.tsx b/src/components/navigator/views/room-settings/NavigatorRoomSettingsBasicTabView.tsx index 09175dea..8fb0d876 100644 --- a/src/components/navigator/views/room-settings/NavigatorRoomSettingsBasicTabView.tsx +++ b/src/components/navigator/views/room-settings/NavigatorRoomSettingsBasicTabView.tsx @@ -1,8 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { RoomDeleteComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect, useState } from 'react'; -import { CreateLinkEvent, GetMaxVisitorsList, IRoomData, LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../api'; +import { CreateLinkEvent, GetMaxVisitorsList, IRoomData, LocalizeText, SendMessageComposer } from '../../../../api'; import { Base, Column, Flex, Text } from '../../../../common'; +import { useNotification } from '../../../../hooks'; import { useNavigatorContext } from '../../NavigatorContext'; const ROOM_NAME_MIN_LENGTH = 3; @@ -22,11 +23,12 @@ export const NavigatorRoomSettingsBasicTabView: FC(''); const [ roomDescription, setRoomDescription ] = useState(''); + const { showConfirm = null } = useNotification(); const { categories = null } = useNavigatorContext(); const deleteRoom = () => { - NotificationUtilities.confirm(LocalizeText('navigator.roomsettings.deleteroom.confirm.message', [ 'room_name' ], [ roomData.roomName ] ), () => + showConfirm(LocalizeText('navigator.roomsettings.deleteroom.confirm.message', [ 'room_name' ], [ roomData.roomName ] ), () => { SendMessageComposer(new RoomDeleteComposer(roomData.roomId)); diff --git a/src/components/nitropedia/NitropediaView.tsx b/src/components/nitropedia/NitropediaView.tsx index f325fe47..788e2208 100644 --- a/src/components/nitropedia/NitropediaView.tsx +++ b/src/components/nitropedia/NitropediaView.tsx @@ -1,6 +1,6 @@ import { NitroLogger } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { AddEventLinkTracker, GetConfiguration, NotificationUtilities, RemoveLinkEventTracker } from '../../api'; +import { AddEventLinkTracker, GetConfiguration, OpenUrl, RemoveLinkEventTracker } from '../../api'; import { Base, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common'; const NEW_LINE_REGEX = /\n\r|\n|\r/mg; @@ -80,7 +80,7 @@ export const NitropediaView: FC<{}> = props => if(!link || !link.length) return; - NotificationUtilities.openUrl(link); + OpenUrl(link); } document.addEventListener('click', handle); diff --git a/src/components/notification-center/NotificationCenterMessageHandler.tsx b/src/components/notification-center/NotificationCenterMessageHandler.tsx deleted file mode 100644 index a5db8eeb..00000000 --- a/src/components/notification-center/NotificationCenterMessageHandler.tsx +++ /dev/null @@ -1,215 +0,0 @@ -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 { GetConfiguration, GetRoomEngine, GetSessionDataManager, LocalizeBadgeName, LocalizeText, NotificationBubbleType, NotificationUtilities, ProductImageUtility } from '../../api'; -import { useMessageEvent } from '../../hooks'; - -export const NotificationCenterMessageHandler: FC<{}> = props => -{ - const onRespectReceivedEvent = useCallback((event: RespectReceivedEvent) => - { - const parser = event.getParser(); - - if(parser.userId !== GetSessionDataManager().userId) return; - - const text1 = LocalizeText('notifications.text.respect.1'); - const text2 = LocalizeText('notifications.text.respect.2', [ 'count' ], [ parser.respectsReceived.toString() ]); - - NotificationUtilities.showSingleBubble(text1, NotificationBubbleType.RESPECT); - NotificationUtilities.showSingleBubble(text2, NotificationBubbleType.RESPECT); - }, []); - - useMessageEvent(RespectReceivedEvent, onRespectReceivedEvent); - - const onHabboBroadcastMessageEvent = useCallback((event: HabboBroadcastMessageEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.simpleAlert(parser.message.replace(/\\r/g, '\r'), null, null, LocalizeText('notifications.broadcast.title')); - }, []); - - useMessageEvent(HabboBroadcastMessageEvent, onHabboBroadcastMessageEvent); - - const onAchievementNotificationMessageEvent = useCallback((event: AchievementNotificationMessageEvent) => - { - const parser = event.getParser(); - - const text1 = LocalizeText('achievements.levelup.desc'); - const badgeName = LocalizeBadgeName(parser.data.badgeCode); - const badgeImage = GetSessionDataManager().getBadgeUrl(parser.data.badgeCode); - const internalLink = 'questengine/achievements/' + parser.data.category; - - NotificationUtilities.showSingleBubble((text1 + ' ' + badgeName), NotificationBubbleType.ACHIEVEMENT, badgeImage, internalLink); - }, []); - - useMessageEvent(AchievementNotificationMessageEvent, onAchievementNotificationMessageEvent); - - const onClubGiftNotificationEvent = useCallback((event: ClubGiftNotificationEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.showClubGiftNotification(parser.numGifts); - }, []); - - useMessageEvent(ClubGiftNotificationEvent, onClubGiftNotificationEvent); - - const onModeratorMessageEvent = useCallback((event: ModeratorMessageEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.handleModeratorMessage(parser.message, parser.url); - }, []); - - useMessageEvent(ModeratorMessageEvent, onModeratorMessageEvent); - - const onActivityPointNotificationMessageEvent = useCallback((event: ActivityPointNotificationMessageEvent) => - { - const parser = event.getParser(); - - if((parser.amountChanged <= 0) || (parser.type !== 5)) return; - - const imageUrl = GetConfiguration('currency.asset.icon.url', '').replace('%type%', parser.type.toString()); - - NotificationUtilities.showSingleBubble(LocalizeText('notifications.text.loyalty.received', [ 'AMOUNT' ], [ parser.amountChanged.toString() ]), NotificationBubbleType.INFO, imageUrl); - }, []); - - useMessageEvent(ActivityPointNotificationMessageEvent, onActivityPointNotificationMessageEvent); - - const onUserBannedMessageEvent = useCallback((event: UserBannedMessageEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.handleUserBannedMessage(parser.message); - }, []); - - useMessageEvent(UserBannedMessageEvent, onUserBannedMessageEvent); - - const onHotelClosesAndWillOpenAtEvent = useCallback((event: HotelClosesAndWillOpenAtEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.handleHotelClosedMessage(parser.openHour, parser.openMinute, parser.userThrowOutAtClose); - }, []); - - useMessageEvent(HotelClosesAndWillOpenAtEvent, onHotelClosesAndWillOpenAtEvent); - - const onPetReceivedMessageEvent = useCallback((event: PetReceivedMessageEvent) => - { - const parser = event.getParser(); - - const text = LocalizeText('notifications.text.' + (parser.boughtAsGift ? 'petbought' : 'petreceived')); - - let imageUrl: string = null; - - const imageResult = GetRoomEngine().getRoomObjectPetImage(parser.pet.typeId, parser.pet.paletteId, parseInt(parser.pet.color, 16), new Vector3d(45 * 3), 64, null, true); - - if(imageResult) imageUrl = imageResult.getImage().src; - - NotificationUtilities.showSingleBubble(text, NotificationBubbleType.PETLEVEL, imageUrl); - }, []); - - useMessageEvent(PetReceivedMessageEvent, onPetReceivedMessageEvent); - - const onRoomEnterEvent = useCallback((event: RoomEnterEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.showModerationDisclaimer(); - }, []); - - useMessageEvent(RoomEnterEvent, onRoomEnterEvent); - - const onMOTDNotificationEvent = useCallback((event: MOTDNotificationEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.handleMOTD(parser.messages); - }, []); - - useMessageEvent(MOTDNotificationEvent, onMOTDNotificationEvent); - - const onPetLevelNotificationEvent = useCallback((event: PetLevelNotificationEvent) => - { - const parser = event.getParser(); - - let imageUrl: string = null; - - 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); - }, []); - - useMessageEvent(PetLevelNotificationEvent, onPetLevelNotificationEvent); - - const onInfoFeedEnableMessageEvent = useCallback((event: InfoFeedEnableMessageEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.BUBBLES_DISABLED = !(parser.enabled); - }, []); - - useMessageEvent(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)) - }, []); - - useMessageEvent(ClubGiftSelectedEvent, onClubGiftSelectedEvent); - - const onMaintenanceStatusMessageEvent = useCallback((event: MaintenanceStatusMessageEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.handleHotelMaintenanceMessage(parser.minutesUntilMaintenance, parser.duration); - }, []); - - useMessageEvent(MaintenanceStatusMessageEvent, onMaintenanceStatusMessageEvent); - - const onModeratorCautionEvent = useCallback((event: ModeratorCautionEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.handleModeratorCaution(parser.message, parser.url); - }, []); - - useMessageEvent(ModeratorCautionEvent, onModeratorCautionEvent); - - const onNotificationDialogMessageEvent = useCallback((event: NotificationDialogMessageEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.showNotification(parser.type, parser.parameters); - }, []); - - useMessageEvent(NotificationDialogMessageEvent, onNotificationDialogMessageEvent); - - const onHotelWillCloseInMinutesEvent = useCallback((event: HotelWillCloseInMinutesEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.handleHotelClosingMessage(parser.openMinute); - }, []); - - useMessageEvent(HotelWillCloseInMinutesEvent, onHotelWillCloseInMinutesEvent); - - const onHotelClosedAndOpensEvent = useCallback((event: HotelClosedAndOpensEvent) => - { - const parser = event.getParser(); - - NotificationUtilities.handleLoginFailedHotelClosedMessage(parser.openHour, parser.openMinute); - }, []); - - useMessageEvent(HotelClosedAndOpensEvent, onHotelClosedAndOpensEvent); - - return null; -} diff --git a/src/components/notification-center/NotificationCenterView.tsx b/src/components/notification-center/NotificationCenterView.tsx index a546836a..1817b09c 100644 --- a/src/components/notification-center/NotificationCenterView.tsx +++ b/src/components/notification-center/NotificationCenterView.tsx @@ -1,84 +1,14 @@ -import { FC, ReactNode, useCallback, useMemo, useState } from 'react'; -import { NotificationAlertItem, NotificationBubbleItem, NotificationBubbleType, NotificationConfirmItem } from '../../api'; +import { FC, ReactNode, useMemo } from 'react'; +import { NotificationBubbleType } from '../../api'; import { Column } from '../../common'; -import { NotificationAlertEvent, NotificationBubbleEvent, NotificationConfirmEvent } from '../../events'; -import { useUiEvent } from '../../hooks'; -import { NotificationCenterMessageHandler } from './NotificationCenterMessageHandler'; +import { useNotification } from '../../hooks'; import { GetAlertLayout } from './views/alert-layouts/GetAlertLayout'; import { GetBubbleLayout } from './views/bubble-layouts/GetBubbleLayout'; import { GetConfirmLayout } from './views/confirm-layouts/GetConfirmLayout'; export const NotificationCenterView: FC<{}> = props => { - const [ alerts, setAlerts ] = useState([]); - const [ bubbleAlerts, setBubbleAlerts ] = useState([]); - const [ confirms, setConfirms ] = useState([]); - - const onNotificationAlertEvent = useCallback((event: NotificationAlertEvent) => - { - const alertItem = new NotificationAlertItem(event.messages, event.alertType, event.clickUrl, event.clickUrlText, event.title, event.imageUrl); - - setAlerts(prevValue => [ alertItem, ...prevValue ]); - }, []); - - useUiEvent(NotificationAlertEvent.ALERT, onNotificationAlertEvent); - - const onNotificationBubbleEvent = useCallback((event: NotificationBubbleEvent) => - { - const notificationItem = new NotificationBubbleItem(event.message, event.notificationType, event.imageUrl, event.linkUrl); - - setBubbleAlerts(prevValue => [ notificationItem, ...prevValue ]); - }, []); - - useUiEvent(NotificationBubbleEvent.NEW_BUBBLE, onNotificationBubbleEvent); - - const onNotificationConfirmEvent = useCallback((event: NotificationConfirmEvent) => - { - const confirmItem = new NotificationConfirmItem(event.type, event.message, event.onConfirm, event.onCancel, event.confirmText, event.cancelText, event.title); - - setConfirms(prevValue => [ confirmItem, ...prevValue ]); - }, []); - - useUiEvent(NotificationConfirmEvent.CONFIRM, onNotificationConfirmEvent); - - const closeAlert = useCallback((alert: NotificationAlertItem) => - { - setAlerts(prevValue => - { - const newAlerts = [ ...prevValue ]; - const index = newAlerts.findIndex(value => (alert === value)); - - if(index >= 0) newAlerts.splice(index, 1); - - return newAlerts; - }); - }, []); - - const closeBubbleAlert = useCallback((item: NotificationBubbleItem) => - { - setBubbleAlerts(prevValue => - { - const newAlerts = [ ...prevValue ]; - const index = newAlerts.findIndex(value => (item === value)); - - if(index >= 0) newAlerts.splice(index, 1); - - return newAlerts; - }) - }, []); - - const closeConfirm = useCallback((item: NotificationConfirmItem) => - { - setConfirms(prevValue => - { - const newConfirms = [ ...prevValue ]; - const index = newConfirms.findIndex(value => (item === value)); - - if(index >= 0) newConfirms.splice(index, 1); - - return newConfirms; - }) - }, []); + const { alerts = [], bubbleAlerts = [], confirms = [], closeAlert = null, closeBubbleAlert = null, closeConfirm = null } = useNotification(); const getAlerts = useMemo(() => { @@ -137,7 +67,6 @@ export const NotificationCenterView: FC<{}> = props => return ( <> - { getBubbleAlerts } diff --git a/src/components/notification-center/views/alert-layouts/NotificationDefaultAlertView.tsx b/src/components/notification-center/views/alert-layouts/NotificationDefaultAlertView.tsx index f6970ea6..73ba2ee0 100644 --- a/src/components/notification-center/views/alert-layouts/NotificationDefaultAlertView.tsx +++ b/src/components/notification-center/views/alert-layouts/NotificationDefaultAlertView.tsx @@ -1,5 +1,5 @@ import { FC, useCallback, useState } from 'react'; -import { LocalizeText, NotificationAlertItem, NotificationAlertType, NotificationUtilities } from '../../../../api'; +import { LocalizeText, NotificationAlertItem, NotificationAlertType, OpenUrl } from '../../../../api'; import { Base, Button, Column, Flex, LayoutNotificationAlertView, LayoutNotificationAlertViewProps } from '../../../../common'; interface NotificationDefaultAlertViewProps extends LayoutNotificationAlertViewProps @@ -15,7 +15,7 @@ export const NotificationDefaultAlertView: FC const visitUrl = useCallback(() => { - NotificationUtilities.openUrl(item.clickUrl); + OpenUrl(item.clickUrl); close(); }, [ item, close ]); diff --git a/src/components/notification-center/views/alert-layouts/NotificationSearchAlertView.tsx b/src/components/notification-center/views/alert-layouts/NotificationSearchAlertView.tsx index ccd19c1c..273a6aa6 100644 --- a/src/components/notification-center/views/alert-layouts/NotificationSearchAlertView.tsx +++ b/src/components/notification-center/views/alert-layouts/NotificationSearchAlertView.tsx @@ -1,5 +1,5 @@ import { FC, useCallback, useEffect, useState } from 'react'; -import { LocalizeText, NotificationAlertItem, NotificationUtilities } from '../../../../api'; +import { LocalizeText, NotificationAlertItem, OpenUrl } from '../../../../api'; import { AutoGrid, Button, Column, Flex, LayoutNotificationAlertView, LayoutNotificationAlertViewProps } from '../../../../common'; interface NotificationDefaultAlertViewProps extends LayoutNotificationAlertViewProps @@ -16,7 +16,7 @@ export const NotificationSeachAlertView: FC = const visitUrl = useCallback(() => { - NotificationUtilities.openUrl(item.clickUrl); + OpenUrl(item.clickUrl); close(); }, [ item, close ]); diff --git a/src/components/notification-center/views/bubble-layouts/NotificationClubGiftBubbleView.tsx b/src/components/notification-center/views/bubble-layouts/NotificationClubGiftBubbleView.tsx index 21955844..c5bb304d 100644 --- a/src/components/notification-center/views/bubble-layouts/NotificationClubGiftBubbleView.tsx +++ b/src/components/notification-center/views/bubble-layouts/NotificationClubGiftBubbleView.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { LocalizeText, NotificationBubbleItem, NotificationUtilities } from '../../../../api'; +import { LocalizeText, NotificationBubbleItem, OpenUrl } from '../../../../api'; import { LayoutCurrencyIcon, LayoutNotificationBubbleView, LayoutNotificationBubbleViewProps } from '../../../../common'; export interface NotificationClubGiftBubbleViewProps extends LayoutNotificationBubbleViewProps @@ -18,7 +18,7 @@ export const NotificationClubGiftBubbleView: FC{ LocalizeText('notifications.text.club_gift') }
- + { LocalizeText('notifications.button.later') }
diff --git a/src/components/notification-center/views/bubble-layouts/NotificationDefaultBubbleView.tsx b/src/components/notification-center/views/bubble-layouts/NotificationDefaultBubbleView.tsx index cfa7d2ef..76041b45 100644 --- a/src/components/notification-center/views/bubble-layouts/NotificationDefaultBubbleView.tsx +++ b/src/components/notification-center/views/bubble-layouts/NotificationDefaultBubbleView.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { NotificationBubbleItem, NotificationUtilities } from '../../../../api'; +import { NotificationBubbleItem, OpenUrl } from '../../../../api'; import { Flex, LayoutNotificationBubbleView, LayoutNotificationBubbleViewProps, Text } from '../../../../common'; export interface NotificationDefaultBubbleViewProps extends LayoutNotificationBubbleViewProps @@ -14,7 +14,7 @@ export const NotificationDefaultBubbleView: FC'); return ( - (item.linkUrl && item.linkUrl.length && NotificationUtilities.openUrl(item.linkUrl)) } { ...rest }> + (item.linkUrl && item.linkUrl.length && OpenUrl(item.linkUrl)) } { ...rest }> { (item.iconUrl && item.iconUrl.length) && } diff --git a/src/components/room/widgets/RoomWidgetsView.tsx b/src/components/room/widgets/RoomWidgetsView.tsx index b0962486..83cbb190 100644 --- a/src/components/room/widgets/RoomWidgetsView.tsx +++ b/src/components/room/widgets/RoomWidgetsView.tsx @@ -1,7 +1,7 @@ import { RoomEngineObjectEvent, RoomEngineRoomAdEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomId, RoomSessionErrorMessageEvent, RoomZoomEvent } from '@nitrots/nitro-renderer'; import { FC } from 'react'; -import { DispatchUiEvent, GetRoomEngine, LocalizeText, NotificationAlertType, NotificationUtilities, RoomWidgetUpdateRoomObjectEvent } from '../../../api'; -import { useRoom, useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks'; +import { DispatchUiEvent, GetRoomEngine, LocalizeText, NotificationAlertType, RoomWidgetUpdateRoomObjectEvent } from '../../../api'; +import { useNotification, useRoom, useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks'; import { AvatarInfoWidgetView } from './avatar-info/AvatarInfoWidgetView'; import { ChatInputView } from './chat-input/ChatInputView'; import { ChatWidgetView } from './chat/ChatWidgetView'; @@ -17,6 +17,7 @@ import { WordQuizWidgetView } from './word-quiz/WordQuizWidgetView'; export const RoomWidgetsView: FC<{}> = props => { const { roomSession = null } = useRoom(); + const { simpleAlert = null } = useNotification(); useRoomEngineEvent(RoomZoomEvent.ROOM_ZOOM, event => GetRoomEngine().setRoomInstanceRenderingCanvasScale(event.roomId, 1, event.level, null, null, false, event.asDelta)); @@ -146,7 +147,7 @@ export const RoomWidgetsView: FC<{}> = props => return; } - NotificationUtilities.simpleAlert(errorMessage, NotificationAlertType.DEFAULT, null, null, errorTitle); + simpleAlert(errorMessage, NotificationAlertType.DEFAULT, null, null, errorTitle); }); return ( diff --git a/src/hooks/catalog/useCatalog.ts b/src/hooks/catalog/useCatalog.ts index 16b844ba..49e549c1 100644 --- a/src/hooks/catalog/useCatalog.ts +++ b/src/hooks/catalog/useCatalog.ts @@ -1,9 +1,10 @@ import { BuildersClubFurniCountMessageEvent, BuildersClubPlaceRoomItemMessageComposer, BuildersClubPlaceWallItemMessageComposer, BuildersClubQueryFurniCountMessageComposer, BuildersClubSubscriptionStatusMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, ClubGiftInfoEvent, FrontPageItem, FurniturePlaceComposer, FurniturePlacePaintComposer, GetCatalogIndexComposer, GetCatalogPageComposer, GetClubGiftInfo, GetGiftWrappingConfigurationComposer, GiftWrappingConfigurationEvent, GuildMembershipsMessageEvent, HabboClubOffersMessageEvent, LegacyDataType, LimitedEditionSoldOutEvent, MarketplaceMakeOfferResult, NodeData, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseFromCatalogComposer, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, RoomControllerLevel, RoomEngineObjectPlacedEvent, RoomObjectCategory, RoomObjectPlacementSource, RoomObjectType, RoomObjectVariable, RoomPreviewer, SellablePetPalettesMessageEvent, Vector3d } from '@nitrots/nitro-renderer'; import { useCallback, useEffect, useRef, useState } from 'react'; import { useBetween } from 'use-between'; -import { BuilderFurniPlaceableStatus, CatalogNode, CatalogPage, CatalogPetPalette, CatalogType, CreateLinkEvent, DispatchUiEvent, FurniCategory, GetFurnitureData, GetNitroInstance, GetProductDataForLocalization, GetRoomEngine, GetRoomSession, GiftWrappingConfiguration, ICatalogNode, ICatalogOptions, ICatalogPage, IPageLocalization, IProduct, IPurchasableOffer, IPurchaseOptions, LocalizeText, NotificationAlertType, NotificationUtilities, Offer, PageLocalization, PlacedObjectPurchaseData, PlaySound, Product, ProductTypeEnum, RequestedPage, SearchResult, SendMessageComposer, SoundNames } from '../../api'; +import { BuilderFurniPlaceableStatus, CatalogNode, CatalogPage, CatalogPetPalette, CatalogType, CreateLinkEvent, DispatchUiEvent, FurniCategory, GetFurnitureData, GetNitroInstance, GetProductDataForLocalization, GetRoomEngine, GetRoomSession, GiftWrappingConfiguration, ICatalogNode, ICatalogOptions, ICatalogPage, IPageLocalization, IProduct, IPurchasableOffer, IPurchaseOptions, LocalizeText, NotificationAlertType, Offer, PageLocalization, PlacedObjectPurchaseData, PlaySound, Product, ProductTypeEnum, RequestedPage, SearchResult, SendMessageComposer, SoundNames } from '../../api'; import { CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent, InventoryFurniAddedEvent } from '../../events'; import { useMessageEvent, useRoomEngineEvent, useUiEvent } from '../events'; +import { useNotification } from '../notification'; import { useCatalogPlaceMultipleItems } from './useCatalogPlaceMultipleItems'; import { useCatalogSkipPurchaseConfirmation } from './useCatalogSkipPurchaseConfirmation'; @@ -39,6 +40,7 @@ const useCatalogState = () => const [ secondsLeft, setSecondsLeft ] = useState(0); const [ updateTime, setUpdateTime ] = useState(0); const [ secondsLeftWithGrace, setSecondsLeftWithGrace ] = useState(0); + const { simpleAlert = null } = useNotification(); const requestedPage = useRef(new RequestedPage()); const resetState = useCallback(() => @@ -657,8 +659,8 @@ const useCatalogState = () => const message = LocalizeText(`inventory.marketplace.result.${ parser.result }`); - NotificationUtilities.simpleAlert(message, NotificationAlertType.DEFAULT, null, null, title); - }, []); + simpleAlert(message, NotificationAlertType.DEFAULT, null, null, title); + }, [ simpleAlert ]); useMessageEvent(MarketplaceMakeOfferResult, onMarketplaceMakeOfferResult); @@ -682,8 +684,8 @@ const useCatalogState = () => resetState(); - if(wasVisible) NotificationUtilities.simpleAlert(LocalizeText('catalog.alert.published.description'), NotificationAlertType.ALERT, null, null, LocalizeText('catalog.alert.published.title')); - }, [ isVisible, resetState ]); + if(wasVisible) simpleAlert(LocalizeText('catalog.alert.published.description'), NotificationAlertType.ALERT, null, null, LocalizeText('catalog.alert.published.title')); + }, [ isVisible, resetState, simpleAlert ]); useMessageEvent(CatalogPublishedMessageEvent, onCatalogPublishedMessageEvent); diff --git a/src/hooks/friends/useMessenger.ts b/src/hooks/friends/useMessenger.ts index c3458307..71a9675b 100644 --- a/src/hooks/friends/useMessenger.ts +++ b/src/hooks/friends/useMessenger.ts @@ -1,8 +1,9 @@ import { NewConsoleMessageEvent, RoomInviteErrorEvent, RoomInviteEvent, SendMessageComposer as SendMessageComposerPacket } from '@nitrots/nitro-renderer'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useBetween } from 'use-between'; -import { CloneObject, GetSessionDataManager, LocalizeText, MessengerIconState, MessengerThread, MessengerThreadChat, NotificationAlertType, NotificationUtilities, PlaySound, SendMessageComposer, SoundNames } from '../../api'; +import { CloneObject, GetSessionDataManager, LocalizeText, MessengerIconState, MessengerThread, MessengerThreadChat, NotificationAlertType, PlaySound, SendMessageComposer, SoundNames } from '../../api'; import { useMessageEvent } from '../events'; +import { useNotification } from '../notification'; import { useFriends } from './useFriends'; const useMessengerState = () => @@ -12,6 +13,7 @@ const useMessengerState = () => const [ hiddenThreadIds, setHiddenThreadIds ] = useState([]); const [ iconState, setIconState ] = useState(MessengerIconState.HIDDEN); const { getFriend = null } = useFriends(); + const { simpleAlert = null } = useNotification(); const visibleThreads = useMemo(() => messageThreads.filter(thread => (hiddenThreadIds.indexOf(thread.threadId) === -1)), [ messageThreads, hiddenThreadIds ]); const activeThread = useMemo(() => ((activeThreadId > 0) && visibleThreads.find(thread => (thread.threadId === activeThreadId) || null)), [ activeThreadId, visibleThreads ]); @@ -94,7 +96,7 @@ const useMessengerState = () => }); } - const onNewConsoleMessageEvent = useCallback((event: NewConsoleMessageEvent) => + useMessageEvent(NewConsoleMessageEvent, event => { const parser = event.getParser(); @@ -131,11 +133,9 @@ const useMessengerState = () => return newValue; }); - }, [ activeThreadId, getFriend ]); + }); - useMessageEvent(NewConsoleMessageEvent, onNewConsoleMessageEvent); - - const onRoomInviteEvent = useCallback((event: RoomInviteEvent) => + useMessageEvent(RoomInviteEvent, event => { const parser = event.getParser(); @@ -172,19 +172,15 @@ const useMessengerState = () => return newValue; }); - }, [ activeThreadId, getFriend ]); + }); - useMessageEvent(RoomInviteEvent, onRoomInviteEvent); - - const onRoomInviteErrorEvent = useCallback((event: RoomInviteErrorEvent) => + useMessageEvent(RoomInviteErrorEvent, event => { const parser = event.getParser(); const message = ((('Received room invite error: errorCode: ' + parser.errorCode) + ', recipients: ') + parser.failedRecipients); - NotificationUtilities.simpleAlert(message, NotificationAlertType.DEFAULT, null, null, LocalizeText('friendlist.alert.title')); - }, []); - - useMessageEvent(RoomInviteErrorEvent, onRoomInviteErrorEvent); + simpleAlert(message, NotificationAlertType.DEFAULT, null, null, LocalizeText('friendlist.alert.title')); + }); useEffect(() => { diff --git a/src/hooks/index.ts b/src/hooks/index.ts index e28adade..e2289c33 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -9,6 +9,7 @@ export * from './friends'; export * from './groups'; export * from './inventory'; export * from './navigator'; +export * from './notification'; export * from './purse'; export * from './rooms'; export * from './session'; diff --git a/src/hooks/inventory/useInventoryTrade.ts b/src/hooks/inventory/useInventoryTrade.ts index 005d2984..7eb7481f 100644 --- a/src/hooks/inventory/useInventoryTrade.ts +++ b/src/hooks/inventory/useInventoryTrade.ts @@ -1,8 +1,9 @@ import { AdvancedMap, TradingAcceptComposer, TradingAcceptEvent, TradingCancelComposer, TradingCloseComposer, TradingCloseEvent, TradingCloseParser, TradingCompletedEvent, TradingConfirmationComposer, TradingConfirmationEvent, TradingListItemEvent, TradingListItemRemoveComposer, TradingNotOpenEvent, TradingOpenEvent, TradingOpenFailedEvent, TradingOtherNotAllowedEvent, TradingUnacceptComposer, TradingYouAreNotAllowedEvent } from '@nitrots/nitro-renderer'; import { useEffect, useState } from 'react'; import { useBetween } from 'use-between'; -import { CloneObject, GetRoomSession, GetSessionDataManager, GroupItem, LocalizeText, NotificationUtilities, parseTradeItems, SendMessageComposer, TradeState, TradeUserData, TradingNotificationMessage, TradingNotificationType } from '../../api'; +import { CloneObject, GetRoomSession, GetSessionDataManager, GroupItem, LocalizeText, parseTradeItems, SendMessageComposer, TradeState, TradeUserData, TradingNotificationType } from '../../api'; import { useMessageEvent } from '../events'; +import { useNotification } from '../notification'; import { useInventoryFurni } from './useInventoryFurni'; const useInventoryTradeState = () => @@ -11,6 +12,7 @@ const useInventoryTradeState = () => const [ otherUser, setOtherUser ] = useState(null); const [ tradeState, setTradeState ] = useState(TradeState.TRADING_STATE_READY); const { groupItems = [], setGroupItems = null, activate = null, deactivate = null } = useInventoryFurni(); + const { simpleAlert = null, showTradeAlert = null } = useNotification(); const isTrading = (tradeState >= TradeState.TRADING_STATE_RUNNING); const progressTrade = () => @@ -20,7 +22,7 @@ const useInventoryTradeState = () => case TradeState.TRADING_STATE_RUNNING: if(!otherUser.itemCount && !ownUser.accepts) { - NotificationUtilities.simpleAlert(LocalizeText('inventory.trading.warning.other_not_offering'), null, null, null); + simpleAlert(LocalizeText('inventory.trading.warning.other_not_offering'), null, null, null); } if(ownUser.accepts) @@ -101,13 +103,13 @@ const useInventoryTradeState = () => if(parser.reason === TradingCloseParser.ERROR_WHILE_COMMIT) { - TradingNotificationMessage(TradingNotificationType.ERROR_WHILE_COMMIT); + showTradeAlert(TradingNotificationType.ERROR_WHILE_COMMIT); } else { if(ownUser && (parser.userID !== ownUser.userId)) { - TradingNotificationMessage(TradingNotificationType.THEY_CANCELLED); + showTradeAlert(TradingNotificationType.THEY_CANCELLED); } } @@ -254,21 +256,21 @@ const useInventoryTradeState = () => { const parser = event.getParser(); - TradingNotificationMessage(parser.reason, parser.otherUserName); + showTradeAlert(parser.reason, parser.otherUserName); }); useMessageEvent(TradingOtherNotAllowedEvent, event => { const parser = event.getParser(); - TradingNotificationMessage(TradingNotificationType.THEY_NOT_ALLOWED); + showTradeAlert(TradingNotificationType.THEY_NOT_ALLOWED); }); useMessageEvent(TradingYouAreNotAllowedEvent, event => { const parser = event.getParser(); - TradingNotificationMessage(TradingNotificationType.YOU_NOT_ALLOWED); + showTradeAlert(TradingNotificationType.YOU_NOT_ALLOWED); }); useEffect(() => diff --git a/src/hooks/notification/index.ts b/src/hooks/notification/index.ts new file mode 100644 index 00000000..b5a85616 --- /dev/null +++ b/src/hooks/notification/index.ts @@ -0,0 +1 @@ +export * from './useNotification'; diff --git a/src/hooks/notification/useNotification.ts b/src/hooks/notification/useNotification.ts new file mode 100644 index 00000000..aaf07cbf --- /dev/null +++ b/src/hooks/notification/useNotification.ts @@ -0,0 +1,386 @@ +import { AchievementNotificationMessageEvent, ActivityPointNotificationMessageEvent, ClubGiftNotificationEvent, ClubGiftSelectedEvent, HabboBroadcastMessageEvent, HotelClosedAndOpensEvent, HotelClosesAndWillOpenAtEvent, HotelWillCloseInMinutesEvent, InfoFeedEnableMessageEvent, MaintenanceStatusMessageEvent, ModeratorCautionEvent, ModeratorMessageEvent, MOTDNotificationEvent, NotificationDialogMessageEvent, PetLevelNotificationEvent, PetReceivedMessageEvent, RespectReceivedEvent, RoomEnterEffect, RoomEnterEvent, UserBannedMessageEvent, Vector3d } from '@nitrots/nitro-renderer'; +import { useCallback, useState } from 'react'; +import { useBetween } from 'use-between'; +import { GetConfiguration, GetNitroInstance, GetRoomEngine, GetSessionDataManager, LocalizeBadgeName, LocalizeText, NotificationAlertItem, NotificationAlertType, NotificationBubbleItem, NotificationBubbleType, NotificationConfirmItem, PlaySound, ProductImageUtility, TradingNotificationType } from '../../api'; +import { useMessageEvent } from '../events'; + +const cleanText = (text: string) => text.replace(/\\r/g, '\r'); + +const getTimeZeroPadded = (time: number) => +{ + const text = ('0' + time); + + return text.substr((text.length - 2), text.length); +} + +let modDisclaimerTimeout: ReturnType = null; + +const useNotificationState = () => +{ + const [ alerts, setAlerts ] = useState([]); + const [ bubbleAlerts, setBubbleAlerts ] = useState([]); + const [ confirms, setConfirms ] = useState([]); + const [ bubblesDisabled, setBubblesDisabled ] = useState(false); + const [ modDisclaimerShown, setModDisclaimerShown ] = useState(false); + + const getMainNotificationConfig = () => GetConfiguration<{ [key: string]: { delivery?: string, display?: string; title?: string; image?: string }}>('notification', {}); + + const getNotificationConfig = (key: string) => + { + const mainConfig = getMainNotificationConfig(); + + if(!mainConfig) return null; + + return mainConfig[key]; + } + + const getNotificationPart = (options: Map, type: string, key: string, localize: boolean) => + { + if(options.has(key)) return options.get(key); + + const localizeKey = [ 'notification', type, key ].join('.'); + + if(GetNitroInstance().localization.hasValue(localizeKey) || localize) return LocalizeText(localizeKey, Array.from(options.keys()), Array.from(options.values())); + + return null; + } + + const getNotificationImageUrl = (options: Map, type: string) => + { + let imageUrl = options.get('image'); + + if(!imageUrl) imageUrl = GetConfiguration('image.library.notifications.url', '').replace('%image%', type.replace(/\./g, '_')); + + return LocalizeText(imageUrl); + } + + const simpleAlert = useCallback((message: string, type: string = null, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null) => + { + if(!title || !title.length) title = LocalizeText('notifications.broadcast.title'); + + if(!type || !type.length) type = NotificationAlertType.DEFAULT; + + const alertItem = new NotificationAlertItem([ cleanText(message) ], type, clickUrl, clickUrlText, title, imageUrl); + + setAlerts(prevValue => [ alertItem, ...prevValue ]); + }, []); + + const showNitroAlert = useCallback(() => simpleAlert(null, NotificationAlertType.NITRO), [ simpleAlert ]); + + const showSingleBubble = useCallback((message: string, type: string, imageUrl: string = null, internalLink: string = null) => + { + if(bubblesDisabled) return; + + const notificationItem = new NotificationBubbleItem(message, type, imageUrl, internalLink); + + setBubbleAlerts(prevValue => [ notificationItem, ...prevValue ]); + }, [ bubblesDisabled ]); + + const showNotification = (type: string, options: Map = null) => + { + if(!options) options = new Map(); + + const configuration = getNotificationConfig(('notification.' + type)); + + if(configuration) for(const key in configuration) options.set(key, configuration[key]); + + const title = getNotificationPart(options, type, 'title', true); + const message = getNotificationPart(options, type, 'message', true).replace(/\\r/g, '\r'); + const linkTitle = getNotificationPart(options, type, 'linkTitle', false); + const linkUrl = getNotificationPart(options, type, 'linkUrl', false); + const image = getNotificationImageUrl(options, type); + + if(options.get('display') === 'BUBBLE') + { + showSingleBubble(LocalizeText(message), NotificationBubbleType.INFO, image, linkUrl); + } + else + { + simpleAlert(message, type, linkUrl, linkTitle, title, image); + } + + if(options.get('sound')) PlaySound(options.get('sound')); + } + + const showConfirm = useCallback((message: string, onConfirm: () => void, onCancel: () => void, confirmText: string = null, cancelText: string = null, title: string = null, type: string = null) => + { + if(!confirmText || !confirmText.length) confirmText = LocalizeText('generic.confirm'); + + if(!cancelText || !cancelText.length) cancelText = LocalizeText('generic.cancel'); + + if(!title || !title.length) title = LocalizeText('notifications.broadcast.title'); + + const confirmItem = new NotificationConfirmItem(type, message, onConfirm, onCancel, confirmText, cancelText, title); + + setConfirms(prevValue => [ confirmItem, ...prevValue ]); + }, []); + + const showModeratorMessage = (message: string, url: string = null, showHabboWay: boolean = true) => + { + simpleAlert(message, NotificationAlertType.DEFAULT, url, LocalizeText('mod.alert.link'), LocalizeText('mod.alert.title')); + } + + const showTradeAlert = useCallback((type: number, otherUsername: string = '') => + { + switch(type) + { + case TradingNotificationType.ALERT_SCAM: + simpleAlert(LocalizeText('inventory.trading.warning.other_not_offering'), null, null, null, LocalizeText('inventory.trading.notification.title')); + return; + case TradingNotificationType.HOTEL_TRADING_DISABLED: + case TradingNotificationType.YOU_NOT_ALLOWED: + case TradingNotificationType.THEY_NOT_ALLOWED: + case TradingNotificationType.ROOM_DISABLED: + case TradingNotificationType.YOU_OPEN: + case TradingNotificationType.THEY_OPEN: + simpleAlert(LocalizeText(`inventory.trading.openfail.${ type }`, [ 'otherusername' ], [ otherUsername ]), null, null, null, LocalizeText('inventory.trading.openfail.title')); + return; + case TradingNotificationType.ERROR_WHILE_COMMIT: + simpleAlert(`${ LocalizeText('inventory.trading.notification.caption') }, ${ LocalizeText('inventory.trading.notification.commiterror.info') }`, null, null, null, LocalizeText('inventory.trading.notification.title')); + return; + case TradingNotificationType.THEY_CANCELLED: + simpleAlert(LocalizeText('inventory.trading.info.closed'), null, null, null, LocalizeText('inventory.trading.notification.title')); + return; + } + }, [ simpleAlert ]); + + const closeAlert = useCallback((alert: NotificationAlertItem) => + { + setAlerts(prevValue => + { + const newAlerts = [ ...prevValue ]; + const index = newAlerts.findIndex(value => (alert === value)); + + if(index >= 0) newAlerts.splice(index, 1); + + return newAlerts; + }); + }, []); + + const closeBubbleAlert = useCallback((item: NotificationBubbleItem) => + { + setBubbleAlerts(prevValue => + { + const newAlerts = [ ...prevValue ]; + const index = newAlerts.findIndex(value => (item === value)); + + if(index >= 0) newAlerts.splice(index, 1); + + return newAlerts; + }) + }, []); + + const closeConfirm = useCallback((item: NotificationConfirmItem) => + { + setConfirms(prevValue => + { + const newConfirms = [ ...prevValue ]; + const index = newConfirms.findIndex(value => (item === value)); + + if(index >= 0) newConfirms.splice(index, 1); + + return newConfirms; + }) + }, []); + + useMessageEvent(RespectReceivedEvent, event => + { + const parser = event.getParser(); + + if(parser.userId !== GetSessionDataManager().userId) return; + + const text1 = LocalizeText('notifications.text.respect.1'); + const text2 = LocalizeText('notifications.text.respect.2', [ 'count' ], [ parser.respectsReceived.toString() ]); + + showSingleBubble(text1, NotificationBubbleType.RESPECT); + showSingleBubble(text2, NotificationBubbleType.RESPECT); + }); + + useMessageEvent(HabboBroadcastMessageEvent, event => + { + const parser = event.getParser(); + + simpleAlert(parser.message.replace(/\\r/g, '\r'), null, null, LocalizeText('notifications.broadcast.title')); + }); + + useMessageEvent(AchievementNotificationMessageEvent, event => + { + const parser = event.getParser(); + + const text1 = LocalizeText('achievements.levelup.desc'); + const badgeName = LocalizeBadgeName(parser.data.badgeCode); + const badgeImage = GetSessionDataManager().getBadgeUrl(parser.data.badgeCode); + const internalLink = 'questengine/achievements/' + parser.data.category; + + showSingleBubble((text1 + ' ' + badgeName), NotificationBubbleType.ACHIEVEMENT, badgeImage, internalLink); + }); + + useMessageEvent(ClubGiftNotificationEvent, event => + { + const parser = event.getParser(); + + if(parser.numGifts <= 0) return; + + showSingleBubble(parser.numGifts.toString(), NotificationBubbleType.CLUBGIFT, null, ('catalog/open/' + GetConfiguration('catalog.links')['hc.hc_gifts'])); + }); + + useMessageEvent(ModeratorMessageEvent, event => + { + const parser = event.getParser(); + + showModeratorMessage(parser.message, parser.url, false); + }); + + useMessageEvent(ActivityPointNotificationMessageEvent, event => + { + const parser = event.getParser(); + + if((parser.amountChanged <= 0) || (parser.type !== 5)) return; + + const imageUrl = GetConfiguration('currency.asset.icon.url', '').replace('%type%', parser.type.toString()); + + showSingleBubble(LocalizeText('notifications.text.loyalty.received', [ 'AMOUNT' ], [ parser.amountChanged.toString() ]), NotificationBubbleType.INFO, imageUrl); + }); + + useMessageEvent(UserBannedMessageEvent, event => + { + const parser = event.getParser(); + + showModeratorMessage(parser.message); + }); + + useMessageEvent(HotelClosesAndWillOpenAtEvent, event => + { + const parser = event.getParser(); + + simpleAlert( LocalizeText(('opening.hours.' + (parser.userThrowOutAtClose ? 'disconnected' : 'closed')), [ 'h', 'm' ], [ getTimeZeroPadded(parser.openHour), getTimeZeroPadded(parser.openMinute) ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title')); + }); + + useMessageEvent(PetReceivedMessageEvent, event => + { + const parser = event.getParser(); + + const text = LocalizeText('notifications.text.' + (parser.boughtAsGift ? 'petbought' : 'petreceived')); + + let imageUrl: string = null; + + const imageResult = GetRoomEngine().getRoomObjectPetImage(parser.pet.typeId, parser.pet.paletteId, parseInt(parser.pet.color, 16), new Vector3d(45 * 3), 64, null, true); + + if(imageResult) imageUrl = imageResult.getImage().src; + + showSingleBubble(text, NotificationBubbleType.PETLEVEL, imageUrl); + }); + + useMessageEvent(MOTDNotificationEvent, event => + { + const parser = event.getParser(); + + const messages = parser.messages.map(message => cleanText(message)); + + const alertItem = new NotificationAlertItem(messages, NotificationAlertType.MOTD, null, null, LocalizeText('notifications.motd.title')); + + setAlerts(prevValue => [ alertItem, ...prevValue ]); + }); + + useMessageEvent(PetLevelNotificationEvent, event => + { + const parser = event.getParser(); + + let imageUrl: string = null; + + 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; + + showSingleBubble(LocalizeText('notifications.text.petlevel', [ 'pet_name', 'level' ], [ parser.petName, parser.level.toString() ]), NotificationBubbleType.PETLEVEL, imageUrl); + }); + + useMessageEvent(InfoFeedEnableMessageEvent, event => + { + const parser = event.getParser(); + + setBubblesDisabled(!parser.enabled); + }); + + useMessageEvent(ClubGiftSelectedEvent, event => + { + const parser = event.getParser(); + + if(!parser.products || !parser.products.length) return; + + const productData = parser.products[0]; + + if(!productData) return; + + showSingleBubble(LocalizeText('notifications.text.club_gift.selected'), NotificationBubbleType.INFO, ProductImageUtility.getProductImageUrl(productData.productType, productData.furniClassId, productData.extraParam)); + }); + + useMessageEvent(MaintenanceStatusMessageEvent, event => + { + const parser = event.getParser(); + + simpleAlert(LocalizeText('maintenance.shutdown', [ 'm', 'd' ], [ parser.minutesUntilMaintenance.toString(), parser.duration.toString() ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title')); + }); + + useMessageEvent(ModeratorCautionEvent, event => + { + const parser = event.getParser(); + + showModeratorMessage(parser.message, parser.url); + }); + + useMessageEvent(NotificationDialogMessageEvent, event => + { + const parser = event.getParser(); + + showNotification(parser.type, parser.parameters); + }); + + useMessageEvent(HotelWillCloseInMinutesEvent, event => + { + const parser = event.getParser(); + + simpleAlert(LocalizeText('opening.hours.shutdown', [ 'm' ], [ parser.openMinute.toString() ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title')); + }); + + useMessageEvent(HotelClosedAndOpensEvent, event => + { + const parser = event.getParser(); + + simpleAlert(LocalizeText('opening.hours.disconnected', [ 'h', 'm' ], [ parser.openHour.toString(), parser.openMinute.toString() ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title')); + }); + + const onRoomEnterEvent = useCallback(() => + { + if(modDisclaimerShown) return; + + if(RoomEnterEffect.isRunning()) + { + if(modDisclaimerTimeout) return; + + modDisclaimerTimeout = setTimeout(() => + { + onRoomEnterEvent(); + }, (RoomEnterEffect.totalRunningTime + 5000)); + } + else + { + if(modDisclaimerTimeout) + { + clearTimeout(modDisclaimerTimeout); + + modDisclaimerTimeout = null; + } + + showSingleBubble(LocalizeText('mod.chatdisclaimer'), NotificationBubbleType.INFO); + + setModDisclaimerShown(true); + } + }, [ modDisclaimerShown, showSingleBubble ]); + + useMessageEvent(RoomEnterEvent, onRoomEnterEvent); + + return { alerts, bubbleAlerts, confirms, simpleAlert, showNitroAlert, showTradeAlert, showConfirm, closeAlert, closeBubbleAlert, closeConfirm }; +} + +export const useNotification = () => useBetween(useNotificationState); diff --git a/src/hooks/rooms/widgets/furniture/useFurnitureBadgeDisplayWidget.ts b/src/hooks/rooms/widgets/furniture/useFurnitureBadgeDisplayWidget.ts index 38e918ab..c8fb0185 100644 --- a/src/hooks/rooms/widgets/furniture/useFurnitureBadgeDisplayWidget.ts +++ b/src/hooks/rooms/widgets/furniture/useFurnitureBadgeDisplayWidget.ts @@ -1,7 +1,8 @@ import { RoomEngineTriggerWidgetEvent, RoomObjectVariable, StringDataType } from '@nitrots/nitro-renderer'; import { useState } from 'react'; -import { GetRoomEngine, GetSessionDataManager, LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText, NotificationUtilities } from '../../../../api'; +import { GetRoomEngine, GetSessionDataManager, LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../../../api'; import { useRoomEngineEvent } from '../../../events'; +import { useNotification } from '../../../notification'; import { useFurniRemovedEvent } from '../../engine'; const useFurnitureBadgeDisplayWidgetState = () => @@ -13,6 +14,7 @@ const useFurnitureBadgeDisplayWidgetState = () => const [ badgeDesc, setBadgeDesc ] = useState(''); const [ date, setDate ] = useState(''); const [ senderName, setSenderName ] = useState(''); + const { simpleAlert = null } = useNotification(); const close = () => { @@ -57,7 +59,7 @@ const useFurnitureBadgeDisplayWidgetState = () => if(ownerId !== GetSessionDataManager().userId) return; - NotificationUtilities.simpleAlert(`${ LocalizeText('resolution.failed.subtitle') } ${ LocalizeText('resolution.failed.text') }`, null, null, null, LocalizeText('resolution.failed.title')); + simpleAlert(`${ LocalizeText('resolution.failed.subtitle') } ${ LocalizeText('resolution.failed.text') }`, null, null, null, LocalizeText('resolution.failed.title')); }); useFurniRemovedEvent(((objectId !== -1) && (category !== -1)), event => diff --git a/src/hooks/rooms/widgets/useChatInputWidget.ts b/src/hooks/rooms/widgets/useChatInputWidget.ts index 51761d43..e79af288 100644 --- a/src/hooks/rooms/widgets/useChatInputWidget.ts +++ b/src/hooks/rooms/widgets/useChatInputWidget.ts @@ -1,7 +1,8 @@ import { AvatarExpressionEnum, HabboClubLevelEnum, RoomControllerLevel, RoomEngineObjectEvent, RoomObjectCategory, RoomRotatingEffect, RoomSessionChatEvent, RoomSettingsComposer, RoomShakingEffect, RoomZoomEvent, TextureUtils } from '@nitrots/nitro-renderer'; import { useEffect, useState } from 'react'; -import { ChatMessageTypeEnum, CreateLinkEvent, GetClubMemberLevel, GetConfiguration, GetNitroInstance, GetRoomEngine, GetSessionDataManager, LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../api'; +import { ChatMessageTypeEnum, CreateLinkEvent, GetClubMemberLevel, GetConfiguration, GetNitroInstance, GetRoomEngine, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../api'; import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../events'; +import { useNotification } from '../../notification'; import { useObjectSelectedEvent } from '../engine'; import { useRoom } from '../useRoom'; @@ -13,6 +14,7 @@ const useChatInputWidgetState = () => const [ isIdle, setIsIdle ] = useState(false); const [ floodBlocked, setFloodBlocked ] = useState(false); const [ floodBlockedSeconds, setFloodBlockedSeconds ] = useState(0); + const { showNitroAlert = null, showConfirm = null } = useNotification(); const { roomSession = null } = useRoom(); const sendChat = (text: string, chatType: number, recipientName: string = '', styleId: number = 0) => @@ -122,7 +124,7 @@ const useChatInputWidgetState = () => case ':pickall': if(roomSession.isRoomOwner || GetSessionDataManager().isModerator) { - NotificationUtilities.confirm(LocalizeText('room.confirm.pick_all'), () => + showConfirm(LocalizeText('room.confirm.pick_all'), () => { GetSessionDataManager().sendSpecialCommandMessage(':pickall'); }, @@ -150,7 +152,7 @@ const useChatInputWidgetState = () => case ':client': case ':nitro': case ':billsonnn': - NotificationUtilities.showNitroAlert(); + showNitroAlert(); return null; case ':settings': if(roomSession.isRoomOwner || GetSessionDataManager().isModerator) diff --git a/src/hooks/wired/useWired.ts b/src/hooks/wired/useWired.ts index ae3e983a..c7c43ace 100644 --- a/src/hooks/wired/useWired.ts +++ b/src/hooks/wired/useWired.ts @@ -1,9 +1,10 @@ import { ConditionDefinition, Triggerable, TriggerDefinition, UpdateActionMessageComposer, UpdateConditionMessageComposer, UpdateTriggerMessageComposer, WiredActionDefinition, WiredFurniActionEvent, WiredFurniConditionEvent, WiredFurniTriggerEvent, WiredSaveSuccessEvent } from '@nitrots/nitro-renderer'; import { useEffect, useState } from 'react'; import { useBetween } from 'use-between'; -import { IsOwnerOfFloorFurniture, LocalizeText, NotificationUtilities, SendMessageComposer, WiredSelectionVisualizer } from '../../api'; +import { IsOwnerOfFloorFurniture, LocalizeText, SendMessageComposer, WiredSelectionVisualizer } from '../../api'; import { WiredSelectObjectEvent } from '../../events'; import { useMessageEvent, useUiEvent } from '../events'; +import { useNotification } from '../notification'; const useWiredState = () => { @@ -12,6 +13,7 @@ const useWiredState = () => const [ stringParam, setStringParam ] = useState(''); const [ furniIds, setFurniIds ] = useState([]); const [ actionDelay, setActionDelay ] = useState(0); + const { showConfirm = null } = useNotification(); const saveWired = () => { @@ -37,7 +39,7 @@ const useWiredState = () => if(!IsOwnerOfFloorFurniture(trigger.id)) { - NotificationUtilities.confirm(LocalizeText('wiredfurni.nonowner.change.confirm.body'), () => + showConfirm(LocalizeText('wiredfurni.nonowner.change.confirm.body'), () => { save(trigger) }, null, null, null, LocalizeText('wiredfurni.nonowner.change.confirm.title'));