Merge branch 'feat/ui-1.0.4' into 'test'

fix(Question): Optimise the display of check information for Question related form fields

See merge request opensource/answer!432
This commit is contained in:
Li Shuailing 2023-02-03 03:39:10 +00:00
commit c7c293cdac
8 changed files with 101 additions and 97 deletions

View File

@ -56,7 +56,7 @@ export interface QuestionParams {
title: string; title: string;
url_title?: string; url_title?: string;
content: string; content: string;
html: string; html?: string;
tags: Tag[]; tags: Tag[];
} }
@ -207,7 +207,7 @@ export interface AnswerItem {
export interface PostAnswerReq { export interface PostAnswerReq {
content: string; content: string;
html: string; html?: string;
question_id: string; question_id: string;
} }

View File

@ -1,5 +1,5 @@
import { useState, useEffect, memo } from 'react'; import { useState, useEffect, memo } from 'react';
import { Button } from 'react-bootstrap'; import { Button, Form } from 'react-bootstrap';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import classNames from 'classnames'; import classNames from 'classnames';
@ -7,7 +7,7 @@ import classNames from 'classnames';
import { TextArea, Mentions } from '@/components'; import { TextArea, Mentions } from '@/components';
import { usePageUsers } from '@/hooks'; import { usePageUsers } from '@/hooks';
const Form = ({ const Index = ({
className = '', className = '',
value: initialValue = '', value: initialValue = '',
onSendReply, onSendReply,
@ -18,7 +18,7 @@ const Form = ({
const [value, setValue] = useState(''); const [value, setValue] = useState('');
const pageUsers = usePageUsers(); const pageUsers = usePageUsers();
const { t } = useTranslation('translation', { keyPrefix: 'comment' }); const { t } = useTranslation('translation', { keyPrefix: 'comment' });
const [validationErrorMsg, setValidationErrorMsg] = useState('');
useEffect(() => { useEffect(() => {
if (!initialValue) { if (!initialValue) {
return; return;
@ -32,6 +32,13 @@ const Form = ({
const handleSelected = (val) => { const handleSelected = (val) => {
setValue(val); setValue(val);
}; };
const handleSendReply = () => {
onSendReply(value).catch((ex) => {
if (ex.isError) {
setValidationErrorMsg(ex.msg);
}
});
};
return ( return (
<div <div
className={classNames( className={classNames(
@ -39,17 +46,27 @@ const Form = ({
className, className,
)}> )}>
<div> <div>
<Mentions pageUsers={pageUsers.getUsers()} onSelected={handleSelected}> <div
<TextArea size="sm" value={value} onChange={handleChange} /> className={classNames('custom-form-control', {
</Mentions> 'is-invalid': validationErrorMsg,
<div className="form-text">{t(`tip_${mode}`)}</div> })}>
<Mentions
pageUsers={pageUsers.getUsers()}
onSelected={handleSelected}>
<TextArea size="sm" value={value} onChange={handleChange} />
</Mentions>
<div className="form-text">{t(`tip_${mode}`)}</div>
</div>
<Form.Control.Feedback type="invalid">
{validationErrorMsg}
</Form.Control.Feedback>
</div> </div>
{type === 'edit' ? ( {type === 'edit' ? (
<div className="d-flex flex-row flex-md-column ms-0 ms-md-2 mt-2 mt-md-0"> <div className="d-flex flex-row flex-md-column ms-0 ms-md-2 mt-2 mt-md-0">
<Button <Button
size="sm" size="sm"
className="text-nowrap " className="text-nowrap "
onClick={() => onSendReply(value)}> onClick={() => handleSendReply()}>
{t('btn_save_edits')} {t('btn_save_edits')}
</Button> </Button>
<Button <Button
@ -64,7 +81,7 @@ const Form = ({
<Button <Button
size="sm" size="sm"
className="text-nowrap ms-0 ms-md-2 mt-2 mt-md-0" className="text-nowrap ms-0 ms-md-2 mt-2 mt-md-0"
onClick={() => onSendReply(value)}> onClick={() => handleSendReply()}>
{t('btn_add_comment')} {t('btn_add_comment')}
</Button> </Button>
)} )}
@ -72,4 +89,4 @@ const Form = ({
); );
}; };
export default memo(Form); export default memo(Index);

View File

@ -1,21 +1,30 @@
import { useState, memo } from 'react'; import { useState, memo } from 'react';
import { Button } from 'react-bootstrap'; import { Button, Form } from 'react-bootstrap';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import classNames from 'classnames';
import { TextArea, Mentions } from '@/components'; import { TextArea, Mentions } from '@/components';
import { usePageUsers } from '@/hooks'; import { usePageUsers } from '@/hooks';
const Form = ({ userName, onSendReply, onCancel, mode }) => { const Index = ({ userName, onSendReply, onCancel, mode }) => {
const [value, setValue] = useState(''); const [value, setValue] = useState('');
const pageUsers = usePageUsers(); const pageUsers = usePageUsers();
const { t } = useTranslation('translation', { keyPrefix: 'comment' }); const { t } = useTranslation('translation', { keyPrefix: 'comment' });
const [validationErrorMsg, setValidationErrorMsg] = useState('');
const handleChange = (e) => { const handleChange = (e) => {
setValue(e.target.value); setValue(e.target.value);
}; };
const handleSelected = (val) => { const handleSelected = (val) => {
setValue(val); setValue(val);
}; };
const handleSendReply = () => {
onSendReply(value).catch((ex) => {
if (ex.isError) {
setValidationErrorMsg(ex.msg);
}
});
};
return ( return (
<div className="mb-2"> <div className="mb-2">
@ -24,18 +33,26 @@ const Form = ({ userName, onSendReply, onCancel, mode }) => {
</div> </div>
<div className="d-flex mb-1 align-items-start flex-column flex-md-row"> <div className="d-flex mb-1 align-items-start flex-column flex-md-row">
<div> <div>
<Mentions <div
pageUsers={pageUsers.getUsers()} className={classNames('custom-form-control', {
onSelected={handleSelected}> 'is-invalid': validationErrorMsg,
<TextArea size="sm" value={value} onChange={handleChange} /> })}>
</Mentions> <Mentions
<div className="form-text">{t(`tip_${mode}`)}</div> pageUsers={pageUsers.getUsers()}
onSelected={handleSelected}>
<TextArea size="sm" value={value} onChange={handleChange} />
</Mentions>
<div className="form-text">{t(`tip_${mode}`)}</div>
</div>
<Form.Control.Feedback type="invalid">
{validationErrorMsg}
</Form.Control.Feedback>
</div> </div>
<div className="d-flex flex-row flex-md-column ms-0 ms-md-2 mt-2 mt-md-0"> <div className="d-flex flex-row flex-md-column ms-0 ms-md-2 mt-2 mt-md-0">
<Button <Button
size="sm" size="sm"
className="text-nowrap" className="text-nowrap"
onClick={() => onSendReply(value)}> onClick={() => handleSendReply()}>
{t('btn_add_comment')} {t('btn_add_comment')}
</Button> </Button>
<Button <Button
@ -51,4 +68,4 @@ const Form = ({ userName, onSendReply, onCancel, mode }) => {
); );
}; };
export default memo(Form); export default memo(Index);

View File

@ -109,9 +109,9 @@ const Comment = ({ objectId, mode, commentId }) => {
const userNames = unionBy(users.map((user) => user.userName)); const userNames = unionBy(users.map((user) => user.userName));
const commentMarkDown = parseUserInfo(item.value); const commentMarkDown = parseUserInfo(item.value);
const html = marked.parse(commentMarkDown); const html = marked.parse(commentMarkDown);
if (!commentMarkDown || !html) { // if (!commentMarkDown || !html) {
return; // return;
} // }
const params = { const params = {
object_id: objectId, object_id: objectId,
original_text: commentMarkDown, original_text: commentMarkDown,
@ -125,7 +125,7 @@ const Comment = ({ objectId, mode, commentId }) => {
}; };
if (item.type === 'edit') { if (item.type === 'edit') {
updateComment({ return updateComment({
...params, ...params,
comment_id: item.comment_id, comment_id: item.comment_id,
}).then(() => { }).then(() => {
@ -140,30 +140,29 @@ const Comment = ({ objectId, mode, commentId }) => {
}), }),
); );
}); });
} else {
addComment(params).then((res) => {
if (item.type === 'reply') {
const index = comments.findIndex(
(comment) => comment.comment_id === item.comment_id,
);
comments[index].showReply = false;
comments.splice(index + 1, 0, res);
setComments([...comments]);
} else {
setComments([
...comments.map((comment) => {
if (comment.comment_id === item.comment_id) {
comment.showReply = false;
}
return comment;
}),
res,
]);
}
setVisibleComment(false);
});
} }
return addComment(params).then((res) => {
if (item.type === 'reply') {
const index = comments.findIndex(
(comment) => comment.comment_id === item.comment_id,
);
comments[index].showReply = false;
comments.splice(index + 1, 0, res);
setComments([...comments]);
} else {
setComments([
...comments.map((comment) => {
if (comment.comment_id === item.comment_id) {
comment.showReply = false;
}
return comment;
}),
res,
]);
}
setVisibleComment(false);
});
}; };
const handleDelete = (id) => { const handleDelete = (id) => {

View File

@ -143,21 +143,7 @@ const Ask = () => {
const checkValidated = (): boolean => { const checkValidated = (): boolean => {
const bol = true; const bol = true;
const { title, content, tags, answer } = formData; const { title, content, tags, answer } = formData;
if (!title.value) { if (title.value && Array.from(title.value).length <= 150) {
// bol = false;
// formData.title = {
// value: '',
// isInvalid: true,
// errorMsg: t('form.fields.title.msg.empty'),
// };
} else if (Array.from(title.value).length > 150) {
// bol = false;
// formData.title = {
// value: title.value,
// isInvalid: true,
// errorMsg: t('form.fields.title.msg.range'),
// };
} else {
formData.title = { formData.title = {
value: title.value, value: title.value,
isInvalid: false, isInvalid: false,
@ -165,14 +151,7 @@ const Ask = () => {
}; };
} }
if (!content.value) { if (content.value) {
// bol = false;
// formData.content = {
// value: '',
// isInvalid: true,
// errorMsg: t('form.fields.body.msg.empty'),
// };
} else {
formData.content = { formData.content = {
value: content.value, value: content.value,
isInvalid: false, isInvalid: false,
@ -180,29 +159,16 @@ const Ask = () => {
}; };
} }
if (tags.value.length === 0) { if (Array.isArray(tags.value) && tags.value.length > 0) {
// bol = false;
// formData.tags = {
// value: [],
// isInvalid: true,
// errorMsg: t('form.fields.tags.msg.empty'),
// };
} else {
formData.tags = { formData.tags = {
value: tags.value, value: tags.value,
isInvalid: false, isInvalid: false,
errorMsg: '', errorMsg: '',
}; };
} }
if (checked) { if (checked) {
if (!answer.value) { if (answer.value) {
// bol = false;
// formData.answer = {
// value: '',
// isInvalid: true,
// errorMsg: t('form.fields.answer.msg.empty'),
// };
} else {
formData.answer = { formData.answer = {
value: answer.value, value: answer.value,
isInvalid: false, isInvalid: false,
@ -227,7 +193,6 @@ const Ask = () => {
const params: Type.QuestionParams = { const params: Type.QuestionParams = {
title: formData.title.value, title: formData.title.value,
content: formData.content.value, content: formData.content.value,
html: editorRef.current.getHtml(),
tags: formData.tags.value, tags: formData.tags.value,
}; };
if (isEdit) { if (isEdit) {
@ -261,7 +226,6 @@ const Ask = () => {
postAnswer({ postAnswer({
question_id: id, question_id: id,
content: formData.answer.value, content: formData.answer.value,
html: editorRef2.current.getHtml(),
}) })
.then(() => { .then(() => {
navigate(pathFactory.questionLanding(id, params.url_title)); navigate(pathFactory.questionLanding(id, params.url_title));

View File

@ -140,8 +140,6 @@ const Index = () => {
usePageTags({ usePageTags({
title: t('edit_answer', { keyPrefix: 'page_title' }), title: t('edit_answer', { keyPrefix: 'page_title' }),
}); });
console.log('formData.content.value', formData.content.value);
return ( return (
<Container className="pt-4 mt-2 mb-5 edit-answer-wrap"> <Container className="pt-4 mt-2 mb-5 edit-answer-wrap">
<Row className="justify-content-center"> <Row className="justify-content-center">

View File

@ -171,8 +171,11 @@ function handleFormError(
) { ) {
if (error.list?.length > 0) { if (error.list?.length > 0) {
error.list.forEach((item) => { error.list.forEach((item) => {
data[item.error_field].isInvalid = true; const errorFieldObject = data[item.error_field];
data[item.error_field].errorMsg = item.error_msg; if (errorFieldObject) {
errorFieldObject.isInvalid = true;
errorFieldObject.errorMsg = item.error_msg;
}
}); });
} }
return data; return data;

View File

@ -48,7 +48,7 @@ class Request {
}, },
(error) => { (error) => {
const { status, data: respData } = error.response || {}; const { status, data: respData } = error.response || {};
const { data = {}, msg = '' } = respData || {}; const { data = {}, msg = '', reason = '' } = respData || {};
if (status === 400) { if (status === 400) {
// show error message // show error message
if (data instanceof Object && data.err_type) { if (data instanceof Object && data.err_type) {
@ -79,7 +79,13 @@ class Request {
if (data instanceof Array && data.length > 0) { if (data instanceof Array && data.length > 0) {
// handle form error // handle form error
return Promise.reject({ isError: true, list: data }); return Promise.reject({
code: status,
msg,
reason,
isError: true,
list: data,
});
} }
if (!data || Object.keys(data).length <= 0) { if (!data || Object.keys(data).length <= 0) {