diff --git a/src/components/room/widgets/furniture/FurnitureRentableSpaceView.tsx b/src/components/room/widgets/furniture/FurnitureRentableSpaceView.tsx
new file mode 100644
index 00000000..bc073929
--- /dev/null
+++ b/src/components/room/widgets/furniture/FurnitureRentableSpaceView.tsx
@@ -0,0 +1,43 @@
+import { FriendlyTime } from '@nitrots/nitro-renderer';
+import { FC } from 'react';
+import { LocalizeText } from '../../../../api';
+import { Button, Column, Flex, LayoutCurrencyIcon, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
+import { useFurnitureRentableSpaceWidget } from '../../../../hooks';
+
+export const FurnitureRentableSpaceView: FC<{}> = props =>
+{
+ const { renter, isRoomOwner, onRent, onCancelRent, onClose } = useFurnitureRentableSpaceWidget();
+
+ if(!renter) return null;
+
+ return (
+
+
+
+
+ { (!renter.rented) &&
+ <>
+ { LocalizeText('rentablespace.widget.instructions') }
+
+ { renter.price + ' x' }
+
+ { LocalizeText('catalog.purchase_confirmation.rent') }
+
+ >
+ }
+ { (renter.rented) &&
+ <>
+ { LocalizeText('rentablespace.widget.rented_to_label') }
+ { renter.renterName }
+ { LocalizeText('rentablespace.widget.expires_label') }
+ { FriendlyTime.shortFormat(renter.timeRemaining) }
+ { (isRoomOwner) &&
+ }
+
+ >
+ }
+
+
+
+ );
+}
diff --git a/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx b/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx
index d0e4066d..9354c894 100644
--- a/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx
+++ b/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx
@@ -1,6 +1,5 @@
import { FC } from 'react';
import { Base } from '../../../../common';
-import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView';
import { FurnitureBackgroundColorView } from './FurnitureBackgroundColorView';
import { FurnitureBadgeDisplayView } from './FurnitureBadgeDisplayView';
import { FurnitureCraftingView } from './FurnitureCraftingView';
@@ -12,12 +11,14 @@ import { FurnitureGiftOpeningView } from './FurnitureGiftOpeningView';
import { FurnitureHighScoreView } from './FurnitureHighScoreView';
import { FurnitureInternalLinkView } from './FurnitureInternalLinkView';
import { FurnitureMannequinView } from './FurnitureMannequinView';
+import { FurnitureRentableSpaceView } from './FurnitureRentableSpaceView';
import { FurnitureRoomLinkView } from './FurnitureRoomLinkView';
import { FurnitureSpamWallPostItView } from './FurnitureSpamWallPostItView';
import { FurnitureStackHeightView } from './FurnitureStackHeightView';
import { FurnitureStickieView } from './FurnitureStickieView';
import { FurnitureTrophyView } from './FurnitureTrophyView';
import { FurnitureYoutubeDisplayView } from './FurnitureYoutubeDisplayView';
+import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView';
import { FurniturePlaylistEditorWidgetView } from './playlist-editor/FurniturePlaylistEditorWidgetView';
export const FurnitureWidgetsView: FC<{}> = props =>
@@ -43,6 +44,7 @@ export const FurnitureWidgetsView: FC<{}> = props =>
+
);
}
diff --git a/src/hooks/rooms/widgets/furniture/index.ts b/src/hooks/rooms/widgets/furniture/index.ts
index 37fa5732..7f5946f9 100644
--- a/src/hooks/rooms/widgets/furniture/index.ts
+++ b/src/hooks/rooms/widgets/furniture/index.ts
@@ -11,6 +11,7 @@ export * from './useFurnitureInternalLinkWidget';
export * from './useFurnitureMannequinWidget';
export * from './useFurniturePlaylistEditorWidget';
export * from './useFurniturePresentWidget';
+export * from './useFurnitureRentableSpaceWidget';
export * from './useFurnitureRoomLinkWidget';
export * from './useFurnitureSpamWallPostItWidget';
export * from './useFurnitureStackHeightWidget';
diff --git a/src/hooks/rooms/widgets/furniture/useFurnitureRentableSpaceWidget.ts b/src/hooks/rooms/widgets/furniture/useFurnitureRentableSpaceWidget.ts
new file mode 100644
index 00000000..54a9747a
--- /dev/null
+++ b/src/hooks/rooms/widgets/furniture/useFurnitureRentableSpaceWidget.ts
@@ -0,0 +1,116 @@
+import { RentableSpaceCancelRentMessageComposer, RentableSpaceRentMessageComposer, RentableSpaceStatusMessageEvent, RentableSpaceStatusMessageParser, RoomEngineTriggerWidgetEvent, RoomWidgetEnum } from '@nitrots/nitro-renderer';
+import { useState } from 'react';
+import { GetRoomEngine, GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../api';
+import { useMessageEvent, useRoomEngineEvent } from '../../../events';
+import { useNavigator } from '../../../navigator';
+import { useNotification } from '../../../notification';
+import { useFurniRemovedEvent } from '../../engine';
+
+const useFurnitureRentableSpaceWidgetState = () =>
+{
+ const [ renter, setRenter ] = useState(null);
+ const [ itemId, setItemId ] = useState(-1);
+ const [ category, setCategory ] = useState(-1);
+ const { navigatorData = null } = useNavigator();
+ const { simpleAlert } = useNotification();
+
+ const isRoomOwner = GetSessionDataManager().userName === navigatorData.enteredGuestRoom.ownerName;
+
+ const onClose = () =>
+ {
+ setItemId(-1);
+ setCategory(-1);
+ setRenter(null);
+ }
+
+ const onRent = () =>
+ {
+ if (!itemId) return;
+
+ SendMessageComposer(new RentableSpaceRentMessageComposer(itemId));
+ }
+
+ const onCancelRent = () =>
+ {
+ if (!itemId) return;
+
+ SendMessageComposer(new RentableSpaceCancelRentMessageComposer(itemId));
+ onClose();
+ }
+
+ const getRentErrorCode = (code: number) =>
+ {
+ let errorAlert = '';
+
+ switch(code)
+ {
+ case RentableSpaceStatusMessageParser.SPACE_ALREADY_RENTED:
+ errorAlert = LocalizeText('rentablespace.widget.error_reason_already_rented');
+ break;
+ case RentableSpaceStatusMessageParser.SPACE_EXTEND_NOT_RENTED:
+ errorAlert = LocalizeText('rentablespace.widget.error_reason_not_rented');
+ break;
+ case RentableSpaceStatusMessageParser.SPACE_EXTEND_NOT_RENTED_BY_YOU:
+ errorAlert = LocalizeText('rentablespace.widget.error_reason_not_rented_by_you');
+ break;
+ case RentableSpaceStatusMessageParser.CAN_RENT_ONLY_ONE_SPACE:
+ errorAlert = LocalizeText('rentablespace.widget.error_reason_can_rent_only_one_space');
+ break;
+ case RentableSpaceStatusMessageParser.NOT_ENOUGH_CREDITS:
+ errorAlert = LocalizeText('rentablespace.widget.error_reason_not_enough_credits');
+ break;
+ case RentableSpaceStatusMessageParser.NOT_ENOUGH_PIXELS:
+ errorAlert = LocalizeText('rentablespace.widget.error_reason_not_enough_duckets');
+ break;
+ case RentableSpaceStatusMessageParser.CANT_RENT_NO_PERMISSION:
+ errorAlert = LocalizeText('rentablespace.widget.error_reason_no_permission');
+ break;
+ case RentableSpaceStatusMessageParser.CANT_RENT_NO_HABBO_CLUB:
+ errorAlert = LocalizeText('rentablespace.widget.error_reason_no_habboclub');
+ break;
+ case RentableSpaceStatusMessageParser.CANT_RENT:
+ errorAlert = LocalizeText('rentablespace.widget.error_reason_disabled');
+ break;
+ case RentableSpaceStatusMessageParser.CANT_RENT_GENERIC:
+ errorAlert = LocalizeText('rentablespace.widget.error_reason_generic');
+ break;
+ }
+
+ onClose();
+ return simpleAlert(errorAlert);
+ }
+
+ useRoomEngineEvent(RoomEngineTriggerWidgetEvent.OPEN_WIDGET, event =>
+ {
+ if (event.widget !== RoomWidgetEnum.RENTABLESPACE) return;
+
+ const roomObject = GetRoomEngine().getRoomObject(event.roomId, event.objectId, event.category);
+
+ if(!roomObject) return;
+
+ setItemId(roomObject.id);
+ setCategory(event.category);
+ });
+
+ useFurniRemovedEvent(((itemId !== -1) && (category !== -1)), event =>
+ {
+ if((event.id !== itemId) || (event.category !== category)) return;
+
+ onCancelRent();
+ });
+
+ useMessageEvent(RentableSpaceStatusMessageEvent, event =>
+ {
+ const parser = event.getParser();
+
+ if (!parser) return;
+
+ if (parser.canRentErrorCode !== 0 && (!isRoomOwner || !GetSessionDataManager().isModerator) || (parser.renterName === '' && parser.canRentErrorCode !== 0)) return getRentErrorCode(parser.canRentErrorCode);
+
+ setRenter(parser);
+ });
+
+ return { renter, isRoomOwner, onRent, onCancelRent, onClose };
+}
+
+export const useFurnitureRentableSpaceWidget = useFurnitureRentableSpaceWidgetState;