Skip to content

Commit

Permalink
feat: polls feature endpoints (#1269)
Browse files Browse the repository at this point in the history
Co-authored-by: Lennart Kuijs <[email protected]>
Co-authored-by: kanat <[email protected]>
  • Loading branch information
3 people authored Apr 12, 2024
1 parent deb5043 commit 1d81480
Show file tree
Hide file tree
Showing 6 changed files with 657 additions and 11 deletions.
40 changes: 40 additions & 0 deletions src/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
UserFilters,
UserResponse,
QueryChannelAPIResponse,
PollVoteData,
SendMessageOptions,
} from './types';
import { Role } from './permissions';
Expand Down Expand Up @@ -1158,6 +1159,20 @@ export class Channel<StreamChatGenerics extends ExtendableGenerics = DefaultGene
return await this.getClient().post<CreateCallResponse>(this._channelURL() + '/call', options);
}

/**
* Cast or cancel one or more votes on a poll
* @param pollId string The poll id
* @param votes PollVoteData[] The votes that will be casted (or canceled in case of an empty array)
* @returns {APIResponse & PollVoteResponse} The poll votes
*/
async vote(messageId: string, pollId: string, vote: PollVoteData) {
return await this.getClient().castPollVote(messageId, pollId, vote);
}

async removeVote(messageId: string, pollId: string, voteId: string) {
return await this.getClient().removePollVote(messageId, pollId, voteId);
}

/**
* on - Listen to events on this channel.
*
Expand Down Expand Up @@ -1401,6 +1416,31 @@ export class Channel<StreamChatGenerics extends ExtendableGenerics = DefaultGene
};
}
break;
case 'poll.updated':
if (event.poll) {
channelState.updatePoll(event.poll, event.message?.id || '');
}
break;
case 'poll.vote_casted':
if (event.poll_vote && event.poll) {
channelState.addPollVote(event.poll_vote, event.poll, event.message?.id || '');
}
break;
case 'poll.vote_changed':
if (event.poll_vote && event.poll) {
channelState.updatePollVote(event.poll_vote, event.poll, event.message?.id || '');
}
break;
case 'poll.vote_removed':
if (event.poll_vote && event.poll) {
channelState.removePollVote(event.poll_vote, event.poll, event.message?.id || '');
}
break;
case 'poll.closed':
if (event.message) {
channelState.addMessageSorted(event.message, false, false);
}
break;
case 'reaction.new':
if (event.message && event.reaction) {
event.message = channelState.addReaction(event.reaction, event.message);
Expand Down
92 changes: 92 additions & 0 deletions src/channel_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
ReactionResponse,
UserResponse,
PendingMessageResponse,
PollVote,
PollResponse,
} from './types';
import { addToMessageList } from './utils';

Expand Down Expand Up @@ -486,6 +488,96 @@ export class ChannelState<StreamChatGenerics extends ExtendableGenerics = Defaul
return { removed: result.length < msgArray.length, result };
};

// this handles the case when vote on poll is changed
updatePollVote = (
pollVote: PollVote<StreamChatGenerics>,
poll: PollResponse<StreamChatGenerics>,
messageId: string,
) => {
const message = this.findMessage(messageId);
if (!message) return;

if (message.poll_id !== pollVote.poll_id) return;

const updatedPoll = { ...poll };
let ownVotes = [...(message.poll.own_votes || [])];

if (pollVote.user_id === this._channel.getClient().userID) {
if (pollVote.option_id && poll.enforce_unique_vote) {
// remove all previous votes where option_id is not empty
ownVotes = ownVotes.filter((vote) => !vote.option_id);
} else if (pollVote.answer_text) {
// remove all previous votes where option_id is empty
ownVotes = ownVotes.filter((vote) => vote.answer_text);
}

ownVotes.push(pollVote);
}

updatedPoll.own_votes = ownVotes as PollVote<StreamChatGenerics>[];
const newMessage = { ...message, poll: updatedPoll };

this.addMessageSorted((newMessage as unknown) as MessageResponse<StreamChatGenerics>, false, false);
};

addPollVote = (pollVote: PollVote<StreamChatGenerics>, poll: PollResponse<StreamChatGenerics>, messageId: string) => {
const message = this.findMessage(messageId);
if (!message) return;

if (message.poll_id !== pollVote.poll_id) return;

const updatedPoll = { ...poll };
const ownVotes = [...(message.poll.own_votes || [])];

if (pollVote.user_id === this._channel.getClient().userID) {
ownVotes.push(pollVote);
}

updatedPoll.own_votes = ownVotes as PollVote<StreamChatGenerics>[];
const newMessage = { ...message, poll: updatedPoll };

this.addMessageSorted((newMessage as unknown) as MessageResponse<StreamChatGenerics>, false, false);
};

removePollVote = (
pollVote: PollVote<StreamChatGenerics>,
poll: PollResponse<StreamChatGenerics>,
messageId: string,
) => {
const message = this.findMessage(messageId);
if (!message) return;

if (message.poll_id !== pollVote.poll_id) return;

const updatedPoll = { ...poll };
const ownVotes = [...(message.poll.own_votes || [])];
if (pollVote.user_id === this._channel.getClient().userID) {
const index = ownVotes.findIndex((vote) => vote.option_id === pollVote.option_id);
if (index > -1) {
ownVotes.splice(index, 1);
}
}

updatedPoll.own_votes = ownVotes as PollVote<StreamChatGenerics>[];

const newMessage = { ...message, poll: updatedPoll };
this.addMessageSorted((newMessage as unknown) as MessageResponse<StreamChatGenerics>, false, false);
};

updatePoll = (poll: PollResponse<StreamChatGenerics>, messageId: string) => {
const message = this.findMessage(messageId);
if (!message) return;

const updatedPoll = {
...poll,
own_votes: [...(message.poll?.own_votes || [])],
};

const newMessage = { ...message, poll: updatedPoll };

this.addMessageSorted((newMessage as unknown) as MessageResponse<StreamChatGenerics>, false, false);
};

/**
* Updates the message.user property with updated user object, for messages.
*
Expand Down
Loading

0 comments on commit 1d81480

Please sign in to comment.