index.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import {
  2. useCallback,
  3. } from 'react'
  4. import {
  5. RiLink,
  6. RiUploadCloud2Line,
  7. } from '@remixicon/react'
  8. import { useTranslation } from 'react-i18next'
  9. import FileFromLinkOrLocal from '../file-from-link-or-local'
  10. import {
  11. FileContextProvider,
  12. useStore,
  13. } from '../store'
  14. import type { FileEntity } from '../types'
  15. import FileInput from '../file-input'
  16. import { useFile } from '../hooks'
  17. import FileItem from './file-item'
  18. import Button from '@/app/components/base/button'
  19. import cn from '@/utils/classnames'
  20. import type { FileUpload } from '@/app/components/base/features/types'
  21. import { TransferMethod } from '@/types/app'
  22. type Option = {
  23. value: string
  24. label: string
  25. icon: JSX.Element
  26. }
  27. type FileUploaderInAttachmentProps = {
  28. fileConfig: FileUpload
  29. }
  30. const FileUploaderInAttachment = ({
  31. fileConfig,
  32. }: FileUploaderInAttachmentProps) => {
  33. const { t } = useTranslation()
  34. const files = useStore(s => s.files)
  35. const {
  36. handleRemoveFile,
  37. handleReUploadFile,
  38. } = useFile(fileConfig)
  39. const options = [
  40. {
  41. value: TransferMethod.local_file,
  42. label: t('common.fileUploader.uploadFromComputer'),
  43. icon: <RiUploadCloud2Line className='w-4 h-4' />,
  44. },
  45. {
  46. value: TransferMethod.remote_url,
  47. label: t('common.fileUploader.pasteFileLink'),
  48. icon: <RiLink className='w-4 h-4' />,
  49. },
  50. ]
  51. const renderButton = useCallback((option: Option, open?: boolean) => {
  52. return (
  53. <Button
  54. key={option.value}
  55. variant='tertiary'
  56. className={cn('grow relative', open && 'bg-components-button-tertiary-bg-hover')}
  57. disabled={!!(fileConfig.number_limits && files.length >= fileConfig.number_limits)}
  58. >
  59. {option.icon}
  60. <span className='ml-1'>{option.label}</span>
  61. {
  62. option.value === TransferMethod.local_file && (
  63. <FileInput fileConfig={fileConfig} />
  64. )
  65. }
  66. </Button>
  67. )
  68. }, [fileConfig, files.length])
  69. const renderTrigger = useCallback((option: Option) => {
  70. return (open: boolean) => renderButton(option, open)
  71. }, [renderButton])
  72. const renderOption = useCallback((option: Option) => {
  73. if (option.value === TransferMethod.local_file && fileConfig?.allowed_file_upload_methods?.includes(TransferMethod.local_file))
  74. return renderButton(option)
  75. if (option.value === TransferMethod.remote_url && fileConfig?.allowed_file_upload_methods?.includes(TransferMethod.remote_url)) {
  76. return (
  77. <FileFromLinkOrLocal
  78. key={option.value}
  79. showFromLocal={false}
  80. trigger={renderTrigger(option)}
  81. fileConfig={fileConfig}
  82. />
  83. )
  84. }
  85. }, [renderButton, renderTrigger, fileConfig])
  86. return (
  87. <div>
  88. <div className='flex items-center space-x-1'>
  89. {options.map(renderOption)}
  90. </div>
  91. <div className='mt-1 space-y-1'>
  92. {
  93. files.map(file => (
  94. <FileItem
  95. key={file.id}
  96. file={file}
  97. showDeleteAction
  98. showDownloadAction={false}
  99. onRemove={() => handleRemoveFile(file.id)}
  100. onReUpload={() => handleReUploadFile(file.id)}
  101. />
  102. ))
  103. }
  104. </div>
  105. </div>
  106. )
  107. }
  108. type FileUploaderInAttachmentWrapperProps = {
  109. value?: FileEntity[]
  110. onChange: (files: FileEntity[]) => void
  111. fileConfig: FileUpload
  112. }
  113. const FileUploaderInAttachmentWrapper = ({
  114. value,
  115. onChange,
  116. fileConfig,
  117. }: FileUploaderInAttachmentWrapperProps) => {
  118. return (
  119. <FileContextProvider
  120. value={value}
  121. onChange={onChange}
  122. >
  123. <FileUploaderInAttachment fileConfig={fileConfig} />
  124. </FileContextProvider>
  125. )
  126. }
  127. export default FileUploaderInAttachmentWrapper