Merge branch 'feature/messenger' into dev

This commit is contained in:
Bill 2021-09-24 04:51:17 -04:00
commit c19efc7fed
193 changed files with 2172 additions and 1270 deletions

View File

@ -5,6 +5,23 @@ module.exports = {
webpack: { webpack: {
configure: (webpackConfig) => ({ configure: (webpackConfig) => ({
...webpackConfig, ...webpackConfig,
optimization: {
...webpackConfig.optimization,
splitChunks: {
cacheGroups: {
vendor: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
chunks: 'all',
},
renderer: {
name: 'renderer',
test: /[\\/]node_modules[\\/]@nitrots[\\/]nitro-renderer[\\/]/,
chunks: 'all',
}
}
}
},
module: { module: {
...webpackConfig.module, ...webpackConfig.module,
rules: webpackConfig.module.rules.map((rule) => rules: webpackConfig.module.rules.map((rule) =>

View File

@ -17,6 +17,21 @@ $grid-active-border-color: $white;
$toolbar-height: 55px; $toolbar-height: 55px;
$achievement-width: 650px;
$achievement-height: 400px;
$avatar-editor-width: 620px;
$avatar-editor-height: 374px;
$catalog-width: 620px;
$catalog-height: 400px;
$inventory-width: 528px;
$inventory-height: 320px;
$navigator-width: 400px;
$navigator-height: 420px;
.nitro-app { .nitro-app {
width: 100%; width: 100%;
height: 100%; height: 100%;

View File

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

View File

@ -0,0 +1,7 @@
import { CreateLinkEvent } from '..';
export function OpenMessengerChat(friendId: number = -1): void
{
if(friendId === -1) CreateLinkEvent('friends/messenger/open');
else CreateLinkEvent(`friends/messenger/${friendId}`);
}

1
src/api/friends/index.ts Normal file
View File

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

View File

@ -1,4 +1,5 @@
export * from './core'; export * from './core';
export * from './friends';
export * from './groups'; export * from './groups';
export * from './navigator'; export * from './navigator';
export * from './nitro'; export * from './nitro';

View File

@ -47,6 +47,8 @@ export function DispatchMouseEvent(roomId: number, canvasId: number, event: Mous
break; break;
case MouseEventType.MOUSE_UP: case MouseEventType.MOUSE_UP:
break; break;
case MouseEventType.RIGHT_CLICK:
break;
default: return; default: return;
} }

View File

@ -0,0 +1,20 @@
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
export class RoomWidgetUpdateDecorateModeEvent extends RoomWidgetUpdateEvent
{
public static UPDATE_DECORATE: string = 'RWUDME_UPDATE_DECORATE';
private _isDecorating: boolean;
constructor(isDecorating: boolean)
{
super(RoomWidgetUpdateDecorateModeEvent.UPDATE_DECORATE);
this._isDecorating = isDecorating;
}
public get isDecorating(): boolean
{
return this._isDecorating;
}
}

View File

@ -14,6 +14,7 @@ export * from './RoomWidgetUpdateChatInputContentEvent';
export * from './RoomWidgetUpdateCreditFurniEvent'; export * from './RoomWidgetUpdateCreditFurniEvent';
export * from './RoomWidgetUpdateCustomStackHeightEvent'; export * from './RoomWidgetUpdateCustomStackHeightEvent';
export * from './RoomWidgetUpdateDanceStatusEvent'; export * from './RoomWidgetUpdateDanceStatusEvent';
export * from './RoomWidgetUpdateDecorateModeEvent';
export * from './RoomWidgetUpdateDimmerEvent'; export * from './RoomWidgetUpdateDimmerEvent';
export * from './RoomWidgetUpdateDimmerStateEvent'; export * from './RoomWidgetUpdateDimmerStateEvent';
export * from './RoomWidgetUpdateEvent'; export * from './RoomWidgetUpdateEvent';

View File

@ -1,7 +1,7 @@
import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, Vector3d } from '@nitrots/nitro-renderer'; import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, Vector3d } from '@nitrots/nitro-renderer';
import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..'; import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..';
import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../../../events'; import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../../../events';
import { FriendListSendFriendRequestEvent } from '../../../../../events/friend-list/FriendListSendFriendRequestEvent'; import { FriendsSendFriendRequestEvent } from '../../../../../events/friends/FriendsSendFriendRequestEvent';
import { dispatchUiEvent } from '../../../../../hooks/events'; import { dispatchUiEvent } from '../../../../../hooks/events';
import { SendMessageHook } from '../../../../../hooks/messages'; import { SendMessageHook } from '../../../../../hooks/messages';
import { PetSupplementEnum } from '../../../../../views/room/widgets/avatar-info/common/PetSupplementEnum'; import { PetSupplementEnum } from '../../../../../views/room/widgets/avatar-info/common/PetSupplementEnum';
@ -76,7 +76,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
case RoomWidgetRoomObjectMessage.GET_OBJECT_INFO: case RoomWidgetRoomObjectMessage.GET_OBJECT_INFO:
return this.processObjectInfoMessage((message as RoomWidgetRoomObjectMessage)); return this.processObjectInfoMessage((message as RoomWidgetRoomObjectMessage));
case RoomWidgetUserActionMessage.SEND_FRIEND_REQUEST: case RoomWidgetUserActionMessage.SEND_FRIEND_REQUEST:
dispatchUiEvent(new FriendListSendFriendRequestEvent(userId)); dispatchUiEvent(new FriendsSendFriendRequestEvent(userId));
break; break;
case RoomWidgetUserActionMessage.RESPECT_USER: case RoomWidgetUserActionMessage.RESPECT_USER:
GetSessionDataManager().giveRespect(userId); GetSessionDataManager().giveRespect(userId);

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

View File

@ -42,6 +42,14 @@ $utilities: map-merge(
property: overflow, property: overflow,
values: auto hidden visible scroll, values: auto hidden visible scroll,
), ),
"overflow-x": (
property: overflow-x,
values: auto hidden visible scroll,
),
"overflow-y": (
property: overflow-y,
values: auto hidden visible scroll,
),
// scss-docs-end utils-overflow // scss-docs-end utils-overflow
// scss-docs-start utils-display // scss-docs-start utils-display
"display": ( "display": (

View File

@ -85,6 +85,7 @@ $ghost: #c8cad0 !default;
$gray-chateau: #a3a7b1 !default; $gray-chateau: #a3a7b1 !default;
$gable-green: #1C323F !default; $gable-green: #1C323F !default;
$william: #3d5f6e !default; $william: #3d5f6e !default;
$bluewood: #304059 !default;
$success: $green !default; $success: $green !default;
$info: $cyan !default; $info: $cyan !default;
$warning: $yellow !default; $warning: $yellow !default;
@ -385,7 +386,7 @@ $enable-transitions: true !default;
$enable-reduced-motion: true !default; $enable-reduced-motion: true !default;
$enable-smooth-scroll: true !default; $enable-smooth-scroll: true !default;
$enable-grid-classes: true !default; $enable-grid-classes: true !default;
$enable-cssgrid: false !default; $enable-cssgrid: true !default;
$enable-button-pointers: true !default; $enable-button-pointers: true !default;
$enable-rfs: true !default; $enable-rfs: true !default;
$enable-validation-icons: true !default; $enable-validation-icons: true !default;

View File

@ -1,44 +0,0 @@
$grid-options: (
"2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"
);
.grid-items {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-content: flex-start;
width: 100%;
margin-top: -3px;
overflow: hidden;
@each $option in $grid-options {
&.grid-#{$option} {
.grid-item {
width: calc(1 / #{$option} * 100% - (1 - 1 / #{$option}) * 3px);
&:nth-child(#{$option}n) {
margin-right: 0;
}
}
}
}
}
.row-grid {
margin: 0 !important;
.col {
padding: 0 !important;
}
}
@each $option in $grid-options {
.row-grid {
&.row-cols-#{$option} {
.col:nth-child(#{$option}n) {
padding-left: 10px !important;
}
}
}
}

View File

@ -693,6 +693,18 @@
height: 16px; height: 16px;
} }
&.icon-friendlist-warning {
background: url('../images/friendlist/icons/icon_warning.png');
width: 23px;
height: 21px;
}
&.icon-friendlist-new-message {
background: url('../images/friendlist/icons/icon_new_message.png');
width: 14px;
height: 16px;
}
&.spin { &.spin {
animation: rotating 1s linear infinite; animation: rotating 1s linear infinite;
} }

View File

@ -7,7 +7,6 @@
@import '../node_modules/animate.css/animate.min.css'; @import '../node_modules/animate.css/animate.min.css';
@import './scrollbars'; @import './scrollbars';
@import './slider'; @import './slider';
@import './grid';
@import './icons'; @import './icons';
@import './utils'; @import './utils';
@ -15,6 +14,10 @@
min-height: 28px; min-height: 28px;
} }
textarea {
resize: none;
}
/* Chrome, Safari, Edge, Opera */ /* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button, input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button { input::-webkit-inner-spin-button {

View File

@ -1,15 +1,41 @@
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 0.5rem; width: 0.5rem;
&:horizontal {
height: 0.5rem; height: 0.5rem;
}
&:not(:horizontal) {
width: 0.5rem;
}
} }
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
background-clip: padding-box;
&:horizontal {
border-bottom: 0.25rem solid rgba($black, .1);
}
&:not(:horizontal) {
border-right: 0.25rem solid rgba($black, .1); border-right: 0.25rem solid rgba($black, .1);
}
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background-clip: padding-box;
&:horizontal {
border-bottom: 0.25rem solid rgba($primary, .4);
&:hover {
border-bottom: 0.25rem solid rgba($primary, .8);
}
&:active {
border-bottom: 0.25rem solid $secondary;
}
}
&:not(:horizontal) {
border-right: 0.25rem solid rgba($primary, .4); border-right: 0.25rem solid rgba($primary, .4);
&:hover { &:hover {
@ -19,4 +45,9 @@
&:active { &:active {
border-right: 0.25rem solid $secondary; border-right: 0.25rem solid $secondary;
} }
}
}
::-webkit-scrollbar-corner {
background: rgba($black, .1);
} }

View File

@ -10,6 +10,14 @@
transform: scale(1) translateZ(0); transform: scale(1) translateZ(0);
} }
.scale-1-25 {
transform: scale(1.25) translateZ(0);
}
.scale-1-50 {
transform: scale(1.50) translateZ(0);
}
.scale-2 { .scale-2 {
transform: scale(2) translateZ(0); transform: scale(2) translateZ(0);
} }

View File

@ -1,2 +0,0 @@
export * from './FriendEnteredRoomEvent';
export * from './FriendListEvent';

View File

@ -1,7 +1,7 @@
import { MessengerFriend } from '../../views/friends/common/MessengerFriend'; import { MessengerFriend } from '../../views/friends/common/MessengerFriend';
import { FriendListEvent } from './FriendListEvent'; import { FriendsEvent } from './FriendsEvent';
export class FriendListContentEvent extends FriendListEvent export class FriendListContentEvent extends FriendsEvent
{ {
public static FRIEND_LIST_CONTENT: string = 'FLSFRE_FRIEND_LIST_CONTENT'; public static FRIEND_LIST_CONTENT: string = 'FLSFRE_FRIEND_LIST_CONTENT';

View File

@ -1,8 +1,10 @@
import { NitroEvent } from '@nitrots/nitro-renderer'; import { NitroEvent } from '@nitrots/nitro-renderer';
export class FriendListEvent extends NitroEvent export class FriendsEvent extends NitroEvent
{ {
public static SHOW_FRIEND_LIST: string = 'IE_SHOW_FRIEND_LIST'; public static SHOW_FRIEND_LIST: string = 'IE_SHOW_FRIEND_LIST';
public static TOGGLE_FRIEND_LIST: string = 'IE_TOGGLE_FRIEND_LIST'; public static TOGGLE_FRIEND_LIST: string = 'IE_TOGGLE_FRIEND_LIST';
public static SHOW_FRIEND_MESSENGER: string = 'IE_SHOW_FRIEND_MESSENGER';
public static TOGGLE_FRIEND_MESSENGER: string = 'IE_TOGGLE_FRIEND_MESSENGER';
public static REQUEST_FRIEND_LIST: string = 'FLSFRE_REQUEST_FRIEND_LIST'; public static REQUEST_FRIEND_LIST: string = 'FLSFRE_REQUEST_FRIEND_LIST';
} }

View File

@ -0,0 +1,23 @@
import { NitroEvent } from '@nitrots/nitro-renderer';
export class FriendsMessengerIconEvent extends NitroEvent
{
public static UPDATE_ICON: string = 'FMIE_UPDATE_ICON';
public static HIDE_ICON: number = 0;
public static SHOW_ICON: number = 1;
public static UNREAD_ICON: number = 2;
private _iconType: number;
constructor(type: string, subType: number = FriendsMessengerIconEvent.SHOW_ICON)
{
super(type);
this._iconType = subType;
}
public get iconType(): number
{
return this._iconType;
}
}

View File

@ -1,6 +1,6 @@
import { FriendListEvent } from './FriendListEvent'; import { FriendsEvent } from './FriendsEvent';
export class FriendListSendFriendRequestEvent extends FriendListEvent export class FriendsSendFriendRequestEvent extends FriendsEvent
{ {
public static SEND_FRIEND_REQUEST: string = 'FLSFRE_SEND_FRIEND_REQUEST'; public static SEND_FRIEND_REQUEST: string = 'FLSFRE_SEND_FRIEND_REQUEST';
@ -8,7 +8,7 @@ export class FriendListSendFriendRequestEvent extends FriendListEvent
constructor(userId: number) constructor(userId: number)
{ {
super(FriendListSendFriendRequestEvent.SEND_FRIEND_REQUEST); super(FriendsSendFriendRequestEvent.SEND_FRIEND_REQUEST);
this._userId = userId; this._userId = userId;
} }

View File

@ -0,0 +1,5 @@
export * from './FriendEnteredRoomEvent';
export * from './FriendListContentEvent';
export * from './FriendsEvent';
export * from './FriendsMessengerIconEvent';
export * from './FriendsSendFriendRequestEvent';

View File

@ -1,7 +1,7 @@
export * from './avatar-editor'; export * from './avatar-editor';
export * from './camera'; export * from './camera';
export * from './catalog'; export * from './catalog';
export * from './friend-list'; export * from './friends';
export * from './inventory'; export * from './inventory';
export * from './navigator'; export * from './navigator';
export * from './notification-center'; export * from './notification-center';

View File

@ -14,4 +14,8 @@ body {
image-rendering: -moz-crisp-edges; image-rendering: -moz-crisp-edges;
} }
img {
object-fit: none;
}
@import './App'; @import './App';

View File

@ -0,0 +1,28 @@
import { FC, useMemo } from 'react';
import { NitroLayoutBaseProps } from './NitroLayoutBase.types';
export const NitroLayoutBase: FC<NitroLayoutBaseProps> = props =>
{
const { className = '', overflow = null, position = null, gap = null, children = null, ...rest } = props;
const getClassName = useMemo(() =>
{
let newClassName = '';
if(overflow && overflow.length) newClassName += ` overflow-${ overflow }`;
if(position && position.length) newClassName += ` position-${ position }`;
if(gap && gap >= 1) newClassName += ` gap-${ gap }`;
if(className && className.length) newClassName += ` ${ className }`;
return newClassName;
}, [ className, overflow, position, gap ]);
return (
<div className={ getClassName } { ...rest }>
{ children }
</div>
);
}

View File

@ -0,0 +1,9 @@
import { ButtonHTMLAttributes, DetailedHTMLProps } from 'react';
import { NitroLayoutOverflow, NitroLayoutPosition, NitroLayoutSpacing } from '../common';
export interface NitroLayoutBaseProps extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLDivElement>, HTMLDivElement>
{
overflow?: NitroLayoutOverflow;
position?: NitroLayoutPosition;
gap?: NitroLayoutSpacing;
}

2
src/layout/base/index.ts Normal file
View File

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

View File

@ -0,0 +1,26 @@
import { FC, useMemo } from 'react';
import { NitroLayoutButtonProps } from './NitroLayoutButton.types';
export const NitroLayoutButton: FC<NitroLayoutButtonProps> = props =>
{
const { className = '', variant = 'primary', size = null, children = null, ...rest } = props;
const getClassName = useMemo(() =>
{
let newClassName = 'btn';
if(variant && variant.length) newClassName += ` btn-${ variant }`;
if(size && size.length) newClassName += ` btn-${ size }`;
if(className && className.length) newClassName += ` ${ className }`;
return newClassName;
}, [ className, variant, size ]);
return (
<button type="button" className={ getClassName } { ...rest }>
{ children }
</button>
);
}

View File

@ -0,0 +1,8 @@
import { ButtonHTMLAttributes, DetailedHTMLProps } from 'react';
import { NitroLayoutButtonSize, NitroLayoutVariant } from '../common';
export interface NitroLayoutButtonProps extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
{
variant?: NitroLayoutVariant;
size?: NitroLayoutButtonSize;
}

View File

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

View File

@ -3,6 +3,7 @@ $nitro-card-tabs-height: 33px;
.nitro-card { .nitro-card {
pointer-events: all; pointer-events: all;
resize: both;
@import './accordion/NitroCardAccordionView'; @import './accordion/NitroCardAccordionView';
@import './content/NitroCardContentView'; @import './content/NitroCardContentView';
@ -19,6 +20,10 @@ $nitro-card-tabs-height: 33px;
height: 100%; height: 100%;
pointer-events: none; pointer-events: none;
.theme-primary {
border: $border-width solid $border-color;
}
@include media-breakpoint-down(lg) { @include media-breakpoint-down(lg) {
.draggable-window { .draggable-window {
@ -31,12 +36,13 @@ $nitro-card-tabs-height: 33px;
} }
.nitro-card { .nitro-card {
width: 100%; max-width: 75%;
height: 100%; max-height: calc(100% - 20px);
margin: 10px auto 10px;
&.rounded { // &.rounded {
border-radius: 0 !important; // border-radius: 0 !important;
} // }
} }
} }
} }

View File

@ -11,7 +11,7 @@ export const NitroCardView: FC<NitroCardViewProps> = props =>
<NitroCardContextProvider value={ { theme, simple } }> <NitroCardContextProvider value={ { theme, simple } }>
<div className="nitro-card-responsive"> <div className="nitro-card-responsive">
<DraggableWindow { ...rest }> <DraggableWindow { ...rest }>
<div className={ 'nitro-card d-flex flex-column rounded border shadow overflow-hidden ' + className }> <div className={ `nitro-card d-flex flex-column rounded shadow overflow-hidden theme-${theme} ${className}` }>
{ children } { children }
</div> </div>
</DraggableWindow> </DraggableWindow>

View File

@ -1,4 +1,5 @@
.content-area { .content-area {
height: 100%;
padding-top: $container-padding-x; padding-top: $container-padding-x;
padding-bottom: $container-padding-x; padding-bottom: $container-padding-x;
overflow: auto; overflow: auto;
@ -9,6 +10,5 @@
height: 100% !important; height: 100% !important;
min-height: auto !important; min-height: auto !important;
max-height: 100% !important; max-height: 100% !important;
resize: none !important;
} }
} }

View File

@ -8,7 +8,7 @@ export const NitroCardContentView: FC<NitroCardContentViewProps> = props =>
const { simple = false } = useNitroCardContext(); const { simple = false } = useNitroCardContext();
return ( return (
<div className={ `container-fluid bg-light content-area ${ (simple ? 'simple' : '') } ${ className || '' }` } { ...rest }> <div className={ `container-fluid bg-light content-area d-flex flex-column overflow-auto ${ (simple ? 'simple' : '') } ${ className || '' }` } { ...rest }>
{ children } { children }
</div> </div>
); );

View File

@ -1,71 +1,6 @@
.nitro-card-grid { .nitro-grid {
width: 100%; --nitro-grid-column-min-width: 45px;
grid-template-columns: repeat(auto-fill, minmax(var(--nitro-grid-column-min-width, 45px), 1fr));
.row-cols-3 {
.col {
padding-right: 0.25rem;
&:nth-child(3n+3) {
padding-right: 0;
}
}
}
.row-cols-4 {
.col {
padding-right: 0.25rem;
&:nth-child(4n+4) {
padding-right: 0;
}
}
}
.row-cols-5 {
.col {
padding-right: 0.25rem;
&:nth-child(5n+5) {
padding-right: 0;
}
}
}
.row-cols-6 {
.col {
padding-right: 0.25rem;
&:nth-child(6n+6) {
padding-right: 0;
}
}
}
.row-cols-7 {
.col {
padding-right: 0.25rem;
&:nth-child(7n+7) {
padding-right: 0;
}
}
}
.row-cols-8 {
.col {
padding-right: 0.25rem;
&:nth-child(8n+8) {
padding-right: 0;
}
}
}
@import './item/NitroCardGridItemView.scss';
} }
@import './item/NitroCardGridItemView.scss';

View File

@ -1,18 +1,31 @@
import { FC } from 'react'; import { FC, useMemo } from 'react';
import { NitroCardGridContextProvider } from './context/NitroCardGridContext'; import { NitroCardGridViewProps } from './NitroCardGridView.types';
import { NitroCardGridThemes, NitroCardGridViewProps } from './NitroCardGridView.types';
export const NitroCardGridView: FC<NitroCardGridViewProps> = props => export const NitroCardGridView: FC<NitroCardGridViewProps> = props =>
{ {
const { columns = 5, theme = NitroCardGridThemes.THEME_DEFAULT, className = '', children = null, ...rest } = props; const { columns = 5, gap = 2, className = '', style = null, children = null, ...rest } = props;
const getClassName = useMemo(() =>
{
let newClassName = `grid gap-${ gap } nitro-grid overflow-auto`;
if(className && className.length) newClassName += ' ' + className;
return newClassName;
}, [ className, gap ]);
const getStyle = useMemo(() =>
{
const newStyle = { ...style };
//newStyle['--bs-columns'] = columns.toString();
return newStyle;
}, [ style, columns ]);
return ( return (
<NitroCardGridContextProvider value={ { theme } }> <div className={ getClassName } style={ getStyle } { ...rest }>
<div className={ `h-100 overflow-hidden nitro-card-grid ${ theme } ${ className || '' }` } { ...rest }>
<div className={ `row row-cols-${ columns } align-content-start g-0 w-100 h-100 overflow-auto` }>
{ children } { children }
</div> </div>
</div>
</NitroCardGridContextProvider>
); );
} }

View File

@ -3,11 +3,5 @@ import { DetailsHTMLAttributes } from 'react';
export interface NitroCardGridViewProps extends DetailsHTMLAttributes<HTMLDivElement> export interface NitroCardGridViewProps extends DetailsHTMLAttributes<HTMLDivElement>
{ {
columns?: number; columns?: number;
theme?: string; gap?: number;
}
export class NitroCardGridThemes
{
public static THEME_DEFAULT: string = 'theme-default';
public static THEME_SHADOWED: string = 'theme-shadowed';
} }

View File

@ -1,13 +0,0 @@
import { createContext, FC, useContext } from 'react';
import { INitroCardGridContext, NitroCardGridContextProps } from './NitroCardGridContext.types';
const NitroCardGridContext = createContext<INitroCardGridContext>({
theme: null
});
export const NitroCardGridContextProvider: FC<NitroCardGridContextProps> = props =>
{
return <NitroCardGridContext.Provider value={ props.value }>{ props.children }</NitroCardGridContext.Provider>
}
export const useNitroCardGridContext = () => useContext(NitroCardGridContext);

View File

@ -1,11 +0,0 @@
import { ProviderProps } from 'react';
export interface INitroCardGridContext
{
theme: string;
}
export interface NitroCardGridContextProps extends ProviderProps<INitroCardGridContext>
{
}

View File

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

View File

@ -1,4 +1,3 @@
export * from './context';
export * from './item'; export * from './item';
export * from './NitroCardGridView'; export * from './NitroCardGridView';
export * from './NitroCardGridView.types'; export * from './NitroCardGridView.types';

View File

@ -1,52 +1,17 @@
.grid-item-container { .grid-item {
height: 50px; position: relative;
max-height: 50px;
.grid-item {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
position: relative; height: 50px;
max-height: 50px;
width: 100%; width: 100%;
height: 100%;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
overflow: hidden;
&.theme-default {
border-radius: $border-radius; border-radius: $border-radius;
border-color: $grid-border-color !important; border-color: $grid-border-color !important;
background-color: $grid-bg-color; background-color: $grid-bg-color;
border: nth(map-values($border-widths), 2) solid; border: nth(map-values($border-widths), 2) solid;
}
&.theme-shadowed {
border-radius: $border-radius;
background-color: $light;
&::after {
position: absolute;
content: '';
top: 0;
bottom: 0;
left: 0;
right: 0;
border-radius: $border-radius;
border-bottom: 2px solid white;
border-right: 2px solid white;
box-shadow: -2px -2px rgba(0, 0, 0, .4), inset 3px 3px rgba(0, 0, 0, .2);
}
&.active {
border: nth(map-values($border-widths), 2) solid;
border-color: $oslo-gray !important;
background-color: #F5F5F5;
&:after {
content: unset;
}
}
}
&.active { &.active {
border-color: $grid-active-border-color !important; border-color: $grid-active-border-color !important;
@ -64,9 +29,7 @@
} }
.avatar-image { .avatar-image {
background-position: center; background-position-y: 10px;
background-repeat: no-repeat;
background-position-y: 12px !important;
} }
.trade-button { .trade-button {
@ -82,5 +45,4 @@
left: 2px; left: 2px;
} }
} }
}
} }

View File

@ -1,27 +1,50 @@
import { FC } from 'react'; import { FC, useMemo } from 'react';
import { LimitedEditionStyledNumberView } from '../../../../views/shared/limited-edition/styled-number/LimitedEditionStyledNumberView'; import { LimitedEditionStyledNumberView } from '../../../../views/shared/limited-edition/styled-number/LimitedEditionStyledNumberView';
import { useNitroCardGridContext } from '../context';
import { NitroCardGridThemes } from '../NitroCardGridView.types';
import { NitroCardGridItemViewProps } from './NitroCardGridItemView.types'; import { NitroCardGridItemViewProps } from './NitroCardGridItemView.types';
export const NitroCardGridItemView: FC<NitroCardGridItemViewProps> = props => export const NitroCardGridItemView: FC<NitroCardGridItemViewProps> = props =>
{ {
const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemUnique = false, itemUniqueNumber = 0, itemUnseen = false, columns = undefined, className = '', style = {}, children = null, ...rest } = props; const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemUniqueNumber = -2, itemUnseen = false, className = '', style = {}, children = null, ...rest } = props;
const { theme = NitroCardGridThemes.THEME_DEFAULT } = useNitroCardGridContext();
const imageUrl = `url(${ itemImage })`; const getClassName = useMemo(() =>
{
let newClassName = 'grid-item gap-1 cursor-pointer overflow-hidden';
if(itemActive) newClassName += ' active';
if(itemUniqueNumber === -1) newClassName += ' unique-item sold-out';
if(itemUniqueNumber > 0) newClassName += ' unique-item';
if(itemUnseen) newClassName += ' unseen';
if(itemImage === null) newClassName += ' icon loading-icon';
if(className && className.length) newClassName += ' ' + className;
return newClassName;
}, [ className, itemActive, itemUniqueNumber, itemUnseen, itemImage ]);
const getStyle = useMemo(() =>
{
const newStyle = { ...style };
if(itemImage) newStyle.backgroundImage = `url(${ itemImage })`;
if(itemColor) newStyle.backgroundColor = itemColor;
return newStyle;
}, [ style, itemImage, itemColor ]);
return ( return (
<div className={ `${ columns === undefined ? 'col' : ('col-' + columns) } pb-1 grid-item-container` }> <div className={ getClassName } style={ getStyle } { ...rest }>
<div className={ `grid-item ${ theme } cursor-pointer${ itemActive ? ' active' : '' }${ itemUnique ? ' unique-item' : '' }${ itemUnseen ? ' unseen' : ''}${ (itemImage === null ? ' icon loading-icon': '')} ${ className || '' }` } style={ itemImage ? { ...style, backgroundImage: imageUrl } : (itemColor ? { ...style, backgroundColor: itemColor } : style) } { ...rest }>
{ (itemCount > 1) && { (itemCount > 1) &&
<span className="position-absolute badge border bg-danger px-1 rounded-circle">{ itemCount }</span> } <span className="position-absolute badge border bg-danger px-1 rounded-circle">{ itemCount }</span> }
{ itemUnique && { (itemUniqueNumber > 0) &&
<div className="position-absolute unique-item-counter"> <div className="position-absolute unique-item-counter">
<LimitedEditionStyledNumberView value={ itemUniqueNumber } /> <LimitedEditionStyledNumberView value={ itemUniqueNumber } />
</div> } </div> }
{ children } { children }
</div> </div>
</div>
); );
} }

View File

@ -6,8 +6,6 @@ export interface NitroCardGridItemViewProps extends DetailsHTMLAttributes<HTMLDi
itemColor?: string; itemColor?: string;
itemActive?: boolean; itemActive?: boolean;
itemCount?: number; itemCount?: number;
itemUnique?: boolean;
itemUniqueNumber?: number; itemUniqueNumber?: number;
itemUnseen?: boolean; itemUnseen?: boolean;
columns?: number;
} }

View File

@ -0,0 +1 @@
export type NitroLayoutButtonSize = 'sm' | 'lg';

View File

@ -0,0 +1 @@
export type NitroLayoutColumns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;

View File

@ -0,0 +1 @@
export type NitroLayoutOverflow = 'hidden' | 'auto';

View File

@ -0,0 +1 @@
export type NitroLayoutPosition = 'static' | 'relative' | 'fixed' | 'absolute' | 'sticky';

View File

@ -0,0 +1 @@
export type NitroLayoutSpacing = 1 | 2 | 3 | 4 | 5;

View File

@ -0,0 +1 @@
export type NitroLayoutVariant = 'primary' | 'success' | 'danger';

View File

@ -0,0 +1,6 @@
export * from './NitroLayoutButtonSize.type';
export * from './NitroLayoutColumns.type';
export * from './NitroLayoutOverflow.type';
export * from './NitroLayoutPosition.type';
export * from './NitroLayoutSpacing.type';
export * from './NitroLayoutVariant.type';

View File

@ -0,0 +1,19 @@
import { FC, useMemo } from 'react';
import { NitroLayoutFlex } from '../flex/NitroLayoutFlex';
import { NitroLayoutFlexColumnProps } from './NitroLayoutFlexColumn.types';
export const NitroLayoutFlexColumn: FC<NitroLayoutFlexColumnProps> = props =>
{
const { className = '', ...rest } = props;
const getClassName = useMemo(() =>
{
let newClassName = 'flex-column';
if(className && className.length) newClassName += ` ${ className }`;
return newClassName;
}, [ className ]);
return <NitroLayoutFlex className={ getClassName } { ...rest } />;
}

View File

@ -0,0 +1,6 @@
import { NitroLayoutFlexProps } from '../flex/NitroLayoutFlex.types';
export interface NitroLayoutFlexColumnProps extends NitroLayoutFlexProps
{
}

View File

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

View File

@ -0,0 +1,19 @@
import { FC, useMemo } from 'react';
import { NitroLayoutBase } from '../base/NitroLayoutBase';
import { NitroLayoutFlexProps } from './NitroLayoutFlex.types';
export const NitroLayoutFlex: FC<NitroLayoutFlexProps> = props =>
{
const { className = '', ...rest } = props;
const getClassName = useMemo(() =>
{
let newClassName = 'd-flex';
if(className && className.length) newClassName += ` ${ className }`;
return newClassName;
}, [ className ]);
return <NitroLayoutBase className={ getClassName } { ...rest } />;
}

View File

@ -0,0 +1,6 @@
import { NitroLayoutBaseProps } from '../base/NitroLayoutBase.types';
export interface NitroLayoutFlexProps extends NitroLayoutBaseProps
{
}

2
src/layout/flex/index.ts Normal file
View File

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

View File

@ -0,0 +1,19 @@
import { FC, useMemo } from 'react';
import { NitroLayoutBase } from '../base';
import { NitroLayoutGridProps } from './NitroLayoutGrid.types';
export const NitroLayoutGrid: FC<NitroLayoutGridProps> = props =>
{
const { className = '', gap = 3, ...rest } = props;
const getClassName = useMemo(() =>
{
let newClassName = 'grid h-100';
if(className && className.length) newClassName += ' ' + className;
return newClassName;
}, [ className ]);
return <NitroLayoutBase className={ getClassName } gap={ gap } { ...rest } />;
}

View File

@ -0,0 +1,6 @@
import { NitroLayoutBaseProps } from '../base';
export interface NitroLayoutGridProps extends NitroLayoutBaseProps
{
}

View File

@ -0,0 +1,19 @@
import { FC, useMemo } from 'react';
import { NitroLayoutFlexColumn } from '../../flex-column/NitroLayoutFlexColumn';
import { NitroLayoutGridColumnProps } from './NitroLayoutGridColumn.types';
export const NitroLayoutGridColumn: FC<NitroLayoutGridColumnProps> = props =>
{
const { className = '', size = 12, gap = 3, ...rest } = props;
const getClassName = useMemo(() =>
{
let newClassName = `g-col-${ size }`;
if(className && className.length) newClassName += ' ' + className;
return newClassName;
}, [ className, size ]);
return <NitroLayoutFlexColumn className={ getClassName } gap={ gap } overflow="auto" { ...rest } />
}

View File

@ -0,0 +1,8 @@
import { NitroLayoutColumns, NitroLayoutSpacing } from '../../common';
import { NitroLayoutFlexColumnProps } from '../../flex-column/NitroLayoutFlexColumn.types';
export interface NitroLayoutGridColumnProps extends NitroLayoutFlexColumnProps
{
size?: NitroLayoutColumns;
gap?: NitroLayoutSpacing;
}

View File

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

3
src/layout/grid/index.ts Normal file
View File

@ -0,0 +1,3 @@
export * from './column';
export * from './NitroLayoutGrid';
export * from './NitroLayoutGrid.types';

View File

@ -1,6 +1,12 @@
export * from './button';
export * from './card'; export * from './card';
export * from './common';
export * from './draggable-window'; export * from './draggable-window';
export * from './flex';
export * from './flex-column';
export * from './gift-card'; export * from './gift-card';
export * from './grid';
export * from './loading-habbos';
export * from './loading-spinner'; export * from './loading-spinner';
export * from './mini-camera'; export * from './mini-camera';
export * from './notification-alert'; export * from './notification-alert';

View File

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

View File

@ -1,5 +1,6 @@
.nitro-achievements { .nitro-achievements {
width: 650px; width: $achievement-width;
height: $achievement-height;
.score { .score {
border-color: $grid-border-color !important; border-color: $grid-border-color !important;

View File

@ -1,10 +1,6 @@
.nitro-avatar-editor { .nitro-avatar-editor {
width: 620px; width: $avatar-editor-width;
height: $avatar-editor-height;
.content-area {
min-height: 300px;
height: 300px;
}
.category-item { .category-item {
height: 40px; height: 40px;
@ -82,6 +78,37 @@
.wardrobe-grid { .wardrobe-grid {
.grid-item {
height: 140px;
max-height: 140px;
background-color: $ghost;
&:after {
position: absolute;
content: '';
top: 75%;
bottom: 0;
left: 0;
right: 0;
border-radius: 50%;
background-color: $gray-chateau;
box-shadow: 0 0 8px 2px rgba($white,.6);
transform: scale(2);
}
.avatar-image {
position: absolute;
bottom: 0;
background-position-y: -23px !important;
z-index: 4;
}
.figure-button-container {
background-color: $gray-chateau;
z-index: 3;
}
}
.grid-item-container { .grid-item-container {
height: 142px !important; height: 142px !important;
max-height: 142px !important; max-height: 142px !important;

View File

@ -1,6 +1,5 @@
import { FC, useCallback } from 'react'; import { FC, useCallback } from 'react';
import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView';
import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types';
import { AvatarEditorGridPartItem } from '../../common/AvatarEditorGridPartItem'; import { AvatarEditorGridPartItem } from '../../common/AvatarEditorGridPartItem';
import { AvatarEditorFigureSetItemView } from '../figure-set-item/AvatarEditorFigureSetItemView'; import { AvatarEditorFigureSetItemView } from '../figure-set-item/AvatarEditorFigureSetItemView';
import { AvatarEditorFigureSetViewProps } from './AvatarEditorFigureSetView.types'; import { AvatarEditorFigureSetViewProps } from './AvatarEditorFigureSetView.types';
@ -23,7 +22,7 @@ export const AvatarEditorFigureSetView: FC<AvatarEditorFigureSetViewProps> = pro
}, [ model, category, setMaxPaletteCount ]); }, [ model, category, setMaxPaletteCount ]);
return ( return (
<NitroCardGridView columns={ 3 } theme={ NitroCardGridThemes.THEME_SHADOWED }> <NitroCardGridView columns={ 3 }>
{ (category.parts.length > 0) && category.parts.map((item, index) => { (category.parts.length > 0) && category.parts.map((item, index) =>
{ {
return <AvatarEditorFigureSetItemView key={ index } partItem={ item } onClick={ selectPart } />; return <AvatarEditorFigureSetItemView key={ index } partItem={ item } onClick={ selectPart } />;

View File

@ -71,7 +71,7 @@ export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props =>
<div className="col-5 d-flex flex-column h-100"> <div className="col-5 d-flex flex-column h-100">
<AvatarEditorFigureSetView model={ model } category={ activeCategory } setMaxPaletteCount={ setMaxPaletteCount } /> <AvatarEditorFigureSetView model={ model } category={ activeCategory } setMaxPaletteCount={ setMaxPaletteCount } />
</div> </div>
<div className="col-5 d-flex flex-column h-100"> <div className="col-5 d-flex flex-column h-100 gap-2">
{ (maxPaletteCount >= 1) && { (maxPaletteCount >= 1) &&
<AvatarEditorPaletteSetView model={ model } category={ activeCategory } paletteSet={ activeCategory.getPalette(0) } paletteIndex={ 0 } /> } <AvatarEditorPaletteSetView model={ model } category={ activeCategory } paletteSet={ activeCategory.getPalette(0) } paletteIndex={ 0 } /> }
{ (maxPaletteCount === 2) && { (maxPaletteCount === 2) &&

View File

@ -1,6 +1,5 @@
import { FC, useCallback } from 'react'; import { FC, useCallback } from 'react';
import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView';
import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types';
import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem'; import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem';
import { AvatarEditorPaletteSetItem } from '../palette-set-item/AvatarEditorPaletteSetItem'; import { AvatarEditorPaletteSetItem } from '../palette-set-item/AvatarEditorPaletteSetItem';
import { AvatarEditorPaletteSetViewProps } from './AvatarEditorPaletteSetView.types'; import { AvatarEditorPaletteSetViewProps } from './AvatarEditorPaletteSetView.types';
@ -19,7 +18,7 @@ export const AvatarEditorPaletteSetView: FC<AvatarEditorPaletteSetViewProps> = p
}, [ model, category, paletteSet, paletteIndex ]); }, [ model, category, paletteSet, paletteIndex ]);
return ( return (
<NitroCardGridView columns={ 4 } theme={ NitroCardGridThemes.THEME_SHADOWED } { ...rest }> <NitroCardGridView columns={ 4 } { ...rest }>
{ (paletteSet.length > 0) && paletteSet.map((item, index) => { (paletteSet.length > 0) && paletteSet.map((item, index) =>
{ {
return <AvatarEditorPaletteSetItem key={ index } colorItem={ item } onClick={ event => selectColor(item) } />; return <AvatarEditorPaletteSetItem key={ index } colorItem={ item } onClick={ event => selectColor(item) } />;

View File

@ -5,7 +5,6 @@ import { GetAvatarRenderManager, GetSessionDataManager } from '../../../../api';
import { SendMessageHook } from '../../../../hooks'; import { SendMessageHook } from '../../../../hooks';
import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView';
import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView';
import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types';
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon'; import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon';
import { AvatarEditorWardrobeViewProps } from './AvatarEditorWardrobeView.types'; import { AvatarEditorWardrobeViewProps } from './AvatarEditorWardrobeView.types';
@ -68,7 +67,7 @@ export const AvatarEditorWardrobeView: FC<AvatarEditorWardrobeViewProps> = props
return ( return (
<div className="row h-100"> <div className="row h-100">
<div className="col-12 d-flex h-100"> <div className="col-12 d-flex h-100">
<NitroCardGridView className="wardrobe-grid" columns={ 5 } theme={ NitroCardGridThemes.THEME_DEFAULT }> <NitroCardGridView className="wardrobe-grid" columns={ 5 }>
{ figures } { figures }
</NitroCardGridView> </NitroCardGridView>
</div> </div>

View File

@ -1,11 +1,6 @@
.nitro-catalog { .nitro-catalog {
width: 620px; width: $catalog-width;
height: $catalog-height;
.content-area {
min-height: 350px;
height: 350px;
resize: vertical;
}
font[size="16"] { font[size="16"] {
font-size: 20px; font-size: 20px;

View File

@ -205,7 +205,7 @@ export const CatalogView: FC<CatalogViewProps> = props =>
<NitroCardContentView> <NitroCardContentView>
<div className="row h-100"> <div className="row h-100">
{ currentNavigationPage && !navigationHidden && { currentNavigationPage && !navigationHidden &&
<div className="col-3 d-flex flex-column h-100"> <div className="col-3 h-100">
<CatalogNavigationView page={ currentNavigationPage } pendingTree={ pendingTree } setPendingTree={ setPendingTree } /> <CatalogNavigationView page={ currentNavigationPage } pendingTree={ pendingTree } setPendingTree={ setPendingTree } />
</div> } </div> }
<div className="col h-100"> <div className="col h-100">

View File

@ -0,0 +1,30 @@
import { CatalogPageMessageOfferData, RoomObjectCategory, RoomObjectPlacementSource } from '@nitrots/nitro-renderer';
import { GetRoomEngine } from '../../../api';
import { IsCatalogOfferDraggable } from './IsCatalogOfferDraggable';
import { ProductTypeEnum } from './ProductTypeEnum';
export const AttemptCatalogPlacement = (offer: CatalogPageMessageOfferData) =>
{
if(!IsCatalogOfferDraggable(offer)) return;
const product = offer.products[0];
let category: number = -1;
switch(product.productType)
{
case ProductTypeEnum.FLOOR:
category = RoomObjectCategory.FLOOR;
break;
case ProductTypeEnum.WALL:
category = RoomObjectCategory.WALL;
break;
}
if(category === -1) return;
if(GetRoomEngine().processRoomObjectPlacement(RoomObjectPlacementSource.CATALOG, -(offer.offerId), category, product.furniClassId, (product.extraParam) ? product.extraParam.toString() : null))
{
}
}

View File

@ -0,0 +1,47 @@
import { FurnitureType } from '@nitrots/nitro-renderer';
import { GetConfiguration, GetRoomEngine, GetSessionDataManager } from '../../../api';
export const GetProductIconUrl = (furniClassId: number, productType: string, customParams: string = null) =>
{
switch(productType.toUpperCase())
{
case FurnitureType.BADGE:
return GetSessionDataManager().getBadgeUrl(customParams);
case FurnitureType.ROBOT:
return undefined;
case FurnitureType.FLOOR:
return GetRoomEngine().getFurnitureFloorIconUrl(furniClassId);
case FurnitureType.WALL: {
const furniData = GetSessionDataManager().getWallItemData(furniClassId);
let iconName = '';
if(furniData)
{
switch(furniData.className)
{
case 'floor':
iconName = [ 'th', furniData.className, customParams ].join('_');
break;
case 'wallpaper':
iconName = [ 'th', 'wall', customParams ].join('_');
break;
case 'landscape':
iconName = [ 'th', furniData.className, customParams.replace('.', '_'), '001' ].join('_');
break;
}
if(iconName !== '')
{
const assetUrl = GetConfiguration<string>('catalog.asset.url');
return `${ assetUrl }/${ iconName }.png`;
}
}
return GetRoomEngine().getFurnitureWallIconUrl(furniClassId, customParams);
}
}
return null;
}

View File

@ -0,0 +1,8 @@
import { CatalogPageMessageOfferData, RoomControllerLevel } from '@nitrots/nitro-renderer';
import { GetRoomSession } from '../../../api';
import { ProductTypeEnum } from './ProductTypeEnum';
export const IsCatalogOfferDraggable = (offer: CatalogPageMessageOfferData) =>
{
return ((GetRoomSession().isRoomOwner || (GetRoomSession().isGuildRoom && (GetRoomSession().controllerLevel >= RoomControllerLevel.GUILD_MEMBER))) && (offer.products.length === 1) && (offer.products[0].productType !== ProductTypeEnum.EFFECT) && (offer.products[0].productType !== ProductTypeEnum.HABBO_CLUB))
}

View File

@ -1,5 +1,4 @@
@import './catalog-icon/CatalogIconView'; @import './catalog-icon/CatalogIconView';
@import './gift/CatalogGiftView';
@import './navigation/CatalogNavigationView'; @import './navigation/CatalogNavigationView';
@import './page/CatalogPageView'; @import './page/CatalogPageView';
@import './search/CatalogSearchView';
@import './gift/CatalogGiftView';

View File

@ -1,4 +1,5 @@
.nitro-catalog-gift { .nitro-catalog-gift {
width: 325px;
.gift-preview { .gift-preview {
width: 80px; width: 80px;

View File

@ -1,11 +1,21 @@
.nitro-catalog-navigation { .nitro-catalog-navigation-grid {
border-color: $grid-border-color !important; border-radius: 0.25rem;
background-color: $grid-bg-color !important; border-color: #B6BEC5 !important;
background-color: #CDD3D9;
border: 2px solid;
.navigation-container { .grid-item {
overflow-y: auto; font-size: $font-size-sm;
height: 23px !important;
border-color: unset !important;
background-color: #CDD3D9;
border: 0 !important;
padding: 1px 3px;
i.fas {
color: $black;
font-size: 10px;
padding: 1px;
}
} }
} }
@import './item/CatalogNavigationItemView';
@import './set/CatalogNavigationSetView';

View File

@ -1,5 +1,6 @@
import { INodeData } from '@nitrots/nitro-renderer'; import { INodeData } from '@nitrots/nitro-renderer';
import { FC, useEffect } from 'react'; import { FC, useEffect } from 'react';
import { NitroCardGridView } from '../../../../layout';
import { CatalogSearchView } from '../search/CatalogSearchView'; import { CatalogSearchView } from '../search/CatalogSearchView';
import { CatalogNavigationViewProps } from './CatalogNavigationView.types'; import { CatalogNavigationViewProps } from './CatalogNavigationView.types';
import { CatalogNavigationSetView } from './set/CatalogNavigationSetView'; import { CatalogNavigationSetView } from './set/CatalogNavigationSetView';
@ -23,13 +24,15 @@ export const CatalogNavigationView: FC<CatalogNavigationViewProps> = props =>
}, [ page ]); }, [ page ]);
return ( return (
<> <div className="row h-100">
<div className="d-flex flex-column col gap-2 h-100">
<CatalogSearchView /> <CatalogSearchView />
<div className="border border-2 rounded overflow-hidden nitro-catalog-navigation p-1 h-100"> <div className="d-flex flex-column overflow-hidden nitro-catalog-navigation-grid p-1 h-100">
<div className="navigation-container h-100"> <NitroCardGridView columns={ 1 } gap={ 1 }>
<CatalogNavigationSetView page={ page } isFirstSet={ true } pendingTree={ pendingTree } setPendingTree={ setPendingTree } /> <CatalogNavigationSetView page={ page } isFirstSet={ true } pendingTree={ pendingTree } setPendingTree={ setPendingTree } />
</NitroCardGridView>
</div>
</div> </div>
</div> </div>
</>
); );
} }

View File

@ -1,18 +0,0 @@
.catalog-navigation-item-container {
.catalog-navigation-item {
font-size: $font-size-sm;
border-radius: $border-radius;
i.fas {
color: $black;
font-size: 10px;
padding: 1px;
}
&.active {
padding: 1px 2px;
background-color: $grid-active-bg-color;
}
}
}

View File

@ -1,6 +1,7 @@
import { GetCatalogPageComposer, INodeData } from '@nitrots/nitro-renderer'; import { GetCatalogPageComposer, INodeData } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react'; import { FC, useCallback, useEffect, useState } from 'react';
import { SendMessageHook } from '../../../../../hooks/messages/message-event'; import { SendMessageHook } from '../../../../../hooks/messages/message-event';
import { NitroCardGridItemView } from '../../../../../layout';
import { CatalogMode } from '../../../CatalogView.types'; import { CatalogMode } from '../../../CatalogView.types';
import { CatalogIconView } from '../../catalog-icon/CatalogIconView'; import { CatalogIconView } from '../../catalog-icon/CatalogIconView';
import { ACTIVE_PAGES } from '../CatalogNavigationView'; import { ACTIVE_PAGES } from '../CatalogNavigationView';
@ -70,16 +71,14 @@ export const CatalogNavigationItemView: FC<CatalogNavigationItemViewProps> = pro
}, [ isActive, page ]); }, [ isActive, page ]);
return ( return (
<div className="col pb-1 catalog-navigation-item-container"> <>
<div className={ 'd-flex align-items-center cursor-pointer catalog-navigation-item ' + (isActive ? 'active ': '') } onClick={ event => select(page) }> <NitroCardGridItemView itemActive={ isActive } onClick={ event => select(page) }>
<CatalogIconView icon={ page.icon } /> <CatalogIconView icon={ page.icon } />
<div className="flex-grow-1 text-black text-truncate px-1">{ page.localization }</div> <div className="flex-grow-1 text-black text-truncate">{ page.localization }</div>
{ (page.children.length > 0) && <i className={ 'fas fa-caret-' + (isExpanded ? 'up' : 'down') } /> } { (page.children.length > 0) && <i className={ 'fas fa-caret-' + (isExpanded ? 'up' : 'down') } /> }
</div> </NitroCardGridItemView>
{ isActive && isExpanded && page.children && (page.children.length > 0) && { isActive && isExpanded && page.children && (page.children.length > 0) &&
<div className="d-flex flex-column mt-1"> <CatalogNavigationSetView page={ page } pendingTree={ pendingTree } setPendingTree={ setPendingTree } /> }
<CatalogNavigationSetView page={ page } pendingTree={ pendingTree } setPendingTree={ setPendingTree } /> </>
</div> }
</div>
); );
} }

View File

@ -1,14 +0,0 @@
.catalog-navigation-set-container {
.catalog-navigation-set-container {
padding-left: 5px;
.catalog-navigation-item-container {
padding-right: 0px !important;
}
}
> :last-child {
padding-bottom: 0px !important;
}
}

View File

@ -26,13 +26,13 @@ export const CatalogNavigationSetView: FC<CatalogNavigationSetViewProps> = props
}, [ page, isFirstSet, activeChild, pendingTree ]); }, [ page, isFirstSet, activeChild, pendingTree ]);
return ( return (
<div className="row row-cols-1 g-0 catalog-navigation-set-container w-100"> <>
{ page && (page.children.length > 0) && page.children.map((page, index) => { page && (page.children.length > 0) && page.children.map((page, index) =>
{ {
if(!page.visible) return null; if(!page.visible) return null;
return <CatalogNavigationItemView key={ index } page={ page } isActive={ (activeChild === page) } pendingTree={ pendingTree } setPendingTree={ setPendingTree } setActiveChild={ setActiveChild } /> return <CatalogNavigationItemView key={ index } page={ page } isActive={ (activeChild === page) } pendingTree={ pendingTree } setPendingTree={ setPendingTree } setActiveChild={ setActiveChild } />
}) } }) }
</div> </>
); );
} }

View File

@ -0,0 +1,19 @@
import { FC } from 'react';
import { GetCatalogPageImage, GetCatalogPageText } from '../../common/CatalogUtilities';
import { CatalogPageDetailsViewProps } from './CatalogPageDetailsView.types';
export const CatalogPageDetailsView: FC<CatalogPageDetailsViewProps> = props =>
{
const { pageParser = null } = props;
if(!pageParser) return null;
const imageUrl = GetCatalogPageImage(pageParser, 1);
return (
<div className="d-flex flex-column justify-content-center align-items-center overflow-hidden h-100">
{ imageUrl && <img className="" alt="" src={ imageUrl } /> }
<div className="d-flex flex-column fs-6 text-center text-black lh-sm overflow-auto" dangerouslySetInnerHTML={ { __html: GetCatalogPageText(pageParser, 0) } } />
</div>
);
}

View File

@ -0,0 +1,6 @@
import { CatalogPageMessageParser } from '@nitrots/nitro-renderer';
export interface CatalogPageDetailsViewProps
{
pageParser: CatalogPageMessageParser;
}

View File

@ -1,6 +1,2 @@
@import './layout/CatalogLayout'; @import './layout/CatalogLayout';
@import './offer/CatalogPageOfferView';
@import './offers/CatalogPageOffersView';
@import './product/CatalogProductView';
@import './purchase/CatalogPurchaseView'; @import './purchase/CatalogPurchaseView';
@import './search-result/CatalogLayoutSearchResultView';

View File

@ -1,10 +1,3 @@
@import './badge-display/CatalogLayoutBadgeDisplayView';
@import './default/CatalogLayoutDefaultView';
@import './frontpage4/CatalogLayoutFrontpage4View'; @import './frontpage4/CatalogLayoutFrontpage4View';
@import './pets/CatalogLayoutPetView';
@import './pets3/CatalogLayoutPets3View';
@import './single-bundle/CatalogLayoutSingleBundleView';
@import './spaces-new/CatalogLayoutSpacesView';
@import './trophies/CatalogLayoutTrophiesView';
@import './vip-buy/CatalogLayoutVipBuyView';
@import './info-loyalty/CatalogLayoutInfoLoyaltyView.scss'; @import './info-loyalty/CatalogLayoutInfoLoyaltyView.scss';
@import './vip-buy/CatalogLayoutVipBuyView';

View File

@ -1,7 +0,0 @@
.nitro-catalog-layout-badge-display {
.inventory-badge-grid {
height: 200px;
max-height: 200px;
}
}

View File

@ -1,5 +1,5 @@
import { StringDataType } from '@nitrots/nitro-renderer'; import { StringDataType } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../../api'; import { LocalizeText } from '../../../../../../api';
import { InventoryBadgesUpdatedEvent, SetRoomPreviewerStuffDataEvent } from '../../../../../../events'; import { InventoryBadgesUpdatedEvent, SetRoomPreviewerStuffDataEvent } from '../../../../../../events';
import { InventoryBadgesRequestEvent } from '../../../../../../events/inventory/InventoryBadgesRequestEvent'; import { InventoryBadgesRequestEvent } from '../../../../../../events/inventory/InventoryBadgesRequestEvent';
@ -7,11 +7,9 @@ import { dispatchUiEvent, useUiEvent } from '../../../../../../hooks';
import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView'; import { NitroCardGridItemView } from '../../../../../../layout/card/grid/item/NitroCardGridItemView';
import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView'; import { NitroCardGridView } from '../../../../../../layout/card/grid/NitroCardGridView';
import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView';
import { GetOfferName } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext'; import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
import { CatalogLayoutBadgeDisplayViewProps } from './CatalogLayoutBadgeDisplayView.types'; import { CatalogLayoutBadgeDisplayViewProps } from './CatalogLayoutBadgeDisplayView.types';
export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutBadgeDisplayViewProps> = props => export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutBadgeDisplayViewProps> = props =>
@ -32,18 +30,6 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutBadgeDisplayViewProp
useUiEvent(InventoryBadgesUpdatedEvent.BADGES_UPDATED, onInventoryBadgesUpdatedEvent); useUiEvent(InventoryBadgesUpdatedEvent.BADGES_UPDATED, onInventoryBadgesUpdatedEvent);
const badgeElements = useMemo(() =>
{
return badges.map(code =>
{
return (
<NitroCardGridItemView key={ code } itemActive={ (currentBadge === code) } onMouseDown={ event => setCurrentBadge(code) }>
<BadgeImageView badgeCode={ code } />
</NitroCardGridItemView>
);
});
}, [ badges, currentBadge ]);
useEffect(() => useEffect(() =>
{ {
dispatchUiEvent(new InventoryBadgesRequestEvent(InventoryBadgesRequestEvent.REQUEST_BADGES)); dispatchUiEvent(new InventoryBadgesRequestEvent(InventoryBadgesRequestEvent.REQUEST_BADGES));
@ -67,22 +53,26 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutBadgeDisplayViewProp
}, [ currentBadge, activeOffer, roomPreviewer ]); }, [ currentBadge, activeOffer, roomPreviewer ]);
return ( return (
<div className="row h-100 nitro-catalog-layout-badge-display"> <div className="row h-100">
<div className="d-flex flex-column col-7 h-100"> <div className="d-flex flex-column col-7 gap-2 h-100">
<CatalogPageOffersView offers={ pageParser.offers } /> <CatalogPageOffersView className="flex-shrink-0" offers={ pageParser.offers } />
<div className="d-flex flex-column mt-2"> <div className="d-flex flex-column overflow-hidden">
<div className="text-black fw-bold">{ LocalizeText('catalog_selectbadge') }</div> <div className="text-black fw-bold">{ LocalizeText('catalog_selectbadge') }</div>
<NitroCardGridView className="inventory-badge-grid"> <NitroCardGridView>
{ badgeElements } { badges && (badges.length > 0) && badges.map(code =>
{
return (
<NitroCardGridItemView key={ code } itemActive={ (currentBadge === code) } onMouseDown={ event => setCurrentBadge(code) }>
<BadgeImageView badgeCode={ code } />
</NitroCardGridItemView>
);
}) }
</NitroCardGridView> </NitroCardGridView>
</div> </div>
</div> </div>
{ product && <div className="position-relative d-flex flex-column col-5">
<div className="position-relative d-flex flex-column col"> <CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } extra={ currentBadge } disabled={ !currentBadge } />
<CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } /> </div>
<div className="fs-6 text-black mt-1 overflow-hidden">{ GetOfferName(activeOffer) }</div>
<CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ currentBadge } disabled={ !currentBadge } />
</div> }
</div> </div>
); );
} }

View File

@ -1,10 +1,7 @@
import { FC } from 'react'; import { FC } from 'react';
import { LimitedEditionCompletePlateView } from '../../../../../shared/limited-edition/complete-plate/LimitedEditionCompletePlateView';
import { GetCatalogPageImage, GetCatalogPageText, GetOfferName } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext'; import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView';
import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; import { CatalogProductPreviewView } from '../../product-preview/CatalogProductPreviewView';
import { CatalogLayoutDefaultViewProps } from './CatalogLayoutDefaultView.types'; import { CatalogLayoutDefaultViewProps } from './CatalogLayoutDefaultView.types';
export const CatalogLayoutDefaultView: FC<CatalogLayoutDefaultViewProps> = props => export const CatalogLayoutDefaultView: FC<CatalogLayoutDefaultViewProps> = props =>
@ -17,24 +14,12 @@ export const CatalogLayoutDefaultView: FC<CatalogLayoutDefaultViewProps> = props
return ( return (
<div className="row h-100"> <div className="row h-100">
<div className="col-7 h-100"> <div className="d-flex flex-column col-7 h-100">
<CatalogPageOffersView offers={ pageParser.offers } /> <CatalogPageOffersView offers={ pageParser.offers } />
</div> </div>
{ !product && <div className="position-relative d-flex flex-column col-5 gap-2 h-100 overflow-hidden">
<div className="position-relative d-flex flex-column col-5 justify-content-center align-items-center overflow-hidden"> <CatalogProductPreviewView pageParser={ pageParser } activeOffer={ activeOffer } roomPreviewer={ roomPreviewer } />
<div className="d-block mb-2">
<img alt="" src={ GetCatalogPageImage(pageParser, 1) } />
</div> </div>
<div className="fs-6 text-center text-black lh-sm overflow-hidden">{ GetCatalogPageText(pageParser, 0) }</div>
</div> }
{ product &&
<div className="position-relative d-flex flex-column col-5">
<CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 } />
{ product.uniqueLimitedItem &&
<LimitedEditionCompletePlateView uniqueLimitedItemsLeft={ product.uniqueLimitedItemsLeft } uniqueLimitedSeriesSize={ product.uniqueLimitedSeriesSize } /> }
<div className="fs-6 text-black mt-1 overflow-hidden">{ GetOfferName(activeOffer) }</div>
<CatalogPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } />
</div> }
</div> </div>
); );
} }

View File

@ -1,10 +0,0 @@
.nitro-catalog-layout-pets {
.color-button {
position: absolute;
left: 5px;
bottom: 5px;
}
@import './name-approval/CatalogPetNameApprovalView';
}

View File

@ -2,11 +2,13 @@ import { ColorConverter, GetSellablePetPalettesComposer, SellablePetPaletteData
import { FC, useEffect, useMemo, useState } from 'react'; import { FC, useEffect, useMemo, useState } from 'react';
import { GetProductDataForLocalization, LocalizeText } from '../../../../../../api'; import { GetProductDataForLocalization, LocalizeText } from '../../../../../../api';
import { SendMessageHook } from '../../../../../../hooks/messages/message-event'; import { SendMessageHook } from '../../../../../../hooks/messages/message-event';
import { NitroCardGridItemView, NitroCardGridView } from '../../../../../../layout';
import { PetImageView } from '../../../../../shared/pet-image/PetImageView'; import { PetImageView } from '../../../../../shared/pet-image/PetImageView';
import { GetCatalogPageImage, GetCatalogPageText, GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../common/CatalogUtilities'; import { GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../common/CatalogUtilities';
import { useCatalogContext } from '../../../../context/CatalogContext'; import { useCatalogContext } from '../../../../context/CatalogContext';
import { CatalogActions } from '../../../../reducers/CatalogReducer'; import { CatalogActions } from '../../../../reducers/CatalogReducer';
import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView';
import { CatalogPageDetailsView } from '../../../page-details/CatalogPageDetailsView';
import { CatalogLayoutPetViewProps } from './CatalogLayoutPetView.types'; import { CatalogLayoutPetViewProps } from './CatalogLayoutPetView.types';
import { CatalogLayoutPetPurchaseView } from './purchase/CatalogLayoutPetPurchaseView'; import { CatalogLayoutPetPurchaseView } from './purchase/CatalogLayoutPetPurchaseView';
@ -139,35 +141,30 @@ export const CatalogLayoutPetView: FC<CatalogLayoutPetViewProps> = props =>
if(!activeOffer) return null; if(!activeOffer) return null;
return ( return (
<div className="row h-100 nitro-catalog-layout-pets"> <div className="row h-100">
<div className="col-7 h-100"> <div className="d-flex flex-column col-7 h-100">
<div className="row row-cols-5 align-content-start g-0 mb-n1 w-100 h-100 overflow-auto catalog-offers-container single-bundle-items-container"> <NitroCardGridView columns={ 5 }>
{ colorsShowing && (sellableColors.length > 0) && sellableColors.map((colorSet, index) =>
{
return <div key={ index } className="col pe-1 pb-1 catalog-offer-item-container">
<div className={ 'position-relative border border-2 rounded catalog-offer-item cursor-pointer ' + ((selectedColorIndex === index) ? 'active ' : '') } style={ { backgroundColor: ColorConverter.int2rgb(colorSet[0]) } } onClick={ event => setSelectedColorIndex(index) }>
</div>
</div>;
})}
{ !colorsShowing && (sellablePalettes.length > 0) && sellablePalettes.map((palette, index) => { !colorsShowing && (sellablePalettes.length > 0) && sellablePalettes.map((palette, index) =>
{ {
return <div key={ index } className="col pe-1 pb-1 catalog-offer-item-container"> return (
<div className={ 'position-relative border border-2 rounded catalog-offer-item cursor-pointer ' + ((selectedPaletteIndex === index) ? 'active ' : '') } onClick={ event => setSelectedPaletteIndex(index) }> <NitroCardGridItemView key={ index } itemActive={ (selectedPaletteIndex === index) } onClick={ event => setSelectedPaletteIndex(index) }>
<PetImageView typeId={ petIndex } paletteId={ palette.paletteId } direction={ 2 } headOnly={ true } /> <PetImageView typeId={ petIndex } paletteId={ palette.paletteId } direction={ 2 } headOnly={ true } />
</NitroCardGridItemView>
);
})}
{ colorsShowing && (sellableColors.length > 0) && sellableColors.map((colorSet, index) =>
{
return (
<NitroCardGridItemView key={ index } itemActive={ (selectedColorIndex === index) } itemColor={ ColorConverter.int2rgb(colorSet[0]) } onClick={ event => setSelectedColorIndex(index) } />
);
})}
</NitroCardGridView>
</div> </div>
</div>;
}) }
</div>
</div>
{ (petIndex === -1) &&
<div className="position-relative d-flex flex-column col-5 justify-content-center align-items-center">
<div className="d-block mb-2">
<img alt="" src={ GetCatalogPageImage(pageParser, 1) } />
</div>
<div className="fs-6 text-center text-black lh-sm overflow-hidden">{ GetCatalogPageText(pageParser, 0) }</div>
</div> }
{ (petIndex >= 0) &&
<div className="position-relative d-flex flex-column col-5"> <div className="position-relative d-flex flex-column col-5">
{ (petIndex === -1) &&
<CatalogPageDetailsView pageParser={ pageParser } /> }
{ (petIndex >= 0) &&
<>
<CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 }> <CatalogRoomPreviewerView roomPreviewer={ roomPreviewer } height={ 140 }>
{ (petIndex > -1 && petIndex <= 7) && { (petIndex > -1 && petIndex <= 7) &&
<button type="button" className= { 'btn btn-primary btn-sm color-button ' + (colorsShowing ? 'active ' : '') } onClick={ event => setColorsShowing(!colorsShowing) }> <button type="button" className= { 'btn btn-primary btn-sm color-button ' + (colorsShowing ? 'active ' : '') } onClick={ event => setColorsShowing(!colorsShowing) }>
@ -176,7 +173,8 @@ export const CatalogLayoutPetView: FC<CatalogLayoutPetViewProps> = props =>
</CatalogRoomPreviewerView> </CatalogRoomPreviewerView>
<div className="fs-6 text-black mt-1 overflow-hidden">{ petBreedName }</div> <div className="fs-6 text-black mt-1 overflow-hidden">{ petBreedName }</div>
<CatalogLayoutPetPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ petPurchaseString } /> <CatalogLayoutPetPurchaseView offer={ activeOffer } pageId={ pageParser.pageId } extra={ petPurchaseString } />
</div> } </> }
</div>
</div> </div>
); );
} }

View File

@ -6,6 +6,7 @@ import { useUiEvent } from '../../../../../../../hooks/events/ui/ui-event';
import { SendMessageHook } from '../../../../../../../hooks/messages/message-event'; import { SendMessageHook } from '../../../../../../../hooks/messages/message-event';
import { CurrencyIcon } from '../../../../../../shared/currency-icon/CurrencyIcon'; import { CurrencyIcon } from '../../../../../../shared/currency-icon/CurrencyIcon';
import { CatalogPurchaseButtonView } from '../../../purchase/purchase-button/CatalogPurchaseButtonView'; import { CatalogPurchaseButtonView } from '../../../purchase/purchase-button/CatalogPurchaseButtonView';
import { CatalogPurchaseGiftButtonView } from '../../../purchase/purchase-gift-button/CatalogPurchaseGiftButtonView';
import { CatalogPetNameApprovalView } from '../name-approval/CatalogPetNameApprovalView'; import { CatalogPetNameApprovalView } from '../name-approval/CatalogPetNameApprovalView';
import { CatalogLayoutPetPurchaseViewProps } from './CatalogLayoutPetPurchaseView.types'; import { CatalogLayoutPetPurchaseViewProps } from './CatalogLayoutPetPurchaseView.types';
@ -59,6 +60,8 @@ export const CatalogLayoutPetPurchaseView: FC<CatalogLayoutPetPurchaseViewProps>
</div> </div>
<div className="d-flex flex-column mt-1"> <div className="d-flex flex-column mt-1">
<CatalogPurchaseButtonView className="btn-sm w-100" offer={ offer } pageId={ pageId } extra={ extraData } quantity={ 1 } isPurchaseAllowed={ nameApproved } beforePurchase={ beforePurchase } /> <CatalogPurchaseButtonView className="btn-sm w-100" offer={ offer } pageId={ pageId } extra={ extraData } quantity={ 1 } isPurchaseAllowed={ nameApproved } beforePurchase={ beforePurchase } />
{ offer.giftable &&
<CatalogPurchaseGiftButtonView className="btn-sm w-100 mt-1" offer={ offer } pageId={ pageId } extra={ extraData } disabled={ nameApproved } /> }
</div> </div>
</div> </div>
</> </>

Some files were not shown because too many files have changed in this diff Show More