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
6 changes: 5 additions & 1 deletion front_end/messages/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -718,5 +718,9 @@
"xTwitter": "X / Twitter",
"copyFromBranch": "kopie z {branch}",
"parentResolvesAsYes": "Rodič vyřeší jako Ano",
"parentResolvesAsNo": "Rodič se rozhodne jako Ne"
"parentResolvesAsNo": "Rodič se rozhodne jako Ne",
"othersCount": "{count} ostatní",
"selectAll": "vybrat vše",
"deselectAll": "zrušit výběr všech",
"forecastDataIsEmpty": "Údaje o prognóze jsou prázdné"
}
7 changes: 6 additions & 1 deletion front_end/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -729,5 +729,10 @@
"xTwitter": "X / Twitter",
"copyFromBranch": "copy from {branch}",
"parentResolvesAsYes": "Parent Resolves as Yes",
"parentResolvesAsNo": "Parent Resolves as No"
"parentResolvesAsNo": "Parent Resolves as No",
"othersCount": "{count} others",
"selectAll": "select all",
"deselectAll": "deselect all",
"forecastDataIsEmpty": "Forecast data is empty",
"createdByUserOnDate": "Created by {user} on {date}"
}
8 changes: 5 additions & 3 deletions front_end/messages/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@
"resolutionAnnulled": "已廢止",
"resolutionPending": "待解決",
"resolution": "解決",
"Yes": "如果是",
"No": "如果沒有",
"pendingResolution": "待解決",
"forecastTimelineHeading": "預測時間線",
"totalPredictionsLabel": "總預測",
Expand Down Expand Up @@ -711,5 +709,9 @@
"xTwitter": "X / Twitter",
"copyFromBranch": "從{branch}複製",
"parentResolvesAsYes": "家長決定是",
"parentResolvesAsNo": "家長決定不"
"parentResolvesAsNo": "家長決定不",
"othersCount": "{count}其他",
"selectAll": "選擇全部",
"deselectAll": "取消全選",
"forecastDataIsEmpty": "預測資料為空"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { faChevronDown } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
import classNames from "classnames";
import { useTranslations } from "next-intl";
import React, { FC, useMemo } from "react";

