Use locale/get response to suggest homepage and language switch (#839)
* Use locale/get response to suggest homepage and language switch * Fix language modal condition * Fixes from review * Fixes from review * Fix gdpr * string * Fix multiple options behavior * Fix gdpr and use only one fetch * Only show if no languages set or loaded * pt-br * Fix ad * Fix homepage select * Fix zh langs
This commit is contained in:
parent
f839e0c35d
commit
712e02db16
20 changed files with 684 additions and 99 deletions
|
@ -18,6 +18,7 @@ SOCKETY_SERVER_API=wss://sockety.odysee.com/ws
|
||||||
RECSYS_ENDPOINT=https://recsys.odysee.tv/v1/lvv
|
RECSYS_ENDPOINT=https://recsys.odysee.tv/v1/lvv
|
||||||
THUMBNAIL_CDN_URL=https://thumbnails.odycdn.com/optimize/
|
THUMBNAIL_CDN_URL=https://thumbnails.odycdn.com/optimize/
|
||||||
THUMBNAIL_CARDS_CDN_URL=https://cards.odycdn.com/
|
THUMBNAIL_CARDS_CDN_URL=https://cards.odycdn.com/
|
||||||
|
LOCALE_API=https://api.odysee.com/locale/get
|
||||||
THUMBNAIL_HEIGHT=220
|
THUMBNAIL_HEIGHT=220
|
||||||
THUMBNAIL_WIDTH=390
|
THUMBNAIL_WIDTH=390
|
||||||
THUMBNAIL_QUALITY=85
|
THUMBNAIL_QUALITY=85
|
||||||
|
|
|
@ -31,6 +31,7 @@ module.name_mapper='^rewards\(.*\)$' -> '<PROJECT_ROOT>/ui/rewards\1'
|
||||||
module.name_mapper='^i18n\(.*\)$' -> '<PROJECT_ROOT>/ui/i18n\1'
|
module.name_mapper='^i18n\(.*\)$' -> '<PROJECT_ROOT>/ui/i18n\1'
|
||||||
module.name_mapper='^effects\(.*\)$' -> '<PROJECT_ROOT>/ui/effects\1'
|
module.name_mapper='^effects\(.*\)$' -> '<PROJECT_ROOT>/ui/effects\1'
|
||||||
module.name_mapper='^comments\(.*\)$' -> '<PROJECT_ROOT>/ui/comments\1'
|
module.name_mapper='^comments\(.*\)$' -> '<PROJECT_ROOT>/ui/comments\1'
|
||||||
|
module.name_mapper='^locale\(.*\)$' -> '<PROJECT_ROOT>/ui/locale\1'
|
||||||
module.name_mapper='^config\(.*\)$' -> '<PROJECT_ROOT>/config\1'
|
module.name_mapper='^config\(.*\)$' -> '<PROJECT_ROOT>/config\1'
|
||||||
module.name_mapper='^web\/component\(.*\)$' -> '<PROJECT_ROOT>/web/component\1'
|
module.name_mapper='^web\/component\(.*\)$' -> '<PROJECT_ROOT>/web/component\1'
|
||||||
module.name_mapper='^web\/effects\(.*\)$' -> '<PROJECT_ROOT>/web/effects\1'
|
module.name_mapper='^web\/effects\(.*\)$' -> '<PROJECT_ROOT>/web/effects\1'
|
||||||
|
|
|
@ -16,6 +16,7 @@ const config = {
|
||||||
SEARCH_SERVER_API_ALT: process.env.SEARCH_SERVER_API_ALT,
|
SEARCH_SERVER_API_ALT: process.env.SEARCH_SERVER_API_ALT,
|
||||||
COMMENT_SERVER_API: process.env.COMMENT_SERVER_API,
|
COMMENT_SERVER_API: process.env.COMMENT_SERVER_API,
|
||||||
SOCKETY_SERVER_API: process.env.SOCKETY_SERVER_API,
|
SOCKETY_SERVER_API: process.env.SOCKETY_SERVER_API,
|
||||||
|
LOCALE_API: process.env.LOCALE_API,
|
||||||
WELCOME_VERSION: process.env.WELCOME_VERSION,
|
WELCOME_VERSION: process.env.WELCOME_VERSION,
|
||||||
DOMAIN: process.env.DOMAIN,
|
DOMAIN: process.env.DOMAIN,
|
||||||
SHARE_DOMAIN_URL: process.env.SHARE_DOMAIN_URL,
|
SHARE_DOMAIN_URL: process.env.SHARE_DOMAIN_URL,
|
||||||
|
|
|
@ -2209,5 +2209,12 @@
|
||||||
"The minimum duration must not exceed Feb 8th, 2022.": "The minimum duration must not exceed Feb 8th, 2022.",
|
"The minimum duration must not exceed Feb 8th, 2022.": "The minimum duration must not exceed Feb 8th, 2022.",
|
||||||
"No limit": "No limit",
|
"No limit": "No limit",
|
||||||
"Search results are being filtered by language. Click here to change the setting.": "Search results are being filtered by language. Click here to change the setting.",
|
"Search results are being filtered by language. Click here to change the setting.": "Search results are being filtered by language. Click here to change the setting.",
|
||||||
|
"There are language translations available for your location! Do you want to switch from English?": "There are language translations available for your location! Do you want to switch from English?",
|
||||||
|
"A homepage and language translations are available for your location! Do you want to switch?": "A homepage and language translations are available for your location! Do you want to switch?",
|
||||||
|
"Switch Now": "Switch Now",
|
||||||
|
"Both": "Both",
|
||||||
|
"Only Language": "Only Language",
|
||||||
|
"Only Homepage": "Only Homepage",
|
||||||
|
"Choose Your Preference": "Choose Your Preference",
|
||||||
"--end--": "--end--"
|
"--end--": "--end--"
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,13 @@ import {
|
||||||
} from 'web/effects/use-degraded-performance';
|
} from 'web/effects/use-degraded-performance';
|
||||||
import LANGUAGE_MIGRATIONS from 'constants/language-migrations';
|
import LANGUAGE_MIGRATIONS from 'constants/language-migrations';
|
||||||
import { useIsMobile } from 'effects/use-screensize';
|
import { useIsMobile } from 'effects/use-screensize';
|
||||||
|
import { fetchLocaleApi } from 'locale';
|
||||||
|
import getLanguagesForCountry from 'constants/country_languages';
|
||||||
|
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||||
|
|
||||||
const FileDrop = lazyImport(() => import('component/fileDrop' /* webpackChunkName: "fileDrop" */));
|
const FileDrop = lazyImport(() => import('component/fileDrop' /* webpackChunkName: "fileDrop" */));
|
||||||
const NagContinueFirstRun = lazyImport(() => import('component/nagContinueFirstRun' /* webpackChunkName: "nagCFR" */));
|
const NagContinueFirstRun = lazyImport(() => import('component/nagContinueFirstRun' /* webpackChunkName: "nagCFR" */));
|
||||||
|
const NagLocaleSwitch = lazyImport(() => import('component/nagLocaleSwitch' /* webpackChunkName: "nagLocaleSwitch" */));
|
||||||
const OpenInAppLink = lazyImport(() => import('web/component/openInAppLink' /* webpackChunkName: "openInAppLink" */));
|
const OpenInAppLink = lazyImport(() => import('web/component/openInAppLink' /* webpackChunkName: "openInAppLink" */));
|
||||||
const NagDataCollection = lazyImport(() => import('web/component/nag-data-collection' /* webpackChunkName: "nagDC" */));
|
const NagDataCollection = lazyImport(() => import('web/component/nag-data-collection' /* webpackChunkName: "nagDC" */));
|
||||||
const NagDegradedPerformance = lazyImport(() =>
|
const NagDegradedPerformance = lazyImport(() =>
|
||||||
|
@ -132,6 +136,10 @@ function App(props: Props) {
|
||||||
const previousHasVerifiedEmail = usePrevious(hasVerifiedEmail);
|
const previousHasVerifiedEmail = usePrevious(hasVerifiedEmail);
|
||||||
const previousRewardApproved = usePrevious(isRewardApproved);
|
const previousRewardApproved = usePrevious(isRewardApproved);
|
||||||
|
|
||||||
|
const [gdprRequired, setGdprRequired] = usePersistedState('gdprRequired');
|
||||||
|
const [localeLangs, setLocaleLangs] = React.useState();
|
||||||
|
const [localeSwitchDismissed] = usePersistedState('locale-switch-dismissed', false);
|
||||||
|
|
||||||
const [showAnalyticsNag, setShowAnalyticsNag] = usePersistedState('analytics-nag', true);
|
const [showAnalyticsNag, setShowAnalyticsNag] = usePersistedState('analytics-nag', true);
|
||||||
const [lbryTvApiStatus, setLbryTvApiStatus] = useState(STATUS_OK);
|
const [lbryTvApiStatus, setLbryTvApiStatus] = useState(STATUS_OK);
|
||||||
|
|
||||||
|
@ -212,6 +220,11 @@ function App(props: Props) {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (localeLangs) {
|
||||||
|
const noLanguageSet = language === 'en' && languages.length === 1;
|
||||||
|
return <NagLocaleSwitch localeLangs={localeLangs} noLanguageSet={noLanguageSet} />;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -312,6 +325,7 @@ function App(props: Props) {
|
||||||
fetchModBlockedList();
|
fetchModBlockedList();
|
||||||
fetchModAmIList();
|
fetchModAmIList();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [hasMyChannels, hasNoChannels, hasActiveChannelClaim, setActiveChannelIfNotSet, setIncognito]);
|
}, [hasMyChannels, hasNoChannels, hasActiveChannelClaim, setActiveChannelIfNotSet, setIncognito]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -396,40 +410,42 @@ function App(props: Props) {
|
||||||
// OneTrust asks to add this
|
// OneTrust asks to add this
|
||||||
secondScript.innerHTML = 'function OptanonWrapper() { }';
|
secondScript.innerHTML = 'function OptanonWrapper() { }';
|
||||||
|
|
||||||
const getLocaleEndpoint = 'https://api.odysee.com/locale/get';
|
|
||||||
let gdprRequired;
|
|
||||||
try {
|
|
||||||
gdprRequired = localStorage.getItem('gdprRequired');
|
|
||||||
} catch (err) {
|
|
||||||
if (err) return;
|
|
||||||
}
|
|
||||||
// gdpr is known to be required, add script
|
// gdpr is known to be required, add script
|
||||||
if (gdprRequired === 'true') {
|
if (gdprRequired) {
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
document.head.appendChild(script);
|
document.head.appendChild(script);
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
document.head.appendChild(secondScript);
|
document.head.appendChild(secondScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchLocaleApi().then((response) => {
|
||||||
|
if (!localeLangs && !localeSwitchDismissed) {
|
||||||
|
const countryCode = response?.data?.country;
|
||||||
|
const langs = getLanguagesForCountry(countryCode);
|
||||||
|
|
||||||
|
const supportedLangs = [];
|
||||||
|
langs.forEach((lang) => lang !== 'en' && SUPPORTED_LANGUAGES[lang] && supportedLangs.push(lang));
|
||||||
|
|
||||||
|
if (supportedLangs.length > 0) setLocaleLangs(supportedLangs);
|
||||||
|
}
|
||||||
|
|
||||||
// haven't done a gdpr check, do it now
|
// haven't done a gdpr check, do it now
|
||||||
if (gdprRequired === null) {
|
if (gdprRequired === null || gdprRequired === undefined) {
|
||||||
(async function () {
|
const gdprRequiredBasedOnLocation = response?.data?.gdpr_required;
|
||||||
const response = await fetch(getLocaleEndpoint);
|
|
||||||
const json = await response.json();
|
|
||||||
const gdprRequiredBasedOnLocation = json.data.gdpr_required;
|
|
||||||
// note we need gdpr and load script
|
// note we need gdpr and load script
|
||||||
if (gdprRequiredBasedOnLocation) {
|
if (gdprRequiredBasedOnLocation) {
|
||||||
localStorage.setItem('gdprRequired', 'true');
|
setGdprRequired(true);
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
document.head.appendChild(script);
|
document.head.appendChild(script);
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
document.head.appendChild(secondScript);
|
document.head.appendChild(secondScript);
|
||||||
// note we don't need gdpr, save to session
|
// note we don't need gdpr, save to session
|
||||||
} else if (gdprRequiredBasedOnLocation === false) {
|
} else if (gdprRequiredBasedOnLocation === false) {
|
||||||
localStorage.setItem('gdprRequired', 'false');
|
setGdprRequired(false);
|
||||||
}
|
}
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
try {
|
try {
|
||||||
|
@ -438,9 +454,11 @@ function App(props: Props) {
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
document.head.removeChild(secondScript);
|
document.head.removeChild(secondScript);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// ready for sync syncs, however after signin when hasVerifiedEmail, that syncs too.
|
// ready for sync syncs, however after signin when hasVerifiedEmail, that syncs too.
|
||||||
|
|
|
@ -7,6 +7,8 @@ import Button from 'component/button';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
message: string | Node,
|
message: string | Node,
|
||||||
|
action?: Node,
|
||||||
|
closeTitle?: string,
|
||||||
actionText?: string,
|
actionText?: string,
|
||||||
href?: string,
|
href?: string,
|
||||||
type?: string,
|
type?: string,
|
||||||
|
@ -17,9 +19,20 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Nag(props: Props) {
|
export default function Nag(props: Props) {
|
||||||
const { message, actionText, href, onClick, onClose, type, inline, relative } = props;
|
const {
|
||||||
|
message,
|
||||||
|
action: customAction,
|
||||||
|
closeTitle,
|
||||||
|
actionText,
|
||||||
|
href,
|
||||||
|
onClick,
|
||||||
|
onClose,
|
||||||
|
type,
|
||||||
|
inline,
|
||||||
|
relative,
|
||||||
|
} = props;
|
||||||
|
|
||||||
const buttonProps = onClick ? { onClick } : { href };
|
const buttonProps = onClick ? { onClick } : href ? { href } : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -31,7 +44,10 @@ export default function Nag(props: Props) {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className="nag__message">{message}</div>
|
<div className="nag__message">{message}</div>
|
||||||
{(href || onClick) && (
|
|
||||||
|
{customAction}
|
||||||
|
|
||||||
|
{buttonProps && (
|
||||||
<Button
|
<Button
|
||||||
className={classnames('nag__button', {
|
className={classnames('nag__button', {
|
||||||
'nag__button--helpful': type === 'helpful',
|
'nag__button--helpful': type === 'helpful',
|
||||||
|
@ -42,12 +58,14 @@ export default function Nag(props: Props) {
|
||||||
{actionText}
|
{actionText}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{onClose && (
|
{onClose && (
|
||||||
<Button
|
<Button
|
||||||
className={classnames('nag__button nag__close', {
|
className={classnames('nag__button nag__close', {
|
||||||
'nag__button--helpful': type === 'helpful',
|
'nag__button--helpful': type === 'helpful',
|
||||||
'nag__button--error': type === 'error',
|
'nag__button--error': type === 'error',
|
||||||
})}
|
})}
|
||||||
|
title={closeTitle}
|
||||||
icon={ICONS.REMOVE}
|
icon={ICONS.REMOVE}
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
import homepages from 'homepages';
|
import homepages from 'homepages';
|
||||||
import LANGUAGES from 'constants/languages';
|
import { getLanguageEngName } from 'constants/languages';
|
||||||
import { FormField } from 'component/common/form';
|
import { FormField } from 'component/common/form';
|
||||||
import { getDefaultHomepageKey } from 'util/default-languages';
|
import { getDefaultHomepageKey } from 'util/default-languages';
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ function SelectHomepage(props: Props) {
|
||||||
>
|
>
|
||||||
{Object.keys(homepages).map((hp) => (
|
{Object.keys(homepages).map((hp) => (
|
||||||
<option key={'hp' + hp} value={hp}>
|
<option key={'hp' + hp} value={hp}>
|
||||||
{`${LANGUAGES[hp][1]}`}
|
{`${getLanguageEngName(hp)}`}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
12
ui/component/nagLocaleSwitch/index.js
Normal file
12
ui/component/nagLocaleSwitch/index.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doSetLanguage, doSetHomepage } from 'redux/actions/settings';
|
||||||
|
import { doOpenModal } from 'redux/actions/app';
|
||||||
|
import NagLocaleSwitch from './view';
|
||||||
|
|
||||||
|
const perform = {
|
||||||
|
doSetLanguage,
|
||||||
|
doSetHomepage,
|
||||||
|
doOpenModal,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(null, perform)(NagLocaleSwitch);
|
194
ui/component/nagLocaleSwitch/view.jsx
Normal file
194
ui/component/nagLocaleSwitch/view.jsx
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
// @flow
|
||||||
|
import { FormField } from 'component/common/form';
|
||||||
|
import * as MODALS from 'constants/modal_types';
|
||||||
|
import HOMEPAGE_LANGUAGES, { getHomepageLanguage } from 'constants/homepage_languages';
|
||||||
|
import Nag from 'component/common/nag';
|
||||||
|
import React from 'react';
|
||||||
|
import usePersistedState from 'effects/use-persisted-state';
|
||||||
|
import { getLanguageEngName, getLanguageName } from 'constants/languages';
|
||||||
|
|
||||||
|
const LOCALE_OPTIONS = {
|
||||||
|
BOTH: 'both',
|
||||||
|
LANG: 'lang',
|
||||||
|
HOME: 'home',
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
localeLangs: Array<string>,
|
||||||
|
noLanguageSet: boolean,
|
||||||
|
// redux
|
||||||
|
doSetLanguage: (string) => void,
|
||||||
|
doSetHomepage: (string) => void,
|
||||||
|
doOpenModal: (string, {}) => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function NagLocaleSwitch(props: Props) {
|
||||||
|
const { localeLangs, noLanguageSet, doSetLanguage, doSetHomepage, doOpenModal } = props;
|
||||||
|
|
||||||
|
const [switchOption, setSwitchOption] = React.useState(LOCALE_OPTIONS.BOTH);
|
||||||
|
const [localeSwitchDismissed, setLocaleSwitchDismissed] = usePersistedState('locale-switch-dismissed', false);
|
||||||
|
|
||||||
|
const hasHomepageForLang = localeLangs.some((lang) => getHomepageLanguage(lang));
|
||||||
|
const message = __(
|
||||||
|
// If no homepage, only suggest language switch
|
||||||
|
!hasHomepageForLang
|
||||||
|
? 'There are language translations available for your location! Do you want to switch from English?'
|
||||||
|
: 'A homepage and language translations are available for your location! Do you want to switch?'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (localeSwitchDismissed || (!noLanguageSet && !hasHomepageForLang)) return null;
|
||||||
|
|
||||||
|
function dismissNag() {
|
||||||
|
setLocaleSwitchDismissed(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSwitch() {
|
||||||
|
const homepages = [];
|
||||||
|
localeLangs.forEach((lang) => {
|
||||||
|
const homepageLanguage = getHomepageLanguage(lang);
|
||||||
|
|
||||||
|
if (homepageLanguage && !homepages.includes(homepageLanguage)) {
|
||||||
|
homepages.push(homepageLanguage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const homeSwitchSelected = switchOption === LOCALE_OPTIONS.BOTH || switchOption === LOCALE_OPTIONS.HOME;
|
||||||
|
const multipleHomepages = homeSwitchSelected && homepages.length > 1;
|
||||||
|
const langSwitchSelected = switchOption === LOCALE_OPTIONS.BOTH || switchOption === LOCALE_OPTIONS.LANG;
|
||||||
|
const multipleLangs = langSwitchSelected && localeLangs.length > 1;
|
||||||
|
|
||||||
|
// if language or homepage has more than 1 option, modal for selection
|
||||||
|
// if some has only one option, still show the selection for confirmation of what's being switched
|
||||||
|
if (multipleHomepages || multipleLangs) {
|
||||||
|
doOpenModal(MODALS.CONFIRM, {
|
||||||
|
title: __('Choose Your Preference'),
|
||||||
|
body: (
|
||||||
|
<>
|
||||||
|
{langSwitchSelected && <LanguageSelect langs={localeLangs} />}
|
||||||
|
{homeSwitchSelected && <HomepageSelect homepages={homepages} />}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
onConfirm: (closeModal) => {
|
||||||
|
if (langSwitchSelected) {
|
||||||
|
// $FlowFixMe
|
||||||
|
const selection = document.querySelector('.language-switch.checked').id.split(' ')[1];
|
||||||
|
doSetLanguage(selection);
|
||||||
|
}
|
||||||
|
if (homeSwitchSelected) {
|
||||||
|
// $FlowFixMe
|
||||||
|
const selection = document.querySelector('.homepage-switch.checked').id.split(' ')[1];
|
||||||
|
let homepageSelection = '';
|
||||||
|
Object.values(HOMEPAGE_LANGUAGES).some((lang, index) => {
|
||||||
|
if (lang === selection) {
|
||||||
|
homepageSelection = Object.keys(HOMEPAGE_LANGUAGES)[index];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
doSetHomepage(homepageSelection);
|
||||||
|
}
|
||||||
|
dismissNag();
|
||||||
|
closeModal();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// if selected switch has only one option, just make the switch
|
||||||
|
} else {
|
||||||
|
const onlyLanguage = localeLangs[0];
|
||||||
|
|
||||||
|
if (langSwitchSelected) doSetLanguage(onlyLanguage);
|
||||||
|
if (homeSwitchSelected) doSetHomepage(onlyLanguage);
|
||||||
|
|
||||||
|
dismissNag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Nag
|
||||||
|
message={message}
|
||||||
|
type="helpful"
|
||||||
|
action={
|
||||||
|
// Menu field only needed if there is a homepage + language to choose, otherwise
|
||||||
|
// there is only 1 option to switch, so use the nag button
|
||||||
|
hasHomepageForLang && (
|
||||||
|
<FormField
|
||||||
|
className="nag__select"
|
||||||
|
type="select"
|
||||||
|
value={switchOption}
|
||||||
|
onChange={(e) => setSwitchOption(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value={LOCALE_OPTIONS.BOTH}>{__('Both')}</option>
|
||||||
|
<option value={LOCALE_OPTIONS.LANG}>{__('Only Language')}</option>
|
||||||
|
<option value={LOCALE_OPTIONS.HOME}>{__('Only Homepage')}</option>
|
||||||
|
</FormField>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
actionText={__('Switch Now')}
|
||||||
|
onClick={handleSwitch}
|
||||||
|
onClose={dismissNag}
|
||||||
|
closeTitle={__('Dismiss')}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
type HomepageProps = {
|
||||||
|
homepages: Array<string>,
|
||||||
|
};
|
||||||
|
|
||||||
|
const HomepageSelect = (props: HomepageProps) => {
|
||||||
|
const { homepages } = props;
|
||||||
|
|
||||||
|
const [selection, setSelection] = React.useState(homepages[0]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>{__('Homepage')}</h1>
|
||||||
|
|
||||||
|
{homepages.map((homepage) => (
|
||||||
|
<FormField
|
||||||
|
type="radio"
|
||||||
|
className={`homepage-switch ${selection === homepage ? 'checked' : ''}`}
|
||||||
|
name={`homepage_switch ${homepage}`}
|
||||||
|
key={homepage}
|
||||||
|
label={homepage}
|
||||||
|
checked={selection === homepage}
|
||||||
|
onChange={() => setSelection(homepage)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type LangProps = {
|
||||||
|
langs: Array<string>,
|
||||||
|
};
|
||||||
|
|
||||||
|
const LanguageSelect = (props: LangProps) => {
|
||||||
|
const { langs } = props;
|
||||||
|
|
||||||
|
const [selection, setSelection] = React.useState(langs[0]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>{__('Language')}</h1>
|
||||||
|
|
||||||
|
{langs.map((lang) => {
|
||||||
|
const language = getLanguageEngName(lang);
|
||||||
|
const languageName = getLanguageName(lang);
|
||||||
|
const label = language === languageName ? language : `${language} - ${languageName}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormField
|
||||||
|
type="radio"
|
||||||
|
className={`language-switch ${selection === lang ? 'checked' : ''}`}
|
||||||
|
name={`language_switch ${lang}`}
|
||||||
|
key={lang}
|
||||||
|
label={label}
|
||||||
|
checked={selection === lang}
|
||||||
|
onChange={() => setSelection(lang)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
279
ui/constants/country_languages.js
Normal file
279
ui/constants/country_languages.js
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
/*
|
||||||
|
* Upstream source: https://wiki.openstreetmap.org/wiki/Nominatim/Country_Codes
|
||||||
|
*/
|
||||||
|
|
||||||
|
const COUNTRY_LANGUAGES = {
|
||||||
|
ad: 'ca',
|
||||||
|
ae: 'ar',
|
||||||
|
af: 'fa,ps',
|
||||||
|
ag: 'en',
|
||||||
|
ai: 'en',
|
||||||
|
al: 'sq',
|
||||||
|
am: 'hy',
|
||||||
|
ao: 'pt',
|
||||||
|
aq: '',
|
||||||
|
ar: 'es',
|
||||||
|
as: 'en,sm',
|
||||||
|
at: 'de',
|
||||||
|
au: 'en',
|
||||||
|
aw: 'nl,pap',
|
||||||
|
ax: 'sv',
|
||||||
|
az: 'az',
|
||||||
|
ba: 'bs,hr,sr',
|
||||||
|
bb: 'en',
|
||||||
|
bd: 'bn',
|
||||||
|
be: 'nl,fr,de',
|
||||||
|
bf: 'fr',
|
||||||
|
bg: 'bg',
|
||||||
|
bh: 'ar',
|
||||||
|
bi: 'fr',
|
||||||
|
bj: 'fr',
|
||||||
|
bl: 'fr',
|
||||||
|
bm: 'en',
|
||||||
|
bn: 'ms',
|
||||||
|
bo: 'es,qu,ay',
|
||||||
|
bq: 'nl',
|
||||||
|
br: 'pt',
|
||||||
|
bs: 'en',
|
||||||
|
bt: 'dz',
|
||||||
|
bv: 'no',
|
||||||
|
bw: 'en,tn',
|
||||||
|
by: 'be,ru',
|
||||||
|
bz: 'en',
|
||||||
|
ca: 'en,fr',
|
||||||
|
cc: 'en',
|
||||||
|
cd: 'fr',
|
||||||
|
cf: 'fr',
|
||||||
|
cg: 'fr',
|
||||||
|
ch: 'de,fr,it,rm',
|
||||||
|
ci: 'fr',
|
||||||
|
ck: 'en,rar',
|
||||||
|
cl: 'es',
|
||||||
|
cm: 'fr,en',
|
||||||
|
cn: 'zh',
|
||||||
|
co: 'es',
|
||||||
|
cr: 'es',
|
||||||
|
cu: 'es',
|
||||||
|
cv: 'pt',
|
||||||
|
cw: 'nl,en',
|
||||||
|
cx: 'en',
|
||||||
|
cy: 'el,tr',
|
||||||
|
cz: 'cs',
|
||||||
|
de: 'de',
|
||||||
|
dj: 'fr,ar',
|
||||||
|
dk: 'da',
|
||||||
|
dm: 'en',
|
||||||
|
do: 'es',
|
||||||
|
dz: 'ar,ber',
|
||||||
|
ec: 'es',
|
||||||
|
ee: 'et',
|
||||||
|
eg: 'ar',
|
||||||
|
eh: 'ar,es,fr',
|
||||||
|
er: 'ti,ar,en',
|
||||||
|
es: 'es',
|
||||||
|
et: 'am,om',
|
||||||
|
fi: 'fi,sv,se',
|
||||||
|
fj: 'en',
|
||||||
|
fk: 'en',
|
||||||
|
fm: 'en',
|
||||||
|
fo: 'fo',
|
||||||
|
fr: 'fr',
|
||||||
|
ga: 'fr',
|
||||||
|
gb: 'en',
|
||||||
|
gd: 'en',
|
||||||
|
ge: 'ka',
|
||||||
|
gf: 'fr',
|
||||||
|
gg: 'en',
|
||||||
|
gh: 'en',
|
||||||
|
gi: 'en',
|
||||||
|
gl: 'kl,da',
|
||||||
|
gm: 'en',
|
||||||
|
gn: 'fr',
|
||||||
|
gp: 'fr',
|
||||||
|
gq: 'es',
|
||||||
|
gr: 'el',
|
||||||
|
gs: 'en',
|
||||||
|
gt: 'es',
|
||||||
|
gu: 'en,ch',
|
||||||
|
gw: 'pt',
|
||||||
|
gy: 'en',
|
||||||
|
hk: 'zh,en',
|
||||||
|
hm: 'en',
|
||||||
|
hn: 'es',
|
||||||
|
hr: 'hr',
|
||||||
|
ht: 'fr,ht',
|
||||||
|
hu: 'hu',
|
||||||
|
id: 'id',
|
||||||
|
ie: 'en,ga',
|
||||||
|
il: 'he',
|
||||||
|
im: 'en',
|
||||||
|
in: 'hi,en',
|
||||||
|
io: 'en',
|
||||||
|
iq: 'ar,ku',
|
||||||
|
ir: 'fa',
|
||||||
|
is: 'is',
|
||||||
|
it: 'it',
|
||||||
|
je: 'en',
|
||||||
|
jm: 'en',
|
||||||
|
jo: 'ar',
|
||||||
|
jp: 'ja',
|
||||||
|
ke: 'sw,en',
|
||||||
|
kg: 'ky,ru',
|
||||||
|
kh: 'km',
|
||||||
|
ki: 'en',
|
||||||
|
km: 'bnt,ar,fr',
|
||||||
|
kn: 'en',
|
||||||
|
kp: 'ko',
|
||||||
|
kr: 'ko',
|
||||||
|
kw: 'ar',
|
||||||
|
ky: 'en',
|
||||||
|
kz: 'kk,ru',
|
||||||
|
la: 'lo',
|
||||||
|
lb: 'ar,fr',
|
||||||
|
lc: 'en',
|
||||||
|
li: 'de',
|
||||||
|
lk: 'si,ta',
|
||||||
|
lr: 'en',
|
||||||
|
ls: 'en,st',
|
||||||
|
lt: 'lt',
|
||||||
|
lu: 'lb,fr,de',
|
||||||
|
lv: 'lv',
|
||||||
|
ly: 'ar,ber',
|
||||||
|
ma: 'ar,ber',
|
||||||
|
mc: 'fr',
|
||||||
|
md: 'ru,uk,ro',
|
||||||
|
me: 'sr,sh',
|
||||||
|
mf: 'fr',
|
||||||
|
mg: 'mg,fr',
|
||||||
|
mh: 'en,mh',
|
||||||
|
mk: 'mk',
|
||||||
|
ml: 'fr',
|
||||||
|
mm: 'my',
|
||||||
|
mn: 'mn',
|
||||||
|
mo: 'zh,pt',
|
||||||
|
mp: 'ch',
|
||||||
|
mq: 'fr',
|
||||||
|
mr: 'ar,fr',
|
||||||
|
ms: 'en',
|
||||||
|
mt: 'mt,en',
|
||||||
|
mu: 'mfe,fr,en',
|
||||||
|
mv: 'dv',
|
||||||
|
mw: 'en,ny',
|
||||||
|
mx: 'es',
|
||||||
|
my: 'en,ms,zh,ta',
|
||||||
|
mz: 'pt',
|
||||||
|
na: 'en,sf,de',
|
||||||
|
nc: 'fr',
|
||||||
|
ne: 'fr',
|
||||||
|
nf: 'en,pih',
|
||||||
|
ng: 'en',
|
||||||
|
ni: 'es',
|
||||||
|
nl: 'nl',
|
||||||
|
no: 'nb,nn,no',
|
||||||
|
np: 'ne',
|
||||||
|
nr: 'na,en',
|
||||||
|
nu: 'niu,en',
|
||||||
|
nz: 'mi,en',
|
||||||
|
om: 'ar',
|
||||||
|
pa: 'es',
|
||||||
|
pe: 'es',
|
||||||
|
pf: 'fr',
|
||||||
|
pg: 'en,tpi,ho',
|
||||||
|
ph: 'en,tl',
|
||||||
|
pk: 'en,ur',
|
||||||
|
pl: 'pl',
|
||||||
|
pm: 'fr',
|
||||||
|
pn: 'en,pih',
|
||||||
|
pr: 'es,en',
|
||||||
|
ps: 'ar,he',
|
||||||
|
pt: 'pt',
|
||||||
|
pw: 'en,pau,ja,sov,tox',
|
||||||
|
py: 'es,gn',
|
||||||
|
qa: 'ar',
|
||||||
|
re: 'fr',
|
||||||
|
ro: 'ro',
|
||||||
|
rs: 'sr',
|
||||||
|
ru: 'ru',
|
||||||
|
rw: 'rw,fr,en',
|
||||||
|
sa: 'ar',
|
||||||
|
sb: 'en',
|
||||||
|
sc: 'fr,en,crs',
|
||||||
|
sd: 'ar,en',
|
||||||
|
se: 'sv',
|
||||||
|
sg: 'en,ms,zh,ta',
|
||||||
|
sh: 'en',
|
||||||
|
si: 'sl',
|
||||||
|
sj: 'no',
|
||||||
|
sk: 'sk',
|
||||||
|
sl: 'en',
|
||||||
|
sm: 'it',
|
||||||
|
sn: 'fr',
|
||||||
|
so: 'so,ar',
|
||||||
|
sr: 'nl',
|
||||||
|
st: 'pt',
|
||||||
|
ss: 'en',
|
||||||
|
sv: 'es',
|
||||||
|
sx: 'nl,en',
|
||||||
|
sy: 'ar',
|
||||||
|
sz: 'en,ss',
|
||||||
|
tc: 'en',
|
||||||
|
td: 'fr,ar',
|
||||||
|
tf: 'fr',
|
||||||
|
tg: 'fr',
|
||||||
|
th: 'th',
|
||||||
|
tj: 'tg,ru',
|
||||||
|
tk: 'tkl,en,sm',
|
||||||
|
tl: 'pt,tet',
|
||||||
|
tm: 'tk',
|
||||||
|
tn: 'ar',
|
||||||
|
to: 'en',
|
||||||
|
tr: 'tr',
|
||||||
|
tt: 'en',
|
||||||
|
tv: 'en',
|
||||||
|
tw: 'zh',
|
||||||
|
tz: 'sw,en',
|
||||||
|
ua: 'uk',
|
||||||
|
ug: 'en,sw',
|
||||||
|
um: 'en',
|
||||||
|
us: 'en',
|
||||||
|
uy: 'es',
|
||||||
|
uz: 'uz,kaa',
|
||||||
|
va: 'it',
|
||||||
|
vc: 'en',
|
||||||
|
ve: 'es',
|
||||||
|
vg: 'en',
|
||||||
|
vi: 'en',
|
||||||
|
vn: 'vi',
|
||||||
|
vu: 'bi,en,fr',
|
||||||
|
wf: 'fr',
|
||||||
|
ws: 'sm,en',
|
||||||
|
ye: 'ar',
|
||||||
|
yt: 'fr',
|
||||||
|
za: 'af,zu,xh',
|
||||||
|
zm: 'en',
|
||||||
|
zw: 'en,sn,nd',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function getLanguagesForCountry(countryCode) {
|
||||||
|
const country = countryCode.toLowerCase();
|
||||||
|
const countryLanguages = COUNTRY_LANGUAGES[country];
|
||||||
|
|
||||||
|
if (!countryLanguages || countryLanguages.length === 0) return null;
|
||||||
|
|
||||||
|
const languages = countryLanguages.split(',');
|
||||||
|
|
||||||
|
// ----overrides----
|
||||||
|
if (country === 'br') return ['pt-BR'];
|
||||||
|
|
||||||
|
const zhCountries = ['cn', 'hk', 'tw'];
|
||||||
|
const zhLangs = ['zh-Hans', 'zh-Hant'];
|
||||||
|
|
||||||
|
if (zhCountries.includes(country)) return zhLangs;
|
||||||
|
if (languages.includes('zh')) {
|
||||||
|
languages.filter((lang) => lang === 'zh');
|
||||||
|
languages.push(...zhLangs);
|
||||||
|
}
|
||||||
|
// -----------------
|
||||||
|
|
||||||
|
return languages;
|
||||||
|
}
|
21
ui/constants/homepage_languages.js
Normal file
21
ui/constants/homepage_languages.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { getLanguageEngName } from 'constants/languages';
|
||||||
|
|
||||||
|
const HOMEPAGE_LANGUAGES = {
|
||||||
|
en: getLanguageEngName('en'),
|
||||||
|
fr: getLanguageEngName('fr'),
|
||||||
|
es: getLanguageEngName('es'),
|
||||||
|
de: getLanguageEngName('de'),
|
||||||
|
zh: getLanguageEngName('zh'),
|
||||||
|
ru: getLanguageEngName('ru'),
|
||||||
|
'pt-BR': getLanguageEngName('pt-BR'),
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getHomepageLanguage(code) {
|
||||||
|
// -----override-----
|
||||||
|
if (code === 'zh-Hans' || code === 'zh-Hant') return HOMEPAGE_LANGUAGES.zh;
|
||||||
|
// ------------------
|
||||||
|
|
||||||
|
return HOMEPAGE_LANGUAGES[code] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HOMEPAGE_LANGUAGES;
|
|
@ -187,4 +187,12 @@ const LANGUAGES = {
|
||||||
zu: ['Zulu', 'isiZulu'],
|
zu: ['Zulu', 'isiZulu'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getLanguageEngName(code) {
|
||||||
|
return LANGUAGES[code][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLanguageName(code) {
|
||||||
|
return LANGUAGES[code][1];
|
||||||
|
}
|
||||||
|
|
||||||
export default LANGUAGES;
|
export default LANGUAGES;
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import LANGUAGES from './languages';
|
import { getLanguageName } from './languages';
|
||||||
|
|
||||||
const SEARCHABLE_LANGUAGES = {
|
const SEARCHABLE_LANGUAGES = {
|
||||||
en: LANGUAGES.en[1],
|
en: getLanguageName('en'),
|
||||||
hr: LANGUAGES.hr[1],
|
hr: getLanguageName('hr'),
|
||||||
nl: LANGUAGES.nl[1],
|
nl: getLanguageName('nl'),
|
||||||
fr: LANGUAGES.fr[1],
|
fr: getLanguageName('fr'),
|
||||||
de: LANGUAGES.de[1],
|
de: getLanguageName('de'),
|
||||||
it: LANGUAGES.it[1],
|
it: getLanguageName('it'),
|
||||||
pl: LANGUAGES.pl[1],
|
pl: getLanguageName('pl'),
|
||||||
pt: LANGUAGES.pt[1],
|
pt: getLanguageName('pt'),
|
||||||
ru: LANGUAGES.ru[1],
|
ru: getLanguageName('ru'),
|
||||||
es: LANGUAGES.es[1],
|
es: getLanguageName('es'),
|
||||||
tr: LANGUAGES.tr[1],
|
tr: getLanguageName('tr'),
|
||||||
cs: LANGUAGES.cs[1],
|
cs: getLanguageName('cs'),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Properties: language code (e.g. 'ja')
|
// Properties: language code (e.g. 'ja')
|
||||||
|
|
|
@ -1,47 +1,48 @@
|
||||||
import LANGUAGES from './languages';
|
import { getLanguageName } from './languages';
|
||||||
|
|
||||||
// supported_browser_languages
|
// supported_browser_languages
|
||||||
const SUPPORTED_LANGUAGES = {
|
const SUPPORTED_LANGUAGES = {
|
||||||
af: LANGUAGES.af[1],
|
af: getLanguageName('af'),
|
||||||
en: LANGUAGES.en[1],
|
en: getLanguageName('en'),
|
||||||
da: LANGUAGES.da[1],
|
da: getLanguageName('da'),
|
||||||
'zh-Hans': LANGUAGES['zh-Hans'][1],
|
'zh-Hans': getLanguageName('zh-Hans'),
|
||||||
'zh-Hant': LANGUAGES['zh-Hant'][1],
|
'zh-Hant': getLanguageName('zh-Hant'),
|
||||||
hr: LANGUAGES.hr[1],
|
hr: getLanguageName('hr'),
|
||||||
nl: LANGUAGES.nl[1],
|
nl: getLanguageName('nl'),
|
||||||
no: LANGUAGES.no[1],
|
no: getLanguageName('no'),
|
||||||
fi: LANGUAGES.fi[1],
|
fi: getLanguageName('fi'),
|
||||||
fr: LANGUAGES.fr[1],
|
fr: getLanguageName('fr'),
|
||||||
de: LANGUAGES.de[1],
|
de: getLanguageName('de'),
|
||||||
gu: LANGUAGES.gu[1],
|
gu: getLanguageName('gu'),
|
||||||
hi: LANGUAGES.hi[1],
|
hi: getLanguageName('hi'),
|
||||||
hu: LANGUAGES.hu[1],
|
hu: getLanguageName('hu'),
|
||||||
id: LANGUAGES.id[1],
|
id: getLanguageName('id'),
|
||||||
ja: LANGUAGES.ja[1],
|
ja: getLanguageName('ja'),
|
||||||
jv: LANGUAGES.jv[1],
|
jv: getLanguageName('jv'),
|
||||||
it: LANGUAGES.it[1],
|
it: getLanguageName('it'),
|
||||||
ms: LANGUAGES.ms[1],
|
ms: getLanguageName('ms'),
|
||||||
ml: LANGUAGES.ml[1],
|
ml: getLanguageName('ml'),
|
||||||
mr: LANGUAGES.mr[1],
|
mr: getLanguageName('mr'),
|
||||||
pa: LANGUAGES.pa[1],
|
pa: getLanguageName('pa'),
|
||||||
pl: LANGUAGES.pl[1],
|
pl: getLanguageName('pl'),
|
||||||
pt: LANGUAGES.pt[1],
|
pt: getLanguageName('pt'),
|
||||||
'pt-BR': LANGUAGES['pt-BR'][1],
|
'pt-BR': getLanguageName('pt-BR'),
|
||||||
ro: LANGUAGES.ro[1],
|
ro: getLanguageName('ro'),
|
||||||
ru: LANGUAGES.ru[1],
|
ru: getLanguageName('ru'),
|
||||||
sr: LANGUAGES.sr[1],
|
sr: getLanguageName('sr'),
|
||||||
sk: LANGUAGES.sk[1],
|
sk: getLanguageName('sk'),
|
||||||
th: LANGUAGES.th[1],
|
th: getLanguageName('th'),
|
||||||
ur: LANGUAGES.ur[1],
|
ur: getLanguageName('ur'),
|
||||||
ca: LANGUAGES.ca[1],
|
ca: getLanguageName('ca'),
|
||||||
es: LANGUAGES.es[1],
|
es: getLanguageName('es'),
|
||||||
sv: LANGUAGES.sv[1],
|
sv: getLanguageName('sv'),
|
||||||
tl: LANGUAGES.tl[1],
|
tl: getLanguageName('tl'),
|
||||||
tr: LANGUAGES.tr[1],
|
tr: getLanguageName('tr'),
|
||||||
cs: LANGUAGES.cs[1],
|
cs: getLanguageName('cs'),
|
||||||
kn: LANGUAGES.kn[1],
|
kn: getLanguageName('kn'),
|
||||||
uk: LANGUAGES.uk[1],
|
uk: getLanguageName('uk'),
|
||||||
vi: LANGUAGES.vi[1],
|
vi: getLanguageName('vi'),
|
||||||
ar: LANGUAGES.ar[1],
|
ar: getLanguageName('ar'),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Properties: language code (e.g. 'ja')
|
// Properties: language code (e.g. 'ja')
|
||||||
|
|
6
ui/locale.js
Normal file
6
ui/locale.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// @flow
|
||||||
|
import { LOCALE_API } from 'config';
|
||||||
|
|
||||||
|
export async function fetchLocaleApi() {
|
||||||
|
return fetch(LOCALE_API).then((res) => res.json());
|
||||||
|
}
|
|
@ -1,10 +1,9 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doHideModal } from 'redux/actions/app';
|
import { doHideModal } from 'redux/actions/app';
|
||||||
|
|
||||||
import ModalConfirm from './view';
|
import ModalConfirm from './view';
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = {
|
||||||
doHideModal: () => dispatch(doHideModal()),
|
doHideModal,
|
||||||
});
|
};
|
||||||
|
|
||||||
export default connect(null, perform)(ModalConfirm);
|
export default connect(null, perform)(ModalConfirm);
|
||||||
|
|
|
@ -12,14 +12,15 @@ type Props = {
|
||||||
body?: string | Node,
|
body?: string | Node,
|
||||||
labelOk?: string,
|
labelOk?: string,
|
||||||
labelCancel?: string,
|
labelCancel?: string,
|
||||||
onConfirm: (closeModal: () => void, setIsBusy: (boolean) => void) => void,
|
|
||||||
hideCancel?: boolean,
|
hideCancel?: boolean,
|
||||||
|
onConfirm: (closeModal: () => void, setIsBusy: (boolean) => void) => void,
|
||||||
// --- perform ---
|
// --- perform ---
|
||||||
doHideModal: () => void,
|
doHideModal: () => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ModalConfirm(props: Props) {
|
export default function ModalConfirm(props: Props) {
|
||||||
const { title, subtitle, body, labelOk, labelCancel, onConfirm, hideCancel, doHideModal } = props;
|
const { title, subtitle, body, labelOk, labelCancel, hideCancel, onConfirm, doHideModal } = props;
|
||||||
|
|
||||||
const [isBusy, setIsBusy] = React.useState(false);
|
const [isBusy, setIsBusy] = React.useState(false);
|
||||||
|
|
||||||
function handleOnClick() {
|
function handleOnClick() {
|
||||||
|
@ -28,14 +29,6 @@ export default function ModalConfirm(props: Props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOkLabel() {
|
|
||||||
return isBusy ? <Spinner type="small" /> : labelOk || __('OK');
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCancelLabel() {
|
|
||||||
return labelCancel || __('Cancel');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen type="card" onAborted={doHideModal}>
|
<Modal isOpen type="card" onAborted={doHideModal}>
|
||||||
<Card
|
<Card
|
||||||
|
@ -43,12 +36,18 @@ export default function ModalConfirm(props: Props) {
|
||||||
subtitle={subtitle}
|
subtitle={subtitle}
|
||||||
body={body}
|
body={body}
|
||||||
actions={
|
actions={
|
||||||
<>
|
|
||||||
<div className="section__actions">
|
<div className="section__actions">
|
||||||
<Button button="primary" label={getOkLabel()} disabled={isBusy} onClick={handleOnClick} />
|
<Button
|
||||||
{!hideCancel && <Button button="link" label={getCancelLabel()} disabled={isBusy} onClick={doHideModal} />}
|
button="primary"
|
||||||
|
label={isBusy ? <Spinner type="small" /> : labelOk || __('OK')}
|
||||||
|
disabled={isBusy}
|
||||||
|
onClick={handleOnClick}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{!hideCancel && (
|
||||||
|
<Button button="link" label={labelCancel || __('Cancel')} disabled={isBusy} onClick={doHideModal} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -176,7 +176,9 @@ function DiscoverPage(props: Props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (isAuthenticated || !SHOW_ADS || window.location.pathname === `/$/${PAGES.WILD_WEST}`) {
|
const hasAdOnPage = document.querySelector('.homepageAdContainer');
|
||||||
|
|
||||||
|
if (hasAdOnPage || isAuthenticated || !SHOW_ADS || window.location.pathname === `/$/${PAGES.WILD_WEST}`) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
injectAd();
|
injectAd();
|
||||||
|
|
|
@ -109,6 +109,11 @@
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
margin-top: var(--spacing-s);
|
margin-top: var(--spacing-s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.radio,
|
||||||
|
.radio + h1 {
|
||||||
|
margin-top: var(--spacing-s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal--card-internal {
|
.modal--card-internal {
|
||||||
|
|
|
@ -112,3 +112,16 @@ $nag-error-z-index: 999;
|
||||||
stroke-width: 4px;
|
stroke-width: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nag__select {
|
||||||
|
display: inline;
|
||||||
|
color: var(--color-text);
|
||||||
|
|
||||||
|
select {
|
||||||
|
width: unset;
|
||||||
|
min-width: 10rem;
|
||||||
|
padding-right: unset;
|
||||||
|
margin: 0px var(--spacing-s);
|
||||||
|
height: var(--height-button-mobile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue