@@ -0,0 +1,128 @@
|
||||
import { type FC, useEffect, useState } from 'react'
|
||||
import { MessageText1 } from 'iconsax-react'
|
||||
import Textarea from '@/components/Textarea'
|
||||
import Button from '@/components/Button'
|
||||
import { formatOptionalDate } from '@/helpers/func'
|
||||
import { toast } from 'react-toastify'
|
||||
import { extractErrorMessage } from '@/config/func'
|
||||
import { useDeleteReviewReply, useReplyToReview } from '../hooks/useReviewData'
|
||||
import type { ReviewReply } from '../types/Types'
|
||||
|
||||
interface ReviewReplySectionProps {
|
||||
reviewId: string
|
||||
replies: ReviewReply[]
|
||||
}
|
||||
|
||||
const ReviewReplySection: FC<ReviewReplySectionProps> = ({ reviewId, replies }) => {
|
||||
const existingReply = replies[0]
|
||||
const [comment, setComment] = useState(existingReply?.comment || '')
|
||||
const replyMutation = useReplyToReview()
|
||||
const deleteMutation = useDeleteReviewReply()
|
||||
|
||||
useEffect(() => {
|
||||
setComment(existingReply?.comment || '')
|
||||
}, [existingReply?.comment, existingReply?.id])
|
||||
|
||||
const hasChanges = comment.trim() !== (existingReply?.comment || '').trim()
|
||||
const canSave = comment.trim().length > 0 && hasChanges
|
||||
|
||||
const handleSave = () => {
|
||||
if (!canSave) return
|
||||
|
||||
replyMutation.mutate(
|
||||
{ id: reviewId, comment: comment.trim() },
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.success(existingReply ? 'پاسخ با موفقیت بهروزرسانی شد' : 'پاسخ با موفقیت ثبت شد')
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const handleDelete = () => {
|
||||
deleteMutation.mutate(reviewId, {
|
||||
onSuccess: () => {
|
||||
setComment('')
|
||||
toast.success('پاسخ حذف شد')
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='pt-6 border-t border-border space-y-6'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<MessageText1 size={20} color="#8C90A3" />
|
||||
<span className='text-sm font-medium'>پاسخ رستوران</span>
|
||||
{replies.length > 0 && (
|
||||
<span className='text-xs text-gray-400'>({replies.length})</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{replies.length > 0 && (
|
||||
<div className='space-y-3'>
|
||||
{replies.map((reply) => (
|
||||
<div
|
||||
key={reply.id}
|
||||
className='bg-gray-50 rounded-xl p-4 border border-border'
|
||||
>
|
||||
<div className='flex items-center justify-between mb-2'>
|
||||
<span className='text-xs font-medium text-gray-500'>پاسخ</span>
|
||||
{reply.createdAt && (
|
||||
<span className='text-xs text-gray-500'>
|
||||
{formatOptionalDate(reply.createdAt, {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className='text-sm leading-6 text-gray-700 whitespace-pre-wrap'>
|
||||
{reply.comment || '-'}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Textarea
|
||||
label='متن پاسخ'
|
||||
isNotRequired
|
||||
placeholder='پاسخ خود را به این نظر بنویسید...'
|
||||
value={comment}
|
||||
onChange={(e) => setComment(e.target.value)}
|
||||
rows={4}
|
||||
/>
|
||||
|
||||
<div className='flex items-center gap-3 mt-4'>
|
||||
<Button
|
||||
label={existingReply ? 'ویرایش پاسخ' : 'ثبت پاسخ'}
|
||||
onClick={handleSave}
|
||||
isloading={replyMutation.isPending}
|
||||
disabled={!canSave}
|
||||
className='w-36'
|
||||
/>
|
||||
{existingReply && (
|
||||
<Button
|
||||
label='حذف پاسخ'
|
||||
onClick={handleDelete}
|
||||
isloading={deleteMutation.isPending}
|
||||
className='w-28 bg-red-500 hover:bg-red-600'
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReviewReplySection
|
||||
Reference in New Issue
Block a user