Skip to content

Commit b7e6397

Browse files
authored
Merge pull request #999 from trycompai/main
[comp] Production Deploy
2 parents 76a0ec2 + a1e7a7d commit b7e6397

File tree

4 files changed

+44
-16
lines changed

4 files changed

+44
-16
lines changed

apps/app/src/app/(app)/[orgId]/people/all/actions/addEmployeeWithoutInvite.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
import { auth } from '@/utils/auth';
44
import { db } from '@comp/db';
5+
import type { Role } from '@comp/db/types';
56

67
export const addEmployeeWithoutInvite = async ({
78
email,
89
organizationId,
10+
roles,
911
}: {
1012
email: string;
1113
organizationId: string;
14+
roles: Role[];
1215
}) => {
1316
try {
1417
let userId = '';
@@ -34,7 +37,7 @@ export const addEmployeeWithoutInvite = async ({
3437
body: {
3538
userId: existingUser?.id ?? userId,
3639
organizationId,
37-
role: 'employee',
40+
role: roles, // Auth API expects role or role array
3841
},
3942
});
4043

apps/app/src/app/(app)/[orgId]/people/all/actions/removeMember.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const removeMember = authActionClient
4141

4242
if (
4343
!currentUserMember ||
44-
(currentUserMember.role !== 'admin' && currentUserMember.role !== 'owner')
44+
(!currentUserMember.role.includes('admin') && !currentUserMember.role.includes('owner'))
4545
) {
4646
return {
4747
success: false,
@@ -65,7 +65,7 @@ export const removeMember = authActionClient
6565
}
6666

6767
// Prevent removing the owner
68-
if (targetMember.role === 'owner') {
68+
if (targetMember.role.includes('owner')) {
6969
return {
7070
success: false,
7171
error: 'Cannot remove the organization owner',

apps/app/src/app/(app)/[orgId]/people/all/components/InviteMembersModal.tsx

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,17 @@ import { addEmployeeWithoutInvite } from '../actions/addEmployeeWithoutInvite';
3535
import { MultiRoleCombobox } from './MultiRoleCombobox';
3636

3737
// --- Constants for Roles ---
38-
const selectableRoles = ['admin', 'auditor', 'employee'] as const satisfies Readonly<Role[]>;
38+
const selectableRoles = ['admin', 'auditor', 'employee'] as const satisfies Readonly<
39+
[Role, ...Role[]]
40+
>;
3941
type InviteRole = (typeof selectableRoles)[number];
4042
const DEFAULT_ROLES: InviteRole[] = [];
4143

44+
// Type guard to check if a string is a valid InviteRole
45+
const isInviteRole = (role: string): role is InviteRole => {
46+
return role === 'admin' || role === 'auditor' || role === 'employee';
47+
};
48+
4249
// --- Schemas ---
4350
const manualInviteSchema = z.object({
4451
email: z.string().email({ message: 'Invalid email address.' }),
@@ -151,12 +158,13 @@ export function InviteMembersModal({
151158

152159
// Process each invitation sequentially
153160
for (const invite of values.manualInvites) {
154-
const isEmployeeOnly = invite.roles.length === 1 && invite.roles[0] === 'employee';
161+
const hasEmployeeRole = invite.roles.includes('employee');
155162
try {
156-
if (isEmployeeOnly) {
163+
if (hasEmployeeRole) {
157164
await addEmployeeWithoutInvite({
158165
organizationId,
159166
email: invite.email,
167+
roles: invite.roles,
160168
});
161169
} else {
162170
// Use authClient to send the invitation
@@ -276,6 +284,7 @@ export function InviteMembersModal({
276284
// Process each row
277285
for (const row of dataRows) {
278286
const columns = row.split(',').map((col) => col.trim());
287+
279288
if (columns.length <= Math.max(emailIndex, roleIndex)) {
280289
failedInvites.push({
281290
email: columns[emailIndex] || 'Invalid row',
@@ -296,9 +305,9 @@ export function InviteMembersModal({
296305
continue;
297306
}
298307

299-
// Validate role(s)
300-
const roles = roleValue.split(',').map((r) => r.trim()) as Role[];
301-
const validRoles = roles.filter((role) => selectableRoles.includes(role as any));
308+
// Validate role(s) - split by pipe for multiple roles
309+
const roles = roleValue.split('|').map((r) => r.trim());
310+
const validRoles = roles.filter(isInviteRole);
302311

303312
if (validRoles.length === 0) {
304313
failedInvites.push({
@@ -309,11 +318,20 @@ export function InviteMembersModal({
309318
}
310319

311320
// Attempt to invite
321+
const hasEmployeeRole = validRoles.includes('employee');
312322
try {
313-
await authClient.organization.inviteMember({
314-
email,
315-
role: validRoles.length === 1 ? validRoles[0] : validRoles,
316-
});
323+
if (hasEmployeeRole) {
324+
await addEmployeeWithoutInvite({
325+
organizationId,
326+
email,
327+
roles: validRoles,
328+
});
329+
} else {
330+
await authClient.organization.inviteMember({
331+
email,
332+
role: validRoles,
333+
});
334+
}
317335
successCount++;
318336
} catch (error) {
319337
console.error(`Failed to invite ${email}:`, error);
@@ -374,7 +392,12 @@ export function InviteMembersModal({
374392
}
375393
};
376394

377-
const csvTemplate = 'email,role\[email protected],employee\[email protected],admin';
395+
const csvTemplate = `email,role
396+
397+
[email protected],employee|admin
398+
399+
[email protected],employee|auditor
400+
378401
const csvTemplateDataUri = `data:text/csv;charset=utf-8,${encodeURIComponent(csvTemplate)}`;
379402

380403
return (
@@ -499,7 +522,9 @@ export function InviteMembersModal({
499522
/>
500523
</FormControl>
501524
<FormDescription>
502-
{"Upload a CSV file with columns for 'email' and 'role'."}
525+
{
526+
"Upload a CSV file with 'email' and 'role' columns. Use pipe (|) to separate multiple roles (e.g., employee|admin)."
527+
}
503528
</FormDescription>
504529
<a
505530
href={csvTemplateDataUri}

apps/app/src/app/(app)/[orgId]/people/all/components/MemberRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export function MemberRow({ member, onRemove, onUpdateRole }: MemberRowProps) {
7474
const [isRemoving, setIsRemoving] = useState(false);
7575
const dropdownTriggerRef = useRef<HTMLButtonElement>(null);
7676
const focusRef = useRef<HTMLButtonElement | null>(null);
77-
const currentUserIsOwner = member.role === 'owner';
77+
const currentUserIsOwner = member.role.includes('owner');
7878

7979
const memberName = member.user.name || member.user.email || 'Member';
8080
const memberEmail = member.user.email || '';

0 commit comments

Comments
 (0)