From 189313e94a16e694d192d157642d77f664fd709b Mon Sep 17 00:00:00 2001 From: TheCatLady <52870424+TheCatLady@users.noreply.github.com> Date: Fri, 30 Apr 2021 14:02:59 -0400 Subject: [PATCH] fix: correctly fall back to English name in LanguageSelector (#1537) * fix: correctly fall back to English name in LanguageSelector * refactor: clean up language sort & name logic * refactor: also clean up region sort & name logic * refactor: use arrow functions --- server/lib/settings.ts | 1 + src/components/LanguageSelector/index.tsx | 56 ++++++++--------- src/components/RegionSelector/index.tsx | 61 ++++++------------- src/components/Settings/SettingsMain.tsx | 30 ++------- .../UserGeneralSettings/index.tsx | 33 +--------- 5 files changed, 49 insertions(+), 132 deletions(-) diff --git a/server/lib/settings.ts b/server/lib/settings.ts index 1f6fc89d..c2cda61e 100644 --- a/server/lib/settings.ts +++ b/server/lib/settings.ts @@ -14,6 +14,7 @@ export interface Library { export interface Region { iso_3166_1: string; english_name: string; + name?: string; } export interface Language { diff --git a/src/components/LanguageSelector/index.tsx b/src/components/LanguageSelector/index.tsx index 89392b31..652687da 100644 --- a/src/components/LanguageSelector/index.tsx +++ b/src/components/LanguageSelector/index.tsx @@ -1,8 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import { sortBy } from 'lodash'; import dynamic from 'next/dynamic'; -import React from 'react'; +import React, { useMemo } from 'react'; import { defineMessages, useIntl } from 'react-intl'; import type { OptionsType, OptionTypeBase } from 'react-select'; +import useSWR from 'swr'; import { Language } from '../../../server/lib/settings'; import globalMessages from '../../i18n/globalMessages'; @@ -29,7 +31,6 @@ const selectStyles = { }; interface LanguageSelectorProps { - languages: Language[]; value?: string; setFieldValue: (property: string, value: string) => void; serverValue?: string; @@ -37,26 +38,33 @@ interface LanguageSelectorProps { } const LanguageSelector: React.FC = ({ - languages, value, setFieldValue, serverValue, isUserSettings = false, }) => { const intl = useIntl(); + const { data: languages } = useSWR('/api/v1/languages'); - const defaultLanguageNameFallback = serverValue - ? languages.find((language) => language.iso_639_1 === serverValue) - ?.english_name ?? serverValue - : undefined; - - const options: OptionType[] = - languages.map((language) => ({ - label: + const sortedLanguages = useMemo(() => { + languages?.forEach((language) => { + language.name = intl.formatDisplayName(language.iso_639_1, { type: 'language', fallback: 'none', - }) ?? language.english_name, + }) ?? language.english_name; + }); + + return sortBy(languages, 'name'); + }, [intl, languages]); + + const languageName = (languageCode: string) => + sortedLanguages?.find((language) => language.iso_639_1 === languageCode) + ?.name ?? languageCode; + + const options: OptionType[] = + sortedLanguages?.map((language) => ({ + label: language.name, value: language.iso_639_1, })) ?? []; @@ -67,13 +75,7 @@ const LanguageSelector: React.FC = ({ language: serverValue ? serverValue .split('|') - .map( - (value) => - intl.formatDisplayName(value, { - type: 'language', - fallback: 'none', - }) ?? defaultLanguageNameFallback - ) + .map((value) => languageName(value)) .reduce((prev, curr) => intl.formatMessage(globalMessages.delimitedlist, { a: prev, @@ -112,13 +114,7 @@ const LanguageSelector: React.FC = ({ language: serverValue ? serverValue .split('|') - .map( - (value) => - intl.formatDisplayName(value, { - type: 'language', - fallback: 'none', - }) ?? defaultLanguageNameFallback - ) + .map((value) => languageName(value)) .reduce((prev, curr) => intl.formatMessage(globalMessages.delimitedlist, { a: prev, @@ -130,7 +126,7 @@ const LanguageSelector: React.FC = ({ isFixed: true, } : value?.split('|').map((code) => { - const matchedLanguage = languages.find( + const matchedLanguage = sortedLanguages?.find( (lang) => lang.iso_639_1 === code ); @@ -139,11 +135,7 @@ const LanguageSelector: React.FC = ({ } return { - label: - intl.formatDisplayName(matchedLanguage.iso_639_1, { - type: 'language', - fallback: 'none', - }) ?? matchedLanguage.english_name, + label: matchedLanguage.name, value: matchedLanguage.iso_639_1, }; }) ?? undefined diff --git a/src/components/RegionSelector/index.tsx b/src/components/RegionSelector/index.tsx index 724f8e19..da4c30c5 100644 --- a/src/components/RegionSelector/index.tsx +++ b/src/components/RegionSelector/index.tsx @@ -2,6 +2,7 @@ import { Listbox, Transition } from '@headlessui/react'; import { CheckIcon, ChevronDownIcon } from '@heroicons/react/solid'; import { hasFlag } from 'country-flag-icons'; import 'country-flag-icons/3x2/flags.css'; +import { sortBy } from 'lodash'; import React, { useEffect, useMemo, useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; import useSWR from 'swr'; @@ -39,32 +40,21 @@ const RegionSelector: React.FC = ({ [] ); - const sortedRegions = useMemo( - () => - regions?.sort((region1, region2) => { - const region1Name = - intl.formatDisplayName(region1.iso_3166_1, { - type: 'region', - fallback: 'none', - }) ?? region1.english_name; - const region2Name = - intl.formatDisplayName(region2.iso_3166_1, { - type: 'region', - fallback: 'none', - }) ?? region2.english_name; + const sortedRegions = useMemo(() => { + regions?.forEach((region) => { + region.name = + intl.formatDisplayName(region.iso_3166_1, { + type: 'region', + fallback: 'none', + }) ?? region.english_name; + }); - return region1Name === region2Name - ? 0 - : region1Name > region2Name - ? 1 - : -1; - }), - [intl, regions] - ); + return sortBy(regions, 'name'); + }, [intl, regions]); - const defaultRegionNameFallback = - regions?.find((region) => region.iso_3166_1 === currentSettings.region) - ?.english_name ?? currentSettings.region; + const regionName = (regionCode: string) => + sortedRegions?.find((region) => region.iso_3166_1 === regionCode)?.name ?? + regionCode; useEffect(() => { if (regions && value) { @@ -110,17 +100,11 @@ const RegionSelector: React.FC = ({ )} {selectedRegion && selectedRegion.iso_3166_1 !== 'all' - ? intl.formatDisplayName(selectedRegion.iso_3166_1, { - type: 'region', - fallback: 'none', - }) ?? selectedRegion.english_name + ? regionName(selectedRegion.iso_3166_1) : isUserSetting && selectedRegion?.iso_3166_1 !== 'all' ? intl.formatMessage(messages.regionServerDefault, { region: currentSettings.region - ? intl.formatDisplayName(currentSettings.region, { - type: 'region', - fallback: 'none', - }) ?? defaultRegionNameFallback + ? regionName(currentSettings.region) : intl.formatMessage(messages.regionDefault), }) : intl.formatMessage(messages.regionDefault)} @@ -168,13 +152,7 @@ const RegionSelector: React.FC = ({ > {intl.formatMessage(messages.regionServerDefault, { region: currentSettings.region - ? intl.formatDisplayName( - currentSettings.region, - { - type: 'region', - fallback: 'none', - } - ) ?? defaultRegionNameFallback + ? regionName(currentSettings.region) : intl.formatMessage(messages.regionDefault), })} @@ -241,10 +219,7 @@ const RegionSelector: React.FC = ({ selected ? 'font-semibold' : 'font-normal' } block truncate`} > - {intl.formatDisplayName(region.iso_3166_1, { - type: 'region', - fallback: 'none', - }) ?? region.english_name} + {regionName(region.iso_3166_1)} {selected && ( { const { data, error, revalidate } = useSWR( '/api/v1/settings/main' ); - const { data: languages, error: languagesError } = useSWR( - '/api/v1/languages' - ); + const MainSettingsSchema = Yup.object().shape({ applicationTitle: Yup.string().required( intl.formatMessage(messages.validationApplicationTitle) @@ -96,26 +94,7 @@ const SettingsMain: React.FC = () => { } }; - const sortedLanguages = useMemo( - () => - languages?.sort((lang1, lang2) => { - const lang1Name = - intl.formatDisplayName(lang1.iso_639_1, { - type: 'language', - fallback: 'none', - }) ?? lang1.english_name; - const lang2Name = - intl.formatDisplayName(lang2.iso_639_1, { - type: 'language', - fallback: 'none', - }) ?? lang2.english_name; - - return lang1Name === lang2Name ? 0 : lang1Name > lang2Name ? 1 : -1; - }), - [intl, languages] - ); - - if (!data && !error && !languages && !languagesError) { + if (!data && !error) { return ; } @@ -316,7 +295,6 @@ const SettingsMain: React.FC = () => {
diff --git a/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx b/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx index b90592ba..967c8d2e 100644 --- a/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx +++ b/src/components/UserProfile/UserSettings/UserGeneralSettings/index.tsx @@ -1,12 +1,11 @@ import axios from 'axios'; import { Field, Form, Formik } from 'formik'; import { useRouter } from 'next/router'; -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; import { useToasts } from 'react-toast-notifications'; import useSWR from 'swr'; import { UserSettingsGeneralResponse } from '../../../../../server/interfaces/api/userSettingsInterfaces'; -import { Language } from '../../../../../server/lib/settings'; import { availableLanguages, AvailableLocales, @@ -72,38 +71,11 @@ const UserGeneralSettings: React.FC = () => { ); }, [data]); - const { data: languages, error: languagesError } = useSWR( - '/api/v1/languages' - ); - - const sortedLanguages = useMemo( - () => - languages?.sort((lang1, lang2) => { - const lang1Name = - intl.formatDisplayName(lang1.iso_639_1, { - type: 'language', - fallback: 'none', - }) ?? lang1.english_name; - const lang2Name = - intl.formatDisplayName(lang2.iso_639_1, { - type: 'language', - fallback: 'none', - }) ?? lang2.english_name; - - return lang1Name === lang2Name ? 0 : lang1Name > lang2Name ? 1 : -1; - }), - [intl, languages] - ); - if (!data && !error) { return ; } - if (!languages && !languagesError) { - return ; - } - - if (!data || !languages) { + if (!data) { return ; } @@ -263,7 +235,6 @@ const UserGeneralSettings: React.FC = () => {