mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-23 14:40:50 +01:00
finished logic
This commit is contained in:
parent
b7c978c786
commit
1e84760324
@ -43,7 +43,6 @@ export class PollWidgetHandler extends RoomWidgetHandler
|
|||||||
public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent
|
public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent
|
||||||
{
|
{
|
||||||
const pollMessage = (message as RoomWidgetPollMessage);
|
const pollMessage = (message as RoomWidgetPollMessage);
|
||||||
|
|
||||||
switch(message.type)
|
switch(message.type)
|
||||||
{
|
{
|
||||||
case RoomWidgetPollMessage.START:
|
case RoomWidgetPollMessage.START:
|
||||||
|
@ -11,7 +11,6 @@ export class WordQuizWidgetHandler extends RoomWidgetHandler
|
|||||||
{
|
{
|
||||||
const roomQuizEvent = (event as RoomSessionWordQuizEvent);
|
const roomQuizEvent = (event as RoomSessionWordQuizEvent);
|
||||||
let widgetEvent: RoomWidgetWordQuizUpdateEvent;
|
let widgetEvent: RoomWidgetWordQuizUpdateEvent;
|
||||||
|
|
||||||
switch(event.type)
|
switch(event.type)
|
||||||
{
|
{
|
||||||
case RoomSessionWordQuizEvent.ANSWERED:
|
case RoomSessionWordQuizEvent.ANSWERED:
|
||||||
|
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 |
@ -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 { FC, useCallback } from 'react';
|
||||||
import { CanManipulateFurniture, GetRoomEngine, GetSessionDataManager, IsFurnitureSelectionDisabled, LocalizeText, ProcessRoomObjectOperation, RoomWidgetFurniToWidgetMessage, RoomWidgetUpdateRoomEngineEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../api';
|
import { CanManipulateFurniture, GetRoomEngine, GetSessionDataManager, IsFurnitureSelectionDisabled, LocalizeText, ProcessRoomObjectOperation, RoomWidgetFurniToWidgetMessage, RoomWidgetUpdateRoomEngineEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../api';
|
||||||
import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks/events';
|
import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks/events';
|
||||||
@ -269,6 +269,12 @@ export const RoomWidgetsView: FC<RoomWidgetViewProps> = props =>
|
|||||||
useRoomSessionManagerEvent(RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST, onRoomSessionEvent);
|
useRoomSessionManagerEvent(RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST, onRoomSessionEvent);
|
||||||
useRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onRoomSessionEvent);
|
useRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onRoomSessionEvent);
|
||||||
useRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, 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) =>
|
const onRoomSessionErrorMessageEvent = useCallback((event: RoomSessionErrorMessageEvent) =>
|
||||||
{
|
{
|
||||||
|
@ -1,12 +1,39 @@
|
|||||||
.word-quiz-question-container {
|
.wordquiz-question {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
left: 0px;
|
left: 50%;
|
||||||
.wordquiz-question {
|
transform: translateX(-50%);
|
||||||
font-size: large;
|
font-size: large;
|
||||||
background: rgba($dark, 0.90);
|
background: rgba($dark, 0.9);
|
||||||
//box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
|
//box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
|
||||||
border-radius: $border-radius;
|
border-radius: $border-radius;
|
||||||
transition: all 0.2s ease;
|
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;
|
||||||
|
}
|
||||||
|
@ -1,17 +1,32 @@
|
|||||||
import { IQuestion } from '@nitrots/nitro-renderer';
|
import { IQuestion } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { RoomWidgetWordQuizUpdateEvent } from '../../../../api/nitro/room/widgets/events/RoomWidgetWordQuizUpdateEvent';
|
import { RoomWidgetWordQuizUpdateEvent } from '../../../../api/nitro/room/widgets/events/RoomWidgetWordQuizUpdateEvent';
|
||||||
|
import { RoomWidgetPollMessage } from '../../../../api/nitro/room/widgets/messages/RoomWidgetPollMessage';
|
||||||
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 { QuestionView } from './views/question/QuestionView';
|
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 =>
|
export const WordQuizWidgetView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const { eventDispatcher = null, widgetHandler = null } = useRoomContext();
|
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 [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) =>
|
const onRoomWidgetWordQuizUpdateEvent = useCallback((event: RoomWidgetWordQuizUpdateEvent) =>
|
||||||
{
|
{
|
||||||
switch(event.type)
|
switch(event.type)
|
||||||
@ -22,25 +37,131 @@ export const WordQuizWidgetView: FC<{}> = props =>
|
|||||||
setPollId(event.id);
|
setPollId(event.id);
|
||||||
setQuestion(event.question);
|
setQuestion(event.question);
|
||||||
setAnswerSent(false);
|
setAnswerSent(false);
|
||||||
|
setAnswerCounts(new Map());
|
||||||
|
setUserAnswers(new Map());
|
||||||
|
if(questionClearTimeout) clearTimeout(questionClearTimeout);
|
||||||
});
|
});
|
||||||
//this._showSignCounters = new Dictionary();
|
|
||||||
//this.showNewQuestion(this._question, k.duration);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}, []);
|
}, [clearQuestion, question, questionClearTimeout, roomSession.userDataManager, userAnswers]);
|
||||||
|
|
||||||
const vote = useCallback((vote: string) =>
|
|
||||||
{
|
|
||||||
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.NEW_QUESTION, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.NEW_QUESTION, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
||||||
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.QUESTION_ANSWERED, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.QUESTION_ANSWERED, eventDispatcher, onRoomWidgetWordQuizUpdateEvent);
|
||||||
CreateEventDispatcherHook(RoomWidgetWordQuizUpdateEvent.QUESTION_FINISHED, 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 (
|
return (
|
||||||
<>
|
<>
|
||||||
{question && <QuestionView question={question.content} canVote={!answerSent} vote={vote}/>}
|
{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} />
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,8 @@
|
|||||||
export const VALUE_KEY_DISLIKE = '0';
|
export const VALUE_KEY_DISLIKE = '0';
|
||||||
export const VALUE_KEY_LIKE = '1';
|
export const VALUE_KEY_LIKE = '1';
|
||||||
|
|
||||||
|
export interface VoteValue
|
||||||
|
{
|
||||||
|
value: string;
|
||||||
|
secondsLeft: number;
|
||||||
|
}
|
||||||
|
@ -1,14 +1,24 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
|
import { VALUE_KEY_DISLIKE, VALUE_KEY_LIKE } from '../../common/VoteValue';
|
||||||
import { QuestionViewProps } from './QuestionView.types';
|
import { QuestionViewProps } from './QuestionView.types';
|
||||||
|
|
||||||
export const QuestionView:FC<QuestionViewProps> = props =>
|
export const QuestionView:FC<QuestionViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { question = null, canVote = null } = props;
|
const { question = null, canVote = null, vote = null, noVotes = null, yesVotes = null } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="word-quiz-question-container w-100 align-content-center d-flex">
|
<div className="wordquiz-question p-2 d-flex flex-column gap-2">
|
||||||
<div className="wordquiz-question p-3 d-flex mx-auto">{question}</div>
|
<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>
|
</div>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,6 @@ export interface QuestionViewProps
|
|||||||
question: string;
|
question: string;
|
||||||
canVote: boolean;
|
canVote: boolean;
|
||||||
vote(value: string): void;
|
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