mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 05:37:34 +03:00
Added limit to the description size, when adding/editing a recommendation (#18380)
closes https://github.com/TryGhost/Product/issues/3960 - recommendation description is limited to 200 characters, so that it renders nicely in Portal
This commit is contained in:
parent
5e85d2f58f
commit
488ef87a7d
@ -9,8 +9,7 @@ import useRouting from '../../../../hooks/useRouting';
|
||||
import {AlreadyExistsError} from '../../../../utils/errors';
|
||||
import {EditOrAddRecommendation, RecommendationResponseType, useGetRecommendationByUrl} from '../../../../api/recommendations';
|
||||
import {RoutingModalProps} from '../../../providers/RoutingProvider';
|
||||
import {showToast} from '../../../../admin-x-ds/global/Toast';
|
||||
import {toast} from 'react-hot-toast';
|
||||
import {dismissAllToasts, showToast} from '../../../../admin-x-ds/global/Toast';
|
||||
import {trimSearchAndHash} from '../../../../utils/url';
|
||||
import {useExternalGhostSite} from '../../../../api/external-ghost-site';
|
||||
import {useGetOembed} from '../../../../api/oembed';
|
||||
@ -138,7 +137,7 @@ const AddRecommendationModal: React.FC<RoutingModalProps & AddRecommendationModa
|
||||
return;
|
||||
}
|
||||
|
||||
toast.remove();
|
||||
dismissAllToasts();
|
||||
try {
|
||||
await handleSave({force: true});
|
||||
} catch (e) {
|
||||
|
@ -20,7 +20,7 @@ const AddRecommendationModalConfirm: React.FC<AddRecommendationModalProps> = ({r
|
||||
const {mutateAsync: addRecommendation} = useAddRecommendation();
|
||||
const handleError = useHandleError();
|
||||
|
||||
const {formState, updateForm, handleSave, saveState, errors} = useForm({
|
||||
const {formState, updateForm, handleSave, saveState, errors, clearError} = useForm({
|
||||
initialState: {
|
||||
...recommendation
|
||||
},
|
||||
@ -39,6 +39,10 @@ const AddRecommendationModalConfirm: React.FC<AddRecommendationModalProps> = ({r
|
||||
if (!formState.title) {
|
||||
newErrors.title = 'Title is required';
|
||||
}
|
||||
|
||||
if (formState.reason && formState.reason.length > 200) {
|
||||
newErrors.reason = 'Description cannot be longer than 200 characters';
|
||||
}
|
||||
return newErrors;
|
||||
}
|
||||
});
|
||||
@ -115,7 +119,7 @@ const AddRecommendationModalConfirm: React.FC<AddRecommendationModalProps> = ({r
|
||||
}
|
||||
}}
|
||||
>
|
||||
<RecommendationReasonForm errors={errors} formState={formState} showURL={false} updateForm={updateForm}/>
|
||||
<RecommendationReasonForm clearError={clearError} errors={errors} formState={formState} showURL={false} updateForm={updateForm}/>
|
||||
</Modal>;
|
||||
};
|
||||
|
||||
|
@ -8,8 +8,7 @@ import useHandleError from '../../../../utils/api/handleError';
|
||||
import useRouting from '../../../../hooks/useRouting';
|
||||
import {Recommendation, useDeleteRecommendation, useEditRecommendation} from '../../../../api/recommendations';
|
||||
import {RoutingModalProps} from '../../../providers/RoutingProvider';
|
||||
import {showToast} from '../../../../admin-x-ds/global/Toast';
|
||||
import {toast} from 'react-hot-toast';
|
||||
import {dismissAllToasts, showToast} from '../../../../admin-x-ds/global/Toast';
|
||||
|
||||
interface EditRecommendationModalProps {
|
||||
recommendation: Recommendation,
|
||||
@ -23,7 +22,7 @@ const EditRecommendationModal: React.FC<RoutingModalProps & EditRecommendationMo
|
||||
const {mutateAsync: deleteRecommendation} = useDeleteRecommendation();
|
||||
const handleError = useHandleError();
|
||||
|
||||
const {formState, updateForm, handleSave, saveState, errors} = useForm({
|
||||
const {formState, updateForm, handleSave, saveState, errors, clearError} = useForm({
|
||||
initialState: {
|
||||
...recommendation
|
||||
},
|
||||
@ -35,9 +34,15 @@ const EditRecommendationModal: React.FC<RoutingModalProps & EditRecommendationMo
|
||||
onSaveError: handleError,
|
||||
onValidate: () => {
|
||||
const newErrors: Record<string, string> = {};
|
||||
|
||||
if (!formState.title) {
|
||||
newErrors.title = 'Title is required';
|
||||
}
|
||||
|
||||
if (formState.reason && formState.reason.length > 200) {
|
||||
newErrors.reason = 'Description cannot be longer than 200 characters';
|
||||
}
|
||||
|
||||
return newErrors;
|
||||
}
|
||||
});
|
||||
@ -103,10 +108,10 @@ const EditRecommendationModal: React.FC<RoutingModalProps & EditRecommendationMo
|
||||
return;
|
||||
}
|
||||
|
||||
toast.remove();
|
||||
if (await handleSave({force: true})) {
|
||||
// Already handled
|
||||
} else {
|
||||
dismissAllToasts();
|
||||
try {
|
||||
await handleSave({force: true});
|
||||
} catch (e) {
|
||||
showToast({
|
||||
type: 'pageError',
|
||||
message: 'One or more fields have errors, please double check that you\'ve filled all mandatory fields.'
|
||||
@ -114,7 +119,7 @@ const EditRecommendationModal: React.FC<RoutingModalProps & EditRecommendationMo
|
||||
}
|
||||
}}
|
||||
>
|
||||
<RecommendationReasonForm errors={errors} formState={formState} showURL={true} updateForm={updateForm as any}/>
|
||||
<RecommendationReasonForm clearError={clearError} errors={errors} formState={formState} showURL={true} updateForm={updateForm as any}/>
|
||||
</Modal>;
|
||||
};
|
||||
|
||||
|
@ -13,10 +13,14 @@ interface Props<T extends EditOrAddRecommendation> {
|
||||
showURL?: boolean,
|
||||
formState: T,
|
||||
errors: ErrorMessages,
|
||||
updateForm: (fn: (state: T) => T) => void
|
||||
updateForm: (fn: (state: T) => T) => void,
|
||||
clearError?: (key: keyof ErrorMessages) => void
|
||||
}
|
||||
|
||||
const RecommendationReasonForm: React.FC<Props<EditOrAddRecommendation | Recommendation>> = ({showURL, formState, updateForm, errors}) => {
|
||||
const RecommendationReasonForm: React.FC<Props<EditOrAddRecommendation | Recommendation>> = ({showURL, formState, updateForm, errors, clearError}) => {
|
||||
const [reasonLength, setReasonLength] = React.useState(formState?.reason?.length || 0);
|
||||
const reasonLengthColor = reasonLength > 200 ? 'text-red' : 'text-green';
|
||||
|
||||
return <Form
|
||||
marginBottom={false}
|
||||
marginTop
|
||||
@ -53,15 +57,23 @@ const RecommendationReasonForm: React.FC<Props<EditOrAddRecommendation | Recomme
|
||||
hint={errors.title}
|
||||
title="Title"
|
||||
value={formState.title ?? ''}
|
||||
onChange={e => updateForm(state => ({...state, title: e.target.value}))}
|
||||
onChange={(e) => {
|
||||
clearError?.('title');
|
||||
updateForm(state => ({...state, title: e.target.value}));
|
||||
}}
|
||||
/>
|
||||
<TextArea
|
||||
clearBg={true}
|
||||
hint='Optional, try to keep it under 156 characters'
|
||||
error={Boolean(errors.reason)}
|
||||
hint={errors.reason || <>Max. <strong>200</strong> characters. You've used <strong className={reasonLengthColor}>{reasonLength}</strong></>}
|
||||
rows={3}
|
||||
title="Short description"
|
||||
value={formState.reason ?? ''}
|
||||
onChange={e => updateForm(state => ({...state, reason: e.target.value}))}
|
||||
onChange={(e) => {
|
||||
clearError?.('reason');
|
||||
setReasonLength(e.target.value.length);
|
||||
updateForm(state => ({...state, reason: e.target.value}));
|
||||
}}
|
||||
/>
|
||||
</Form>;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user