refactor reply code

This commit is contained in:
hjlarry 2025-09-17 20:29:23 +08:00
parent 29178d8adf
commit ea17f41b5b
3 changed files with 48 additions and 38 deletions

View File

@ -80,8 +80,6 @@ export const CommentInput: FC<CommentInputProps> = memo(({ position, onSubmit, o
onSubmit={handleMentionSubmit}
placeholder="Add a comment"
autoFocus
minRows={1}
maxRows={4}
className="relative"
/>
</div>

View File

@ -15,16 +15,12 @@ type MentionInputProps = {
value: string
onChange: (value: string) => void
onSubmit: (content: string, mentionedUserIds: string[]) => void
onKeyDown?: (e: React.KeyboardEvent) => void
onCancel?: () => void
placeholder?: string
disabled?: boolean
loading?: boolean
className?: string
minRows?: number
maxRows?: number
showSubmitButton?: boolean
showMentionButton?: boolean
submitButtonIcon?: React.ReactNode
isEditing?: boolean
autoFocus?: boolean
}
@ -32,13 +28,12 @@ export const MentionInput: FC<MentionInputProps> = memo(({
value,
onChange,
onSubmit,
onKeyDown,
onCancel,
placeholder = 'Add a comment',
disabled = false,
loading = false,
className,
showSubmitButton = true,
showMentionButton = true,
isEditing = false,
autoFocus = false,
}) => {
const params = useParams()
@ -140,14 +135,16 @@ export const MentionInput: FC<MentionInputProps> = memo(({
onChange(newContent)
setShowMentionDropdown(false)
setMentionedUserIds(prev => [...prev, user.id])
const newMentionedUserIds = [...mentionedUserIds, user.id]
setMentionedUserIds(newMentionedUserIds)
setTimeout(() => {
const newCursorPos = mentionPosition + user.name.length + 2 // @ + name + space
textarea.setSelectionRange(newCursorPos, newCursorPos)
textarea.focus()
}, 0)
}, [value, mentionPosition, onChange])
}, [value, mentionPosition, onChange, mentionedUserIds])
const handleSubmit = useCallback((e?: React.MouseEvent) => {
if (e) {
@ -194,9 +191,7 @@ export const MentionInput: FC<MentionInputProps> = memo(({
e.preventDefault()
handleSubmit()
}
onKeyDown?.(e)
}, [showMentionDropdown, filteredMentionUsers, selectedMentionIndex, insertMention, handleSubmit, onKeyDown])
}, [showMentionDropdown, filteredMentionUsers, selectedMentionIndex, insertMention, handleSubmit])
const resetMentionState = useCallback(() => {
setMentionedUserIds([])
@ -221,7 +216,7 @@ export const MentionInput: FC<MentionInputProps> = memo(({
)}
placeholder={placeholder}
autoFocus={autoFocus}
minRows={1}
minRows={isEditing ? 4 : 1}
maxRows={4}
value={value}
disabled={disabled || loading}
@ -229,17 +224,14 @@ export const MentionInput: FC<MentionInputProps> = memo(({
onKeyDown={handleKeyDown}
/>
{(showMentionButton || showSubmitButton) && (
{!isEditing && (
<div className="absolute bottom-0 right-1 z-20 flex items-end gap-1">
{showMentionButton && (
<div
className="z-20 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-components-button-secondary-bg hover:bg-state-base-hover"
onClick={handleMentionButtonClick}
>
<RiAtLine className="h-4 w-4" />
</div>
)}
{showSubmitButton && (
<Button
className='z-20 ml-2 w-8 px-0'
variant='primary'
@ -248,7 +240,30 @@ export const MentionInput: FC<MentionInputProps> = memo(({
>
<RiArrowUpLine className='h-4 w-4' />
</Button>
)}
</div>
)}
{isEditing && (
<div className="absolute bottom-0 left-1 right-1 z-20 flex items-end justify-between">
<div
className="z-20 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-components-button-secondary-bg hover:bg-state-base-hover"
onClick={handleMentionButtonClick}
>
<RiAtLine className="h-4 w-4" />
</div>
<div className='flex items-center gap-2'>
<Button variant='secondary' size='small' onClick={onCancel} disabled={loading}>
Cancel
</Button>
<Button
variant='primary'
size='small'
disabled={loading || !value.trim()}
onClick={() => handleSubmit()}
>
Save
</Button>
</div>
</div>
)}
</div>

View File

@ -1,13 +1,10 @@
'use client'
import { useParams } from 'next/navigation'
import type { FC } from 'react'
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { useReactFlow, useViewport } from 'reactflow'
import { RiArrowDownSLine, RiArrowUpSLine, RiCheckboxCircleFill, RiCheckboxCircleLine, RiCloseLine, RiDeleteBinLine, RiMoreFill } from '@remixicon/react'
import Textarea from 'react-textarea-autosize'
import Avatar from '@/app/components/base/avatar'
import Button from '@/app/components/base/button'
import Divider from '@/app/components/base/divider'
import cn from '@/utils/classnames'
import { useFormatTimeFromNow } from '@/app/components/workflow/hooks'
@ -75,7 +72,6 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
onReplyEdit,
onReplyDelete,
}) => {
const params = useParams()
const { flowToScreenPosition } = useReactFlow()
const viewport = useViewport()
const { userProfile } = useAppContext()
@ -115,11 +111,11 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
setEditingReply({ id: '', content: '' })
}, [])
const handleSaveEdit = useCallback(async () => {
const handleEditSubmit = useCallback(async (content: string, mentionedUserIds: string[]) => {
if (!onReplyEdit || !editingReply) return
const trimmed = editingReply.content.trim()
const trimmed = content.trim()
if (!trimmed) return
await onReplyEdit(editingReply.id, trimmed, [])
await onReplyEdit(editingReply.id, trimmed, mentionedUserIds)
setEditingReply({ id: '', content: '' })
}, [editingReply, onReplyEdit])
@ -235,17 +231,18 @@ export const CommentThread: FC<CommentThreadProps> = memo(({
</div>
{isReplyEditing ? (
<div className='rounded-lg border border-components-chat-input-border bg-components-panel-bg-blur px-3 py-2 shadow-sm'>
<Textarea
minRows={1}
maxRows={4}
<MentionInput
value={editingReply?.content ?? ''}
onChange={e => setEditingReply(prev => prev ? { ...prev, content: e.target.value } : prev)}
className='system-sm-regular w-full resize-none bg-transparent text-text-primary caret-primary-500 outline-none'
onChange={newContent => setEditingReply(prev => prev ? { ...prev, content: newContent } : prev)}
onSubmit={handleEditSubmit}
onCancel={handleCancelEdit}
placeholder="Edit reply"
disabled={loading}
loading={loading}
isEditing={true}
className="system-sm-regular"
autoFocus
/>
<div className='mt-2 flex items-center justify-end gap-2'>
<Button variant='secondary' size='small' onClick={handleCancelEdit} disabled={loading}>Cancel</Button>
<Button variant='primary' size='small' disabled={loading || !(editingReply?.content?.trim())} onClick={handleSaveEdit}>Save</Button>
</div>
</div>
) : (
<ThreadMessage