diff --git a/apps/mail/components/context/thread-context.tsx b/apps/mail/components/context/thread-context.tsx index 592d0b2cc..1094380c9 100644 --- a/apps/mail/components/context/thread-context.tsx +++ b/apps/mail/components/context/thread-context.tsx @@ -32,6 +32,7 @@ import { useThread, useThreads } from '@/hooks/use-threads'; import { useSearchValue } from '@/hooks/use-search-value'; import { useParams, useRouter } from 'next/navigation'; import { useTRPC } from '@/providers/query-provider'; +import { ExclamationCircle } from '../icons/icons'; import { useLabels } from '@/hooks/use-labels'; import { LABELS, FOLDERS } from '@/lib/utils'; import { useStats } from '@/hooks/use-stats'; @@ -142,6 +143,7 @@ export function ThreadContextMenu({ trpc.mail.markAsUnread.mutationOptions({ onSuccess: () => invalidateCount() }), ); const { mutateAsync: toggleStar } = useMutation(trpc.mail.toggleStar.mutationOptions()); + const { mutateAsync: toggleImportant } = useMutation(trpc.mail.toggleImportant.mutationOptions()); const { mutateAsync: deleteThread } = useMutation(trpc.mail.delete.mutationOptions()); const selectedThreads = useMemo(() => { @@ -162,6 +164,12 @@ export function ThreadContextMenu({ ); }, [threadData]); + const isImportant = useMemo(() => { + return threadData?.messages.some((message) => + message.tags?.some((tag) => tag.name.toLowerCase() === 'important'), + ); + }, [threadData]); + const noopAction = () => async () => { toast.info(t('common.actions.featureNotImplemented')); }; @@ -212,6 +220,13 @@ export function ThreadContextMenu({ return await Promise.allSettled([refetchThread(), refetch()]); }; + const handleToggleImportant = async () => { + const targets = mail.bulkSelected.length ? mail.bulkSelected : [threadId]; + await toggleImportant({ ids: targets }); + setMail((prev) => ({ ...prev, bulkSelected: [] })); + return await Promise.allSettled([refetchThread(), refetch()]); + }; + const handleReadUnread = () => { const targets = mail.bulkSelected.length ? mail.bulkSelected : [threadId]; const action = isUnread ? markAsRead : markAsUnread; @@ -399,6 +414,12 @@ export function ThreadContextMenu({ action: handleReadUnread, disabled: false, }, + { + id: 'toggle-important', + label: isImportant ? t('common.mail.removeFromImportant') : t('common.mail.markAsImportant'), + icon: , + action: handleToggleImportant, + }, { id: 'favorite', label: isStarred ? t('common.mail.removeFavorite') : t('common.mail.addFavorite'), diff --git a/apps/mail/components/icons/icons.tsx b/apps/mail/components/icons/icons.tsx index 74a5b13ec..b7cda0786 100644 --- a/apps/mail/components/icons/icons.tsx +++ b/apps/mail/components/icons/icons.tsx @@ -1490,3 +1490,20 @@ export const Search = ({ className }: { className?: string }) => ( /> ); + +export const Folders = ({ className }: { className?: string }) => ( + + + + + +); diff --git a/apps/mail/components/mail/mail-list.tsx b/apps/mail/components/mail/mail-list.tsx index 103e49c52..4f9115f56 100644 --- a/apps/mail/components/mail/mail-list.tsx +++ b/apps/mail/components/mail/mail-list.tsx @@ -4,6 +4,7 @@ import { Archive2, Bell, ChevronDown, + ExclamationCircle, GroupPeople, Lightning, People, @@ -183,16 +184,22 @@ const Thread = memo( refetch: refetchThread, } = useThread(demo ? null : message.id); const [isStarred, setIsStarred] = useState(false); + const [isImportant, setIsImportant] = useState(false); const trpc = useTRPC(); const queryClient = useQueryClient(); const { mutateAsync: toggleStar } = useMutation(trpc.mail.toggleStar.mutationOptions()); + const { mutateAsync: toggleImportant } = useMutation( + trpc.mail.toggleImportant.mutationOptions(), + ); const [id, setThreadId] = useQueryState('threadId'); const [activeReplyId, setActiveReplyId] = useQueryState('activeReplyId'); const [focusedIndex, setFocusedIndex] = useAtom(focusedIndexAtom); useEffect(() => { if (getThreadData?.latest?.tags) { + console.log(getThreadData.latest.tags); setIsStarred(getThreadData.latest.tags.some((tag) => tag.name === 'STARRED')); + setIsImportant(getThreadData.latest.tags.some((tag) => tag.name === 'IMPORTANT')); } }, [getThreadData?.latest?.tags]); @@ -214,6 +221,23 @@ const Thread = memo( [getThreadData, message.id, isStarred, refetchThreads, t], ); + const handleToggleImportant = useCallback( + async (e: React.MouseEvent) => { + e.stopPropagation(); + if (!getThreadData || !message.id) return; + const newImportantState = !isImportant; + setIsImportant(newImportantState); + await toggleImportant({ ids: [message.id] }); + if (newImportantState) { + toast.success(t('common.actions.addedToImportant')); + } else { + toast.success(t('common.actions.removedFromImportant')); + } + await refetchThread(); + }, + [getThreadData, message.id, refetchThreads], + ); + const handleNext = useCallback( (id: string) => { if (!id || !threads.length || focusedIndex === null) return setThreadId(null); @@ -469,13 +493,28 @@ const Thread = memo( {isStarred ? t('common.threadDisplay.unstar') : t('common.threadDisplay.star')} + {/* + + + + + {t('common.mail.toggleImportant')} + + */}