Skip to content
Open
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
2 changes: 2 additions & 0 deletions front_end/messages/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,8 @@
"groupVariableDescription": "Co představují štítky podotázek (např. rok, země atd.).",
"categoryPickerDescription": "Název parametru, který se liší mezi podotázkami, jako je \"Možnost\", \"Rok\" nebo \"Země\"",
"subquestionLabel": "Štítek podotázky",
"optionColor": "Barva",
"defaultColor": "Výchozí barva",
"subquestionLabelDescription": "Štítek nebo parametr, který identifikuje tuto podotázku, jako je \"Možnost 1\", \"2033\" nebo \"Francie\"",
"conditionalPairDescription": "Podmíněný pár je speciální typ skupiny otázek, který vyvolává podmíněné pravděpodobnosti. Každý podmíněný pár je mezi nadřazenou otázkou a podřazenou otázkou. Nadřazená otázka musí být binární, zatímco podřazená může být buď binární, číselná nebo datová otázka.",
"isDoneError": "Nelze upravit uzavřené, vyřešené nebo odmítnuté otázky",
Expand Down
2 changes: 2 additions & 0 deletions front_end/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,8 @@
"groupVariableDescription": "What the subquestion labels represent (e.g. year, country, etc).",
"categoryPickerDescription": "A name for the parameter which varies between subquestions, like \"Option\", \"Year\" or \"Country\"",
"subquestionLabel": "Subquestion label",
"optionColor": "Color",
"defaultColor": "Default color",
"subquestionLabelDescription": "The label or parameter which identifies this subquestion, like \"Option 1\", \"2033\" or \"France\"",
"conditionalPairDescription": "A Conditional Pair is a special type of Question Group that elicits conditional probabilities. Each Conditional Pair sits between a Parent Question and a Child Question. The Parent must be a binary question, while the child may be a single binary, numeric, or date question.",
"parentQuestion": "Parent Question",
Expand Down
2 changes: 2 additions & 0 deletions front_end/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,8 @@
"groupVariableDescription": "Lo que representan las etiquetas de subpreguntas (por ejemplo, año, país, etc.).",
"categoryPickerDescription": "Un nombre para el parámetro que varía entre subpreguntas, como \"Opción\", \"Año\" o \"País\"",
"subquestionLabel": "Etiqueta de subpregunta",
"optionColor": "Color",
"defaultColor": "Color predeterminado",
"subquestionLabelDescription": "La etiqueta o parámetro que identifica esta subpregunta, como \"Opción 1\", \"2033\" o \"Francia\"",
"conditionalPairDescription": "Un Par Condicional es un tipo especial de Grupo de Preguntas que solicita probabilidades condicionales. Cada Par Condicional se encuentra entre una Pregunta Principal y una Pregunta Secundaria. La Principal debe ser una pregunta binaria, mientras que la secundaria puede ser una pregunta binaria, numérica o de fecha.",
"isDoneError": "No se pueden editar preguntas cerradas, resueltas o rechazadas",
Expand Down
2 changes: 2 additions & 0 deletions front_end/messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,8 @@
"groupVariableDescription": "O que os rótulos das subperguntas representam (por exemplo, ano, país, etc.).",
"categoryPickerDescription": "Um nome para o parâmetro que varia entre as subperguntas, como \"Opção\", \"Ano\" ou \"País\"",
"subquestionLabel": "Rótulo da Subpergunta",
"optionColor": "Cor",
"defaultColor": "Cor padrão",
"subquestionLabelDescription": "O rótulo ou parâmetro que identifica esta subpergunta, como \"Opção 1\", \"2033\" ou \"França\"",
"conditionalPairDescription": "Um Par Condicional é um tipo especial de Grupo de Perguntas que elicia probabilidades condicionais. Cada Par Condicional está entre uma Pergunta Pai e uma Pergunta Filha. O Pai deve ser uma pergunta binária, enquanto a filha pode ser uma única pergunta binária, numérica ou de data.",
"isDoneError": "Não é possível editar perguntas fechadas, resolvidas ou rejeitadas",
Expand Down
2 changes: 2 additions & 0 deletions front_end/messages/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,8 @@
"groupVariableDescription": "子問題標籤代表什麼 (例如年份、國家等)。",
"categoryPickerDescription": "在子問題之間變化的參數名稱,例如“選項”、“年份”或“國家”",
"subquestionLabel": "子問題標籤",
"optionColor": "顏色",
"defaultColor": "預設顏色",
"subquestionLabelDescription": "標籤或參數,用於識別此子問題,例如“選項 1”、“2033”或“法國”",
"conditionalPairDescription": "條件對是一種特殊類型的問題組,用於引出條件概率。每個條件對位於父問題與子問題之間。父問題必須是二元問題,而子問題可以是單個二元、數字或日期問題。",
"parentQuestion": "父問題",
Expand Down
2 changes: 2 additions & 0 deletions front_end/messages/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,8 @@
"groupVariableDescription": "子問題標籤所代表的內容(例如年份、國家等)。",
"categoryPickerDescription": "子問題之間變化的參數名稱,如「選項」、「年份」或「國家」",
"subquestionLabel": "子問題標籤",
"optionColor": "颜色",
"defaultColor": "默认颜色",
"subquestionLabelDescription": "識別此子問題的���籤或參數,如「選項1」、「2033」或「法國」",
"conditionalPairDescription": "條件對是一種特殊類型的問題組,用於獲取條件概率。每個條件對位於父問題和子問題之間。父問題必須是二元問題,而子問題可以是單一二元、數值或日期問題。",
"isDoneError": "無法編輯已關閉、已解決或被拒絕的問題",
Expand Down
87 changes: 87 additions & 0 deletions front_end/src/app/(main)/questions/components/color_picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"use client";

import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
import { useTranslations } from "next-intl";
import { FC } from "react";

import {
getMcOptionColor,
MC_OPTION_PALETTE_KEYS,
METAC_COLORS,
} from "@/constants/colors";
import useAppTheme from "@/hooks/use_app_theme";
import { ThemeColor } from "@/types/theme";
import cn from "@/utils/core/cn";

type Props = {
value: string | null | undefined;
onChange: (key: string | null) => void;
fallback?: ThemeColor;
};

const ColorPicker: FC<Props> = ({ value, onChange, fallback }) => {
const t = useTranslations();
const { getThemeColor } = useAppTheme();

const currentColor =
getMcOptionColor(value) ?? fallback ?? METAC_COLORS.gray["400"];

return (
<Popover className="relative">
<PopoverButton
type="button"
title={t("optionColor")}
aria-label={t("optionColor")}
className="block size-6 shrink-0 rounded border border-gray-500 dark:border-gray-500-dark"
style={{ backgroundColor: getThemeColor(currentColor) }}
/>
<PopoverPanel
portal
anchor="bottom start"
className="z-[100] grid grid-cols-6 gap-1 rounded border border-gray-300 bg-gray-0 p-2 shadow-lg dark:border-gray-300-dark dark:bg-gray-0-dark"
>
{({ close }) => (
<>
{MC_OPTION_PALETTE_KEYS.map((key) => {
const color = getMcOptionColor(key);
if (!color) return null;

return (
<button
key={key}
type="button"
className={cn(
"size-6 rounded border border-transparent",
key === value &&
"ring-2 ring-blue-700 ring-offset-1 dark:ring-blue-700-dark"
)}
style={{ backgroundColor: getThemeColor(color) }}
onClick={() => {
onChange(key);
close();
}}
/>
);
Comment thread
aseckin marked this conversation as resolved.
})}
<button
type="button"
title={t("defaultColor")}
aria-label={t("defaultColor")}
className="flex size-6 items-center justify-center rounded border border-gray-500 text-gray-600 dark:border-gray-500-dark dark:text-gray-600-dark"
onClick={() => {
onChange(null);
close();
}}
>
<FontAwesomeIcon icon={faXmark} size="sm" />
</button>
</>
)}
</PopoverPanel>
</Popover>
);
};

export default ColorPicker;
54 changes: 40 additions & 14 deletions front_end/src/app/(main)/questions/components/group_form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ import { InputContainer } from "@/components/ui/input_container";
import LoadingIndicator from "@/components/ui/loading_indicator";
import { MarkdownText } from "@/components/ui/markdown_text";
import Select from "@/components/ui/select";
import { MULTIPLE_CHOICE_COLOR_SCALE } from "@/constants/colors";
import { ContinuousQuestionTypes } from "@/constants/questions";
import { useAuth } from "@/contexts/auth_context";
import { useDebouncedCallback } from "@/hooks/use_debounce";
import {
GroupOfQuestionsGraphType,
Expand Down Expand Up @@ -66,13 +68,15 @@ import { sortGroupPredictionOptions } from "@/utils/questions/groupOrdering";

import BacktoCreate from "./back_to_create";
import CategoryPicker from "./category_picker";
import ColorPicker from "./color_picker";
import NumericQuestionInput from "./numeric_question_input";
import { createQuestionPost, updatePost } from "../actions";

type SubQuestionDraftBase = {
id?: number;
clientId: string;
label: string;
label_color?: string | null;
scheduled_close_time?: string | undefined;
scheduled_resolve_time?: string | undefined;
open_time?: string | undefined;
Expand All @@ -96,6 +100,7 @@ type CreateSubQuestionPayload = {
type: SimpleQuestionType;
title: string;
label: string;
label_color?: string | null;
scheduled_close_time: string | undefined;
scheduled_resolve_time?: string | undefined;
open_time: string | undefined;
Expand Down Expand Up @@ -209,6 +214,7 @@ const GroupForm: React.FC<Props> = ({
}) => {
const router = useRouter();
const t = useTranslations();
const { user } = useAuth();
const isDuplicate = mode === "create" && !!post;
const isDraftMounted = useRef(false);
const draftKey = `group_${subtype}`;
Expand Down Expand Up @@ -259,6 +265,7 @@ const GroupForm: React.FC<Props> = ({
type: sqType,
title: `${data["title"]} (${x.label})`,
label: x.label,
label_color: x.label_color ?? null,
scheduled_close_time: x.scheduled_close_time,
scheduled_resolve_time: x.scheduled_resolve_time,
open_time: x.open_time,
Expand Down Expand Up @@ -395,6 +402,7 @@ const GroupForm: React.FC<Props> = ({
open_time: isDuplicate ? undefined : x.open_time,
cp_reveal_time: isDuplicate ? undefined : x.cp_reveal_time,
label: x.label,
label_color: x.label_color,
unit: x.unit,
scaling: x.scaling,
open_lower_bound: x.open_lower_bound,
Expand Down Expand Up @@ -789,20 +797,38 @@ const GroupForm: React.FC<Props> = ({
: undefined
}
>
<Input
onChange={(e) => {
setSubQuestions(
subQuestions.map((subQuestion, iter_index) => {
if (index === iter_index) {
subQuestion["label"] = e.target.value;
}
return subQuestion;
})
);
}}
className="rounded border border-gray-500 px-3 py-2 text-base dark:border-gray-500-dark dark:bg-blue-50-dark"
value={subQuestion?.label}
/>
<div className="flex items-center gap-2">
<Input
onChange={(e) => {
setSubQuestions(
subQuestions.map((subQuestion, iter_index) => {
if (index === iter_index) {
subQuestion["label"] = e.target.value;
}
return subQuestion;
})
);
}}
className="w-full rounded border border-gray-500 px-3 py-2 text-base dark:border-gray-500-dark dark:bg-blue-50-dark"
value={subQuestion?.label}
/>
{user?.is_superuser && (
<ColorPicker
value={subQuestion?.label_color}
fallback={MULTIPLE_CHOICE_COLOR_SCALE[index]}
onChange={(key) => {
setSubQuestions(
subQuestions.map((subQuestion, iter_index) => {
if (index === iter_index) {
subQuestion["label_color"] = key;
}
return subQuestion;
})
);
}}
/>
)}
</div>
</InputContainer>
{collapsedSubQuestions[index] && (
<div className="flex w-full flex-col gap-4">
Expand Down
Loading
Loading