mirror of
https://github.com/billsonnn/nitro-react.git
synced 2025-02-20 18:52:35 +01:00
Merge branch '@update/react-18' into @update/friends
This commit is contained in:
commit
6f865f05ec
86
.eslintrc.js
86
.eslintrc.js
@ -1,86 +0,0 @@
|
||||
module.exports = {
|
||||
'extends': [
|
||||
'react-app',
|
||||
'react-app/jest'
|
||||
],
|
||||
'rules': {
|
||||
'linebreak-style': [
|
||||
'off'
|
||||
],
|
||||
'quotes': [
|
||||
'error',
|
||||
'single'
|
||||
],
|
||||
'brace-style': [
|
||||
'error',
|
||||
'allman',
|
||||
{
|
||||
'allowSingleLine': true
|
||||
}
|
||||
],
|
||||
'object-curly-spacing': [
|
||||
'error',
|
||||
'always'
|
||||
],
|
||||
'keyword-spacing': [
|
||||
'error',
|
||||
{
|
||||
'overrides': {
|
||||
'if': {
|
||||
'after': false
|
||||
},
|
||||
'for': {
|
||||
'after': false
|
||||
},
|
||||
'while': {
|
||||
'after': false
|
||||
},
|
||||
'switch': {
|
||||
'after': false
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/no-explicit-any': [
|
||||
'off'
|
||||
],
|
||||
'@typescript-eslint/ban-ts-comment': [
|
||||
'off'
|
||||
],
|
||||
'@typescript-eslint/no-empty-function': [
|
||||
'error',
|
||||
{
|
||||
'allow': [
|
||||
'functions',
|
||||
'arrowFunctions',
|
||||
'generatorFunctions',
|
||||
'methods',
|
||||
'generatorMethods',
|
||||
'constructors'
|
||||
]
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'off'
|
||||
],
|
||||
'@typescript-eslint/ban-types': [
|
||||
'error',
|
||||
{
|
||||
'types': {
|
||||
'String': true,
|
||||
'Boolean': true,
|
||||
'Number': true,
|
||||
'Symbol': true,
|
||||
'{}': false,
|
||||
'Object': false,
|
||||
'object': false,
|
||||
'Function': false
|
||||
},
|
||||
'extendDefaults': true
|
||||
}
|
||||
],
|
||||
'no-switch-case-fall-through': [
|
||||
'off'
|
||||
]
|
||||
}
|
||||
}
|
55
.eslintrc.json
Normal file
55
.eslintrc.json
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"settings": {
|
||||
"react": {
|
||||
"pragma": "React",
|
||||
"version": "18.0.0"
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:react/recommended",
|
||||
"plugin:react/jsx-runtime",
|
||||
"plugin:react-hooks/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"react",
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"linebreak-style": [ "off" ],
|
||||
"quotes": [ "error", "single" ],
|
||||
"@typescript-eslint/indent": [ "error", 4, { "SwitchCase": 1 } ],
|
||||
"array-bracket-spacing": [ "error", "always" ],
|
||||
"brace-style": [ "error", "allman" ],
|
||||
"react/prop-types": [ "off" ],
|
||||
"object-curly-spacing": [ "error", "always" ],
|
||||
"@typescript-eslint/ban-types": [
|
||||
"error",
|
||||
{
|
||||
"types": {
|
||||
"String": true,
|
||||
"Boolean": true,
|
||||
"Number": true,
|
||||
"Symbol": true,
|
||||
"{}": false,
|
||||
"Object": false,
|
||||
"object": false,
|
||||
"Function": false
|
||||
},
|
||||
"extendDefaults": true
|
||||
}
|
||||
],
|
||||
"no-switch-case-fall-through": [ "off" ]
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
*.scss
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -14,5 +14,7 @@
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
"editor.wordWrap": "on",
|
||||
"emmet.showExpandedAbbreviation": "never"
|
||||
"emmet.showExpandedAbbreviation": "never",
|
||||
"eslint.validate": [ "javascript", "javascriptreact", "html", "typescriptreact" ],
|
||||
"eslint.workingDirectories": [ "./src" ]
|
||||
}
|
||||
|
17
package.json
17
package.json
@ -7,7 +7,8 @@
|
||||
"build": "cross-env SKIP_PREFLIGHT_CHECK=true GENERATE_SOURCEMAP=false IMAGE_INLINE_SIZE_LIMIT=100000 craco build",
|
||||
"build:prod": "npx browserslist@latest --update-db && yarn build",
|
||||
"test": "craco test",
|
||||
"eject": "react-scripts eject"
|
||||
"eject": "react-scripts eject",
|
||||
"eslint": "eslint src --ext .ts,.tsx"
|
||||
},
|
||||
"dependencies": {
|
||||
"@craco/craco": "^6.3.0",
|
||||
@ -20,11 +21,11 @@
|
||||
"cross-env": "^7.0.3",
|
||||
"emoji-toolkit": "^6.6.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react": "^18.0.0",
|
||||
"react-bootstrap": "^2.2.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-scripts": "4.0.3",
|
||||
"react-slider": "^1.3.1",
|
||||
"react-slider": "^2.0.0",
|
||||
"react-transition-group": "^4.4.2",
|
||||
"react-virtualized": "^9.22.3",
|
||||
"react-youtube": "^7.13.1",
|
||||
@ -41,7 +42,13 @@
|
||||
"@types/react-slider": "^1.3.1",
|
||||
"@types/react-transition-group": "^4.4.2",
|
||||
"@types/react-virtualized": "^9.21.13",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.17.0",
|
||||
"@typescript-eslint/parser": "^5.17.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-react": "^7.29.4",
|
||||
"eslint-plugin-react-hooks": "^4.4.0",
|
||||
"react-error-overlay": "6.0.9"
|
||||
}
|
||||
}
|
||||
|
22
src/App.tsx
22
src/App.tsx
@ -14,8 +14,8 @@ export const App: FC<{}> = props =>
|
||||
{
|
||||
const [ isReady, setIsReady ] = useState(false);
|
||||
const [ isError, setIsError ] = useState(false);
|
||||
const [message, setMessage] = useState('Getting Ready');
|
||||
const [percent, setPercent] = useState(0);
|
||||
const [ message, setMessage ] = useState('Getting Ready');
|
||||
const [ percent, setPercent ] = useState(0);
|
||||
|
||||
//@ts-ignore
|
||||
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
|
||||
@ -68,24 +68,24 @@ export const App: FC<{}> = props =>
|
||||
return;
|
||||
case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKING:
|
||||
loadPercent();
|
||||
return;
|
||||
case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKE_FAILED:
|
||||
return;
|
||||
case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKE_FAILED:
|
||||
setIsError(true);
|
||||
setMessage('Handshake Failed');
|
||||
return;
|
||||
case NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED:
|
||||
return;
|
||||
case NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED:
|
||||
loadPercent();
|
||||
|
||||
GetNitroInstance().init();
|
||||
|
||||
if(LegacyExternalInterface.available) LegacyExternalInterface.call('legacyTrack', 'authentication', 'authok', []);
|
||||
return;
|
||||
case NitroCommunicationDemoEvent.CONNECTION_ERROR:
|
||||
return;
|
||||
case NitroCommunicationDemoEvent.CONNECTION_ERROR:
|
||||
setIsError(true);
|
||||
setMessage('Connection Error');
|
||||
return;
|
||||
case NitroCommunicationDemoEvent.CONNECTION_CLOSED:
|
||||
//if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose();
|
||||
return;
|
||||
case NitroCommunicationDemoEvent.CONNECTION_CLOSED:
|
||||
//if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose();
|
||||
|
||||
//setIsError(true);
|
||||
setMessage('Connection Error');
|
||||
|
@ -34,7 +34,7 @@ export class ProductImageUtility
|
||||
}
|
||||
break;
|
||||
case CatalogPageMessageProductData.E:
|
||||
// fx_icon_furniClassId_png
|
||||
// fx_icon_furniClassId_png
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -6,5 +6,6 @@ export class MessengerSettings
|
||||
public userFriendLimit: number = 0,
|
||||
public normalFriendLimit: number = 0,
|
||||
public extendedFriendLimit: number = 0,
|
||||
public categories: FriendCategoryData[] = []) {}
|
||||
public categories: FriendCategoryData[] = [])
|
||||
{}
|
||||
}
|
||||
|
@ -10,5 +10,6 @@ export class TradeUserData
|
||||
public itemCount: number = 0,
|
||||
public creditsCount: number = 0,
|
||||
public accepts: boolean = false,
|
||||
public canTrade: boolean = false) {}
|
||||
public canTrade: boolean = false)
|
||||
{}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ export interface IUnseenItemTracker
|
||||
dispose(): void;
|
||||
resetCategory(category: number): boolean;
|
||||
resetItems(category: number, itemIds: number[]): boolean;
|
||||
resetCategoryIfEmpty(category: number): boolean;
|
||||
isUnseen(category: number, itemId: number): boolean;
|
||||
removeUnseen(category: number, itemId: number): boolean;
|
||||
getIds(category: number): number[];
|
||||
|
@ -37,40 +37,40 @@ export class FurniChooserWidgetHandler extends RoomWidgetHandler
|
||||
const floorItems = GetRoomEngine().getRoomObjects(roomId, RoomObjectCategory.FLOOR);
|
||||
|
||||
wallItems.forEach(roomObject =>
|
||||
{
|
||||
let name = roomObject.type;
|
||||
|
||||
if(name.startsWith('poster'))
|
||||
{
|
||||
let name = roomObject.type;
|
||||
|
||||
if(name.startsWith('poster'))
|
||||
{
|
||||
name = LocalizeText(`poster_${ name.replace('poster', '') }_name`);
|
||||
}
|
||||
else
|
||||
{
|
||||
const typeId = roomObject.model.getValue<number>(RoomObjectVariable.FURNITURE_TYPE_ID);
|
||||
const furniData = GetSessionDataManager().getWallItemData(typeId);
|
||||
|
||||
if(furniData && furniData.name.length) name = furniData.name;
|
||||
}
|
||||
|
||||
items.push(new RoomObjectItem(roomObject.id, RoomObjectCategory.WALL, name));
|
||||
});
|
||||
|
||||
floorItems.forEach(roomObject =>
|
||||
name = LocalizeText(`poster_${ name.replace('poster', '') }_name`);
|
||||
}
|
||||
else
|
||||
{
|
||||
let name = roomObject.type;
|
||||
|
||||
const typeId = roomObject.model.getValue<number>(RoomObjectVariable.FURNITURE_TYPE_ID);
|
||||
const furniData = GetSessionDataManager().getFloorItemData(typeId);
|
||||
const furniData = GetSessionDataManager().getWallItemData(typeId);
|
||||
|
||||
if(furniData && furniData.name.length) name = furniData.name;
|
||||
}
|
||||
|
||||
items.push(new RoomObjectItem(roomObject.id, RoomObjectCategory.FLOOR, name));
|
||||
});
|
||||
items.push(new RoomObjectItem(roomObject.id, RoomObjectCategory.WALL, name));
|
||||
});
|
||||
|
||||
floorItems.forEach(roomObject =>
|
||||
{
|
||||
let name = roomObject.type;
|
||||
|
||||
const typeId = roomObject.model.getValue<number>(RoomObjectVariable.FURNITURE_TYPE_ID);
|
||||
const furniData = GetSessionDataManager().getFloorItemData(typeId);
|
||||
|
||||
if(furniData && furniData.name.length) name = furniData.name;
|
||||
|
||||
items.push(new RoomObjectItem(roomObject.id, RoomObjectCategory.FLOOR, name));
|
||||
});
|
||||
|
||||
items.sort((a, b) =>
|
||||
{
|
||||
return (a.name < b.name) ? -1 : 1;
|
||||
});
|
||||
{
|
||||
return (a.name < b.name) ? -1 : 1;
|
||||
});
|
||||
|
||||
this.container.eventDispatcher.dispatchEvent(new RoomWidgetChooserContentEvent(RoomWidgetChooserContentEvent.FURNI_CHOOSER_CONTENT, items));
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ export class FurnitureInternalLinkHandler extends RoomWidgetHandler
|
||||
|
||||
public get eventTypes(): string[]
|
||||
{
|
||||
return [RoomEngineTriggerWidgetEvent.REQUEST_INTERNAL_LINK];
|
||||
return [ RoomEngineTriggerWidgetEvent.REQUEST_INTERNAL_LINK ];
|
||||
}
|
||||
|
||||
public get messageTypes(): string[]
|
||||
|
@ -49,7 +49,7 @@ export class FurnitureRoomLinkHandler extends RoomWidgetHandler
|
||||
|
||||
public get eventTypes(): string[]
|
||||
{
|
||||
return [RoomEngineTriggerWidgetEvent.REQUEST_ROOM_LINK];
|
||||
return [ RoomEngineTriggerWidgetEvent.REQUEST_ROOM_LINK ];
|
||||
}
|
||||
|
||||
public get messageTypes(): string[]
|
||||
|
@ -63,11 +63,11 @@ export class PollWidgetHandler extends RoomWidgetHandler
|
||||
|
||||
public get eventTypes(): string[]
|
||||
{
|
||||
return [RoomSessionPollEvent.OFFER, RoomSessionPollEvent.ERROR, RoomSessionPollEvent.CONTENT];
|
||||
return [ RoomSessionPollEvent.OFFER, RoomSessionPollEvent.ERROR, RoomSessionPollEvent.CONTENT ];
|
||||
}
|
||||
|
||||
public get messageTypes(): string[]
|
||||
{
|
||||
return [RoomWidgetPollMessage.ANSWER, RoomWidgetPollMessage.REJECT, RoomWidgetPollMessage.START];
|
||||
return [ RoomWidgetPollMessage.ANSWER, RoomWidgetPollMessage.REJECT, RoomWidgetPollMessage.START ];
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler
|
||||
this.processOwnCharacterInfo();
|
||||
break;
|
||||
case RoomWidgetUserActionMessage.START_NAME_CHANGE:
|
||||
// habbo help - start name change
|
||||
// habbo help - start name change
|
||||
break;
|
||||
case RoomWidgetUserActionMessage.REQUEST_PET_UPDATE:
|
||||
break;
|
||||
|
@ -101,7 +101,7 @@ export class RoomWidgetChatHandler extends RoomWidgetHandler implements IAvatarI
|
||||
text = LocalizeText('widget.chatbubble.pettreat', [ 'petname' ], [ username ]);
|
||||
break;
|
||||
case RoomSessionChatEvent.CHAT_TYPE_HAND_ITEM_RECEIVED:
|
||||
text = LocalizeText('widget.chatbubble.handitem', [ 'username', 'handitem' ], [ username, LocalizeText(('handitem' + chatEvent.extraParam))]);
|
||||
text = LocalizeText('widget.chatbubble.handitem', [ 'username', 'handitem' ], [ username, LocalizeText(('handitem' + chatEvent.extraParam)) ]);
|
||||
break;
|
||||
case RoomSessionChatEvent.CHAT_TYPE_MUTE_REMAINING: {
|
||||
const hours = ((chatEvent.extraParam > 0) ? Math.floor((chatEvent.extraParam / 3600)) : 0).toString();
|
||||
|
@ -141,10 +141,10 @@ export class RoomWidgetChatInputHandler extends RoomWidgetHandler
|
||||
if(this.container.roomSession.isRoomOwner || GetSessionDataManager().isModerator)
|
||||
{
|
||||
NotificationUtilities.confirm(LocalizeText('room.confirm.pick_all'), () =>
|
||||
{
|
||||
GetSessionDataManager().sendSpecialCommandMessage(':pickall');
|
||||
},
|
||||
null, null, null, LocalizeText('generic.alert.title'));
|
||||
{
|
||||
GetSessionDataManager().sendSpecialCommandMessage(':pickall');
|
||||
},
|
||||
null, null, null, LocalizeText('generic.alert.title'));
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -35,13 +35,13 @@ export class UserChooserWidgetHandler extends RoomWidgetHandler
|
||||
const userItems = GetRoomEngine().getRoomObjects(roomId, RoomObjectCategory.UNIT);
|
||||
|
||||
userItems.forEach(roomObject =>
|
||||
{
|
||||
const userData = this.container.roomSession.userDataManager.getUserDataByIndex(roomObject.id);
|
||||
{
|
||||
const userData = this.container.roomSession.userDataManager.getUserDataByIndex(roomObject.id);
|
||||
|
||||
if(!userData) return;
|
||||
if(!userData) return;
|
||||
|
||||
items.push(new RoomObjectItem(userData.roomIndex, RoomObjectCategory.UNIT, userData.name));
|
||||
});
|
||||
items.push(new RoomObjectItem(userData.roomIndex, RoomObjectCategory.UNIT, userData.name));
|
||||
});
|
||||
|
||||
items.sort((a, b) =>
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ export class WordQuizWidgetHandler extends RoomWidgetHandler
|
||||
|
||||
public get eventTypes(): string[]
|
||||
{
|
||||
return [RoomSessionWordQuizEvent.ANSWERED, RoomSessionWordQuizEvent.FINISHED, RoomSessionWordQuizEvent.QUESTION];
|
||||
return [ RoomSessionWordQuizEvent.ANSWERED, RoomSessionWordQuizEvent.FINISHED, RoomSessionWordQuizEvent.QUESTION ];
|
||||
}
|
||||
|
||||
public get messageTypes(): string[]
|
||||
|
@ -4,7 +4,7 @@ export class RoomWidgetDanceMessage extends RoomWidgetMessage
|
||||
{
|
||||
public static DANCE: string = 'RWDM_MESSAGE_DANCE';
|
||||
public static NORMAL_STYLE: number = 0;
|
||||
public static CLUB_STYLE: number[] = [2, 3, 4];
|
||||
public static CLUB_STYLE: number[] = [ 2, 3, 4 ];
|
||||
|
||||
private _style: number = 0;
|
||||
|
||||
|
@ -157,7 +157,7 @@ export class NotificationUtilities
|
||||
|
||||
public static handleHotelClosedMessage(open: number, minute: number, thrownOut: boolean): void
|
||||
{
|
||||
this.simpleAlert( LocalizeText(('opening.hours.' + (thrownOut ? 'disconnected' : 'closed')), [ 'h', 'm'], [ this.getTimeZeroPadded(open), this.getTimeZeroPadded(minute) ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title'));
|
||||
this.simpleAlert( LocalizeText(('opening.hours.' + (thrownOut ? 'disconnected' : 'closed')), [ 'h', 'm' ], [ this.getTimeZeroPadded(open), this.getTimeZeroPadded(minute) ]), NotificationAlertType.DEFAULT, null, null, LocalizeText('opening.hours.title'));
|
||||
}
|
||||
|
||||
public static handleHotelMaintenanceMessage(minutesUntilMaintenance: number, duration: number): void
|
||||
|
@ -26,16 +26,16 @@ allowedColours.set('pink', 'pink');
|
||||
function encodeHTML(str: string)
|
||||
{
|
||||
return str.replace(/([\u00A0-\u9999<>&])(.|$)/g, function(full, char, next)
|
||||
{
|
||||
if(char !== '&' || next !== '#')
|
||||
{
|
||||
if(/[\u00A0-\u9999<>&]/.test(next))
|
||||
next = '&#' + next.charCodeAt(0) + ';';
|
||||
{
|
||||
if(char !== '&' || next !== '#')
|
||||
{
|
||||
if(/[\u00A0-\u9999<>&]/.test(next))
|
||||
next = '&#' + next.charCodeAt(0) + ';';
|
||||
|
||||
return '&#' + char.charCodeAt(0) + ';' + next;
|
||||
}
|
||||
return '&#' + char.charCodeAt(0) + ';' + next;
|
||||
}
|
||||
|
||||
return full;
|
||||
return full;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -45,26 +45,26 @@ export const NitroCardAccordionSetView: FC<NitroCardAccordionSetViewProps> = pro
|
||||
const closeFunction = close;
|
||||
|
||||
setClosers(prevValue =>
|
||||
{
|
||||
const newClosers = [ ...prevValue ];
|
||||
{
|
||||
const newClosers = [ ...prevValue ];
|
||||
|
||||
newClosers.push(closeFunction);
|
||||
newClosers.push(closeFunction);
|
||||
|
||||
return newClosers;
|
||||
});
|
||||
return newClosers;
|
||||
});
|
||||
|
||||
return () =>
|
||||
{
|
||||
setClosers(prevValue =>
|
||||
{
|
||||
const newClosers = [ ...prevValue ];
|
||||
{
|
||||
const newClosers = [ ...prevValue ];
|
||||
|
||||
const index = newClosers.indexOf(closeFunction);
|
||||
const index = newClosers.indexOf(closeFunction);
|
||||
|
||||
if(index >= 0) newClosers.splice(index, 1);
|
||||
if(index >= 0) newClosers.splice(index, 1);
|
||||
|
||||
return newClosers;
|
||||
});
|
||||
return newClosers;
|
||||
});
|
||||
}
|
||||
}, [ close, setClosers ]);
|
||||
|
||||
|
@ -2,7 +2,6 @@ import { MouseEventType, TouchEventType } from '@nitrots/nitro-renderer';
|
||||
import { CSSProperties, FC, Key, MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { Base } from '..';
|
||||
import { BatchUpdates } from '../../hooks';
|
||||
import { DraggableWindowPosition } from './DraggableWindowPosition';
|
||||
|
||||
const CURRENT_WINDOWS: HTMLElement[] = [];
|
||||
@ -134,12 +133,9 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
|
||||
offsetX = (document.body.offsetWidth - elementRef.current.offsetWidth) - elementRef.current.offsetLeft;
|
||||
}
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setDelta({ x: 0, y: 0 });
|
||||
setOffset({ x: offsetX, y: offsetY });
|
||||
setIsDragging(false);
|
||||
});
|
||||
setDelta({ x: 0, y: 0 });
|
||||
setOffset({ x: offsetX, y: offsetY });
|
||||
setIsDragging(false);
|
||||
|
||||
if(uniqueKey !== null) POS_MEMORY.set(uniqueKey, { x: offsetX, y: offsetY });
|
||||
}, [ dragHandler, delta, offset, uniqueKey ]);
|
||||
@ -201,11 +197,8 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
|
||||
}
|
||||
}
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setDelta({ x: 0, y: 0 });
|
||||
setOffset({ x: offsetX, y: offsetY });
|
||||
});
|
||||
setDelta({ x: 0, y: 0 });
|
||||
setOffset({ x: offsetX, y: offsetY });
|
||||
|
||||
return () =>
|
||||
{
|
||||
@ -213,7 +206,7 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
|
||||
|
||||
if(index >= 0) CURRENT_WINDOWS.splice(index, 1);
|
||||
}
|
||||
}, [ handleSelector, windowPosition, uniqueKey, disableDrag, bringToTop ]);
|
||||
}, [ handleSelector, windowPosition, uniqueKey, disableDrag, offsetLeft, offsetTop, bringToTop ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@ -261,8 +254,8 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
|
||||
|
||||
return (
|
||||
createPortal(
|
||||
<Base position="absolute" innerRef={ elementRef } className="draggable-window" onMouseDownCapture={ onMouseDown } onTouchStartCapture={ onTouchStart } style={ dragStyle }>
|
||||
{ children }
|
||||
</Base>, document.getElementById('draggable-windows-container'))
|
||||
<Base position="absolute" innerRef={ elementRef } className="draggable-window" onMouseDownCapture={ onMouseDown } onTouchStartCapture={ onTouchStart } style={ dragStyle }>
|
||||
{ children }
|
||||
</Base>, document.getElementById('draggable-windows-container'))
|
||||
);
|
||||
}
|
||||
|
@ -67,7 +67,8 @@ export const LayoutAvatarImageView: FC<LayoutAvatarImageViewProps> = props =>
|
||||
|
||||
setRandomValue(Math.random());
|
||||
},
|
||||
dispose: () => {},
|
||||
dispose: () =>
|
||||
{},
|
||||
disposed: false
|
||||
}, null);
|
||||
|
||||
|
@ -31,7 +31,7 @@ export const LayoutGiftTagView: FC<LayoutGiftTagViewProps> = props =>
|
||||
{ editable && (onChange !== null) &&
|
||||
<textarea className="gift-message h-100" maxLength={ 140 } value={ message } onChange={ (e) => onChange(e.target.value) } placeholder={ LocalizeText('catalog.gift_wrapping_new.message_hint') }></textarea> }
|
||||
{ userName &&
|
||||
<Text italics textEnd className="pe-1">{ LocalizeText('catalog.gift_wrapping_new.message_from', ['name'], [userName]) }</Text> }
|
||||
<Text italics textEnd className="pe-1">{ LocalizeText('catalog.gift_wrapping_new.message_from', [ 'name' ], [ userName ]) }</Text> }
|
||||
</Column>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
@ -15,7 +15,7 @@ export const LayoutNotificationAlertView: FC<LayoutNotificationAlertViewProps> =
|
||||
|
||||
const getClassNames = useMemo(() =>
|
||||
{
|
||||
const newClassNames: string[] = ['nitro-alert'];
|
||||
const newClassNames: string[] = [ 'nitro-alert' ];
|
||||
|
||||
newClassNames.push('nitro-alert-' + type);
|
||||
|
||||
|
@ -35,11 +35,11 @@ export const LayoutNotificationBubbleView: FC<LayoutNotificationBubbleViewProps>
|
||||
if(!fadesOut) return;
|
||||
|
||||
const timeout = setTimeout(() =>
|
||||
{
|
||||
setIsVisible(false);
|
||||
{
|
||||
setIsVisible(false);
|
||||
|
||||
setTimeout(() => close(), 300);
|
||||
}, timeoutMs);
|
||||
setTimeout(() => close(), 300);
|
||||
}, timeoutMs);
|
||||
|
||||
return () => clearTimeout(timeout);
|
||||
}, [ fadesOut, timeoutMs, close ]);
|
||||
|
@ -74,15 +74,15 @@ export const LayoutRoomPreviewerView: FC<LayoutRoomPreviewerViewProps> = props =
|
||||
GetNitroInstance().ticker.add(update);
|
||||
|
||||
const resizeObserver = new ResizeObserver(() =>
|
||||
{
|
||||
if(!roomPreviewer || !elementRef.current) return;
|
||||
{
|
||||
if(!roomPreviewer || !elementRef.current) return;
|
||||
|
||||
const width = elementRef.current.parentElement.offsetWidth;
|
||||
const width = elementRef.current.parentElement.offsetWidth;
|
||||
|
||||
roomPreviewer.modifyRoomCanvas(width, height);
|
||||
roomPreviewer.modifyRoomCanvas(width, height);
|
||||
|
||||
update(-1);
|
||||
});
|
||||
update(-1);
|
||||
});
|
||||
|
||||
resizeObserver.observe(elementRef.current);
|
||||
|
||||
|
@ -8,15 +8,11 @@ interface LayoutLimitedEditionStyledNumberViewProps
|
||||
export const LayoutLimitedEditionStyledNumberView: FC<LayoutLimitedEditionStyledNumberViewProps> = props =>
|
||||
{
|
||||
const { value = 0 } = props;
|
||||
|
||||
const numbers = value.toString().split('');
|
||||
|
||||
return (
|
||||
<>
|
||||
{ numbers.map((number, index) =>
|
||||
{
|
||||
return <i key={ index } className={ 'limited-edition-number n-' + number } />;
|
||||
})}
|
||||
{ numbers.map((number, index) => <i key={ index } className={ 'limited-edition-number n-' + number } />) }
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { AchievementCategory, AddEventLinkTracker, CloneObject, GetAchievementCategoryImageUrl, GetAchievementIsIgnored, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
|
||||
import { Base, Column, LayoutImage, LayoutProgressBar, NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, Text } from '../../common';
|
||||
import { AchievementsUIUnseenCountEvent } from '../../events';
|
||||
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../hooks';
|
||||
import { DispatchUiEvent, UseMessageEventHook } from '../../hooks';
|
||||
import { AchievementCategoryView } from './views/AchievementCategoryView';
|
||||
import { AchievementsCategoryListView } from './views/category-list/AchievementsCategoryListView';
|
||||
|
||||
@ -22,50 +22,50 @@ export const AchievementsView: FC<{}> = props =>
|
||||
const categoryName = achievement.category;
|
||||
|
||||
setAchievementCategories(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
const categoryIndex = newValue.findIndex(existing => (existing.code === categoryName));
|
||||
|
||||
if(categoryIndex === -1)
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
const categoryIndex = newValue.findIndex(existing => (existing.code === categoryName));
|
||||
const category = new AchievementCategory(categoryName);
|
||||
|
||||
if(categoryIndex === -1)
|
||||
category.achievements.push(achievement);
|
||||
|
||||
newValue.push(category);
|
||||
}
|
||||
else
|
||||
{
|
||||
const category = CloneObject(newValue[categoryIndex]);
|
||||
const newAchievements = [ ...category.achievements ];
|
||||
const achievementIndex = newAchievements.findIndex(existing => (existing.achievementId === achievement.achievementId));
|
||||
let previousAchievement: AchievementData = null;
|
||||
|
||||
if(achievementIndex === -1)
|
||||
{
|
||||
const category = new AchievementCategory(categoryName);
|
||||
|
||||
category.achievements.push(achievement);
|
||||
|
||||
newValue.push(category);
|
||||
newAchievements.push(achievement);
|
||||
}
|
||||
else
|
||||
{
|
||||
const category = CloneObject(newValue[categoryIndex]);
|
||||
const newAchievements = [ ...category.achievements ];
|
||||
const achievementIndex = newAchievements.findIndex(existing => (existing.achievementId === achievement.achievementId));
|
||||
let previousAchievement: AchievementData = null;
|
||||
previousAchievement = newAchievements[achievementIndex];
|
||||
|
||||
if(achievementIndex === -1)
|
||||
{
|
||||
newAchievements.push(achievement);
|
||||
}
|
||||
else
|
||||
{
|
||||
previousAchievement = newAchievements[achievementIndex];
|
||||
|
||||
newAchievements[achievementIndex] = achievement;
|
||||
}
|
||||
|
||||
if(!GetAchievementIsIgnored(achievement))
|
||||
{
|
||||
achievement.unseen++;
|
||||
|
||||
if(previousAchievement) achievement.unseen += previousAchievement.unseen;
|
||||
}
|
||||
|
||||
category.achievements = newAchievements;
|
||||
|
||||
newValue[categoryIndex] = category;
|
||||
newAchievements[achievementIndex] = achievement;
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
if(!GetAchievementIsIgnored(achievement))
|
||||
{
|
||||
achievement.unseen++;
|
||||
|
||||
if(previousAchievement) achievement.unseen += previousAchievement.unseen;
|
||||
}
|
||||
|
||||
category.achievements = newAchievements;
|
||||
|
||||
newValue[categoryIndex] = category;
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(AchievementEvent, onAchievementEvent);
|
||||
@ -92,11 +92,8 @@ export const AchievementsView: FC<{}> = props =>
|
||||
existing.achievements.push(achievement);
|
||||
}
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setAchievementCategories(categories);
|
||||
setIsInitalized(true);
|
||||
});
|
||||
setAchievementCategories(categories);
|
||||
setIsInitalized(true);
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(AchievementsEvent, onAchievementsEvent);
|
||||
@ -155,23 +152,23 @@ export const AchievementsView: FC<{}> = props =>
|
||||
const setAchievementSeen = useCallback((code: string, achievementId: number) =>
|
||||
{
|
||||
setAchievementCategories(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
for(const category of newValue)
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
if(category.code !== code) continue;
|
||||
|
||||
for(const category of newValue)
|
||||
for(const achievement of category.achievements)
|
||||
{
|
||||
if(category.code !== code) continue;
|
||||
if(achievement.achievementId !== achievementId) continue;
|
||||
|
||||
for(const achievement of category.achievements)
|
||||
{
|
||||
if(achievement.achievementId !== achievementId) continue;
|
||||
|
||||
achievement.unseen = 0;
|
||||
}
|
||||
achievement.unseen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const linkReceived = useCallback((url: string) =>
|
||||
|
@ -288,15 +288,15 @@ export const AvatarEditorView: FC<{}> = props =>
|
||||
<NitroCardHeaderView headerText={ LocalizeText('avatareditor.title') } onCloseClick={ event => setIsVisible(false) } />
|
||||
<NitroCardTabsView>
|
||||
{ categories && (categories.size > 0) && Array.from(categories.keys()).map(category =>
|
||||
{
|
||||
const isActive = (activeCategory && (activeCategory.name === category));
|
||||
{
|
||||
const isActive = (activeCategory && (activeCategory.name === category));
|
||||
|
||||
return (
|
||||
<NitroCardTabsItemView key={ category } isActive={ isActive } onClick={ event => selectCategory(category) }>
|
||||
{ LocalizeText(`avatareditor.category.${ category }`) }
|
||||
</NitroCardTabsItemView>
|
||||
);
|
||||
})}
|
||||
return (
|
||||
<NitroCardTabsItemView key={ category } isActive={ isActive } onClick={ event => selectCategory(category) }>
|
||||
{ LocalizeText(`avatareditor.category.${ category }`) }
|
||||
</NitroCardTabsItemView>
|
||||
);
|
||||
})}
|
||||
<NitroCardTabsItemView isActive={ isWardrobeVisible } onClick={ event => setIsWardrobeVisible(true) }>
|
||||
{ LocalizeText('avatareditor.category.wardrobe') }
|
||||
</NitroCardTabsItemView>
|
||||
|
@ -5,7 +5,7 @@ import { FigureData } from './FigureData';
|
||||
export class AvatarEditorGridPartItem implements IAvatarImageListener
|
||||
{
|
||||
private static ALPHA_FILTER: NitroAlphaFilter = new NitroAlphaFilter(0.2);
|
||||
private static THUMB_DIRECTIONS: number[] = [2, 6, 0, 4, 3, 1];
|
||||
private static THUMB_DIRECTIONS: number[] = [ 2, 6, 0, 4, 3, 1 ];
|
||||
private static DRAW_ORDER: string[] = [
|
||||
AvatarFigurePartType.LEFT_HAND_ITEM,
|
||||
AvatarFigurePartType.LEFT_HAND,
|
||||
|
@ -26,11 +26,11 @@ function getRandomPartSet(setType: SetType, gender: string, clubLevel: number =
|
||||
if(!setType) return null;
|
||||
|
||||
const options = setType.partSets.getValues().filter(option =>
|
||||
{
|
||||
if(!option.isSelectable || ((option.gender !== 'U') && (option.gender !== gender)) || (option.clubLevel > clubLevel) || (option.isSellable && (figureSetIds.indexOf(option.id) === -1))) return null;
|
||||
{
|
||||
if(!option.isSelectable || ((option.gender !== 'U') && (option.gender !== gender)) || (option.clubLevel > clubLevel) || (option.isSellable && (figureSetIds.indexOf(option.id) === -1))) return null;
|
||||
|
||||
return option;
|
||||
});
|
||||
return option;
|
||||
});
|
||||
|
||||
if(!options || !options.length) return null;
|
||||
|
||||
@ -42,11 +42,11 @@ function getRandomColors(palette: IPalette, partSet: IFigurePartSet, clubLevel:
|
||||
if(!palette) return [];
|
||||
|
||||
const options = palette.colors.getValues().filter(option =>
|
||||
{
|
||||
if(!option.isSelectable || (option.clubLevel > clubLevel)) return null;
|
||||
{
|
||||
if(!option.isSelectable || (option.clubLevel > clubLevel)) return null;
|
||||
|
||||
return option;
|
||||
});
|
||||
return option;
|
||||
});
|
||||
|
||||
if(!options || !options.length) return null;
|
||||
|
||||
|
@ -68,15 +68,15 @@ export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props =>
|
||||
</Flex>
|
||||
</> }
|
||||
{ !model.canSetGender && model.categories && (model.categories.size > 0) && Array.from(model.categories.keys()).map(name =>
|
||||
{
|
||||
const category = model.categories.get(name);
|
||||
{
|
||||
const category = model.categories.get(name);
|
||||
|
||||
return (
|
||||
<Flex center pointer key={ name } className="category-item" onClick={ event => selectCategory(name) }>
|
||||
<AvatarEditorIcon icon={ category.name } selected={ (activeCategory === category) } />
|
||||
</Flex>
|
||||
);
|
||||
})}
|
||||
return (
|
||||
<Flex center pointer key={ name } className="category-item" onClick={ event => selectCategory(name) }>
|
||||
<AvatarEditorIcon icon={ category.name } selected={ (activeCategory === category) } />
|
||||
</Flex>
|
||||
);
|
||||
})}
|
||||
</Column>
|
||||
<Column size={ 5 } overflow="hidden">
|
||||
<AvatarEditorFigureSetView model={ model } category={ activeCategory } setMaxPaletteCount={ setMaxPaletteCount } />
|
||||
|
@ -47,25 +47,25 @@ export const AvatarEditorWardrobeView: FC<AvatarEditorWardrobeViewProps> = props
|
||||
const items: JSX.Element[] = [];
|
||||
|
||||
savedFigures.forEach(([ figureContainer, gender ], index) =>
|
||||
{
|
||||
let clubLevel = 0;
|
||||
{
|
||||
let clubLevel = 0;
|
||||
|
||||
if(figureContainer) clubLevel = GetAvatarRenderManager().getFigureClubLevel(figureContainer, gender);
|
||||
if(figureContainer) clubLevel = GetAvatarRenderManager().getFigureClubLevel(figureContainer, gender);
|
||||
|
||||
items.push(
|
||||
<LayoutGridItem key={ index } position="relative" overflow="hidden" className="nitro-avatar-editor-wardrobe-figure-preview">
|
||||
{ figureContainer &&
|
||||
items.push(
|
||||
<LayoutGridItem key={ index } position="relative" overflow="hidden" className="nitro-avatar-editor-wardrobe-figure-preview">
|
||||
{ figureContainer &&
|
||||
<LayoutAvatarImageView figure={ figureContainer.getFigureString() } gender={ gender } direction={ 2 } /> }
|
||||
<Base className="avatar-shadow" />
|
||||
{ (clubLevel > 0) && <LayoutCurrencyIcon className="position-absolute top-1 start-1" type="hc" /> }
|
||||
<Flex gap={ 1 } className="button-container">
|
||||
<Button variant="link" fullWidth onClick={ event => saveFigureAtWardrobeIndex(index) }>{ LocalizeText('avatareditor.wardrobe.save') }</Button>
|
||||
{ figureContainer &&
|
||||
<Base className="avatar-shadow" />
|
||||
{ (clubLevel > 0) && <LayoutCurrencyIcon className="position-absolute top-1 start-1" type="hc" /> }
|
||||
<Flex gap={ 1 } className="button-container">
|
||||
<Button variant="link" fullWidth onClick={ event => saveFigureAtWardrobeIndex(index) }>{ LocalizeText('avatareditor.wardrobe.save') }</Button>
|
||||
{ figureContainer &&
|
||||
<Button variant="link" fullWidth onClick={ event => wearFigureAtIndex(index) } disabled={ (clubLevel > GetClubMemberLevel()) }>{ LocalizeText('generic_usable.button.use') }</Button> }
|
||||
</Flex>
|
||||
</LayoutGridItem>
|
||||
);
|
||||
});
|
||||
</Flex>
|
||||
</LayoutGridItem>
|
||||
);
|
||||
});
|
||||
|
||||
return items;
|
||||
}, [ savedFigures, saveFigureAtWardrobeIndex, wearFigureAtIndex ]);
|
||||
|
@ -70,13 +70,13 @@ export const CameraWidgetView: FC<{}> = props =>
|
||||
return;
|
||||
case 'delete':
|
||||
setCameraRoll(prevValue =>
|
||||
{
|
||||
const clone = [ ...prevValue ];
|
||||
{
|
||||
const clone = [ ...prevValue ];
|
||||
|
||||
clone.splice(selectedPictureIndex, 1);
|
||||
clone.splice(selectedPictureIndex, 1);
|
||||
|
||||
return clone;
|
||||
});
|
||||
return clone;
|
||||
});
|
||||
return;
|
||||
case 'editor_cancel':
|
||||
setMode(MODE_CAPTURE);
|
||||
@ -106,10 +106,10 @@ export const CameraWidgetView: FC<{}> = props =>
|
||||
return;
|
||||
case 'toggle':
|
||||
setMode(prevValue =>
|
||||
{
|
||||
if(!prevValue) return MODE_CAPTURE;
|
||||
else return MODE_NONE;
|
||||
});
|
||||
{
|
||||
if(!prevValue) return MODE_CAPTURE;
|
||||
else return MODE_NONE;
|
||||
});
|
||||
return;
|
||||
}
|
||||
}, []);
|
||||
|
@ -4,5 +4,6 @@ export class CameraPicture
|
||||
{
|
||||
constructor(
|
||||
public texture: NitroTexture,
|
||||
public imageUrl: string) {}
|
||||
public imageUrl: string)
|
||||
{}
|
||||
}
|
||||
|
@ -2,5 +2,6 @@ export class CameraPictureThumbnail
|
||||
{
|
||||
constructor(
|
||||
public effectName: string,
|
||||
public thumbnailUrl: string) {}
|
||||
public thumbnailUrl: string)
|
||||
{}
|
||||
}
|
||||
|
@ -80,9 +80,9 @@ export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =
|
||||
{ (cameraRoll.length > 0) &&
|
||||
<Flex gap={ 2 } justifyContent="center" className="camera-roll d-flex justify-content-center py-2">
|
||||
{ cameraRoll.map((picture, index) =>
|
||||
{
|
||||
return <img alt="" key={ index } src={ picture.imageUrl } onClick={ event => setSelectedPictureIndex(index) } />;
|
||||
}) }
|
||||
{
|
||||
return <img alt="" key={ index } src={ picture.imageUrl } onClick={ event => setSelectedPictureIndex(index) } />;
|
||||
}) }
|
||||
</Flex> }
|
||||
</Column>
|
||||
</DraggableWindow>
|
||||
|
@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { GetConfiguration, GetRoomEngine, LocalizeText, SendMessageComposer } from '../../../../api';
|
||||
import { Button, Column, Flex, LayoutCurrencyIcon, LayoutImage, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
||||
import { InventoryEvent } from '../../../../events';
|
||||
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../../../hooks';
|
||||
import { DispatchUiEvent, UseMessageEventHook } from '../../../../hooks';
|
||||
|
||||
export interface CameraWidgetCheckoutViewProps
|
||||
{
|
||||
@ -27,11 +27,8 @@ export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props
|
||||
|
||||
const onCameraPurchaseOKMessageEvent = useCallback((event: CameraPurchaseOKMessageEvent) =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setPicturesBought(value => (value + 1));
|
||||
setIsWaiting(false);
|
||||
});
|
||||
setPicturesBought(value => (value + 1));
|
||||
setIsWaiting(false);
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(CameraPurchaseOKMessageEvent, onCameraPurchaseOKMessageEvent);
|
||||
@ -40,13 +37,10 @@ export const CameraWidgetCheckoutView: FC<CameraWidgetCheckoutViewProps> = props
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setPublishUrl(parser.extraDataId);
|
||||
setPublishCooldown(parser.secondsToWait);
|
||||
setWasPicturePublished(parser.ok);
|
||||
setIsWaiting(false);
|
||||
});
|
||||
setPublishUrl(parser.extraDataId);
|
||||
setPublishCooldown(parser.secondsToWait);
|
||||
setWasPicturePublished(parser.ok);
|
||||
setIsWaiting(false);
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(CameraPublishStatusMessageEvent, onCameraPublishStatusMessageEvent);
|
||||
|
@ -76,14 +76,14 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
||||
if(index === -1) return;
|
||||
|
||||
setSelectedEffects(prevValue =>
|
||||
{
|
||||
const clone = [ ...prevValue ];
|
||||
const currentEffect = clone[index];
|
||||
{
|
||||
const clone = [ ...prevValue ];
|
||||
const currentEffect = clone[index];
|
||||
|
||||
clone[getCurrentEffectIndex] = new RoomCameraWidgetSelectedEffect(currentEffect.effect, alpha);
|
||||
clone[getCurrentEffectIndex] = new RoomCameraWidgetSelectedEffect(currentEffect.effect, alpha);
|
||||
|
||||
return clone;
|
||||
});
|
||||
return clone;
|
||||
});
|
||||
}, [ getCurrentEffectIndex, setSelectedEffects ]);
|
||||
|
||||
const getCurrentPictureUrl = useMemo(() =>
|
||||
@ -117,9 +117,9 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
||||
if(!effect) return;
|
||||
|
||||
setSelectedEffects(prevValue =>
|
||||
{
|
||||
return [ ...prevValue, new RoomCameraWidgetSelectedEffect(effect, 1) ];
|
||||
});
|
||||
{
|
||||
return [ ...prevValue, new RoomCameraWidgetSelectedEffect(effect, 1) ];
|
||||
});
|
||||
|
||||
setSelectedEffectName(effect.name);
|
||||
return;
|
||||
@ -130,13 +130,13 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
||||
if(existingIndex === -1) return;
|
||||
|
||||
setSelectedEffects(prevValue =>
|
||||
{
|
||||
const clone = [ ...prevValue ];
|
||||
{
|
||||
const clone = [ ...prevValue ];
|
||||
|
||||
clone.splice(existingIndex, 1);
|
||||
clone.splice(existingIndex, 1);
|
||||
|
||||
return clone;
|
||||
});
|
||||
return clone;
|
||||
});
|
||||
|
||||
if(selectedEffectName === effectName) setSelectedEffectName(null);
|
||||
return;
|
||||
@ -177,9 +177,9 @@ export const CameraWidgetEditorView: FC<CameraWidgetEditorViewProps> = props =>
|
||||
<NitroCardHeaderView headerText={ LocalizeText('camera.editor.button.text') } onCloseClick={ event => processAction('close') } />
|
||||
<NitroCardTabsView>
|
||||
{ TABS.map(tab =>
|
||||
{
|
||||
return <NitroCardTabsItemView key={ tab } isActive={ currentTab === tab } onClick={ event => processAction('change_tab', tab) }><i className={ 'icon icon-camera-' + tab }></i></NitroCardTabsItemView>
|
||||
}) }
|
||||
{
|
||||
return <NitroCardTabsItemView key={ tab } isActive={ currentTab === tab } onClick={ event => processAction('change_tab', tab) }><i className={ 'icon icon-camera-' + tab }></i></NitroCardTabsItemView>
|
||||
}) }
|
||||
</NitroCardTabsView>
|
||||
<NitroCardContentView>
|
||||
<Grid>
|
||||
|
@ -20,12 +20,12 @@ export const CameraWidgetEffectListView: FC<CameraWidgetEffectListViewProps> = p
|
||||
return (
|
||||
<AutoGrid columnCount={ 2 } columnMinHeight={ 60 }>
|
||||
{ effects && (effects.length > 0) && effects.map((effect, index) =>
|
||||
{
|
||||
const thumbnailUrl = (thumbnails.find(thumbnail => (thumbnail.effectName === effect.name)));
|
||||
const isActive = (selectedEffects.findIndex(selectedEffect => (selectedEffect.effect.name === effect.name)) > -1);
|
||||
{
|
||||
const thumbnailUrl = (thumbnails.find(thumbnail => (thumbnail.effectName === effect.name)));
|
||||
const isActive = (selectedEffects.findIndex(selectedEffect => (selectedEffect.effect.name === effect.name)) > -1);
|
||||
|
||||
return <CameraWidgetEffectListItemView key={ index } effect={ effect } thumbnailUrl={ ((thumbnailUrl && thumbnailUrl.thumbnailUrl) || null) } isActive={ isActive } isLocked={ (effect.minLevel > myLevel) } selectEffect={ () => processAction('select_effect', effect.name) } removeEffect={ () => processAction('remove_effect', effect.name) } />
|
||||
}) }
|
||||
return <CameraWidgetEffectListItemView key={ index } effect={ effect } thumbnailUrl={ ((thumbnailUrl && thumbnailUrl.thumbnailUrl) || null) } isActive={ isActive } isLocked={ (effect.minLevel > myLevel) } selectEffect={ () => processAction('select_effect', effect.name) } removeEffect={ () => processAction('remove_effect', effect.name) } />
|
||||
}) }
|
||||
</AutoGrid>
|
||||
);
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ export const CalendarView: FC<CalendarViewProps> = props =>
|
||||
<Column size={ 10 }>
|
||||
<Flex justifyContent="between" alignItems="center" gap={ 1 }>
|
||||
<Column gap={ 1 }>
|
||||
<Text fontSize={ 3 }>{ LocalizeText('campaign.calendar.heading.day', ['number'], [(selectedDay + 1).toString()]) }</Text>
|
||||
<Text fontSize={ 3 }>{ LocalizeText('campaign.calendar.heading.day', [ 'number' ], [ (selectedDay + 1).toString() ]) }</Text>
|
||||
<Text>{ dayMessage(selectedDay) }</Text>
|
||||
</Column>
|
||||
<div>
|
||||
@ -121,16 +121,16 @@ export const CalendarView: FC<CalendarViewProps> = props =>
|
||||
</Flex>
|
||||
<Column center fullWidth>
|
||||
<Grid fit columnCount={ TOTAL_SHOWN_ITEMS } gap={ 1 }>
|
||||
{ [...Array(TOTAL_SHOWN_ITEMS)].map((e, i) =>
|
||||
{
|
||||
const day = (index + i);
|
||||
{ [ ...Array(TOTAL_SHOWN_ITEMS) ].map((e, i) =>
|
||||
{
|
||||
const day = (index + i);
|
||||
|
||||
return (
|
||||
<Column key={ i } overflow="hidden">
|
||||
<CalendarItemView itemId={ day } state={ getDayState(day) } active={ (selectedDay === day) } product={ receivedProducts.has(day) ? receivedProducts.get(day) : null } onClick={ onClickItem } />
|
||||
</Column>
|
||||
);
|
||||
}) }
|
||||
return (
|
||||
<Column key={ i } overflow="hidden">
|
||||
<CalendarItemView itemId={ day } state={ getDayState(day) } active={ (selectedDay === day) } product={ receivedProducts.has(day) ? receivedProducts.get(day) : null } onClick={ onClickItem } />
|
||||
</Column>
|
||||
);
|
||||
}) }
|
||||
</Grid>
|
||||
</Column>
|
||||
<Flex center>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CampaignCalendarData, CampaignCalendarDataMessageEvent, CampaignCalendarDoorOpenedMessageEvent, OpenCampaignCalendarDoorAsStaffComposer, OpenCampaignCalendarDoorComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { AddEventLinkTracker, CalendarItem, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
|
||||
import { BatchUpdates, UseMessageEventHook } from '../../hooks';
|
||||
import { UseMessageEventHook } from '../../hooks';
|
||||
import { CalendarView } from './CalendarView';
|
||||
|
||||
export const CampaignView: FC<{}> = props =>
|
||||
@ -31,28 +31,25 @@ export const CampaignView: FC<{}> = props =>
|
||||
|
||||
if(parser.doorOpened)
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
setCalendarData(prev =>
|
||||
{
|
||||
setCalendarData(prev =>
|
||||
{
|
||||
const copy = prev.clone();
|
||||
copy.openedDays.push(lastOpenAttempt);
|
||||
|
||||
return copy;
|
||||
});
|
||||
|
||||
setReceivedProducts(prev =>
|
||||
{
|
||||
const copy = new Map(prev);
|
||||
copy.set(lastAttempt, new CalendarItem(parser.productName, parser.customImage,parser.furnitureClassName));
|
||||
|
||||
return copy;
|
||||
});
|
||||
const copy = prev.clone();
|
||||
copy.openedDays.push(lastOpenAttempt);
|
||||
|
||||
return copy;
|
||||
});
|
||||
|
||||
setReceivedProducts(prev =>
|
||||
{
|
||||
const copy = new Map(prev);
|
||||
copy.set(lastAttempt, new CalendarItem(parser.productName, parser.customImage,parser.furnitureClassName));
|
||||
|
||||
return copy;
|
||||
});
|
||||
}
|
||||
|
||||
setLastOpenAttempt(-1);
|
||||
}, [lastOpenAttempt]);
|
||||
}, [ lastOpenAttempt ]);
|
||||
|
||||
UseMessageEventHook(CampaignCalendarDoorOpenedMessageEvent, onCampaignCalendarDoorOpenedMessageEvent);
|
||||
|
||||
@ -71,7 +68,7 @@ export const CampaignView: FC<{}> = props =>
|
||||
{
|
||||
SendMessageComposer(new OpenCampaignCalendarDoorComposer(calendarData.campaignName, id));
|
||||
}
|
||||
}, [calendarData]);
|
||||
}, [ calendarData ]);
|
||||
|
||||
const onCalendarClose = useCallback(() =>
|
||||
{
|
||||
@ -101,7 +98,7 @@ export const CampaignView: FC<{}> = props =>
|
||||
{
|
||||
RemoveLinkEventTracker(linkTracker);
|
||||
}
|
||||
}, [onLinkReceived]);
|
||||
}, [ onLinkReceived ]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -3,7 +3,7 @@ import { GuildMembershipsMessageEvent } from '@nitrots/nitro-renderer/src/nitro/
|
||||
import { FC, useCallback } from 'react';
|
||||
import { GetFurnitureData, GetProductDataForLocalization, LocalizeText, NotificationAlertType, NotificationUtilities, ProductTypeEnum } from '../../api';
|
||||
import { CatalogGiftReceiverNotFoundEvent, CatalogNameResultEvent, CatalogPurchasedEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent } from '../../events';
|
||||
import { BatchUpdates, DispatchUiEvent, UseMessageEventHook } from '../../hooks';
|
||||
import { DispatchUiEvent, UseMessageEventHook } from '../../hooks';
|
||||
import { useCatalogContext } from './CatalogContext';
|
||||
import { CatalogNode } from './common/CatalogNode';
|
||||
import { CatalogPetPalette } from './common/CatalogPetPalette';
|
||||
@ -43,11 +43,8 @@ export const CatalogMessageHandler: FC<{}> = props =>
|
||||
return catalogNode;
|
||||
}
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setRootNode(getCatalogNode(parser.root, 0, null));
|
||||
setOffersToNodes(offers);
|
||||
});
|
||||
setRootNode(getCatalogNode(parser.root, 0, null));
|
||||
setOffersToNodes(offers);
|
||||
}, [ setRootNode, setOffersToNodes ]);
|
||||
|
||||
const onCatalogPageMessageEvent = useCallback((event: CatalogPageMessageEvent) =>
|
||||
@ -77,17 +74,14 @@ export const CatalogMessageHandler: FC<{}> = props =>
|
||||
if((currentType === CatalogType.NORMAL) || ((purchasableOffer.pricingModel !== Offer.PRICING_MODEL_BUNDLE) && (purchasableOffer.pricingModel !== Offer.PRICING_MODEL_MULTI))) purchasableOffers.push(purchasableOffer);
|
||||
}
|
||||
|
||||
BatchUpdates(() =>
|
||||
if(parser.frontPageItems && parser.frontPageItems.length) setFrontPageItems(parser.frontPageItems);
|
||||
|
||||
setIsBusy(false);
|
||||
|
||||
if(pageId === parser.pageId)
|
||||
{
|
||||
if(parser.frontPageItems && parser.frontPageItems.length) setFrontPageItems(parser.frontPageItems);
|
||||
|
||||
setIsBusy(false);
|
||||
|
||||
if(pageId === parser.pageId)
|
||||
{
|
||||
showCatalogPage(parser.pageId, parser.layoutCode, new PageLocalization(parser.localization.images.concat(), parser.localization.texts.concat()), purchasableOffers, parser.offerId, parser.acceptSeasonCurrencyAsCredits);
|
||||
}
|
||||
});
|
||||
showCatalogPage(parser.pageId, parser.layoutCode, new PageLocalization(parser.localization.images.concat(), parser.localization.texts.concat()), purchasableOffers, parser.offerId, parser.acceptSeasonCurrencyAsCredits);
|
||||
}
|
||||
}, [ currentType, pageId, setFrontPageItems, setIsBusy, showCatalogPage ]);
|
||||
|
||||
const onPurchaseOKMessageEvent = useCallback((event: PurchaseOKMessageEvent) =>
|
||||
@ -155,13 +149,13 @@ export const CatalogMessageHandler: FC<{}> = props =>
|
||||
if(offer.product && (offer.product.productType === ProductTypeEnum.WALL))
|
||||
{
|
||||
setPurchaseOptions(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.extraData =( offer.product.extraParam || null);
|
||||
newValue.extraData =( offer.product.extraParam || null);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,27 +168,27 @@ export const CatalogMessageHandler: FC<{}> = props =>
|
||||
const petPalette = new CatalogPetPalette(parser.productCode, parser.palettes.slice());
|
||||
|
||||
setCatalogOptions(prevValue =>
|
||||
{
|
||||
const petPalettes = [];
|
||||
|
||||
if(prevValue.petPalettes) petPalettes.push(...prevValue.petPalettes);
|
||||
|
||||
for(let i = 0; i < petPalettes.length; i++)
|
||||
{
|
||||
const petPalettes = [];
|
||||
const palette = petPalettes[i];
|
||||
|
||||
if(prevValue.petPalettes) petPalettes.push(...prevValue.petPalettes);
|
||||
|
||||
for(let i = 0; i < petPalettes.length; i++)
|
||||
if(palette.breed === petPalette.breed)
|
||||
{
|
||||
const palette = petPalettes[i];
|
||||
petPalettes.splice(i, 1);
|
||||
|
||||
if(palette.breed === petPalette.breed)
|
||||
{
|
||||
petPalettes.splice(i, 1);
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
petPalettes.push(petPalette);
|
||||
petPalettes.push(petPalette);
|
||||
|
||||
return { ...prevValue, petPalettes };
|
||||
});
|
||||
return { ...prevValue, petPalettes };
|
||||
});
|
||||
}, [ setCatalogOptions ]);
|
||||
|
||||
const onApproveNameMessageEvent = useCallback((event: ApproveNameMessageEvent) =>
|
||||
@ -214,11 +208,11 @@ export const CatalogMessageHandler: FC<{}> = props =>
|
||||
const parser = event.getParser();
|
||||
|
||||
setCatalogOptions(prevValue =>
|
||||
{
|
||||
const clubOffers = parser.offers;
|
||||
{
|
||||
const clubOffers = parser.offers;
|
||||
|
||||
return { ...prevValue, clubOffers };
|
||||
});
|
||||
return { ...prevValue, clubOffers };
|
||||
});
|
||||
}, [ setCatalogOptions ]);
|
||||
|
||||
const onGuildMembershipsMessageEvent = useCallback((event: GuildMembershipsMessageEvent) =>
|
||||
@ -226,11 +220,11 @@ export const CatalogMessageHandler: FC<{}> = props =>
|
||||
const parser = event.getParser();
|
||||
|
||||
setCatalogOptions(prevValue =>
|
||||
{
|
||||
const groups = parser.groups;
|
||||
{
|
||||
const groups = parser.groups;
|
||||
|
||||
return { ...prevValue, groups };
|
||||
});
|
||||
return { ...prevValue, groups };
|
||||
});
|
||||
}, [ setCatalogOptions ]);
|
||||
|
||||
const onUserSubscriptionEvent = useCallback((event: UserSubscriptionEvent) =>
|
||||
@ -238,16 +232,16 @@ export const CatalogMessageHandler: FC<{}> = props =>
|
||||
const parser = event.getParser();
|
||||
|
||||
setCatalogOptions(prevValue =>
|
||||
{
|
||||
const subscriptionInfo = new SubscriptionInfo(
|
||||
Math.max(0, parser.daysToPeriodEnd),
|
||||
Math.max(0, parser.periodsSubscribedAhead),
|
||||
parser.isVip,
|
||||
parser.pastClubDays,
|
||||
parser.pastVipDays);
|
||||
{
|
||||
const subscriptionInfo = new SubscriptionInfo(
|
||||
Math.max(0, parser.daysToPeriodEnd),
|
||||
Math.max(0, parser.periodsSubscribedAhead),
|
||||
parser.isVip,
|
||||
parser.pastClubDays,
|
||||
parser.pastVipDays);
|
||||
|
||||
return { ...prevValue, subscriptionInfo };
|
||||
});
|
||||
return { ...prevValue, subscriptionInfo };
|
||||
});
|
||||
}, [ setCatalogOptions ]);
|
||||
|
||||
const onGiftWrappingConfigurationEvent = useCallback((event: GiftWrappingConfigurationEvent) =>
|
||||
@ -255,11 +249,11 @@ export const CatalogMessageHandler: FC<{}> = props =>
|
||||
const parser = event.getParser();
|
||||
|
||||
setCatalogOptions(prevValue =>
|
||||
{
|
||||
const giftConfiguration = new GiftWrappingConfiguration(parser);
|
||||
{
|
||||
const giftConfiguration = new GiftWrappingConfiguration(parser);
|
||||
|
||||
return { ...prevValue, giftConfiguration };
|
||||
});
|
||||
return { ...prevValue, giftConfiguration };
|
||||
});
|
||||
}, [ setCatalogOptions ]);
|
||||
|
||||
const onMarketplaceMakeOfferResult = useCallback((event: MarketplaceMakeOfferResult) =>
|
||||
@ -288,11 +282,11 @@ export const CatalogMessageHandler: FC<{}> = props =>
|
||||
const parser = event.getParser();
|
||||
|
||||
setCatalogOptions(prevValue =>
|
||||
{
|
||||
const clubGifts = parser;
|
||||
{
|
||||
const clubGifts = parser;
|
||||
|
||||
return { ...prevValue, clubGifts };
|
||||
});
|
||||
return { ...prevValue, clubGifts };
|
||||
});
|
||||
}, [ setCatalogOptions ]);
|
||||
|
||||
UseMessageEventHook(CatalogPagesListEvent, onCatalogPagesListEvent);
|
||||
|
@ -3,7 +3,7 @@ import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { AddEventLinkTracker, GetRoomEngine, LocalizeText, NotificationAlertType, NotificationUtilities, PlaySound, RemoveLinkEventTracker, SendMessageComposer, SoundNames } from '../../api';
|
||||
import { Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../common';
|
||||
import { CatalogPurchasedEvent } from '../../events';
|
||||
import { BatchUpdates, UseMessageEventHook, UseUiEvent } from '../../hooks';
|
||||
import { UseMessageEventHook, UseUiEvent } from '../../hooks';
|
||||
import { CatalogContextProvider } from './CatalogContext';
|
||||
import { CatalogMessageHandler } from './CatalogMessageHandler';
|
||||
import { CatalogPage } from './common/CatalogPage';
|
||||
@ -44,19 +44,16 @@ export const CatalogView: FC<{}> = props =>
|
||||
|
||||
const resetState = useCallback(() =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setPageId(-1);
|
||||
setPreviousPageId(-1);
|
||||
setRootNode(null);
|
||||
setOffersToNodes(null);
|
||||
setCurrentPage(null);
|
||||
setCurrentOffer(null);
|
||||
setActiveNodes([]);
|
||||
setSearchResult(null);
|
||||
setFrontPageItems([]);
|
||||
setIsVisible(false);
|
||||
});
|
||||
setPageId(-1);
|
||||
setPreviousPageId(-1);
|
||||
setRootNode(null);
|
||||
setOffersToNodes(null);
|
||||
setCurrentPage(null);
|
||||
setCurrentOffer(null);
|
||||
setActiveNodes([]);
|
||||
setSearchResult(null);
|
||||
setFrontPageItems([]);
|
||||
setIsVisible(false);
|
||||
}, []);
|
||||
|
||||
const onCatalogPublishedMessageEvent = useCallback((event: CatalogPublishedMessageEvent) =>
|
||||
@ -119,11 +116,8 @@ export const CatalogView: FC<{}> = props =>
|
||||
{
|
||||
if(pageId < 0) return;
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setIsBusy(true);
|
||||
setPageId(pageId);
|
||||
});
|
||||
setIsBusy(true);
|
||||
setPageId(pageId);
|
||||
|
||||
if(pageId > -1) SendMessageComposer(new GetCatalogPageComposer(pageId, offerId, currentType));
|
||||
}, [ currentType ]);
|
||||
@ -132,24 +126,21 @@ export const CatalogView: FC<{}> = props =>
|
||||
{
|
||||
const catalogPage = (new CatalogPage(pageId, layoutCode, localization, offers, acceptSeasonCurrencyAsCredits) as ICatalogPage);
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setCurrentPage(catalogPage);
|
||||
setPreviousPageId(prevValue => ((pageId !== -1) ? pageId : prevValue));
|
||||
setNavigationHidden(false);
|
||||
setCurrentPage(catalogPage);
|
||||
setPreviousPageId(prevValue => ((pageId !== -1) ? pageId : prevValue));
|
||||
setNavigationHidden(false);
|
||||
|
||||
if((offerId > -1) && catalogPage.offers.length)
|
||||
if((offerId > -1) && catalogPage.offers.length)
|
||||
{
|
||||
for(const offer of catalogPage.offers)
|
||||
{
|
||||
for(const offer of catalogPage.offers)
|
||||
{
|
||||
if(offer.offerId !== offerId) continue;
|
||||
|
||||
setCurrentOffer(offer)
|
||||
|
||||
break;
|
||||
}
|
||||
if(offer.offerId !== offerId) continue;
|
||||
|
||||
setCurrentOffer(offer)
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const activateNode = useCallback((targetNode: ICatalogNode, offerId: number = -1) =>
|
||||
@ -183,98 +174,89 @@ export const CatalogView: FC<{}> = props =>
|
||||
nodes.reverse();
|
||||
|
||||
setActiveNodes(prevValue =>
|
||||
{
|
||||
const isActive = (prevValue.indexOf(targetNode) >= 0);
|
||||
const isOpen = targetNode.isOpen;
|
||||
|
||||
for(const existing of prevValue)
|
||||
{
|
||||
const isActive = (prevValue.indexOf(targetNode) >= 0);
|
||||
const isOpen = targetNode.isOpen;
|
||||
existing.deactivate();
|
||||
|
||||
for(const existing of prevValue)
|
||||
{
|
||||
existing.deactivate();
|
||||
if(nodes.indexOf(existing) === -1) existing.close();
|
||||
}
|
||||
|
||||
if(nodes.indexOf(existing) === -1) existing.close();
|
||||
}
|
||||
for(const n of nodes)
|
||||
{
|
||||
n.activate();
|
||||
|
||||
for(const n of nodes)
|
||||
{
|
||||
n.activate();
|
||||
if(n.parent) n.open();
|
||||
|
||||
if(n.parent) n.open();
|
||||
if((n === targetNode.parent) && n.children.length) n.open();
|
||||
}
|
||||
|
||||
if((n === targetNode.parent) && n.children.length) n.open();
|
||||
}
|
||||
if(isActive && isOpen) targetNode.close();
|
||||
else targetNode.open();
|
||||
|
||||
if(isActive && isOpen) targetNode.close();
|
||||
else targetNode.open();
|
||||
|
||||
return nodes;
|
||||
});
|
||||
return nodes;
|
||||
});
|
||||
|
||||
if(targetNode.pageId > -1) loadCatalogPage(targetNode.pageId, offerId);
|
||||
}, [ setActiveNodes, loadCatalogPage ]);
|
||||
|
||||
const openPageById = useCallback((id: number) =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
setSearchResult(null);
|
||||
|
||||
if(!isVisible)
|
||||
{
|
||||
setSearchResult(null);
|
||||
REQUESTED_PAGE.requestById = id;
|
||||
|
||||
if(!isVisible)
|
||||
{
|
||||
REQUESTED_PAGE.requestById = id;
|
||||
setIsVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const node = getNodeById(id, rootNode);
|
||||
|
||||
setIsVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const node = getNodeById(id, rootNode);
|
||||
|
||||
if(node) activateNode(node);
|
||||
}
|
||||
});
|
||||
if(node) activateNode(node);
|
||||
}
|
||||
}, [ isVisible, rootNode, getNodeById, activateNode ]);
|
||||
|
||||
const openPageByName = useCallback((name: string) =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
setSearchResult(null);
|
||||
|
||||
if(!isVisible)
|
||||
{
|
||||
setSearchResult(null);
|
||||
REQUESTED_PAGE.requestByName = name;
|
||||
|
||||
if(!isVisible)
|
||||
{
|
||||
REQUESTED_PAGE.requestByName = name;
|
||||
setIsVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const node = getNodeByName(name, rootNode);
|
||||
|
||||
setIsVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const node = getNodeByName(name, rootNode);
|
||||
|
||||
if(node) activateNode(node);
|
||||
}
|
||||
});
|
||||
if(node) activateNode(node);
|
||||
}
|
||||
}, [ isVisible, rootNode, getNodeByName, activateNode ]);
|
||||
|
||||
const openPageByOfferId = useCallback((offerId: number) =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
setSearchResult(null);
|
||||
|
||||
if(!isVisible)
|
||||
{
|
||||
setSearchResult(null);
|
||||
REQUESTED_PAGE.requestedByOfferId = offerId;
|
||||
|
||||
if(!isVisible)
|
||||
{
|
||||
REQUESTED_PAGE.requestedByOfferId = offerId;
|
||||
setIsVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const nodes = getNodesByOfferId(offerId);
|
||||
|
||||
setIsVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
const nodes = getNodesByOfferId(offerId);
|
||||
if(!nodes || !nodes.length) return;
|
||||
|
||||
if(!nodes || !nodes.length) return;
|
||||
|
||||
activateNode(nodes[0], offerId);
|
||||
}
|
||||
});
|
||||
activateNode(nodes[0], offerId);
|
||||
}
|
||||
}, [ isVisible, getNodesByOfferId, activateNode ]);
|
||||
|
||||
const onCatalogPurchasedEvent = useCallback((event: CatalogPurchasedEvent) =>
|
||||
@ -346,11 +328,11 @@ export const CatalogView: FC<{}> = props =>
|
||||
return () =>
|
||||
{
|
||||
setRoomPreviewer(prevValue =>
|
||||
{
|
||||
prevValue.dispose();
|
||||
{
|
||||
prevValue.dispose();
|
||||
|
||||
return null;
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
@ -415,23 +397,26 @@ export const CatalogView: FC<{}> = props =>
|
||||
<CatalogMessageHandler />
|
||||
{ isVisible &&
|
||||
<NitroCardView uniqueKey="catalog" className="nitro-catalog">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('catalog.title') } onCloseClick={ event => { setIsVisible(false); } } />
|
||||
<NitroCardHeaderView headerText={ LocalizeText('catalog.title') } onCloseClick={ event =>
|
||||
{
|
||||
setIsVisible(false);
|
||||
} } />
|
||||
<NitroCardTabsView>
|
||||
{ rootNode && (rootNode.children.length > 0) && rootNode.children.map(child =>
|
||||
{
|
||||
if(!child.isVisible) return null;
|
||||
{
|
||||
if(!child.isVisible) return null;
|
||||
|
||||
return (
|
||||
<NitroCardTabsItemView key={ child.pageId } isActive={ child.isActive } onClick={ event =>
|
||||
{
|
||||
if(searchResult) setSearchResult(null);
|
||||
return (
|
||||
<NitroCardTabsItemView key={ child.pageId } isActive={ child.isActive } onClick={ event =>
|
||||
{
|
||||
if(searchResult) setSearchResult(null);
|
||||
|
||||
activateNode(child);
|
||||
} }>
|
||||
{ child.localization }
|
||||
</NitroCardTabsItemView>
|
||||
);
|
||||
}) }
|
||||
activateNode(child);
|
||||
} }>
|
||||
{ child.localization }
|
||||
</NitroCardTabsItemView>
|
||||
);
|
||||
}) }
|
||||
</NitroCardTabsView>
|
||||
<NitroCardContentView>
|
||||
<Grid>
|
||||
@ -446,8 +431,8 @@ export const CatalogView: FC<{}> = props =>
|
||||
</Grid>
|
||||
</NitroCardContentView>
|
||||
</NitroCardView> }
|
||||
<CatalogGiftView />
|
||||
<MarketplacePostOfferView />
|
||||
<CatalogGiftView />
|
||||
<MarketplacePostOfferView />
|
||||
</CatalogContextProvider>
|
||||
);
|
||||
}
|
||||
|
@ -5,5 +5,6 @@ export class CatalogPetPalette
|
||||
constructor(
|
||||
public readonly breed: string,
|
||||
public readonly palettes: SellablePetPaletteData[]
|
||||
) {}
|
||||
)
|
||||
{}
|
||||
}
|
||||
|
@ -85,21 +85,21 @@ export function GetPetAvailableColors(petIndex: number, palettes: SellablePetPal
|
||||
switch(petIndex)
|
||||
{
|
||||
case 0:
|
||||
return [[16743226], [16750435], [16764339], [0xF59500], [16498012], [16704690], [0xEDD400], [16115545], [16513201], [8694111], [11585939], [14413767], [6664599], [9553845], [12971486], [8358322], [10002885], [13292268], [10780600], [12623573], [14403561], [12418717], [14327229], [15517403], [14515069], [15764368], [16366271], [0xABABAB], [0xD4D4D4], [0xFFFFFF], [14256481], [14656129], [15848130], [14005087], [14337152], [15918540], [15118118], [15531929], [9764857], [11258085]];
|
||||
return [ [ 16743226 ], [ 16750435 ], [ 16764339 ], [ 0xF59500 ], [ 16498012 ], [ 16704690 ], [ 0xEDD400 ], [ 16115545 ], [ 16513201 ], [ 8694111 ], [ 11585939 ], [ 14413767 ], [ 6664599 ], [ 9553845 ], [ 12971486 ], [ 8358322 ], [ 10002885 ], [ 13292268 ], [ 10780600 ], [ 12623573 ], [ 14403561 ], [ 12418717 ], [ 14327229 ], [ 15517403 ], [ 14515069 ], [ 15764368 ], [ 16366271 ], [ 0xABABAB ], [ 0xD4D4D4 ], [ 0xFFFFFF ], [ 14256481 ], [ 14656129 ], [ 15848130 ], [ 14005087 ], [ 14337152 ], [ 15918540 ], [ 15118118 ], [ 15531929 ], [ 9764857 ], [ 11258085 ] ];
|
||||
case 1:
|
||||
return [[16743226], [16750435], [16764339], [0xF59500], [16498012], [16704690], [0xEDD400], [16115545], [16513201], [8694111], [11585939], [14413767], [6664599], [9553845], [12971486], [8358322], [10002885], [13292268], [10780600], [12623573], [14403561], [12418717], [14327229], [15517403], [14515069], [15764368], [16366271], [0xABABAB], [0xD4D4D4], [0xFFFFFF], [14256481], [14656129], [15848130], [14005087], [14337152], [15918540], [15118118], [15531929], [9764857], [11258085]];
|
||||
return [ [ 16743226 ], [ 16750435 ], [ 16764339 ], [ 0xF59500 ], [ 16498012 ], [ 16704690 ], [ 0xEDD400 ], [ 16115545 ], [ 16513201 ], [ 8694111 ], [ 11585939 ], [ 14413767 ], [ 6664599 ], [ 9553845 ], [ 12971486 ], [ 8358322 ], [ 10002885 ], [ 13292268 ], [ 10780600 ], [ 12623573 ], [ 14403561 ], [ 12418717 ], [ 14327229 ], [ 15517403 ], [ 14515069 ], [ 15764368 ], [ 16366271 ], [ 0xABABAB ], [ 0xD4D4D4 ], [ 0xFFFFFF ], [ 14256481 ], [ 14656129 ], [ 15848130 ], [ 14005087 ], [ 14337152 ], [ 15918540 ], [ 15118118 ], [ 15531929 ], [ 9764857 ], [ 11258085 ] ];
|
||||
case 2:
|
||||
return [[16579283], [15378351], [8830016], [15257125], [9340985], [8949607], [6198292], [8703620], [9889626], [8972045], [12161285], [13162269], [8620113], [12616503], [8628101], [0xD2FF00], [9764857]];
|
||||
return [ [ 16579283 ], [ 15378351 ], [ 8830016 ], [ 15257125 ], [ 9340985 ], [ 8949607 ], [ 6198292 ], [ 8703620 ], [ 9889626 ], [ 8972045 ], [ 12161285 ], [ 13162269 ], [ 8620113 ], [ 12616503 ], [ 8628101 ], [ 0xD2FF00 ], [ 9764857 ] ];
|
||||
case 3:
|
||||
return [[0xFFFFFF], [0xEEEEEE], [0xDDDDDD]];
|
||||
return [ [ 0xFFFFFF ], [ 0xEEEEEE ], [ 0xDDDDDD ] ];
|
||||
case 4:
|
||||
return [[0xFFFFFF], [16053490], [15464440], [16248792], [15396319], [15007487]];
|
||||
return [ [ 0xFFFFFF ], [ 16053490 ], [ 15464440 ], [ 16248792 ], [ 15396319 ], [ 15007487 ] ];
|
||||
case 5:
|
||||
return [[0xFFFFFF], [0xEEEEEE], [0xDDDDDD]];
|
||||
return [ [ 0xFFFFFF ], [ 0xEEEEEE ], [ 0xDDDDDD ] ];
|
||||
case 6:
|
||||
return [[0xFFFFFF], [0xEEEEEE], [0xDDDDDD], [16767177], [16770205], [16751331]];
|
||||
return [ [ 0xFFFFFF ], [ 0xEEEEEE ], [ 0xDDDDDD ], [ 16767177 ], [ 16770205 ], [ 16751331 ] ];
|
||||
case 7:
|
||||
return [[0xCCCCCC], [0xAEAEAE], [16751331], [10149119], [16763290], [16743786]];
|
||||
return [ [ 0xCCCCCC ], [ 0xAEAEAE ], [ 16751331 ], [ 10149119 ], [ 16763290 ], [ 16743786 ] ];
|
||||
default: {
|
||||
const colors: number[][] = [];
|
||||
|
||||
|
@ -6,6 +6,6 @@ export class SearchResult
|
||||
constructor(
|
||||
public readonly searchValue: string,
|
||||
public readonly offers: IPurchasableOffer[],
|
||||
public readonly filteredNodes: ICatalogNode[]
|
||||
) {}
|
||||
public readonly filteredNodes: ICatalogNode[])
|
||||
{}
|
||||
}
|
||||
|
@ -8,7 +8,8 @@ export class SubscriptionInfo
|
||||
public readonly clubPeriods: number = 0,
|
||||
public readonly isVip: boolean = false,
|
||||
public readonly pastDays: number = 0,
|
||||
public readonly pastVipDays: number = 0) {}
|
||||
public readonly pastVipDays: number = 0)
|
||||
{}
|
||||
|
||||
public get lastUpdated(): number
|
||||
{
|
||||
|
@ -5,7 +5,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { GetSessionDataManager, LocalizeText, ProductTypeEnum, SendMessageComposer } from '../../../../api';
|
||||
import { Base, Button, ButtonGroup, Column, Flex, FormGroup, LayoutCurrencyIcon, LayoutFurniImageView, LayoutGiftTagView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
||||
import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchasedEvent } from '../../../../events';
|
||||
import { BatchUpdates, UseUiEvent } from '../../../../hooks';
|
||||
import { UseUiEvent } from '../../../../hooks';
|
||||
import { useCatalogContext } from '../../CatalogContext';
|
||||
|
||||
export const CatalogGiftView: FC<{}> = props =>
|
||||
@ -29,20 +29,17 @@ export const CatalogGiftView: FC<{}> = props =>
|
||||
|
||||
const close = useCallback(() =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setIsVisible(false);
|
||||
setPageId(0);
|
||||
setOfferId(0);
|
||||
setExtraData('');
|
||||
setReceiverName('');
|
||||
setShowMyFace(true);
|
||||
setMessage('');
|
||||
setSelectedBoxIndex(0);
|
||||
setSelectedRibbonIndex(0);
|
||||
|
||||
if(colors.length) setSelectedColorId(colors[0].id);
|
||||
});
|
||||
setIsVisible(false);
|
||||
setPageId(0);
|
||||
setOfferId(0);
|
||||
setExtraData('');
|
||||
setReceiverName('');
|
||||
setShowMyFace(true);
|
||||
setMessage('');
|
||||
setSelectedBoxIndex(0);
|
||||
setSelectedRibbonIndex(0);
|
||||
|
||||
if(colors.length) setSelectedColorId(colors[0].id);
|
||||
}, [ colors ]);
|
||||
|
||||
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
||||
@ -55,15 +52,12 @@ export const CatalogGiftView: FC<{}> = props =>
|
||||
case CatalogEvent.INIT_GIFT:
|
||||
const castedEvent = (event as CatalogInitGiftEvent);
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
close();
|
||||
close();
|
||||
|
||||
setPageId(castedEvent.pageId);
|
||||
setOfferId(castedEvent.offerId);
|
||||
setExtraData(castedEvent.extraData);
|
||||
setIsVisible(true);
|
||||
});
|
||||
setPageId(castedEvent.pageId);
|
||||
setOfferId(castedEvent.offerId);
|
||||
setExtraData(castedEvent.extraData);
|
||||
setIsVisible(true);
|
||||
return;
|
||||
case CatalogEvent.GIFT_RECEIVER_NOT_FOUND:
|
||||
setReceiverNotFound(true);
|
||||
@ -144,17 +138,14 @@ export const CatalogGiftView: FC<{}> = props =>
|
||||
if(giftData.colors && giftData.colors.length > 0) newColors.push({ id: colorId, color: `#${giftData.colors[0].toString(16)}` });
|
||||
}
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setMaxBoxIndex(giftConfiguration.boxTypes.length - 1);
|
||||
setMaxRibbonIndex(giftConfiguration.ribbonTypes.length - 1);
|
||||
setMaxBoxIndex(giftConfiguration.boxTypes.length - 1);
|
||||
setMaxRibbonIndex(giftConfiguration.ribbonTypes.length - 1);
|
||||
|
||||
if(newColors.length)
|
||||
{
|
||||
setSelectedColorId(newColors[0].id);
|
||||
setColors(newColors);
|
||||
}
|
||||
});
|
||||
if(newColors.length)
|
||||
{
|
||||
setSelectedColorId(newColors[0].id);
|
||||
setColors(newColors);
|
||||
}
|
||||
}, [ giftConfiguration ]);
|
||||
|
||||
if(!giftConfiguration || !giftConfiguration.isEnabled || !isVisible) return null;
|
||||
@ -196,7 +187,7 @@ export const CatalogGiftView: FC<{}> = props =>
|
||||
<Column gap={ 1 }>
|
||||
<Text fontWeight="bold">{ LocalizeText(boxName) }</Text>
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
{ LocalizeText(priceText, ['price'], [giftConfiguration.price.toString()]) }
|
||||
{ LocalizeText(priceText, [ 'price' ], [ giftConfiguration.price.toString() ]) }
|
||||
<LayoutCurrencyIcon type={ -1 } />
|
||||
</Flex>
|
||||
</Column>
|
||||
|
@ -14,11 +14,11 @@ export const CatalogNavigationSetView: FC<CatalogNavigationSetViewProps> = props
|
||||
return (
|
||||
<>
|
||||
{ node && (node.children.length > 0) && node.children.map((n, index) =>
|
||||
{
|
||||
if(!n.isVisible) return null;
|
||||
{
|
||||
if(!n.isVisible) return null;
|
||||
|
||||
return <CatalogNavigationItemView key={ index } node={ n } />
|
||||
}) }
|
||||
return <CatalogNavigationItemView key={ index } node={ n } />
|
||||
}) }
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { RedeemVoucherMessageComposer, VoucherRedeemErrorMessageEvent, VoucherRe
|
||||
import { FC, useCallback, useState } from 'react';
|
||||
import { LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../../api';
|
||||
import { Button, Flex } from '../../../../../common';
|
||||
import { BatchUpdates, UseMessageEventHook } from '../../../../../hooks';
|
||||
import { UseMessageEventHook } from '../../../../../hooks';
|
||||
|
||||
export interface CatalogRedeemVoucherViewProps
|
||||
{
|
||||
@ -35,11 +35,8 @@ export const CatalogRedeemVoucherView: FC<CatalogRedeemVoucherViewProps> = props
|
||||
|
||||
NotificationUtilities.simpleAlert(message, null, null, null, LocalizeText('catalog.alert.voucherredeem.ok.title'));
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setIsWaiting(false);
|
||||
setVoucher('');
|
||||
});
|
||||
setIsWaiting(false);
|
||||
setVoucher('');
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(VoucherRedeemOkMessageEvent, onVoucherRedeemOkMessageEvent);
|
||||
|
@ -4,7 +4,6 @@ import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { GetSessionDataManager, LocalizeText } from '../../../../../api';
|
||||
import { Button } from '../../../../../common/Button';
|
||||
import { Flex } from '../../../../../common/Flex';
|
||||
import { BatchUpdates } from '../../../../../hooks';
|
||||
import { useCatalogContext } from '../../../CatalogContext';
|
||||
import { CatalogPage } from '../../../common/CatalogPage';
|
||||
import { CatalogType } from '../../../common/CatalogType';
|
||||
@ -24,20 +23,17 @@ export const CatalogSearchView: FC<{}> = props =>
|
||||
|
||||
const updateSearchValue = (value: string) =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
if(!value || !value.length)
|
||||
{
|
||||
if(!value || !value.length)
|
||||
{
|
||||
setSearchValue('');
|
||||
setSearchValue('');
|
||||
|
||||
if(searchResult) setSearchResult(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
setSearchValue(value);
|
||||
setNeedsProcessing(true);
|
||||
}
|
||||
});
|
||||
if(searchResult) setSearchResult(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
setSearchValue(value);
|
||||
setNeedsProcessing(true);
|
||||
}
|
||||
}
|
||||
|
||||
const processSearch = useCallback((search: string) =>
|
||||
@ -96,11 +92,8 @@ export const CatalogSearchView: FC<{}> = props =>
|
||||
|
||||
FilterCatalogNode(search, foundFurniLines, rootNode, nodes);
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setCurrentPage((new CatalogPage(-1, 'default_3x3', new PageLocalization([], []), offers, false, 1) as ICatalogPage));
|
||||
setSearchResult(new SearchResult(search, offers, nodes.filter(node => (node.isVisible))));
|
||||
});
|
||||
setCurrentPage((new CatalogPage(-1, 'default_3x3', new PageLocalization([], []), offers, false, 1) as ICatalogPage));
|
||||
setSearchResult(new SearchResult(search, offers, nodes.filter(node => (node.isVisible))));
|
||||
}, [ offersToNodes, currentType, rootNode, setCurrentPage, setSearchResult ]);
|
||||
|
||||
useEffect(() =>
|
||||
|
@ -42,7 +42,7 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutProps> = props =>
|
||||
<Column grow gap={ 1 }>
|
||||
<Text grow truncate>{ currentOffer.localizationName }</Text>
|
||||
<Flex justifyContent="end">
|
||||
<CatalogTotalPriceWidget alignItems="end" />
|
||||
<CatalogTotalPriceWidget alignItems="end" />
|
||||
</Flex>
|
||||
<CatalogPurchaseWidgetView />
|
||||
</Column>
|
||||
|
@ -21,13 +21,13 @@ export const CatalogLayoutTrophiesView: FC<CatalogLayoutProps> = props =>
|
||||
if(!currentOffer) return;
|
||||
|
||||
setPurchaseOptions(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.extraData = trophyText;
|
||||
newValue.extraData = trophyText;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}, [ currentOffer, trophyText, setPurchaseOptions ]);
|
||||
|
||||
return (
|
||||
|
@ -140,28 +140,28 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutProps> = props =>
|
||||
<Column fullHeight size={ 7 } overflow="hidden" justifyContent="between">
|
||||
<AutoGrid columnCount={ 1 } className="nitro-catalog-layout-vip-buy-grid">
|
||||
{ clubOffers && (clubOffers.length > 0) && clubOffers.map((offer, index) =>
|
||||
{
|
||||
return (
|
||||
<LayoutGridItem key={ index } column={ false } center={ false } alignItems="center" justifyContent="between" itemActive={ pendingOffer === offer } className="p-1" onClick={ () => setOffer(offer) }>
|
||||
<i className="icon-hc-banner" />
|
||||
<Column justifyContent="end" gap={ 0 }>
|
||||
<Text textEnd>{ getOfferText(offer) }</Text>
|
||||
<Flex justifyContent="end" gap={ 1 }>
|
||||
{ (offer.priceCredits > 0) &&
|
||||
{
|
||||
return (
|
||||
<LayoutGridItem key={ index } column={ false } center={ false } alignItems="center" justifyContent="between" itemActive={ pendingOffer === offer } className="p-1" onClick={ () => setOffer(offer) }>
|
||||
<i className="icon-hc-banner" />
|
||||
<Column justifyContent="end" gap={ 0 }>
|
||||
<Text textEnd>{ getOfferText(offer) }</Text>
|
||||
<Flex justifyContent="end" gap={ 1 }>
|
||||
{ (offer.priceCredits > 0) &&
|
||||
<Flex alignItems="center" justifyContent="end" gap={ 1 }>
|
||||
<Text>{ offer.priceCredits }</Text>
|
||||
<LayoutCurrencyIcon type={ -1 } />
|
||||
</Flex> }
|
||||
{ (offer.priceActivityPoints > 0) &&
|
||||
{ (offer.priceActivityPoints > 0) &&
|
||||
<Flex alignItems="center" justifyContent="end" gap={ 1 }>
|
||||
<Text>{ offer.priceActivityPoints }</Text>
|
||||
<LayoutCurrencyIcon type={ offer.priceActivityPointsType } />
|
||||
</Flex> }
|
||||
</Flex>
|
||||
</Column>
|
||||
</LayoutGridItem>
|
||||
);
|
||||
}) }
|
||||
</Flex>
|
||||
</Column>
|
||||
</LayoutGridItem>
|
||||
);
|
||||
}) }
|
||||
</AutoGrid>
|
||||
<Text center dangerouslySetInnerHTML={{ __html: LocalizeText('catalog.vip.buy.hccenter') }}></Text>
|
||||
</Column>
|
||||
|
@ -64,7 +64,7 @@ export const GetCatalogLayout = (page: ICatalogPage, hideNavigation: () => void)
|
||||
case 'badge_display':
|
||||
return <CatalogLayoutBadgeDisplayView { ...layoutProps } />;
|
||||
//case 'default_3x3_color_grouping':
|
||||
//return <CatalogLayoutColorGroupingView { ...layoutProps } />;
|
||||
//return <CatalogLayoutColorGroupingView { ...layoutProps } />;
|
||||
case 'bots':
|
||||
case 'default_3x3':
|
||||
default:
|
||||
|
@ -44,8 +44,8 @@ export const CatalogLayoutMarketplaceItemView: FC<MarketplaceItemViewProps> = pr
|
||||
text = hours + ' ' + LocalizeText('catalog.marketplace.offer.hours') + ' ' + text;
|
||||
}
|
||||
|
||||
return LocalizeText('catalog.marketplace.offer.time_left', ['time'], [text] );
|
||||
}, [offerData]);
|
||||
return LocalizeText('catalog.marketplace.offer.time_left', [ 'time' ], [ text ] );
|
||||
}, [ offerData ]);
|
||||
|
||||
return (
|
||||
<LayoutGridItem shrink center={ false } column={ false } alignItems="center" className="p-1">
|
||||
@ -59,8 +59,8 @@ export const CatalogLayoutMarketplaceItemView: FC<MarketplaceItemViewProps> = pr
|
||||
</> }
|
||||
{ (type === PUBLIC_OFFER) &&
|
||||
<>
|
||||
<Text>{ LocalizeText('catalog.marketplace.offer.price_public_item', ['price', 'average'], [offerData.price.toString(), offerData.averagePrice.toString() ]) }</Text>
|
||||
<Text>{ LocalizeText('catalog.marketplace.offer_count', ['count'], [offerData.offerCount.toString()]) }</Text>
|
||||
<Text>{ LocalizeText('catalog.marketplace.offer.price_public_item', [ 'price', 'average' ], [ offerData.price.toString(), offerData.averagePrice.toString() ]) }</Text>
|
||||
<Text>{ LocalizeText('catalog.marketplace.offer_count', [ 'count' ], [ offerData.offerCount.toString() ]) }</Text>
|
||||
</> }
|
||||
</Column>
|
||||
<Column gap={ 1 }>
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { CancelMarketplaceOfferMessageComposer, GetMarketplaceOwnOffersMessageComposer, MarketplaceCancelOfferResultEvent, MarketplaceOwnOffersEvent, RedeemMarketplaceOfferCreditsMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer } from '../../../../../../api';
|
||||
import { Button, Column, Text } from '../../../../../../common';
|
||||
import { BatchUpdates, UseMessageEventHook, UseMountEffect } from '../../../../../../hooks';
|
||||
import { UseMessageEventHook } from '../../../../../../hooks';
|
||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||
import { CatalogLayoutMarketplaceItemView, OWN_OFFER } from './CatalogLayoutMarketplaceItemView';
|
||||
import { MarketplaceOfferData } from './common/MarketplaceOfferData';
|
||||
@ -20,19 +20,16 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutProps> = prop
|
||||
if(!parser) return;
|
||||
|
||||
const offers = parser.offers.map(offer =>
|
||||
{
|
||||
const newOffer = new MarketplaceOfferData(offer.offerId, offer.furniId, offer.furniType, offer.extraData, offer.stuffData, offer.price, offer.status, offer.averagePrice, offer.offerCount);
|
||||
|
||||
newOffer.timeLeftMinutes = offer.timeLeftMinutes;
|
||||
|
||||
return newOffer;
|
||||
});
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setCreditsWaiting(parser.creditsWaiting);
|
||||
setOffers(offers);
|
||||
const newOffer = new MarketplaceOfferData(offer.offerId, offer.furniId, offer.furniType, offer.extraData, offer.stuffData, offer.price, offer.status, offer.averagePrice, offer.offerCount);
|
||||
|
||||
newOffer.timeLeftMinutes = offer.timeLeftMinutes;
|
||||
|
||||
return newOffer;
|
||||
});
|
||||
|
||||
setCreditsWaiting(parser.creditsWaiting);
|
||||
setOffers(offers);
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(MarketplaceOwnOffersEvent, onMarketPlaceOwnOffersEvent);
|
||||
@ -77,10 +74,10 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutProps> = prop
|
||||
SendMessageComposer(new CancelMarketplaceOfferMessageComposer(offerData.offerId));
|
||||
};
|
||||
|
||||
UseMountEffect(() =>
|
||||
useEffect(() =>
|
||||
{
|
||||
SendMessageComposer(new GetMarketplaceOwnOffersMessageComposer());
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Column overflow="hidden">
|
||||
@ -91,7 +88,7 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutProps> = prop
|
||||
{ (creditsWaiting > 0) &&
|
||||
<Column center gap={ 1 } className="bg-muted rounded p-2">
|
||||
<Text>
|
||||
{ LocalizeText('catalog.marketplace.redeem.get_credits', ['count', 'credits'], [ soldOffers.length.toString(), creditsWaiting.toString() ]) }
|
||||
{ LocalizeText('catalog.marketplace.redeem.get_credits', [ 'count', 'credits' ], [ soldOffers.length.toString(), creditsWaiting.toString() ]) }
|
||||
</Text>
|
||||
<Button className="mt-1" onClick={ redeemSoldOffers }>
|
||||
{ LocalizeText('catalog.marketplace.offer.redeem') }
|
||||
|
@ -2,7 +2,7 @@ import { BuyMarketplaceOfferMessageComposer, GetMarketplaceOffersMessageComposer
|
||||
import { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { LocalizeText, NotificationAlertType, NotificationUtilities, SendMessageComposer } from '../../../../../../api';
|
||||
import { Button, ButtonGroup, Column, Text } from '../../../../../../common';
|
||||
import { BatchUpdates, UseMessageEventHook } from '../../../../../../hooks';
|
||||
import { UseMessageEventHook } from '../../../../../../hooks';
|
||||
import { GetCurrencyAmount } from '../../../../../purse/common/CurrencyHelper';
|
||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||
import { CatalogLayoutMarketplaceItemView, PUBLIC_OFFER } from './CatalogLayoutMarketplaceItemView';
|
||||
@ -11,9 +11,9 @@ import { IMarketplaceSearchOptions } from './common/IMarketplaceSearchOptions';
|
||||
import { MarketplaceOfferData } from './common/MarketplaceOfferData';
|
||||
import { MarketplaceSearchType } from './common/MarketplaceSearchType';
|
||||
|
||||
const SORT_TYPES_VALUE = [1, 2];
|
||||
const SORT_TYPES_ACTIVITY = [3, 4, 5, 6];
|
||||
const SORT_TYPES_ADVANCED = [1, 2, 3, 4, 5, 6];
|
||||
const SORT_TYPES_VALUE = [ 1, 2 ];
|
||||
const SORT_TYPES_ACTIVITY = [ 3, 4, 5, 6 ];
|
||||
const SORT_TYPES_ADVANCED = [ 1, 2, 3, 4, 5, 6 ];
|
||||
export interface CatalogLayoutMarketplacePublicItemsViewProps extends CatalogLayoutProps
|
||||
{
|
||||
|
||||
@ -44,7 +44,7 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
|
||||
return SORT_TYPES_ADVANCED;
|
||||
}
|
||||
return [];
|
||||
}, [searchType]);
|
||||
}, [ searchType ]);
|
||||
|
||||
const purchaseItem = useCallback((offerData: MarketplaceOfferData) =>
|
||||
{
|
||||
@ -55,10 +55,10 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
|
||||
}
|
||||
const offerId = offerData.offerId;
|
||||
NotificationUtilities.confirm(LocalizeText('catalog.marketplace.confirm_header'), () =>
|
||||
{
|
||||
SendMessageComposer(new BuyMarketplaceOfferMessageComposer(offerId));
|
||||
},
|
||||
null, null, null, LocalizeText('catalog.marketplace.confirm_title'));
|
||||
{
|
||||
SendMessageComposer(new BuyMarketplaceOfferMessageComposer(offerId));
|
||||
},
|
||||
null, null, null, LocalizeText('catalog.marketplace.confirm_title'));
|
||||
},[]);
|
||||
|
||||
const onMarketPlaceOffersEvent = useCallback( (event: MarketPlaceOffersEvent) =>
|
||||
@ -75,12 +75,8 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
|
||||
latestOffers.set(entry.offerId, offerEntry);
|
||||
});
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setTotalItemsFound(parser.totalItemsFound);
|
||||
setOffers(latestOffers);
|
||||
});
|
||||
|
||||
setTotalItemsFound(parser.totalItemsFound);
|
||||
setOffers(latestOffers);
|
||||
}, []);
|
||||
|
||||
const onMarketplaceBuyOfferResultEvent = useCallback( (event: MarketplaceBuyOfferResultEvent) =>
|
||||
@ -104,8 +100,8 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
|
||||
NotificationUtilities.simpleAlert(LocalizeText('catalog.marketplace.not_available_header'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.marketplace.not_available_title'));
|
||||
break;
|
||||
case 3:
|
||||
// our shit was updated
|
||||
// todo: some dialogue modal
|
||||
// our shit was updated
|
||||
// todo: some dialogue modal
|
||||
setOffers( prev =>
|
||||
{
|
||||
const newVal = new Map(prev);
|
||||
@ -124,7 +120,7 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
|
||||
});
|
||||
|
||||
NotificationUtilities.confirm(LocalizeText('catalog.marketplace.confirm_higher_header') +
|
||||
'\n' + LocalizeText('catalog.marketplace.confirm_price', ['price'], [parser.newPrice.toString()]), () =>
|
||||
'\n' + LocalizeText('catalog.marketplace.confirm_price', [ 'price' ], [ parser.newPrice.toString() ]), () =>
|
||||
{
|
||||
SendMessageComposer(new BuyMarketplaceOfferMessageComposer(parser.offerId));
|
||||
},
|
||||
@ -134,7 +130,7 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
|
||||
NotificationUtilities.simpleAlert(LocalizeText('catalog.alert.notenough.credits.description'), NotificationAlertType.DEFAULT, null, null, LocalizeText('catalog.alert.notenough.title'));
|
||||
break;
|
||||
}
|
||||
}, [lastSearch, requestOffers]);
|
||||
}, [ lastSearch, requestOffers ]);
|
||||
|
||||
UseMessageEventHook(MarketPlaceOffersEvent, onMarketPlaceOffersEvent);
|
||||
UseMessageEventHook(MarketplaceBuyOfferResultEvent, onMarketplaceBuyOfferResultEvent);
|
||||
|
@ -46,7 +46,7 @@ export const SearchFormView: FC<SearchFormViewProps> = props =>
|
||||
setSortType(sortType);
|
||||
|
||||
if(searchType === MarketplaceSearchType.BY_ACTIVITY || MarketplaceSearchType.BY_VALUE === searchType) onSearch({ minPrice: -1, maxPrice: -1, query: '', type: sortType });
|
||||
}, [onSearch, searchType, sortTypes]);
|
||||
}, [ onSearch, searchType, sortTypes ]);
|
||||
|
||||
return (
|
||||
<Column gap={ 1 }>
|
||||
|
@ -18,13 +18,13 @@ export const MarketplacePostOfferView : FC<{}> = props =>
|
||||
const parser = event.getParser();
|
||||
|
||||
setCatalogOptions(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.marketplaceConfiguration = parser;
|
||||
newValue.marketplaceConfiguration = parser;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}, [ setCatalogOptions ]);
|
||||
|
||||
UseMessageEventHook(MarketplaceConfigurationEvent, onMarketplaceConfigurationEvent);
|
||||
@ -60,11 +60,14 @@ export const MarketplacePostOfferView : FC<{}> = props =>
|
||||
if(!item || (askingPrice <= marketplaceConfiguration.minimumPrice)) return;
|
||||
|
||||
NotificationUtilities.confirm(LocalizeText('inventory.marketplace.confirm_offer.info', [ 'furniname', 'price' ], [ getFurniTitle, askingPrice.toString() ]), () =>
|
||||
{
|
||||
SendMessageComposer(new MakeOfferMessageComposer(askingPrice, item.isWallItem ? 2 : 1, item.id));
|
||||
setItem(null);
|
||||
},
|
||||
() => { setItem(null) }, null, null, LocalizeText('inventory.marketplace.confirm_offer.title'));
|
||||
{
|
||||
SendMessageComposer(new MakeOfferMessageComposer(askingPrice, item.isWallItem ? 2 : 1, item.id));
|
||||
setItem(null);
|
||||
},
|
||||
() =>
|
||||
{
|
||||
setItem(null)
|
||||
}, null, null, LocalizeText('inventory.marketplace.confirm_offer.title'));
|
||||
}
|
||||
|
||||
return (
|
||||
@ -82,7 +85,7 @@ export const MarketplacePostOfferView : FC<{}> = props =>
|
||||
</Column>
|
||||
<Column overflow="auto">
|
||||
<Text italics>
|
||||
{ LocalizeText('inventory.marketplace.make_offer.expiration_info', ['time'], [marketplaceConfiguration.offerTime.toString()]) }
|
||||
{ LocalizeText('inventory.marketplace.make_offer.expiration_info', [ 'time' ], [ marketplaceConfiguration.offerTime.toString() ]) }
|
||||
</Text>
|
||||
<div className="input-group has-validation">
|
||||
<input className="form-control form-control-sm" type="number" min={ 0 } value={ askingPrice } onChange={ event => setAskingPrice(parseInt(event.target.value)) } placeholder={ LocalizeText('inventory.marketplace.make_offer.price_request') } />
|
||||
|
@ -4,7 +4,7 @@ import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { LocalizeText, SendMessageComposer } from '../../../../../../api';
|
||||
import { AutoGrid, Base, Button, Column, Flex, Grid, LayoutGridItem, LayoutPetImageView, Text } from '../../../../../../common';
|
||||
import { CatalogNameResultEvent, CatalogPurchaseFailureEvent, CatalogWidgetEvent } from '../../../../../../events';
|
||||
import { BatchUpdates, DispatchUiEvent, UseUiEvent } from '../../../../../../hooks';
|
||||
import { DispatchUiEvent, UseUiEvent } from '../../../../../../hooks';
|
||||
import { useCatalogContext } from '../../../../CatalogContext';
|
||||
import { GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../common/CatalogUtilities';
|
||||
import { CatalogAddOnBadgeWidgetView } from '../../widgets/CatalogAddOnBadgeWidgetView';
|
||||
@ -122,12 +122,9 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
||||
|
||||
const offer = page.offers[0];
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setCurrentOffer(offer);
|
||||
setPetIndex(GetPetIndexFromLocalization(offer.localizationId));
|
||||
setColorsShowing(false);
|
||||
});
|
||||
setCurrentOffer(offer);
|
||||
setPetIndex(GetPetIndexFromLocalization(offer.localizationId));
|
||||
setColorsShowing(false);
|
||||
}, [ page, setCurrentOffer ]);
|
||||
|
||||
useEffect(() =>
|
||||
@ -153,21 +150,15 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
||||
palettes.push(palette);
|
||||
}
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setSelectedPaletteIndex((palettes.length ? 0 : -1));
|
||||
setSellablePalettes(palettes);
|
||||
});
|
||||
setSelectedPaletteIndex((palettes.length ? 0 : -1));
|
||||
setSellablePalettes(palettes);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setSelectedPaletteIndex(-1);
|
||||
setSellablePalettes([]);
|
||||
});
|
||||
setSelectedPaletteIndex(-1);
|
||||
setSellablePalettes([]);
|
||||
|
||||
SendMessageComposer(new GetSellablePetPalettesComposer(productData.type));
|
||||
}, [ currentOffer, petPalettes ]);
|
||||
@ -178,11 +169,8 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
||||
|
||||
const colors = GetPetAvailableColors(petIndex, sellablePalettes);
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setSelectedColorIndex((colors.length ? 0 : -1));
|
||||
setSellableColors(colors);
|
||||
});
|
||||
setSelectedColorIndex((colors.length ? 0 : -1));
|
||||
setSellableColors(colors);
|
||||
}, [ petIndex, sellablePalettes ]);
|
||||
|
||||
useEffect(() =>
|
||||
@ -212,13 +200,13 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
||||
<Column size={ 7 } overflow="hidden">
|
||||
<AutoGrid columnCount={ 5 }>
|
||||
{ !colorsShowing && (sellablePalettes.length > 0) && sellablePalettes.map((palette, index) =>
|
||||
{
|
||||
return (
|
||||
<LayoutGridItem key={ index } itemActive={ (selectedPaletteIndex === index) } onClick={ event => setSelectedPaletteIndex(index) }>
|
||||
<LayoutPetImageView typeId={ petIndex } paletteId={ palette.paletteId } direction={ 2 } headOnly={ true } />
|
||||
</LayoutGridItem>
|
||||
);
|
||||
})}
|
||||
{
|
||||
return (
|
||||
<LayoutGridItem key={ index } itemActive={ (selectedPaletteIndex === index) } onClick={ event => setSelectedPaletteIndex(index) }>
|
||||
<LayoutPetImageView typeId={ petIndex } paletteId={ palette.paletteId } direction={ 2 } headOnly={ true } />
|
||||
</LayoutGridItem>
|
||||
);
|
||||
})}
|
||||
{ colorsShowing && (sellableColors.length > 0) && sellableColors.map((colorSet, index) => <LayoutGridItem itemHighlight key={ index } itemActive={ (selectedColorIndex === index) } itemColor={ ColorConverter.int2rgb(colorSet[0]) } className="clear-bg" onClick={ event => setSelectedColorIndex(index) } />) }
|
||||
</AutoGrid>
|
||||
</Column>
|
||||
|
@ -27,16 +27,16 @@ export const CatalogLayoutVipGiftsView: FC<CatalogLayoutProps> = props =>
|
||||
const selectGift = useCallback((localizationId: string) =>
|
||||
{
|
||||
NotificationUtilities.confirm(LocalizeText('catalog.club_gift.confirm'), () =>
|
||||
{
|
||||
SendMessageComposer(new SelectClubGiftComposer(localizationId));
|
||||
|
||||
setCatalogOptions(prevValue =>
|
||||
{
|
||||
SendMessageComposer(new SelectClubGiftComposer(localizationId));
|
||||
prevValue.clubGifts.giftsAvailable--;
|
||||
|
||||
setCatalogOptions(prevValue =>
|
||||
{
|
||||
prevValue.clubGifts.giftsAvailable--;
|
||||
|
||||
return { ...prevValue };
|
||||
});
|
||||
}, null);
|
||||
return { ...prevValue };
|
||||
});
|
||||
}, null);
|
||||
}, [ setCatalogOptions ]);
|
||||
|
||||
return (
|
||||
|
@ -21,7 +21,7 @@ export const VipGiftItem : FC<VipGiftItemViewProps> = props =>
|
||||
const productData = offer.products[0];
|
||||
|
||||
return ProductImageUtility.getProductImageUrl(productData.productType, productData.furniClassId, productData.extraParam);
|
||||
}, [offer]);
|
||||
}, [ offer ]);
|
||||
|
||||
const getItemTitle = useCallback(() =>
|
||||
{
|
||||
@ -32,7 +32,7 @@ export const VipGiftItem : FC<VipGiftItemViewProps> = props =>
|
||||
const localizationKey = ProductImageUtility.getProductCategory(productData.productType, productData.furniClassId) === 2 ? 'wallItem.name.' + productData.furniClassId : 'roomItem.name.' + productData.furniClassId;
|
||||
|
||||
return LocalizeText(localizationKey);
|
||||
}, [offer]);
|
||||
}, [ offer ]);
|
||||
|
||||
const getItemDesc = useCallback( () =>
|
||||
{
|
||||
@ -43,7 +43,7 @@ export const VipGiftItem : FC<VipGiftItemViewProps> = props =>
|
||||
const localizationKey = ProductImageUtility.getProductCategory(productData.productType, productData.furniClassId) === 2 ? 'wallItem.desc.' + productData.furniClassId : 'roomItem.desc.' + productData.furniClassId ;
|
||||
|
||||
return LocalizeText(localizationKey);
|
||||
}, [offer]);
|
||||
}, [ offer ]);
|
||||
|
||||
return (
|
||||
<LayoutGridItem center={ false } column={ false } alignItems="center" className="p-1">
|
||||
|
@ -14,9 +14,10 @@ interface CatalogBadgeSelectorWidgetViewProps extends AutoGridProps
|
||||
export const CatalogBadgeSelectorWidgetView: FC<CatalogBadgeSelectorWidgetViewProps> = props =>
|
||||
{
|
||||
const { columnCount = 5, ...rest } = props;
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
const [ currentBadgeCode, setCurrentBadgeCode ] = useState<string>(null);
|
||||
const { currentOffer = null, setPurchaseOptions = null } = useCatalogContext();
|
||||
const { badgeCodes = [] } = useInventoryBadges();
|
||||
const { badgeCodes = [], activate = null, deactivate = null } = useInventoryBadges();
|
||||
|
||||
const previewStuffData = useMemo(() =>
|
||||
{
|
||||
@ -34,27 +35,43 @@ export const CatalogBadgeSelectorWidgetView: FC<CatalogBadgeSelectorWidgetViewPr
|
||||
if(!currentOffer) return;
|
||||
|
||||
setPurchaseOptions(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.extraParamRequired = true;
|
||||
newValue.extraData = ((previewStuffData && previewStuffData.getValue(1)) || null);
|
||||
newValue.previewStuffData = previewStuffData;
|
||||
newValue.extraParamRequired = true;
|
||||
newValue.extraData = ((previewStuffData && previewStuffData.getValue(1)) || null);
|
||||
newValue.previewStuffData = previewStuffData;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}, [ currentOffer, previewStuffData, setPurchaseOptions ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible) return;
|
||||
|
||||
const id = activate();
|
||||
|
||||
return () => deactivate(id);
|
||||
}, [ isVisible, activate, deactivate ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setIsVisible(true);
|
||||
|
||||
return () => setIsVisible(false);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AutoGrid columnCount={ columnCount } { ...rest }>
|
||||
{ badgeCodes && (badgeCodes.length > 0) && badgeCodes.map((badgeCode, index) =>
|
||||
{
|
||||
return (
|
||||
<LayoutGridItem key={ index } itemActive={ (currentBadgeCode === badgeCode) } onClick={ event => setCurrentBadgeCode(badgeCode) }>
|
||||
<LayoutBadgeImageView badgeCode={ badgeCode } />
|
||||
</LayoutGridItem>
|
||||
);
|
||||
}) }
|
||||
{
|
||||
return (
|
||||
<LayoutGridItem key={ index } itemActive={ (currentBadgeCode === badgeCode) } onClick={ event => setCurrentBadgeCode(badgeCode) }>
|
||||
<LayoutBadgeImageView badgeCode={ badgeCode } />
|
||||
</LayoutGridItem>
|
||||
);
|
||||
}) }
|
||||
</AutoGrid>
|
||||
);
|
||||
}
|
||||
|
@ -30,15 +30,15 @@ export const CatalogGuildSelectorWidgetView: FC<{}> = props =>
|
||||
if(!currentOffer) return;
|
||||
|
||||
setPurchaseOptions(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.extraParamRequired = true;
|
||||
newValue.extraData = ((previewStuffData && previewStuffData.getValue(1)) || null);
|
||||
newValue.previewStuffData = previewStuffData;
|
||||
newValue.extraParamRequired = true;
|
||||
newValue.extraData = ((previewStuffData && previewStuffData.getValue(1)) || null);
|
||||
newValue.previewStuffData = previewStuffData;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}, [ currentOffer, previewStuffData, setPurchaseOptions ]);
|
||||
|
||||
useEffect(() =>
|
||||
|
@ -28,13 +28,13 @@ export const CatalogItemGridWidgetView: FC<CatalogItemGridWidgetViewProps> = pro
|
||||
if(offer.product && (offer.product.productType === ProductTypeEnum.WALL))
|
||||
{
|
||||
setPurchaseOptions(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.extraData = (offer.product.extraParam || null);
|
||||
newValue.extraData = (offer.product.extraParam || null);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { LocalizeText, ProductTypeEnum } from '../../../../../api';
|
||||
import { AutoGrid, AutoGridProps, Button, ButtonGroup } from '../../../../../common';
|
||||
import { BatchUpdates } from '../../../../../hooks';
|
||||
import { useCatalogContext } from '../../../CatalogContext';
|
||||
import { IPurchasableOffer } from '../../../common/IPurchasableOffer';
|
||||
import { Offer } from '../../../common/Offer';
|
||||
@ -52,12 +51,9 @@ export const CatalogSpacesWidgetView: FC<CatalogSpacesWidgetViewProps> = props =
|
||||
}
|
||||
}
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setGroupedOffers(groupedOffers);
|
||||
setSelectedGroupIndex(0);
|
||||
setSelectedOfferForGroup([ groupedOffers[0][0], groupedOffers[1][0], groupedOffers[2][0] ]);
|
||||
});
|
||||
setGroupedOffers(groupedOffers);
|
||||
setSelectedGroupIndex(0);
|
||||
setSelectedOfferForGroup([ groupedOffers[0][0], groupedOffers[1][0], groupedOffers[2][0] ]);
|
||||
}, [ currentPage ]);
|
||||
|
||||
useEffect(() =>
|
||||
@ -73,14 +69,14 @@ export const CatalogSpacesWidgetView: FC<CatalogSpacesWidgetViewProps> = props =
|
||||
if((selectedGroupIndex === -1) || !selectedOfferForGroup || !currentOffer) return;
|
||||
|
||||
setPurchaseOptions(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.extraData = selectedOfferForGroup[selectedGroupIndex].product.extraParam;
|
||||
newValue.extraParamRequired = true;
|
||||
newValue.extraData = selectedOfferForGroup[selectedGroupIndex].product.extraParam;
|
||||
newValue.extraParamRequired = true;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}, [ currentOffer, selectedGroupIndex, selectedOfferForGroup, setPurchaseOptions ]);
|
||||
|
||||
if(!groupedOffers || (selectedGroupIndex === -1)) return null;
|
||||
@ -98,13 +94,13 @@ export const CatalogSpacesWidgetView: FC<CatalogSpacesWidgetViewProps> = props =
|
||||
const setSelectedOffer = () =>
|
||||
{
|
||||
setSelectedOfferForGroup(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
newValue[selectedGroupIndex] = offer;
|
||||
newValue[selectedGroupIndex] = offer;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
|
||||
return <CatalogGridOfferView key={ index } itemActive={ (currentOffer && (currentOffer === offer)) } offer={ offer } onClick={ setSelectedOffer } />;
|
||||
|
@ -23,13 +23,13 @@ export const CatalogSpinnerWidgetView: FC<{}> = props =>
|
||||
if(value === quantity) return;
|
||||
|
||||
setPurchaseOptions(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.quantity = value;
|
||||
newValue.quantity = value;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
|
||||
if(!currentOffer || !currentOffer.bundlePurchaseAllowed) return null;
|
||||
|
@ -15,7 +15,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
|
||||
{
|
||||
const { chatHistoryState = null, roomHistoryState = null } = useChatHistoryContext();
|
||||
|
||||
const [needsRoomInsert, setNeedsRoomInsert ] = useState(false);
|
||||
const [ needsRoomInsert, setNeedsRoomInsert ] = useState(false);
|
||||
|
||||
const addChatEntry = useCallback((entry: IChatEntry) =>
|
||||
{
|
||||
@ -32,7 +32,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
|
||||
|
||||
//dispatchUiEvent(new ChatHistoryEvent(ChatHistoryEvent.CHAT_HISTORY_CHANGED));
|
||||
|
||||
}, [chatHistoryState]);
|
||||
}, [ chatHistoryState ]);
|
||||
|
||||
const addRoomHistoryEntry = useCallback((entry: IRoomHistoryEntry) =>
|
||||
{
|
||||
@ -45,7 +45,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
|
||||
}
|
||||
|
||||
roomHistoryState.notify();
|
||||
}, [roomHistoryState]);
|
||||
}, [ roomHistoryState ]);
|
||||
|
||||
const onChatEvent = useCallback((event: RoomSessionChatEvent) =>
|
||||
{
|
||||
@ -62,7 +62,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
|
||||
const entry: IChatEntry = { id: -1, entityId: userData.webID, name: userData.name, look: userData.figure, entityType: userData.type, message: event.message, timestamp: timeString, type: ChatEntryType.TYPE_CHAT, roomId: roomSession.roomId };
|
||||
|
||||
addChatEntry(entry);
|
||||
}, [addChatEntry]);
|
||||
}, [ addChatEntry ]);
|
||||
|
||||
UseRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onChatEvent);
|
||||
|
||||
@ -74,7 +74,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
|
||||
setNeedsRoomInsert(true);
|
||||
break;
|
||||
case RoomSessionEvent.ENDED:
|
||||
//dispatchUiEvent(new ChatHistoryEvent(ChatHistoryEvent.HIDE_CHAT_HISTORY));
|
||||
//dispatchUiEvent(new ChatHistoryEvent(ChatHistoryEvent.HIDE_CHAT_HISTORY));
|
||||
break;
|
||||
}
|
||||
}, []);
|
||||
@ -104,7 +104,7 @@ export const ChatHistoryMessageHandler: FC<{}> = props =>
|
||||
|
||||
setNeedsRoomInsert(false);
|
||||
}
|
||||
}, [addChatEntry, addRoomHistoryEntry, needsRoomInsert]);
|
||||
}, [ addChatEntry, addRoomHistoryEntry, needsRoomInsert ]);
|
||||
|
||||
UseMessageEventHook(GetGuestRoomResultEvent, onGetGuestRoomResultEvent);
|
||||
|
||||
|
@ -3,7 +3,6 @@ import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { AutoSizer, CellMeasurer, CellMeasurerCache, List, ListRowProps, ListRowRenderer, Size } from 'react-virtualized';
|
||||
import { AddEventLinkTracker, LocalizeText, RemoveLinkEventTracker } from '../../api';
|
||||
import { Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
|
||||
import { BatchUpdates } from '../../hooks';
|
||||
import { ChatHistoryContextProvider } from './ChatHistoryContext';
|
||||
import { ChatHistoryMessageHandler } from './ChatHistoryMessageHandler';
|
||||
import { ChatEntryType } from './common/ChatEntryType';
|
||||
@ -91,11 +90,8 @@ export const ChatHistoryView: FC<{}> = props =>
|
||||
chatState.notifier = () => setChatHistoryUpdateId(prevValue => (prevValue + 1));
|
||||
roomState.notifier = () => setRoomHistoryUpdateId(prevValue => (prevValue + 1));
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setChatHistoryState(chatState);
|
||||
setRoomHistoryState(roomState);
|
||||
});
|
||||
setChatHistoryState(chatState);
|
||||
setRoomHistoryState(roomState);
|
||||
|
||||
return () =>
|
||||
{
|
||||
@ -118,19 +114,19 @@ export const ChatHistoryView: FC<{}> = props =>
|
||||
<NitroCardContentView>
|
||||
<AutoSizer defaultWidth={ 300 } defaultHeight={ 200 } onResize={ onResize }>
|
||||
{ ({ height, width }) =>
|
||||
{
|
||||
return (
|
||||
<List
|
||||
ref={ elementRef }
|
||||
width={ width }
|
||||
height={ height }
|
||||
rowCount={ chatHistoryState.chats.length }
|
||||
rowHeight={ cache.rowHeight }
|
||||
className={ 'chat-history-list' }
|
||||
rowRenderer={ RowRenderer }
|
||||
deferredMeasurementCache={ cache } />
|
||||
)
|
||||
} }
|
||||
{
|
||||
return (
|
||||
<List
|
||||
ref={ elementRef }
|
||||
width={ width }
|
||||
height={ height }
|
||||
rowCount={ chatHistoryState.chats.length }
|
||||
rowHeight={ cache.rowHeight }
|
||||
className={ 'chat-history-list' }
|
||||
rowRenderer={ RowRenderer }
|
||||
deferredMeasurementCache={ cache } />
|
||||
)
|
||||
} }
|
||||
</AutoSizer>
|
||||
</NitroCardContentView>
|
||||
</NitroCardView> }
|
||||
|
@ -20,7 +20,7 @@ export const FloorplanEditorView: FC<{}> = props =>
|
||||
const [ originalFloorplanSettings, setOriginalFloorplanSettings ] = useState<IFloorplanSettings>({
|
||||
tilemap: '',
|
||||
reservedTiles: [],
|
||||
entryPoint: [0, 0],
|
||||
entryPoint: [ 0, 0 ],
|
||||
entryPointDir: 2,
|
||||
wallHeight: -1,
|
||||
thicknessWall: 1,
|
||||
@ -65,23 +65,23 @@ export const FloorplanEditorView: FC<{}> = props =>
|
||||
const parser = event.getParser();
|
||||
|
||||
setOriginalFloorplanSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.tilemap = parser.model;
|
||||
newValue.wallHeight = (parser.wallHeight + 1);
|
||||
newValue.tilemap = parser.model;
|
||||
newValue.wallHeight = (parser.wallHeight + 1);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.wallHeight = (parser.wallHeight + 1);
|
||||
newValue.wallHeight = (parser.wallHeight + 1);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(FloorHeightMapEvent, onFloorHeightMapEvent);
|
||||
@ -91,24 +91,24 @@ export const FloorplanEditorView: FC<{}> = props =>
|
||||
const parser = event.getParser();
|
||||
|
||||
setOriginalFloorplanSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
|
||||
newValue.thicknessWall = convertSettingToNumber(parser.thicknessWall);
|
||||
newValue.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
|
||||
newValue.thicknessWall = convertSettingToNumber(parser.thicknessWall);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
|
||||
newValue.thicknessWall = convertSettingToNumber(parser.thicknessWall);
|
||||
newValue.thicknessFloor = convertSettingToNumber(parser.thicknessFloor);
|
||||
newValue.thicknessWall = convertSettingToNumber(parser.thicknessWall);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(RoomVisualizationSettingsEvent, onRoomVisualizationSettingsEvent);
|
||||
|
@ -151,7 +151,7 @@ export class FloorplanEditor extends PixiApplicationProxy
|
||||
{
|
||||
if(this._isHolding)
|
||||
{
|
||||
const [realX, realY] = getTileFromScreenPosition(tileStartX, tileStartY);
|
||||
const [ realX, realY ] = getTileFromScreenPosition(tileStartX, tileStartY);
|
||||
|
||||
if(isClick)
|
||||
{
|
||||
@ -246,7 +246,7 @@ export class FloorplanEditor extends PixiApplicationProxy
|
||||
if(tile.isBlocked) assetName = FloorplanEditor.TILE_BLOCKED;
|
||||
|
||||
//if((tile.height === 'x') || tile.height === 'X') continue;
|
||||
const [positionX, positionY] = getScreenPositionForTile(x, y);
|
||||
const [ positionX, positionY ] = getScreenPositionForTile(x, y);
|
||||
|
||||
this._tilemapRenderer.tile(this._assetCollection.getTexture(`floor_editor_${ assetName }`), positionX, positionY);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ export const getScreenPositionForTile = (x: number, y: number): [number , number
|
||||
|
||||
positionX = positionX + 1024; // center the map in the canvas
|
||||
|
||||
return [positionX, positionY];
|
||||
return [ positionX, positionY ];
|
||||
}
|
||||
|
||||
export const getTileFromScreenPosition = (x: number, y: number): [number, number] =>
|
||||
@ -17,7 +17,7 @@ export const getTileFromScreenPosition = (x: number, y: number): [number, number
|
||||
const realX = ((translatedX /(TILE_SIZE / 2)) + (y / (TILE_SIZE / 4))) / 2;
|
||||
const realY = ((y /(TILE_SIZE / 4)) - (translatedX / (TILE_SIZE / 2))) / 2;
|
||||
|
||||
return [realX, realY];
|
||||
return [ realX, realY ];
|
||||
}
|
||||
|
||||
export const convertNumbersForSaving = (value: number): number =>
|
||||
|
@ -28,15 +28,15 @@ export const FloorplanCanvasView: FC<FloorplanCanvasViewProps> = props =>
|
||||
let newFloorPlanSettings: IFloorplanSettings = null;
|
||||
|
||||
setOriginalFloorplanSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.reservedTiles = parser.blockedTilesMap;
|
||||
newValue.reservedTiles = parser.blockedTilesMap;
|
||||
|
||||
newFloorPlanSettings = newValue;
|
||||
newFloorPlanSettings = newValue;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
|
||||
FloorplanEditor.instance.setTilemap(newFloorPlanSettings.tilemap, parser.blockedTilesMap);
|
||||
|
||||
@ -52,23 +52,23 @@ export const FloorplanCanvasView: FC<FloorplanCanvasViewProps> = props =>
|
||||
const parser = event.getParser();
|
||||
|
||||
setOriginalFloorplanSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.entryPoint = [ parser.x, parser.y ];
|
||||
newValue.entryPointDir = parser.direction;
|
||||
newValue.entryPoint = [ parser.x, parser.y ];
|
||||
newValue.entryPointDir = parser.direction;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.entryPointDir = parser.direction;
|
||||
newValue.entryPointDir = parser.direction;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
|
||||
FloorplanEditor.instance.doorLocation = new NitroPoint(parser.x, parser.y);
|
||||
|
||||
@ -107,14 +107,14 @@ export const FloorplanCanvasView: FC<FloorplanCanvasViewProps> = props =>
|
||||
FloorplanEditor.instance.clear();
|
||||
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
return {
|
||||
wallHeight: originalFloorplanSettings.wallHeight,
|
||||
thicknessWall: originalFloorplanSettings.thicknessWall,
|
||||
thicknessFloor: originalFloorplanSettings.thicknessFloor,
|
||||
entryPointDir: prevValue.entryPointDir
|
||||
}
|
||||
});
|
||||
{
|
||||
return {
|
||||
wallHeight: originalFloorplanSettings.wallHeight,
|
||||
thicknessWall: originalFloorplanSettings.thicknessWall,
|
||||
thicknessFloor: originalFloorplanSettings.thicknessFloor,
|
||||
entryPointDir: prevValue.entryPointDir
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [ originalFloorplanSettings.thicknessFloor, originalFloorplanSettings.thicknessWall, originalFloorplanSettings.wallHeight, setVisualizationSettings ]);
|
||||
|
||||
|
@ -29,20 +29,20 @@ export const FloorplanOptionsView: FC<{}> = props =>
|
||||
const changeDoorDirection = () =>
|
||||
{
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
if(newValue.entryPointDir < 7)
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
++newValue.entryPointDir;
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue.entryPointDir = 0;
|
||||
}
|
||||
|
||||
if(newValue.entryPointDir < 7)
|
||||
{
|
||||
++newValue.entryPointDir;
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue.entryPointDir = 0;
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
|
||||
const onFloorHeightChange = (value: number) =>
|
||||
@ -71,13 +71,13 @@ export const FloorplanOptionsView: FC<{}> = props =>
|
||||
const onWallThicknessChange = (value: number) =>
|
||||
{
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.thicknessWall = value;
|
||||
newValue.thicknessWall = value;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
|
||||
const onWallHeightChange = (value: number) =>
|
||||
@ -87,13 +87,13 @@ export const FloorplanOptionsView: FC<{}> = props =>
|
||||
if(value > MAX_WALL_HEIGHT) value = MAX_WALL_HEIGHT;
|
||||
|
||||
setVisualizationSettings(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.wallHeight = value;
|
||||
newValue.wallHeight = value;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
|
||||
const increaseWallHeight = () =>
|
||||
|
@ -18,8 +18,8 @@ export const FriendsRemoveConfirmationView: FC<FriendsRemoveConfirmationViewProp
|
||||
<NitroCardView className="nitro-friends-remove-confirmation" theme="primary-slim">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('friendlist.removefriendconfirm.title') } onCloseClick={ onCloseClick } />
|
||||
<NitroCardContentView className="text-black">
|
||||
<div>{ removeFriendsText }</div>
|
||||
<Flex gap={ 1 }>
|
||||
<div>{ removeFriendsText }</div>
|
||||
<Flex gap={ 1 }>
|
||||
<Button fullWidth variant="danger" disabled={ (selectedFriendsIds.length === 0) } onClick={ removeSelectedFriends }>{ LocalizeText('generic.ok') }</Button>
|
||||
<Button fullWidth onClick={ onCloseClick }>{ LocalizeText('generic.cancel') }</Button>
|
||||
</Flex>
|
||||
|
@ -2,7 +2,7 @@ import { HabboSearchComposer, HabboSearchResultData, HabboSearchResultEvent } fr
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { LocalizeText, OpenMessengerChat, SendMessageComposer } from '../../../../api';
|
||||
import { Base, Column, Flex, NitroCardAccordionItemView, NitroCardAccordionSetView, NitroCardAccordionSetViewProps, Text, UserProfileIconView } from '../../../../common';
|
||||
import { BatchUpdates, useFriends, UseMessageEventHook } from '../../../../hooks';
|
||||
import { useFriends, UseMessageEventHook } from '../../../../hooks';
|
||||
|
||||
interface FriendsSearchViewProps extends NitroCardAccordionSetViewProps
|
||||
{
|
||||
@ -21,11 +21,8 @@ export const FriendsSearchView: FC<FriendsSearchViewProps> = props =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setFriendResults(parser.friends);
|
||||
setOtherResults(parser.others);
|
||||
});
|
||||
setFriendResults(parser.friends);
|
||||
setOtherResults(parser.others);
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(HabboSearchResultEvent, onHabboSearchResultEvent);
|
||||
@ -58,20 +55,20 @@ export const FriendsSearchView: FC<FriendsSearchViewProps> = props =>
|
||||
<hr className="mx-2 mt-0 mb-1 text-black" />
|
||||
<Column gap={ 0 }>
|
||||
{ friendResults.map(result =>
|
||||
{
|
||||
return (
|
||||
<NitroCardAccordionItemView key={ result.avatarId } justifyContent="between" className="px-2 py-1">
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
<UserProfileIconView userId={ result.avatarId } />
|
||||
<div>{ result.avatarName }</div>
|
||||
</Flex>
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
{ result.isAvatarOnline &&
|
||||
{
|
||||
return (
|
||||
<NitroCardAccordionItemView key={ result.avatarId } justifyContent="between" className="px-2 py-1">
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
<UserProfileIconView userId={ result.avatarId } />
|
||||
<div>{ result.avatarName }</div>
|
||||
</Flex>
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
{ result.isAvatarOnline &&
|
||||
<Base className="nitro-friends-spritesheet icon-chat cursor-pointer" onClick={ event => OpenMessengerChat(result.avatarId) } title={ LocalizeText('friendlist.tip.im') } /> }
|
||||
</Flex>
|
||||
</NitroCardAccordionItemView>
|
||||
)
|
||||
}) }
|
||||
</Flex>
|
||||
</NitroCardAccordionItemView>
|
||||
)
|
||||
}) }
|
||||
</Column>
|
||||
</Column> }
|
||||
</> }
|
||||
@ -85,20 +82,20 @@ export const FriendsSearchView: FC<FriendsSearchViewProps> = props =>
|
||||
<hr className="mx-2 mt-0 mb-1 text-black" />
|
||||
<Column gap={ 0 }>
|
||||
{ otherResults.map(result =>
|
||||
{
|
||||
return (
|
||||
<NitroCardAccordionItemView key={ result.avatarId } justifyContent="between" className="px-2 py-1">
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
<UserProfileIconView userId={ result.avatarId } />
|
||||
<div>{ result.avatarName }</div>
|
||||
</Flex>
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
{ canRequestFriend(result.avatarId) &&
|
||||
{
|
||||
return (
|
||||
<NitroCardAccordionItemView key={ result.avatarId } justifyContent="between" className="px-2 py-1">
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
<UserProfileIconView userId={ result.avatarId } />
|
||||
<div>{ result.avatarName }</div>
|
||||
</Flex>
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
{ canRequestFriend(result.avatarId) &&
|
||||
<Base className="nitro-friends-spritesheet icon-add cursor-pointer" onClick={ event => requestFriend(result.avatarId, result.avatarName) } title={ LocalizeText('friendlist.tip.addfriend') } /> }
|
||||
</Flex>
|
||||
</NitroCardAccordionItemView>
|
||||
)
|
||||
}) }
|
||||
</Flex>
|
||||
</NitroCardAccordionItemView>
|
||||
)
|
||||
}) }
|
||||
</Column>
|
||||
</Column> }
|
||||
</> }
|
||||
|
@ -35,29 +35,29 @@ export const FriendsListView: FC<{}> = props =>
|
||||
}
|
||||
|
||||
return LocalizeText('friendlist.removefriendconfirm.userlist', [ 'user_names' ], [ userNames.join(', ') ]);
|
||||
}, [offlineFriends, onlineFriends, selectedFriendsIds]);
|
||||
}, [ offlineFriends, onlineFriends, selectedFriendsIds ]);
|
||||
|
||||
const selectFriend = useCallback((userId: number) =>
|
||||
{
|
||||
if(userId < 0) return;
|
||||
|
||||
setSelectedFriendsIds(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
const existingUserIdIndex: number = newValue.indexOf(userId);
|
||||
|
||||
if(existingUserIdIndex > -1)
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
newValue.splice(existingUserIdIndex, 1)
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue.push(userId);
|
||||
}
|
||||
|
||||
const existingUserIdIndex: number = newValue.indexOf(userId);
|
||||
|
||||
if(existingUserIdIndex > -1)
|
||||
{
|
||||
newValue.splice(existingUserIdIndex, 1)
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue.push(userId);
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}, [ setSelectedFriendsIds ]);
|
||||
|
||||
const sendRoomInvite = (message: string) =>
|
||||
@ -73,11 +73,11 @@ export const FriendsListView: FC<{}> = props =>
|
||||
if(selectedFriendsIds.length === 0) return;
|
||||
|
||||
setSelectedFriendsIds(prevValue =>
|
||||
{
|
||||
SendMessageComposer(new RemoveFriendComposer(...prevValue));
|
||||
{
|
||||
SendMessageComposer(new RemoveFriendComposer(...prevValue));
|
||||
|
||||
return [];
|
||||
});
|
||||
return [];
|
||||
});
|
||||
|
||||
setShowRemoveFriendsConfirmation(false);
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
import { FC, useMemo } from 'react';
|
||||
import { GetSessionDataManager, LocalizeText } from '../../../../api';
|
||||
import { Base, Flex, LayoutAvatarImageView } from '../../../../common';
|
||||
import { GroupType } from '../../common/GroupType';
|
||||
import { MessengerThread } from '../../common/MessengerThread';
|
||||
import { MessengerThreadChat } from '../../common/MessengerThreadChat';
|
||||
import { MessengerThreadChatGroup } from '../../common/MessengerThreadChatGroup';
|
||||
import { getGroupChatData } from '../../common/Utils';
|
||||
|
||||
interface FriendsMessengerThreadGroupProps
|
||||
{
|
||||
thread: MessengerThread;
|
||||
group: MessengerThreadChatGroup;
|
||||
}
|
||||
|
||||
export const FriendsMessengerThreadGroup: FC<FriendsMessengerThreadGroupProps> = props =>
|
||||
{
|
||||
const { thread = null, group = null } = props;
|
||||
|
||||
const isOwnChat = useMemo(() =>
|
||||
{
|
||||
if(!thread || !group) return false;
|
||||
|
||||
if(group.type === GroupType.PRIVATE_CHAT && (group.userId === GetSessionDataManager().userId)) return true;
|
||||
|
||||
if( (group.type === GroupType.GROUP_CHAT) && (group.chats.length && getGroupChatData(group.chats[0].extraData).userId === GetSessionDataManager().userId)) return true;
|
||||
|
||||
return false;
|
||||
}, [ group, thread ]);
|
||||
|
||||
if(!thread || !group) return null;
|
||||
|
||||
if(!group.userId)
|
||||
{
|
||||
return (
|
||||
<>
|
||||
{ group.chats.map((chat, index) =>
|
||||
{
|
||||
return (
|
||||
<div key={ index } className="d-flex gap-2 w-100 justify-content-start">
|
||||
<Base className="w-100 text-break">
|
||||
{ chat.type === MessengerThreadChat.SECURITY_NOTIFICATION &&
|
||||
<Base className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-muted align-items-center">
|
||||
<Base className="nitro-friends-spritesheet icon-warning flex-shrink-0" />
|
||||
<Base>{ chat.message }</Base>
|
||||
</Base> }
|
||||
{ chat.type === MessengerThreadChat.ROOM_INVITE &&
|
||||
<Base className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-black align-items-center">
|
||||
<Base className="messenger-notification-icon flex-shrink-0" />
|
||||
<Base>{(LocalizeText('messenger.invitation') + ' ') }{ chat.message }</Base>
|
||||
</Base> }
|
||||
</Base>
|
||||
</div>
|
||||
);
|
||||
}) }
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex className={ 'w-100 justify-content-' + (isOwnChat ? 'end' : 'start') } gap={ 2 }>
|
||||
<Base className="message-avatar flex-shrink-0">
|
||||
{ (group.type === GroupType.PRIVATE_CHAT && !isOwnChat) &&
|
||||
<LayoutAvatarImageView figure={ thread.participant.figure } direction={ 2 } />
|
||||
}
|
||||
{ (group.type === GroupType.GROUP_CHAT && !isOwnChat) &&
|
||||
<LayoutAvatarImageView figure={ getGroupChatData(group.chats[0].extraData).figure } direction={ 2} />
|
||||
}
|
||||
</Base>
|
||||
<Base className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (isOwnChat ? 'right' : 'left') }>
|
||||
<Base className='fw-bold'>
|
||||
{ (isOwnChat) && GetSessionDataManager().userName }
|
||||
{ (!isOwnChat) && ((group.type === GroupType.GROUP_CHAT) ? getGroupChatData(group.chats[0].extraData).username : thread.participant.name)
|
||||
}
|
||||
</Base>
|
||||
{ group.chats.map((chat, index) =><Base key={ index } className="text-break">{ chat.message }</Base>) }
|
||||
</Base>
|
||||
{ (isOwnChat) &&
|
||||
<Base className="message-avatar flex-shrink-0">
|
||||
<LayoutAvatarImageView figure={ GetSessionDataManager().figure } direction={ 4 } />
|
||||
</Base> }
|
||||
</Flex>
|
||||
);
|
||||
}
|
@ -26,40 +26,40 @@ export const FriendsMessengerThreadView: FC<{ thread: MessengerThread }> = props
|
||||
if(!group.userId)
|
||||
{
|
||||
return (
|
||||
<>
|
||||
<>
|
||||
{ group.chats.map((chat, index) =>
|
||||
{
|
||||
return (
|
||||
<Flex key={ index } fullWidth justifyContent="start" gap={ 2 }>
|
||||
<Base className="w-100 text-break">
|
||||
{ (chat.type === MessengerThreadChat.SECURITY_NOTIFICATION) &&
|
||||
{
|
||||
return (
|
||||
<Flex key={ index } fullWidth justifyContent="start" gap={ 2 }>
|
||||
<Base className="w-100 text-break">
|
||||
{ (chat.type === MessengerThreadChat.SECURITY_NOTIFICATION) &&
|
||||
<Base className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-muted align-items-center">
|
||||
<Base className="nitro-friends-spritesheet icon-warning flex-shrink-0" />
|
||||
<Base>{ chat.message }</Base>
|
||||
</Base> }
|
||||
{ (chat.type === MessengerThreadChat.ROOM_INVITE) &&
|
||||
{ (chat.type === MessengerThreadChat.ROOM_INVITE) &&
|
||||
<Base className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-black align-items-center">
|
||||
<Base className="messenger-notification-icon flex-shrink-0" />
|
||||
<Base>{ `${ LocalizeText('messenger.invitation') } ${ chat.message }` }</Base>
|
||||
</Base> }
|
||||
</Base>
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
<Base className="messenger-notification-icon flex-shrink-0" />
|
||||
<Base>{ `${ LocalizeText('messenger.invitation') } ${ chat.message }` }</Base>
|
||||
</Base> }
|
||||
</Base>
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex className={ 'w-100 justify-content-' + (isOwnChat ? 'end' : 'start') } gap={ 2 } { ...rest }>
|
||||
<Base className="message-avatar flex-shrink-0">
|
||||
<Base className="message-avatar flex-shrink-0">
|
||||
{ (group.type === GroupType.PRIVATE_CHAT && !isOwnChat) &&
|
||||
<LayoutAvatarImageView figure={ thread.participant.figure } direction={ 2 } />
|
||||
}
|
||||
{ (group.type === GroupType.GROUP_CHAT && !isOwnChat) &&
|
||||
<LayoutAvatarImageView figure={ GetGroupChatData(group.chats[0].extraData).figure } direction={ 2} />
|
||||
}
|
||||
</Base>
|
||||
</Base>
|
||||
<Base className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (isOwnChat ? 'right' : 'left') }>
|
||||
<Base className='fw-bold'>
|
||||
{ (isOwnChat) && GetSessionDataManager().userName }
|
||||
|
@ -3,7 +3,7 @@ import { FollowFriendMessageComposer, ILinkEventTracker } from '@nitrots/nitro-r
|
||||
import { FC, KeyboardEvent, useEffect, useRef, useState } from 'react';
|
||||
import { AddEventLinkTracker, GetUserProfile, LocalizeText, RemoveLinkEventTracker, SendMessageComposer } from '../../../../api';
|
||||
import { Base, Button, ButtonGroup, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, LayoutGridItem, LayoutItemCountView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
||||
import { BatchUpdates, useMessenger } from '../../../../hooks';
|
||||
import { useMessenger } from '../../../../hooks';
|
||||
import { FriendsMessengerThreadView } from './FriendsMessengerThreadView';
|
||||
|
||||
export const FriendsMessengerView: FC<{}> = props =>
|
||||
@ -54,11 +54,8 @@ export const FriendsMessengerView: FC<{}> = props =>
|
||||
|
||||
if(!thread) return;
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setActiveThread(thread);
|
||||
setIsVisible(true);
|
||||
});
|
||||
setActiveThread(thread);
|
||||
setIsVisible(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -34,33 +34,33 @@ export const GroupBadgeCreatorView: FC<GroupBadgeCreatorViewProps> = props =>
|
||||
return (
|
||||
<>
|
||||
{ ((selectedIndex < 0) && badgeParts && (badgeParts.length > 0)) && badgeParts.map((part, index) =>
|
||||
{
|
||||
return (
|
||||
<Flex key={ index } alignItems="center" justifyContent="between" gap={ 2 } className="bg-muted rounded px-2 py-1">
|
||||
<Flex pointer center className="bg-muted rounded p-1" onClick={ event => setSelectedIndex(index) }>
|
||||
{ (badgeParts[index].code && (badgeParts[index].code.length > 0)) &&
|
||||
{
|
||||
return (
|
||||
<Flex key={ index } alignItems="center" justifyContent="between" gap={ 2 } className="bg-muted rounded px-2 py-1">
|
||||
<Flex pointer center className="bg-muted rounded p-1" onClick={ event => setSelectedIndex(index) }>
|
||||
{ (badgeParts[index].code && (badgeParts[index].code.length > 0)) &&
|
||||
<LayoutBadgeImageView badgeCode={ badgeParts[index].code } isGroup={ true } /> }
|
||||
{ (!badgeParts[index].code || !badgeParts[index].code.length) &&
|
||||
{ (!badgeParts[index].code || !badgeParts[index].code.length) &&
|
||||
<Flex center className="badge-image group-badge">
|
||||
<FontAwesomeIcon icon="plus" />
|
||||
</Flex> }
|
||||
</Flex>
|
||||
{ (part.type !== GroupBadgePart.BASE) &&
|
||||
</Flex>
|
||||
{ (part.type !== GroupBadgePart.BASE) &&
|
||||
<Grid gap={ 1 } columnCount={ 3 }>
|
||||
{ POSITIONS.map((position, posIndex) =>
|
||||
{
|
||||
return <Base key={ posIndex } pointer className={ `group-badge-position-swatch ${ (badgeParts[index].position === position) ? 'active' : '' }` } onClick={ event => setPartProperty(index, 'position', position) }></Base>
|
||||
}) }
|
||||
</Grid> }
|
||||
<Grid gap={ 1 } columnCount={ 8 }>
|
||||
{ (groupCustomize.badgePartColors.length > 0) && groupCustomize.badgePartColors.map((item, colorIndex) =>
|
||||
{
|
||||
return <Base key={ colorIndex } pointer className={ `group-badge-color-swatch ${ (badgeParts[index].color === (colorIndex + 1)) ? 'active' : '' }` } style={{ backgroundColor: '#' + item.color }} onClick={ event => setPartProperty(index, 'color', (colorIndex + 1)) }></Base>
|
||||
return <Base key={ posIndex } pointer className={ `group-badge-position-swatch ${ (badgeParts[index].position === position) ? 'active' : '' }` } onClick={ event => setPartProperty(index, 'position', position) }></Base>
|
||||
}) }
|
||||
</Grid>
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
</Grid> }
|
||||
<Grid gap={ 1 } columnCount={ 8 }>
|
||||
{ (groupCustomize.badgePartColors.length > 0) && groupCustomize.badgePartColors.map((item, colorIndex) =>
|
||||
{
|
||||
return <Base key={ colorIndex } pointer className={ `group-badge-color-swatch ${ (badgeParts[index].color === (colorIndex + 1)) ? 'active' : '' }` } style={{ backgroundColor: '#' + item.color }} onClick={ event => setPartProperty(index, 'color', (colorIndex + 1)) }></Base>
|
||||
}) }
|
||||
</Grid>
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
{ (selectedIndex >= 0) &&
|
||||
<Grid gap={ 1 } columnCount={ 5 }>
|
||||
{ (badgeParts[selectedIndex].type === GroupBadgePart.SYMBOL) &&
|
||||
@ -70,13 +70,13 @@ export const GroupBadgeCreatorView: FC<GroupBadgeCreatorViewProps> = props =>
|
||||
</Flex>
|
||||
</Column> }
|
||||
{ ((badgeParts[selectedIndex].type === GroupBadgePart.BASE) ? groupCustomize.badgeBases : groupCustomize.badgeSymbols).map((item, index) =>
|
||||
{
|
||||
return (
|
||||
<Column key={ index } pointer center className="bg-muted rounded p-1" onClick={ event => setPartProperty(selectedIndex, 'key', item.id) }>
|
||||
<LayoutBadgeImageView badgeCode={ GroupBadgePart.getCode(badgeParts[selectedIndex].type, item.id, badgeParts[selectedIndex].color, 4) } isGroup={ true } />
|
||||
</Column>
|
||||
);
|
||||
}) }
|
||||
{
|
||||
return (
|
||||
<Column key={ index } pointer center className="bg-muted rounded p-1" onClick={ event => setPartProperty(selectedIndex, 'key', item.id) }>
|
||||
<LayoutBadgeImageView badgeCode={ GroupBadgePart.getCode(badgeParts[selectedIndex].type, item.id, badgeParts[selectedIndex].color, 4) } isGroup={ true } />
|
||||
</Column>
|
||||
);
|
||||
}) }
|
||||
</Grid> }
|
||||
</>
|
||||
);
|
||||
|
@ -2,7 +2,7 @@ import { GroupBuyComposer, GroupBuyDataComposer, GroupBuyDataEvent } from '@nitr
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { HasHabboClub, LocalizeText, SendMessageComposer } from '../../../api';
|
||||
import { Base, Button, Column, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common';
|
||||
import { BatchUpdates, UseMessageEventHook } from '../../../hooks';
|
||||
import { UseMessageEventHook } from '../../../hooks';
|
||||
import { IGroupData } from '../common/IGroupData';
|
||||
import { GroupTabBadgeView } from './tabs/GroupTabBadgeView';
|
||||
import { GroupTabColorsView } from './tabs/GroupTabColorsView';
|
||||
@ -94,31 +94,25 @@ export const GroupCreatorView: FC<GroupCreatorViewProps> = props =>
|
||||
|
||||
parser.availableRooms.forEach((name, id) => rooms.push({ id, name }));
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setAvailableRooms(rooms);
|
||||
setPurchaseCost(parser.groupCost);
|
||||
});
|
||||
setAvailableRooms(rooms);
|
||||
setPurchaseCost(parser.groupCost);
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(GroupBuyDataEvent, onGroupBuyDataEvent);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setCurrentTab(1);
|
||||
setCurrentTab(1);
|
||||
|
||||
setGroupData({
|
||||
groupId: -1,
|
||||
groupName: null,
|
||||
groupDescription: null,
|
||||
groupHomeroomId: -1,
|
||||
groupState: 1,
|
||||
groupCanMembersDecorate: true,
|
||||
groupColors: null,
|
||||
groupBadgeParts: null
|
||||
});
|
||||
setGroupData({
|
||||
groupId: -1,
|
||||
groupName: null,
|
||||
groupDescription: null,
|
||||
groupHomeroomId: -1,
|
||||
groupState: 1,
|
||||
groupCanMembersDecorate: true,
|
||||
groupColors: null,
|
||||
groupBadgeParts: null
|
||||
});
|
||||
|
||||
SendMessageComposer(new GroupBuyDataComposer());
|
||||
@ -132,13 +126,13 @@ export const GroupCreatorView: FC<GroupCreatorViewProps> = props =>
|
||||
<NitroCardContentView>
|
||||
<Flex center className="creator-tabs">
|
||||
{ TABS.map((tab, index) =>
|
||||
{
|
||||
return (
|
||||
<Flex center key={ index } className={ `tab tab-${ ((tab === 1) ? 'blue-flat' : (tab === 4) ? 'yellow' : 'blue-arrow') } ${ (currentTab === tab) ? 'active' : '' }` }>
|
||||
<Text variant="white">{ LocalizeText(`group.create.steplabel.${ tab }`) }</Text>
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
{
|
||||
return (
|
||||
<Flex center key={ index } className={ `tab tab-${ ((tab === 1) ? 'blue-flat' : (tab === 4) ? 'yellow' : 'blue-arrow') } ${ (currentTab === tab) ? 'active' : '' }` }>
|
||||
<Text variant="white">{ LocalizeText(`group.create.steplabel.${ tab }`) }</Text>
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
</Flex>
|
||||
<Column overflow="hidden">
|
||||
<Flex alignItems="center" gap={ 2 }>
|
||||
|
@ -26,11 +26,11 @@ export const GroupInformationView: FC<GroupInformationViewProps> = props =>
|
||||
const leaveGroup = () =>
|
||||
{
|
||||
NotificationUtilities.confirm(LocalizeText('group.leaveconfirm.desc'), () =>
|
||||
{
|
||||
SendMessageComposer(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId));
|
||||
{
|
||||
SendMessageComposer(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId));
|
||||
|
||||
if(onClose) onClose();
|
||||
}, null);
|
||||
if(onClose) onClose();
|
||||
}, null);
|
||||
}
|
||||
|
||||
const getRoleIcon = () =>
|
||||
@ -126,7 +126,7 @@ export const GroupInformationView: FC<GroupInformationViewProps> = props =>
|
||||
<i className="icon icon-group-decorate" title={ LocalizeText('group.memberscandecorate') } /> }
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Text small>{ LocalizeText('group.created', ['date', 'owner'], [groupInformation.createdAt, groupInformation.ownerName]) }</Text>
|
||||
<Text small>{ LocalizeText('group.created', [ 'date', 'owner' ], [ groupInformation.createdAt, groupInformation.ownerName ]) }</Text>
|
||||
</Column>
|
||||
<Text small overflow="auto" className="group-description">{ groupInformation.description }</Text>
|
||||
</Column>
|
||||
|
@ -20,11 +20,11 @@ export const GroupManagerView: FC<{}> = props =>
|
||||
const close = () =>
|
||||
{
|
||||
setCloseAction(prevValue =>
|
||||
{
|
||||
if(prevValue && prevValue.action) prevValue.action();
|
||||
{
|
||||
if(prevValue && prevValue.action) prevValue.action();
|
||||
|
||||
return null;
|
||||
});
|
||||
return null;
|
||||
});
|
||||
|
||||
setGroupData(null);
|
||||
}
|
||||
@ -43,16 +43,16 @@ export const GroupManagerView: FC<{}> = props =>
|
||||
if(!groupData || (groupData.groupId !== parser.id)) return;
|
||||
|
||||
setGroupData(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.groupName = parser.title;
|
||||
newValue.groupDescription = parser.description;
|
||||
newValue.groupState = parser.type;
|
||||
newValue.groupCanMembersDecorate = parser.canMembersDecorate;
|
||||
newValue.groupName = parser.title;
|
||||
newValue.groupDescription = parser.description;
|
||||
newValue.groupState = parser.type;
|
||||
newValue.groupCanMembersDecorate = parser.canMembersDecorate;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
}, [ groupData ]);
|
||||
|
||||
UseMessageEventHook(GroupInformationEvent, onGroupInformationEvent);
|
||||
@ -94,11 +94,11 @@ export const GroupManagerView: FC<{}> = props =>
|
||||
<NitroCardHeaderView headerText={ LocalizeText('group.window.title') } onCloseClick={ close } />
|
||||
<NitroCardTabsView>
|
||||
{ TABS.map(tab =>
|
||||
{
|
||||
return (<NitroCardTabsItemView key={ tab } isActive={ currentTab === tab } onClick={ () => changeTab(tab) }>
|
||||
{ LocalizeText(`group.edit.tab.${tab}`) }
|
||||
</NitroCardTabsItemView>);
|
||||
}) }
|
||||
{
|
||||
return (<NitroCardTabsItemView key={ tab } isActive={ currentTab === tab } onClick={ () => changeTab(tab) }>
|
||||
{ LocalizeText(`group.edit.tab.${tab}`) }
|
||||
</NitroCardTabsItemView>);
|
||||
}) }
|
||||
</NitroCardTabsView>
|
||||
<NitroCardContentView>
|
||||
<Flex alignItems="center" gap={ 2 }>
|
||||
|
@ -3,7 +3,7 @@ import { GroupAdminGiveComposer, GroupAdminTakeComposer, GroupConfirmMemberRemov
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { AddEventLinkTracker, GetSessionDataManager, GetUserProfile, LocalizeText, NotificationUtilities, RemoveLinkEventTracker, SendMessageComposer } from '../../../api';
|
||||
import { Base, Button, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common';
|
||||
import { BatchUpdates, UseMessageEventHook } from '../../../hooks';
|
||||
import { UseMessageEventHook } from '../../../hooks';
|
||||
|
||||
export const GroupMembersView: FC<{}> = props =>
|
||||
{
|
||||
@ -76,12 +76,9 @@ export const GroupMembersView: FC<{}> = props =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setMembersData(parser);
|
||||
setLevelId(parser.level);
|
||||
setTotalPages(Math.ceil(parser.totalMembersCount / parser.pageSize));
|
||||
});
|
||||
setMembersData(parser);
|
||||
setLevelId(parser.level);
|
||||
setTotalPages(Math.ceil(parser.totalMembersCount / parser.pageSize));
|
||||
}, []);
|
||||
|
||||
UseMessageEventHook(GroupMembersEvent, onGroupMembersEvent);
|
||||
@ -91,11 +88,11 @@ export const GroupMembersView: FC<{}> = props =>
|
||||
const parser = event.getParser();
|
||||
|
||||
NotificationUtilities.confirm(LocalizeText(((parser.furnitureCount > 0) ? 'group.kickconfirm.desc' : 'group.kickconfirm_nofurni.desc'), [ 'user', 'amount' ], [ removingMemberName, parser.furnitureCount.toString() ]), () =>
|
||||
{
|
||||
SendMessageComposer(new GroupRemoveMemberComposer(membersData.groupId, parser.userId));
|
||||
{
|
||||
SendMessageComposer(new GroupRemoveMemberComposer(membersData.groupId, parser.userId));
|
||||
|
||||
refreshMembers();
|
||||
}, null);
|
||||
refreshMembers();
|
||||
}, null);
|
||||
|
||||
setRemovingMemberName(null);
|
||||
}, [ membersData, removingMemberName, refreshMembers ]);
|
||||
@ -111,11 +108,8 @@ export const GroupMembersView: FC<{}> = props =>
|
||||
const groupId = (parseInt(parts[1]) || -1);
|
||||
const levelId = (parseInt(parts[2]) || 3);
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setGroupId(groupId);
|
||||
setLevelId(levelId);
|
||||
});
|
||||
setGroupId(groupId);
|
||||
setLevelId(levelId);
|
||||
}, []);
|
||||
|
||||
useEffect(() =>
|
||||
@ -146,21 +140,18 @@ export const GroupMembersView: FC<{}> = props =>
|
||||
{
|
||||
if(groupId === -1) return;
|
||||
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setLevelId(-1);
|
||||
setMembersData(null);
|
||||
setTotalPages(0);
|
||||
setSearchQuery('');
|
||||
setRemovingMemberName(null);
|
||||
})
|
||||
setLevelId(-1);
|
||||
setMembersData(null);
|
||||
setTotalPages(0);
|
||||
setSearchQuery('');
|
||||
setRemovingMemberName(null);
|
||||
}, [ groupId ]);
|
||||
|
||||
if((groupId === -1) || !membersData) return null;
|
||||
|
||||
return (
|
||||
<NitroCardView className="nitro-group-members" theme="primary-slim">
|
||||
<NitroCardHeaderView headerText={ LocalizeText('group.members.title', ['groupName'], [ membersData ? membersData.groupTitle : '' ]) } onCloseClick={ event => setGroupId(-1) } />
|
||||
<NitroCardHeaderView headerText={ LocalizeText('group.members.title', [ 'groupName' ], [ membersData ? membersData.groupTitle : '' ]) } onCloseClick={ event => setGroupId(-1) } />
|
||||
<NitroCardContentView overflow="hidden">
|
||||
<Flex gap={ 2 }>
|
||||
<Flex center className="group-badge">
|
||||
@ -177,41 +168,41 @@ export const GroupMembersView: FC<{}> = props =>
|
||||
</Flex>
|
||||
<Grid columnCount={ 2 } overflow="auto" className="nitro-group-members-list-grid">
|
||||
{ membersData.result.map((member, index) =>
|
||||
{
|
||||
return (
|
||||
<Flex key={ index } gap={ 2 } alignItems="center" overflow="hidden" className="member-list-item bg-white rounded p-2">
|
||||
<div className="avatar-head cursor-pointer" onClick={ () => GetUserProfile(member.id) }>
|
||||
<LayoutAvatarImageView figure={ member.figure } headOnly={ true } direction={ 2 } />
|
||||
</div>
|
||||
<Column grow gap={ 1 }>
|
||||
<Text bold small pointer onClick={ event => GetUserProfile(member.id) }>{ member.name }</Text>
|
||||
{ (member.rank !== GroupRank.REQUESTED) &&
|
||||
{
|
||||
return (
|
||||
<Flex key={ index } gap={ 2 } alignItems="center" overflow="hidden" className="member-list-item bg-white rounded p-2">
|
||||
<div className="avatar-head cursor-pointer" onClick={ () => GetUserProfile(member.id) }>
|
||||
<LayoutAvatarImageView figure={ member.figure } headOnly={ true } direction={ 2 } />
|
||||
</div>
|
||||
<Column grow gap={ 1 }>
|
||||
<Text bold small pointer onClick={ event => GetUserProfile(member.id) }>{ member.name }</Text>
|
||||
{ (member.rank !== GroupRank.REQUESTED) &&
|
||||
<Text small italics variant="muted">{ LocalizeText('group.members.since', [ 'date' ], [ member.joinedAt ]) }</Text> }
|
||||
</Column>
|
||||
<Column gap={ 1 }>
|
||||
{ (member.rank !== GroupRank.REQUESTED) &&
|
||||
</Column>
|
||||
<Column gap={ 1 }>
|
||||
{ (member.rank !== GroupRank.REQUESTED) &&
|
||||
<Flex center>
|
||||
<Base pointer={ membersData.admin } className={ `icon icon-group-small-${ ((member.rank === GroupRank.OWNER) ? 'owner' : (member.rank === GroupRank.ADMIN) ? 'admin' : (membersData.admin && (member.rank === GroupRank.MEMBER)) ? 'not-admin' : '') }` } title={ LocalizeText(getRankDescription(member)) } onClick={ event => toggleAdmin(member) } />
|
||||
</Flex> }
|
||||
{ membersData.admin && (member.rank === GroupRank.REQUESTED) &&
|
||||
{ membersData.admin && (member.rank === GroupRank.REQUESTED) &&
|
||||
<Flex alignItems="center">
|
||||
<Base pointer className="nitro-friends-spritesheet icon-accept" title={ LocalizeText('group.members.accept') } onClick={ event => acceptMembership(member) }></Base>
|
||||
</Flex> }
|
||||
{ membersData.admin && (member.rank !== GroupRank.OWNER) && (member.id !== GetSessionDataManager().userId) &&
|
||||
{ membersData.admin && (member.rank !== GroupRank.OWNER) && (member.id !== GetSessionDataManager().userId) &&
|
||||
<Flex alignItems="center">
|
||||
<Base pointer className="nitro-friends-spritesheet icon-deny" title={ LocalizeText(member.rank === GroupRank.REQUESTED ? 'group.members.reject' : 'group.members.kick') } onClick={ event => removeMemberOrDeclineMembership(member) }></Base>
|
||||
</Flex> }
|
||||
</Column>
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
</Column>
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
</Grid>
|
||||
<Flex gap={ 1 } justifyContent="between" alignItems="center">
|
||||
<Button disabled={ (membersData.pageIndex === 0) } onClick={ event => setPageId(prevValue => (prevValue - 1)) }>
|
||||
<FontAwesomeIcon icon="chevron-left" />
|
||||
</Button>
|
||||
<Text small>
|
||||
{ LocalizeText('group.members.pageinfo', ['amount', 'page', 'totalPages'], [membersData.totalMembersCount.toString(), (membersData.pageIndex + 1).toString(), totalPages.toString()]) }
|
||||
{ LocalizeText('group.members.pageinfo', [ 'amount', 'page', 'totalPages' ], [ membersData.totalMembersCount.toString(), (membersData.pageIndex + 1).toString(), totalPages.toString() ]) }
|
||||
</Text>
|
||||
<Button disabled={ (membersData.pageIndex === (totalPages - 1)) } onClick={ event => setPageId(prevValue => (prevValue + 1)) }>
|
||||
<FontAwesomeIcon icon="chevron-right" />
|
||||
|
@ -75,9 +75,9 @@ export const GroupRoomInformationView: FC<{}> = props =>
|
||||
const leaveGroup = () =>
|
||||
{
|
||||
NotificationUtilities.confirm(LocalizeText('group.leaveconfirm.desc'), () =>
|
||||
{
|
||||
SendMessageComposer(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId));
|
||||
}, null);
|
||||
{
|
||||
SendMessageComposer(new GroupRemoveMemberComposer(groupInformation.id, GetSessionDataManager().userId));
|
||||
}, null);
|
||||
}
|
||||
|
||||
const isRealOwner = (groupInformation && (groupInformation.ownerName === GetSessionDataManager().userName));
|
||||
@ -134,7 +134,7 @@ export const GroupRoomInformationView: FC<{}> = props =>
|
||||
<Button fullWidth variant="success" disabled={ (groupInformation.membershipType === GroupMembershipType.REQUEST_PENDING) } onClick={ handleButtonClick }>
|
||||
{ LocalizeText(getButtonText()) }
|
||||
</Button>
|
||||
}
|
||||
}
|
||||
</> }
|
||||
</Column>
|
||||
</Base>
|
||||
|
@ -41,13 +41,13 @@ export const GroupTabBadgeView: FC<GroupTabBadgeViewProps> = props =>
|
||||
if(groupData.groupId <= 0)
|
||||
{
|
||||
setGroupData(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.groupBadgeParts = badgeParts;
|
||||
newValue.groupBadgeParts = badgeParts;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -81,11 +81,11 @@ export const GroupTabBadgeView: FC<GroupTabBadgeViewProps> = props =>
|
||||
];
|
||||
|
||||
setGroupData(prevValue =>
|
||||
{
|
||||
const groupBadgeParts = badgeParts;
|
||||
{
|
||||
const groupBadgeParts = badgeParts;
|
||||
|
||||
return { ...prevValue, groupBadgeParts };
|
||||
});
|
||||
return { ...prevValue, groupBadgeParts };
|
||||
});
|
||||
}, [ groupData.groupBadgeParts, groupCustomize, setGroupData ]);
|
||||
|
||||
useEffect(() =>
|
||||
|
@ -29,13 +29,13 @@ export const GroupTabColorsView: FC<GroupTabColorsViewProps> = props =>
|
||||
const selectColor = (colorIndex: number, colorId: number) =>
|
||||
{
|
||||
setColors(prevValue =>
|
||||
{
|
||||
const newColors = [ ...prevValue ];
|
||||
{
|
||||
const newColors = [ ...prevValue ];
|
||||
|
||||
newColors[colorIndex] = colorId;
|
||||
newColors[colorIndex] = colorId;
|
||||
|
||||
return newColors;
|
||||
});
|
||||
return newColors;
|
||||
});
|
||||
}
|
||||
|
||||
const saveColors = useCallback(() =>
|
||||
@ -47,13 +47,13 @@ export const GroupTabColorsView: FC<GroupTabColorsViewProps> = props =>
|
||||
if(groupData.groupId <= 0)
|
||||
{
|
||||
setGroupData(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.groupColors = [ ...colors ];
|
||||
newValue.groupColors = [ ...colors ];
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -70,9 +70,9 @@ export const GroupTabColorsView: FC<GroupTabColorsViewProps> = props =>
|
||||
const groupColors = [ groupCustomize.groupColorsA[0].id, groupCustomize.groupColorsB[0].id ];
|
||||
|
||||
setGroupData(prevValue =>
|
||||
{
|
||||
return { ...prevValue, groupColors };
|
||||
});
|
||||
{
|
||||
return { ...prevValue, groupColors };
|
||||
});
|
||||
}, [ groupCustomize, groupData.groupColors, setGroupData ]);
|
||||
|
||||
useEffect(() =>
|
||||
@ -110,18 +110,18 @@ export const GroupTabColorsView: FC<GroupTabColorsViewProps> = props =>
|
||||
<Text bold>{ LocalizeText('group.edit.color.primary.color') }</Text>
|
||||
<AutoGrid gap={ 1 } columnCount={ 7 } columnMinWidth={ 16 } columnMinHeight={ 16 }>
|
||||
{ groupData.groupColors && groupCustomize.groupColorsA && groupCustomize.groupColorsA.map((item, index) =>
|
||||
{
|
||||
return <div key={ index } className={ 'group-badge-color-swatch cursor-pointer' + classNames({ ' active': (groupData.groupColors[0] === item.id) }) } style={{ backgroundColor: '#' + item.color }} onClick={ () => selectColor(0, item.id) }></div>
|
||||
}) }
|
||||
{
|
||||
return <div key={ index } className={ 'group-badge-color-swatch cursor-pointer' + classNames({ ' active': (groupData.groupColors[0] === item.id) }) } style={{ backgroundColor: '#' + item.color }} onClick={ () => selectColor(0, item.id) }></div>
|
||||
}) }
|
||||
</AutoGrid>
|
||||
</Column>
|
||||
<Column size={ 5 } gap={ 1 } overflow="hidden">
|
||||
<Text bold>{ LocalizeText('group.edit.color.secondary.color') }</Text>
|
||||
<AutoGrid gap={ 1 } columnCount={ 7 } columnMinWidth={ 16 } columnMinHeight={ 16 }>
|
||||
{ groupData.groupColors && groupCustomize.groupColorsB && groupCustomize.groupColorsB.map((item, index) =>
|
||||
{
|
||||
return <div key={ index } className={ 'group-badge-color-swatch cursor-pointer' + classNames({ ' active': (groupData.groupColors[1] === item.id) }) } style={{ backgroundColor: '#' + item.color }} onClick={ () => selectColor(1, item.id) }></div>
|
||||
}) }
|
||||
{
|
||||
return <div key={ index } className={ 'group-badge-color-swatch cursor-pointer' + classNames({ ' active': (groupData.groupColors[1] === item.id) }) } style={{ backgroundColor: '#' + item.color }} onClick={ () => selectColor(1, item.id) }></div>
|
||||
}) }
|
||||
</AutoGrid>
|
||||
</Column>
|
||||
</Grid>
|
||||
|
@ -2,7 +2,6 @@ import { GroupDeleteComposer, GroupSaveInformationComposer } from '@nitrots/nitr
|
||||
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
|
||||
import { CreateLinkEvent, LocalizeText, NotificationUtilities, SendMessageComposer } from '../../../../api';
|
||||
import { Base, Button, Column, Flex, Text } from '../../../../common';
|
||||
import { BatchUpdates } from '../../../../hooks';
|
||||
import { IGroupData } from '../../common/IGroupData';
|
||||
|
||||
interface GroupTabIdentityViewProps
|
||||
@ -27,11 +26,11 @@ export const GroupTabIdentityView: FC<GroupTabIdentityViewProps> = props =>
|
||||
if(!groupData || (groupData.groupId <= 0)) return;
|
||||
|
||||
NotificationUtilities.confirm(LocalizeText('group.deleteconfirm.desc'), () =>
|
||||
{
|
||||
SendMessageComposer(new GroupDeleteComposer(groupData.groupId));
|
||||
{
|
||||
SendMessageComposer(new GroupDeleteComposer(groupData.groupId));
|
||||
|
||||
if(close) close();
|
||||
}, null, null, null, LocalizeText('group.deleteconfirm.title'));
|
||||
if(close) close();
|
||||
}, null, null, null, LocalizeText('group.deleteconfirm.title'));
|
||||
}
|
||||
|
||||
const saveIdentity = useCallback(() =>
|
||||
@ -45,15 +44,15 @@ export const GroupTabIdentityView: FC<GroupTabIdentityViewProps> = props =>
|
||||
if(groupHomeroomId <= 0) return false;
|
||||
|
||||
setGroupData(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.groupName = groupName;
|
||||
newValue.groupDescription = groupDescription;
|
||||
newValue.groupHomeroomId = groupHomeroomId;
|
||||
newValue.groupName = groupName;
|
||||
newValue.groupDescription = groupDescription;
|
||||
newValue.groupHomeroomId = groupHomeroomId;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -65,12 +64,9 @@ export const GroupTabIdentityView: FC<GroupTabIdentityViewProps> = props =>
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setGroupName(groupData.groupName || '');
|
||||
setGroupDescription(groupData.groupDescription || '');
|
||||
setGroupHomeroomId(groupData.groupHomeroomId);
|
||||
});
|
||||
setGroupName(groupData.groupName || '');
|
||||
setGroupDescription(groupData.groupDescription || '');
|
||||
setGroupHomeroomId(groupData.groupHomeroomId);
|
||||
}, [ groupData ]);
|
||||
|
||||
useEffect(() =>
|
||||
|
@ -3,7 +3,6 @@ import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from '
|
||||
import { SendMessageComposer } from '../../../../api';
|
||||
import { LocalizeText } from '../../../../api/utils/LocalizeText';
|
||||
import { Column, Flex, HorizontalRule, Text } from '../../../../common';
|
||||
import { BatchUpdates } from '../../../../hooks';
|
||||
import { IGroupData } from '../../common/IGroupData';
|
||||
|
||||
const STATES: string[] = [ 'regular', 'exclusive', 'private' ];
|
||||
@ -30,14 +29,14 @@ export const GroupTabSettingsView: FC<GroupTabSettingsViewProps> = props =>
|
||||
if(groupData.groupId <= 0)
|
||||
{
|
||||
setGroupData(prevValue =>
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
{
|
||||
const newValue = { ...prevValue };
|
||||
|
||||
newValue.groupState = groupState;
|
||||
newValue.groupCanMembersDecorate = groupDecorate;
|
||||
newValue.groupState = groupState;
|
||||
newValue.groupCanMembersDecorate = groupDecorate;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
return newValue;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -49,11 +48,8 @@ export const GroupTabSettingsView: FC<GroupTabSettingsViewProps> = props =>
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setGroupState(groupData.groupState);
|
||||
setGroupDecorate(groupData.groupCanMembersDecorate);
|
||||
});
|
||||
setGroupState(groupData.groupState);
|
||||
setGroupDecorate(groupData.groupCanMembersDecorate);
|
||||
}, [ groupData ]);
|
||||
|
||||
useEffect(() =>
|
||||
@ -67,20 +63,20 @@ export const GroupTabSettingsView: FC<GroupTabSettingsViewProps> = props =>
|
||||
<Column overflow="auto">
|
||||
<Column>
|
||||
{ STATES.map((state, index) =>
|
||||
{
|
||||
return (
|
||||
<Flex key={ index } alignItems="center" gap={ 1 }>
|
||||
<input className="form-check-input" type="radio" name="groupState" checked={ (groupState === index) } onChange={ event => setGroupState(index) } />
|
||||
<Column gap={ 0 }>
|
||||
<Flex gap={ 1 }>
|
||||
<i className={ `icon icon-group-type-${ index }` } />
|
||||
<Text bold>{ LocalizeText(`group.edit.settings.type.${ state }.label`) }</Text>
|
||||
</Flex>
|
||||
<Text>{ LocalizeText(`group.edit.settings.type.${ state }.help`) }</Text>
|
||||
</Column>
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
{
|
||||
return (
|
||||
<Flex key={ index } alignItems="center" gap={ 1 }>
|
||||
<input className="form-check-input" type="radio" name="groupState" checked={ (groupState === index) } onChange={ event => setGroupState(index) } />
|
||||
<Column gap={ 0 }>
|
||||
<Flex gap={ 1 }>
|
||||
<i className={ `icon icon-group-type-${ index }` } />
|
||||
<Text bold>{ LocalizeText(`group.edit.settings.type.${ state }.label`) }</Text>
|
||||
</Flex>
|
||||
<Text>{ LocalizeText(`group.edit.settings.type.${ state }.help`) }</Text>
|
||||
</Column>
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
</Column>
|
||||
<HorizontalRule />
|
||||
<Flex alignItems="center" gap={ 1 }>
|
||||
|
@ -55,7 +55,7 @@ export const GuideToolView: FC<{}> = props =>
|
||||
setNoCloseButton(true);
|
||||
break;
|
||||
case GuideSessionState.GUIDE_ONGOING:
|
||||
setHeaderText(LocalizeText('guide.help.request.guide.ongoing.title', ['name'], [replacement]));
|
||||
setHeaderText(LocalizeText('guide.help.request.guide.ongoing.title', [ 'name' ], [ replacement ]));
|
||||
setNoCloseButton(true);
|
||||
break;
|
||||
case GuideSessionState.USER_CREATE:
|
||||
@ -67,7 +67,7 @@ export const GuideToolView: FC<{}> = props =>
|
||||
setNoCloseButton(true);
|
||||
break;
|
||||
case GuideSessionState.USER_ONGOING:
|
||||
setHeaderText(LocalizeText('guide.help.request.user.ongoing.title', ['name'], [replacement]));
|
||||
setHeaderText(LocalizeText('guide.help.request.user.ongoing.title', [ 'name' ], [ replacement ]));
|
||||
setNoCloseButton(true);
|
||||
break;
|
||||
case GuideSessionState.USER_FEEDBACK:
|
||||
@ -183,7 +183,7 @@ export const GuideToolView: FC<{}> = props =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
const messageGroups = [...ongoingMessageGroups];
|
||||
const messageGroups = [ ...ongoingMessageGroups ];
|
||||
|
||||
let lastGroup = messageGroups[messageGroups.length - 1];
|
||||
|
||||
@ -203,7 +203,7 @@ export const GuideToolView: FC<{}> = props =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
const messageGroups = [...ongoingMessageGroups];
|
||||
const messageGroups = [ ...ongoingMessageGroups ];
|
||||
|
||||
let lastGroup = messageGroups[messageGroups.length - 1];
|
||||
|
||||
@ -217,7 +217,7 @@ export const GuideToolView: FC<{}> = props =>
|
||||
|
||||
lastGroup.addChat(new GuideToolMessage(parser.roomName, parser.roomId));
|
||||
setOngoingMessageGroups(messageGroups);
|
||||
}, [isOnDuty, ongoingMessageGroups, ongoingUserId]);
|
||||
}, [ isOnDuty, ongoingMessageGroups, ongoingUserId ]);
|
||||
|
||||
UseMessageEventHook(GuideSessionInvitedToGuideRoomMessageEvent, onGuideSessionInvitedToGuideRoomMessageEvent);
|
||||
|
||||
@ -270,7 +270,7 @@ export const GuideToolView: FC<{}> = props =>
|
||||
switch(parts[1])
|
||||
{
|
||||
case 'tour':
|
||||
//Create Tour Request
|
||||
//Create Tour Request
|
||||
return;
|
||||
}
|
||||
}, []);
|
||||
@ -299,15 +299,15 @@ export const GuideToolView: FC<{}> = props =>
|
||||
case 'toggle_duty':
|
||||
if(!isHandlingBullyReports && !isHandlingGuideRequests && !isHandlingHelpRequests)
|
||||
{
|
||||
DispatchUiEvent(new NotificationAlertEvent([LocalizeText('guide.help.guide.tool.noqueueselected.message')], null, null, null, LocalizeText('guide.help.guide.tool.noqueueselected.caption'), null));
|
||||
DispatchUiEvent(new NotificationAlertEvent([ LocalizeText('guide.help.guide.tool.noqueueselected.message') ], null, null, null, LocalizeText('guide.help.guide.tool.noqueueselected.caption'), null));
|
||||
return;
|
||||
}
|
||||
|
||||
setIsOnDuty(v =>
|
||||
{
|
||||
SendMessageComposer(new GuideSessionOnDutyUpdateMessageComposer(!v, v ? false : isHandlingGuideRequests, v ? false : isHandlingHelpRequests, v ? false : isHandlingBullyReports));
|
||||
return !v;
|
||||
});
|
||||
{
|
||||
SendMessageComposer(new GuideSessionOnDutyUpdateMessageComposer(!v, v ? false : isHandlingGuideRequests, v ? false : isHandlingHelpRequests, v ? false : isHandlingBullyReports));
|
||||
return !v;
|
||||
});
|
||||
|
||||
return;
|
||||
case 'forum_link':
|
||||
@ -315,7 +315,7 @@ export const GuideToolView: FC<{}> = props =>
|
||||
window.open(url);
|
||||
return;
|
||||
}
|
||||
}, [isHandlingBullyReports, isHandlingGuideRequests, isHandlingHelpRequests]);
|
||||
}, [ isHandlingBullyReports, isHandlingGuideRequests, isHandlingHelpRequests ]);
|
||||
|
||||
if(!isVisible) return null;
|
||||
|
||||
|
@ -24,8 +24,8 @@ export const GuideToolAcceptView: FC<GuideToolAcceptViewProps> = props =>
|
||||
</Column>
|
||||
<Column gap={ 1 }>
|
||||
<Button variant="success" onClick={ event => answerRequest(true) }>
|
||||
{ LocalizeText('guide.help.request.guide.accept.accept.button') }
|
||||
</Button>
|
||||
{ LocalizeText('guide.help.request.guide.accept.accept.button') }
|
||||
</Button>
|
||||
<Button variant="danger" onClick={ event => answerRequest(false) }>
|
||||
{ LocalizeText('guide.help.request.guide.accept.skip.link') }
|
||||
</Button>
|
||||
|
@ -83,27 +83,27 @@ export const GuideToolOngoingView: FC<GuideToolOngoingViewProps> = props =>
|
||||
<Column overflow="hidden" gap={ 1 } className="bg-muted rounded chat-messages p-2">
|
||||
<Column overflow="auto">
|
||||
{ messageGroups.map((group, index) =>
|
||||
{
|
||||
return (
|
||||
<Flex fullWidth justifyContent={ isOwnChat(group.userId) ? 'end' : 'start' } gap={ 2 }>
|
||||
<Base shrink className="message-avatar">
|
||||
{ (!isOwnChat(group.userId)) &&
|
||||
{
|
||||
return (
|
||||
<Flex key={ index } fullWidth justifyContent={ isOwnChat(group.userId) ? 'end' : 'start' } gap={ 2 }>
|
||||
<Base shrink className="message-avatar">
|
||||
{ (!isOwnChat(group.userId)) &&
|
||||
<LayoutAvatarImageView figure={ userFigure } direction={ 2 } /> }
|
||||
</Base>
|
||||
<Base className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (isOwnChat(group.userId) ? 'right' : 'left') }>
|
||||
<Text bold>
|
||||
{ (isOwnChat(group.userId)) && GetSessionDataManager().userName }
|
||||
{ (!isOwnChat(group.userId)) && userName }
|
||||
</Text>
|
||||
{ group.messages.map((chat, index) => <Base key={ index } className="text-break">{ chat.message }</Base>) }
|
||||
</Base>
|
||||
{ (isOwnChat(group.userId)) &&
|
||||
</Base>
|
||||
<Base className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (isOwnChat(group.userId) ? 'right' : 'left') }>
|
||||
<Text bold>
|
||||
{ (isOwnChat(group.userId)) && GetSessionDataManager().userName }
|
||||
{ (!isOwnChat(group.userId)) && userName }
|
||||
</Text>
|
||||
{ group.messages.map((chat, index) => <Base key={ index } className="text-break">{ chat.message }</Base>) }
|
||||
</Base>
|
||||
{ (isOwnChat(group.userId)) &&
|
||||
<Base className="message-avatar flex-shrink-0">
|
||||
<LayoutAvatarImageView figure={ GetSessionDataManager().figure } direction={ 4 } />
|
||||
</Base> }
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
</Flex>
|
||||
);
|
||||
}) }
|
||||
</Column>
|
||||
</Column>
|
||||
<Column gap={ 1 }>
|
||||
|
@ -90,7 +90,7 @@ export const HcCenterView: FC<{}> = props =>
|
||||
setIsVisible(!isVisible);
|
||||
break;
|
||||
}
|
||||
}, [isVisible]);
|
||||
}, [ isVisible ]);
|
||||
|
||||
UseUiEvent(HcCenterEvent.TOGGLE_HC_CENTER, onHcCenterEvent);
|
||||
|
||||
@ -169,7 +169,7 @@ export const HcCenterView: FC<{}> = props =>
|
||||
AddEventLinkTracker(linkTracker);
|
||||
|
||||
return () => RemoveLinkEventTracker(linkTracker);
|
||||
}, [ linkReceived]);
|
||||
}, [ linkReceived ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
@ -201,14 +201,17 @@ export const HcCenterView: FC<{}> = props =>
|
||||
<Popover id="popover-basic">
|
||||
<Popover.Body className="text-black py-2 px-3">
|
||||
<h5>{LocalizeText('hccenter.breakdown.title')}</h5>
|
||||
<div>{LocalizeText('hccenter.breakdown.creditsspent', ['credits'], [kickbackData.totalCreditsSpent.toString()])}</div>
|
||||
<div>{LocalizeText('hccenter.breakdown.paydayfactor.percent', ['percent'], [(kickbackData.kickbackPercentage * 100).toString()])}</div>
|
||||
<div>{LocalizeText('hccenter.breakdown.streakbonus', ['credits'], [kickbackData.creditRewardForStreakBonus.toString()])}</div>
|
||||
<div>{LocalizeText('hccenter.breakdown.creditsspent', [ 'credits' ], [ kickbackData.totalCreditsSpent.toString() ])}</div>
|
||||
<div>{LocalizeText('hccenter.breakdown.paydayfactor.percent', [ 'percent' ], [ (kickbackData.kickbackPercentage * 100).toString() ])}</div>
|
||||
<div>{LocalizeText('hccenter.breakdown.streakbonus', [ 'credits' ], [ kickbackData.creditRewardForStreakBonus.toString() ])}</div>
|
||||
<hr className="w-100 text-black my-1" />
|
||||
<div>{LocalizeText('hccenter.breakdown.total', ['credits', 'actual'], [getHcPaydayAmount(),
|
||||
((((kickbackData.kickbackPercentage * kickbackData.totalCreditsSpent) + kickbackData.creditRewardForStreakBonus) * 100) / 100).toString()])}</div>
|
||||
<div className="btn btn-link text-primary p-0" onClick={() => { CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['payday.habbopage']) }}>{
|
||||
LocalizeText('hccenter.special.infolink')}
|
||||
<div>{LocalizeText('hccenter.breakdown.total', [ 'credits', 'actual' ], [ getHcPaydayAmount(),
|
||||
((((kickbackData.kickbackPercentage * kickbackData.totalCreditsSpent) + kickbackData.creditRewardForStreakBonus) * 100) / 100).toString() ])}</div>
|
||||
<div className="btn btn-link text-primary p-0" onClick={() =>
|
||||
{
|
||||
CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['payday.habbopage'])
|
||||
}}>{
|
||||
LocalizeText('hccenter.special.infolink')}
|
||||
</div>
|
||||
</Popover.Body>
|
||||
</Popover>
|
||||
@ -221,7 +224,10 @@ export const HcCenterView: FC<{}> = props =>
|
||||
<Column gap={ 1 }>
|
||||
<div className="hc-logo" />
|
||||
<Flex>
|
||||
<Button variant="success" onClick={ event => { CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['hc.buy_hc']) } }>
|
||||
<Button variant="success" onClick={ event =>
|
||||
{
|
||||
CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['hc.buy_hc'])
|
||||
} }>
|
||||
{ LocalizeText((clubStatus === ClubStatus.ACTIVE) ? 'hccenter.btn.extend' : 'hccenter.btn.buy') }
|
||||
</Button>
|
||||
</Flex>
|
||||
@ -243,7 +249,10 @@ export const HcCenterView: FC<{}> = props =>
|
||||
<Column className="rounded-start bg-primary p-2 payday-special mb-1">
|
||||
<h4 className="mb-1">{LocalizeText('hccenter.special.title')}</h4>
|
||||
<div>{LocalizeText('hccenter.special.info')}</div>
|
||||
<div className="btn btn-link text-white p-0 mt-auto align-self-baseline" onClick={() => { CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['payday.habbopage']) }}>{LocalizeText('hccenter.special.infolink')}</div>
|
||||
<div className="btn btn-link text-white p-0 mt-auto align-self-baseline" onClick={() =>
|
||||
{
|
||||
CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['payday.habbopage'])
|
||||
}}>{LocalizeText('hccenter.special.infolink')}</div>
|
||||
</Column>
|
||||
<div className="payday flex-shrink-0 p-2">
|
||||
<h5 className="mb-2 ms-2">{LocalizeText('hccenter.special.time.title')}</h5>
|
||||
@ -271,16 +280,22 @@ export const HcCenterView: FC<{}> = props =>
|
||||
<div className="rounded bg-success p-2 d-flex flex-row mb-0">
|
||||
<div>
|
||||
<h4 className="mb-1">{LocalizeText('hccenter.gift.title')}</h4>
|
||||
<div dangerouslySetInnerHTML={{ __html: unclaimedGifts > 0 ? LocalizeText('hccenter.unclaimedgifts', ['unclaimedgifts'], [unclaimedGifts.toString()]) : LocalizeText('hccenter.gift.info') }}></div>
|
||||
<div dangerouslySetInnerHTML={{ __html: unclaimedGifts > 0 ? LocalizeText('hccenter.unclaimedgifts', [ 'unclaimedgifts' ], [ unclaimedGifts.toString() ]) : LocalizeText('hccenter.gift.info') }}></div>
|
||||
</div>
|
||||
<button className="btn btn-primary btn-lg align-self-center ms-auto" onClick={() => { CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['hc.hc_gifts']) }}>{LocalizeText(clubStatus === ClubStatus.ACTIVE ? 'hccenter.btn.gifts.redeem' : 'hccenter.btn.gifts.view')}</button>
|
||||
<button className="btn btn-primary btn-lg align-self-center ms-auto" onClick={() =>
|
||||
{
|
||||
CreateLinkEvent('catalog/open/' + GetConfiguration('catalog.links')['hc.hc_gifts'])
|
||||
}}>{LocalizeText(clubStatus === ClubStatus.ACTIVE ? 'hccenter.btn.gifts.redeem' : 'hccenter.btn.gifts.view')}</button>
|
||||
</div>
|
||||
}
|
||||
{GetConfiguration('hc.center')['benefits.info'] &&
|
||||
<div className="benefits text-black py-2">
|
||||
<h5 className="mb-1 text-primary">{LocalizeText('hccenter.general.title')}</h5>
|
||||
<div className="mb-2" dangerouslySetInnerHTML={{ __html: LocalizeText('hccenter.general.info') }} />
|
||||
<button className="btn btn-link p-0 text-primary" onClick={() => { CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['benefits.habbopage']) }}>{LocalizeText('hccenter.general.infolink')}</button>
|
||||
<button className="btn btn-link p-0 text-primary" onClick={() =>
|
||||
{
|
||||
CreateLinkEvent('habbopages/' + GetConfiguration('hc.center')['benefits.habbopage'])
|
||||
}}>{LocalizeText('hccenter.general.infolink')}</button>
|
||||
</div>
|
||||
}
|
||||
</NitroCardContentView>
|
||||
|
@ -2,7 +2,7 @@
|
||||
export class BadgeResolver
|
||||
{
|
||||
public static default_badge: string = 'HC1';
|
||||
public static badges: string[] = ['ACH_VipHC1', 'ACH_VipHC2', 'ACH_VipHC3', 'ACH_VipHC4', 'ACH_VipHC5', 'HC1', 'HC2', 'HC3', 'HC4', 'HC5'];
|
||||
public static badges: string[] = [ 'ACH_VipHC1', 'ACH_VipHC2', 'ACH_VipHC3', 'ACH_VipHC4', 'ACH_VipHC5', 'HC1', 'HC2', 'HC3', 'HC4', 'HC5' ];
|
||||
|
||||
|
||||
public static getClubBadge(k: string[]): string
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user