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
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { generateChoiceItemsFromMultipleChoiceForecast } from "@/utils/charts";
import { getForecastPctDisplayValue } from "@/utils/forecasts";

import ChoicesTooltip from "../choices_tooltip";
import { generateUserForecastsForMultipleQuestion } from "@/utils/questions";

const MAX_VISIBLE_CHECKBOXES = 6;

Expand Down Expand Up @@ -47,7 +48,7 @@ const MultipleChoiceChartCard: FC<Props> = ({
const [choiceItems, setChoiceItems] = useState<ChoiceItem[]>(
generateList(question)
);

const userForecasts = generateUserForecastsForMultipleQuestion(question);
const timestampsCount = timestamps.length;
const prevTimestampsCount = usePrevious(timestampsCount);
// sync BE driven data with local state
Expand Down Expand Up @@ -77,6 +78,30 @@ const MultipleChoiceChartCard: FC<Props> = ({
[choiceItems, cursorIndex]
);

const tooltipUserChoices = useMemo<ChoiceTooltipItem[]>(() => {
if (!userForecasts) {
return [];
}

return userForecasts.map(
({ choice, values, color, timestamps: optionTimestamps }) => {
const timestampIndex = optionTimestamps?.findLastIndex(
(timestamp) => timestamp <= cursorTimestamp
);

return {
choiceLabel: choice,
color,
valueLabel: getForecastPctDisplayValue(
timestampIndex === -1 || timestampIndex === undefined
? null
: values?.[timestampIndex]
),
};
}
);
}, [userForecasts, cursorTimestamp]);

const {
isActive: isTooltipActive,
getReferenceProps,
Expand Down Expand Up @@ -150,6 +175,7 @@ const MultipleChoiceChartCard: FC<Props> = ({
? new Date(question.actual_close_time).getTime() < Date.now()
: false
}
userForecasts={userForecasts}
/>
</div>

Expand All @@ -170,7 +196,11 @@ const MultipleChoiceChartCard: FC<Props> = ({
style={floatingStyles}
{...getFloatingProps()}
>
<ChoicesTooltip date={tooltipDate} choices={tooltipChoices} />
<ChoicesTooltip
date={tooltipDate}
choices={tooltipChoices}
userChoices={tooltipUserChoices}
/>
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const GroupOfQuestionsTile: FC<Props> = ({ questions, curationStatus }) => {
userForecasts={
user
? generateUserForecasts(
questions as QuestionWithNumericForecasts[]
sortedQuestions as QuestionWithNumericForecasts[]
)
: undefined
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { generateChoiceItemsFromMultipleChoiceForecast } from "@/utils/charts";

import QuestionNumericTile from "./question_numeric_tile";
import { useTranslations } from "next-intl";
import { generateUserForecastsForMultipleQuestion } from "@/utils/questions";

type Props = {
question: QuestionWithForecasts;
Expand Down Expand Up @@ -62,6 +63,8 @@ const QuestionChartTile: FC<Props> = ({
const choices = generateChoiceItemsFromMultipleChoiceForecast(question, {
activeCount: visibleChoicesCount,
});
const userForecasts = generateUserForecastsForMultipleQuestion(question);

return (
<MultipleChoiceTile
timestamps={question.aggregations.recency_weighted.history.map(
Expand All @@ -71,6 +74,7 @@ const QuestionChartTile: FC<Props> = ({
visibleChoicesCount={visibleChoicesCount}
defaultChartZoom={defaultChartZoom}
question={question}
userForecasts={userForecasts}
/>
);
}
Expand Down
28 changes: 28 additions & 0 deletions front_end/src/utils/questions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
MultipleChoiceForecast,
Question,
QuestionType,
QuestionWithMultipleChoiceForecasts,
QuestionWithNumericForecasts,
} from "@/types/question";
import { abbreviatedNumber } from "@/utils/number_formatters";
Expand Down Expand Up @@ -209,6 +210,33 @@ export function getPredictionQuestion(
);
}

export const generateUserForecastsForMultipleQuestion = (
question: QuestionWithMultipleChoiceForecasts
): UserChoiceItem[] | undefined => {
const latest = question.aggregations.recency_weighted.latest;
const options = question.options!;

const choiceOrdering: number[] = options.map((_, i) => i);
choiceOrdering.sort((a, b) => {
const aCenter = latest?.forecast_values[a] ?? 0;
const bCenter = latest?.forecast_values[b] ?? 0;
return bCenter - aCenter;
});

return options.map((choice, index) => {
const userForecasts = question.my_forecasts?.history;
return {
choice,
values:
userForecasts?.map((forecast) => forecast.forecast_values[index]) ?? [],
timestamps: userForecasts?.map((forecast) => forecast.start_time) ?? [],
color:
MULTIPLE_CHOICE_COLOR_SCALE[choiceOrdering[index]] ??
METAC_COLORS.gray["400"],
};
});
};

export const generateUserForecasts = (
questions: QuestionWithNumericForecasts[]
): UserChoiceItem[] => {
Expand Down