cc and bcc

This commit is contained in:
hamid zarghami
2025-10-23 11:05:03 +03:30
parent a081c364fe
commit 58f054ccfa
3 changed files with 121 additions and 3 deletions
+14 -1
View File
@@ -8,6 +8,8 @@ interface EmailInputProps {
onRemoveEmail: (email: string) => void onRemoveEmail: (email: string) => void
suggestions: EmailSuggestion[] suggestions: EmailSuggestion[]
onSearchSuggestions?: (query: string) => void onSearchSuggestions?: (query: string) => void
showCcBccButton?: boolean
onCcBccClick?: () => void
} }
const EmailInput: FC<EmailInputProps> = ({ const EmailInput: FC<EmailInputProps> = ({
@@ -15,7 +17,9 @@ const EmailInput: FC<EmailInputProps> = ({
onAddEmail, onAddEmail,
onRemoveEmail, onRemoveEmail,
suggestions, suggestions,
onSearchSuggestions onSearchSuggestions,
showCcBccButton = false,
onCcBccClick
}) => { }) => {
const [to, setTo] = useState('') const [to, setTo] = useState('')
const [filteredSuggestions, setFilteredSuggestions] = useState<EmailSuggestion[]>([]) const [filteredSuggestions, setFilteredSuggestions] = useState<EmailSuggestion[]>([])
@@ -195,6 +199,15 @@ const EmailInput: FC<EmailInputProps> = ({
placeholder={toEmails.length === 0 ? "ایمیل را وارد کرده و Enter بزنید" : ""} placeholder={toEmails.length === 0 ? "ایمیل را وارد کرده و Enter بزنید" : ""}
className="flex-1 min-w-32 bg-transparent outline-none" className="flex-1 min-w-32 bg-transparent outline-none"
/> />
{showCcBccButton && (
<button
onClick={onCcBccClick}
className='text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-colors pt-[3px] cursor-pointer '
>
CC/BCC
</button>
)}
</div> </div>
{showSuggestions && filteredSuggestions.length > 0 && ( {showSuggestions && filteredSuggestions.length > 0 && (
+50 -2
View File
@@ -21,10 +21,13 @@ const NewMessage: FC = () => {
const [isOpening, setIsOpening] = useState(false) const [isOpening, setIsOpening] = useState(false)
const [isIntelligenseOpen, setIsIntelligenseOpen] = useState(false) const [isIntelligenseOpen, setIsIntelligenseOpen] = useState(false)
const [prompt, setPrompt] = useState('') const [prompt, setPrompt] = useState('')
const [showCcBcc, setShowCcBcc] = useState(false)
const { const {
// Form state // Form state
toEmails, toEmails,
ccEmails,
bccEmails,
subject, subject,
content, content,
priority, priority,
@@ -38,6 +41,10 @@ const NewMessage: FC = () => {
// Form handlers // Form handlers
addEmail, addEmail,
removeEmail, removeEmail,
addCcEmail,
removeCcEmail,
addBccEmail,
removeBccEmail,
setSubject, setSubject,
setContent, setContent,
setPriority, setPriority,
@@ -76,6 +83,7 @@ const NewMessage: FC = () => {
setTimeout(() => { setTimeout(() => {
setOpenNewMessage(false) setOpenNewMessage(false)
resetForm() resetForm()
setShowCcBcc(false)
}, 300) }, 300)
} }
@@ -132,20 +140,60 @@ const NewMessage: FC = () => {
{/* Content */} {/* Content */}
<div className='space-y-6 md:space-y-8'> <div className='space-y-6 md:space-y-8'>
<div> <div>
<label className='text-sm'> <label className='text-sm mb-1 block'>
{t('new_message.to')} {t('new_message.to')}
</label> </label>
<div className='mt-1'> <div>
<EmailInput <EmailInput
toEmails={toEmails} toEmails={toEmails}
onAddEmail={addEmail} onAddEmail={addEmail}
onRemoveEmail={removeEmail} onRemoveEmail={removeEmail}
suggestions={emailSuggestions} suggestions={emailSuggestions}
onSearchSuggestions={searchEmailSuggestions} onSearchSuggestions={searchEmailSuggestions}
showCcBccButton={true}
onCcBccClick={() => setShowCcBcc(!showCcBcc)}
/> />
</div> </div>
</div> </div>
{/* CC/BCC Accordion */}
<div
className={clx(
'overflow-hidden transition-all duration-300 ease-in-out space-y-4',
showCcBcc ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'
)}
>
<div>
<label className='text-sm'>
CC
</label>
<div className='mt-1'>
<EmailInput
toEmails={ccEmails}
onAddEmail={addCcEmail}
onRemoveEmail={removeCcEmail}
suggestions={emailSuggestions}
onSearchSuggestions={searchEmailSuggestions}
/>
</div>
</div>
<div>
<label className='text-sm'>
BCC
</label>
<div className='mt-1'>
<EmailInput
toEmails={bccEmails}
onAddEmail={addBccEmail}
onRemoveEmail={removeBccEmail}
suggestions={emailSuggestions}
onSearchSuggestions={searchEmailSuggestions}
/>
</div>
</div>
</div>
<div className='flex gap-2 items-end'> <div className='flex gap-2 items-end'>
<div className='flex lg:flex-row flex-col flex-1 items-end gap-2'> <div className='flex lg:flex-row flex-col flex-1 items-end gap-2'>
<Input <Input
@@ -21,6 +21,8 @@ export const useNewMessage = () => {
const { email: userEmail } = useAuthStore(); const { email: userEmail } = useAuthStore();
const [toEmails, setToEmails] = useState<string[]>([]); const [toEmails, setToEmails] = useState<string[]>([]);
const [ccEmails, setCcEmails] = useState<string[]>([]);
const [bccEmails, setBccEmails] = useState<string[]>([]);
const [subject, setSubject] = useState(""); const [subject, setSubject] = useState("");
const [content, setContent] = useState(""); const [content, setContent] = useState("");
const [priority, setPriority] = useState(""); const [priority, setPriority] = useState("");
@@ -48,6 +50,15 @@ export const useNewMessage = () => {
const toEmailsList = const toEmailsList =
draftDetail.to?.map((recipient) => recipient.address) || []; draftDetail.to?.map((recipient) => recipient.address) || [];
setToEmails(toEmailsList); setToEmails(toEmailsList);
const ccEmailsList =
draftDetail.cc?.map((recipient) => recipient.address) || [];
setCcEmails(ccEmailsList);
const bccEmailsList =
draftDetail.bcc?.map((recipient) => recipient.address) || [];
setBccEmails(bccEmailsList);
setSubject(draftDetail.subject || ""); setSubject(draftDetail.subject || "");
const draftWithContent = (draftDetail as unknown) as { const draftWithContent = (draftDetail as unknown) as {
@@ -96,6 +107,40 @@ export const useNewMessage = () => {
setToEmails(toEmails.filter((email) => email !== emailToRemove)); setToEmails(toEmails.filter((email) => email !== emailToRemove));
}; };
const addCcEmail = (email: string) => {
if (!isValidEmail(email)) {
return;
}
if (ccEmails.includes(email)) {
toast("این ایمیل قبلاً اضافه شده است", "error");
return;
}
setCcEmails([...ccEmails, email]);
};
const removeCcEmail = (emailToRemove: string) => {
setCcEmails(ccEmails.filter((email) => email !== emailToRemove));
};
const addBccEmail = (email: string) => {
if (!isValidEmail(email)) {
return;
}
if (bccEmails.includes(email)) {
toast("این ایمیل قبلاً اضافه شده است", "error");
return;
}
setBccEmails([...bccEmails, email]);
};
const removeBccEmail = (emailToRemove: string) => {
setBccEmails(bccEmails.filter((email) => email !== emailToRemove));
};
const parseEmailAddresses = (emails: string[]) => { const parseEmailAddresses = (emails: string[]) => {
return emails return emails
.filter((email) => email.length > 0) .filter((email) => email.length > 0)
@@ -104,6 +149,8 @@ export const useNewMessage = () => {
const resetForm = () => { const resetForm = () => {
setToEmails([]); setToEmails([]);
setCcEmails([]);
setBccEmails([]);
setSubject(""); setSubject("");
setContent(""); setContent("");
setPriority(""); setPriority("");
@@ -141,6 +188,8 @@ export const useNewMessage = () => {
const textDirection = detectTextDirection(contentString); const textDirection = detectTextDirection(contentString);
const draftUpdateData = { const draftUpdateData = {
to: parseEmailAddresses(toEmails), to: parseEmailAddresses(toEmails),
...(ccEmails.length > 0 && { cc: parseEmailAddresses(ccEmails) }),
...(bccEmails.length > 0 && { bcc: parseEmailAddresses(bccEmails) }),
subject, subject,
html: `<div dir="${textDirection}" style="text-align: start; unicode-bidi: plaintext; font-family: 'Irancell', 'Vazirmatn', sans-serif;">${contentString}</div>`, html: `<div dir="${textDirection}" style="text-align: start; unicode-bidi: plaintext; font-family: 'Irancell', 'Vazirmatn', sans-serif;">${contentString}</div>`,
text: contentString.replace(/<[^>]*>/g, ""), text: contentString.replace(/<[^>]*>/g, ""),
@@ -193,6 +242,8 @@ export const useNewMessage = () => {
const emailData: SendEmailDto = { const emailData: SendEmailDto = {
from: { address: userEmail || "sender@example.com" }, from: { address: userEmail || "sender@example.com" },
to: parseEmailAddresses(toEmails), to: parseEmailAddresses(toEmails),
...(ccEmails.length > 0 && { cc: parseEmailAddresses(ccEmails) }),
...(bccEmails.length > 0 && { bcc: parseEmailAddresses(bccEmails) }),
subject, subject,
html: `<div dir="${textDirection}" style="text-align: start; unicode-bidi: plaintext; font-family: 'Irancell', 'Vazirmatn', sans-serif;">${contentString}</div>`, html: `<div dir="${textDirection}" style="text-align: start; unicode-bidi: plaintext; font-family: 'Irancell', 'Vazirmatn', sans-serif;">${contentString}</div>`,
text: contentString.replace(/<[^>]*>/g, ""), text: contentString.replace(/<[^>]*>/g, ""),
@@ -231,6 +282,8 @@ export const useNewMessage = () => {
return { return {
toEmails, toEmails,
ccEmails,
bccEmails,
subject, subject,
content, content,
priority, priority,
@@ -242,6 +295,10 @@ export const useNewMessage = () => {
addEmail, addEmail,
removeEmail, removeEmail,
addCcEmail,
removeCcEmail,
addBccEmail,
removeBccEmail,
setSubject, setSubject,
setContent, setContent,
setPriority, setPriority,