mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-23 14:40:50 +01:00
More widget updates
This commit is contained in:
parent
34bfd96c4f
commit
06bc3f238e
@ -1,3 +1,99 @@
|
|||||||
|
.nitro-room-tools-container {
|
||||||
|
position: absolute;
|
||||||
|
bottom: $toolbar-height + 65px;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
.nitro-room-tools {
|
||||||
|
background: rgba($dark,.95);
|
||||||
|
box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
|
||||||
|
border-top-right-radius: $border-radius;
|
||||||
|
border-bottom-right-radius: $border-radius;
|
||||||
|
transition: all .2s ease;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
background: transparent;
|
||||||
|
padding: 3px 0px;
|
||||||
|
color: $white;
|
||||||
|
border-color: rgba($black, 0.3);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools-item {
|
||||||
|
.icon {
|
||||||
|
width: 22px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nitro-room-tools-info {
|
||||||
|
background: rgba($dark,.95);
|
||||||
|
box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
|
||||||
|
transition: all .2s ease;
|
||||||
|
pointer-events: none;
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wordquiz-question {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
font-size: large;
|
||||||
|
background: rgba($dark, 0.95);
|
||||||
|
box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
|
||||||
|
border-radius: $border-radius;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
.question {
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.word-quiz-dislike {
|
||||||
|
background: url("../../../assets/images/room-widgets/wordquiz-widget/thumbs-down.png");
|
||||||
|
width: 31px;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.word-quiz-like {
|
||||||
|
background: url("../../../assets/images/room-widgets/wordquiz-widget/thumbs-up.png");
|
||||||
|
width: 31px;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.word-quiz-dislike-sm {
|
||||||
|
background: url("../../../assets/images/room-widgets/wordquiz-widget/thumbs-down-small.png");
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.word-quiz-like-sm {
|
||||||
|
background: url("../../../assets/images/room-widgets/wordquiz-widget/thumbs-up-small.png");
|
||||||
|
height: 22px;
|
||||||
|
width: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
@import './avatar-info/AvatarInfoWidgetView';
|
@import './avatar-info/AvatarInfoWidgetView';
|
||||||
@import './chat/ChatWidgetView';
|
@import './chat/ChatWidgetView';
|
||||||
@import './chat-input/ChatInputView';
|
@import './chat-input/ChatInputView';
|
||||||
@ -6,6 +102,3 @@
|
|||||||
@import './friend-request/FriendRequestDialogView';
|
@import './friend-request/FriendRequestDialogView';
|
||||||
@import './furniture/FurnitureWidgets';
|
@import './furniture/FurnitureWidgets';
|
||||||
@import './infostand/InfoStandWidgetView';
|
@import './infostand/InfoStandWidgetView';
|
||||||
@import './object-location/ObjectLocationView';
|
|
||||||
@import './room-tools/RoomToolsWidgetView';
|
|
||||||
@import './word-quiz/WordQuizWidgetView';
|
|
||||||
|
@ -20,14 +20,4 @@
|
|||||||
background: url('../../../../assets/images/room-widgets/furni-context-menu/monsterplant-preview.png') no-repeat center;
|
background: url('../../../../assets/images/room-widgets/furni-context-menu/monsterplant-preview.png') no-repeat center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mannequin-preview {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 83px;
|
|
||||||
height: 130px;
|
|
||||||
background-image: url('../../../../assets/images/room-widgets/mannequin-widget/mannequin-spritesheet.png');
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,21 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nitro-mannequin {
|
||||||
|
}
|
||||||
|
|
||||||
|
.mannequin-preview {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 83px;
|
||||||
|
height: 130px;
|
||||||
|
background-image: url('../../../../assets/images/room-widgets/mannequin-widget/mannequin-spritesheet.png');
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
@import './friend-furni/FurnitureFriendFurniView';
|
@import './friend-furni/FurnitureFriendFurniView';
|
||||||
@import './manipulation-menu/FurnitureManipulationMenuView';
|
@import './manipulation-menu/FurnitureManipulationMenuView';
|
||||||
@import './mannequin/FurnitureMannequinView';
|
|
||||||
@import './stickie/FurnitureStickieView';
|
@import './stickie/FurnitureStickieView';
|
||||||
@import './high-score/FurnitureHighScoreView';
|
@import './high-score/FurnitureHighScoreView';
|
||||||
@import './youtube-tv/FurnitureYoutubeDisplayView';
|
@import './youtube-tv/FurnitureYoutubeDisplayView';
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { Base } from '../../../../../common';
|
||||||
|
import { AvatarImageView } from '../../../../shared/avatar-image/AvatarImageView';
|
||||||
|
import { CurrencyIcon } from '../../../../shared/currency-icon/CurrencyIcon';
|
||||||
|
|
||||||
|
interface FurnitureMannequinPreviewViewProps
|
||||||
|
{
|
||||||
|
figure: string;
|
||||||
|
clubLevel: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FurnitureMannequinPreviewView: FC<FurnitureMannequinPreviewViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { figure = null, clubLevel = 0 } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Base position="relative" className="mannequin-preview">
|
||||||
|
<AvatarImageView figure={ figure } direction={ 2 } />
|
||||||
|
{ (clubLevel > 0) &&
|
||||||
|
<CurrencyIcon className="position-absolute end-2 bottom-2" type="hc" /> }
|
||||||
|
</Base>
|
||||||
|
);
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
.nitro-mannequin {
|
|
||||||
width: 350px;
|
|
||||||
|
|
||||||
.mannequin-preview {
|
|
||||||
width: 83px;
|
|
||||||
height: 130px;
|
|
||||||
background-image: url('../../../../../assets/images/room-widgets/mannequin-widget/mannequin-spritesheet.png');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +1,17 @@
|
|||||||
import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, HabboClubLevelEnum, IAvatarFigureContainer, RoomControllerLevel } from '@nitrots/nitro-renderer';
|
import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, HabboClubLevelEnum, IAvatarFigureContainer, RoomControllerLevel } from '@nitrots/nitro-renderer';
|
||||||
import { FC, KeyboardEvent, useCallback, useEffect, useState } from 'react';
|
import { FC, KeyboardEvent, useCallback, useEffect, useState } from 'react';
|
||||||
import { GetAvatarRenderManager, GetSessionDataManager, LocalizeText, RoomWidgetUpdateMannequinEvent } from '../../../../../api';
|
import { GetAvatarRenderManager, GetSessionDataManager, LocalizeText, RoomWidgetUpdateMannequinEvent } from '../../../../../api';
|
||||||
|
import { Base } from '../../../../../common';
|
||||||
import { Button } from '../../../../../common/Button';
|
import { Button } from '../../../../../common/Button';
|
||||||
import { Column } from '../../../../../common/Column';
|
import { Column } from '../../../../../common/Column';
|
||||||
import { Flex } from '../../../../../common/Flex';
|
import { Flex } from '../../../../../common/Flex';
|
||||||
import { Grid } from '../../../../../common/Grid';
|
|
||||||
import { Text } from '../../../../../common/Text';
|
import { Text } from '../../../../../common/Text';
|
||||||
import { BatchUpdates, SendMessageHook } from '../../../../../hooks';
|
import { BatchUpdates, SendMessageHook } from '../../../../../hooks';
|
||||||
import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base';
|
import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout';
|
||||||
|
import { AvatarImageView } from '../../../../shared/avatar-image/AvatarImageView';
|
||||||
|
import { CurrencyIcon } from '../../../../shared/currency-icon/CurrencyIcon';
|
||||||
import { useRoomContext } from '../../../context/RoomContext';
|
import { useRoomContext } from '../../../context/RoomContext';
|
||||||
import { FurnitureMannequinPreviewView } from './views/preview/FurnitureMannequinPreviewView';
|
|
||||||
|
|
||||||
const MODE_NONE: number = -1;
|
const MODE_NONE: number = -1;
|
||||||
const MODE_CONTROLLER: number = 0;
|
const MODE_CONTROLLER: number = 0;
|
||||||
@ -143,8 +144,11 @@ export const FurnitureMannequinView: FC<{}> = props =>
|
|||||||
|
|
||||||
transformAsMannequinFigure(figureContainer);
|
transformAsMannequinFigure(figureContainer);
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
setRenderedFigure(figureContainer.getFigureString());
|
setRenderedFigure(figureContainer.getFigureString());
|
||||||
setRenderedClubLevel(clubLevel);
|
setRenderedClubLevel(clubLevel);
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MODE_UPDATE: {
|
case MODE_UPDATE: {
|
||||||
@ -152,16 +156,22 @@ export const FurnitureMannequinView: FC<{}> = props =>
|
|||||||
|
|
||||||
transformAsMannequinFigure(figureContainer);
|
transformAsMannequinFigure(figureContainer);
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
setRenderedFigure(figureContainer.getFigureString());
|
setRenderedFigure(figureContainer.getFigureString());
|
||||||
setRenderedClubLevel(GetAvatarRenderManager().getFigureClubLevel(figureContainer, GetSessionDataManager().gender, MANNEQUIN_CLOTHING_PART_TYPES));
|
setRenderedClubLevel(GetAvatarRenderManager().getFigureClubLevel(figureContainer, GetSessionDataManager().gender, MANNEQUIN_CLOTHING_PART_TYPES));
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MODE_PEER:
|
case MODE_PEER:
|
||||||
case MODE_NO_CLUB: {
|
case MODE_NO_CLUB: {
|
||||||
const figureContainer = getMergedFigureContainer(GetSessionDataManager().figure, figure);
|
const figureContainer = getMergedFigureContainer(GetSessionDataManager().figure, figure);
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
setRenderedFigure(figureContainer.getFigureString());
|
setRenderedFigure(figureContainer.getFigureString());
|
||||||
setRenderedClubLevel(clubLevel);
|
setRenderedClubLevel(clubLevel);
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,18 +180,22 @@ export const FurnitureMannequinView: FC<{}> = props =>
|
|||||||
if(mode === MODE_NONE) return null;
|
if(mode === MODE_NONE) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardView className="nitro-mannequin" simple={ true }>
|
<NitroCardView className="nitro-mannequin" simple>
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('mannequin.widget.title') } onCloseClick={ event => setMode(MODE_NONE) } />
|
<NitroCardHeaderView headerText={ LocalizeText('mannequin.widget.title') } onCloseClick={ event => setMode(MODE_NONE) } />
|
||||||
<NitroCardContentView>
|
<NitroCardContentView center>
|
||||||
<Grid>
|
<Flex gap={ 2 } overflow="hidden">
|
||||||
<Column center size={ 4 } overflow="hidden">
|
<Column>
|
||||||
<FurnitureMannequinPreviewView figure={ renderedFigure } clubLevel={ renderedClubLevel } />
|
<Base position="relative" className="mannequin-preview">
|
||||||
|
<AvatarImageView figure={ renderedFigure } direction={ 2 } />
|
||||||
|
{ (clubLevel > 0) &&
|
||||||
|
<CurrencyIcon className="position-absolute end-2 bottom-2" type="hc" /> }
|
||||||
|
</Base>
|
||||||
</Column>
|
</Column>
|
||||||
<Column size={ 8 } justifyContent="between" overflow="hidden">
|
<Column justifyContent="between" overflow="auto">
|
||||||
{ (mode === MODE_CONTROLLER) &&
|
{ (mode === MODE_CONTROLLER) &&
|
||||||
<>
|
<>
|
||||||
<input type="text" className="form-control" value={ name } onChange={ event => setName(event.target.value) } onKeyDown={ event => handleKeyDown(event) } />
|
<input type="text" className="form-control" value={ name } onChange={ event => setName(event.target.value) } onKeyDown={ event => handleKeyDown(event) } />
|
||||||
<Column gap={ 1 } overflow="auto">
|
<Column gap={ 1 }>
|
||||||
<Button variant="success" onClick={ event => setMode(MODE_UPDATE) }>
|
<Button variant="success" onClick={ event => setMode(MODE_UPDATE) }>
|
||||||
{ LocalizeText('mannequin.widget.style') }
|
{ LocalizeText('mannequin.widget.style') }
|
||||||
</Button>
|
</Button>
|
||||||
@ -192,9 +206,9 @@ export const FurnitureMannequinView: FC<{}> = props =>
|
|||||||
</> }
|
</> }
|
||||||
{ (mode === MODE_UPDATE) &&
|
{ (mode === MODE_UPDATE) &&
|
||||||
<>
|
<>
|
||||||
<Column gap={ 1 } overflow="auto">
|
<Column gap={ 1 }>
|
||||||
<Text fontWeight="bold">{ name }</Text>
|
<Text bold>{ name }</Text>
|
||||||
<Text>{ LocalizeText('mannequin.widget.savetext') }</Text>
|
<Text wrap>{ LocalizeText('mannequin.widget.savetext') }</Text>
|
||||||
</Column>
|
</Column>
|
||||||
<Flex alignItems="center" justifyContent="between">
|
<Flex alignItems="center" justifyContent="between">
|
||||||
<Text underline pointer onClick={ event => setMode(MODE_CONTROLLER) }>
|
<Text underline pointer onClick={ event => setMode(MODE_CONTROLLER) }>
|
||||||
@ -207,18 +221,20 @@ export const FurnitureMannequinView: FC<{}> = props =>
|
|||||||
</> }
|
</> }
|
||||||
{ (mode === MODE_PEER) &&
|
{ (mode === MODE_PEER) &&
|
||||||
<>
|
<>
|
||||||
<Column gap={ 1 } overflow="auto">
|
<Column gap={ 1 }>
|
||||||
<Text fontWeight="bold">{ name }</Text>
|
<Text bold>{ name }</Text>
|
||||||
<Text>{ LocalizeText('mannequin.widget.weartext') }</Text>
|
<Text>{ LocalizeText('mannequin.widget.weartext') }</Text>
|
||||||
</Column>
|
</Column>
|
||||||
<Button variant="success" onClick={ event => processAction(ACTION_WEAR) }>
|
<Button variant="success" onClick={ event => processAction(ACTION_WEAR) }>
|
||||||
{ LocalizeText('mannequin.widget.wear') }
|
{ LocalizeText('mannequin.widget.wear') }
|
||||||
</Button>
|
</Button>
|
||||||
</> }
|
</> }
|
||||||
{ (mode === MODE_NO_CLUB) && <Text>{ LocalizeText('mannequin.widget.clubnotification') }</Text> }
|
{ (mode === MODE_NO_CLUB) &&
|
||||||
{ (mode === MODE_WRONG_GENDER) && <Text>{ LocalizeText('mannequin.widget.wronggender') }</Text> }
|
<Text>{ LocalizeText('mannequin.widget.clubnotification') }</Text> }
|
||||||
|
{ (mode === MODE_WRONG_GENDER) &&
|
||||||
|
<Text>{ LocalizeText('mannequin.widget.wronggender') }</Text> }
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Flex>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
</NitroCardView>
|
</NitroCardView>
|
||||||
);
|
);
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
import { FC } from 'react';
|
|
||||||
import { NitroLayoutBase } from '../../../../../../../layout/base';
|
|
||||||
import { AvatarImageView } from '../../../../../../shared/avatar-image/AvatarImageView';
|
|
||||||
import { CurrencyIcon } from '../../../../../../shared/currency-icon/CurrencyIcon';
|
|
||||||
import { FurnitureMannequinPreviewViewProps } from './FurnitureMannequinPreviewView.types';
|
|
||||||
|
|
||||||
export const FurnitureMannequinPreviewView: FC<FurnitureMannequinPreviewViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { figure = null, clubLevel = 0 } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NitroLayoutBase className="mannequin-preview" position="relative">
|
|
||||||
<AvatarImageView figure={ figure } direction={ 2 } />
|
|
||||||
{ (clubLevel > 0) && <CurrencyIcon className="position-absolute end-2 bottom-2" type="hc" /> }
|
|
||||||
</NitroLayoutBase>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
export interface FurnitureMannequinPreviewViewProps
|
|
||||||
{
|
|
||||||
figure: string;
|
|
||||||
clubLevel: number;
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
.object-location {
|
|
||||||
}
|
|
@ -1,11 +1,17 @@
|
|||||||
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
import { FC, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { GetNitroInstance, GetRoomEngine, GetRoomSession } from '../../../../api';
|
import { GetNitroInstance, GetRoomEngine, GetRoomSession } from '../../../../api';
|
||||||
import { NitroLayoutBase } from '../../../../layout/base';
|
import { Base, BaseProps } from '../../../../common';
|
||||||
import { ObjectLocationViewProps } from './ObjectLocationView.types';
|
|
||||||
|
interface ObjectLocationViewProps extends BaseProps<HTMLDivElement>
|
||||||
|
{
|
||||||
|
objectId: number;
|
||||||
|
category: number;
|
||||||
|
noFollow?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export const ObjectLocationView: FC<ObjectLocationViewProps> = props =>
|
export const ObjectLocationView: FC<ObjectLocationViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { objectId = -1, category = -1, noFollow = false, children = null, ...rest } = props;
|
const { objectId = -1, category = -1, noFollow = false, position = 'absolute', ...rest } = props;
|
||||||
const [ pos, setPos ] = useState<{ x: number, y: number }>({ x: -1, y: -1 });
|
const [ pos, setPos ] = useState<{ x: number, y: number }>({ x: -1, y: -1 });
|
||||||
const elementRef = useRef<HTMLDivElement>();
|
const elementRef = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
@ -50,9 +56,5 @@ export const ObjectLocationView: FC<ObjectLocationViewProps> = props =>
|
|||||||
}
|
}
|
||||||
}, [ updatePosition, noFollow ]);
|
}, [ updatePosition, noFollow ]);
|
||||||
|
|
||||||
return (
|
return <Base innerRef={ elementRef } position={ position } visible={ (pos.x + (elementRef.current ? elementRef.current.offsetWidth : 0)) > -1 } className="object-location" style={ { left: pos.x, top: pos.y } } { ...rest } />;
|
||||||
<NitroLayoutBase innerRef={ elementRef } className={ 'object-location position-absolute ' + ( (pos.x + (elementRef.current ? elementRef.current.offsetWidth : 0 ) )> -1 ? 'visible' : 'invisible') } style={ { left: pos.x, top: pos.y } } { ...rest }>
|
|
||||||
{ children }
|
|
||||||
</NitroLayoutBase>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
import { NitroLayoutBaseProps } from '../../../../layout/base';
|
|
||||||
|
|
||||||
export interface ObjectLocationViewProps extends NitroLayoutBaseProps
|
|
||||||
{
|
|
||||||
objectId: number;
|
|
||||||
category: number;
|
|
||||||
noFollow?: boolean;
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
.nitro-room-tools-container {
|
|
||||||
position: absolute;
|
|
||||||
bottom: $toolbar-height + 65px;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
.nitro-room-tools {
|
|
||||||
background: rgba($dark,.95);
|
|
||||||
box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
|
|
||||||
border-top-right-radius: $border-radius;
|
|
||||||
border-bottom-right-radius: $border-radius;
|
|
||||||
transition: all .2s ease;
|
|
||||||
|
|
||||||
.list-group-item {
|
|
||||||
background: transparent;
|
|
||||||
padding: 3px 0px;
|
|
||||||
color: $white;
|
|
||||||
border-color: rgba($black, 0.3);
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
padding-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools-item {
|
|
||||||
.icon {
|
|
||||||
width: 22px;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nitro-room-tools-info {
|
|
||||||
margin-left: 10px;
|
|
||||||
background: rgba($dark,.95);
|
|
||||||
box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
|
|
||||||
transition: all .2s ease;
|
|
||||||
pointer-events: none;
|
|
||||||
max-width: 250px;
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,8 +4,10 @@ import { FC, useCallback, useEffect, useState } from 'react';
|
|||||||
import { CreateLinkEvent, LocalizeText, RoomWidgetZoomToggleMessage } from '../../../../api';
|
import { CreateLinkEvent, LocalizeText, RoomWidgetZoomToggleMessage } from '../../../../api';
|
||||||
import { Base, Column, Flex, Text } from '../../../../common';
|
import { Base, Column, Flex, Text } from '../../../../common';
|
||||||
import { NavigatorEvent } from '../../../../events';
|
import { NavigatorEvent } from '../../../../events';
|
||||||
|
import { BatchUpdates } from '../../../../hooks';
|
||||||
import { dispatchUiEvent } from '../../../../hooks/events';
|
import { dispatchUiEvent } from '../../../../hooks/events';
|
||||||
import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages';
|
import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages';
|
||||||
|
import { TransitionAnimation, TransitionAnimationTypes } from '../../../../layout';
|
||||||
import { useRoomContext } from '../../context/RoomContext';
|
import { useRoomContext } from '../../context/RoomContext';
|
||||||
|
|
||||||
export const RoomToolsWidgetView: FC<{}> = props =>
|
export const RoomToolsWidgetView: FC<{}> = props =>
|
||||||
@ -13,14 +15,13 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
const [ isZoomedIn, setIsZoomedIn ] = useState(false);
|
const [ isZoomedIn, setIsZoomedIn ] = useState(false);
|
||||||
const [ isLiked, setIsLiked ] = useState(false);
|
const [ isLiked, setIsLiked ] = useState(false);
|
||||||
const { widgetHandler = null } = useRoomContext();
|
const { widgetHandler = null } = useRoomContext();
|
||||||
|
|
||||||
const [ roomName, setRoomName ] = useState(null);
|
const [ roomName, setRoomName ] = useState(null);
|
||||||
const [ roomOwner, setRoomOwner ] = useState(null);
|
const [ roomOwner, setRoomOwner ] = useState(null);
|
||||||
const [ roomTags, setRoomTags ] = useState(null);
|
const [ roomTags, setRoomTags ] = useState(null);
|
||||||
const [ roomInfoDisplay, setRoomInfoDisplay ] = useState(false);
|
const [ roomInfoDisplay, setRoomInfoDisplay ] = useState(false);
|
||||||
const [ isOpen, setIsOpen ] = useState(false);
|
const [ isOpen, setIsOpen ] = useState(false);
|
||||||
|
|
||||||
const handleToolClick = useCallback((action: string) =>
|
const handleToolClick = (action: string) =>
|
||||||
{
|
{
|
||||||
switch(action)
|
switch(action)
|
||||||
{
|
{
|
||||||
@ -44,17 +45,18 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
dispatchUiEvent(new NavigatorEvent(NavigatorEvent.TOGGLE_ROOM_LINK));
|
dispatchUiEvent(new NavigatorEvent(NavigatorEvent.TOGGLE_ROOM_LINK));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, [ isZoomedIn, isLiked, widgetHandler ]);
|
}
|
||||||
|
|
||||||
const onGetGuestRoomResultEvent = useCallback((event: GetGuestRoomResultEvent) =>
|
const onGetGuestRoomResultEvent = useCallback((event: GetGuestRoomResultEvent) =>
|
||||||
{
|
{
|
||||||
const parser = event.getParser();
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
if(roomName !== parser.data.roomName) setRoomName(parser.data.roomName);
|
if(roomName !== parser.data.roomName) setRoomName(parser.data.roomName);
|
||||||
|
|
||||||
if(roomOwner !== parser.data.ownerName) setRoomOwner(parser.data.ownerName);
|
if(roomOwner !== parser.data.ownerName) setRoomOwner(parser.data.ownerName);
|
||||||
|
|
||||||
if(roomTags !== parser.data.tags) setRoomTags(parser.data.tags);
|
if(roomTags !== parser.data.tags) setRoomTags(parser.data.tags);
|
||||||
|
});
|
||||||
}, [ roomName, roomOwner, roomTags ]);
|
}, [ roomName, roomOwner, roomTags ]);
|
||||||
|
|
||||||
CreateMessageHook(GetGuestRoomResultEvent, onGetGuestRoomResultEvent);
|
CreateMessageHook(GetGuestRoomResultEvent, onGetGuestRoomResultEvent);
|
||||||
@ -69,26 +71,29 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
}, [ roomName, roomOwner, roomTags ]);
|
}, [ roomName, roomOwner, roomTags ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex className="nitro-room-tools-container">
|
<Flex className="nitro-room-tools-container" gap={ 2 }>
|
||||||
<Column center className="nitro-room-tools p-2">
|
<Column center className="nitro-room-tools p-2">
|
||||||
<Base pointer title={ LocalizeText('room.settings.button.text') } className="icon icon-cog" onClick={ () => handleToolClick('settings') } />
|
<Base pointer title={ LocalizeText('room.settings.button.text') } className="icon icon-cog" onClick={ () => handleToolClick('settings') } />
|
||||||
<Base pointer title={ LocalizeText('room.zoom.button.text') } onClick={ () => handleToolClick('zoom') } className={ 'icon ' + classNames({ 'icon-zoom-less': !isZoomedIn, 'icon-zoom-more': isZoomedIn }) } />
|
<Base pointer title={ LocalizeText('room.zoom.button.text') } onClick={ () => handleToolClick('zoom') } className={ 'icon ' + classNames({ 'icon-zoom-less': !isZoomedIn, 'icon-zoom-more': isZoomedIn }) } />
|
||||||
<Base pointer title={ LocalizeText('room.chathistory.button.text') } onClick={ () => handleToolClick('chat_history') } className="icon icon-chat-history" />
|
<Base pointer title={ LocalizeText('room.chathistory.button.text') } onClick={ () => handleToolClick('chat_history') } className="icon icon-chat-history" />
|
||||||
{ !isLiked && <Base pointer title={ LocalizeText('room.like.button.text') } onClick={ () => handleToolClick('like_room') } className="icon icon-like-room" /> }
|
{ !isLiked && <Base pointer title={ LocalizeText('room.like.button.text') } onClick={ () => handleToolClick('like_room') } className="icon icon-like-room" /> }
|
||||||
</Column>
|
</Column>
|
||||||
{ isOpen &&
|
<Column justifyContent="center">
|
||||||
|
<TransitionAnimation type={ TransitionAnimationTypes.SLIDE_LEFT } inProp={ isOpen } timeout={ 300 }>
|
||||||
<Column center>
|
<Column center>
|
||||||
<Column className="nitro-room-tools-info rounded py-2 px-3">
|
<Column className="nitro-room-tools-info rounded py-2 px-3">
|
||||||
<Column gap={ 1 }>
|
<Column gap={ 1 }>
|
||||||
<Text variant="white" fontSize={ 4 }>{ roomName }</Text>
|
<Text wrap variant="white" fontSize={ 4 }>{ roomName }</Text>
|
||||||
<Text variant="muted" fontSize={ 5 }>{ roomOwner }</Text>
|
<Text variant="muted" fontSize={ 5 }>{ roomOwner }</Text>
|
||||||
</Column>
|
</Column>
|
||||||
{ roomTags && roomTags.length > 0 &&
|
{ roomTags && roomTags.length > 0 &&
|
||||||
<div className="d-flex gap-2">
|
<Flex gap={ 2 }>
|
||||||
{ roomTags.map((tag: string) => <div className="rounded bg-primary text-white p-1 text-sm">#{ tag }</div>) }
|
{ roomTags.map((tag: string) => <Text small variant="white" className="rounded bg-primary p-1">#{ tag }</Text>) }
|
||||||
</div> }
|
</Flex> }
|
||||||
|
</Column>
|
||||||
|
</Column>
|
||||||
|
</TransitionAnimation>
|
||||||
</Column>
|
</Column>
|
||||||
</Column> }
|
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
import { RoomObjectCategory } from '@nitrots/nitro-renderer';
|
import { RoomObjectCategory } from '@nitrots/nitro-renderer';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
|
import { BaseProps } from '../../../../common';
|
||||||
import { useRoomContext } from '../../context/RoomContext';
|
import { useRoomContext } from '../../context/RoomContext';
|
||||||
import { ObjectLocationView } from '../object-location/ObjectLocationView';
|
import { ObjectLocationView } from '../object-location/ObjectLocationView';
|
||||||
import { UserLocationViewProps } from './UserLocationView.types';
|
|
||||||
|
interface UserLocationViewProps extends BaseProps<HTMLDivElement>
|
||||||
|
{
|
||||||
|
userId: number;
|
||||||
|
}
|
||||||
|
|
||||||
export const UserLocationView: FC<UserLocationViewProps> = props =>
|
export const UserLocationView: FC<UserLocationViewProps> = props =>
|
||||||
{
|
{
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
import { NitroLayoutBaseProps } from '../../../../layout/base';
|
|
||||||
|
|
||||||
export interface UserLocationViewProps extends NitroLayoutBaseProps
|
|
||||||
{
|
|
||||||
userId: number;
|
|
||||||
}
|
|
44
src/views/room/widgets/word-quiz/WordQuizQuestionView.tsx
Normal file
44
src/views/room/widgets/word-quiz/WordQuizQuestionView.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { Base, Column, Flex, Text } from '../../../../common';
|
||||||
|
import { VALUE_KEY_DISLIKE, VALUE_KEY_LIKE } from './common/VoteValue';
|
||||||
|
|
||||||
|
interface WordQuizQuestionViewProps
|
||||||
|
{
|
||||||
|
question: string;
|
||||||
|
canVote: boolean;
|
||||||
|
vote(value: string): void;
|
||||||
|
noVotes: number;
|
||||||
|
yesVotes: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WordQuizQuestionView: FC<WordQuizQuestionViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { question = null, canVote = null, vote = null, noVotes = null, yesVotes = null } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column gap={ 2 } className="wordquiz-question p-2">
|
||||||
|
{ !canVote &&
|
||||||
|
<Flex fullWidth alignItems="center" gap={ 2 }>
|
||||||
|
<Flex center pointer className="bg-danger rounded p-2">
|
||||||
|
<Text variant="white">{ noVotes }</Text>
|
||||||
|
</Flex>
|
||||||
|
<Text variant="white" center textBreak>{ question }</Text>
|
||||||
|
<Flex center pointer className="bg-success rounded p-2">
|
||||||
|
<Text variant="white">{ yesVotes }</Text>
|
||||||
|
</Flex>
|
||||||
|
</Flex> }
|
||||||
|
{ canVote &&
|
||||||
|
<Column>
|
||||||
|
<Text variant="white" center textBreak>{ question }</Text>
|
||||||
|
<Flex fullWidth justifyContent="center" gap={ 1 }>
|
||||||
|
<Flex center pointer className="bg-danger rounded p-1" onClick={ event => vote(VALUE_KEY_DISLIKE) }>
|
||||||
|
<Base className="word-quiz-dislike" />
|
||||||
|
</Flex>
|
||||||
|
<Flex center pointer className="bg-success rounded p-1" onClick={ event => vote(VALUE_KEY_LIKE) }>
|
||||||
|
<Base className="word-quiz-like" />
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Column> }
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
24
src/views/room/widgets/word-quiz/WordQuizVoteView.tsx
Normal file
24
src/views/room/widgets/word-quiz/WordQuizVoteView.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { RoomObjectCategory } from '@nitrots/nitro-renderer/src';
|
||||||
|
import { FC } from 'react';
|
||||||
|
import { Base, BaseProps, Flex } from '../../../../common';
|
||||||
|
import { ObjectLocationView } from '../object-location/ObjectLocationView';
|
||||||
|
import { VALUE_KEY_DISLIKE } from './common/VoteValue';
|
||||||
|
|
||||||
|
interface WordQuizVoteViewProps extends BaseProps<HTMLDivElement>
|
||||||
|
{
|
||||||
|
userIndex: number;
|
||||||
|
vote: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WordQuizVoteView: FC<WordQuizVoteViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { userIndex = null, vote = null, ...rest } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ObjectLocationView objectId={ userIndex } category={ RoomObjectCategory.UNIT } { ...rest }>
|
||||||
|
<Flex center pointer className={ `bg-${ (vote === VALUE_KEY_DISLIKE) ? 'danger' : 'success' } rounded p-1` }>
|
||||||
|
<Base className={ `word-quiz-${ (vote === VALUE_KEY_DISLIKE) ? 'dislike' : 'like' }-sm` } />
|
||||||
|
</Flex>
|
||||||
|
</ObjectLocationView>
|
||||||
|
);
|
||||||
|
}
|
@ -1,39 +0,0 @@
|
|||||||
.wordquiz-question {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
font-size: large;
|
|
||||||
background: rgba($dark, 0.9);
|
|
||||||
//box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
|
|
||||||
border-radius: $border-radius;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
|
|
||||||
.question {
|
|
||||||
max-width: 300px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.word-quiz-dislike {
|
|
||||||
background: url("../../../../assets/images/room-widgets/wordquiz-widget/thumbs-down.png");
|
|
||||||
width: 31px;
|
|
||||||
height: 34px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.word-quiz-like {
|
|
||||||
background: url("../../../../assets/images/room-widgets/wordquiz-widget/thumbs-up.png");
|
|
||||||
width: 31px;
|
|
||||||
height: 34px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.word-quiz-dislike-sm {
|
|
||||||
background: url("../../../../assets/images/room-widgets/wordquiz-widget/thumbs-down-small.png");
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.word-quiz-like-sm {
|
|
||||||
background: url("../../../../assets/images/room-widgets/wordquiz-widget/thumbs-up-small.png");
|
|
||||||
height: 22px;
|
|
||||||
width: 22px;
|
|
||||||
}
|
|
@ -5,21 +5,21 @@ import { RoomWidgetPollMessage } from '../../../../api/nitro/room/widgets/messag
|
|||||||
import { BatchUpdates, CreateEventDispatcherHook } from '../../../../hooks';
|
import { BatchUpdates, CreateEventDispatcherHook } from '../../../../hooks';
|
||||||
import { useRoomContext } from '../../context/RoomContext';
|
import { useRoomContext } from '../../context/RoomContext';
|
||||||
import { VALUE_KEY_DISLIKE, VALUE_KEY_LIKE, VoteValue } from './common/VoteValue';
|
import { VALUE_KEY_DISLIKE, VALUE_KEY_LIKE, VoteValue } from './common/VoteValue';
|
||||||
import { QuestionView } from './views/question/QuestionView';
|
import { WordQuizQuestionView } from './WordQuizQuestionView';
|
||||||
import { VoteView } from './views/vote/VoteView';
|
import { WordQuizVoteView } from './WordQuizVoteView';
|
||||||
|
|
||||||
const DEFAULT_DISPLAY_DELAY = 4000;
|
const DEFAULT_DISPLAY_DELAY = 4000;
|
||||||
const SIGN_FADE_DELAY = 3;
|
const SIGN_FADE_DELAY = 3;
|
||||||
|
|
||||||
export const WordQuizWidgetView: FC<{}> = props =>
|
export const WordQuizWidgetView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const { eventDispatcher = null, widgetHandler = null, roomSession = null } = useRoomContext();
|
|
||||||
const [ pollId, setPollId ] = useState(-1);
|
const [ pollId, setPollId ] = useState(-1);
|
||||||
const [ question, setQuestion ] = useState<IQuestion>(null);
|
const [ question, setQuestion ] = useState<IQuestion>(null);
|
||||||
const [ answerSent, setAnswerSent ] = useState(false);
|
const [ answerSent, setAnswerSent ] = useState(false);
|
||||||
const [ questionClearTimeout, setQuestionClearTimeout ] = useState<number>(null);
|
const [ questionClearTimeout, setQuestionClearTimeout ] = useState<number>(null);
|
||||||
const [ answerCounts, setAnswerCounts ] = useState<Map<string, number>>(new Map());
|
const [ answerCounts, setAnswerCounts ] = useState<Map<string, number>>(new Map());
|
||||||
const [ userAnswers, setUserAnswers ] = useState<Map<number, VoteValue>>(new Map());
|
const [ userAnswers, setUserAnswers ] = useState<Map<number, VoteValue>>(new Map());
|
||||||
|
const { eventDispatcher = null, widgetHandler = null, roomSession = null } = useRoomContext();
|
||||||
|
|
||||||
const clearQuestion = useCallback(() =>
|
const clearQuestion = useCallback(() =>
|
||||||
{
|
{
|
||||||
@ -39,33 +39,47 @@ export const WordQuizWidgetView: FC<{}> = props =>
|
|||||||
setAnswerSent(false);
|
setAnswerSent(false);
|
||||||
setAnswerCounts(new Map());
|
setAnswerCounts(new Map());
|
||||||
setUserAnswers(new Map());
|
setUserAnswers(new Map());
|
||||||
if(questionClearTimeout) clearTimeout(questionClearTimeout);
|
|
||||||
});
|
|
||||||
|
|
||||||
if(event.duration > 0)
|
|
||||||
{
|
|
||||||
const delay = event.duration < 1000 ? DEFAULT_DISPLAY_DELAY : event.duration;
|
|
||||||
setQuestionClearTimeout(prevValue =>
|
setQuestionClearTimeout(prevValue =>
|
||||||
{
|
{
|
||||||
if(prevValue) clearTimeout(prevValue);
|
if(prevValue) clearTimeout(prevValue);
|
||||||
|
|
||||||
return setTimeout((clearQuestion as TimerHandler), delay);
|
if(event.duration > 0)
|
||||||
})
|
{
|
||||||
|
const delay = event.duration < 1000 ? DEFAULT_DISPLAY_DELAY : event.duration;
|
||||||
|
|
||||||
|
return setTimeout(() => clearQuestion(), delay) as unknown as number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case RoomWidgetWordQuizUpdateEvent.QUESTION_ANSWERED:
|
case RoomWidgetWordQuizUpdateEvent.QUESTION_ANSWERED: {
|
||||||
const userData = roomSession.userDataManager.getUserData(event.userId);
|
const userData = roomSession.userDataManager.getUserData(event.userId);
|
||||||
|
|
||||||
if(!userData) return;
|
if(!userData) return;
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
setAnswerCounts(event.answerCounts);
|
setAnswerCounts(event.answerCounts);
|
||||||
|
|
||||||
if(!userAnswers.has(userData.roomIndex))
|
setUserAnswers(prevValue =>
|
||||||
{
|
{
|
||||||
const answersCopy = new Map(userAnswers);
|
if(!prevValue.has(userData.roomIndex))
|
||||||
answersCopy.set(userData.roomIndex, { value: event.value, secondsLeft: SIGN_FADE_DELAY });
|
{
|
||||||
setUserAnswers(answersCopy);
|
const newValue = new Map(userAnswers);
|
||||||
|
|
||||||
|
newValue.set(userData.roomIndex, { value: event.value, secondsLeft: SIGN_FADE_DELAY });
|
||||||
|
|
||||||
|
return newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return prevValue;
|
||||||
|
});
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RoomWidgetWordQuizUpdateEvent.QUESTION_FINISHED:
|
case RoomWidgetWordQuizUpdateEvent.QUESTION_FINISHED:
|
||||||
if(question && question.id === event.questionId)
|
if(question && question.id === event.questionId)
|
||||||
{
|
{
|
||||||
@ -73,18 +87,20 @@ export const WordQuizWidgetView: FC<{}> = props =>
|
|||||||
{
|
{
|
||||||
setAnswerCounts(event.answerCounts);
|
setAnswerCounts(event.answerCounts);
|
||||||
setAnswerSent(true);
|
setAnswerSent(true);
|
||||||
|
|
||||||
setQuestionClearTimeout(prevValue =>
|
setQuestionClearTimeout(prevValue =>
|
||||||
{
|
{
|
||||||
if(prevValue) clearTimeout(prevValue);
|
if(prevValue) clearTimeout(prevValue);
|
||||||
|
|
||||||
return setTimeout((clearQuestion as TimerHandler), DEFAULT_DISPLAY_DELAY);
|
return setTimeout(() => clearQuestion(), DEFAULT_DISPLAY_DELAY) as unknown as number;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setUserAnswers(new Map());
|
setUserAnswers(new Map());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}, [clearQuestion, question, questionClearTimeout, roomSession.userDataManager, userAnswers]);
|
}, [ question, roomSession.userDataManager, userAnswers, clearQuestion ]);
|
||||||
|
|
||||||
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.NEW_QUESTION, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.NEW_QUESTION, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
||||||
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.QUESTION_ANSWERED, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.QUESTION_ANSWERED, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
||||||
@ -95,48 +111,43 @@ export const WordQuizWidgetView: FC<{}> = props =>
|
|||||||
if(answerSent || !question) return;
|
if(answerSent || !question) return;
|
||||||
|
|
||||||
const updateMessage = new RoomWidgetPollMessage(RoomWidgetPollMessage.ANSWER, pollId);
|
const updateMessage = new RoomWidgetPollMessage(RoomWidgetPollMessage.ANSWER, pollId);
|
||||||
|
|
||||||
updateMessage.questionId = question.id;
|
updateMessage.questionId = question.id;
|
||||||
updateMessage.answers = [vote];
|
updateMessage.answers = [vote];
|
||||||
widgetHandler.processWidgetMessage(updateMessage);
|
|
||||||
setAnswerSent(true);
|
|
||||||
|
|
||||||
|
widgetHandler.processWidgetMessage(updateMessage);
|
||||||
|
|
||||||
|
setAnswerSent(true);
|
||||||
}, [ answerSent, pollId, question, widgetHandler ]);
|
}, [ answerSent, pollId, question, widgetHandler ]);
|
||||||
|
|
||||||
const checkSignFade = useCallback(() =>
|
const checkSignFade = useCallback(() =>
|
||||||
{
|
{
|
||||||
setUserAnswers(prev =>
|
setUserAnswers(prevValue =>
|
||||||
{
|
{
|
||||||
const keysToRemove: number[] = [];
|
const keysToRemove: number[] = [];
|
||||||
prev.forEach((value, key) =>
|
|
||||||
|
prevValue.forEach((value, key) =>
|
||||||
{
|
{
|
||||||
value.secondsLeft--;
|
value.secondsLeft--;
|
||||||
|
|
||||||
if(value.secondsLeft <= 0)
|
if(value.secondsLeft <= 0) keysToRemove.push(key);
|
||||||
{
|
|
||||||
keysToRemove.push(key);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if(keysToRemove.length === 0) return prev;
|
if(keysToRemove.length === 0) return prevValue;
|
||||||
|
|
||||||
|
const copy = new Map(prevValue);
|
||||||
|
|
||||||
const copy = new Map(prev);
|
|
||||||
keysToRemove.forEach(key => copy.delete(key));
|
keysToRemove.forEach(key => copy.delete(key));
|
||||||
return copy;
|
|
||||||
})
|
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
const interval = setInterval(() =>
|
const interval = setInterval(() => checkSignFade(), 1000);
|
||||||
{
|
|
||||||
checkSignFade();
|
|
||||||
}, 1000)
|
|
||||||
|
|
||||||
return () =>
|
return () => clearInterval(interval);
|
||||||
{
|
|
||||||
clearInterval(interval);
|
|
||||||
}
|
|
||||||
}, [ checkSignFade ]);
|
}, [ checkSignFade ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
@ -155,14 +166,9 @@ export const WordQuizWidgetView: FC<{}> = props =>
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{ question &&
|
{ question &&
|
||||||
<QuestionView question={question.content} canVote={!answerSent} vote={vote} noVotes={answerCounts.get(VALUE_KEY_DISLIKE) || 0} yesVotes={answerCounts.get(VALUE_KEY_LIKE) || 0} />
|
<WordQuizQuestionView question={question.content} canVote={!answerSent} vote={vote} noVotes={answerCounts.get(VALUE_KEY_DISLIKE) || 0} yesVotes={answerCounts.get(VALUE_KEY_LIKE) || 0} /> }
|
||||||
}
|
|
||||||
{ userAnswers &&
|
{ userAnswers &&
|
||||||
Array.from(userAnswers.entries()).map(([key, value], index) =>
|
Array.from(userAnswers.entries()).map(([key, value], index) => <WordQuizVoteView key={index} userIndex={key} vote={value.value} />) }
|
||||||
{
|
|
||||||
return <VoteView key={index} userIndex={key} vote={value.value} />
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import { FC } from 'react';
|
|
||||||
import { VALUE_KEY_DISLIKE, VALUE_KEY_LIKE } from '../../common/VoteValue';
|
|
||||||
import { QuestionViewProps } from './QuestionView.types';
|
|
||||||
|
|
||||||
export const QuestionView:FC<QuestionViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { question = null, canVote = null, vote = null, noVotes = null, yesVotes = null } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="wordquiz-question p-2 d-flex flex-column gap-2">
|
|
||||||
<div className="w-100 d-flex align-items-center gap-2">
|
|
||||||
{ !canVote && <button className="btn btn-danger btn-sm">{noVotes}</button> }
|
|
||||||
<div className="question text-center text-break">{question}</div>
|
|
||||||
{ !canVote && <button className="btn btn-success btn-sm">{yesVotes}</button> }
|
|
||||||
</div>
|
|
||||||
{canVote &&
|
|
||||||
<div className="w-100 d-flex justify-content-center gap-2">
|
|
||||||
<button className="btn btn-danger btn-sm"><div className="word-quiz-dislike" onClick={ () => vote(VALUE_KEY_DISLIKE) }/></button>
|
|
||||||
<button className="btn btn-success btn-sm"><div className="word-quiz-like" onClick={ () => vote(VALUE_KEY_LIKE) }/></button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
export interface QuestionViewProps
|
|
||||||
{
|
|
||||||
question: string;
|
|
||||||
canVote: boolean;
|
|
||||||
vote(value: string): void;
|
|
||||||
noVotes: number;
|
|
||||||
yesVotes: number;
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { RoomObjectCategory } from '@nitrots/nitro-renderer/src';
|
|
||||||
import { FC } from 'react';
|
|
||||||
import { ObjectLocationView } from '../../../object-location/ObjectLocationView';
|
|
||||||
import { VALUE_KEY_DISLIKE } from '../../common/VoteValue';
|
|
||||||
import { VoteViewProps } from './VoteView.types';
|
|
||||||
|
|
||||||
export const VoteView:FC<VoteViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { userIndex = null , vote = null } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ObjectLocationView objectId={userIndex} category={RoomObjectCategory.UNIT}>
|
|
||||||
<button className={`btn btn-${(vote === VALUE_KEY_DISLIKE) ? 'danger' : 'success'} btn-sm px-1`}><div className={`word-quiz-${(vote === VALUE_KEY_DISLIKE) ? 'dislike' : 'like'}-sm`} /></button>
|
|
||||||
</ObjectLocationView>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
export interface VoteViewProps
|
|
||||||
{
|
|
||||||
userIndex: number;
|
|
||||||
vote: string;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user