Skip to content

Commit

Permalink
Merge pull request #13 from HieuPham2000/feature/code-ui
Browse files Browse the repository at this point in the history
feat: sử dụng react quill để tạo richtext box example
  • Loading branch information
HieuPham2000 authored Jul 2, 2023
2 parents f0d3838 + 8f0e290 commit 5833bfa
Show file tree
Hide file tree
Showing 7 changed files with 273 additions and 21 deletions.
109 changes: 109 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"react-hook-form": "^7.43.9",
"react-hotkeys-hook": "^4.4.0",
"react-lazy-load-image-component": "^1.6.0",
"react-quill": "^2.0.0",
"react-router-dom": "^6.8.1",
"react-scripts": "5.0.1",
"react-toastify": "^9.1.2",
Expand Down
126 changes: 126 additions & 0 deletions src/components/Example/ExampleRTEControl/ExampleRTEControl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { memo } from 'react';
import { Box, FormHelperText, IconButton, Tooltip, alpha } from '@mui/material';
import { Controller, useFormContext } from 'react-hook-form';
import ReactQuill, { Quill } from 'react-quill';
import styled from '@emotion/styled';
import { Highlight } from '@mui/icons-material';
import 'react-quill/dist/quill.snow.css';

let Inline = Quill.import('blots/inline');
class MarkBlot extends Inline {}
MarkBlot.blotName = 'mark';
MarkBlot.tagName = 'mark';
Quill.register(MarkBlot, true);

const modules = {
toolbar: {
container: '#toolbar',
},
clipboard: {
matchVisual: false,
},
};

const formats = ['mark'];

const StyledEditor = styled(Box)(({ theme }) => ({
overflow: 'hidden',
position: 'relative',
borderRadius: theme.shape.borderRadius,
border: `solid 1px ${alpha(theme.palette.text.primary, 0.23)}`,
boxSizing: 'border-box',
padding: '1px',

'&:hover': {
borderColor: theme.palette.text.primary,
},

'&:focus-within': {
padding: 0,
borderColor: theme.palette.primary.main,
borderWidth: '2px',
},

'&.hasError': {
borderColor: theme.palette.error.main,
color: theme.palette.error.main,

'& .ql-editor': {
'&.ql-blank::before': {
color: theme.palette.error.main,
},
},
},

'& .ql-container.ql-snow': {
border: 'none',
...theme.typography.body2,
fontFamily: theme.typography.fontFamily,
},
'& .ql-toolbar.ql-snow': {
border: 'none',
fontFamily: theme.typography.fontFamily,
},
'& .ql-toolbar.ql-snow button': {
width: '34px',
height: '34px',
border: 'unset',
float: 'unset',
display: 'block',
color: alpha(theme.palette.primary.light, 0.7),

'&:hover, &:focus, &.ql-active, &.ql-selected': {
color: theme.palette.primary.main,
},
},
'& .ql-editor': {
minHeight: 160,
maxHeight: 640,
// backgroundColor: alpha(theme.palette.grey[500], 0.08),

'&.ql-blank::before': {
fontStyle: 'normal',
color: theme.palette.text.disabled,
},
'& pre.ql-syntax': {
...theme.typography.body2,
padding: theme.spacing(2),
borderRadius: theme.shape.borderRadius,
backgroundColor: theme.palette.grey[900],
},
},
}));

function ExampleRTEControl({ style }) {
const {
control,
formState: { errors },
} = useFormContext();
return (
<>
<StyledEditor className={!!errors?.example ? 'hasError' : ''} style={style}>
<Box id="toolbar" sx={{ position: 'absolute', bottom: 0, right: 0, zIndex: 20 }}>
<Tooltip title="Highlight">
<IconButton className="ql-mark">
<Highlight />
</IconButton>
</Tooltip>
</Box>
<Controller
name="example"
control={control}
render={({ field }) => (
<ReactQuill {...field} modules={modules} formats={formats} placeholder="Example (*)" />
)}
/>
</StyledEditor>
{!!errors?.example && (
<FormHelperText error sx={{ px: 2 }}>
{errors.example.message}
</FormHelperText>
)}
</>
);
}

