| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 | 
							- import type { FC } from 'react'
 
- import { useCallback, useState } from 'react'
 
- import { useTranslation } from 'react-i18next'
 
- import type { Area } from 'react-easy-crop'
 
- import Modal from '../modal'
 
- import Divider from '../divider'
 
- import Button from '../button'
 
- import { ImagePlus } from '../icons/src/vender/line/images'
 
- import { useLocalFileUploader } from '../image-uploader/hooks'
 
- import EmojiPickerInner from '../emoji-picker/Inner'
 
- import type { OnImageInput } from './ImageInput'
 
- import ImageInput from './ImageInput'
 
- import s from './style.module.css'
 
- import getCroppedImg from './utils'
 
- import type { AppIconType, ImageFile } from '@/types/app'
 
- import cn from '@/utils/classnames'
 
- import { DISABLE_UPLOAD_IMAGE_AS_ICON } from '@/config'
 
- export type AppIconEmojiSelection = {
 
-   type: 'emoji'
 
-   icon: string
 
-   background: string
 
- }
 
- export type AppIconImageSelection = {
 
-   type: 'image'
 
-   fileId: string
 
-   url: string
 
- }
 
- export type AppIconSelection = AppIconEmojiSelection | AppIconImageSelection
 
- type AppIconPickerProps = {
 
-   onSelect?: (payload: AppIconSelection) => void
 
-   onClose?: () => void
 
-   className?: string
 
- }
 
- const AppIconPicker: FC<AppIconPickerProps> = ({
 
-   onSelect,
 
-   onClose,
 
-   className,
 
- }) => {
 
-   const { t } = useTranslation()
 
-   const tabs = [
 
-     { key: 'emoji', label: t('app.iconPicker.emoji'), icon: <span className="text-lg">🤖</span> },
 
-     { key: 'image', label: t('app.iconPicker.image'), icon: <ImagePlus /> },
 
-   ]
 
-   const [activeTab, setActiveTab] = useState<AppIconType>('emoji')
 
-   const [emoji, setEmoji] = useState<{ emoji: string; background: string }>()
 
-   const handleSelectEmoji = useCallback((emoji: string, background: string) => {
 
-     setEmoji({ emoji, background })
 
-   }, [setEmoji])
 
-   const [uploading, setUploading] = useState<boolean>()
 
-   const { handleLocalFileUpload } = useLocalFileUploader({
 
-     limit: 3,
 
-     disabled: false,
 
-     onUpload: (imageFile: ImageFile) => {
 
-       if (imageFile.fileId) {
 
-         setUploading(false)
 
-         onSelect?.({
 
-           type: 'image',
 
-           fileId: imageFile.fileId,
 
-           url: imageFile.url,
 
-         })
 
-       }
 
-     },
 
-   })
 
-   type InputImageInfo = { file: File } | { tempUrl: string; croppedAreaPixels: Area; fileName: string }
 
-   const [inputImageInfo, setInputImageInfo] = useState<InputImageInfo>()
 
-   const handleImageInput: OnImageInput = async (isCropped: boolean, fileOrTempUrl: string | File, croppedAreaPixels?: Area, fileName?: string) => {
 
-     setInputImageInfo(
 
-       isCropped
 
-         ? { tempUrl: fileOrTempUrl as string, croppedAreaPixels: croppedAreaPixels!, fileName: fileName! }
 
-         : { file: fileOrTempUrl as File },
 
-     )
 
-   }
 
-   const handleSelect = async () => {
 
-     if (activeTab === 'emoji') {
 
-       if (emoji) {
 
-         onSelect?.({
 
-           type: 'emoji',
 
-           icon: emoji.emoji,
 
-           background: emoji.background,
 
-         })
 
-       }
 
-     }
 
-     else {
 
-       if (!inputImageInfo)
 
-         return
 
-       setUploading(true)
 
-       if ('file' in inputImageInfo) {
 
-         handleLocalFileUpload(inputImageInfo.file)
 
-         return
 
-       }
 
-       const blob = await getCroppedImg(inputImageInfo.tempUrl, inputImageInfo.croppedAreaPixels, inputImageInfo.fileName)
 
-       const file = new File([blob], inputImageInfo.fileName, { type: blob.type })
 
-       handleLocalFileUpload(file)
 
-     }
 
-   }
 
-   return <Modal
 
-     onClose={() => { }}
 
-     isShow
 
-     closable={false}
 
-     wrapperClassName={className}
 
-     className={cn(s.container, '!w-[362px] !p-0')}
 
-   >
 
-     {!DISABLE_UPLOAD_IMAGE_AS_ICON && <div className="w-full p-2 pb-0">
 
-       <div className='flex items-center justify-center gap-2 rounded-xl bg-background-body p-1'>
 
-         {tabs.map(tab => (
 
-           <button
 
-             key={tab.key}
 
-             className={`
 
-                         flex h-8 flex-1 shrink-0 items-center justify-center rounded-xl p-2 text-sm font-medium
 
-                         ${activeTab === tab.key && 'bg-components-main-nav-nav-button-bg-active shadow-md'}
 
-                       `}
 
-             onClick={() => setActiveTab(tab.key as AppIconType)}
 
-           >
 
-             {tab.icon}   {tab.label}
 
-           </button>
 
-         ))}
 
-       </div>
 
-     </div>}
 
-     <EmojiPickerInner className={cn(activeTab === 'emoji' ? 'block' : 'hidden', 'pt-2')} onSelect={handleSelectEmoji} />
 
-     <ImageInput className={activeTab === 'image' ? 'block' : 'hidden'} onImageInput={handleImageInput} />
 
-     <Divider className='m-0' />
 
-     <div className='flex w-full items-center justify-center gap-2 p-3'>
 
-       <Button className='w-full' onClick={() => onClose?.()}>
 
-         {t('app.iconPicker.cancel')}
 
-       </Button>
 
-       <Button variant="primary" className='w-full' disabled={uploading} loading={uploading} onClick={handleSelect}>
 
-         {t('app.iconPicker.ok')}
 
-       </Button>
 
-     </div>
 
-   </Modal>
 
- }
 
- export default AppIconPicker
 
 
  |