Skip to content

Commit fa2d879

Browse files
committed
add new user
1 parent dff44b0 commit fa2d879

File tree

4 files changed

+125
-63
lines changed

4 files changed

+125
-63
lines changed

src/components/ui/members/add-member-dialog.tsx

Lines changed: 110 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
DialogContent,
1010
DialogHeader,
1111
DialogTitle,
12+
DialogDescription,
13+
DialogFooter,
1214
} from "@/components/ui/dialog";
1315
import { Label } from "@/components/ui/label";
1416
import { Input } from "@/components/ui/input";
@@ -39,8 +41,12 @@ export function AddMemberDialog({
3941
lastName: "",
4042
displayName: "",
4143
email: "",
44+
password: "",
45+
confirmPassword: "", // For validation
4246
});
4347

48+
const [passwordError, setPasswordError] = useState("");
49+
4450
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
4551
const { name, value } = e.target;
4652
setFormData((prev) => ({
@@ -52,80 +58,126 @@ export function AddMemberDialog({
5258
const handleSubmit = async (e: React.FormEvent) => {
5359
e.preventDefault();
5460

61+
// Validate passwords match
62+
// we may want to add other validations in the future
63+
if (formData.password !== formData.confirmPassword) {
64+
setPasswordError("Passwords do not match");
65+
return;
66+
}
67+
5568
const newUser: NewUser = {
5669
first_name: formData.firstName,
5770
last_name: formData.lastName,
5871
display_name: formData.displayName,
5972
email: formData.email,
73+
password: formData.password, // Add password to the NewUser type
6074
};
6175

62-
await createUserNested(currentOrganizationId, newUser);
63-
setFormData({
64-
firstName: "",
65-
lastName: "",
66-
displayName: "",
67-
email: "",
68-
});
69-
// SWR Refresh
70-
onMemberAdded();
71-
onOpenChange(false);
76+
try {
77+
await createUserNested(currentOrganizationId, newUser);
78+
setFormData({
79+
firstName: "",
80+
lastName: "",
81+
displayName: "",
82+
email: "",
83+
password: "",
84+
confirmPassword: "",
85+
});
86+
setPasswordError("");
87+
onMemberAdded();
88+
onOpenChange(false);
89+
} catch (error) {
90+
console.error("Error creating user:", error);
91+
// Handle error appropriately
92+
}
7293
};
7394

7495
return (
7596
<Dialog open={open} onOpenChange={onOpenChange}>
7697
<DialogContent>
7798
<DialogHeader>
7899
<DialogTitle>Add New Member</DialogTitle>
100+
<DialogDescription>
101+
Create a new member account. The member will be able to change their
102+
password after first login.
103+
</DialogDescription>
79104
</DialogHeader>
80-
<form onSubmit={handleSubmit} className="space-y-4 pt-4">
81-
<div className="space-y-2">
82-
<Label htmlFor="firstName">First Name</Label>
83-
<Input
84-
id="firstName"
85-
name="firstName"
86-
value={formData.firstName}
87-
onChange={handleInputChange}
88-
placeholder="Enter first name"
89-
required
90-
/>
91-
</div>
92-
<div className="space-y-2">
93-
<Label htmlFor="lastName">Last Name</Label>
94-
<Input
95-
id="lastName"
96-
name="lastName"
97-
value={formData.lastName}
98-
onChange={handleInputChange}
99-
placeholder="Enter last name"
100-
required
101-
/>
102-
</div>
103-
<div className="space-y-2">
104-
<Label htmlFor="displayName">Display Name</Label>
105-
<Input
106-
id="displayName"
107-
name="displayName"
108-
value={formData.displayName}
109-
onChange={handleInputChange}
110-
placeholder="Enter display name"
111-
required
112-
/>
113-
</div>
114-
<div className="space-y-2">
115-
<Label htmlFor="email">Email</Label>
116-
<Input
117-
id="email"
118-
name="email"
119-
type="email"
120-
value={formData.email}
121-
onChange={handleInputChange}
122-
placeholder="Enter email address"
123-
required
124-
/>
105+
<form onSubmit={handleSubmit}>
106+
<div className="space-y-4">
107+
<div className="space-y-2">
108+
<Label htmlFor="firstName">First Name</Label>
109+
<Input
110+
id="firstName"
111+
name="firstName"
112+
value={formData.firstName}
113+
onChange={handleInputChange}
114+
placeholder="Enter first name"
115+
required
116+
/>
117+
</div>
118+
<div className="space-y-2">
119+
<Label htmlFor="lastName">Last Name</Label>
120+
<Input
121+
id="lastName"
122+
name="lastName"
123+
value={formData.lastName}
124+
onChange={handleInputChange}
125+
placeholder="Enter last name"
126+
required
127+
/>
128+
</div>
129+
<div className="space-y-2">
130+
<Label htmlFor="displayName">Display Name</Label>
131+
<Input
132+
id="displayName"
133+
name="displayName"
134+
value={formData.displayName}
135+
onChange={handleInputChange}
136+
placeholder="Enter display name"
137+
required
138+
/>
139+
</div>
140+
<div className="space-y-2">
141+
<Label htmlFor="email">Email</Label>
142+
<Input
143+
id="email"
144+
name="email"
145+
type="email"
146+
value={formData.email}
147+
onChange={handleInputChange}
148+
placeholder="Enter email address"
149+
required
150+
/>
151+
</div>
152+
<div className="grid gap-4">
153+
<Label htmlFor="password">Initial Password</Label>
154+
<Input
155+
id="password"
156+
name="password"
157+
type="password"
158+
value={formData.password}
159+
onChange={handleInputChange}
160+
required
161+
/>
162+
</div>
163+
<div className="grid gap-4">
164+
<Label htmlFor="confirmPassword">Confirm Password</Label>
165+
<Input
166+
id="confirmPassword"
167+
name="confirmPassword"
168+
type="password"
169+
value={formData.confirmPassword}
170+
onChange={handleInputChange}
171+
required
172+
/>
173+
</div>
174+
{passwordError && (
175+
<div className="text-red-500 text-sm">{passwordError}</div>
176+
)}
125177
</div>
126-
<Button type="submit" className="w-full">
127-
Add Member
128-
</Button>
178+
<DialogFooter>
179+
<Button type="submit">Create Member</Button>
180+
</DialogFooter>
129181
</form>
130182
</DialogContent>
131183
</Dialog>

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ export function MemberContainer({
1919
onRefresh,
2020
isLoading,
2121
}: MemberContainerProps) {
22+
// Check if current user is a coach in any relationship
23+
const isCoachInAnyRelationship = relationships.some(
24+
(rel) => rel.coach_id === userSession.id
25+
);
26+
2227
// Find relationships where current user is either coach or coachee
2328
const userRelationships = relationships.filter(
2429
(rel) =>
@@ -45,7 +50,12 @@ export function MemberContainer({
4550
<div className="space-y-6">
4651
<div className="flex justify-between items-center">
4752
<h2 className="text-2xl font-semibold">Members</h2>
48-
<AddMemberButton onMemberAdded={onRefresh} />
53+
{/* Only show the button if user is a coach to _some_ user within the
54+
scope of the organization. We may come back and add this directly to user
55+
data. */}
56+
{isCoachInAnyRelationship && (
57+
<AddMemberButton onMemberAdded={onRefresh} />
58+
)}
4959
</div>
5060
<MemberList users={associatedUsers} />
5161
</div>

src/lib/api/entity-api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,8 @@ export namespace EntityApi {
372372
api: {
373373
create: (entity: T) => Promise<U>;
374374
createNested: (id: Id, entity: T) => Promise<U>;
375-
update: (id: Id, entity: T) => Promise<T>;
376-
delete: (id: Id) => Promise<T>;
375+
update: (id: Id, entity: T) => Promise<U>;
376+
delete: (id: Id) => Promise<U>;
377377
}
378378
) => {
379379
const [isLoading, setIsLoading] = useState(false);

src/types/user.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ export interface User {
1111
}
1212

1313
export interface NewUser {
14-
email: string;
15-
password?: string;
1614
first_name: string;
1715
last_name: string;
1816
display_name: string;
17+
email: string;
18+
password: string;
1919
}
2020

2121
export function parseUser(data: unknown): User {

0 commit comments

Comments
 (0)