Skip to content
Draft
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
1 change: 1 addition & 0 deletions front_end/messages/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -2169,5 +2169,6 @@
"whyTrustMetaculusLessNoise": "Předpovědi Metaculus, poháněné davem, prořezávají šum tím, že zakládají každou předpověď na transparentních důkazech, odpovědném skóre a desetiletí doložené přesnosti. Metaculus vybavuje politiky, výzkumníky, novináře a korporátní organizace předpověďmi založenými na důkazech, které poskytují jasný, kvantifikovatelný vhled do nejkritičtějších nejistot světa. Prozkoumejte naši nabídku <servicesLink>Business řešení</servicesLink> a zjistěte, jak může Metaculus zlepšit rozhodování vaší organizace.",
"publishTimeLockedDescription": "Čas publikace nelze po vytvoření změnit.",
"nMore": "{count} více...",
"noHistogramData": "Žádná data histogramu nejsou k dispozici",
"thousandsOfOpenQuestions": "20 000+ otevřených otázek"
}
1 change: 1 addition & 0 deletions front_end/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,7 @@
"deselectAll": "deselect all",
"forecastDataIsEmpty": "Forecast data is empty",
"noForecastsYet": "No forecasts yet",
"noHistogramData": "No histogram data available",
"RevealTemporarily": "Reveal Temporarily",
"CPIsHidden": "Community Prediction is hidden",
"createdByUserOnDate": "Created by {user} on {date}",
Expand Down
1 change: 1 addition & 0 deletions front_end/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -2169,5 +2169,6 @@
"whyTrustMetaculusLessNoise": "Los pronósticos impulsados por la multitud de Metaculus cortan el ruido al basar cada predicción en evidencia transparente, puntuaciones responsables y una década de precisión demostrada. Metaculus equipa a los responsables de políticas, investigadores, periodistas y organizaciones corporativas con pronósticos basados en evidencia que ofrecen una visión clara y cuantificable de las incertidumbres más críticas del mundo. Explora nuestra suite de <servicesLink>Soluciones Empresariales</servicesLink> para aprender cómo Metaculus puede mejorar la toma de decisiones de tu organización.",
"publishTimeLockedDescription": "La hora de publicación no puede cambiarse después de la creación.",
"nMore": "{count} más...",
"noHistogramData": "No hay datos de histograma disponibles",
"thousandsOfOpenQuestions": "20,000+ preguntas abiertas"
}
1 change: 1 addition & 0 deletions front_end/messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -2167,5 +2167,6 @@
"whyTrustMetaculusLessNoise": "As previsões baseadas na multidão do Metaculus cortam o ruído ao basear cada previsão em evidências transparentes, pontuações responsáveis e uma década de precisão demonstrada. O Metaculus equipa formuladores de políticas, pesquisadores, jornalistas e organizações corporativas com previsões baseadas em evidências que oferecem insights claros e quantificáveis sobre as incertezas mais críticas do mundo. Explore nosso conjunto de <servicesLink>Soluções Empresariais</servicesLink> para saber mais sobre como o Metaculus pode melhorar a tomada de decisões da sua organização.",
"publishTimeLockedDescription": "O horário de publicação não pode ser alterado após a criação.",
"nMore": "{count} a mais...",
"noHistogramData": "Não há dados de histograma disponíveis",
"thousandsOfOpenQuestions": "20.000+ perguntas abertas"
}
1 change: 1 addition & 0 deletions front_end/messages/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -2166,5 +2166,6 @@
"whyTrustMetaculusLessNoise": "Metaculus 的群眾驅動預測通過將每一個預測植根於透明的證據、負責的計分和十年的已證準確性,抑制了噪音。Metaculus 為政策制定者、研究人員、記者和企業組織提供基於證據的預測,為全球最重要的不確定性提供清晰、可量化的洞察。探索我們的 <servicesLink>企業解決方案</servicesLink>,了解 Metaculus 如何改善貴組織的決策。",
"publishTimeLockedDescription": "建立後將無法更改發佈時間。",
"nMore": "還有 {count} 個...",
"noHistogramData": "沒有可用的直方圖數據",
"thousandsOfOpenQuestions": "20,000+ 開放問題"
}
1 change: 1 addition & 0 deletions front_end/messages/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -2171,5 +2171,6 @@
"whyTrustMetaculusLessNoise": "Metaculus 的众包预测通过以透明证据、可追溯的评分以及十年证明的准确性为基础来削减预测中的噪音。Metaculus 为政策制定者、研究人员、记者和企业组织提供基于证据的预测,为世界上最重要的不确定性提供清晰、可量化的洞察。了解我们的<servicesLink>企业解决方案</servicesLink>,了解 Metaculus 如何改善贵组织的决策。",
"publishTimeLockedDescription": "创建后将无法更改发布时间。",
"nMore": "{count} 更多...",
"noHistogramData": "没有可用的直方图数据",
"thousandsOfOpenQuestions": "20,000+ 开放问题"
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import { useCommentsFeed } from "@/app/(main)/components/comments_feed_provider"
import { openKeyFactorsSectionAndScrollTo } from "@/app/(main)/questions/[id]/components/key_factors/utils";
import { PostStatus, PostWithForecasts } from "@/types/post";
import { sendAnalyticsEvent } from "@/utils/analytics";
import { getQuestionForecastAvailability } from "@/utils/questions/forecastAvailability";
import { isQuestionPost } from "@/utils/questions/helpers";

