index.tsx 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. 'use client'
  2. import React, { useState } from 'react'
  3. import cn from 'classnames'
  4. import { useTranslation } from 'react-i18next'
  5. import s from './style.module.css'
  6. import Modal from '@/app/components/base/modal'
  7. import Button from '@/app/components/base/button'
  8. import Toast from '@/app/components/base/toast'
  9. import AppIcon from '@/app/components/base/app-icon'
  10. import EmojiPicker from '@/app/components/base/emoji-picker'
  11. import { useProviderContext } from '@/context/provider-context'
  12. import AppsFull from '@/app/components/billing/apps-full-in-dialog'
  13. export type CreateAppModalProps = {
  14. appName: string
  15. show: boolean
  16. onConfirm: (info: {
  17. name: string
  18. icon: string
  19. icon_background: string
  20. }) => Promise<void>
  21. onHide: () => void
  22. }
  23. const CreateAppModal = ({
  24. appName,
  25. show = false,
  26. onConfirm,
  27. onHide,
  28. }: CreateAppModalProps) => {
  29. const { t } = useTranslation()
  30. const [name, setName] = React.useState('')
  31. const [showEmojiPicker, setShowEmojiPicker] = useState(false)
  32. const [emoji, setEmoji] = useState({ icon: '🤖', icon_background: '#FFEAD5' })
  33. const { plan, enableBilling } = useProviderContext()
  34. const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
  35. const submit = () => {
  36. if (!name.trim()) {
  37. Toast.notify({ type: 'error', message: t('explore.appCustomize.nameRequired') })
  38. return
  39. }
  40. onConfirm({
  41. name,
  42. ...emoji,
  43. })
  44. onHide()
  45. }
  46. return (
  47. <>
  48. <Modal
  49. isShow={show}
  50. onClose={() => {}}
  51. className={cn(s.modal, '!max-w-[480px]', 'px-8')}
  52. >
  53. <span className={s.close} onClick={onHide}/>
  54. <div className={s.title}>{t('explore.appCustomize.title', { name: appName })}</div>
  55. <div className={s.content}>
  56. <div className={s.subTitle}>{t('explore.appCustomize.subTitle')}</div>
  57. <div className='flex items-center justify-between space-x-3'>
  58. <AppIcon size='large' onClick={() => { setShowEmojiPicker(true) }} className='cursor-pointer' icon={emoji.icon} background={emoji.icon_background} />
  59. <input
  60. value={name}
  61. onChange={e => setName(e.target.value)}
  62. className='h-10 px-3 text-sm font-normal bg-gray-100 rounded-lg grow'
  63. />
  64. </div>
  65. {isAppsFull && <AppsFull loc='app-explore-create'/>}
  66. </div>
  67. <div className='flex flex-row-reverse'>
  68. <Button disabled={isAppsFull} className='w-24 ml-2' type='primary' onClick={submit}>{t('common.operation.create')}</Button>
  69. <Button className='w-24' onClick={onHide}>{t('common.operation.cancel')}</Button>
  70. </div>
  71. </Modal>
  72. {showEmojiPicker && <EmojiPicker
  73. onSelect={(icon, icon_background) => {
  74. console.log(icon, icon_background)
  75. setEmoji({ icon, icon_background })
  76. setShowEmojiPicker(false)
  77. }}
  78. onClose={() => {
  79. setEmoji({ icon: '🤖', icon_background: '#FFEAD5' })
  80. setShowEmojiPicker(false)
  81. }}
  82. />}
  83. </>
  84. )
  85. }
  86. export default CreateAppModal