Skip to content

Commit f8c0925

Browse files
committed
add UI for assigning coach/coachee
1 parent 9250c7e commit f8c0925

File tree

2 files changed

+114
-13
lines changed

2 files changed

+114
-13
lines changed

src/components/ui/members/member-card.tsx

Lines changed: 113 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,35 @@
1+
import { useState } from "react";
12
import { useOrganizationStateStore } from "@/lib/providers/organization-state-store-provider";
23
import { useAuthStore } from "@/lib/providers/auth-store-provider";
34
import { useUserMutation } from "@/lib/api/organizations/users";
45
import { Button } from "@/components/ui/button";
5-
import { Trash2 } from "lucide-react";
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+
DialogHeader,
18+
DialogFooter,
19+
DialogTitle,
20+
} from "@/components/ui/dialog";
21+
import {
22+
Select,
23+
SelectTrigger,
24+
SelectValue,
25+
SelectContent,
26+
SelectItem,
27+
} from "@/components/ui/select";
628
import { CoachingRelationshipWithUserNames } from "@/types/coaching_relationship_with_user_names";
729
import { OrganizationStateStore } from "@/lib/stores/organization-state-store";
830
import { AuthStore } from "@/lib/stores/auth-store";
931
import { Id } from "@/types/general";
10-
import { Role } from "@/types/user";
32+
import { User, Role } from "@/types/user";
1133

1234
interface MemberCardProps {
1335
firstName: string;
@@ -16,6 +38,7 @@ interface MemberCardProps {
1638
userId: Id;
1739
userRelationships: CoachingRelationshipWithUserNames[];
1840
onRefresh: () => void;
41+
users: User[];
1942
}
2043

2144
export function MemberCard({
@@ -25,6 +48,7 @@ export function MemberCard({
2548
userId,
2649
userRelationships,
2750
onRefresh,
51+
users,
2852
}: MemberCardProps) {
2953
const currentOrganizationId = useOrganizationStateStore(
3054
(state: OrganizationStateStore) => state.currentOrganizationId
@@ -36,7 +60,7 @@ export function MemberCard({
3660
// and make sure we can't delete ourselves. Admins can delete any user.
3761
const canDeleteUser = userRelationships?.some(
3862
(rel) => rel.coach_id === userSession.id && userId !== userSession.id
39-
) || userSession.role === Role.Admin;
63+
) || (userSession.role === Role.Admin && userSession.id !== userId);
4064

4165
const handleDelete = async () => {
4266
if (!confirm("Are you sure you want to delete this member?")) {
@@ -52,6 +76,23 @@ export function MemberCard({
5276
}
5377
};
5478

79+
// Placeholder – actual UI flows will be implemented later
80+
const [assignDialogOpen, setAssignDialogOpen] = useState(false);
81+
const [assignMode, setAssignMode] = useState<"coach" | "coachee">("coach");
82+
const [selectedMemberId, setSelectedMemberId] = useState<Id | null>(null);
83+
84+
const handleCreateCoachingRelationship = () => {
85+
if (!selectedMemberId) return;
86+
if (assignMode === "coach") {
87+
console.log("Assign", selectedMemberId, "as coach for", userId);
88+
} else {
89+
console.log("Assign", selectedMemberId, "as coachee for", userId);
90+
}
91+
// TODO: call mutation
92+
setAssignDialogOpen(false);
93+
setSelectedMemberId(null);
94+
};
95+
5596
return (
5697
<div className="flex items-center p-4 hover:bg-accent/50 transition-colors">
5798
<div className="flex-1">
@@ -60,16 +101,75 @@ export function MemberCard({
60101
</h3>
61102
{email && <p className="text-sm text-muted-foreground">{email}</p>}
62103
</div>
63-
{canDeleteUser && (
64-
<Button
65-
variant="ghost"
66-
size="icon"
67-
onClick={handleDelete}
68-
className="text-destructive hover:text-destructive"
69-
>
70-
<Trash2 className="h-4 w-4" />
71-
</Button>
72-
)}
104+
<DropdownMenu>
105+
<DropdownMenuTrigger asChild>
106+
<Button variant="ghost" size="icon" className="text-muted-foreground">
107+
<MoreHorizontal className="h-4 w-4" />
108+
</Button>
109+
</DropdownMenuTrigger>
110+
<DropdownMenuContent align="end">
111+
{userSession.role === Role.Admin && (
112+
<>
113+
<DropdownMenuItem
114+
onClick={() => {
115+
setAssignMode("coach");
116+
setAssignDialogOpen(true);
117+
}}
118+
>
119+
Assign Coach
120+
</DropdownMenuItem>
121+
<DropdownMenuItem
122+
onClick={() => {
123+
setAssignMode("coachee");
124+
setAssignDialogOpen(true);
125+
}}
126+
>
127+
Assign Coachee
128+
</DropdownMenuItem>
129+
</>
130+
)}
131+
{canDeleteUser && (
132+
<>
133+
<DropdownMenuSeparator />
134+
<DropdownMenuItem
135+
onClick={handleDelete}
136+
className="text-destructive focus:text-destructive"
137+
>
138+
<Trash2 className="mr-2 h-4 w-4" /> Delete
139+
</DropdownMenuItem>
140+
</>
141+
)}
142+
</DropdownMenuContent>
143+
</DropdownMenu>
144+
145+
{/* Assign Coach/Coachee Modal */}
146+
<Dialog open={assignDialogOpen} onOpenChange={setAssignDialogOpen}>
147+
<DialogContent>
148+
<DialogHeader>
149+
<DialogTitle>
150+
{assignMode === "coach" ? "Assign Coach" : "Assign Coachee"}
151+
</DialogTitle>
152+
</DialogHeader>
153+
<Select
154+
onValueChange={(val) => setSelectedMemberId(val as Id)}
155+
value={selectedMemberId ?? undefined}
156+
>
157+
<SelectTrigger className="w-full">
158+
<SelectValue placeholder="Select a member" />
159+
</SelectTrigger>
160+
<SelectContent>
161+
{users
162+
.filter((m) => m.id !== userId)
163+
.map((m) => (
164+
<SelectItem key={m.id} value={m.id.toString()}>{`${m.first_name} ${m.last_name}`}</SelectItem>
165+
))}
166+
</SelectContent>
167+
</Select>
168+
<DialogFooter>
169+
<Button onClick={handleCreateCoachingRelationship}>{assignMode === "coach" ? "Assign as Coach" : "Assign as Coachee"}</Button>
170+
</DialogFooter>
171+
</DialogContent>
172+
</Dialog>
73173
</div>
74174
);
75175
}

src/components/ui/members/member-list.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export function MemberList({
3636
userId={user.id}
3737
userRelationships={userRelationshipsMap[user.id]}
3838
onRefresh={onRefresh}
39+
users={users}
3940
/>
4041
))}
4142
</div>

0 commit comments

Comments
 (0)