mirror of https://gitee.com/answerdev/answer.git
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:
commit
c7c293cdac
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue