mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-27 08:00:51 +01:00
Merge pull request #33 from billsonnn/feature/room-quiz
Feature/room quiz
This commit is contained in:
commit
128919af62
110
src/api/nitro/room/widgets/events/RoomWidgetPollUpdateEvent.ts
Normal file
110
src/api/nitro/room/widgets/events/RoomWidgetPollUpdateEvent.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import { PollQuestion } from '@nitrots/nitro-renderer';
|
||||
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
|
||||
|
||||
export class RoomWidgetPollUpdateEvent extends RoomWidgetUpdateEvent
|
||||
{
|
||||
public static readonly OFFER = 'RWPUW_OFFER';
|
||||
public static readonly ERROR = 'RWPUW_ERROR';
|
||||
public static readonly CONTENT = 'RWPUW_CONTENT';
|
||||
|
||||
private _id = -1;
|
||||
private _summary: string;
|
||||
private _headline: string;
|
||||
private _numQuestions = 0;
|
||||
private _startMessage = '';
|
||||
private _endMessage = '';
|
||||
private _questionArray: PollQuestion[] = null;
|
||||
private _pollType = '';
|
||||
private _npsPoll = false;
|
||||
|
||||
constructor(type: string, id: number)
|
||||
{
|
||||
super(type);
|
||||
this._id = id;
|
||||
}
|
||||
|
||||
public get id(): number
|
||||
{
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get summary(): string
|
||||
{
|
||||
return this._summary;
|
||||
}
|
||||
|
||||
public set summary(k: string)
|
||||
{
|
||||
this._summary = k;
|
||||
}
|
||||
|
||||
public get headline(): string
|
||||
{
|
||||
return this._headline;
|
||||
}
|
||||
|
||||
public set headline(k: string)
|
||||
{
|
||||
this._headline = k;
|
||||
}
|
||||
|
||||
public get numQuestions(): number
|
||||
{
|
||||
return this._numQuestions;
|
||||
}
|
||||
|
||||
public set numQuestions(k: number)
|
||||
{
|
||||
this._numQuestions = k;
|
||||
}
|
||||
|
||||
public get startMessage(): string
|
||||
{
|
||||
return this._startMessage;
|
||||
}
|
||||
|
||||
public set startMessage(k: string)
|
||||
{
|
||||
this._startMessage = k;
|
||||
}
|
||||
|
||||
public get endMessage(): string
|
||||
{
|
||||
return this._endMessage;
|
||||
}
|
||||
|
||||
public set endMessage(k: string)
|
||||
{
|
||||
this._endMessage = k;
|
||||
}
|
||||
|
||||
public get questionArray(): PollQuestion[]
|
||||
{
|
||||
return this._questionArray;
|
||||
}
|
||||
|
||||
public set questionArray(k: PollQuestion[])
|
||||
{
|
||||
this._questionArray = k;
|
||||
}
|
||||
|
||||
public get pollType(): string
|
||||
{
|
||||
return this._pollType;
|
||||
}
|
||||
|
||||
public set pollType(k: string)
|
||||
{
|
||||
this._pollType = k;
|
||||
}
|
||||
|
||||
public get npsPoll(): boolean
|
||||
{
|
||||
return this._npsPoll;
|
||||
}
|
||||
|
||||
public set npsPoll(k: boolean)
|
||||
{
|
||||
this._npsPoll = k;
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
import { IQuestion } from '@nitrots/nitro-renderer';
|
||||
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
|
||||
|
||||
export class RoomWidgetWordQuizUpdateEvent extends RoomWidgetUpdateEvent
|
||||
{
|
||||
public static readonly NEW_QUESTION = 'RWPUW_NEW_QUESTION';
|
||||
public static readonly QUESTION_FINISHED = 'RWPUW_QUESION_FINSIHED';
|
||||
public static readonly QUESTION_ANSWERED = 'RWPUW_QUESTION_ANSWERED';
|
||||
|
||||
private _id: number = -1;
|
||||
private _pollType: string = null;
|
||||
private _pollId: number = -1;
|
||||
private _questionId: number = -1;
|
||||
private _duration: number = -1;
|
||||
private _question: IQuestion = null;
|
||||
private _userId: number = -1;
|
||||
private _value: string;
|
||||
private _answerCounts: Map<string, number>;
|
||||
|
||||
constructor(type: string, id: number)
|
||||
{
|
||||
super(type);
|
||||
this._id = id;
|
||||
}
|
||||
|
||||
public get id(): number
|
||||
{
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get pollType(): string
|
||||
{
|
||||
return this._pollType;
|
||||
}
|
||||
|
||||
public set pollType(k: string)
|
||||
{
|
||||
this._pollType = k;
|
||||
}
|
||||
|
||||
public get pollId(): number
|
||||
{
|
||||
return this._pollId;
|
||||
}
|
||||
|
||||
public set pollId(k: number)
|
||||
{
|
||||
this._pollId = k;
|
||||
}
|
||||
|
||||
public get questionId(): number
|
||||
{
|
||||
return this._questionId;
|
||||
}
|
||||
|
||||
public set questionId(k: number)
|
||||
{
|
||||
this._questionId = k;
|
||||
}
|
||||
|
||||
public get duration(): number
|
||||
{
|
||||
return this._duration;
|
||||
}
|
||||
|
||||
public set duration(k: number)
|
||||
{
|
||||
this._duration = k;
|
||||
}
|
||||
|
||||
public get question(): IQuestion
|
||||
{
|
||||
return this._question;
|
||||
}
|
||||
|
||||
public set question(k: IQuestion)
|
||||
{
|
||||
this._question = k;
|
||||
}
|
||||
|
||||
public get userId(): number
|
||||
{
|
||||
return this._userId;
|
||||
}
|
||||
|
||||
public set userId(k: number)
|
||||
{
|
||||
this._userId = k;
|
||||
}
|
||||
|
||||
public get value(): string
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
|
||||
public set value(k: string)
|
||||
{
|
||||
this._value = k;
|
||||
}
|
||||
|
||||
public get answerCounts(): Map<string, number>
|
||||
{
|
||||
return this._answerCounts;
|
||||
}
|
||||
|
||||
public set answerCounts(k: Map<string, number>)
|
||||
{
|
||||
this._answerCounts = k;
|
||||
}
|
||||
}
|
75
src/api/nitro/room/widgets/handlers/PollWidgetHandler.ts
Normal file
75
src/api/nitro/room/widgets/handlers/PollWidgetHandler.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { NitroEvent, RoomSessionPollEvent, RoomWidgetEnum } from '@nitrots/nitro-renderer';
|
||||
import { RoomWidgetPollUpdateEvent } from '../events/RoomWidgetPollUpdateEvent';
|
||||
import { RoomWidgetUpdateEvent } from '../events/RoomWidgetUpdateEvent';
|
||||
import { RoomWidgetMessage } from '../messages/RoomWidgetMessage';
|
||||
import { RoomWidgetPollMessage } from '../messages/RoomWidgetPollMessage';
|
||||
import { RoomWidgetHandler } from './RoomWidgetHandler';
|
||||
|
||||
export class PollWidgetHandler extends RoomWidgetHandler
|
||||
{
|
||||
public processEvent(event: NitroEvent): void
|
||||
{
|
||||
const pollEvent = (event as RoomSessionPollEvent);
|
||||
|
||||
let widgetEvent: RoomWidgetPollUpdateEvent;
|
||||
|
||||
switch(event.type)
|
||||
{
|
||||
case RoomSessionPollEvent.OFFER:
|
||||
widgetEvent = new RoomWidgetPollUpdateEvent(RoomWidgetPollUpdateEvent.OFFER, pollEvent.id);
|
||||
widgetEvent.summary = pollEvent.summary;
|
||||
widgetEvent.headline = pollEvent.headline;
|
||||
break;
|
||||
case RoomSessionPollEvent.ERROR:
|
||||
widgetEvent = new RoomWidgetPollUpdateEvent(RoomWidgetPollUpdateEvent.ERROR, pollEvent.id);
|
||||
widgetEvent.summary = pollEvent.summary;
|
||||
widgetEvent.headline = pollEvent.headline;
|
||||
break;
|
||||
case RoomSessionPollEvent.CONTENT:
|
||||
widgetEvent = new RoomWidgetPollUpdateEvent(RoomWidgetPollUpdateEvent.CONTENT, pollEvent.id);
|
||||
widgetEvent.startMessage = pollEvent.startMessage;
|
||||
widgetEvent.endMessage = pollEvent.endMessage;
|
||||
widgetEvent.numQuestions = pollEvent.numQuestions;
|
||||
widgetEvent.questionArray = pollEvent.questionArray;
|
||||
widgetEvent.npsPoll = pollEvent.npsPoll;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!widgetEvent) return;
|
||||
|
||||
this.container.eventDispatcher.dispatchEvent(widgetEvent);
|
||||
}
|
||||
|
||||
public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent
|
||||
{
|
||||
const pollMessage = (message as RoomWidgetPollMessage);
|
||||
switch(message.type)
|
||||
{
|
||||
case RoomWidgetPollMessage.START:
|
||||
this.container.roomSession.sendPollStartMessage(pollMessage.id);
|
||||
break;
|
||||
case RoomWidgetPollMessage.REJECT:
|
||||
this.container.roomSession.sendPollRejectMessage(pollMessage.id);
|
||||
break;
|
||||
case RoomWidgetPollMessage.ANSWER:
|
||||
this.container.roomSession.sendPollAnswerMessage(pollMessage.id, pollMessage.questionId, pollMessage.answers);
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public get type(): string
|
||||
{
|
||||
return RoomWidgetEnum.ROOM_POLL;
|
||||
}
|
||||
|
||||
public get eventTypes(): string[]
|
||||
{
|
||||
return [RoomSessionPollEvent.OFFER, RoomSessionPollEvent.ERROR, RoomSessionPollEvent.CONTENT];
|
||||
}
|
||||
|
||||
public get messageTypes(): string[]
|
||||
{
|
||||
return [RoomWidgetPollMessage.ANSWER, RoomWidgetPollMessage.REJECT, RoomWidgetPollMessage.START];
|
||||
}
|
||||
}
|
74
src/api/nitro/room/widgets/handlers/WordQuizWidgetHandler.ts
Normal file
74
src/api/nitro/room/widgets/handlers/WordQuizWidgetHandler.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { AvatarAction, NitroEvent, RoomSessionWordQuizEvent, RoomWidgetEnum } from '@nitrots/nitro-renderer';
|
||||
import { RoomWidgetHandler } from '.';
|
||||
import { GetRoomEngine } from '../../GetRoomEngine';
|
||||
import { RoomWidgetUpdateEvent } from '../events';
|
||||
import { RoomWidgetWordQuizUpdateEvent } from '../events/RoomWidgetWordQuizUpdateEvent';
|
||||
import { RoomWidgetMessage } from '../messages';
|
||||
|
||||
export class WordQuizWidgetHandler extends RoomWidgetHandler
|
||||
{
|
||||
public processEvent(event: NitroEvent): void
|
||||
{
|
||||
const roomQuizEvent = (event as RoomSessionWordQuizEvent);
|
||||
let widgetEvent: RoomWidgetWordQuizUpdateEvent;
|
||||
switch(event.type)
|
||||
{
|
||||
case RoomSessionWordQuizEvent.ANSWERED:
|
||||
const roomId = this.container.roomSession.roomId;
|
||||
const userData = this.container.roomSession.userDataManager.getUserData(roomQuizEvent.userId);
|
||||
if(!userData) return;
|
||||
widgetEvent = new RoomWidgetWordQuizUpdateEvent(RoomWidgetWordQuizUpdateEvent.QUESTION_ANSWERED, roomQuizEvent.id);
|
||||
widgetEvent.value = roomQuizEvent.value;
|
||||
widgetEvent.userId = roomQuizEvent.userId;
|
||||
widgetEvent.answerCounts = roomQuizEvent.answerCounts;
|
||||
|
||||
if(widgetEvent.value === '0')
|
||||
{
|
||||
GetRoomEngine().updateRoomObjectUserGesture(roomId, userData.roomIndex, AvatarAction.getGestureId(AvatarAction.GESTURE_SAD));
|
||||
}
|
||||
else
|
||||
{
|
||||
GetRoomEngine().updateRoomObjectUserGesture(roomId, userData.roomIndex, AvatarAction.getGestureId(AvatarAction.GESTURE_SMILE));
|
||||
}
|
||||
break;
|
||||
case RoomSessionWordQuizEvent.FINISHED:
|
||||
widgetEvent = new RoomWidgetWordQuizUpdateEvent(RoomWidgetWordQuizUpdateEvent.QUESTION_FINISHED, roomQuizEvent.id);
|
||||
widgetEvent.pollId = roomQuizEvent.pollId;
|
||||
widgetEvent.questionId = roomQuizEvent.questionId;
|
||||
widgetEvent.answerCounts = roomQuizEvent.answerCounts;
|
||||
break;
|
||||
case RoomSessionWordQuizEvent.QUESTION:
|
||||
widgetEvent = new RoomWidgetWordQuizUpdateEvent(RoomWidgetWordQuizUpdateEvent.NEW_QUESTION, roomQuizEvent.id);
|
||||
widgetEvent.question = roomQuizEvent.question;
|
||||
widgetEvent.duration = roomQuizEvent.duration;
|
||||
widgetEvent.pollType = roomQuizEvent.pollType;
|
||||
widgetEvent.questionId = roomQuizEvent.questionId;
|
||||
widgetEvent.pollId = roomQuizEvent.pollId;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!widgetEvent) return;
|
||||
|
||||
this.container.eventDispatcher.dispatchEvent(widgetEvent);
|
||||
}
|
||||
|
||||
public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public get type(): string
|
||||
{
|
||||
return RoomWidgetEnum.WORD_QUIZZ;
|
||||
}
|
||||
|
||||
public get eventTypes(): string[]
|
||||
{
|
||||
return [RoomSessionWordQuizEvent.ANSWERED, RoomSessionWordQuizEvent.FINISHED, RoomSessionWordQuizEvent.QUESTION];
|
||||
}
|
||||
|
||||
public get messageTypes(): string[]
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
44
src/api/nitro/room/widgets/messages/RoomWidgetPollMessage.ts
Normal file
44
src/api/nitro/room/widgets/messages/RoomWidgetPollMessage.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { RoomWidgetMessage } from './RoomWidgetMessage';
|
||||
|
||||
export class RoomWidgetPollMessage extends RoomWidgetMessage
|
||||
{
|
||||
public static readonly START = 'RWPM_START';
|
||||
public static readonly REJECT = 'RWPM_REJECT';
|
||||
public static readonly ANSWER = 'RWPM_ANSWER';
|
||||
|
||||
private _id = -1;
|
||||
private _questionId = 0;
|
||||
private _answers: string[] = null;
|
||||
|
||||
constructor(type: string, id: number)
|
||||
{
|
||||
super(type);
|
||||
|
||||
this._id = id;
|
||||
}
|
||||
|
||||
public get id(): number
|
||||
{
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get questionId(): number
|
||||
{
|
||||
return this._questionId;
|
||||
}
|
||||
|
||||
public set questionId(k: number)
|
||||
{
|
||||
this._questionId = k;
|
||||
}
|
||||
|
||||
public get answers(): string[]
|
||||
{
|
||||
return this._answers;
|
||||
}
|
||||
|
||||
public set answers(k: string[])
|
||||
{
|
||||
this._answers = k;
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 145 B |
BIN
src/assets/images/room-widgets/wordquiz-widget/thumbs-down.png
Normal file
BIN
src/assets/images/room-widgets/wordquiz-widget/thumbs-down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 182 B |
Binary file not shown.
After Width: | Height: | Size: 135 B |
BIN
src/assets/images/room-widgets/wordquiz-widget/thumbs-up.png
Normal file
BIN
src/assets/images/room-widgets/wordquiz-widget/thumbs-up.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 174 B |
@ -2,6 +2,8 @@ import { EventDispatcher, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector
|
||||
import { FC, useEffect, useRef, useState } from 'react';
|
||||
import { DispatchMouseEvent, DispatchTouchEvent, DoorbellWidgetHandler, FriendRequestHandler, FurniChooserWidgetHandler, FurnitureContextMenuWidgetHandler, FurnitureCreditWidgetHandler, FurnitureCustomStackHeightWidgetHandler, FurnitureDimmerWidgetHandler, FurnitureExternalImageWidgetHandler, FurnitureMannequinWidgetHandler, FurniturePresentWidgetHandler, GetNitroInstance, GetRoomEngine, InitializeRoomInstanceRenderingCanvas, IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler, RoomWidgetRoomToolsHandler, RoomWidgetUpdateRoomViewEvent, UserChooserWidgetHandler } from '../../api';
|
||||
import { FurnitureYoutubeDisplayWidgetHandler } from '../../api/nitro/room/widgets/handlers/FurnitureYoutubeDisplayWidgetHandler';
|
||||
import { PollWidgetHandler } from '../../api/nitro/room/widgets/handlers/PollWidgetHandler';
|
||||
import { WordQuizWidgetHandler } from '../../api/nitro/room/widgets/handlers/WordQuizWidgetHandler';
|
||||
import { RoomContextProvider } from './context/RoomContext';
|
||||
import { RoomColorView } from './RoomColorView';
|
||||
import { RoomViewProps } from './RoomView.types';
|
||||
@ -37,6 +39,8 @@ export const RoomView: FC<RoomViewProps> = props =>
|
||||
widgetHandlerManager.registerHandler(new RoomWidgetChatHandler());
|
||||
widgetHandlerManager.registerHandler(new UserChooserWidgetHandler());
|
||||
widgetHandlerManager.registerHandler(new DoorbellWidgetHandler());
|
||||
widgetHandlerManager.registerHandler(new WordQuizWidgetHandler());
|
||||
widgetHandlerManager.registerHandler(new PollWidgetHandler());
|
||||
widgetHandlerManager.registerHandler(new FriendRequestHandler());
|
||||
|
||||
widgetHandlerManager.registerHandler(new FurniChooserWidgetHandler());
|
||||
|
@ -8,3 +8,4 @@
|
||||
@import './object-location/ObjectLocationView';
|
||||
@import './room-tools/RoomToolsWidgetView';
|
||||
@import './choosers/ChooserWidgetView';
|
||||
@import './word-quiz/WordQuizWidgetView';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { RoomEngineEvent, RoomEngineObjectEvent, RoomEngineRoomAdEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomObjectVariable, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomZoomEvent } from '@nitrots/nitro-renderer';
|
||||
import { RoomEngineEvent, RoomEngineObjectEvent, RoomEngineRoomAdEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomObjectVariable, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPollEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomSessionWordQuizEvent, RoomZoomEvent } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback } from 'react';
|
||||
import { CanManipulateFurniture, GetRoomEngine, GetSessionDataManager, IsFurnitureSelectionDisabled, LocalizeText, ProcessRoomObjectOperation, RoomWidgetFurniToWidgetMessage, RoomWidgetUpdateRoomEngineEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../api';
|
||||
import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks/events';
|
||||
@ -15,6 +15,7 @@ import { FurnitureWidgetsView } from './furniture/FurnitureWidgetsView';
|
||||
import { InfoStandWidgetView } from './infostand/InfoStandWidgetView';
|
||||
import { RoomThumbnailWidgetView } from './room-thumbnail/RoomThumbnailWidgetView';
|
||||
import { RoomToolsWidgetView } from './room-tools/RoomToolsWidgetView';
|
||||
import { WordQuizWidgetView } from './word-quiz/WordQuizWidgetView';
|
||||
|
||||
export const RoomWidgetsView: FC<{}> = props =>
|
||||
{
|
||||
@ -268,6 +269,12 @@ export const RoomWidgetsView: FC<{}> = props =>
|
||||
useRoomSessionManagerEvent(RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST, onRoomSessionEvent);
|
||||
useRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onRoomSessionEvent);
|
||||
useRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, onRoomSessionEvent);
|
||||
useRoomSessionManagerEvent(RoomSessionWordQuizEvent.ANSWERED, onRoomSessionEvent);
|
||||
useRoomSessionManagerEvent(RoomSessionWordQuizEvent.FINISHED, onRoomSessionEvent);
|
||||
useRoomSessionManagerEvent(RoomSessionWordQuizEvent.QUESTION, onRoomSessionEvent);
|
||||
useRoomSessionManagerEvent(RoomSessionPollEvent.OFFER, onRoomSessionEvent);
|
||||
useRoomSessionManagerEvent(RoomSessionPollEvent.ERROR, onRoomSessionEvent);
|
||||
useRoomSessionManagerEvent(RoomSessionPollEvent.CONTENT, onRoomSessionEvent);
|
||||
|
||||
const onRoomSessionErrorMessageEvent = useCallback((event: RoomSessionErrorMessageEvent) =>
|
||||
{
|
||||
@ -349,6 +356,7 @@ export const RoomWidgetsView: FC<{}> = props =>
|
||||
<RoomThumbnailWidgetView />
|
||||
<FurniChooserWidgetView />
|
||||
<UserChooserWidgetView />
|
||||
<WordQuizWidgetView />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
39
src/views/room/widgets/word-quiz/WordQuizWidgetView.scss
Normal file
39
src/views/room/widgets/word-quiz/WordQuizWidgetView.scss
Normal file
@ -0,0 +1,39 @@
|
||||
.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;
|
||||
}
|
167
src/views/room/widgets/word-quiz/WordQuizWidgetView.tsx
Normal file
167
src/views/room/widgets/word-quiz/WordQuizWidgetView.tsx
Normal file
@ -0,0 +1,167 @@
|
||||
import { IQuestion } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { RoomWidgetWordQuizUpdateEvent } from '../../../../api/nitro/room/widgets/events/RoomWidgetWordQuizUpdateEvent';
|
||||
import { RoomWidgetPollMessage } from '../../../../api/nitro/room/widgets/messages/RoomWidgetPollMessage';
|
||||
import { BatchUpdates, CreateEventDispatcherHook } from '../../../../hooks';
|
||||
import { useRoomContext } from '../../context/RoomContext';
|
||||
import { VALUE_KEY_DISLIKE, VALUE_KEY_LIKE, VoteValue } from './common/VoteValue';
|
||||
import { QuestionView } from './views/question/QuestionView';
|
||||
import { VoteView } from './views/vote/VoteView';
|
||||
|
||||
const DEFAULT_DISPLAY_DELAY = 4000;
|
||||
const SIGN_FADE_DELAY = 3;
|
||||
|
||||
export const WordQuizWidgetView: FC<{}> = props =>
|
||||
{
|
||||
const { eventDispatcher = null, widgetHandler = null, roomSession = null } = useRoomContext();
|
||||
const [pollId, setPollId] = useState(-1);
|
||||
const [question, setQuestion] = useState<IQuestion>(null);
|
||||
const [answerSent, setAnswerSent] = useState(false);
|
||||
const [questionClearTimeout, setQuestionClearTimeout] = useState<number>(null);
|
||||
const [answerCounts, setAnswerCounts] = useState<Map<string, number>>(new Map());
|
||||
const [userAnswers, setUserAnswers] = useState<Map<number, VoteValue>>(new Map());
|
||||
|
||||
const clearQuestion = useCallback(() =>
|
||||
{
|
||||
setPollId(-1);
|
||||
setQuestion(null);
|
||||
}, []);
|
||||
|
||||
const onRoomWidgetWordQuizUpdateEvent = useCallback((event: RoomWidgetWordQuizUpdateEvent) =>
|
||||
{
|
||||
switch(event.type)
|
||||
{
|
||||
case RoomWidgetWordQuizUpdateEvent.NEW_QUESTION:
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setPollId(event.id);
|
||||
setQuestion(event.question);
|
||||
setAnswerSent(false);
|
||||
setAnswerCounts(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 =>
|
||||
{
|
||||
if(prevValue) clearTimeout(prevValue);
|
||||
|
||||
return setTimeout((clearQuestion as TimerHandler), delay);
|
||||
})
|
||||
}
|
||||
break;
|
||||
case RoomWidgetWordQuizUpdateEvent.QUESTION_ANSWERED:
|
||||
const userData = roomSession.userDataManager.getUserData(event.userId);
|
||||
if(!userData) return;
|
||||
|
||||
setAnswerCounts(event.answerCounts);
|
||||
|
||||
if(!userAnswers.has(userData.roomIndex))
|
||||
{
|
||||
const answersCopy = new Map(userAnswers);
|
||||
answersCopy.set(userData.roomIndex, { value: event.value, secondsLeft: SIGN_FADE_DELAY });
|
||||
setUserAnswers(answersCopy);
|
||||
}
|
||||
break;
|
||||
case RoomWidgetWordQuizUpdateEvent.QUESTION_FINISHED:
|
||||
if(question && question.id === event.questionId)
|
||||
{
|
||||
BatchUpdates(() =>
|
||||
{
|
||||
setAnswerCounts(event.answerCounts);
|
||||
setAnswerSent(true);
|
||||
setQuestionClearTimeout(prevValue =>
|
||||
{
|
||||
if(prevValue) clearTimeout(prevValue);
|
||||
|
||||
return setTimeout((clearQuestion as TimerHandler), DEFAULT_DISPLAY_DELAY);
|
||||
});
|
||||
})
|
||||
}
|
||||
setUserAnswers(new Map());
|
||||
break;
|
||||
}
|
||||
}, [clearQuestion, question, questionClearTimeout, roomSession.userDataManager, userAnswers]);
|
||||
|
||||
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.NEW_QUESTION, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
||||
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.QUESTION_ANSWERED, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
||||
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.QUESTION_FINISHED, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
||||
|
||||
const vote = useCallback((vote: string) =>
|
||||
{
|
||||
if(answerSent || !question) return;
|
||||
|
||||
const updateMessage = new RoomWidgetPollMessage(RoomWidgetPollMessage.ANSWER, pollId);
|
||||
updateMessage.questionId = question.id;
|
||||
updateMessage.answers = [vote];
|
||||
widgetHandler.processWidgetMessage(updateMessage);
|
||||
setAnswerSent(true);
|
||||
|
||||
}, [answerSent, pollId, question, widgetHandler]);
|
||||
|
||||
const checkSignFade = useCallback(() =>
|
||||
{
|
||||
setUserAnswers(prev =>
|
||||
{
|
||||
const copy = new Map(prev);
|
||||
const keysToRemove: number[] = [];
|
||||
copy.forEach((value, key) =>
|
||||
{
|
||||
value.secondsLeft--;
|
||||
|
||||
if(value.secondsLeft <= 0)
|
||||
{
|
||||
keysToRemove.push(key);
|
||||
}
|
||||
});
|
||||
|
||||
keysToRemove.forEach(key => copy.delete(key));
|
||||
|
||||
return copy;
|
||||
})
|
||||
|
||||
}, []);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
const interval = setInterval(() =>
|
||||
{
|
||||
checkSignFade();
|
||||
}, 1000)
|
||||
|
||||
return () =>
|
||||
{
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, [checkSignFade]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
setQuestionClearTimeout(prev =>
|
||||
{
|
||||
if(prev) clearTimeout(prev);
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{question &&
|
||||
<QuestionView question={question.content} canVote={!answerSent} vote={vote} noVotes={answerCounts.get(VALUE_KEY_DISLIKE) || 0} yesVotes={answerCounts.get(VALUE_KEY_LIKE) || 0} />
|
||||
}
|
||||
{userAnswers &&
|
||||
Array.from(userAnswers.entries()).map(([key, value], index) =>
|
||||
{
|
||||
return <VoteView key={index} userIndex={key} vote={value.value} />
|
||||
})
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
8
src/views/room/widgets/word-quiz/common/VoteValue.ts
Normal file
8
src/views/room/widgets/word-quiz/common/VoteValue.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export const VALUE_KEY_DISLIKE = '0';
|
||||
export const VALUE_KEY_LIKE = '1';
|
||||
|
||||
export interface VoteValue
|
||||
{
|
||||
value: string;
|
||||
secondsLeft: number;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
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>
|
||||
)
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
|
||||
export interface QuestionViewProps
|
||||
{
|
||||
question: string;
|
||||
canVote: boolean;
|
||||
vote(value: string): void;
|
||||
noVotes: number;
|
||||
yesVotes: number;
|
||||
}
|
16
src/views/room/widgets/word-quiz/views/vote/VoteView.tsx
Normal file
16
src/views/room/widgets/word-quiz/views/vote/VoteView.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
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>
|
||||
)
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
export interface VoteViewProps
|
||||
{
|
||||
userIndex: number;
|
||||
vote: string;
|
||||
}
|
Loading…
Reference in New Issue
Block a user