Skip to content

ai-partner: citation → source navigation #1456

@CraigBuckmaster

Description

@CraigBuckmaster

Parent epic: #1446 (Amicus — AI Study Partner v1)
Phase: 2 · Size: S · Depends on: #1455 (citation pills)

Tapping a citation pill in an Amicus message navigates the user to the source — the exact panel, debate topic, word study, or lexicon entry that backed the citation. The navigation is deep-link style and must respect the existing tab structure.


Files to create

  • app/src/services/amicus/citationNav.ts — resolves a chunk_id to a navigation action
  • app/src/services/amicus/__tests__/citationNav.test.ts — unit tests

Files to modify

  • app/src/components/amicus/CitationPill.tsx — wire onTap to call the resolver

Resolver API

// citationNav.ts
import type { NavigationProp } from '@react-navigation/native';

export interface CitationTarget {
  chunk_id: string;
  source_type: string;
  source_id: string;
  metadata?: Record<string, unknown>;
}

/**
 * Resolve a citation target into a navigation action and execute it.
 * Handles cross-stack navigation (e.g., Amicus → Read tab → Chapter screen).
 */
export async function navigateToCitation(
  target: CitationTarget,
  navigation: NavigationProp<ParamListBase>
): Promise<void>;

The resolver switches on source_type and builds the correct navigation action:

source_type Destination
section_panel ReadTab → Chapter screen with openPanel param set to { sectionNum, panelType } (reuses existing OpenPanelParam from nav types)
chapter_panel ReadTab → Chapter screen with openPanel set to { panelType } (chapter-level)
word_study ExploreTab → WordStudyDetail with wordId
lexicon_entry ExploreTab → DictionaryDetail with entryId
debate_topic ExploreTab → DebateDetail with topicId
cross_ref_thread_note ExploreTab → ParallelDetail with entryId
journey_stop HomeTab → JourneyDetail stop (verify existing route)
meta_faq In-app modal showing the FAQ content (no dedicated screen — meta-FAQ is reference-only content)

Cross-stack navigation

To jump from the Amicus tab to e.g. the Read tab's Chapter screen:

navigation.getParent()?.navigate('ReadTab', {
  screen: 'Chapter',
  params: { bookId, chapterNum, openPanel: { sectionNum, panelType } },
});

This uses the existing root-level tab → stack → screen nesting pattern. Verify against TabNavigator.tsx + ReadStack.tsx when implementing.

source_id parsing

Chunk_ids are deterministic per #1447: {source_type}:{source_id}. Example: section_panel:romans-9-s1-calvin.

For section_panel, the source_id format is {book_id}-{chapter_num}-s{section_num}-{panel_type}. Parse via a simple regex; do not invent fields. Add a parser in citationNav.ts:

export function parseSectionPanelId(sourceId: string):
  | { bookId: string; chapterNum: number; sectionNum: number; panelType: string }
  | null;

If parsing fails, log via logger.warn and show a toast "Source unavailable" — never crash.

Resolution from DB when needed

Some source types need a lookup to resolve display info (e.g., a lexicon_entry chunk_id maps to an entry_id field that isn't in the chunk_id string). The resolver queries scripture.db for these cases. Keep queries scoped and fast (<50ms).

Meta-FAQ modal

Since meta-FAQ content doesn't have a destination screen, citation taps open a modal with:

  • Title
  • Full article body (scrollable)
  • Close button
  • Renders via a new lightweight MetaFaqModal.tsx component

Conventions to follow

  • Navigation via useNavigation<NavigationProp<RootParamList>>() hook in CitationPill
  • Cross-stack nav pattern: navigation.getParent()?.navigate('TabName', { screen, params }) — match existing deep-link entry points in the codebase
  • Errors via logger + user-visible toast (reuse existing toast component if present; otherwise subtle bottom banner)
  • No any; strict TS

Acceptance criteria

  • Tap on section_panel citation navigates to Read → Chapter with openPanel param; panel opens
  • Tap on word_study navigates to Explore → WordStudyDetail
  • Tap on lexicon_entry navigates to Explore → DictionaryDetail
  • Tap on debate_topic navigates to Explore → DebateDetail
  • Tap on meta_faq opens modal with FAQ body
  • Malformed source_id logs warning + shows "Source unavailable" toast (no crash)
  • Cross-stack navigation preserves history: back button returns to Amicus thread in same state
  • Unit tests cover each source_type case + the malformed path
  • No any types; strict TS; lint clean

Out of scope

  • Visual feedback on citation hover (mobile has no hover)
  • Preview-on-long-press (future UX enhancement, not v1)

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions