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.

education-apply-page.tsx 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. 'use client'
  2. import {
  3. useState,
  4. } from 'react'
  5. import { useTranslation } from 'react-i18next'
  6. import { RiExternalLinkLine } from '@remixicon/react'
  7. import {
  8. useRouter,
  9. useSearchParams,
  10. } from 'next/navigation'
  11. import UserInfo from './user-info'
  12. import SearchInput from './search-input'
  13. import RoleSelector from './role-selector'
  14. import Confirm from './verify-state-modal'
  15. import Button from '@/app/components/base/button'
  16. import Checkbox from '@/app/components/base/checkbox'
  17. import {
  18. useEducationAdd,
  19. useInvalidateEducationStatus,
  20. } from '@/service/use-education'
  21. import { useProviderContext } from '@/context/provider-context'
  22. import { useToastContext } from '@/app/components/base/toast'
  23. import { EDUCATION_VERIFYING_LOCALSTORAGE_ITEM } from '@/app/education-apply/constants'
  24. import { noop } from 'lodash-es'
  25. import DifyLogo from '../components/base/logo/dify-logo'
  26. import { useDocLink } from '@/context/i18n'
  27. const EducationApplyAge = () => {
  28. const { t } = useTranslation()
  29. const [schoolName, setSchoolName] = useState('')
  30. const [role, setRole] = useState('Student')
  31. const [ageChecked, setAgeChecked] = useState(false)
  32. const [inSchoolChecked, setInSchoolChecked] = useState(false)
  33. const {
  34. isPending,
  35. mutateAsync: educationAdd,
  36. } = useEducationAdd({ onSuccess: noop })
  37. const [modalShow, setShowModal] = useState<undefined | { title: string; desc: string; onConfirm?: () => void }>(undefined)
  38. const { onPlanInfoChanged } = useProviderContext()
  39. const updateEducationStatus = useInvalidateEducationStatus()
  40. const { notify } = useToastContext()
  41. const router = useRouter()
  42. const docLink = useDocLink()
  43. const handleModalConfirm = () => {
  44. setShowModal(undefined)
  45. onPlanInfoChanged()
  46. updateEducationStatus()
  47. localStorage.removeItem(EDUCATION_VERIFYING_LOCALSTORAGE_ITEM)
  48. router.replace('/')
  49. }
  50. const searchParams = useSearchParams()
  51. const token = searchParams.get('token')
  52. const handleSubmit = () => {
  53. educationAdd({
  54. token: token || '',
  55. role,
  56. institution: schoolName,
  57. }).then((res) => {
  58. if (res.message === 'success') {
  59. setShowModal({
  60. title: t('education.successTitle'),
  61. desc: t('education.successContent'),
  62. onConfirm: handleModalConfirm,
  63. })
  64. }
  65. else {
  66. notify({
  67. type: 'error',
  68. message: t('education.submitError'),
  69. })
  70. }
  71. })
  72. }
  73. return (
  74. <div className='fixed inset-0 z-[31] overflow-y-auto bg-background-body p-6'>
  75. <div className='mx-auto w-full max-w-[1408px] rounded-2xl border border-effects-highlight bg-background-default-subtle'>
  76. <div
  77. className="h-[349px] w-full overflow-hidden rounded-t-2xl bg-cover bg-center bg-no-repeat"
  78. style={{
  79. backgroundImage: 'url(/education/bg.png)',
  80. }}
  81. >
  82. </div>
  83. <div className='mt-[-349px] box-content flex h-7 items-center justify-between p-6'>
  84. <DifyLogo size='large' style='monochromeWhite' />
  85. </div>
  86. <div className='mx-auto max-w-[720px] px-8 pb-[180px]'>
  87. <div className='mb-2 flex h-[192px] flex-col justify-end pb-4 pt-3 text-text-primary-on-surface'>
  88. <div className='title-5xl-bold mb-2 shadow-xs'>{t('education.toVerified')}</div>
  89. <div className='system-md-medium shadow-xs'>
  90. {t('education.toVerifiedTip.front')}&nbsp;
  91. <span className='system-md-semibold underline'>{t('education.toVerifiedTip.coupon')}</span>&nbsp;
  92. {t('education.toVerifiedTip.end')}
  93. </div>
  94. </div>
  95. <div className='mb-7'>
  96. <UserInfo />
  97. </div>
  98. <div className='mb-7'>
  99. <div className='system-md-semibold mb-1 flex h-6 items-center text-text-secondary'>
  100. {t('education.form.schoolName.title')}
  101. </div>
  102. <SearchInput
  103. value={schoolName}
  104. onChange={setSchoolName}
  105. />
  106. </div>
  107. <div className='mb-7'>
  108. <div className='system-md-semibold mb-1 flex h-6 items-center text-text-secondary'>
  109. {t('education.form.schoolRole.title')}
  110. </div>
  111. <RoleSelector
  112. value={role}
  113. onChange={setRole}
  114. />
  115. </div>
  116. <div className='mb-7'>
  117. <div className='system-md-semibold mb-1 flex h-6 items-center text-text-secondary'>
  118. {t('education.form.terms.title')}
  119. </div>
  120. <div className='system-md-regular mb-1 text-text-tertiary'>
  121. {t('education.form.terms.desc.front')}&nbsp;
  122. <a href='https://dify.ai/terms' target='_blank' className='text-text-secondary hover:underline'>{t('education.form.terms.desc.termsOfService')}</a>&nbsp;
  123. {t('education.form.terms.desc.and')}&nbsp;
  124. <a href='https://dify.ai/privacy' target='_blank' className='text-text-secondary hover:underline'>{t('education.form.terms.desc.privacyPolicy')}</a>
  125. {t('education.form.terms.desc.end')}
  126. </div>
  127. <div className='system-md-regular py-2 text-text-primary'>
  128. <div className='mb-2 flex'>
  129. <Checkbox
  130. className='mr-2 shrink-0'
  131. checked={ageChecked}
  132. onCheck={() => setAgeChecked(!ageChecked)}
  133. />
  134. {t('education.form.terms.option.age')}
  135. </div>
  136. <div className='flex'>
  137. <Checkbox
  138. className='mr-2 shrink-0'
  139. checked={inSchoolChecked}
  140. onCheck={() => setInSchoolChecked(!inSchoolChecked)}
  141. />
  142. {t('education.form.terms.option.inSchool')}
  143. </div>
  144. </div>
  145. </div>
  146. <Button
  147. variant='primary'
  148. disabled={!ageChecked || !inSchoolChecked || !schoolName || !role || isPending}
  149. onClick={handleSubmit}
  150. >
  151. {t('education.submit')}
  152. </Button>
  153. <div className='mb-4 mt-5 h-[1px] bg-gradient-to-r from-[rgba(16,24,40,0.08)]'></div>
  154. <a
  155. className='system-xs-regular flex items-center text-text-accent'
  156. href={docLink('/getting-started/dify-for-education')}
  157. target='_blank'
  158. >
  159. {t('education.learn')}
  160. <RiExternalLinkLine className='ml-1 h-3 w-3' />
  161. </a>
  162. </div>
  163. </div>
  164. <Confirm
  165. isShow={!!modalShow}
  166. title={modalShow?.title || ''}
  167. content={modalShow?.desc}
  168. onConfirm={modalShow?.onConfirm || noop}
  169. onCancel={modalShow?.onConfirm || noop}
  170. />
  171. </div>
  172. )
  173. }
  174. export default EducationApplyAge