fix(polls): Fix 'Skip' button functionality
This commit is contained in:
parent
09efaa0d0d
commit
70af0d6b78
|
@ -1,5 +1,16 @@
|
|||
// @flow
|
||||
|
||||
/**
|
||||
* The type of the action which signals that a Poll will be changed
|
||||
*
|
||||
* {
|
||||
* type: CHANGE_VOTE,
|
||||
* }
|
||||
*
|
||||
*/
|
||||
export const CHANGE_VOTE = 'CHANGE_VOTE';
|
||||
|
||||
|
||||
/**
|
||||
* The type of the action which signals that a new Poll was received.
|
||||
*
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import {
|
||||
CHANGE_VOTE,
|
||||
RESET_NB_UNREAD_POLLS,
|
||||
RECEIVE_ANSWER,
|
||||
RECEIVE_POLL,
|
||||
|
@ -9,6 +10,26 @@ import {
|
|||
} from './actionTypes';
|
||||
import type { Answer, Poll } from './types';
|
||||
|
||||
/**
|
||||
* Action to signal that a poll's vote will be changed.
|
||||
*
|
||||
* @param {string} pollId - The id of the incoming poll.
|
||||
* @param {boolean} value - The value of the 'changing' state.
|
||||
|
||||
* @returns {{
|
||||
* type: CHANGE_VOTE,
|
||||
* pollId: string,
|
||||
* value: boolean
|
||||
* }}
|
||||
*/
|
||||
export const setVoteChanging = (pollId: string, value: boolean) => {
|
||||
return {
|
||||
type: CHANGE_VOTE,
|
||||
pollId,
|
||||
value
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Action to signal that a new poll was received.
|
||||
*
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
|||
|
||||
import { sendAnalytics, createPollEvent } from '../../analytics';
|
||||
import { getLocalParticipant, getParticipantById } from '../../base/participants';
|
||||
import { registerVote } from '../actions';
|
||||
import { registerVote, setVoteChanging } from '../actions';
|
||||
import { COMMAND_ANSWER_POLL } from '../constants';
|
||||
import type { Poll } from '../types';
|
||||
|
||||
|
@ -27,6 +27,7 @@ export type AbstractProps = {
|
|||
poll: Poll,
|
||||
setCheckbox: Function,
|
||||
skipAnswer: Function,
|
||||
skipChangeVote: Function,
|
||||
submitAnswer: Function,
|
||||
t: Function,
|
||||
};
|
||||
|
@ -90,6 +91,10 @@ const AbstractPollAnswer = (Component: AbstractComponent<AbstractProps>) => (pro
|
|||
|
||||
}, [ pollId ]);
|
||||
|
||||
const skipChangeVote = useCallback(() => {
|
||||
dispatch(setVoteChanging(pollId, false));
|
||||
}, [ dispatch, pollId ]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (<Component
|
||||
|
@ -97,6 +102,7 @@ const AbstractPollAnswer = (Component: AbstractComponent<AbstractProps>) => (pro
|
|||
poll = { poll }
|
||||
setCheckbox = { setCheckbox }
|
||||
skipAnswer = { skipAnswer }
|
||||
skipChangeVote = { skipChangeVote }
|
||||
submitAnswer = { submitAnswer }
|
||||
t = { t } />);
|
||||
|
||||
|
|
|
@ -6,9 +6,8 @@ import { useTranslation } from 'react-i18next';
|
|||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { sendAnalytics, createPollEvent } from '../../analytics';
|
||||
import { getLocalParticipant, getParticipantById } from '../../base/participants/functions';
|
||||
import { retractVote } from '../actions';
|
||||
import { COMMAND_ANSWER_POLL } from '../constants';
|
||||
import { setVoteChanging } from '../actions';
|
||||
import { getPoll } from '../functions';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of inheriting component.
|
||||
|
@ -51,7 +50,7 @@ export type AbstractProps = {
|
|||
const AbstractPollResults = (Component: AbstractComponent<AbstractProps>) => (props: InputProps) => {
|
||||
const { pollId } = props;
|
||||
|
||||
const pollDetails = useSelector(state => state['features/polls'].polls[pollId]);
|
||||
const pollDetails = useSelector(getPoll(pollId));
|
||||
|
||||
const [ showDetails, setShowDetails ] = useState(false);
|
||||
const toggleIsDetailed = useCallback(() => {
|
||||
|
@ -95,33 +94,23 @@ const AbstractPollResults = (Component: AbstractComponent<AbstractProps>) => (pr
|
|||
}, [ pollDetails.answers, showDetails ]);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const conference: Object = useSelector(state => state['features/base/conference'].conference);
|
||||
const localId = useSelector(state => getLocalParticipant(state).id);
|
||||
const localParticipant = useSelector(state => getParticipantById(state, localId));
|
||||
const localName: string = localParticipant ? localParticipant.name : 'Fellow Jitster';
|
||||
const changeVote = useCallback(() => {
|
||||
conference.sendMessage({
|
||||
type: COMMAND_ANSWER_POLL,
|
||||
pollId,
|
||||
voterId: localId,
|
||||
voterName: localName,
|
||||
answers: new Array(pollDetails.answers.length).fill(false)
|
||||
});
|
||||
dispatch(retractVote(pollId));
|
||||
dispatch(setVoteChanging(pollId, true));
|
||||
sendAnalytics(createPollEvent('vote.changed'));
|
||||
}, [ pollId, localId, localName, pollDetails ]);
|
||||
}, [ dispatch, pollId ]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (<Component
|
||||
answers = { answers }
|
||||
changeVote = { changeVote }
|
||||
haveVoted = { pollDetails.lastVote !== null }
|
||||
question = { pollDetails.question }
|
||||
showDetails = { showDetails }
|
||||
t = { t }
|
||||
toggleIsDetailed = { toggleIsDetailed } />);
|
||||
return (
|
||||
<Component
|
||||
answers = { answers }
|
||||
changeVote = { changeVote }
|
||||
haveVoted = { pollDetails.lastVote !== null }
|
||||
question = { pollDetails.question }
|
||||
showDetails = { showDetails }
|
||||
t = { t }
|
||||
toggleIsDetailed = { toggleIsDetailed } />
|
||||
);
|
||||
};
|
||||
|
||||
export default AbstractPollResults;
|
||||
|
|
|
@ -18,9 +18,11 @@ const PollAnswer = (props: AbstractProps) => {
|
|||
poll,
|
||||
setCheckbox,
|
||||
skipAnswer,
|
||||
skipChangeVote,
|
||||
submitAnswer,
|
||||
t
|
||||
} = props;
|
||||
const { changingVote } = poll;
|
||||
|
||||
return (
|
||||
<View>
|
||||
|
@ -44,7 +46,7 @@ const PollAnswer = (props: AbstractProps) => {
|
|||
<Button
|
||||
color = '#3D3D3D'
|
||||
mode = { BUTTON_MODES.CONTAINED }
|
||||
onPress = { skipAnswer }
|
||||
onPress = { changingVote ? skipChangeVote : skipAnswer }
|
||||
style = { chatStyles.pollCreateButton } >
|
||||
{t('polls.answer.skip')}
|
||||
</Button>
|
||||
|
|
|
@ -20,7 +20,7 @@ type Props = {
|
|||
}
|
||||
|
||||
const PollItem = ({ pollId }: Props) => {
|
||||
const showResults = useSelector(state => shouldShowResults(state, pollId));
|
||||
const showResults = useSelector(shouldShowResults(pollId));
|
||||
|
||||
return (
|
||||
<View
|
||||
|
|
|
@ -13,9 +13,11 @@ const PollAnswer = (props: AbstractProps) => {
|
|||
poll,
|
||||
setCheckbox,
|
||||
skipAnswer,
|
||||
skipChangeVote,
|
||||
submitAnswer,
|
||||
t
|
||||
} = props;
|
||||
const { changingVote } = poll;
|
||||
|
||||
return (
|
||||
<div className = 'poll-answer'>
|
||||
|
@ -45,7 +47,7 @@ const PollAnswer = (props: AbstractProps) => {
|
|||
<button
|
||||
aria-label = { t('polls.answer.skip') }
|
||||
className = 'poll-button poll-button-secondary poll-button-shortest'
|
||||
onClick = { skipAnswer } >
|
||||
onClick = { changingVote ? skipChangeVote : skipAnswer } >
|
||||
<span>{t('polls.answer.skip')}</span>
|
||||
</button>
|
||||
<button
|
||||
|
|
|
@ -17,7 +17,7 @@ type Props = {
|
|||
}
|
||||
|
||||
const PollItem = React.forwardRef<Props, HTMLElement>(({ pollId }, ref) => {
|
||||
const showResults = useSelector(state => shouldShowResults(state, pollId));
|
||||
const showResults = useSelector(shouldShowResults(pollId));
|
||||
|
||||
return (
|
||||
<div ref = { ref }>
|
||||
|
|
|
@ -1,14 +1,28 @@
|
|||
// @flow
|
||||
|
||||
/**
|
||||
* Should poll results be shown.
|
||||
* Selector creator for determining if poll results should be displayed or not.
|
||||
*
|
||||
* @param {Object} state - Global state.
|
||||
* @param {string} id - Id of the poll.
|
||||
* @returns {boolean} Should poll results be shown.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export const shouldShowResults = (state: Object, id: string) => Boolean(state['features/polls']?.polls[id].showResults);
|
||||
export function shouldShowResults(id: string) {
|
||||
return function(state: Object) {
|
||||
return Boolean(state['features/polls']?.polls[id].showResults);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector creator for polls.
|
||||
*
|
||||
* @param {string} pollId - Id of the poll to get.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function getPoll(pollId: string) {
|
||||
return function(state: Object) {
|
||||
return state['features/polls'].polls[pollId];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Selector for calculating the number of unread poll messages.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import {
|
||||
CHANGE_VOTE,
|
||||
RECEIVE_POLL,
|
||||
RECEIVE_ANSWER,
|
||||
REGISTER_VOTE,
|
||||
|
@ -21,6 +22,22 @@ const INITIAL_STATE = {
|
|||
ReducerRegistry.register('features/polls', (state = INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
|
||||
case CHANGE_VOTE: {
|
||||
const { pollId, value } = action;
|
||||
|
||||
return {
|
||||
...state,
|
||||
polls: {
|
||||
...state.polls,
|
||||
[pollId]: {
|
||||
...state.polls[pollId],
|
||||
changingVote: value,
|
||||
showResults: !value
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Reducer triggered when a poll is received
|
||||
case RECEIVE_POLL: {
|
||||
const newState = {
|
||||
|
@ -93,6 +110,7 @@ ReducerRegistry.register('features/polls', (state = INITIAL_STATE, action) => {
|
|||
...state.polls,
|
||||
[pollId]: {
|
||||
...state.polls[pollId],
|
||||
changingVote: false,
|
||||
lastVote: answers,
|
||||
showResults: true
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ const parsePollData = (pollData): Poll | null => {
|
|||
}
|
||||
|
||||
return {
|
||||
changingVote: false,
|
||||
senderId,
|
||||
senderName,
|
||||
question,
|
||||
|
@ -63,6 +64,7 @@ StateListenerRegistry.register(
|
|||
const { question, answers, pollId, senderId, senderName } = data;
|
||||
|
||||
const poll = {
|
||||
changingVote: false,
|
||||
senderId,
|
||||
senderName,
|
||||
showResults: false,
|
||||
|
|
|
@ -25,6 +25,11 @@ export type Answer = {
|
|||
|
||||
export type Poll = {
|
||||
|
||||
/**
|
||||
* Whether the poll vote is being edited/changed.
|
||||
*/
|
||||
changingVote: boolean,
|
||||
|
||||
/**
|
||||
* ID of the sender of this poll
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue