From 84ff644ebb83318ecd8d0d782e9583d3c8a4e2ac Mon Sep 17 00:00:00 2001 From: mihretue Date: Mon, 17 Aug 2026 08:26:21 +0000 Subject: [PATCH] fix(question): show both language fields for MCQ options Options editor used a single toggle-based bilingual field (BilingualInput) that swapped English/Amharic in place via a tiny, easy-to-miss button. Authors were filling English only and never noticing Amharic was empty. - QuestionOptionsEditor: show separate always-visible English/Amharic TextInputs per option instead of the toggle field. - BilingualInput (shared): for other callers still using the toggle, add a tooltip and a red dot indicator when the hidden language is empty, so the gap is visible without switching. Co-Authored-By: Claude Sonnet 5 --- .../components/QuestionOptionsEditor.tsx | 39 +++++---- apps/backoffice/src/app/i18n/locales/am.ts | 2 + apps/backoffice/src/app/i18n/locales/en.ts | 2 + libs/ui/src/lib/input/BilingualInput.tsx | 80 ++++++++++++------- 4 files changed, 81 insertions(+), 42 deletions(-) diff --git a/apps/backoffice/src/app/features/question/components/QuestionOptionsEditor.tsx b/apps/backoffice/src/app/features/question/components/QuestionOptionsEditor.tsx index 2daab604a..3a464cff2 100644 --- a/apps/backoffice/src/app/features/question/components/QuestionOptionsEditor.tsx +++ b/apps/backoffice/src/app/features/question/components/QuestionOptionsEditor.tsx @@ -1,8 +1,8 @@ import { useEffect, useState } from 'react'; -import { ActionIcon, Alert, Button, Checkbox, Group, Loader, Stack, Text } from '@mantine/core'; +import { ActionIcon, Alert, Button, Checkbox, Group, Loader, Stack, Text, TextInput } from '@mantine/core'; import { useTranslation } from 'react-i18next'; import { IconGripVertical, IconInfoCircle, IconPlus, IconTrash } from '@tabler/icons-react'; -import { BilingualInput, notify, useErrorHandler } from '@ema-platform/ui'; +import { notify, useErrorHandler } from '@ema-platform/ui'; import type { BilingualValue } from '@ema-platform/ui'; import { useGetQuestionWithOptionsQuery, @@ -48,8 +48,10 @@ export function QuestionOptionsEditor({ questionId }: { questionId: string }) { // pretending to know what they were. }, [question]); - const updateText = (index: number, text: BilingualValue) => { - setDraft((prev) => prev.map((o, i) => (i === index ? { ...o, text } : o))); + const updateField = (index: number, lang: keyof BilingualValue, value: string) => { + setDraft((prev) => + prev.map((o, i) => (i === index ? { ...o, text: { ...o.text, [lang]: value } } : o)), + ); }; const toggleCorrect = (index: number) => { @@ -93,26 +95,33 @@ export function QuestionOptionsEditor({ questionId }: { questionId: string }) { {t('question.options.hint')} {draft.map((option, index) => ( - - - updateText(index, v)} - size="sm" - style={{ flex: 1 }} - /> + + + + updateField(index, 'en', e.currentTarget.value)} + size="sm" + required + /> + updateField(index, 'am', e.currentTarget.value)} + size="sm" + required + /> + toggleCorrect(index)} - mb={4} /> removeOption(index)} > diff --git a/apps/backoffice/src/app/i18n/locales/am.ts b/apps/backoffice/src/app/i18n/locales/am.ts index 63d38a013..ed93619ff 100644 --- a/apps/backoffice/src/app/i18n/locales/am.ts +++ b/apps/backoffice/src/app/i18n/locales/am.ts @@ -742,6 +742,8 @@ export const am: Translations = { title: "የመልስ አማራጮች", hint: "ትክክለኛውን አማራጭ ምረጥ/ምረጪ። ማስቀመጥ መላውን የአማራጭ ስብስብ ይተካል።", optionLabel: "አማራጭ {{number}}", + optionEn: "አማራጭ {{number}} (እንግሊዝኛ)", + optionAm: "አማራጭ {{number}} (አማርኛ)", correct: "ትክክለኛ", addOption: "አማራጭ ጨምር", save: "አማራጮችን አስቀምጥ", diff --git a/apps/backoffice/src/app/i18n/locales/en.ts b/apps/backoffice/src/app/i18n/locales/en.ts index 49a5a8b12..bce0a87d9 100644 --- a/apps/backoffice/src/app/i18n/locales/en.ts +++ b/apps/backoffice/src/app/i18n/locales/en.ts @@ -743,6 +743,8 @@ export const en = { title: 'Answer Options', hint: 'Mark every correct option. Saving replaces the entire option set.', optionLabel: 'Option {{number}}', + optionEn: 'Option {{number}} (English)', + optionAm: 'Option {{number}} (Amharic)', correct: 'Correct', addOption: 'Add option', save: 'Save options', diff --git a/libs/ui/src/lib/input/BilingualInput.tsx b/libs/ui/src/lib/input/BilingualInput.tsx index 3e0a9684d..9fb7c4836 100644 --- a/libs/ui/src/lib/input/BilingualInput.tsx +++ b/libs/ui/src/lib/input/BilingualInput.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import { + Tooltip, TextInput, UnstyledButton, rem, @@ -37,6 +38,9 @@ export function BilingualInput({ ...rest }: BilingualInputProps) { const [lang, setLang] = useState<'en' | 'am'>('en'); + const otherLang = lang === 'en' ? 'am' : 'en'; + const otherLangName = otherLang === 'en' ? 'English' : 'Amharic'; + const otherIsEmpty = !value[otherLang]?.trim(); const toggle = () => setLang((l) => (l === 'en' ? 'am' : 'en')); @@ -48,37 +52,59 @@ export function BilingualInput({ value={value[lang]} onChange={(e) => onChange({ ...value, [lang]: e.currentTarget.value })} rightSection={ - - {lang === 'en' ? 'EN' : 'AM'} - + + {lang === 'en' ? 'EN' : 'AM'} + {otherIsEmpty && ( + + )} + + } styles={{ input: { - paddingRight: rem(42), + paddingRight: rem(46), }, }} {...rest}