review
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-07-17 10:18:55 +03:30
parent 7913c43bc0
commit 3e17cf9e12
13 changed files with 882 additions and 309 deletions
@@ -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