1+ import { useState } from "react" ;
12import { useOrganizationStateStore } from "@/lib/providers/organization-state-store-provider" ;
23import { useAuthStore } from "@/lib/providers/auth-store-provider" ;
34import { useUserMutation } from "@/lib/api/organizations/users" ;
45import { Button } from "@/components/ui/button" ;
5- import { Trash2 } from "lucide-react" ;
6- import { CoachingRelationshipWithUserNames } from "@/types/coaching_relationship_with_user_names" ;
6+ import {
7+ DropdownMenu ,
8+ DropdownMenuTrigger ,
9+ DropdownMenuContent ,
10+ DropdownMenuItem ,
11+ DropdownMenuSeparator ,
12+ } from "@/components/ui/dropdown-menu" ;
13+ import { MoreHorizontal , Trash2 } from "lucide-react" ;
14+ import {
15+ Dialog ,
16+ DialogContent ,
17+ DialogDescription ,
18+ DialogHeader ,
19+ DialogFooter ,
20+ DialogTitle ,
21+ } from "@/components/ui/dialog" ;
22+ import {
23+ Select ,
24+ SelectTrigger ,
25+ SelectValue ,
26+ SelectContent ,
27+ SelectItem ,
28+ } from "@/components/ui/select" ;
29+ import { CoachingRelationshipWithUserNames } from "@/types/coaching_relationship" ;
730import { OrganizationStateStore } from "@/lib/stores/organization-state-store" ;
831import { AuthStore } from "@/lib/stores/auth-store" ;
932import { Id } from "@/types/general" ;
33+ import { User , Role } from "@/types/user" ;
34+ import { useCoachingRelationshipMutation } from "@/lib/api/coaching-relationships" ;
35+ import { toast } from "sonner" ;
1036
1137interface MemberCardProps {
1238 firstName : string ;
@@ -15,6 +41,13 @@ interface MemberCardProps {
1541 userId : Id ;
1642 userRelationships : CoachingRelationshipWithUserNames [ ] ;
1743 onRefresh : ( ) => void ;
44+ users : User [ ] ;
45+ }
46+
47+ interface Member {
48+ id : Id ;
49+ first_name : string ;
50+ last_name : string ;
1851}
1952
2053export function MemberCard ( {
@@ -24,31 +57,84 @@ export function MemberCard({
2457 userId,
2558 userRelationships,
2659 onRefresh,
60+ users,
2761} : MemberCardProps ) {
2862 const currentOrganizationId = useOrganizationStateStore (
2963 ( state : OrganizationStateStore ) => state . currentOrganizationId
3064 ) ;
31- const { userSession } = useAuthStore ( ( state : AuthStore ) => state ) ;
32- const { deleteNested : deleteUser } = useUserMutation ( currentOrganizationId ) ;
65+ const { isACoach, userSession } = useAuthStore ( ( state : AuthStore ) => state ) ;
66+ const { error : deleteError , deleteNested : deleteUser } = useUserMutation ( currentOrganizationId ) ;
67+ const { error : createError , createNested : createRelationship } = useCoachingRelationshipMutation ( currentOrganizationId ) ;
68+
69+ console . log ( "is a coach" , isACoach ) ;
3370
3471 // Check if current user is a coach in any of this user's relationships
35- // and make sure we can't delete ourselves
36- const canDeleteUser = userRelationships . some (
72+ // and make sure we can't delete ourselves. Admins can delete any user.
73+ const canDeleteUser = ( userRelationships ? .some (
3774 ( rel ) => rel . coach_id === userSession . id && userId !== userSession . id
38- ) ;
75+ ) || ( userSession . role === Role . Admin ) ) && userSession . id !== userId ;
3976
4077 const handleDelete = async ( ) => {
4178 if ( ! confirm ( "Are you sure you want to delete this member?" ) ) {
4279 return ;
4380 }
81+ await deleteUser ( currentOrganizationId , userId ) ;
82+ onRefresh ( ) ;
4483
45- try {
46- await deleteUser ( currentOrganizationId , userId ) ;
84+ if ( deleteError ) {
85+ console . error ( "Error deleting member:" , deleteError ) ;
86+ toast . error ( "Error deleting member" ) ;
4787 onRefresh ( ) ;
48- } catch ( error ) {
49- console . error ( "Error deleting user:" , error ) ;
50- // TODO: Show an error toast here once we start using toasts for showing operation results.
88+ return ;
89+ }
90+ toast . success ( "Member deleted successfully" ) ;
91+ onRefresh ( ) ;
92+ } ;
93+
94+ const handleAssignMember = ( val : string ) => {
95+ const user = users . find ( ( m ) => m . id === val ) ;
96+ if ( ! user ) return ;
97+ const member : Member = {
98+ id : user . id ,
99+ first_name : user . first_name ,
100+ last_name : user . last_name ,
101+ } ;
102+ setAssignedMember ( member ) ;
103+ } ;
104+
105+ // Placeholder – actual UI flows will be implemented later
106+ const [ assignDialogOpen , setAssignDialogOpen ] = useState ( false ) ;
107+ const [ assignMode , setAssignMode ] = useState < "coach" | "coachee" > ( "coach" ) ;
108+ const [ selectedMember , setSelectedMember ] = useState < Member | null > ( null ) ;
109+ const [ assignedMember , setAssignedMember ] = useState < Member | null > ( null ) ;
110+
111+ const handleCreateCoachingRelationship = ( ) => {
112+ if ( ! selectedMember || ! assignedMember ) return ;
113+
114+ if ( assignMode === "coach" ) {
115+ console . log ( "Assign" , selectedMember . id , "as coach for" , userId ) ;
116+ createRelationship ( currentOrganizationId , {
117+ coach_id : assignedMember . id ,
118+ coachee_id : selectedMember . id ,
119+ } ) ;
120+ } else {
121+ console . log ( "Assign" , selectedMember . id , "as coachee for" , userId ) ;
122+ createRelationship ( currentOrganizationId , {
123+ coach_id : selectedMember . id ,
124+ coachee_id : assignedMember . id ,
125+ } ) ;
51126 }
127+
128+ if ( createError ) {
129+ toast . error ( `Error assigning ${ assignMode } ` ) ;
130+ return ;
131+ }
132+
133+ toast . success ( `Successfully assigned ${ assignedMember . first_name } ${ assignedMember . last_name } as ${ assignMode } for ${ selectedMember . first_name } ${ selectedMember . last_name } ` ) ;
134+ onRefresh ( ) ;
135+ setAssignDialogOpen ( false ) ;
136+ setSelectedMember ( null ) ;
137+ setAssignedMember ( null ) ;
52138 } ;
53139
54140 return (
@@ -59,16 +145,82 @@ export function MemberCard({
59145 </ h3 >
60146 { email && < p className = "text-sm text-muted-foreground" > { email } </ p > }
61147 </ div >
62- { canDeleteUser && (
63- < Button
64- variant = "ghost"
65- size = "icon"
66- onClick = { handleDelete }
67- className = "text-destructive hover:text-destructive"
68- >
69- < Trash2 className = "h-4 w-4" />
70- </ Button >
71- ) }
148+ { ( isACoach || userSession . role === Role . Admin ) && (
149+ < DropdownMenu >
150+ < DropdownMenuTrigger asChild >
151+ < Button variant = "ghost" size = "icon" className = "text-muted-foreground" >
152+ < MoreHorizontal className = "h-4 w-4" />
153+ </ Button >
154+ </ DropdownMenuTrigger >
155+ < DropdownMenuContent align = "end" >
156+ { userSession . role === Role . Admin && (
157+ < >
158+ < DropdownMenuItem
159+ onClick = { ( ) => {
160+ setAssignMode ( "coach" ) ;
161+ setAssignDialogOpen ( true ) ;
162+ setSelectedMember ( { id : userId , first_name : firstName , last_name : lastName } ) ;
163+ } }
164+ >
165+ Assign Coach
166+ </ DropdownMenuItem >
167+ < DropdownMenuItem
168+ onClick = { ( ) => {
169+ setAssignMode ( "coachee" ) ;
170+ setAssignDialogOpen ( true ) ;
171+ setSelectedMember ( { id : userId , first_name : firstName , last_name : lastName } ) ;
172+ } }
173+ >
174+ Assign Coachee
175+ </ DropdownMenuItem >
176+ </ >
177+ ) }
178+ { canDeleteUser && (
179+ < >
180+ < DropdownMenuSeparator />
181+ < DropdownMenuItem
182+ onClick = { handleDelete }
183+ className = "text-destructive focus:text-destructive"
184+ >
185+ < Trash2 className = "mr-2 h-4 w-4" /> Delete
186+ </ DropdownMenuItem >
187+ </ >
188+ ) }
189+ </ DropdownMenuContent >
190+ </ DropdownMenu >
191+ ) }
192+
193+ { /* Assign Coach/Coachee Modal */ }
194+ < Dialog open = { assignDialogOpen } onOpenChange = { setAssignDialogOpen } >
195+ < DialogContent >
196+ < DialogHeader >
197+ < DialogTitle >
198+ { assignMode === "coach" ? "Assign Coach" : "Assign Coachee" }
199+ </ DialogTitle >
200+ < DialogDescription >
201+ Select a member to be their { assignMode === "coach" ? "coach" : "coachee" }
202+ </ DialogDescription >
203+ </ DialogHeader >
204+ < Select
205+ onValueChange = { ( val ) => handleAssignMember ( val ) }
206+ value = { assignedMember ?. id ?. toString ( ) }
207+ >
208+ < SelectTrigger className = "w-full" >
209+ < SelectValue placeholder = "Select a member" />
210+ </ SelectTrigger >
211+ < SelectContent >
212+ { users
213+ . filter ( ( m ) => m . id !== userId )
214+ . map ( ( m ) => (
215+ < SelectItem key = { m . id } value = { m . id . toString ( ) } > { `${ m . first_name } ${ m . last_name } ` } </ SelectItem >
216+ ) ) }
217+ </ SelectContent >
218+ </ Select >
219+ < DialogFooter >
220+ < Button onClick = { handleCreateCoachingRelationship } > { assignMode === "coach" ? "Assign as Coach" : "Assign as Coachee" } </ Button >
221+ </ DialogFooter >
222+ </ DialogContent >
223+ </ Dialog >
72224 </ div >
73225 ) ;
74226}
0 commit comments