pages_settings.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import React from 'react'
  2. import { useForm } from 'react-hook-form'
  3. import { useMutation, useQuery } from '@tanstack/react-query'
  4. import { UserAPI } from './api/index.ts'
  5. import type { User } from '../share/types.ts'
  6. import type { UserResponse } from './api/index.ts'
  7. export default function SettingsPage() {
  8. const { data: userResponse, isLoading } = useQuery<UserResponse, Error, User>({
  9. queryKey: ['currentUser'],
  10. queryFn: () => UserAPI.getCurrentUser(),
  11. select: (response) => response.data
  12. })
  13. const { register, handleSubmit, formState: { errors }, reset } = useForm<{
  14. nickname: string
  15. email: string
  16. phone?: string
  17. password?: string
  18. }>()
  19. const { mutate: updateUser, isPending } = useMutation({
  20. mutationFn: async (data: {
  21. nickname: string
  22. email: string
  23. phone?: string
  24. password?: string
  25. }) => {
  26. return UserAPI.updateCurrentUser({
  27. nickname: data.nickname,
  28. email: data.email,
  29. phone: data.phone,
  30. ...(data.password ? { password: data.password } : {})
  31. })
  32. },
  33. onSuccess: () => alert('更新成功'),
  34. onError: (error) => {
  35. console.error('更新失败:', error)
  36. alert('更新失败')
  37. }
  38. })
  39. const onSubmit = (data: {
  40. nickname: string
  41. email: string
  42. phone?: string
  43. password?: string
  44. }) => {
  45. updateUser(data)
  46. }
  47. React.useEffect(() => {
  48. if (userResponse) {
  49. reset({
  50. nickname: userResponse.nickname || '',
  51. email: userResponse.email || '',
  52. phone: userResponse.phone || ''
  53. })
  54. }
  55. }, [userResponse, reset])
  56. if (isLoading) {
  57. return (
  58. <div className="p-4">
  59. <h1 className="text-2xl font-bold mb-4">设置</h1>
  60. <div className="bg-white rounded-lg shadow p-4">
  61. <p>加载中...</p>
  62. </div>
  63. </div>
  64. )
  65. }
  66. return (
  67. <div className="p-4">
  68. <h1 className="text-2xl font-bold mb-4">设置</h1>
  69. <div className="bg-white rounded-lg shadow p-4 mb-4">
  70. <h2 className="text-lg font-semibold mb-4">编辑个人信息</h2>
  71. <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
  72. <div>
  73. <label className="block text-sm font-medium text-gray-700 mb-1">昵称</label>
  74. <input
  75. {...register('nickname', { required: '请输入昵称' })}
  76. className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
  77. />
  78. {errors.nickname && <p className="mt-1 text-sm text-red-600">{errors.nickname.message}</p>}
  79. </div>
  80. <div>
  81. <label className="block text-sm font-medium text-gray-700 mb-1">邮箱</label>
  82. <input
  83. {...register('email', {
  84. required: '请输入邮箱',
  85. pattern: {
  86. value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
  87. message: '请输入有效的邮箱地址'
  88. }
  89. })}
  90. type="email"
  91. className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
  92. />
  93. {errors.email && <p className="mt-1 text-sm text-red-600">{errors.email.message}</p>}
  94. </div>
  95. <div>
  96. <label className="block text-sm font-medium text-gray-700 mb-1">手机号</label>
  97. <input
  98. {...register('phone')}
  99. className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
  100. />
  101. </div>
  102. <div>
  103. <label className="block text-sm font-medium text-gray-700 mb-1">新密码</label>
  104. <input
  105. {...register('password')}
  106. type="password"
  107. placeholder="留空则不修改密码"
  108. className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
  109. />
  110. </div>
  111. <div className="flex space-x-3 pt-4">
  112. <button
  113. type="submit"
  114. disabled={isPending}
  115. className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50"
  116. >
  117. {isPending ? '保存中...' : '保存'}
  118. </button>
  119. </div>
  120. </form>
  121. </div>
  122. </div>
  123. )
  124. }