make the email url the selection instead of a mirror of it

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 11:51:45 +00:00
co-authored by Claude Opus 5
parent fd923bb9be
commit 6c47cbeb74
6 changed files with 57 additions and 36 deletions
@@ -1,14 +1,14 @@
import { useMemo, useCallback, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router';
import { useMemo, useCallback } from 'react';
import { useNavigate } from 'react-router';
import type { LayoutNode, PanelComponents } from 'officerdev';
import { WorkspaceView, ChatPanelWrapper } from 'officerdev';
import { useDashboardState } from 'state/useDashboardState';
import { useIsMobile } from 'hooks/useIsMobile';
import { useGlobal } from 'hooks/useGlobal';
import { defaultLayout } from './defaultLayout';
import { EmailList } from './EmailList';
import { EmailReader } from './EmailReader';
import { ComposeModal } from './Compose';
import { useSelectedEmailId } from './shared';
const PROMPT_PREFIX = `You are an email assistant. The user has a local SQLite email database available via the "email_db" tool — use it for all email queries (search, count, stats, aggregations, deletions) unless the user explicitly asks you to use Gmail. Do not use the Gmail integration for questions about existing emails.`;
@@ -19,23 +19,11 @@ const EmailChatPanel = () => <ChatPanelWrapper panelId="email-chat" promptPrefix
export const EmailScreen = () => {
const isMobile = useIsMobile();
const { emailId } = useParams<{ emailId?: string }>();
const navigate = useNavigate();
const [selectedId, setSelectedId] = useGlobal<string | null>('EMAIL_SELECTED', null);
// Sync URL param → global state
useEffect(() => {
if (emailId && emailId !== selectedId) setSelectedId(emailId);
}, [emailId]);
// Sync global state → URL
useEffect(() => {
if (selectedId && selectedId !== emailId) {
navigate(`/email/${selectedId}`, { replace: true });
} else if (!selectedId && emailId) {
navigate('/email', { replace: true });
}
}, [selectedId]);
// No `<Navigate>` guard: unlike a section route, the bare /email is a real state — the list with
// nothing open — exactly as /chat and /jobs are. An id that doesn't resolve is the reader's problem,
// not a reason to rewrite the address the user is looking at.
const selectedId = useSelectedEmailId();
const workspace = useDashboardState<LayoutNode>('screens/email', defaultLayout);
const components: PanelComponents = useMemo(
@@ -48,7 +36,8 @@ export const EmailScreen = () => {
);
const mobilePanelId = isMobile && selectedId ? 'email-reader' : undefined;
const onMobileBack = useCallback(() => setSelectedId(null), [setSelectedId]);
// Back on mobile closes the email, which is now just navigating to the bare route.
const onMobileBack = useCallback(() => navigate('/email'), [navigate]);
return (
<div className="h-full w-full pt-2">