page.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. "use client"
  2. import React, { useState } from 'react'
  3. import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
  4. import { Button } from '@/components/ui/button'
  5. import { Input } from '@/components/ui/input'
  6. import { Label } from '@/components/ui/label'
  7. import { Alert, AlertDescription } from '@/components/ui/alert'
  8. import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
  9. import { ProtectedRoute } from '@/components/auth/protected-route'
  10. import { ApiKeyManager } from '@/components/auth/api-key-manager'
  11. import { UserManagement } from '@/components/auth/user-management'
  12. import { useAuth } from '@/lib/auth-context'
  13. import { authApi } from '@/lib/api'
  14. export default function SettingsPage() {
  15. const { user, logout } = useAuth()
  16. const [activeTab, setActiveTab] = useState('profile')
  17. const [error, setError] = useState<string | null>(null)
  18. const [success, setSuccess] = useState<string | null>(null)
  19. const [passwordData, setPasswordData] = useState({
  20. current_password: '',
  21. new_password: '',
  22. confirm_password: ''
  23. })
  24. const handlePasswordChange = async (e: React.FormEvent) => {
  25. e.preventDefault()
  26. if (passwordData.new_password !== passwordData.confirm_password) {
  27. setError('New passwords do not match')
  28. return
  29. }
  30. if (passwordData.new_password.length < 8) {
  31. setError('Password must be at least 8 characters long')
  32. return
  33. }
  34. try {
  35. await authApi.changePassword(passwordData.current_password, passwordData.new_password)
  36. setSuccess('Password changed successfully')
  37. setPasswordData({
  38. current_password: '',
  39. new_password: '',
  40. confirm_password: ''
  41. })
  42. setError(null)
  43. } catch (err) {
  44. setError(err instanceof Error ? err.message : 'Failed to change password')
  45. setSuccess(null)
  46. }
  47. }
  48. return (
  49. <ProtectedRoute>
  50. <div className="container mx-auto py-6 space-y-6">
  51. <div>
  52. <h1 className="text-3xl font-bold">Settings</h1>
  53. <p className="text-muted-foreground">Manage your account and application settings</p>
  54. </div>
  55. {error && (
  56. <Alert variant="destructive">
  57. <AlertDescription>{error}</AlertDescription>
  58. </Alert>
  59. )}
  60. {success && (
  61. <Alert>
  62. <AlertDescription>{success}</AlertDescription>
  63. </Alert>
  64. )}
  65. <Tabs value={activeTab} onValueChange={setActiveTab}>
  66. <TabsList className="grid w-full grid-cols-3">
  67. <TabsTrigger value="profile">Profile</TabsTrigger>
  68. <TabsTrigger value="api-keys">API Keys</TabsTrigger>
  69. {user?.role === 'admin' && (
  70. <TabsTrigger value="users">User Management</TabsTrigger>
  71. )}
  72. </TabsList>
  73. <TabsContent value="profile" className="space-y-6">
  74. <Card>
  75. <CardHeader>
  76. <CardTitle>Profile Information</CardTitle>
  77. <CardDescription>
  78. View and manage your account details
  79. </CardDescription>
  80. </CardHeader>
  81. <CardContent className="space-y-4">
  82. <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
  83. <div>
  84. <Label>Username</Label>
  85. <Input value={user?.username || ''} disabled />
  86. </div>
  87. <div>
  88. <Label>Role</Label>
  89. <Input value={user?.role || ''} disabled />
  90. </div>
  91. {user?.email && (
  92. <div>
  93. <Label>Email</Label>
  94. <Input value={user.email} disabled />
  95. </div>
  96. )}
  97. <div>
  98. <Label>Account Created</Label>
  99. <Input
  100. value={user?.createdAt ? new Date(user.createdAt).toLocaleDateString() : ''}
  101. disabled
  102. />
  103. </div>
  104. </div>
  105. </CardContent>
  106. </Card>
  107. <Card>
  108. <CardHeader>
  109. <CardTitle>Change Password</CardTitle>
  110. <CardDescription>
  111. Update your account password
  112. </CardDescription>
  113. </CardHeader>
  114. <CardContent>
  115. <form onSubmit={handlePasswordChange} className="space-y-4">
  116. <div>
  117. <Label htmlFor="current_password">Current Password</Label>
  118. <Input
  119. id="current_password"
  120. type="password"
  121. value={passwordData.current_password}
  122. onChange={(e) => setPasswordData(prev => ({ ...prev, current_password: e.target.value }))}
  123. required
  124. />
  125. </div>
  126. <div>
  127. <Label htmlFor="new_password">New Password</Label>
  128. <Input
  129. id="new_password"
  130. type="password"
  131. value={passwordData.new_password}
  132. onChange={(e) => setPasswordData(prev => ({ ...prev, new_password: e.target.value }))}
  133. required
  134. />
  135. </div>
  136. <div>
  137. <Label htmlFor="confirm_password">Confirm New Password</Label>
  138. <Input
  139. id="confirm_password"
  140. type="password"
  141. value={passwordData.confirm_password}
  142. onChange={(e) => setPasswordData(prev => ({ ...prev, confirm_password: e.target.value }))}
  143. required
  144. />
  145. </div>
  146. <Button type="submit">Change Password</Button>
  147. </form>
  148. </CardContent>
  149. </Card>
  150. <Card>
  151. <CardHeader>
  152. <CardTitle>Account Actions</CardTitle>
  153. <CardDescription>
  154. Manage your session
  155. </CardDescription>
  156. </CardHeader>
  157. <CardContent>
  158. <Button variant="destructive" onClick={logout}>
  159. Sign Out
  160. </Button>
  161. </CardContent>
  162. </Card>
  163. </TabsContent>
  164. <TabsContent value="api-keys">
  165. <ApiKeyManager />
  166. </TabsContent>
  167. {user?.role === 'admin' && (
  168. <TabsContent value="users">
  169. <UserManagement />
  170. </TabsContent>
  171. )}
  172. </Tabs>
  173. </div>
  174. </ProtectedRoute>
  175. )
  176. }