123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import { ChatContext } from '@/app/chat-context';
- import { apiInterceptors, getChatFeedBackItme, postChatFeedBackForm } from '@/client/api';
- import { FeedBack } from '@/types/chat';
- import { ChatFeedBackSchema } from '@/types/db';
- import { CloseRounded, MoreHoriz } from '@mui/icons-material';
- import {
- Box,
- Button,
- Dropdown,
- Grid,
- IconButton,
- Menu,
- MenuButton,
- MenuItem,
- Option,
- Select,
- Sheet,
- Slider,
- Textarea,
- Typography,
- styled,
- } from '@mui/joy';
- import { Tooltip, message } from 'antd';
- import { useCallback, useContext, useRef, useState } from 'react';
- import { useTranslation } from 'react-i18next';
- type Props = {
- conv_index: number;
- question: any;
- knowledge_space: string;
- select_param?: FeedBack;
- };
- const ChatFeedback = ({ conv_index, question, knowledge_space, select_param }: Props) => {
- const { t } = useTranslation();
- const { chatId } = useContext(ChatContext);
- const [ques_type, setQuesType] = useState('');
- const [score, setScore] = useState(4);
- const [text, setText] = useState('');
- const action = useRef(null);
- const [messageApi, contextHolder] = message.useMessage();
- const handleOpenChange = useCallback(
- (_: any, isOpen: boolean) => {
- if (isOpen) {
- apiInterceptors(getChatFeedBackItme(chatId, conv_index))
- .then(res => {
- const finddata = res[1] ?? {};
- setQuesType(finddata.ques_type ?? '');
- setScore(parseInt(finddata.score ?? '4'));
- setText(finddata.messages ?? '');
- })
- .catch(err => {
- console.log(err);
- });
- } else {
- setQuesType('');
- setScore(4);
- setText('');
- }
- },
- [chatId, conv_index],
- );
- const marks = [
- { value: 0, label: '0' },
- { value: 1, label: '1' },
- { value: 2, label: '2' },
- { value: 3, label: '3' },
- { value: 4, label: '4' },
- { value: 5, label: '5' },
- ];
- function valueText(value: number) {
- return {
- 0: t('Lowest'),
- 1: t('Missed'),
- 2: t('Lost'),
- 3: t('Incorrect'),
- 4: t('Verbose'),
- 5: t('Best'),
- }[value];
- }
- const Item = styled(Sheet)(({ theme }) => ({
- backgroundColor: theme.palette.mode === 'dark' ? '#FBFCFD' : '#0E0E10',
- ...theme.typography['body-sm'],
- padding: theme.spacing(1),
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- borderRadius: 4,
- width: '100%',
- height: '100%',
- }));
- const handleSubmit = (event: any) => {
- event.preventDefault();
- const formData: ChatFeedBackSchema = {
- conv_uid: chatId,
- conv_index: conv_index,
- question: question,
- knowledge_space: knowledge_space,
- score: score,
- ques_type: ques_type,
- messages: text,
- };
- apiInterceptors(
- postChatFeedBackForm({
- data: formData,
- }),
- )
- .then(_ => {
- messageApi.open({ type: 'success', content: 'save success' });
- })
- .catch(_ => {
- messageApi.open({ type: 'error', content: 'save error' });
- });
- };
- return (
- <Dropdown onOpenChange={handleOpenChange}>
- {contextHolder}
- <Tooltip title={t('Rating')}>
- <MenuButton
- slots={{ root: IconButton }}
- slotProps={{ root: { variant: 'plain', color: 'primary' } }}
- sx={{ borderRadius: 40 }}
- >
- <MoreHoriz />
- </MenuButton>
- </Tooltip>
- <Menu>
- <MenuItem disabled sx={{ minHeight: 0 }} />
- <Box
- sx={{
- width: '100%',
- maxWidth: 350,
- display: 'grid',
- gap: 3,
- padding: 1,
- }}
- >
- <form onSubmit={handleSubmit}>
- <Grid container spacing={0.5} columns={13} sx={{ flexGrow: 1 }}>
- <Grid xs={3}>
- <Item>{t('Q_A_Category')}</Item>
- </Grid>
- <Grid xs={10}>
- <Select
- action={action}
- value={ques_type}
- placeholder='Choose one…'
- onChange={(_, newValue) => setQuesType(newValue ?? '')}
- {...(ques_type && {
- // display the button and remove select indicator
- // when user has selected a value
- endDecorator: (
- <IconButton
- size='sm'
- variant='plain'
- color='neutral'
- onMouseDown={event => {
- // don't open the popup when clicking on this button
- event.stopPropagation();
- }}
- onClick={() => {
- setQuesType('');
- action.current?.focusVisible();
- }}
- >
- <CloseRounded />
- </IconButton>
- ),
- indicator: null,
- })}
- sx={{ width: '100%' }}
- >
- {select_param &&
- Object.keys(select_param)?.map(paramItem => (
- <Option key={paramItem} value={paramItem}>
- {select_param[paramItem]}
- </Option>
- ))}
- </Select>
- </Grid>
- <Grid xs={3}>
- <Item>
- <Tooltip
- title={
- <Box>
- <div>{t('feed_back_desc')}</div>
- </Box>
- }
- variant='solid'
- placement='left'
- >
- {t('Q_A_Rating')}
- </Tooltip>
- </Item>
- </Grid>
- <Grid xs={10} sx={{ pl: 0, ml: 0 }}>
- <Slider
- aria-label='Custom'
- step={1}
- min={0}
- max={5}
- valueLabelFormat={valueText}
- valueLabelDisplay='on'
- marks={marks}
- sx={{ width: '90%', pt: 3, m: 2, ml: 1 }}
- onChange={event => setScore(event.target?.value)}
- value={score}
- />
- </Grid>
- <Grid xs={13}>
- <Textarea
- placeholder={t('Please_input_the_text')}
- value={text}
- onChange={event => setText(event.target.value)}
- minRows={2}
- maxRows={4}
- endDecorator={
- <Typography level='body-xs' sx={{ ml: 'auto' }}>
- {t('input_count') + text.length + t('input_unit')}
- </Typography>
- }
- sx={{ width: '100%', fontSize: 14 }}
- />
- </Grid>
- <Grid xs={13}>
- <Button type='submit' variant='outlined' sx={{ width: '100%', height: '100%' }}>
- {t('submit')}
- </Button>
- </Grid>
- </Grid>
- </form>
- </Box>
- </Menu>
- </Dropdown>
- );
- };
- export default ChatFeedback;
|