From 011fd526babb7ea10c50eededda5856626fd5fbc Mon Sep 17 00:00:00 2001 From: Ahmet Kilinc Date: Wed, 11 Jun 2025 17:40:25 +0100 Subject: [PATCH] fix: email composer paste (#1294) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Add multi-email paste functionality to email composer ## Description Added the ability to paste multiple email addresses at once in the email composer. Users can now copy a list of email addresses separated by commas, semicolons, or whitespace and paste them into the "To" field. The system validates each email address, adds valid ones to the recipient list, and displays appropriate success/error toast notifications. ## Type of Change - [x] ✨ New feature (non-breaking change which adds functionality) - [x] 🎨 UI/UX improvement ## Areas Affected - [x] User Interface/Experience ## Testing Done - [x] Manual testing performed ## Summary by CodeRabbit - **New Features** - You can now paste multiple email addresses into the "To" field when composing an email. Valid addresses are automatically added as recipients, and you’ll receive feedback for any invalid entries. --- .../mail/components/create/email-composer.tsx | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/apps/mail/components/create/email-composer.tsx b/apps/mail/components/create/email-composer.tsx index 3eeccd224..0f9281dfb 100644 --- a/apps/mail/components/create/email-composer.tsx +++ b/apps/mail/components/create/email-composer.tsx @@ -512,6 +512,44 @@ export function EmailComposer({ ref={toInputRef} className="h-6 flex-1 bg-transparent text-sm font-normal leading-normal text-black placeholder:text-[#797979] focus:outline-none dark:text-white" placeholder="Enter email" + onPaste={(e) => { + e.preventDefault(); + const pastedText = e.clipboardData.getData('text'); + const emails = pastedText + .split(/[,;\s]+/) + .map((email) => email.trim()) + .filter((email) => email.length > 0); + + const validEmails: string[] = []; + const invalidEmails: string[] = []; + + emails.forEach((email) => { + if (isValidEmail(email)) { + const emailLower = email.toLowerCase(); + if (!toEmails.some((e) => e.toLowerCase() === emailLower)) { + validEmails.push(email); + } + } else { + invalidEmails.push(email); + } + }); + + if (validEmails.length > 0) { + setValue('to', [...toEmails, ...validEmails]); + setHasUnsavedChanges(true); + if (validEmails.length === 1) { + toast.success('Email address added'); + } else { + toast.success(`${validEmails.length} email addresses added`); + } + } + + if (invalidEmails.length > 0) { + toast.error( + `Invalid email ${invalidEmails.length === 1 ? 'address' : 'addresses'}: ${invalidEmails.join(', ')}`, + ); + } + }} onKeyDown={(e) => { if (e.key === 'Enter' && e.currentTarget.value.trim()) { e.preventDefault();