diff --git a/apps/mail/components/create/email-composer.tsx b/apps/mail/components/create/email-composer.tsx index c9fad7f4d..f64d8eb49 100644 --- a/apps/mail/components/create/email-composer.tsx +++ b/apps/mail/components/create/email-composer.tsx @@ -112,8 +112,22 @@ export function EmailComposer({ useEffect(() => { if (draft) { - if (draft.to) form.setValue('to', draft.to); - if (draft.content) form.setValue('message', draft.content); + if (draft.to) + form.setValue( + 'to', + draft.to.map((email) => email.replace(/[<>]/g, '')), + ); + if (draft.content) { + editor.commands.setContent({ + type: 'doc', + content: draft.content.split(/\r?\n/).map((line) => { + return { + type: 'paragraph', + content: line.trim().length === 0 ? [] : [{ type: 'text', text: line }], + }; + }), + }); + } if (draft.subject) form.setValue('subject', draft.subject); } }, [draft]); @@ -252,6 +266,7 @@ export function EmailComposer({ initialValue: initialMessage, isReadOnly: isLoading, onLengthChange: (length) => { + setHasUnsavedChanges(true); setMessageLength(length); }, onModEnter: () => { @@ -316,21 +331,23 @@ export function EmailComposer({ const handleGenerateReply = async () => {}; - const saveDraft = useCallback(async () => { - console.log('trying to save email'); - if (!hasUnsavedChanges) return; - if (!toEmails.length || !subjectInput || !messageContent) return; + const saveDraft = async () => { const values = getValues(); + if (!hasUnsavedChanges) return; + const messageText = editor.getText(); + console.log(values, messageText); + if (!values.to.length || !values.subject.length || !messageText.length) return; + try { setIsLoading(true); const draftData = { - to: values?.to?.join(', '), - cc: values?.cc?.join(', '), - bcc: values?.bcc?.join(', '), - subject: values?.subject, - message: values?.message, - attachments: values?.attachments, + to: values.to.join(', '), + cc: values.cc?.join(', '), + bcc: values.bcc?.join(', '), + subject: values.subject, + message: messageText, + attachments: values.attachments, id: draftId, }; @@ -339,21 +356,20 @@ export function EmailComposer({ if (response?.id && response.id !== draftId) { setDraftId(response.id); } - - setHasUnsavedChanges(false); - // toast.success(`Draft saved successfully: ${response.id}`); } catch (error) { console.error('Error saving draft:', error); toast.error('Failed to save draft'); } finally { setIsLoading(false); + setHasUnsavedChanges(false); } - }, [toEmails, subjectInput, messageContent, attachments, draftId, hasUnsavedChanges]); + }; useEffect(() => { if (!hasUnsavedChanges) return; const autoSaveTimer = setTimeout(() => { + console.log('timeout set'); saveDraft(); }, 3000); diff --git a/apps/mail/components/ui/app-sidebar.tsx b/apps/mail/components/ui/app-sidebar.tsx index d2767a28c..46a784509 100644 --- a/apps/mail/components/ui/app-sidebar.tsx +++ b/apps/mail/components/ui/app-sidebar.tsx @@ -76,7 +76,9 @@ export function AppSidebar({ ...props }: React.ComponentProps) { {...props} className={`flex select-none flex-col items-center ${state === 'collapsed' ? '' : ''}`} > -
+
@@ -130,13 +132,15 @@ function ComposeButton() { const [dialogOpen, setDialogOpen] = useQueryState('isComposeOpen'); const [, setDraftId] = useQueryState('draftId'); const [, setTo] = useQueryState('to'); + const [, setActiveReplyId] = useQueryState('activeReplyId'); + const [, setMode] = useQueryState('mode'); const handleOpenChange = (open: boolean) => { setDialogOpen(open ? 'true' : null); - if (!open) { - setDraftId(null); - setTo(null); - } + setDraftId(null); + setTo(null); + setActiveReplyId(null); + setMode(null); }; return ( @@ -156,7 +160,7 @@ function ComposeButton() { - + diff --git a/apps/mail/components/ui/nav-main.tsx b/apps/mail/components/ui/nav-main.tsx index e25e2ea02..57a3bd1a5 100644 --- a/apps/mail/components/ui/nav-main.tsx +++ b/apps/mail/components/ui/nav-main.tsx @@ -30,6 +30,7 @@ import { useSearchValue } from '@/hooks/use-search-value'; import { clearBulkSelectionAtom } from '../mail/use-mail'; import { Label as UILabel } from '@/components/ui/label'; import { type MessageKey } from '@/config/navigation'; +import { Command, SettingsIcon } from 'lucide-react'; import { type NavItem } from '@/config/navigation'; import { createLabel } from '@/hooks/use-labels'; import { Button } from '@/components/ui/button'; @@ -39,7 +40,7 @@ import { Badge } from '@/components/ui/badge'; import { Input } from '@/components/ui/input'; import { GoldenTicketModal } from '../golden'; import { useStats } from '@/hooks/use-stats'; -import { Command, SettingsIcon } from 'lucide-react'; +import { CurvedArrow } from '../icons/icons'; import { useTranslations } from 'next-intl'; import { useRef, useCallback } from 'react'; import { BASE_URL } from '@/lib/constants'; @@ -51,7 +52,6 @@ import { useAtom } from 'jotai'; import { toast } from 'sonner'; import * as React from 'react'; import Link from 'next/link'; -import { CurvedArrow } from '../icons/icons'; interface IconProps extends React.SVGProps { ref?: React.Ref; @@ -95,7 +95,7 @@ export function NavMain({ items }: NavMainProps) { const formColor = form.watch('color'); - const { labels } = useLabels(); + const { labels, mutate } = useLabels(); const { state } = useSidebar(); // Check if these are bottom navigation items by looking at the first section's title @@ -216,6 +216,9 @@ export function NavMain({ items }: NavMainProps) { loading: 'Creating label...', success: 'Label created successfully', error: 'Failed to create label', + finally: () => { + mutate(); + }, }); } catch (error) { console.error('Error creating label:', error); @@ -287,12 +290,16 @@ export function NavMain({ items }: NavMainProps) { Create New Label
- { - if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) { - e.preventDefault(); - form.handleSubmit(onSubmit)(); - } - }}> + { + if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) { + e.preventDefault(); + form.handleSubmit(onSubmit)(); + } + }} + >
{[ // Row 1 - Grayscale - '#000000', '#434343', '#666666', '#999999', '#cccccc', '#ffffff', + '#000000', + '#434343', + '#666666', + '#999999', + '#cccccc', + '#ffffff', // Row 2 - Warm colors - '#fb4c2f', '#ffad47', '#fad165', '#ff7537', '#cc3a21', '#8a1c0a', + '#fb4c2f', + '#ffad47', + '#fad165', + '#ff7537', + '#cc3a21', + '#8a1c0a', // Row 3 - Cool colors - '#16a766', '#43d692', '#4a86e8', '#285bac', '#3c78d8', '#0d3472', + '#16a766', + '#43d692', + '#4a86e8', + '#285bac', + '#3c78d8', + '#0d3472', // Row 4 - Purple tones - '#a479e2', '#b99aff', '#653e9b', '#3d188e', '#f691b3', '#994a64', + '#a479e2', + '#b99aff', + '#653e9b', + '#3d188e', + '#f691b3', + '#994a64', // Row 5 - Pastels - '#f6c5be', '#ffe6c7', '#c6f3de', '#c9daf8', + '#f6c5be', + '#ffe6c7', + '#c6f3de', + '#c9daf8', ].map((color) => (
@@ -353,7 +387,7 @@ export function NavMain({ items }: NavMainProps) {