import Button from "@/components/ui/button";
Expand All @@ -25,6 +26,7 @@ const ChoicesLegend: FC<Props> = ({
onToggleAll,
maxLegendChoices,
}) => {
const t = useTranslations()
const { legendChoices, dropdownChoices } = useMemo(
() => ({
legendChoices: choices.slice(0, maxLegendChoices),
Expand Down Expand Up @@ -66,7 +68,7 @@ const ChoicesLegend: FC<Props> = ({
"bg-gray-300 dark:bg-gray-300-dark": open,
})}
>
Others ({dropdownChoices.length})
{t("othersCount", {count: dropdownChoices.length})}
<FontAwesomeIcon icon={faChevronDown} className="ml-1" />
</PopoverButton>
<PopoverPanel
Expand All @@ -76,8 +78,8 @@ const ChoicesLegend: FC<Props> = ({
<Checkbox
checked={areAllSelected}
onChange={() => onToggleAll(areAllSelected)}
label={areAllSelected ? "Deselect All" : "Select All"}
className="p-1.5"
label={areAllSelected ? t("deselectAll") : t("selectAll")}
className="p-1.5 capitalize"
/>
{dropdownChoices.map(({ choice, color, active }, idx) => (
<ChoiceCheckbox
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use client";

import classNames from "classnames";
import { useTranslations } from "next-intl";
import React, { FC, useCallback, useEffect, useMemo, useState } from "react";
Expand All @@ -23,21 +24,52 @@ import ChoicesTooltip from "../choices_tooltip";

const MAX_VISIBLE_CHECKBOXES = 6;

type Props = {
questions: QuestionWithNumericForecasts[];
timestamps: number[];
preselectedQuestionId?: number;
};
function getQuestionTooltipLabel(
timestamps: number[],
values: number[],
cursorTimestamp: number,
isUserPrediction: boolean = false
) {
const hasValue = isUserPrediction
? cursorTimestamp >= Math.min(...timestamps)
: cursorTimestamp >= Math.min(...timestamps) &&
cursorTimestamp <= Math.max(...timestamps);
if (!hasValue) {
return getForecastPctDisplayValue(null);
}
if (isUserPrediction) {
let closestTimestampIndex = 0;
timestamps.forEach((timestamp, index) => {
if (cursorTimestamp >= timestamp) {
closestTimestampIndex = index;
}
});
return getForecastPctDisplayValue(values[closestTimestampIndex]);
}
const closestTimestamp = findPreviousTimestamp(timestamps, cursorTimestamp);
const cursorIndex = timestamps.findIndex(
(timestamp) => timestamp === closestTimestamp
);

const generateList = (
return getForecastPctDisplayValue(values[cursorIndex]);
}

function generateList(
questions: QuestionWithNumericForecasts[],
preselectedQuestionId?: number
) =>
generateChoiceItemsFromBinaryGroup(questions, {
) {
return generateChoiceItemsFromBinaryGroup(questions, {
withMinMax: true,
activeCount: MAX_VISIBLE_CHECKBOXES,
preselectedQuestionId,
});
}

type Props = {
questions: QuestionWithNumericForecasts[];
timestamps: number[];
preselectedQuestionId?: number;
};

const BinaryGroupChart: FC<Props> = ({
questions,
Expand Down Expand Up @@ -200,34 +232,4 @@ const BinaryGroupChart: FC<Props> = ({
);
};

function getQuestionTooltipLabel(
timestamps: number[],
values: number[],
cursorTimestamp: number,
isUserPrediction: boolean = false
) {
const hasValue = isUserPrediction
? cursorTimestamp >= Math.min(...timestamps)
: cursorTimestamp >= Math.min(...timestamps) &&
cursorTimestamp <= Math.max(...timestamps);
if (!hasValue) {
return getForecastPctDisplayValue(null);
}
if (isUserPrediction) {
let closestTimestampIndex = 0;
timestamps.forEach((timestamp, index) => {
if (cursorTimestamp >= timestamp) {
closestTimestampIndex = index;
}
});
return getForecastPctDisplayValue(values[closestTimestampIndex]);
}
const closestTimestamp = findPreviousTimestamp(timestamps, cursorTimestamp);
const cursorIndex = timestamps.findIndex(
(timestamp) => timestamp === closestTimestamp
);

return getForecastPctDisplayValue(values[cursorIndex]);
}

export default BinaryGroupChart;
2 changes: 1 addition & 1 deletion front_end/src/components/comment_feed/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ const CommentFeed: FC<Props> = ({ postData, postPermissions, profileId }) => {
<FontAwesomeIcon icon={faChevronDown} />
</Button>
</DropdownMenu>
<span>{totalCount} comments</span>
<span>{totalCount ? `${totalCount} ` : ""}{t("commentsWithCount", { count: totalCount })}</span>
</div>
{postId && (
<CommentEditor
Expand Down
17 changes: 11 additions & 6 deletions front_end/src/components/post_card/question_chart_tile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use client";

import { FC } from "react";

import MultipleChoiceTile from "@/components/multiple_choice_tile";
Expand All @@ -7,9 +8,9 @@ import { TimelineChartZoomOption } from "@/types/charts";
import { PostStatus } from "@/types/post";
import { QuestionType, QuestionWithForecasts } from "@/types/question";
import { generateChoiceItemsFromMultipleChoiceForecast } from "@/utils/charts";
import { getIsForecastEmpty } from "@/utils/forecasts";

import QuestionNumericTile from "./question_numeric_tile";
import { useTranslations } from "next-intl";

type Props = {
question: QuestionWithForecasts;
Expand All @@ -22,18 +23,22 @@ const QuestionChartTile: FC<Props> = ({
authorUsername,
curationStatus,
}) => {
const t = useTranslations();
const { user } = useAuth();

if (curationStatus === PostStatus.PENDING) {
return (
<div>{`Created by ${authorUsername} on ${question.created_at.slice(0, 7)}`}</div>
<div>
{t("createdByUserOnDate", {
user: authorUsername,
date: question.created_at.slice(0, 7),
})}
</div>
);
}
const isForecastEmpty =
question.aggregations.recency_weighted.history.length === 0;

if (isForecastEmpty) {
return <div>Forecasts data is empty</div>;
if (question.aggregations.recency_weighted.history.length === 0) {
return <div>{t("forecastDataIsEmpty")}</div>;
}

const defaultChartZoom: TimelineChartZoomOption = user
Expand Down