diff --git a/public/ui-config.json.example b/public/ui-config.json.example index 6b3a26c6..d8ae0939 100644 --- a/public/ui-config.json.example +++ b/public/ui-config.json.example @@ -11,6 +11,7 @@ "chat.viewer.height.percentage": 0.40, "widget.dimmer.colorwheel": false, "avatar.wardrobe.max.slots": 10, + "user.badges.max.slots": 5, "hotelview": { "widgets": { "slot.1.widget": "promoarticle", diff --git a/src/App.scss b/src/App.scss index 27afe7cb..225da1b0 100644 --- a/src/App.scss +++ b/src/App.scss @@ -32,7 +32,7 @@ $inventory-height: 320px; $navigator-width: 400px; $navigator-height: 420px; -$chat-input-style-selector-widget-width: 200px; +$chat-input-style-selector-widget-width: 210px; $chat-input-style-selector-widget-height: 200px; $user-profile-width: 560px; @@ -75,6 +75,9 @@ $nitro-mod-tools-width: 175px; $nitro-group-manager-width: 375px; $nitro-group-manager-height: 355px; +$nitro-chooser-width: 200px; +$nitro-chooser-height: 200px; + .nitro-app { width: 100%; height: 100%; diff --git a/src/assets/styles/utils.scss b/src/assets/styles/utils.scss index 029f054e..c1a3be5b 100644 --- a/src/assets/styles/utils.scss +++ b/src/assets/styles/utils.scss @@ -97,3 +97,24 @@ ul { background-color: $table-striped-bg; } } + +@keyframes bounceIn { + 0% { + opacity: 0; + transform: scale(.3); + } + 50% { + opacity: 1; + transform: scale(1.1); + } + 70% { + transform: scale(.9); + } + 100% { + transform: scale(1); + } +} + +.btn { + pointer-events: all; +} diff --git a/src/common/Base.tsx b/src/common/Base.tsx index f5fd00fe..f31ac413 100644 --- a/src/common/Base.tsx +++ b/src/common/Base.tsx @@ -13,13 +13,14 @@ export interface BaseProps extends DetailedHTMLProps> = props => { - const { ref = null, innerRef = null, fit = false, grow = false, shrink = false, fullWidth = false, fullHeight = false, overflow = null, position = null, float = null, pointer = false, textColor = null, classNames = [], className = '', style = {}, ...rest } = props; + const { ref = null, innerRef = null, fit = false, grow = false, shrink = false, fullWidth = false, fullHeight = false, overflow = null, position = null, float = null, pointer = false, visible = null, textColor = null, classNames = [], className = '', style = {}, ...rest } = props; const getClassNames = useMemo(() => { @@ -41,12 +42,14 @@ export const Base: FC> = props => if(pointer) newClassNames.push('cursor-pointer'); + if(visible !== null) newClassNames.push(visible ? 'visible' : 'invisible'); + if(textColor) newClassNames.push('text-' + textColor); if(classNames.length) newClassNames.push(...classNames); return newClassNames; - }, [ fit, grow, shrink, fullWidth, fullHeight, overflow, position, float, pointer, textColor, classNames ]); + }, [ fit, grow, shrink, fullWidth, fullHeight, overflow, position, float, pointer, visible, textColor, classNames ]); const getClassName = useMemo(() => { diff --git a/src/common/Grid.tsx b/src/common/Grid.tsx index ed59d47a..860a89ca 100644 --- a/src/common/Grid.tsx +++ b/src/common/Grid.tsx @@ -1,5 +1,4 @@ -import { FC, useMemo } from 'react'; -import { CSSProperties } from 'styled-components'; +import { CSSProperties, FC, useMemo } from 'react'; import { Base, BaseProps } from './Base'; import { GridContextProvider } from './GridContext'; import { AlignItemType, AlignSelfType, JustifyContentType, SpacingType } from './types'; diff --git a/src/common/types/OverflowType.ts b/src/common/types/OverflowType.ts index a8a793db..7c9e3b15 100644 --- a/src/common/types/OverflowType.ts +++ b/src/common/types/OverflowType.ts @@ -1 +1 @@ -export type OverflowType = 'hidden' | 'auto' | 'unset'; +export type OverflowType = 'auto' | 'hidden' | 'visible' | 'scroll' | 'unset'; diff --git a/src/components/catalog/common/FurnitureOffer.ts b/src/components/catalog/common/FurnitureOffer.ts index 85d3216a..9197ae9f 100644 --- a/src/components/catalog/common/FurnitureOffer.ts +++ b/src/components/catalog/common/FurnitureOffer.ts @@ -1,5 +1,6 @@ -import { IFurnitureData } from '@nitrots/nitro-renderer'; +import { GetProductOfferComposer, IFurnitureData } from '@nitrots/nitro-renderer'; import { GetProductDataForLocalization } from '../../../api'; +import { SendMessageHook } from '../../../hooks'; import { ICatalogPage } from './ICatalogPage'; import { IProduct } from './IProduct'; import { IPurchasableOffer } from './IPurchasableOffer'; @@ -18,6 +19,11 @@ export class FurnitureOffer implements IPurchasableOffer this._product = (new Product(this._furniData.type, this._furniData.id, this._furniData.customParams, 1, GetProductDataForLocalization(this._furniData.className), this._furniData) as IProduct); } + public activate(): void + { + SendMessageHook(new GetProductOfferComposer((this._furniData.rentOfferId > -1) ? this._furniData.rentOfferId : this._furniData.purchaseOfferId)); + } + public get offerId(): number { return (this.isRentOffer) ? this._furniData.rentOfferId : this._furniData.purchaseOfferId; @@ -107,4 +113,9 @@ export class FurnitureOffer implements IPurchasableOffer { return this._furniData.description; } + + public get isLazy(): boolean + { + return true; + } } diff --git a/src/components/catalog/common/IPurchasableOffer.ts b/src/components/catalog/common/IPurchasableOffer.ts index cc2693f7..b1828651 100644 --- a/src/components/catalog/common/IPurchasableOffer.ts +++ b/src/components/catalog/common/IPurchasableOffer.ts @@ -3,6 +3,7 @@ import { IProduct } from './IProduct'; export interface IPurchasableOffer { + activate(): void; clubLevel: number; page: ICatalogPage; offerId: number; @@ -19,5 +20,6 @@ export interface IPurchasableOffer badgeCode: string; localizationName: string; localizationDescription: string; + isLazy: boolean; products: IProduct[]; } diff --git a/src/components/catalog/common/Offer.ts b/src/components/catalog/common/Offer.ts index 16e30a0c..b39ed48f 100644 --- a/src/components/catalog/common/Offer.ts +++ b/src/components/catalog/common/Offer.ts @@ -59,6 +59,11 @@ export class Offer implements IPurchasableOffer } } + public activate(): void + { + + } + public get clubLevel(): number { return this._clubLevel; @@ -160,6 +165,11 @@ export class Offer implements IPurchasableOffer return LocalizeText(this._localizationId); } + public get isLazy(): boolean + { + return false; + } + public get products(): IProduct[] { return this._products; diff --git a/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx b/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx index e18f6220..6b35eba7 100644 --- a/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx +++ b/src/components/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx @@ -78,8 +78,6 @@ export const CatalogLayoutPetView: FC = props => { let key: string = ''; - console.log(approvalResult); - switch(approvalResult) { case 1: diff --git a/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx index e41ff311..dbb20b17 100644 --- a/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogItemGridWidgetView.tsx @@ -21,6 +21,10 @@ export const CatalogItemGridWidgetView: FC = pro const selectOffer = (offer: IPurchasableOffer) => { + offer.activate(); + + if(offer.isLazy) return; + setCurrentOffer(offer); if(offer.product && (offer.product.productType === ProductTypeEnum.WALL)) @@ -31,10 +35,7 @@ export const CatalogItemGridWidgetView: FC = pro return ( - { currentPage.offers && (currentPage.offers.length > 0) && currentPage.offers.map((offer, index) => - { - return selectOffer(offer) } />; - }) } + { currentPage.offers && (currentPage.offers.length > 0) && currentPage.offers.map((offer, index) => selectOffer(offer) } />) } { children } ); diff --git a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx index 9b05d88f..d9df7e86 100644 --- a/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx +++ b/src/components/catalog/views/page/widgets/CatalogPurchaseWidgetView.tsx @@ -106,15 +106,15 @@ export const CatalogPurchaseWidgetView: FC = pro let pageId = currentOffer.page.pageId; - if(pageId === -1) - { - const nodes = getNodesByOfferId(currentOffer.offerId); + // if(pageId === -1) + // { + // const nodes = getNodesByOfferId(currentOffer.offerId); - if(nodes) pageId = nodes[0].pageId; - } + // if(nodes) pageId = nodes[0].pageId; + // } SendMessageHook(new PurchaseFromCatalogComposer(pageId, currentOffer.offerId, extraData, quantity)); - }, [ currentOffer, purchaseCallback, extraData, quantity, getNodesByOfferId ]); + }, [ currentOffer, purchaseCallback, extraData, quantity ]); useEffect(() => { diff --git a/src/components/chat-history/ChatHistoryView.scss b/src/components/chat-history/ChatHistoryView.scss index 8c3838e4..f18f91b5 100644 --- a/src/components/chat-history/ChatHistoryView.scss +++ b/src/components/chat-history/ChatHistoryView.scss @@ -1,8 +1,4 @@ .nitro-chat-history { width: $chat-history-width; height: $chat-history-height; - - .content-area { - min-height: 200px; - } } diff --git a/src/components/inventory/InventoryMessageHandler.tsx b/src/components/inventory/InventoryMessageHandler.tsx index e313bc7b..1cef493b 100644 --- a/src/components/inventory/InventoryMessageHandler.tsx +++ b/src/components/inventory/InventoryMessageHandler.tsx @@ -227,8 +227,6 @@ export const InventoryMessageHandler: FC<{}> = props => { const parser = event.getParser(); - console.log(parser); - dispatchFurnitureState({ type: InventoryFurnitureActions.UPDATE_TRADE, payload: { @@ -292,8 +290,6 @@ export const InventoryMessageHandler: FC<{}> = props => { const parser = event.getParser(); - console.log(parser); - NotificationUtilities.simpleAlert(LocalizeText(`inventory.trading.openfail.${ parser.reason }`, [ 'otherusername' ], [ parser.otherUserName ]), null, null, null, LocalizeText('inventory.trading.openfail.title')); }, []); diff --git a/src/components/inventory/views/badge/InventoryBadgeView.tsx b/src/components/inventory/views/badge/InventoryBadgeView.tsx index 73300e10..8aab5cbf 100644 --- a/src/components/inventory/views/badge/InventoryBadgeView.tsx +++ b/src/components/inventory/views/badge/InventoryBadgeView.tsx @@ -1,6 +1,6 @@ import { RequestBadgesComposer } from '@nitrots/nitro-renderer'; import { FC, useEffect } from 'react'; -import { LocalizeBadgeName, LocalizeText } from '../../../../api'; +import { GetConfiguration, LocalizeBadgeName, LocalizeText } from '../../../../api'; import { AutoGrid } from '../../../../common/AutoGrid'; import { Button } from '../../../../common/Button'; import { Column } from '../../../../common/Column'; @@ -22,9 +22,10 @@ export const InventoryBadgeView: FC = props => const { badgeState = null, dispatchBadgeState = null } = useInventoryContext(); const { needsBadgeUpdate = false, badge = null, badges = [], activeBadges = [] } = badgeState; - const isWearingBadge = (badgeCode: string) => (activeBadges.indexOf(badgeCode) >= 0); + const maxBadgeCount = GetConfiguration('user.badges.max.slots', 5); - const canWearBadges = () => (activeBadges.length < 5); + const isWearingBadge = (badgeCode: string) => (activeBadges.indexOf(badgeCode) >= 0); + const canWearBadges = () => (activeBadges.length < maxBadgeCount); const toggleBadge = () => { diff --git a/src/layout/card/content/NitroCardContentView.tsx b/src/layout/card/content/NitroCardContentView.tsx index 2ada5f99..85c93343 100644 --- a/src/layout/card/content/NitroCardContentView.tsx +++ b/src/layout/card/content/NitroCardContentView.tsx @@ -4,8 +4,8 @@ import { useNitroCardContext } from '../context'; export const NitroCardContentView: FC = props => { - const { classNames = [], ...rest } = props; - const { theme = 'primary', simple = false } = useNitroCardContext(); + const { overflow = 'auto', classNames = [], ...rest } = props; + const { simple = false } = useNitroCardContext(); const getClassNames = useMemo(() => { @@ -18,5 +18,5 @@ export const NitroCardContentView: FC = props => return newClassNames; }, [ simple, classNames ]); - return ; + return ; } diff --git a/src/views/campaign/views/calendar-item/CalendarItemView.tsx b/src/views/campaign/views/calendar-item/CalendarItemView.tsx index fe2eba0c..bf5e9607 100644 --- a/src/views/campaign/views/calendar-item/CalendarItemView.tsx +++ b/src/views/campaign/views/calendar-item/CalendarItemView.tsx @@ -2,7 +2,15 @@ import { FC, useCallback } from 'react'; import { GetRoomEngine, GetSessionDataManager } from '../../../../api'; import { NitroLayoutFlexColumn } from '../../../../layout'; import { CalendarItemState } from '../../common/CalendarItemState'; -import { CalendarItemViewProps } from './CalendarItemView.types'; + +interface CalendarItemViewProps +{ + id: number; + productName?: string; + state: number; + active?: boolean; + onClick(itemId: number): void; +} export const CalendarItemView: FC = props => { diff --git a/src/views/campaign/views/calendar-item/CalendarItemView.types.ts b/src/views/campaign/views/calendar-item/CalendarItemView.types.ts deleted file mode 100644 index 038dc03c..00000000 --- a/src/views/campaign/views/calendar-item/CalendarItemView.types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface CalendarItemViewProps -{ - id: number; - productName?: string; - state: number; - active?: boolean; - onClick(itemId: number): void; -} diff --git a/src/views/campaign/views/calendar/CalendarView.tsx b/src/views/campaign/views/calendar/CalendarView.tsx index b6566791..a7d77d4a 100644 --- a/src/views/campaign/views/calendar/CalendarView.tsx +++ b/src/views/campaign/views/calendar/CalendarView.tsx @@ -4,7 +4,18 @@ import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutFl import { CalendarItemState } from '../../common/CalendarItemState'; import { getNumItemsDisplayed } from '../../common/Utils'; import { CalendarItemView } from '../calendar-item/CalendarItemView'; -import { CalendarViewProps } from './CalendarView.types'; + +interface CalendarViewProps +{ + close(): void; + openPackage(id: number, asStaff: boolean): void; + receivedProducts: Map; + campaignName: string; + currentDay: number; + numDays: number; + openedDays: number[]; + missedDays: number[]; +} export const CalendarView: FC = props => { diff --git a/src/views/campaign/views/calendar/CalendarView.types.ts b/src/views/campaign/views/calendar/CalendarView.types.ts deleted file mode 100644 index 454021e3..00000000 --- a/src/views/campaign/views/calendar/CalendarView.types.ts +++ /dev/null @@ -1,11 +0,0 @@ -export interface CalendarViewProps -{ - close(): void; - openPackage(id: number, asStaff: boolean): void; - receivedProducts: Map; - campaignName: string; - currentDay: number; - numDays: number; - openedDays: number[]; - missedDays: number[]; -} diff --git a/src/views/notification-center/common/NotificationUtilities.ts b/src/views/notification-center/common/NotificationUtilities.ts index 86c73b5e..d751a68f 100644 --- a/src/views/notification-center/common/NotificationUtilities.ts +++ b/src/views/notification-center/common/NotificationUtilities.ts @@ -73,8 +73,6 @@ export class NotificationUtilities if(configuration) for(const key in configuration) options.set(key, configuration[key]); - console.log(options); - const title = this.getNotificationPart(options, type, 'title', true); const message = this.getNotificationPart(options, type, 'message', true).replace(/\\r/g, '\r'); const linkTitle = this.getNotificationPart(options, type, 'linkTitle', false); diff --git a/src/views/room/widgets/RoomWidgets.scss b/src/views/room/widgets/RoomWidgets.scss index 46b5281c..03b34a57 100644 --- a/src/views/room/widgets/RoomWidgets.scss +++ b/src/views/room/widgets/RoomWidgets.scss @@ -1,12 +1,104 @@ +.nitro-room-tools-container { + position: absolute; + bottom: $toolbar-height + 65px; + left: 0; + + .nitro-room-tools { + background: rgba($dark,.95); + box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4); + border-top-right-radius: $border-radius; + border-bottom-right-radius: $border-radius; + transition: all .2s ease; + z-index: 2; + + .list-group-item { + background: transparent; + padding: 3px 0px; + color: $white; + border-color: rgba($black, 0.3); + cursor: pointer; + + &:hover { + text-decoration: underline; + } + + &:first-child { + padding-top: 8px; + } + + &:last-child { + border-bottom: none; + padding-bottom: 8px; + } + + .tools-item { + .icon { + width: 22px; + background-repeat: no-repeat; + background-position: center; + } + + &:hover { + text-decoration: underline; + } + } + } + } + + .nitro-room-tools-info { + background: rgba($dark,.95); + box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4); + transition: all .2s ease; + pointer-events: none; + max-width: 250px; + } +} + +.wordquiz-question { + position: absolute; + top: 10px; + left: 50%; + transform: translateX(-50%); + font-size: large; + background: rgba($dark, 0.95); + box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4); + border-radius: $border-radius; + transition: all 0.2s ease; + + .question { + max-width: 300px; + } +} + +.word-quiz-dislike { + background: url("../../../assets/images/room-widgets/wordquiz-widget/thumbs-down.png"); + width: 31px; + height: 34px; +} + +.word-quiz-like { + background: url("../../../assets/images/room-widgets/wordquiz-widget/thumbs-up.png"); + width: 31px; + height: 34px; +} + +.word-quiz-dislike-sm { + background: url("../../../assets/images/room-widgets/wordquiz-widget/thumbs-down-small.png"); + width: 22px; + height: 22px; +} + +.word-quiz-like-sm { + background: url("../../../assets/images/room-widgets/wordquiz-widget/thumbs-up-small.png"); + height: 22px; + width: 22px; +} + @import './avatar-info/AvatarInfoWidgetView'; @import './chat/ChatWidgetView'; @import './chat-input/ChatInputView'; @import './choosers/ChooserWidgetView'; @import './context-menu/ContextMenu'; -@import './doorbell/DoorbellWidgetView'; @import './friend-request/FriendRequestDialogView'; @import './furniture/FurnitureWidgets'; @import './infostand/InfoStandWidgetView'; -@import './object-location/ObjectLocationView'; -@import './room-tools/RoomToolsWidgetView'; -@import './word-quiz/WordQuizWidgetView'; diff --git a/src/views/room/widgets/avatar-info/AvatarInfoRentableBotChatView.tsx b/src/views/room/widgets/avatar-info/AvatarInfoRentableBotChatView.tsx new file mode 100644 index 00000000..60a34d1e --- /dev/null +++ b/src/views/room/widgets/avatar-info/AvatarInfoRentableBotChatView.tsx @@ -0,0 +1,71 @@ +import { BotSkillSaveComposer } from '@nitrots/nitro-renderer'; +import { FC, useMemo, useState } from 'react'; +import { GetRoomObjectBounds, GetRoomSession, LocalizeText, RoomWidgetUpdateRentableBotChatEvent } from '../../../../api'; +import { Base, Button, Column, Flex, Text } from '../../../../common'; +import { SendMessageHook } from '../../../../hooks'; +import { DraggableWindow, DraggableWindowPosition } from '../../../../layout'; +import { ContextMenuHeaderView } from '../context-menu/ContextMenuHeaderView'; +import { BotSkillsEnum } from './common/BotSkillsEnum'; + +interface AvatarInfoRentableBotChatViewProps +{ + chatEvent: RoomWidgetUpdateRentableBotChatEvent; + close(): void; +} + +export const AvatarInfoRentableBotChatView: FC = props => +{ + const { chatEvent = null, close = null } = props; + // eslint-disable-next-line no-template-curly-in-string + const [ newText, setNewText ] = useState(chatEvent.chat === '${bot.skill.chatter.configuration.text.placeholder}' ? '' : chatEvent.chat); + const [ automaticChat, setAutomaticChat ] = useState(chatEvent.automaticChat); + const [ mixSentences, setMixSentences ] = useState(chatEvent.mixSentences); + const [ chatDelay, setChatDelay ] = useState(chatEvent.chatDelay); + + const getObjectLocation = useMemo(() => GetRoomObjectBounds(GetRoomSession().roomId, chatEvent.objectId, chatEvent.category, 1), [ chatEvent ]); + + const formatChatString = (value: string) => value.replace(/;#;/g, ' ').replace(/\r\n|\r|\n/g, '\r'); + + const save = () => + { + const chatConfiguration = formatChatString(newText) + ';#;' + automaticChat + ';#;' + chatDelay + ';#;' + mixSentences; + + SendMessageHook(new BotSkillSaveComposer(chatEvent.botId, BotSkillsEnum.SETUP_CHAT, chatConfiguration)); + + close(); + } + + return ( + + + + { LocalizeText('bot.skill.chatter.configuration.title') } + + + + { LocalizeText('bot.skill.chatter.configuration.chat.text') } +