Files
chatGPTBox/src/components/ConversationItem/index.jsx
T

138 lines
4.5 KiB
React

import { useState } from 'react'
import { ChevronDownIcon, XCircleIcon, SyncIcon } from '@primer/octicons-react'
import CopyButton from '../CopyButton'
import PropTypes from 'prop-types'
import MarkdownRender from '../MarkdownRender/markdown.jsx'
import { useTranslation } from 'react-i18next'
export function ConversationItem({ type, content, session, done, port, onRetry }) {
const { t } = useTranslation()
const [collapsed, setCollapsed] = useState(false)
switch (type) {
case 'question':
return (
<div className={type} dir="auto">
<div className="gpt-header">
<p>{t('You')}:</p>
<div className="gpt-util-group">
<CopyButton contentFn={() => content.replace(/\n<hr\/>$/, '')} size={14} />
{!collapsed ? (
<span
title={t('Collapse')}
className="gpt-util-icon"
onClick={() => setCollapsed(true)}
>
<XCircleIcon size={14} />
</span>
) : (
<span
title={t('Expand')}
className="gpt-util-icon"
onClick={() => setCollapsed(false)}
>
<ChevronDownIcon size={14} />
</span>
)}
</div>
</div>
{!collapsed && <MarkdownRender>{content}</MarkdownRender>}
</div>
)
case 'answer':
return (
<div className={type} dir="auto">
<div className="gpt-header">
<p style="white-space: nowrap;">
{session && session.aiName ? `${t(session.aiName)}:` : t('Loading...')}
</p>
<div className="gpt-util-group">
{!done && (
<button
type="button"
className="normal-button"
onClick={() => {
port.postMessage({ stop: true })
}}
>
{t('Stop')}
</button>
)}
{onRetry && (
<span title={t('Retry')} className="gpt-util-icon" onClick={onRetry}>
<SyncIcon size={14} />
</span>
)}
{session && (
<CopyButton contentFn={() => content.replace(/\n<hr\/>$/, '')} size={14} />
)}
{!collapsed ? (
<span
title={t('Collapse')}
className="gpt-util-icon"
onClick={() => setCollapsed(true)}
>
<XCircleIcon size={14} />
</span>
) : (
<span
title={t('Expand')}
className="gpt-util-icon"
onClick={() => setCollapsed(false)}
>
<ChevronDownIcon size={14} />
</span>
)}
</div>
</div>
{!collapsed && <MarkdownRender>{content}</MarkdownRender>}
</div>
)
case 'error':
return (
<div className={type} dir="auto">
<div className="gpt-header">
<p>{t('Error')}:</p>
<div className="gpt-util-group">
{onRetry && (
<span title={t('Retry')} className="gpt-util-icon" onClick={onRetry}>
<SyncIcon size={14} />
</span>
)}
<CopyButton contentFn={() => content.replace(/\n<hr\/>$/, '')} size={14} />
{!collapsed ? (
<span
title={t('Collapse')}
className="gpt-util-icon"
onClick={() => setCollapsed(true)}
>
<XCircleIcon size={14} />
</span>
) : (
<span
title={t('Expand')}
className="gpt-util-icon"
onClick={() => setCollapsed(false)}
>
<ChevronDownIcon size={14} />
</span>
)}
</div>
</div>
{!collapsed && <MarkdownRender>{content}</MarkdownRender>}
</div>
)
}
}
ConversationItem.propTypes = {
type: PropTypes.oneOf(['question', 'answer', 'error']).isRequired,
content: PropTypes.string.isRequired,
session: PropTypes.object.isRequired,
done: PropTypes.bool.isRequired,
port: PropTypes.object.isRequired,
onRetry: PropTypes.func,
}
export default ConversationItem