index.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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(appName)
  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. setEmoji({ icon, icon_background })
  75. setShowEmojiPicker(false)
  76. }}
  77. onClose={() => {
  78. setEmoji({ icon: '🤖', icon_background: '#FFEAD5' })
  79. setShowEmojiPicker(false)
  80. }}
  81. />}
  82. </>
  83. )
  84. }
  85. export default CreateAppModal