Add Correspondence side panel section for email and calendar - #5418
Add Correspondence side panel section for email and calendar#5418jbecke wants to merge 1 commit into
Conversation
Adds a "Correspondence" bento at the bottom of the email block's and the
calendar's right-hand side panels. It surfaces, for the external parties on
the open thread / selected event:
1. their CRM contact records (clickable through to the contact panel),
2. the CRM company record behind each external domain, and
3. the 50 most recent email threads shared with them, loaded async and
scrolled inside a fixed-height box so the bento can't stretch.
The section renders only when the thread/event actually has external parties,
where "external" means an address that is neither the signed-in user's nor on
their email domain. On the calendar that additionally means only while an
event is selected.
CRM lookup goes domain -> company id via the unified-search CRM source (the
CRM service has no domain lookup endpoint), then id -> company + contacts via
the existing company endpoint. Search matches domains by substring, so a hit
is accepted only on an exact domain equality check. Rows fall back to what the
thread/event knows about a party when the team tracks no CRM record for them.
The thread list uses the raw any-direction `ef` address filter rather than the
CRM-scoped `eca` widener, so it stays in the caller's own mailbox scope and
works whether or not CRM is enabled for those correspondents.
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdded shared correspondence utilities that normalize external parties and domains. Added CRM company and contact lookups, recent email-thread queries, and rendering for contacts, companies, and threads. Added correspondence sections to email and calendar side panels, using filtered participants from messages and events. Added tests for party normalization, filtering, deduplication, invalid addresses, and domain ordering. 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/web/src/features/correspondence/use-crm-records.ts (1)
33-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove the unnecessary memo.
addressDomain(email())is a cheap primitive derivation.useCrmCompanyForDomainonly needs an accessor. Use a plain accessor instead.Proposed change
- const domain = createMemo(() => addressDomain(email())); + const domain = () => addressDomain(email());As per coding guidelines, “Use
createMemoonly when referential stability is needed or derivation is expensive.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/features/correspondence/use-crm-records.ts` at line 33, Replace the createMemo-based domain derivation near useCrmCompanyForDomain with a plain accessor that returns addressDomain(email()), preserving the accessor interface expected by useCrmCompanyForDomain.Sources: Coding guidelines, Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/web/src/features/correspondence/use-crm-records.ts`:
- Line 33: Replace the createMemo-based domain derivation near
useCrmCompanyForDomain with a plain accessor that returns
addressDomain(email()), preserving the accessor interface expected by
useCrmCompanyForDomain.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 78f15f1a-e2d1-4479-83ac-ceded0e1a3fb
📒 Files selected for processing (11)
apps/web/src/features/block-email/component/sidepanel/EmailSidePanelSections.tsxapps/web/src/features/calendar/CalendarSidePanelSections.tsxapps/web/src/features/companies/Company/emailFilter.tsapps/web/src/features/correspondence/CorrespondenceSection.tsxapps/web/src/features/correspondence/index.tsapps/web/src/features/correspondence/parties.test.tsapps/web/src/features/correspondence/parties.tsapps/web/src/features/correspondence/use-correspondence-threads.tsapps/web/src/features/correspondence/use-crm-records.tsapps/web/src/lib/queries/crm/company-for-domain.tsapps/web/src/lib/queries/crm/keys.ts
Summary
Adds a new "Correspondence" side panel section that displays external parties, their companies, and recent email history for email threads and calendar events. This feature helps users quickly understand who they're communicating with and access related CRM records.
Key Changes
New Correspondence Section Component (
CorrespondenceSection.tsx): Main UI component that displays:Party Filtering Logic (
parties.ts): Utility functions to identify external parties:externalParties(): Filters out the signed-in user and same-domain teammates, dedupes on email addressaddressDomain(): Extracts and normalizes domain from email addressespartyDomains(): Gets distinct domains from a list of partiesCRM Record Resolution (
use-crm-records.ts):useCrmCompanyForDomain(): Two-hop lookup (domain → company ID via unified search, then ID → company + contacts)useCrmContactForAddress(): Resolves individual contacts through their company's domainEmail Thread Querying (
use-correspondence-threads.ts):useCorrespondenceThreadsQuery(): Fetches recent email threads with specified addresses using the soup query APIDomain Lookup Query (
company-for-domain.ts):useCrmCompanyIdForDomainQuery(): Unified search query scoped to CRM companies onlyIntegration Points:
externalParties()to filter consistentlyImplementation Details
emailFilterForAddresses()extended to support multiple addresses with OR logichttps://claude.ai/code/session_0172AYowQFMN2UwQTjhXX328