diff --git a/src/components/AddShortcut.js b/src/components/AddShortcut.js index 070eecef..aff5b4b7 100644 --- a/src/components/AddShortcut.js +++ b/src/components/AddShortcut.js @@ -50,6 +50,14 @@ const addProtocolToURLIfNeeded = (url) => { return url } +const isValidUrl = (urlString) => { + try { + return Boolean(new URL(urlString)) + } catch (e) { + return false + } +} + const AddShortcut = ({ onCancel, onSave, @@ -59,6 +67,8 @@ const AddShortcut = ({ }) => { const [name, setName] = useState(existingName) const [url, setUrl] = useState(existingUrl) + const [nameError, setNameError] = useState(null) + const [urlError, setUrlError] = useState(null) useEffect(() => setName(existingName), [existingName]) useEffect(() => setUrl(existingUrl), [existingUrl]) const classes = useStyles() @@ -67,17 +77,49 @@ const AddShortcut = ({ setUrl(existingUrl) onCancel() } + const validateName = (newName) => { + let newNameError + if (newName.length === 0) { + newNameError = 'Shortcut name cannot be empty.' + } else { + newNameError = null + } + setNameError(newNameError) + return newNameError + } + const validateUrl = (newUrl) => { + let newUrlError + if (newUrl.length === 0) { + newUrlError = 'URL cannot be empty.' + } else if (!isValidUrl(addProtocolToURLIfNeeded(newUrl))) { + newUrlError = 'URL is not valid.' + } else { + newUrlError = null + } + setUrlError(newUrlError) + return newUrlError + } + const validateForm = () => { + const newNameError = validateName(name) + const newUrlError = validateUrl(url) + return newNameError || newUrlError + } const onSaveClick = () => { const newUrl = addProtocolToURLIfNeeded(url) + if (validateForm()) { + return + } onSave(existingId, name, newUrl) setName(name) setUrl(newUrl) } const changeName = (e) => { setName(e.target.value) + validateName(e.target.value) } const changeUrl = (e) => { setUrl(e.target.value) + validateUrl(e.target.value) } return ( @@ -130,8 +172,8 @@ const AddShortcut = ({ onClick={onSaveClick} className={classes.yesButton} variant="contained" - disabled={name.length === 0 || url.length === 0} disableElevation + disabled={!!(nameError || urlError)} > Save diff --git a/src/components/FrontpageShortcutList.js b/src/components/FrontpageShortcutList.js index 7d7ed935..ce327f7f 100644 --- a/src/components/FrontpageShortcutList.js +++ b/src/components/FrontpageShortcutList.js @@ -36,6 +36,7 @@ const useStyles = makeStyles((theme) => ({ flexDirection: 'row', maxWidth: '550px', flexWrap: 'wrap', + zIndex: 1.4e3, }, addCircle: { marginTop: '24px', @@ -61,6 +62,7 @@ const useStyles = makeStyles((theme) => ({ }, addShortcutWrapper: { width: '400px', + position: 'relative', }, })) const FrontpageShortcutList = ({ openHandler, user }) => { diff --git a/src/pages/account.js b/src/pages/account.js index b883ec35..e61e6fcf 100644 --- a/src/pages/account.js +++ b/src/pages/account.js @@ -376,7 +376,7 @@ const Account = ({ data: fallbackData }) => { {localStorageFeaturesManager.getFeatureValue(LAUNCH_BOOKMARKS) !== 'false' && ( ({ zIndex: 1e4, // must be higher than all content besides ads and modal margin: theme.spacing(1), }, - frontpageShortcutList: { - zIndex: 1.4e3, - }, logo: { height: 50, margin: theme.spacing(0.5), @@ -1143,7 +1140,7 @@ const Index = ({ data: fallbackData, userAgent }) => { {localStorageFeaturesManager.getFeatureValue(LAUNCH_BOOKMARKS) !== 'false' && bookmarkWidgetEnabled && ( -
+