export default memo(ExampleRTEControl);
1 change: 1 addition & 0 deletions src/components/Example/ExampleRTEControl/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ExampleRTEControl';
34 changes: 21 additions & 13 deletions src/pages/AddExample/AddExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ import { FormProvider, useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import yup from '~/utils/common/validate/yupGlobal';
import ExampleAttributeBox from '~/components/Example/ExampleAttributeBox';
import ExampleControl from '~/components/Example/ExampleControl';
import ExampleRelationAutocomplete from '~/components/Example/ExampleRelationAutocomplete';
import { addExample } from '~/services/exampleService';
import { Enum } from '~/utils/common/enumeration';
import HUSTConstant from '~/utils/common/constant';
import { saveLog } from '~/services/auditLogService';
import { toast } from 'react-toastify';
import useAccountInfo from '~/hooks/data/useAccountInfo';
import ExampleRTEControl from '~/components/Example/ExampleRTEControl';

const cx = classNames.bind(styles);
const schema = yup.object().shape({
example: yup.string().required('Example is required'),
example: yup.string().textHtmlRequired('Example is required'),
});

const customStylePaper = {
Expand Down Expand Up @@ -73,7 +73,7 @@ function AddExample() {
resolver: yupResolver(schema),
});

const { handleSubmit, reset, setError, resetField } = methods;
const { handleSubmit, reset, setError } = methods;

// ==========================================================================
const { mutate: handleSave } = useMutation(
Expand All @@ -98,18 +98,17 @@ function AddExample() {
saveAuditLog(reqData);

if (reuseParam) {
resetReuseParam();
resetReuseParam(reqData);
} else {
resetNotReuseParam();
}
} else if (data?.Status === Enum.ServiceResultStatus.Fail) {
toast.error(data.Message || 'Add example failed');
if (data.ErrorCode === HUSTConstant.ErrorCode.Err4001) {
setError(
'example',
{ type: HUSTConstant.ErrorCode.Err4001, message: data.Message },
{ shouldFocus: true },
);
if (
data.ErrorCode === HUSTConstant.ErrorCode.Err4001 ||
data.ErrorCode === HUSTConstant.ErrorCode.Err4002
) {
setError('example', { type: data.ErrorCode, message: data.Message }, { shouldFocus: true });
}
} else {
toast.error('Add example failed');
Expand Down Expand Up @@ -207,12 +206,20 @@ function AddExample() {
reset();
};

const resetReuseParam = () => {
const resetReuseParam = (param) => {
// TODO: bug do searchConcept không lưu giá trị mới nhất của searchValue
setDelaySearchConcept(0);
setSearchConcept('');
setListLinkedConcept([]);
resetField('example');
reset({
example: '',
tone: param?.tone || null,
mode: param?.mode || null,
register: param?.register || null,
nuance: param?.nuance || null,
dialect: param?.dialect || null,
note: param?.note || '',
});
};

const saveAuditLog = (reqData) => {
Expand Down Expand Up @@ -264,7 +271,8 @@ function AddExample() {
sx={{ ...customStylePaper, maxHeight: 280 }}
className={cx('main-item', 'item-example')}
>
<ExampleControl sx={{ mt: 1 }} />
{/* <ExampleControl sx={{ mt: 1 }} /> */}
<ExampleRTEControl style={{ marginTop: '8px' }} />
</Paper>
</Grid>

Expand Down
3 changes: 3 additions & 0 deletions src/utils/common/constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ const ErrorCode = {
//Duplicate examples
Err4001: 4001,

//No highlighted parts
Err4002: 4002,

//Invalid parameters
Err9000: 9000,

Expand Down
Loading

0 comments on commit 5833bfa

Please sign in to comment.