diff --git a/web/components/multi-checkbox.tsx b/web/components/multi-checkbox.tsx index 72b0cdef..52bd021c 100644 --- a/web/components/multi-checkbox.tsx +++ b/web/components/multi-checkbox.tsx @@ -23,7 +23,7 @@ export const MultiCheckbox = (props: { addPlaceholder?: string translationPrefix?: string }) => { - const { choices, selected, onChange, className, addOption, addPlaceholder, translationPrefix } = props + const {choices, selected, onChange, className, addOption, addPlaceholder, translationPrefix} = props // Keep a local merged copy to allow optimistic adds while remaining in sync with props const [localChoices, setLocalChoices] = useState<{ [key: string]: string }>(choices) @@ -31,7 +31,7 @@ export const MultiCheckbox = (props: { setLocalChoices((prev) => { // If incoming choices changed, merge them with any locally added that still don't collide // Props should be source of truth on conflicts - return { ...prev, ...choices } + return {...prev, ...choices} }) }, [choices]) @@ -44,12 +44,18 @@ export const MultiCheckbox = (props: { const t = useT() + const translateOption = (key: string, value: string) => { + if (!translationPrefix) return key + return t(`${translationPrefix}.${toKey(value)}`, key) + } + // Filter visible options while typing a new option (case-insensitive label match) const filteredEntries = useMemo(() => { if (!addOption) return entries - const q = newLabel.trim().toLowerCase() + let q = newLabel.trim() + q = translateOption(q, q).toLowerCase() if (!q) return entries - return entries.filter(([key]) => key.toLowerCase().includes(q)) + return entries.filter(([key, value]) => translateOption(key, value).toLowerCase().includes(q)) }, [addOption, entries, newLabel]) const submitAdd = async () => { @@ -57,33 +63,37 @@ export const MultiCheckbox = (props: { const label = newLabel.trim() setError(null) if (!label) { - setError('Please enter a value.') + setError(t('multi-checkbox.enter_value', 'Please enter a value.')) return } // prevent duplicate by label or by value already selected - const lowerCaseChoices = Object.keys(localChoices).map((k: string) => k.toLowerCase()) - if (lowerCaseChoices.includes(label.toLowerCase())) { - setError('That option already exists.') - // const key = Object.keys(lowerCaseChoices).find((k) => k.toLowerCase() === label.toLowerCase()) - // if (!key) return - // setProfile('interests', [...(profile['interests'] ?? []), key]) + const existingEntry = Object.entries(localChoices).find(([key, value]) => + translateOption(key, value).toLowerCase() === translateOption(label, label).toLowerCase() + ) + + if (existingEntry) { + const [_, existingValue] = existingEntry + if (!selected.includes(existingValue)) { + onChange([...selected, existingValue]) + } + setNewLabel('') return } setAdding(true) try { const result = addOption(label) if (!result) { - setError('Could not add option.') + setError(t('multi-checkbox.could_not_add', 'Could not add option.')) setAdding(false) return } - const { key, value } = typeof result === 'string' ? { key: label, value: result } : result - setLocalChoices((prev) => ({ ...prev, [key]: value })) + const {key, value} = typeof result === 'string' ? {key: label, value: result} : result + setLocalChoices((prev) => ({...prev, [key]: value})) // auto-select newly added option if not already selected if (!selected.includes(value)) onChange([...selected, value]) setNewLabel('') } catch (e) { - setError('Failed to add option.') + setError(t('multi-checkbox.add_failed', 'Failed to add option.')) } finally { setAdding(false) } @@ -119,7 +129,7 @@ export const MultiCheckbox = (props: { {filteredEntries.map(([key, value]) => ( { if (checked) { @@ -132,7 +142,9 @@ export const MultiCheckbox = (props: { ))} {addOption && newLabel.trim() && filteredEntries.length === 0 && ( -
No matching options, feel free to add it.
+
+ {t('multi-checkbox.no_matching_options', 'No matching options, feel free to add it.')} +
)} ) diff --git a/web/messages/de.json b/web/messages/de.json index 3943c052..cd01a740 100644 --- a/web/messages/de.json +++ b/web/messages/de.json @@ -283,7 +283,11 @@ "messages.toast.muting_forever.success": "Benachrichtigungen dauerhaft stummgeschaltet", "messages.toast.send_failed": "Senden der Nachricht fehlgeschlagen. Bitte versuchen Sie es später erneut oder kontaktieren Sie den Support, wenn das Problem weiterhin besteht.", "messages.you_prefix": "Sie: ", + "multi-checkbox.enter_value": "Bitte geben Sie einen Wert ein.", + "multi-checkbox.could_not_add": "Option konnte nicht hinzugefügt werden.", + "multi-checkbox.add_failed": "Hinzufügen der Option fehlgeschlagen.", "multi-checkbox.search_or_add": "Suchen oder hinzufügen", + "multi-checkbox.no_matching_options": "Keine passenden Optionen, Sie können gerne eine hinzufügen.", "nav.about": "Über uns", "nav.contact": "Kontakt", "nav.faq": "FAQ", @@ -734,6 +738,7 @@ "register.error.all_fields_required": "Alle Felder sind erforderlich", "register.error.email_in_use": "Diese E-Mail ist bereits registriert", "register.error.unknown": "Registrierung fehlgeschlagen", + "error.option_exists": "Diese Option existiert bereits", "register.get_started": "Loslegen", "register.link_signin": "Anmelden", "register.or_sign_up_with": "Oder registrieren mit", diff --git a/web/messages/fr.json b/web/messages/fr.json index fc4c9c8b..fbb991b9 100644 --- a/web/messages/fr.json +++ b/web/messages/fr.json @@ -283,7 +283,11 @@ "messages.toast.muting_forever.success": "Notifs coupées définitivement", "messages.toast.send_failed": "Échec de l'envoi du message. Veuillez réessayer plus tard ou contacter le support si le problème persiste.", "messages.you_prefix": "Vous : ", - "multi-checkbox.search_or_add": "Chercher ou ajouter", + "multi-checkbox.enter_value": "Veuillez saisir une valeur.", + "multi-checkbox.could_not_add": "Impossible d'ajouter l'option.", + "multi-checkbox.add_failed": "Échec de l'ajout de l'option.", + "multi-checkbox.search_or_add": "Rechercher ou ajouter", + "multi-checkbox.no_matching_options": "Aucune option correspondante, n'hésitez pas à l'ajouter.", "nav.about": "À propos", "nav.contact": "Contact", "nav.faq": "FAQ", @@ -734,6 +738,7 @@ "register.error.all_fields_required": "Tous les champs sont requis", "register.error.email_in_use": "Cet e‑mail est déjà enregistré", "register.error.unknown": "Échec de l'inscription", + "error.option_exists": "Cette option existe déjà", "register.get_started": "Commencer", "register.link_signin": "Se connecter", "register.or_sign_up_with": "Ou inscrivez-vous avec",