You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.tsx 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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: React.JSX.Element
  26. }
  27. type FileUploaderInAttachmentProps = {
  28. isDisabled?: boolean
  29. fileConfig: FileUpload
  30. }
  31. const FileUploaderInAttachment = ({
  32. isDisabled,
  33. fileConfig,
  34. }: FileUploaderInAttachmentProps) => {
  35. const { t } = useTranslation()
  36. const files = useStore(s => s.files)
  37. const {
  38. handleRemoveFile,
  39. handleReUploadFile,
  40. } = useFile(fileConfig)
  41. const options = [
  42. {
  43. value: TransferMethod.local_file,
  44. label: t('common.fileUploader.uploadFromComputer'),
  45. icon: <RiUploadCloud2Line className='h-4 w-4' />,
  46. },
  47. {
  48. value: TransferMethod.remote_url,
  49. label: t('common.fileUploader.pasteFileLink'),
  50. icon: <RiLink className='h-4 w-4' />,
  51. },
  52. ]
  53. const renderButton = useCallback((option: Option, open?: boolean) => {
  54. return (
  55. <Button
  56. key={option.value}
  57. variant='tertiary'
  58. className={cn('relative grow', open && 'bg-components-button-tertiary-bg-hover')}
  59. disabled={!!(fileConfig.number_limits && files.length >= fileConfig.number_limits)}
  60. >
  61. {option.icon}
  62. <span className='ml-1'>{option.label}</span>
  63. {
  64. option.value === TransferMethod.local_file && (
  65. <FileInput fileConfig={fileConfig} />
  66. )
  67. }
  68. </Button>
  69. )
  70. }, [fileConfig, files.length])
  71. const renderTrigger = useCallback((option: Option) => {
  72. return (open: boolean) => renderButton(option, open)
  73. }, [renderButton])
  74. const renderOption = useCallback((option: Option) => {
  75. if (option.value === TransferMethod.local_file && fileConfig?.allowed_file_upload_methods?.includes(TransferMethod.local_file))
  76. return renderButton(option)
  77. if (option.value === TransferMethod.remote_url && fileConfig?.allowed_file_upload_methods?.includes(TransferMethod.remote_url)) {
  78. return (
  79. <FileFromLinkOrLocal
  80. key={option.value}
  81. showFromLocal={false}
  82. trigger={renderTrigger(option)}
  83. fileConfig={fileConfig}
  84. />
  85. )
  86. }
  87. }, [renderButton, renderTrigger, fileConfig])
  88. return (
  89. <div>
  90. {!isDisabled && (
  91. <div className='flex items-center space-x-1'>
  92. {options.map(renderOption)}
  93. </div>
  94. )}
  95. <div className='mt-1 space-y-1'>
  96. {
  97. files.map(file => (
  98. <FileItem
  99. key={file.id}
  100. file={file}
  101. showDeleteAction={!isDisabled}
  102. showDownloadAction={false}
  103. onRemove={() => handleRemoveFile(file.id)}
  104. onReUpload={() => handleReUploadFile(file.id)}
  105. />
  106. ))
  107. }
  108. </div>
  109. </div>
  110. )
  111. }
  112. type FileUploaderInAttachmentWrapperProps = {
  113. value?: FileEntity[]
  114. onChange: (files: FileEntity[]) => void
  115. fileConfig: FileUpload
  116. isDisabled?: boolean
  117. }
  118. const FileUploaderInAttachmentWrapper = ({
  119. value,
  120. onChange,
  121. fileConfig,
  122. isDisabled,
  123. }: FileUploaderInAttachmentWrapperProps) => {
  124. return (
  125. <FileContextProvider
  126. value={value}
  127. onChange={onChange}
  128. >
  129. <FileUploaderInAttachment isDisabled={isDisabled} fileConfig={fileConfig} />
  130. </FileContextProvider>
  131. )
  132. }
  133. export default FileUploaderInAttachmentWrapper