Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 13 additions & 30 deletions packages/feeds-client/src/common/Poll.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { StateStore } from '@stream-io/state-store';
import type { FeedsClient } from '../feeds-client';
import type {
PollVote,
PollVoteResponseData,
QueryPollVotesRequest,
PollUpdatedFeedEvent,
WSEvent,
Expand All @@ -10,7 +10,6 @@ import type {
PollVoteChangedFeedEvent,
PollVoteRemovedFeedEvent,
PollResponseData,
Poll as PollType,
} from '../gen/models';

const isPollUpdatedEvent = (
Expand All @@ -34,7 +33,8 @@ const isPollVoteRemovedEvent = (
): e is { type: 'feeds.poll.vote_removed' } & PollVoteRemovedFeedEvent =>
e.type === 'feeds.poll.vote_removed';

export const isVoteAnswer = (vote: PollVote) => !!vote?.answer_text;
export const isVoteAnswer = (vote: PollVoteResponseData) =>
!!vote?.answer_text;

export type PollAnswersQueryParams = QueryPollVotesRequest & {
poll_id: string;
Expand All @@ -43,16 +43,16 @@ export type PollAnswersQueryParams = QueryPollVotesRequest & {

type OptionId = string;

export type PollState = Omit<PollType, 'own_votes' | 'id'> & {
export type PollState = Omit<PollResponseData, 'own_votes' | 'id'> & {
last_activity_at: Date;
max_voted_option_ids: OptionId[];
own_votes_by_option_id: Record<OptionId, PollVote>;
own_answer?: PollVote; // each user can have only one answer
own_votes_by_option_id: Record<OptionId, PollVoteResponseData>;
own_answer?: PollVoteResponseData; // each user can have only one answer
};

type PollInitOptions = {
client: FeedsClient;
poll: PollType;
poll: PollResponseData;
};

export class StreamPoll {
Expand All @@ -74,8 +74,8 @@ export class StreamPoll {
) => {
const { own_votes, id, ...pollResponseForState } = poll;
const { ownAnswer, ownVotes } = own_votes?.reduce<{
ownVotes: PollVote[];
ownAnswer?: PollVote;
ownVotes: PollVoteResponseData[];
ownAnswer?: PollVoteResponseData;
}>(
(acc, voteOrAnswer) => {
if (isVoteAnswer(voteOrAnswer)) {
Expand Down Expand Up @@ -111,7 +111,6 @@ export class StreamPoll {
if (event.poll?.id && event.poll.id !== this.id) return;
if (!isPollUpdatedEvent(event as WSEvent)) return;
const { id, ...pollData } = event.poll;
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
this.state.partialNext({
...pollData,
last_activity_at: new Date(event.created_at),
Expand Down Expand Up @@ -140,19 +139,14 @@ export class StreamPoll {
let maxVotedOptionIds = currentState.max_voted_option_ids;

if (isOwnVote) {
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
if (isVoteAnswer(event.poll_vote)) {
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
ownAnswer = event.poll_vote;
} else if (event.poll_vote.option_id) {
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote;
}
}

// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
if (isVoteAnswer(event.poll_vote)) {
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
latestAnswers = [event.poll_vote, ...latestAnswers];
} else {
maxVotedOptionIds = getMaxVotedOptionIds(
Expand All @@ -168,7 +162,6 @@ export class StreamPoll {
} = event.poll;
this.state.partialNext({
answers_count,
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
latest_votes_by_option,
vote_count,
vote_counts_by_option,
Expand All @@ -194,22 +187,18 @@ export class StreamPoll {
let maxVotedOptionIds = currentState.max_voted_option_ids;

if (isOwnVote) {
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
if (isVoteAnswer(event.poll_vote)) {
latestAnswers = [
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
event.poll_vote,
...latestAnswers.filter((answer) => answer.id !== event.poll_vote.id),
];
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
ownAnswer = event.poll_vote;
} else if (event.poll_vote.option_id) {
if (event.poll.enforce_unique_vote) {
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
ownVotesByOptionId = { [event.poll_vote.option_id]: event.poll_vote };
} else {
ownVotesByOptionId = Object.entries(ownVotesByOptionId).reduce<
Record<OptionId, PollVote>
Record<OptionId, PollVoteResponseData>
>((acc, [optionId, vote]) => {
if (
optionId !== event.poll_vote.option_id &&
Expand All @@ -220,7 +209,6 @@ export class StreamPoll {
acc[optionId] = vote;
return acc;
}, {});
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote;
}

Expand All @@ -231,9 +219,7 @@ export class StreamPoll {
event.poll.vote_counts_by_option,
);
}
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
} else if (isVoteAnswer(event.poll_vote)) {
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
latestAnswers = [event.poll_vote, ...latestAnswers];
} else {
maxVotedOptionIds = getMaxVotedOptionIds(
Expand All @@ -249,7 +235,6 @@ export class StreamPoll {
} = event.poll;
this.state.partialNext({
answers_count,
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
latest_votes_by_option,
vote_count,
vote_counts_by_option,
Expand All @@ -273,7 +258,6 @@ export class StreamPoll {
const ownVotesByOptionId = { ...currentState.own_votes_by_option_id };
let maxVotedOptionIds = currentState.max_voted_option_ids;

// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
if (isVoteAnswer(event.poll_vote)) {
latestAnswers = latestAnswers.filter(
(answer) => answer.id !== event.poll_vote.id,
Expand All @@ -298,7 +282,6 @@ export class StreamPoll {
} = event.poll;
this.state.partialNext({
answers_count,
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
latest_votes_by_option,
vote_count,
vote_counts_by_option,
Expand Down Expand Up @@ -327,10 +310,10 @@ function getMaxVotedOptionIds(
return winningOptions;
}

function getOwnVotesByOptionId(ownVotes: PollVote[]) {
function getOwnVotesByOptionId(ownVotes: PollVoteResponseData[]) {
return !ownVotes
? ({} satisfies Record<OptionId, PollVote>)
: ownVotes.reduce<Record<OptionId, PollVote>>((acc, vote) => {
? ({} satisfies Record<OptionId, PollVoteResponseData>)
: ownVotes.reduce<Record<OptionId, PollVoteResponseData>>((acc, vote) => {
if (isVoteAnswer(vote) || !vote.option_id) return acc;
acc[vote.option_id] = vote;
return acc;
Expand Down
2 changes: 0 additions & 2 deletions packages/feeds-client/src/feeds-client/feeds-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,9 @@ export class FeedsClient extends FeedsApi {
const pollResponse = activity.poll;
const pollFromCache = this.pollFromState(pollResponse.id);
if (!pollFromCache) {
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
const poll = new StreamPoll({ client: this, poll: pollResponse });
this.polls_by_id.set(poll.id, poll);
} else {
// @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
pollFromCache.reinitializeState(pollResponse);
}
}
Expand Down