import {
MAX_TOP_KEY_FACTORS,
useTopKeyFactorsCarouselItems,
} from "./hooks/use_top_key_factors_carousel_items";
import KeyFactorDetailOverlay from "./key_factor_detail_overlay";
import KeyFactorsCarousel from "./key_factors_carousel";
import KeyFactorsConsumerCarousel from "./key_factors_consumer_carousel";
import { useShouldHideKeyFactors } from "./use_should_hide_key_factors";
import { useQuestionLayout } from "../question_layout/question_layout_context";
Expand Down Expand Up @@ -41,14 +44,21 @@ const KeyFactorsQuestionConsumerSection: FC<Props> = ({ post }) => {

if (post.status === PostStatus.RESOLVED) return null;

const postForecastAvailability = isQuestionPost(post)
? getQuestionForecastAvailability(post.question)
: null;
const forecastIsEmpty =
!!postForecastAvailability?.isEmpty &&
!postForecastAvailability?.cpRevealsOn;

if (topItems.length === 0 && !forecastIsEmpty) return null;

const openKeyFactorsElement = (selector: string) => {
requestKeyFactorsExpand?.();
openKeyFactorsSectionAndScrollTo({ selector, mobileOnly: false });
sendAnalyticsEvent("KeyFactorClick", { event_label: "fromTopList" });
};

if (topItems.length === 0) return null;

return (
<div
className="-ml-4 flex w-[calc(100%+32px)] flex-col pb-4 sm:ml-0 sm:mt-8 sm:w-full"
Expand All @@ -58,18 +68,33 @@ const KeyFactorsQuestionConsumerSection: FC<Props> = ({ post }) => {
<div className="text-sm text-blue-800 dark:text-blue-800-dark">
{t("topKeyFactors")}
</div>
<button
onClick={() => {
openKeyFactorsElement("[id='key-factors']");
sendAnalyticsEvent("KeyFactorViewAllClick");
}}
className="text-center text-sm font-normal leading-5 text-blue-600 hover:text-blue-700 dark:text-blue-600-dark dark:hover:text-blue-700-dark"
>
{t("viewAll", { count: totalCount })}
</button>
{!forecastIsEmpty && (
<button
onClick={() => {
openKeyFactorsElement("[id='key-factors']");
sendAnalyticsEvent("KeyFactorViewAllClick");
}}
className="text-center text-sm font-normal leading-5 text-blue-600 hover:text-blue-700 dark:text-blue-600-dark dark:hover:text-blue-700-dark"
>
{t("viewAll", { count: totalCount })}
</button>
)}
</div>

<KeyFactorsConsumerCarousel post={post} items={topItems} />
{forecastIsEmpty ? (
<KeyFactorsCarousel
listClassName="pb-0 [&>:first-child]:pl-4 [&>:last-child]:pr-4 sm:[&>:first-child]:pl-0 sm:[&>:last-child]:pr-0"
items={Array.from({ length: 5 })}
renderItem={(_, i) => (
<div
key={i}
className="h-[196px] w-[160px] shrink-0 rounded-xl bg-blue-200 dark:bg-blue-200-dark sm:w-[200px]"
/>
)}
/>
) : (
<KeyFactorsConsumerCarousel post={post} items={topItems} />
)}

{keyFactorOverlay?.kind === "keyFactor" && (
<KeyFactorDetailOverlay
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,10 +319,11 @@ const MultiChoicesChartView: FC<Props> = ({
)}

{isTooltipActive &&
!hideCP &&
!forecastAvailability?.cpRevealsOn &&
!activeTimelineMarkerId &&
(tooltipChoices.length > 0 ||
!!tooltipUserChoices?.length ||
!!forecastAvailability?.cpRevealsOn ||
!!forecastAvailability?.isEmpty) && (
<FloatingPortal>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import { FC, Fragment, ReactNode, useEffect } from "react";

import useCoherenceLinksContext from "@/app/(main)/components/coherence_links_provider";
import { PostStatusBox } from "@/app/(main)/questions/[id]/components/post_status_box";
import UpcomingCP from "@/components/consumer_post_card/upcoming_cp";
import DetailedGroupCard from "@/components/detailed_question_card/detailed_group_card";
import DetailedQuestionCard from "@/components/detailed_question_card/detailed_question_card";
import ForecastMaker from "@/components/forecast_maker";
import CommunityDisclaimer from "@/components/post_card/community_disclaimer";
import { ContinuousChartCursorProvider } from "@/contexts/continuous_chart_cursor_context";
import { useHideCP } from "@/contexts/cp_context";
import { useContentTranslatedBannerContext } from "@/contexts/translations_banner_context";
import {
GroupOfQuestionsGraphType,
Expand All @@ -19,6 +22,7 @@ import {
import { TournamentType } from "@/types/projects";
import { QuestionType } from "@/types/question";
import cn from "@/utils/core/cn";
import { getQuestionForecastAvailability } from "@/utils/questions/forecastAvailability";
import {
checkGroupOfQuestionsPostType,
isContinuousQuestion,
Expand All @@ -38,6 +42,8 @@ import { QuestionVariantComposer } from "../question_variant_composer";
import ActionRow from "../question_view/action_row";
import ConsumerQuestionPrediction from "../question_view/consumer_question_view/prediction";
import QuestionTimeline from "../question_view/consumer_question_view/timeline";
import QuestionHeaderCPStatus from "../question_view/forecaster_question_view/question_header/question_header_cp_status";
import RevealCPButton from "../reveal_cp_button";

const baseSectionClassName =
"relative z-10 flex w-[59rem] max-w-full flex-col gap-6 overflow-x-clip rounded border border-blue-400 p-4 text-gray-900 dark:border-blue-200-dark dark:text-gray-900-dark lg:p-8";
Expand Down Expand Up @@ -128,6 +134,7 @@ export const ConsumerShell: FC<{
}> = ({ postData, preselectedGroupQuestionId, mobileSidebar }) => {
const t = useTranslations();
const { aggregateCoherenceLinks } = useCoherenceLinksContext();
const { hideCP } = useHideCP();

const isFanGraph =
postData.group_of_questions?.graph_type ===
Expand All @@ -151,9 +158,16 @@ export const ConsumerShell: FC<{
!isContinuousSingleQuestion &&
!isMultipleChoice;

const binaryForecastAvailability =
isBinarySingleQuestion && isQuestionPost(postData)
? getQuestionForecastAvailability(postData.question)
: null;

const showSideBySide =
(isMultipleChoice || isNonFanGroup || isBinarySingleQuestion) &&
!isContinuousSingleQuestion;
isMultipleChoice ||
isNonFanGroup ||
isBinarySingleQuestion ||
isContinuousSingleQuestion;

const showClosedMessageMultipleChoice =
isMultipleChoicePost(postData) &&
Expand All @@ -166,7 +180,14 @@ export const ConsumerShell: FC<{
aggregateCoherenceLinks?.data.filter(isDisplayableQuestionLink) ?? [];
const hasKeyFactors = (postData.key_factors?.length ?? 0) > 0;
const hasQuestionLinks = questionLinkAggregates.length > 0;
const shouldShowKeyFactorsSection = hasKeyFactors || hasQuestionLinks;
const questionForecastAvailability = isQuestionPost(postData)
? getQuestionForecastAvailability(postData.question)
: null;
const isForecastEmpty =
!!questionForecastAvailability?.isEmpty &&
!questionForecastAvailability?.cpRevealsOn;
const shouldShowKeyFactorsSection =
hasKeyFactors || hasQuestionLinks || isForecastEmpty;

return (
<div className="flex flex-col gap-1.5 md:gap-4">
Expand All @@ -191,7 +212,7 @@ export const ConsumerShell: FC<{
<div className="order-2 sm:order-none">
<ActionRow post={postData} variant="consumer" />
</div>
<div className="order-1 mt-3 sm:order-none sm:mt-8 md:-mt-2 lg:-mt-3">
<div className="order-1 mt-3 sm:order-none sm:mt-0 md:-mt-2 lg:-mt-3">
{showClosedMessageMultipleChoice && (
<p className="m-0 mb-8 text-center text-sm leading-[20px] text-gray-700 dark:text-gray-700-dark">
{t("predictionClosedMessage")}
Expand All @@ -204,26 +225,60 @@ export const ConsumerShell: FC<{
!isMultipleChoice &&
!isNonFanGroup &&
"flex-col-reverse",
showSideBySide && "sm:flex-row sm:items-center sm:gap-8"
showSideBySide &&
cn("sm:flex-row sm:items-center", {
"sm:gap-0 md:gap-8": isBinarySingleQuestion,
"sm:gap-8": !isBinarySingleQuestion,
})
)}
>
<div
className={cn(
showSideBySide && !isDateGroup ? "order-1" : undefined,
isContinuousSingleQuestion && "md:hidden"
)}
>
<ConsumerQuestionPrediction postData={postData} />
</div>
{isBinarySingleQuestion && isQuestionPost(postData) ? (
<div className="order-1 flex w-64 flex-col items-center justify-center gap-[18px] self-center sm:self-stretch">
{hideCP ? (
<RevealCPButton />
) : binaryForecastAvailability?.cpRevealsOn ? (
<UpcomingCP
cpRevealsOn={binaryForecastAvailability.cpRevealsOn}
/>
) : (
<QuestionHeaderCPStatus
question={postData.question}
size="lg"
/>
)}
</div>
) : (
<div
className={cn(
showSideBySide && !isDateGroup ? "order-1" : undefined,
isContinuousSingleQuestion && "md:hidden",
showSideBySide &&
!isDateGroup &&
!isContinuousSingleQuestion &&
"sm:max-w-[200px]",
hideCP &&
!isContinuousSingleQuestion &&
(isDateGroup || isFanGraph) &&
"flex w-full justify-center"
)}
>
{hideCP && !isContinuousSingleQuestion ? (
<RevealCPButton />
) : (
<ConsumerQuestionPrediction postData={postData} />
)}
</div>
)}
{!isFanGraph && !isDateGroup && (
<QuestionTimeline
postData={postData}
keyFactors={postData.key_factors}
isConsumerView={!isContinuousSingleQuestion}
isConsumerView={true}
preselectedGroupQuestionId={preselectedGroupQuestionId}
className={cn(
"hidden sm:block",
showSideBySide && "order-2 mt-0 flex-1"
showSideBySide && "order-2 mt-0 flex-1",
isContinuousSingleQuestion && "mt-0"
)}
/>
)}
Expand Down Expand Up @@ -263,18 +318,23 @@ const QuestionPageShell: FC<Props> = ({
<QuestionLayoutProvider>
<QuestionVariantComposer
consumer={
<ConsumerShell
postData={postData}
preselectedGroupQuestionId={preselectedGroupQuestionId}
mobileSidebar={mobileSidebar}
/>
<ContinuousChartCursorProvider>
{/* Bridges timeline cursor to the mobile mini chart in consumer view */}
<ConsumerShell
postData={postData}
preselectedGroupQuestionId={preselectedGroupQuestionId}
mobileSidebar={mobileSidebar}
/>
</ContinuousChartCursorProvider>
}
forecaster={
<ForecasterShell
postData={postData}
preselectedGroupQuestionId={preselectedGroupQuestionId}
mobileSidebar={mobileSidebar}
/>
<ContinuousChartCursorProvider>
<ForecasterShell
postData={postData}
preselectedGroupQuestionId={preselectedGroupQuestionId}
mobileSidebar={mobileSidebar}
/>
</ContinuousChartCursorProvider>
}
/>
</QuestionLayoutProvider>
Expand Down
Loading
Loading