diff --git a/apps/admin-x-settings/src/admin-x-ds/global/form/TextArea.tsx b/apps/admin-x-settings/src/admin-x-ds/global/form/TextArea.tsx index 8dac3f38b0..ec7e5f9135 100644 --- a/apps/admin-x-settings/src/admin-x-ds/global/form/TextArea.tsx +++ b/apps/admin-x-settings/src/admin-x-ds/global/form/TextArea.tsx @@ -1,4 +1,4 @@ -import React, {useId} from 'react'; +import React, {useEffect, useId} from 'react'; import Heading from '../Heading'; import Hint from '../Hint'; @@ -22,6 +22,7 @@ interface TextAreaProps { fontStyle?: FontStyles; className?: string; onChange?: (event: React.ChangeEvent) => void; + autoFocus?: boolean; } const TextArea: React.FC = ({ @@ -51,6 +52,14 @@ const TextArea: React.FC = ({ setFocusState(false); }; + useEffect(() => { + if (props.autoFocus && inputRef && inputRef.current) { + const textarea = inputRef.current; + textarea.focus(); + textarea.setSelectionRange(textarea.value.length, textarea.value.length); + } + }, [props.autoFocus, inputRef]); + let styles = clsx( 'peer order-2 rounded-sm border px-3 py-2 dark:text-white', clearBg ? 'bg-transparent' : 'bg-grey-75 dark:bg-grey-950', diff --git a/apps/admin-x-settings/src/components/settings/site/recommendations/AddRecommendationModal.tsx b/apps/admin-x-settings/src/components/settings/site/recommendations/AddRecommendationModal.tsx index 5240d17470..cb7b1b490d 100644 --- a/apps/admin-x-settings/src/components/settings/site/recommendations/AddRecommendationModal.tsx +++ b/apps/admin-x-settings/src/components/settings/site/recommendations/AddRecommendationModal.tsx @@ -2,8 +2,8 @@ import AddRecommendationModalConfirm from './AddRecommendationModalConfirm'; import Form from '../../../../admin-x-ds/global/form/Form'; import Modal from '../../../../admin-x-ds/global/modal/Modal'; import NiceModal, {useModal} from '@ebay/nice-modal-react'; -import React from 'react'; -import URLTextField from '../../../../admin-x-ds/global/form/URLTextField'; +import React, {useEffect, useState} from 'react'; +import TextField from '../../../../admin-x-ds/global/form/TextField'; import useForm from '../../../../hooks/useForm'; import useRouting from '../../../../hooks/useRouting'; import {AlreadyExistsError} from '../../../../utils/errors'; @@ -20,13 +20,14 @@ interface AddRecommendationModalProps { } const AddRecommendationModal: React.FC = ({recommendation, animate}) => { + const [enterPressed, setEnterPressed] = useState(false); const modal = useModal(); const {updateRoute} = useRouting(); const {query: queryOembed} = useGetOembed(); const {query: queryExternalGhostSite} = useExternalGhostSite(); const {query: getRecommendationByUrl} = useGetRecommendationByUrl(); - const {formState, updateForm, handleSave, errors, validate, saveState, clearError} = useForm({ + const {formState, updateForm, handleSave, errors, saveState, clearError} = useForm({ initialState: recommendation ?? { title: '', url: '', @@ -111,12 +112,38 @@ const AddRecommendationModal: React.FC { + if (saveState === 'saving') { + // Already saving + return; + } - if (saveState === 'saving') { - loadingState = true; - } + dismissAllToasts(); + try { + await handleSave({force: true}); + } catch (e) { + const message = e instanceof AlreadyExistsError ? e.message : 'Something went wrong while checking this URL, please try again.'; + showToast({ + type: 'pageError', + message + }); + } + }; + + useEffect(() => { + if (enterPressed) { + saveForm(); + setEnterPressed(false); // Reset for future use + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [formState]); + + const formatUrl = (url: string) => { + if (!url.startsWith('http://') && !url.startsWith('https://')) { + url = `https://${url}`; + } + return url; + }; return { @@ -126,49 +153,37 @@ const AddRecommendationModal: React.FC { - if (saveState === 'saving') { - // Already saving - return; - } - - dismissAllToasts(); - try { - await handleSave({force: true}); - } catch (e) { - const message = e instanceof AlreadyExistsError ? e.message : 'Something went wrong while checking this URL, please try again.'; - showToast({ - type: 'pageError', - message - }); - } - }} + onOk={saveForm} >

You can recommend any site your audience will find valuable, not just those published on Ghost.

- Need inspiration? Explore thousands of sites to recommend} placeholder='https://www.example.com' title='URL' value={formState.url} - onBlur={validate} - onChange={u => updateForm((state) => { - return { - ...state, - url: u - }; - })} - onKeyDown={() => clearError?.('url')} + onBlur={() => updateForm(state => ({...state, url: formatUrl(formState.url)}))} + onChange={(e) => { + clearError?.('url'); + updateForm(state => ({...state, url: e.target.value})); + }} + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault(); + updateForm(state => ({...state, url: formatUrl(formState.url)})); + setEnterPressed(true); + } + }} />
; diff --git a/apps/admin-x-settings/src/components/settings/site/recommendations/RecommendationReasonForm.tsx b/apps/admin-x-settings/src/components/settings/site/recommendations/RecommendationReasonForm.tsx index bfae6c3a4c..41818a1b3e 100644 --- a/apps/admin-x-settings/src/components/settings/site/recommendations/RecommendationReasonForm.tsx +++ b/apps/admin-x-settings/src/components/settings/site/recommendations/RecommendationReasonForm.tsx @@ -1,7 +1,7 @@ import Form from '../../../../admin-x-ds/global/form/Form'; import Heading from '../../../../admin-x-ds/global/Heading'; import Hint from '../../../../admin-x-ds/global/Hint'; -import React from 'react'; +import React, {useRef} from 'react'; import RecommendationIcon from './RecommendationIcon'; import TextArea from '../../../../admin-x-ds/global/form/TextArea'; import TextField from '../../../../admin-x-ds/global/form/TextField'; @@ -20,7 +20,7 @@ interface Props { const RecommendationReasonForm: React.FC> = ({showURL, formState, updateForm, errors, clearError}) => { const [reasonLength, setReasonLength] = React.useState(formState?.reason?.length || 0); const reasonLengthColor = reasonLength > 200 ? 'text-red' : 'text-green'; - + const focusRef = useRef(null); return