better-auth-studio 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/package.json +8 -1
  2. package/frontend/index.html +0 -13
  3. package/frontend/package-lock.json +0 -4675
  4. package/frontend/package.json +0 -52
  5. package/frontend/pnpm-lock.yaml +0 -4020
  6. package/frontend/postcss.config.js +0 -6
  7. package/frontend/src/App.tsx +0 -36
  8. package/frontend/src/components/CommandPalette.tsx +0 -219
  9. package/frontend/src/components/Layout.tsx +0 -159
  10. package/frontend/src/components/ui/badge.tsx +0 -40
  11. package/frontend/src/components/ui/button.tsx +0 -53
  12. package/frontend/src/components/ui/card.tsx +0 -78
  13. package/frontend/src/components/ui/input.tsx +0 -20
  14. package/frontend/src/components/ui/label.tsx +0 -19
  15. package/frontend/src/components/ui/select.tsx +0 -71
  16. package/frontend/src/index.css +0 -130
  17. package/frontend/src/lib/utils.ts +0 -6
  18. package/frontend/src/main.tsx +0 -10
  19. package/frontend/src/pages/Dashboard.tsx +0 -231
  20. package/frontend/src/pages/OrganizationDetails.tsx +0 -1281
  21. package/frontend/src/pages/Organizations.tsx +0 -874
  22. package/frontend/src/pages/Sessions.tsx +0 -623
  23. package/frontend/src/pages/Settings.tsx +0 -1019
  24. package/frontend/src/pages/TeamDetails.tsx +0 -666
  25. package/frontend/src/pages/Users.tsx +0 -728
  26. package/frontend/tailwind.config.js +0 -75
  27. package/frontend/tsconfig.json +0 -31
  28. package/frontend/tsconfig.node.json +0 -10
  29. package/frontend/vite.config.ts +0 -31
  30. package/src/auth-adapter.ts +0 -473
  31. package/src/cli.ts +0 -51
  32. package/src/config.ts +0 -320
  33. package/src/data.ts +0 -351
  34. package/src/routes.ts +0 -1585
  35. package/src/studio.ts +0 -86
  36. package/test-project/README.md +0 -0
  37. package/test-project/better-auth.db +0 -0
  38. package/test-project/better-auth_migrations/2025-08-27T15-55-04.099Z.sql +0 -7
  39. package/test-project/better-auth_migrations/2025-09-04T02-33-19.422Z.sql +0 -7
  40. package/test-project/package.json +0 -29
  41. package/test-project/pnpm-lock.yaml +0 -1728
  42. package/test-project/src/auth.ts +0 -47
  43. package/test-project/src/index.ts +0 -40
  44. package/tsconfig.json +0 -21
