feat(polling-groups): can invite multiple people to have their gmail/outlook inboxes connected to a workflow (#2695)

* progress on cred sets

* fix credential set system

* return data to render credential set in block preview

* progress

* invite flow

* simplify code

* fix ui

* fix tests

* fix types

* fix

* fix icon for outlook

* fix cred set name not showing up for owner

* fix rendering of credential set name

* fix outlook well known folder id resolution

* fix perms for creating cred set

* add to docs and simplify ui

* consolidate webhook code better

* fix tests

* fix credential collab logic issue

* fix ui

* fix lint
This commit is contained in:
Vikhyath Mondreti
2026-01-07 17:49:40 -08:00
committed by GitHub
parent cb12ceb82c
commit 020037728d
59 changed files with 14775 additions and 320 deletions

View File

@@ -1,3 +1,4 @@
export { BatchInvitationEmail } from './batch-invitation-email'
export { InvitationEmail } from './invitation-email'
export { PollingGroupInvitationEmail } from './polling-group-invitation-email'
export { WorkspaceInvitationEmail } from './workspace-invitation-email'

View File

@@ -0,0 +1,52 @@
import { Link, Text } from '@react-email/components'
import { baseStyles } from '@/components/emails/_styles'
import { EmailLayout } from '@/components/emails/components'
import { getBrandConfig } from '@/lib/branding/branding'
interface PollingGroupInvitationEmailProps {
inviterName?: string
organizationName?: string
pollingGroupName?: string
provider?: 'google-email' | 'outlook'
inviteLink?: string
}
export function PollingGroupInvitationEmail({
inviterName = 'A team member',
organizationName = 'an organization',
pollingGroupName = 'a polling group',
provider = 'google-email',
inviteLink = '',
}: PollingGroupInvitationEmailProps) {
const brand = getBrandConfig()
const providerName = provider === 'google-email' ? 'Gmail' : 'Outlook'
return (
<EmailLayout preview={`You've been invited to join ${pollingGroupName} on ${brand.name}`}>
<Text style={baseStyles.paragraph}>Hello,</Text>
<Text style={baseStyles.paragraph}>
<strong>{inviterName}</strong> from <strong>{organizationName}</strong> has invited you to
join the polling group <strong>{pollingGroupName}</strong> on {brand.name}.
</Text>
<Text style={baseStyles.paragraph}>
By accepting this invitation, your {providerName} account will be connected to enable email
polling for automated workflows.
</Text>
<Link href={inviteLink} style={{ textDecoration: 'none' }}>
<Text style={baseStyles.button}>Accept Invitation</Text>
</Link>
{/* Divider */}
<div style={baseStyles.divider} />
<Text style={{ ...baseStyles.footerText, textAlign: 'left' }}>
This invitation expires in 7 days. If you weren't expecting this email, you can safely
ignore it.
</Text>
</EmailLayout>
)
}
export default PollingGroupInvitationEmail

View File

@@ -12,6 +12,7 @@ import { CareersConfirmationEmail, CareersSubmissionEmail } from '@/components/e
import {
BatchInvitationEmail,
InvitationEmail,
PollingGroupInvitationEmail,
WorkspaceInvitationEmail,
} from '@/components/emails/invitations'
import { HelpConfirmationEmail } from '@/components/emails/support'
@@ -184,6 +185,24 @@ export async function renderWorkspaceInvitationEmail(
)
}
export async function renderPollingGroupInvitationEmail(params: {
inviterName: string
organizationName: string
pollingGroupName: string
provider: 'google-email' | 'outlook'
inviteLink: string
}): Promise<string> {
return await render(
PollingGroupInvitationEmail({
inviterName: params.inviterName,
organizationName: params.organizationName,
pollingGroupName: params.pollingGroupName,
provider: params.provider,
inviteLink: params.inviteLink,
})
)
}
export async function renderPaymentFailedEmail(params: {
userName?: string
amountDue: number

View File

@@ -8,6 +8,7 @@ export type EmailSubjectType =
| 'reset-password'
| 'invitation'
| 'batch-invitation'
| 'polling-group-invitation'
| 'help-confirmation'
| 'enterprise-subscription'
| 'usage-threshold'
@@ -38,6 +39,8 @@ export function getEmailSubject(type: EmailSubjectType): string {
return `You've been invited to join a team on ${brandName}`
case 'batch-invitation':
return `You've been invited to join a team and workspaces on ${brandName}`
case 'polling-group-invitation':
return `You've been invited to join an email polling group on ${brandName}`
case 'help-confirmation':
return 'Your request has been received'
case 'enterprise-subscription':