data-table-row-actions.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { useState } from 'react'
  2. import { DotsHorizontalIcon } from '@radix-ui/react-icons'
  3. import { type Row } from '@tanstack/react-table'
  4. import { evaluationsService } from '@/services/evaluations.service'
  5. import { type Evaluation } from '@/types/evaluations.types'
  6. import {
  7. CircleCheck,
  8. Download,
  9. Eye,
  10. Pencil,
  11. RefreshCcw,
  12. Trash2,
  13. } from 'lucide-react'
  14. import { toast } from 'sonner'
  15. import { downloadFromUrl } from '@/lib/downloadFromUrl'
  16. import { PERMISSIONS } from '@/constants/permissions'
  17. import { useCan } from '@/hooks/use-can'
  18. import { Button } from '@/components/ui/button'
  19. import {
  20. DropdownMenu,
  21. DropdownMenuContent,
  22. DropdownMenuItem,
  23. DropdownMenuSeparator,
  24. DropdownMenuShortcut,
  25. DropdownMenuTrigger,
  26. } from '@/components/ui/dropdown-menu'
  27. import { useEvaluations } from './evaluations-provider'
  28. interface Props {
  29. row: Row<Evaluation>
  30. }
  31. export function DataTableRowActions({ row }: Props) {
  32. const { setOpen, setCurrentRow } = useEvaluations()
  33. const { can } = useCan()
  34. const canUpdate = can(PERMISSIONS.evaluations.update)
  35. const canDelete = can(PERMISSIONS.evaluations.delete)
  36. const [isDownloading, setIsDownloading] = useState(false)
  37. const evaluations = row.original
  38. const handleShowConfirmRetry = () => {
  39. setCurrentRow(evaluations)
  40. setOpen('retry')
  41. }
  42. const handleView = () => {
  43. setCurrentRow(evaluations)
  44. setOpen('view')
  45. }
  46. const handleShowConfirmApprove = () => {
  47. setCurrentRow(evaluations)
  48. setOpen('approve')
  49. }
  50. const handleEdit = () => {
  51. setCurrentRow(evaluations)
  52. setOpen('edit')
  53. }
  54. const handleDelete = () => {
  55. setCurrentRow(evaluations)
  56. setOpen('delete')
  57. }
  58. const handleDownloadVideo = async () => {
  59. setIsDownloading(true)
  60. const toastId = toast.loading('در حال دانلود ویدیو...')
  61. try {
  62. let media = evaluations.media?.[0]
  63. if (!media?.url) {
  64. const detail = await evaluationsService.detail(evaluations.id)
  65. media = detail?.media?.[0]
  66. }
  67. if (!media?.url) {
  68. toast.error('ویدیویی برای دانلود یافت نشد.', { id: toastId })
  69. return
  70. }
  71. const filename =
  72. media.name || `evaluation-${evaluations.id}.${media.extension || 'mp4'}`
  73. await downloadFromUrl(media.url, filename)
  74. toast.success('دانلود ویدیو شروع شد.', { id: toastId })
  75. } catch {
  76. toast.error('خطا در دانلود ویدیو!', { id: toastId })
  77. } finally {
  78. setIsDownloading(false)
  79. }
  80. }
  81. return (
  82. <DropdownMenu>
  83. <DropdownMenuTrigger asChild>
  84. <Button variant='ghost' className='flex h-8 w-8 p-0'>
  85. <DotsHorizontalIcon className='h-4 w-4' />
  86. </Button>
  87. </DropdownMenuTrigger>
  88. <DropdownMenuContent align='end'>
  89. <DropdownMenuItem onClick={handleView}>
  90. مشاهده
  91. <DropdownMenuShortcut>
  92. <Eye size={16} />
  93. </DropdownMenuShortcut>
  94. </DropdownMenuItem>
  95. {canUpdate && (
  96. <DropdownMenuItem
  97. onClick={handleEdit}
  98. disabled={evaluations?.status === 'pending'}
  99. >
  100. ویرایش ارزیابی
  101. <DropdownMenuShortcut>
  102. <Pencil size={16} />
  103. </DropdownMenuShortcut>
  104. </DropdownMenuItem>
  105. )}
  106. <DropdownMenuItem
  107. onClick={handleDownloadVideo}
  108. disabled={isDownloading}
  109. >
  110. دانلود ویدیو
  111. <DropdownMenuShortcut>
  112. <Download size={16} />
  113. </DropdownMenuShortcut>
  114. </DropdownMenuItem>
  115. {canUpdate && (
  116. <DropdownMenuItem
  117. onClick={handleShowConfirmApprove}
  118. disabled={evaluations?.status !== 'approved_ai'}
  119. >
  120. تایید ارزیابی
  121. <DropdownMenuShortcut>
  122. <CircleCheck size={16} />
  123. </DropdownMenuShortcut>
  124. </DropdownMenuItem>
  125. )}
  126. {canUpdate && (
  127. <DropdownMenuItem
  128. onClick={handleShowConfirmRetry}
  129. disabled={evaluations?.status === 'pending'}
  130. >
  131. ارزیابی مجدد
  132. <DropdownMenuShortcut>
  133. <RefreshCcw size={16} />
  134. </DropdownMenuShortcut>
  135. </DropdownMenuItem>
  136. )}
  137. {canDelete && (
  138. <>
  139. <DropdownMenuSeparator />
  140. <DropdownMenuItem onClick={handleDelete} className='text-red-600'>
  141. حذف ارزیابی
  142. <DropdownMenuShortcut>
  143. <Trash2 size={16} color='red' />
  144. </DropdownMenuShortcut>
  145. </DropdownMenuItem>
  146. </>
  147. )}
  148. </DropdownMenuContent>
  149. </DropdownMenu>
  150. )
  151. }