@@ -1,666 +0,0 @@
1
- import { useState, useEffect } from 'react'
2
- import { useParams, Link } from 'react-router-dom'
3
- import { toast } from 'sonner'
4
- import {
5
- Users,
6
- ArrowLeft,
7
- Edit,
8
- Calendar,
9
- UserPlus,
10
- Trash2,
11
- Search,
12
- X,
13
- Building2
14
- } from 'lucide-react'
15
- import { Button } from '../components/ui/button'
16
- import { Badge } from '../components/ui/badge'
17
- import { Input } from '../components/ui/input'
18
- import { Label } from '../components/ui/label'
19
-
20
- interface Team {
21
- id: string
22
- name: string
23
- organizationId: string
24
- metadata?: any
25
- createdAt: string
26
- updatedAt: string
27
- memberCount?: number
28
- organization?: {
29
- id: string
30
- name: string
31
- }
32
- }
33
-
34
- interface TeamMember {
35
- id: string
36
- userId: string
37
- teamId: string
38
- role: string
39
- joinedAt: string
40
- user: {
41
- id: string
42
- name: string
43
- email: string
44
- image?: string
45
- emailVerified: boolean
46
- }
47
- }
48
-
49
- interface User {
50
- id: string
51
- name: string
52
- email: string
53
- image?: string
54
- emailVerified: boolean
55
- }
56
-
57
- export default function TeamDetails() {
58
- const { teamId } = useParams<{ teamId: string }>()
59
- const [team, setTeam] = useState<Team | null>(null)
60
- const [members, setMembers] = useState<TeamMember[]>([])
61
- const [loading, setLoading] = useState(true)
62
- const [activeTab, setActiveTab] = useState<'details' | 'members'>('details')
63
-
64
- // Modal states
65
- const [showAddMemberModal, setShowAddMemberModal] = useState(false)
66
- const [showEditTeamModal, setShowEditTeamModal] = useState(false)
67
-
68
- // Search and selection states
69
- const [searchTerm, setSearchTerm] = useState('')
70
- const [availableUsers, setAvailableUsers] = useState<User[]>([])
71
- const [selectedUsers, setSelectedUsers] = useState<string[]>([])
72
- const [teamFormData, setTeamFormData] = useState({ name: '' })
73
-
74
- useEffect(() => {
75
- if (teamId) {
76
- fetchTeam()
77
- fetchTeamMembers()
78
- }
79
- }, [teamId])
80
-
81
- const fetchTeam = async () => {
82
- try {
83
- const response = await fetch(`/api/teams/${teamId}`)
84
- const data = await response.json()
85
-
86
- if (data.success) {
87
- setTeam(data.team)
88
- setTeamFormData({ name: data.team.name })
89
- } else {
90
- toast.error('Team not found')
91
- }
92
- } catch (error) {
93
- console.error('Failed to fetch team:', error)
94
- toast.error('Failed to load team')
95
- } finally {
96
- setLoading(false)
97
- }
98
- }
99
-
100
- const fetchTeamMembers = async () => {
101
- try {
102
- const response = await fetch(`/api/teams/${teamId}/members`)
103
- const data = await response.json()
104
-
105
- if (data.success) {
106
- setMembers(data.members || [])
107
- }
108
- } catch (error) {
109
- console.error('Failed to fetch team members:', error)
110
- toast.error('Failed to load team members')
111
- }
112
- }
113
-
114
- const fetchAvailableUsers = async () => {
115
- try {
116
- const response = await fetch('/api/users?limit=10000')
117
- const data = await response.json()
118
-
119
- // Filter out users who are already team members
120
- const memberUserIds = members.map(member => member.userId)
121
- const available = (data.users || []).filter((user: User) =>
122
- !memberUserIds.includes(user.id)
123
- )
124
-
125
- setAvailableUsers(available)
126
- } catch (error) {
127
- console.error('Failed to fetch available users:', error)
128
- toast.error('Failed to load users')
129
- }
130
- }
131
-
132
- const handleUpdateTeam = async () => {
133
- if (!teamFormData.name) {
134
- toast.error('Please enter a team name')
135
- return
136
- }
137
-
138
- const toastId = toast.loading('Updating team...')
139
-
140
- try {
141
- const response = await fetch(`/api/teams/${teamId}`, {
142
- method: 'PUT',
143
- headers: { 'Content-Type': 'application/json' },
144
- body: JSON.stringify({ name: teamFormData.name })
145
- })
146
-
147
- const result = await response.json()
148
-
149
- if (result.success) {
150
- await fetchTeam()
151
- setShowEditTeamModal(false)
152
- toast.success('Team updated successfully!', { id: toastId })
153
- } else {
154
- toast.error(`Error updating team: ${result.error || 'Unknown error'}`, { id: toastId })
155
- }
156
- } catch (error) {
157
- console.error('Error updating team:', error)
158
- toast.error('Error updating team', { id: toastId })
159
- }
160
- }
161
-
162
- const handleAddMembers = async () => {
163
- if (selectedUsers.length === 0) {
164
- toast.error('Please select at least one user')
165
- return
166
- }
167
-
168
- const toastId = toast.loading(`Adding ${selectedUsers.length} members...`)
169
-
170
- try {
171
- const response = await fetch(`/api/teams/${teamId}/members`, {
172
- method: 'POST',
173
- headers: { 'Content-Type': 'application/json' },
174
- body: JSON.stringify({ userIds: selectedUsers })
175
- })
176
-
177
- const result = await response.json()
178
-
179
- if (result.success) {
180
- await fetchTeamMembers()
181
- setShowAddMemberModal(false)
182
- setSelectedUsers([])
183
- setSearchTerm('')
184
- toast.success(`Successfully added ${selectedUsers.length} members!`, { id: toastId })
185
- } else {
186
- toast.error(`Error adding members: ${result.error || 'Unknown error'}`, { id: toastId })
187
- }
188
- } catch (error) {
189
- console.error('Error adding members:', error)
190
- toast.error('Error adding members', { id: toastId })
191
- }
192
- }
193
-
194
- const handleRemoveTeamMember = async (memberId: string, userName: string) => {
195
- const toastId = toast.loading(`Removing ${userName}...`)
196
-
197
- try {
198
- const response = await fetch(`/api/team-members/${memberId}`, {
199
- method: 'DELETE',
200
- headers: { 'Content-Type': 'application/json' }
201
- })
202
-
203
- const result = await response.json()
204
-
205
- if (result.success) {
206
- await fetchTeamMembers()
207
- toast.success(`${userName} removed from team!`, { id: toastId })
208
- } else {
209
- toast.error(`Error removing member: ${result.error || 'Unknown error'}`, { id: toastId })
210
- }
211
- } catch (error) {
212
- console.error('Error removing team member:', error)
213
- toast.error('Error removing team member', { id: toastId })
214
- }
215
- }
216
-
217
- const openAddMemberModal = () => {
218
- fetchAvailableUsers()
219
- setShowAddMemberModal(true)
220
- }
221
-
222
- const toggleUserSelection = (userId: string) => {
223
- setSelectedUsers(prev =>
224
- prev.includes(userId)
225
- ? prev.filter(id => id !== userId)
226
- : [...prev, userId]
227
- )
228
- }
229
-
230
- const filteredUsers = availableUsers.filter(user =>
231
- user.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
232
- user.email.toLowerCase().includes(searchTerm.toLowerCase())
233
- )
234
-
235
- if (loading) {
236
- return (
237
- <div className="flex items-center justify-center h-64">
238
- <div className="text-white">Loading team details...</div>
239
- </div>
240
- )
241
- }
242
-
243
- if (!team) {
244
- return (
245
- <div className="space-y-6 p-6">
246
- <div className="flex items-center space-x-4">
247
- <Link to="/organizations">
248
- <Button variant="ghost" className="text-gray-400 hover:text-white rounded-none">
249
- <ArrowLeft className="w-4 h-4 mr-2" />
250
- Back to Organizations
251
- </Button>
252
- </Link>
253
- </div>
254
- <div className="text-center py-12">
255
- <Users className="w-16 h-16 text-gray-400 mx-auto mb-4" />
256
- <h2 className="text-xl text-white font-light mb-2">Team Not Found</h2>
257
- <p className="text-gray-400">The team you're looking for doesn't exist.</p>
258
- </div>
259
- </div>
260
- )
261
- }
262
-
263
- return (
264
- <div className="space-y-6 p-6">
265
- {/* Header */}
266
- <div className="flex items-center justify-between">
267
- <div className="flex items-center space-x-4">
268
- <Link to={`/organizations/${team.organizationId}`}>
269
- <Button variant="ghost" className="text-gray-400 hover:text-white rounded-none">
270
- <ArrowLeft className="w-4 h-4 mr-2" />
271
- Back to Organization
272
- </Button>
273
- </Link>
274
- </div>
275
-
276
- <div className="flex items-center space-x-3">
277
- <Button
278
- onClick={openAddMemberModal}
279
- className="border border-dashed border-white/20 text-white hover:bg-white/10 bg-transparent rounded-none"
280
- >
281
- <UserPlus className="w-4 h-4 mr-2" />
282
- Add Members
283
- </Button>
284
- <Button
285
- onClick={() => setShowEditTeamModal(true)}
286
- className="bg-white hover:bg-white/90 text-black border border-white/20 rounded-none"
287
- >
288
- <Edit className="w-4 h-4 mr-2" />
289
- Edit Team
290
- </Button>
291
- </div>
292
- </div>
293
-
294
- <div className="flex items-center space-x-3">
295
- <div className="w-12 h-12 bg-white/10 border border-dashed border-white/20 rounded-none flex items-center justify-center">
296
- <Users className="w-6 h-6 text-white" />
297
- </div>
298
- <div>
299
- <h1 className="text-2xl text-white font-light">{team.name}</h1>
300
- <div className="flex items-center space-x-2">
301
- {team.organization && (
302
- <Link to={`/organizations/${team.organizationId}`} className="text-gray-400 hover:text-white text-sm">
303
- <Building2 className="w-4 h-4 inline mr-1" />
304
- {team.organization.name}
305
- </Link>
306
- )}
307
- </div>
308
- </div>
309
- </div>
310
-
311
- {/* Tabs */}
312
- <div className="border-b border-white/10">
313
- <nav className="flex space-x-8">
314
- <button
315
- onClick={() => setActiveTab('details')}
316
- className={`flex items-center space-x-2 px-3 py-4 text-sm font-medium border-b-2 transition-all duration-200 ${
317
- activeTab === 'details'
318
- ? 'border-white text-white'
319
- : 'border-transparent text-gray-400 hover:text-white hover:border-gray-300'
320
- }`}
321
- >
322
- <Users className="w-4 h-4" />
323
- <span>Details</span>
324
- </button>
325
- <button
326
- onClick={() => setActiveTab('members')}
327
- className={`flex items-center space-x-2 px-3 py-4 text-sm font-medium border-b-2 transition-all duration-200 ${
328
- activeTab === 'members'
329
- ? 'border-white text-white'
330
- : 'border-transparent text-gray-400 hover:text-white hover:border-gray-300'
331
- }`}
332
- >
333
- <Users className="w-4 h-4" />
334
- <span>Members</span>
335
- {members.length > 0 && (
336
- <Badge variant="secondary" className="text-xs bg-white/10 border border-white/20 rounded-sm">
337
- {members.length}
338
- </Badge>
339
- )}
340
- </button>
341
- </nav>
342
- </div>
343
-
344
- {/* Tab Content */}
345
- {activeTab === 'details' && (
346
- <div className="space-y-6">
347
- {/* Team Information */}
348
- <div className="bg-black/30 border border-dashed border-white/20 rounded-none p-6">
349
- <h3 className="text-lg text-white font-light mb-4">Team Information</h3>
350
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
351
- <div>
352
- <label className="text-sm text-gray-400 font-light">Name</label>
353
- <p className="text-white mt-1">{team.name}</p>
354
- </div>
355
- <div>
356
- <label className="text-sm text-gray-400 font-light">Organization</label>
357
- <p className="text-white mt-1">{team.organization?.name || 'Unknown'}</p>
358
- </div>
359
- <div>
360
- <label className="text-sm text-gray-400 font-light">Created</label>
361
- <p className="text-white mt-1">
362
- {new Date(team.createdAt).toLocaleDateString('en-US', {
363
- year: 'numeric',
364
- month: 'long',
365
- day: 'numeric'
366
- })}
367
- </p>
368
- </div>
369
- <div>
370
- <label className="text-sm text-gray-400 font-light">Last Updated</label>
371
- <p className="text-white mt-1">
372
- {new Date(team.updatedAt).toLocaleDateString('en-US', {
373
- year: 'numeric',
374
- month: 'long',
375
- day: 'numeric'
376
- })}
377
- </p>
378
- </div>
379
- </div>
380
- </div>
381
-
382
- {/* Team Stats */}
383
- <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
384
- <div className="bg-black/30 border border-dashed border-white/20 rounded-none p-6">
385
- <div className="flex items-center space-x-3">
386
- <Users className="w-8 h-8 text-white" />
387
- <div>
388
- <p className="text-2xl text-white font-light">{members.length}</p>
389
- <p className="text-sm text-gray-400">Members</p>
390
- </div>
391
- </div>
392
- </div>
393
- <div className="bg-black/30 border border-dashed border-white/20 rounded-none p-6">
394
- <div className="flex items-center space-x-3">
395
- <Calendar className="w-8 h-8 text-white" />
396
- <div>
397
- <p className="text-2xl text-white font-light">
398
- {Math.ceil((new Date().getTime() - new Date(team.createdAt).getTime()) / (1000 * 60 * 60 * 24))}
399
- </p>
400
- <p className="text-sm text-gray-400">Days Active</p>
401
- </div>
402
- </div>
403
- </div>
404
- <div className="bg-black/30 border border-dashed border-white/20 rounded-none p-6">
405
- <div className="flex items-center space-x-3">
406
- <Building2 className="w-8 h-8 text-white" />
407
- <div>
408
- <p className="text-2xl text-white font-light">1</p>
409
- <p className="text-sm text-gray-400">Organization</p>
410
- </div>
411
- </div>
412
- </div>
413
- </div>
414
- </div>
415
- )}
416
-
417
- {activeTab === 'members' && (
418
- <div className="space-y-6">
419
- {/* Members Header */}
420
- <div className="flex items-center justify-between">
421
- <div>
422
- <h3 className="text-lg text-white font-light">Team Members ({members.length})</h3>
423
- <p className="text-gray-400 mt-1">Manage members of this team</p>
424
- </div>
425
- </div>
426
-
427
- {/* Members List */}
428
- {members.length > 0 ? (
429
- <div className="bg-black/30 border border-dashed border-white/20 rounded-none">
430
- <div className="overflow-x-auto">
431
- <table className="w-full">
432
- <thead>
433
- <tr className="border-b border-dashed border-white/10">
434
- <th className="text-left py-4 px-4 text-white font-light">User</th>
435
- <th className="text-left py-4 px-4 text-white font-light">Email</th>
436
- <th className="text-left py-4 px-4 text-white font-light">Role</th>
437
- <th className="text-left py-4 px-4 text-white font-light">Joined</th>
438
- <th className="text-right py-4 px-4 text-white font-light">Actions</th>
439
- </tr>
440
- </thead>
441
- <tbody>
442
- {members.map((member) => (
443
- <tr key={member.id} className="border-b border-dashed border-white/5 hover:bg-white/5">
444
- <td className="py-4 px-4">
445
- <div className="flex items-center space-x-3">
446
- <img
447
- src={member.user.image || `https://api.dicebear.com/7.x/avataaars/svg?seed=${member.user.id}`}
448
- alt={member.user.name}
449
- className="w-10 h-10 rounded-none border border-dashed border-white/20"
450
- />
451
- <div>
452
- <div className="text-white font-light">{member.user.name}</div>
453
- <div className="text-sm text-gray-400">ID: {member.user.id}</div>
454
- </div>
455
- </div>
456
- </td>
457
- <td className="py-4 px-4 text-white">{member.user.email}</td>
458
- <td className="py-4 px-4">
459
- <Badge variant="secondary" className="text-xs bg-blue-900/10 border border-dashed border-blue-500/30 text-blue-400/70 rounded-none capitalize">
460
- {member.role}
461
- </Badge>
462
- </td>
463
- <td className="py-4 px-4 text-sm text-gray-400">
464
- {new Date(member.joinedAt).toLocaleDateString()}
465
- </td>
466
- <td className="py-4 px-4 text-right">
467
- <div className="flex items-center justify-end space-x-2">
468
- <Button
469
- variant="outline"
470
- size="sm"
471
- className="border border-dashed border-red-400/50 text-red-400 hover:bg-red-400/10 rounded-none"
472
- onClick={() => handleRemoveTeamMember(member.id, member.user.name)}
473
- >
474
- <Trash2 className="w-4 h-4 mr-1" />
475
- Remove
476
- </Button>
477
- </div>
478
- </td>
479
- </tr>
480
- ))}
481
- </tbody>
482
- </table>
483
- </div>
484
- </div>
485
- ) : (
486
- <div className="bg-black/30 border border-dashed border-white/20 rounded-none p-12">
487
- <div className="text-center">
488
- <Users className="w-16 h-16 text-gray-400 mx-auto mb-4" />
489
- <h3 className="text-xl text-white font-light mb-2">No Members Yet</h3>
490
- <p className="text-gray-400 mb-6">
491
- Add members to this team to get started.
492
- </p>
493
- <Button
494
- onClick={openAddMemberModal}
495
- className="bg-white hover:bg-white/90 text-black border border-white/20 rounded-none"
496
- >
497
- <UserPlus className="w-4 h-4 mr-2" />
498
- Add First Members
499
- </Button>
500
- </div>
501
- </div>
502
- )}
503
- </div>
504
- )}
505
-
506
- {/* Add Members Modal */}
507
- {showAddMemberModal && (
508
- <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
509
- <div className="bg-black/90 border border-dashed border-white/20 p-6 w-full max-w-2xl rounded-none">
510
- <div className="flex items-center justify-between mb-6">
511
- <h3 className="text-lg text-white font-light">Add Team Members</h3>
512
- <Button
513
- variant="ghost"
514
- size="sm"
515
- onClick={() => {
516
- setShowAddMemberModal(false)
517
- setSelectedUsers([])
518
- setSearchTerm('')
519
- }}
520
- className="text-gray-400 hover:text-white rounded-none"
521
- >
522
- <X className="w-4 h-4" />
523
- </Button>
524
- </div>
525
-
526
- <div className="space-y-4">
527
- {/* Search */}
528
- <div className="relative">
529
- <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
530
- <Input
531
- placeholder="Search users by name or email..."
532
- value={searchTerm}
533
- onChange={(e) => setSearchTerm(e.target.value)}
534
- className="pl-10 border border-dashed border-white/20 bg-black/30 text-white rounded-none"
535
- />
536
- </div>
537
-
538
- {/* Selected Count */}
539
- {selectedUsers.length > 0 && (
540
- <div className="bg-blue-900/20 border border-blue-500/30 rounded-none p-3">
541
- <p className="text-blue-400 text-sm">
542
- {selectedUsers.length} user{selectedUsers.length !== 1 ? 's' : ''} selected
543
- </p>
544
- </div>
545
- )}
546
-
547
- {/* User List */}
548
- <div className="bg-black/30 border border-dashed border-white/20 rounded-none max-h-96 overflow-y-auto">
549
- {filteredUsers.length > 0 ? (
550
- <div className="divide-y divide-white/5">
551
- {filteredUsers.map((user) => (
552
- <div
553
- key={user.id}
554
- className={`flex items-center space-x-3 p-4 cursor-pointer hover:bg-white/5 ${
555
- selectedUsers.includes(user.id) ? 'bg-blue-900/20' : ''
556
- }`}
557
- onClick={() => toggleUserSelection(user.id)}
558
- >
559
- <input
560
- type="checkbox"
561
- checked={selectedUsers.includes(user.id)}
562
- onChange={() => toggleUserSelection(user.id)}
563
- className="rounded border-gray-300"
564
- />
565
- <img
566
- src={user.image || `https://api.dicebear.com/7.x/avataaars/svg?seed=${user.id}`}
567
- alt={user.name}
568
- className="w-10 h-10 rounded-none border border-dashed border-white/20"
569
- />
570
- <div className="flex-1">
571
- <div className="text-white font-light">{user.name}</div>
572
- <div className="text-sm text-gray-400">{user.email}</div>
573
- </div>
574
- </div>
575
- ))}
576
- </div>
577
- ) : (
578
- <div className="p-8 text-center">
579
- <p className="text-gray-400">No users found matching your search.</p>
580
- </div>
581
- )}
582
- </div>
583
- </div>
584
-
585
- <div className="flex justify-end space-x-3 mt-6">
586
- <Button
587
- variant="outline"
588
- onClick={() => {
589
- setShowAddMemberModal(false)
590
- setSelectedUsers([])
591
- setSearchTerm('')
592
- }}
593
- className="border border-dashed border-white/20 text-white hover:bg-white/10 rounded-none"
594
- >
595
- Cancel
596
- </Button>
597
- <Button
598
- onClick={handleAddMembers}
599
- disabled={selectedUsers.length === 0}
600
- className="bg-white hover:bg-white/90 text-black border border-white/20 rounded-none disabled:opacity-50"
601
- >
602
- <UserPlus className="w-4 h-4 mr-2" />
603
- Add {selectedUsers.length} Member{selectedUsers.length !== 1 ? 's' : ''}
604
- </Button>
605
- </div>
606
- </div>
607
- </div>
608
- )}
609
-
610
- {/* Edit Team Modal */}
611
- {showEditTeamModal && (
612
- <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
613
- <div className="bg-black/90 border border-dashed border-white/20 p-6 w-full max-w-md rounded-none">
614
- <div className="flex items-center justify-between mb-4">
615
- <h3 className="text-lg text-white font-light">Edit Team</h3>
616
- <Button
617
- variant="ghost"
618
- size="sm"
619
- onClick={() => setShowEditTeamModal(false)}
620
- className="text-gray-400 hover:text-white rounded-none"
621
- >
622
- <X className="w-4 h-4" />
623
- </Button>
624
- </div>
625
- <div className="space-y-4">
626
- <div className="flex items-center space-x-3">
627
- <div className="w-16 h-16 bg-white/10 border border-dashed border-white/20 rounded-none flex items-center justify-center">
628
- <Users className="w-8 h-8 text-white" />
629
- </div>
630
- <div>
631
- <div className="text-white font-light">{team.name}</div>
632
- <div className="text-sm text-gray-400">{team.organization?.name}</div>
633
- </div>
634
- </div>
635
- <div>
636
- <Label htmlFor="edit-team-name" className="text-sm text-gray-400 font-light">Team Name</Label>
637
- <Input
638
- id="edit-team-name"
639
- value={teamFormData.name}
640
- onChange={(e) => setTeamFormData({ name: e.target.value })}
641
- placeholder="e.g. Development Team"
642
- className="mt-1 border border-dashed border-white/20 bg-black/30 text-white rounded-none"
643
- />
644
- </div>
645
- </div>
646
- <div className="flex justify-end space-x-3 mt-6">
647
- <Button
648
- variant="outline"
649
- onClick={() => setShowEditTeamModal(false)}
650
- className="border border-dashed border-white/20 text-white hover:bg-white/10 rounded-none"
651
- >
652
- Cancel
653
- </Button>
654
- <Button
655
- onClick={handleUpdateTeam}
656
- className="bg-white hover:bg-white/90 text-black border border-white/20 rounded-none"
657
- >
658
- Update Team
659
- </Button>
660
- </div>
661
- </div>
662
- </div>
663
- )}
664
- </div>
665
- )
666
- }