Project: doctolib-doctolib · Branch: master · Mode: · Model: claude-haiku-4-5-20251001 Stats: 1 user messages, 41 tool calls, tools used: Read, Glob, Grep, Bash. Conversation Turn 1 — User Find and analyze the component that renders when clicking "dokumente anzeigen" (visualize document button). I need to understand: 1. What component mounts when the user clicks "dokumente anzeigen"? 2. How does this component receive the document object? 3. When does useDecryptedDocumentsShow get called relative to component mounting? 4. Is the document object complete on first mount, or does it change between first and second click? Search for: - Components that use "visualize" or "dokumente anzeigen" button - Document viewer components in timeline context - Components that call useDecryptedDocumentsShow - Timeline document item interaction handlers Start from: engines/ehr/app/assets/javascripts/queries/ehr/timelineItems.ts and related timeline components Turn 1 — Assistant I'll help you analyze the component that renders when clicking "dokumente anzeigen". Let me start by exploring the timeline-related files and searching for the visualization component. Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/engines/ehr/app/assets/javascripts/queries/ehr/timelineItems.ts Tool results: → result (ok): 1→import { useContext, useEffect } from 'react' 2→import { type QueryClient, useIsFetching, useQuery, useQueryClient, keepPreviousData } from '@tanstack/react-query-v5' 3→import { selectTimestamp } from 'services/appointment-list-grouping' 4→import buildTimelineItem from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/items/factory' 5→import { TIMELINE_ITEM_TYPES } from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/items/types' 6→i …(truncated, 26394 more chars) Tools used: - Glob: engines/ehr/app/assets/javascripts//timeline.{ts,tsx} Tools used: - Glob: engines/ehr/app/assets/javascripts//document.{ts,tsx} Tool results: → result (ERROR): Ripgrep search timed out after 20 seconds. The search may have matched files but did not complete in time. Try searching a more specific path or pattern. Tool results: → result (ERROR): Sibling tool call errored Let me search more specifically for the document visualization component and timeline item rendering: Tools used: - Grep: dokumente anzeigen|visualize.document Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib/engines/ehr -name ".tsx" -o -name ".ts" | grep -i "timeline\|document" | head -30 Tools used: - Grep: useDecryptedDocumentsShow Tool results: → result (ok): No files found Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/engines/ehr/app/assets/javascripts/queries/ehr/patients/documents.ts /Users/USER/workspace/doctolib/doctolib/engines/ehr/app/assets/javascripts/queries/ehr/patients/clinicalDocuments.ts /Users/USER/workspace/doctolib/doctolib/engines/ehr/app/assets/javascripts/queries/ehr/timelineItems.ts /Users/USER/workspace/doctolib/doctolib/engines/ehr/app/assets/javascripts/queries/ehr/timelineItems.test.ts /Users/USER/workspace/doctolib/doctolib/engines/ehr/app/asset …(truncated, 4073 more chars) Tool results: → result (ok): Found 17 files limit: 30, offset: 0 engines/documents/app/assets/javascripts/queries/documents/doctor_app/decryptedDocuments.ts app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/panel-items/ConsultationDocumentItem/PaperFormBody.tsx app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/redesign/DigitalFormItemDetails/MusterItemDetails.tsx app/assets/javascripts/components/doctor/desktop/pages/patient/pa …(truncated, 1513 more chars) Great! Let me explore the key files related to timeline document items and the visualization document hook: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/engines/ehr/app/assets/javascripts/hooks/doctor/shared/useVisualizationDocument.ts Tool results: → result (ok): 1→import { useContext } from 'react' 2→import useCurrentPatient from 'hooks/doctor/useCurrentPatient' 3→import AccountContext from 'contexts/doctor/AccountContext' 4→import { TankerContext } from 'engines/e2ee/public' 5→import { VitalsContext } from '@doctolib/ehr_observations/public/contexts/VitalsContext' 6→import { visualizeConsultationDocumentPdf } from 'components/doctor/desktop/pages/patient/patient-file-tabs/shared/document-helper' 7→import { usePrintPdf } fr …(truncated, 6874 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/hooks/useTimelineDocumentItemController.ts Tool results: → result (ok): 1→import useCarePlansWithQuotation from '@doctolib/financial_os_api/public/hooks/useCarePlansWithQuotation' 2→import { updateDocumentCarePlan } from '@doctolib/financial_os_api/public/modules/carePlanHelper' 3→import type { CarePlanOptionValue } from '@doctolib/financial_os_api/public/types/CarePlanSelectorTypes' 4→import { AccountContext } from '@doctolib/shared_context' 5→import { printDocument } from 'components/doctor/desktop/pages/patient/patient-file-tabs/consultation/U …(truncated, 11201 more chars) Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -path "history/items" -name ".tsx" | grep -i document | head -20 Tool results: → result (ok) Perfect! Now let me look at the decrypted documents query and the timeline item factory to understand the full flow: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/decryptedDocuments.ts Tool results: → result (ok): 1→import type { AccountContextType } from '@doctolib/shared_context' 2→import { AccountContext } from '@doctolib/shared_context' 3→import type { DecryptFile } from 'engines/e2ee/public' 4→import { TankerContext } from 'engines/e2ee/public' 5→import { useQuery, useQueryClient } from '@tanstack/react-query' 6→import { handleEncryptedDocument } from 'components/shared/documents/utils' 7→import { HttpClientContext } from 'contexts/ReactQueryProvider' 8→import { use …(truncated, 5496 more chars) Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/items -name "factory" -o -name "Document" | head -20 Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history -name "Document" -type f | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/items/factory.ts Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/DocumentItemDetails/useDocumentItemsVariant.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/shared/ItemDetailsBody/DocumentItemDetailsBody.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/p …(truncated, 3808 more chars) Now let me examine the timeline item factory and the document details components: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/items/factory.ts Tool results: → result (ok): 1→import appointment from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/items/appointment' 2→import consultation from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/items/consultation' 3→import failedDecryptedItem from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/items/failedDecryptedItem' 4→import { TIMELINE_ITEM_TYPES } from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/items/types' 5→import …(truncated, 4162 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/redesign/DocumentItemDetails/DocumentItemDetails.tsx Tool results: → result (ok): 1→import { IconButton } from '@doctolib/design-system/IconButton' 2→import useTimelineDocumentItemController from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/hooks/useTimelineDocumentItemController' 3→import HeaderItemDetails from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/redesign/shared/views/HeaderItemDetails' 4→import DocumentItemDetailsBody from 'components/doctor/desktop/pages/patient/pati …(truncated, 9377 more chars) Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history -name "timeline" -o -name "Timeline" | grep -i "item" | h …(truncated, 7 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/useTimelineItemDetailsPerformance.ts /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/useTimelineItemD …(truncated, 3420 more chars) Perfect! Now let me look at the main timeline item details component and the document item interaction: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/TimelineItemDetails.tsx (1–150) Tool results: → result (ok): 1→import { useContext, useEffect } from 'react' 2→import { useHotkeys } from 'react-hotkeys-hook' 3→import type { IconBackgroundColor, IconColor, IconName } from '@doctolib/design-system/Icon' 4→import { capturePro } from '@doctolib/product-event-wrapper' 5→import { VitalsContextProvider } from '@doctolib/ehr_observations/public/contexts/VitalsContext' 6→import TrackingContext from '@doctolib/tracking_events/public/TrackingContext' 7→import { PublicSickNoteItemDetai …(truncated, 7363 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/items/document.ts Tool results: → result (ERROR): File does not exist. Did you mean document.js? Let me find the correct document item file: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/items -name "document" Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/items/document.js Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/items/document.js Tool results: → result (ok): 1→import { compact } from 'lodash-es' 2→import dayjs from 'dayjs' 3→import { sanitize } from 'packages/suggestion-engine/utils/string' 4→import constants from 'services/constants' 5→import { getFacetsSearchableValues } from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/items/BuilderTimelineItemHelper' 6→import { 7→ DOCUMENT_KIND_GROUP_TRANSLATIONS, 8→ formatDocumentKind, 9→ getDocumentTitle, 10→ KIND_TO_KIND_GROUP, 11→} fro …(truncated, 1875 more chars) Now let me look at the document body details component to understand the full flow: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/shared/ItemDetailsBody/DocumentItemDetailsBody.tsx Tool results: → result (ok): 1→import { isFeatureEnabled } from '@doctolib/variation_management' 2→import type { VersionInfo } from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/panel-items/CdaVersionInfo' 3→import CdaVersionInfo from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/panel-items/CdaVersionInfo' 4→import { Text } from '@doctolib/design-system/Text' 5→import i18n from 'services/i18n' 6→import { SpinnerLoader } from '@doctolib/design-system/Spinner …(truncated, 5883 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/TimelineItemDetails.tsx (150–250) Tool results: → result (ok): 150→ preventDefault: true, 151→ enabled: Boolean(withBackButton), 152→ } 153→ ) 154→ 155→ if (!record || !isNewDesign) return null 156→ 157→ return ( 158→ <> 159→ {isTimelineItemConsultation(record) && ( 160→ 161→ 162→ 163→ < …(truncated, 4286 more chars) Perfect! Now let me search for where the timeline item is clicked to understand the entry point: Tools used: - Bash: grep -r "setActiveTimelineItem\|useActiveTimelineItem" /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-it …(truncated, 37 more chars) Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -path "timeline-item-cards" -name ".tsx" | grep -v test | head -15 Tool results: → result (ok) Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/MedicationRequestCard/MedicationRequestCard.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/AppointmentCard/AppointmentCard.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-ta …(truncated, 2537 more chars) Let me look for document card components: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -path "timeline-item-cards" -name "Document" -o -path "timeline-item-cards" -name "document" | grep -v test | head -15 Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards -type d | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/MedicationRequestCard /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/AppointmentCard /Users/USER/wor …(truncated, 1880 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/DigitalFormCard/DigitalFormDocumentCard.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/ConsultationCard/views/ConsultationAttachments/views/DocumentItem.tsx /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop …(truncated, 2330 more chars) Perfect! Now let me examine the DocumentCard component and the ViewDocumentButton: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/DocumentCard/DocumentCard.tsx Tool results: → result (ok): 1→import dayjs from 'dayjs' 2→import classNames from 'classnames' 3→import TimelineCardContainer from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/shared/TimelineCardContainer' 4→import DocumentInfo from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/shared/DocumentInfo' 5→import CorruptedDocumentAlert from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/Do …(truncated, 4837 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/DocumentCard/views/ViewDocumentButton.tsx Tool results: → result (ok): 1→import type { TouchEventHandler } from 'react' 2→import i18n from 'services/i18n' 3→import { useTimelineRedesignVariant } from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/shared/TimelineHelper' 4→import { Icon } from '@doctolib/design-system/Icon' 5→import { Tooltip } from '@doctolib/design-system/Tooltip' 6→import { Button } from '@doctolib/design-system/Button' 7→import { IconButton } from '@doctolib/design-system/IconButton' 8→import …(truncated, 2358 more chars) Now let me look at the controller to understand how it's opened: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/DocumentCard/useDocumentCardController.ts Tool results: → result (ok): 1→import type { TouchEventHandler } from 'react' 2→import { useContext, useMemo } from 'react' 3→import { capturePro } from '@doctolib/product-event-wrapper' 4→import type { OnTapTimelineItemCardTracking } from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/shared/types' 5→import { getConsultationDocumentKindType } from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/shared/TimelineHelper' 6→import AccountContext …(truncated, 4220 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/DocumentCard/types.ts Tool results: → result (ok): 1→import type { TouchEventHandler } from 'react' 2→import type { Document as DoctorDocument } from 'types/doctor/api/Document' 3→import type { OnTapTimelineItemCardTracking } from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/shared/types' 4→ 5→export type Document = Omit & { 6→ originally_created_on: DoctorDocument['originally_created_on'] | null 7→} 8→ 9→export interface D …(truncated, 1434 more chars) Perfect! Now let me check where the openDocument prop comes from by looking at the parent component that uses DocumentCard: Tools used: - Bash: grep -r "DocumentCard" /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history --include=".tsx" --include=".ts" | grep " …(truncated, 48 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/redesign/ClinicalDocumentItemDetails/PrescriptionsActions.tsx:import usePrescriptionAuthorizationsForTimelineItem from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/ClinicalDocumentCard/usePrescriptionAuthorizationsForTimelineItem' /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doct …(truncated, 6226 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/DocumentCard/views/DocumentCardPreview.tsx Tool results: → result (ok): 1→import classNames from 'classnames' 2→import ViewDocumentButton from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/DocumentCard/views/ViewDocumentButton' 3→import { useTimelineRedesignVariant } from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/shared/TimelineHelper' 4→import type { DocumentCardPreviewProps } from 'components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/DocumentCard/types …(truncated, 1427 more chars) Now let me find where DocumentCard is actually being rendered to understand how openDocument is passed: Tools used: - Bash: grep -r "setActiveTimelineItem\|useActiveTimelineItem" /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history --include=" …(truncated, 49 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/shared/DeleteConsultationButton.tsx:import { useActiveTimelineItem } from '@doctolib/ehr-timeline' /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/shared/DeleteConsultationButton.tsx: const { setActiveTimelineItem } = useActiveTimelineItem() /Users/ …(truncated, 3307 more chars) Tools used: - Bash: grep -r " { e.stopPropagation() // ... tracking code ... openModal(UnifiedDocumentEditModule, { document: { ...(timelineItemRecord as TimelineItemDocument), patient }, forHealthRecord: true, onDocumentUpdate: () => { / invalidate queries / }, onCancel: () => closeModal(UnifiedDocumentEditModule), // ... other props }) } 2. How the Document Object is Received The document is passed through multiple layers: Flow: 1. Timeline Item Click → ViewDocumentButton clicks openDocument prop 2. ViewDocumentButton (DocumentCard/views/ViewDocumentButton.tsx) calls openDocument callback 3. DocumentCard receives openDocument prop from TimelineItem.tsx 4. TimelineItem (in ehr-timeline package) creates the openDocument handler that: - Extracts the document from timelineItemRecord (typed as TimelineItemDocument) - Passes it to UnifiedDocumentEditModule modal via openModal() Document Object at Mount: { ...(timelineItemRecord as TimelineItemDocument), // Full timeline document object patient, // Added patient object } 3. When useDecryptedDocumentsShow Gets Called Critical Timing: useDecryptedDocumentsShow is called AFTER the DocumentItemDetails component mounts, NOT before. Here's the flow: 1. Timeline Item Click → sets activeTimelineItem in context 2. TimelineSlidingPanel renders → passes timelineItems to TimelineItemDetails 3. TimelineItemDetails renders → finds active item and renders DocumentItemDetails 4. DocumentItemDetails mounts → calls useTimelineDocumentItemController (line 71) 5. Inside useTimelineDocumentItemController (line 82): const { data: decryptedDocumentData, isLoading } = useDecryptedDocumentsShow({ document }) - This hook is called as part of the controller initialization - It triggers decryption/download of the encrypted document Files involved: - /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/redesign/DocumentItemDetails/DocumentItemDetails.tsx (line 71) - /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/hooks/useTimelineDocumentItemController.ts (line 82) 4. Document Object Completeness Between Clicks First Mount (Timeline Item Click): - Document object is complete and decrypted from the timeline items query - It contains all properties: id, title, kind, created_at, tanker_encrypted, download_path, etc. - The object comes from formatItems() in timelineItems.ts which decrypts and formats the raw API response When useDecryptedDocumentsShow is called: - The same document object is passed to the hook - useDecryptedDocumentsShow uses refetchOnMount: 'always' (line 109 of decryptedDocuments.ts) - This means it always fetches/decrypts the document file on component mount, regardless of cache - The document object itself does NOT change between first and second click - it's the decrypted file URL that is fetched on mount Key Line from decryptedDocuments.ts (line 109): refetchOnMount: 'always', // CRITICAL: Use 'always' (string) not true (boolean) - true still respects staleTime This ensures the document file is always re-decrypted/re-fetched when the component mounts. Component Hierarchy Summary ViewDocumentButton (onClick) ↓ openDocument handler in TimelineItem.tsx ↓ UnifiedDocumentEditModule (modal opens) ↓ OR (depending on context) ↓ DocumentItemDetails (rendered in TimelineItemDetails) ↓ useTimelineDocumentItemController ↓ useDecryptedDocumentsShow (fetches decrypted file URL) Key Files Reference 1. Timeline Entry Point: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/ehr-timeline/src/components/PatientTimeline/TimelineItem.tsx (lines 150-194) 2. Document Details Controller: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/TimelineItemDetails/hooks/useTimelineDocumentItemController.ts 3. Decrypted Documents Query: /Users/USER/workspace/doctolib/doctolib/engines/documents/app/assets/javascripts/queries/documents/doctor_app/decryptedDocuments.ts (lines 87-114) 4. Document Card Component: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/DocumentCard/DocumentCard.tsx 5. View Button: /Users/USER/workspace/doctolib/doctolib/app/assets/javascripts/components/doctor/desktop/pages/patient/patient-file-tabs/history/timeline-item-cards/DocumentCard/views/ViewDocumentButton.tsx