email: compose + reply via Gmail SMTP (app password), with recipient autocomplete

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 07:12:34 +00:00
co-authored by Claude Opus 4.8
parent 3b13b98532
commit ead8f53951
5 changed files with 275 additions and 3 deletions
@@ -1,11 +1,12 @@
import { useEffect, useRef, useState } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { Mail } from 'lucide-react';
import { Mail, Reply } from 'lucide-react';
import { FileViewerProvider, FileViewerHeader, FileViewerBody } from 'officerdev';
import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog';
import { useClient } from 'hooks/useClient';
import { useGlobal } from 'hooks/useGlobal';
import type { EmailMessage } from 'types';
import { useComposer, replyDraft } from './Compose';
type OpenAttachment = {
filePath: string;
@@ -44,6 +45,7 @@ const HtmlBody = ({ html }: { html: string }) => {
export const EmailReader = () => {
const client = useClient();
const queryClient = useQueryClient();
const [, openCompose] = useComposer();
const [selectedId] = useGlobal<string | null>('EMAIL_SELECTED', null);
const [openAttachment, setOpenAttachment] = useState<OpenAttachment | null>(null);
@@ -89,7 +91,16 @@ export const EmailReader = () => {
return (
<div className="flex h-full flex-col overflow-hidden">
<div className="flex flex-col gap-1 border-b px-4 py-3">
<h2 className="text-lg font-semibold">{message.subject}</h2>
<div className="flex items-start justify-between gap-3">
<h2 className="text-lg font-semibold">{message.subject}</h2>
<button
onClick={() => openCompose(replyDraft(message))}
className="shrink-0 flex items-center gap-1 rounded-md border px-2.5 py-1 text-xs hover:bg-accent cursor-pointer"
title="Reply"
>
<Reply className="h-3.5 w-3.5" /> Reply
</button>
</div>
<div className="flex flex-col gap-0.5 text-sm opacity-70">
<div>
<span className="font-medium">From:</span> {message.from}