Skip to content

feat: ability to invite users to project#71

Merged
jamesholcombe merged 11 commits intomainfrom
feat/invite-user
Aug 12, 2025
Merged

feat: ability to invite users to project#71
jamesholcombe merged 11 commits intomainfrom
feat/invite-user

Conversation

@jamesholcombe
Copy link
Copy Markdown
Member

No description provided.

@vercel
Copy link
Copy Markdown

vercel Bot commented Aug 7, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Project Deployment Preview Comments Updated (UTC)
groundup Ready Preview Comment Aug 12, 2025 2:33pm
groundup-docs Ready Preview Comment Aug 12, 2025 2:33pm

@jamesholcombe jamesholcombe requested a review from Copilot August 8, 2025 14:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds project invitation functionality to allow users to invite others to join projects via email. The implementation includes database schema changes, email notifications, and a complete UI workflow for sending and accepting invitations.

Key Changes:

  • Database schema modifications to support project invitations with status tracking
  • Email invitation system with React Email templates
  • User interface for sending invitations and managing notifications
  • Server actions for accepting/declining invitations

Reviewed Changes

Copilot reviewed 18 out of 20 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/common/src/db/schema/project.ts Adds project invitation schema with status enum and relations
packages/common/drizzle/0010_tranquil_betty_brant.sql Database migration for invitation table and enum
packages/app/src/lib/notifications.ts Service for fetching user notifications
packages/app/src/emails/project-invitation.tsx React Email template for invitation emails
packages/app/src/db/crud/project.ts CRUD operations for project invitations
packages/app/src/components/team/add-team-member-form.tsx Updated form to send invitations instead of direct team member addition
packages/app/src/components/common/sidebar/notifications-panel.tsx Notifications panel for pending invitations
packages/app/src/actions/projects/sendInvitation.ts Server action for sending project invitations
packages/app/src/actions/projects/acceptInvitation.ts Server action for accepting invitations
packages/app/src/actions/projects/declineInvitation.ts Server action for declining invitations

Comment thread packages/app/src/db/crud/project.ts Outdated
})
.from(projectInvitation)
.leftJoin(user, eq(projectInvitation.invitedByUserId, user.id))
.leftJoin(user, eq(projectInvitation.invitedUserId, user.id))
Copy link

Copilot AI Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line creates a duplicate join alias for the user table. The second leftJoin should use a table alias to distinguish between invitedByUser and invitedUser. This will cause SQL ambiguity and incorrect results.

Suggested change
.leftJoin(user, eq(projectInvitation.invitedUserId, user.id))
// Alias for the invitedUser join
const invitedUserAlias = alias(user, "invited_user");
const invitations = await db
.select({
invitation: projectInvitation,
invitedByUser: user,
invitedUser: invitedUserAlias,
total: sql<number>`count(*) over()`,
})
.from(projectInvitation)
.leftJoin(user, eq(projectInvitation.invitedByUserId, user.id))
.leftJoin(invitedUserAlias, eq(projectInvitation.invitedUserId, invitedUserAlias.id))

Copilot uses AI. Check for mistakes.
status: "ACCEPTED" | "DECLINED" | "EXPIRED",
userId?: string,
): Promise<ProjectInvitation> {
const updateData: any = { status };
Copy link

Copilot AI Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using any type defeats TypeScript's type safety. Define a proper type for the update data object to maintain type safety and catch potential errors at compile time.

Suggested change
const updateData: any = { status };
const updateData: Partial<ProjectInvitation> = { status };

Copilot uses AI. Check for mistakes.
Comment thread packages/app/src/lib/notifications.ts Outdated
project: project!,
};
}),
);
Copy link

Copilot AI Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the non-null assertion operator (!) bypasses TypeScript's null checking without proper validation. Consider handling the case where project might be null/undefined more explicitly with proper error handling.

Suggested change
);
const notificationsWithProjects = (
await Promise.all(
pendingInvitations.map(async (invitation) => {
const project = await readProjectById(invitation.projectId);
if (!project) {
// Optionally log or handle missing project here
return null;
}
return {
invitation,
project,
};
}),
)
).filter((item): item is InvitationWithProject => item !== null);

Copilot uses AI. Check for mistakes.
const showEmailOption =
isValidEmail && !hasExistingUsers && searchQuery.length > 0;

console.log(isValidEmail, hasExistingUsers, searchQuery.length);
Copy link

Copilot AI Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug console.log statement should be removed before production deployment. Consider using a proper logging solution or removing this line entirely.

Suggested change
console.log(isValidEmail, hasExistingUsers, searchQuery.length);

Copilot uses AI. Check for mistakes.
@jamesholcombe jamesholcombe merged commit 3dc3249 into main Aug 12, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants