index.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import { ChangeEvent, useEffect } from 'react'
  2. import Link from 'next/link'
  3. import { CheckCircleIcon, ExclamationCircleIcon } from '@heroicons/react/24/solid'
  4. import { useTranslation } from 'react-i18next'
  5. import { useContext } from 'use-context-selector'
  6. import I18n from '@/context/i18n'
  7. import useValidateToken, { ValidatedStatus } from './useValidateToken'
  8. interface IProviderInputProps {
  9. value?: string
  10. name: string
  11. placeholder: string
  12. className?: string
  13. onChange: (v: string) => void
  14. onFocus?: () => void
  15. }
  16. const ProviderInput = ({
  17. value,
  18. name,
  19. placeholder,
  20. className,
  21. onChange,
  22. onFocus,
  23. }: IProviderInputProps) => {
  24. const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
  25. const inputValue = e.target.value
  26. onChange(inputValue)
  27. }
  28. return (
  29. <div className={className}>
  30. <div className="mb-2 text-[13px] font-medium text-gray-800">{name}</div>
  31. <div className='
  32. flex items-center px-3 bg-white rounded-lg
  33. shadow-[0_1px_2px_rgba(16,24,40,0.05)]
  34. '>
  35. <input
  36. className='
  37. w-full py-[9px]
  38. text-xs font-medium text-gray-700 leading-[18px]
  39. appearance-none outline-none bg-transparent
  40. '
  41. value={value}
  42. placeholder={placeholder}
  43. onChange={handleChange}
  44. onFocus={onFocus}
  45. />
  46. </div>
  47. </div>
  48. )
  49. }
  50. type TproviderInputProps = IProviderInputProps
  51. & {
  52. onValidatedStatus?: (status?: ValidatedStatus) => void
  53. providerName: string
  54. }
  55. export const ProviderValidateTokenInput = ({
  56. value,
  57. name,
  58. placeholder,
  59. className,
  60. onChange,
  61. onFocus,
  62. onValidatedStatus,
  63. providerName
  64. }: TproviderInputProps) => {
  65. const { t } = useTranslation()
  66. const { locale } = useContext(I18n)
  67. const [ validating, validatedStatus, validate ] = useValidateToken(providerName)
  68. useEffect(() => {
  69. if (typeof onValidatedStatus === 'function') {
  70. onValidatedStatus(validatedStatus)
  71. }
  72. }, [validatedStatus])
  73. const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
  74. const inputValue = e.target.value
  75. onChange(inputValue)
  76. validate(inputValue)
  77. }
  78. return (
  79. <div className={className}>
  80. <div className="mb-2 text-[13px] font-medium text-gray-800">{name}</div>
  81. <div className='
  82. flex items-center px-3 bg-white rounded-lg
  83. shadow-[0_1px_2px_rgba(16,24,40,0.05)]
  84. '>
  85. <input
  86. className='
  87. w-full py-[9px]
  88. text-xs font-medium text-gray-700 leading-[18px]
  89. appearance-none outline-none bg-transparent
  90. '
  91. value={value}
  92. placeholder={placeholder}
  93. onChange={handleChange}
  94. onFocus={onFocus}
  95. />
  96. {
  97. validatedStatus === ValidatedStatus.Error && <ExclamationCircleIcon className='w-4 h-4 text-[#D92D20]' />
  98. }
  99. {
  100. validatedStatus === ValidatedStatus.Success && <CheckCircleIcon className='w-4 h-4 text-[#039855]' />
  101. }
  102. </div>
  103. {
  104. validating && (
  105. <div className={`mt-2 text-primary-600 text-xs font-normal`}>
  106. {t('common.provider.validating')}
  107. </div>
  108. )
  109. }
  110. {
  111. validatedStatus === ValidatedStatus.Exceed && !validating && (
  112. <div className={`mt-2 text-[#D92D20] text-xs font-normal`}>
  113. {t('common.provider.apiKeyExceedBill')}&nbsp;
  114. <Link
  115. className='underline'
  116. href="https://platform.openai.com/account/api-keys"
  117. target={'_blank'}>
  118. {locale === 'en' ? 'this link' : '这篇文档'}
  119. </Link>
  120. </div>
  121. )
  122. }
  123. {
  124. validatedStatus === ValidatedStatus.Error && !validating && (
  125. <div className={`mt-2 text-[#D92D20] text-xs font-normal`}>
  126. {t('common.provider.invalidKey')}
  127. </div>
  128. )
  129. }
  130. </div>
  131. )
  132. }
  133. export default ProviderInput