Project: workspace-doctolib · Branch: HEAD · Mode: · Model: claude-sonnet-4-6
Stats: 1 user messages, 34 tool calls, tools used: Bash, Read.
Conversation
Turn 1 — User
Review PR https://github.com/doctolib/doctolib/pull/241055 for UpFront architecture compliance. The PR adds archive/unarchive document actions to the NHR (national health records) document list.
Key files changed:
---
NEW: packages/@doctolib/national-health-records/src/components/NhrDocumentActionDialog/NhrDocumentActionDialog.tsx
import { Alert } from '@doctolib/design-system/Alert'
import { Dialog } from '@doctolib/design-system/Dialog'
import i18n from 'monolith_DEPRECATED/services/i18n'
import type { NhrActionModalConfig } from '../types/nhrDocumentActions'
type Props = {
isOpen: boolean
config: NhrActionModalConfig | null
isLoading: boolean
error: string | null
onConfirm: () => void
onDismiss: () => void
}
export const NhrDocumentActionDialog = ({ isOpen, config, isLoading, error, onConfirm, onDismiss }: Props) => {
if (!config) return null
return (
)
}
Note: import path '../types/nhrDocumentActions' goes UP only one level but the component is at src/components/NhrDocumentActionDialog/NhrDocumentActionDialog.tsx — should this be ../../types/nhrDocumentActions?
---
NEW: packages/@doctolib/national-health-records/src/hooks/useNhrDocumentStatusActions.ts
import { useCallback, useMemo, useState } from 'react'
// ... imports ...
export const useNhrDocumentStatusActions = ({ patient }: { patient: Patient }): UseNhrDocumentStatusActionsResult => {
const nhrOperations = useNationalHealthRecords({ patient })
const invalidateNhrDocuments = useInvalidateNhrDocuments(patient)
const [modalState, setModalState] = useState(null)
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState(null)
const openModal = useCallback(
(doc: NhrDocument, config: NhrActionModalConfig) => {
setError(null)
setModalState({ doc, config })
},
[]
)
const options: DropdownActionOption[] = useMemo(
() => [
{
key: 'archive',
label: i18n.t('national_health_records.document_metadata_actions.dmp.options.archive'),
isAvailable: isActive,
onClick: (doc) => openModal(doc, archiveConfig()),
},
{
key: 'unarchive',
label: i18n.t('national_health_records.document_metadata_actions.dmp.options.unarchive'),
isAvailable: isArchived,
onClick: (doc) => openModal(doc, unarchiveConfig()),
},
],
[openModal]
)
const handleConfirm = async () => {
if (!modalState || !nhrOperations || !patient.ins) return
setIsLoading(true)
setError(null)
try {
await nhrOperations.updateDocumentMetadata({
patient: toNhrPatientInformation(patient.ins),
params: { payloads: [{ id: modalState.doc.id, propertyName: 'status' }] },
})
setModalState(null)
await invalidateNhrDocuments()
} catch {
setError(i18n.t('national_health_records.document_metadata_actions.dmp.errors.action_failed'))
} finally {
setIsLoading(false)
}
}
const handleDismiss = () => {
if (isLoading) return
setModalState(null)
setError(null)
}
return { options, modalState, isLoading, error, handleConfirm, handleDismiss }
}
---
MODIFIED: packages/@doctolib/shared_patient_file_and_appointment_page_components/src/desktop/PatientCard/PatientCard.tsx
const { options, modalState, isLoading, error, handleConfirm, handleDismiss } = useNhrDocumentStatusActions({
patient,
})
const nhrActions = useMemo(
() =>
actionsBuilder
.createViewDocumentAction(async (doc) => {
await getDocumentsC
…(truncated, 2058 more chars)
Turn 1 — Assistant
I'll examine the actual repository files to ground my review in real code before providing findings.
Tools used:
- Bash: find /Users/USER/workspace/doctolib/upfront -type f -name ".ts" -o -name ".tsx" 2>/dev/null | head -40
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/upfront/commitlint.config.ts
/Users/USER/workspace/doctolib/upfront/knip.config.ts
/Users/USER/workspace/doctolib/upfront/packages/metrics/vitest.config.ts
/Users/USER/workspace/doctolib/upfront/packages/core/vitest.browser.config.ts
/Users/USER/workspace/doctolib/upfront/packages/core/vitest.config.ts
/Users/USER/workspace/doctolib/upfront/packages/dev/assets.d.ts
/Users/USER/workspace/doctolib/upfront/packages/dev/vitest.config.ts
/Users/USER/workspace/doctolib/u
…(truncated, 2540 more chars)
Tools used:
- Bash: ls /Users/USER/workspace/doctolib/upfront/ 2>/dev/null || echo "not found"
Tool results:
→ result (ok): catalog-info.yaml
CODEOWNERS
commitlint.config.ts
eslint.config.js
knip.config.ts
lint-staged.config.js
nx.json
package-lock.json
package.json
packages
prettier.config.js
README.md
release-please-config.json
renovate.json
TODO-Git-Hooks.md
TODO.md
tsconfig.json
Upfront.code-workspace
Tools used:
- Bash: find /Users/USER/workspace/doctolib/upfront/packages -maxdepth 2 -type d | sort
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/upfront/packages
/Users/USER/workspace/doctolib/upfront/packages/core
/Users/USER/workspace/doctolib/upfront/packages/core/docs
/Users/USER/workspace/doctolib/upfront/packages/core/samples
/Users/USER/workspace/doctolib/upfront/packages/core/src
/Users/USER/workspace/doctolib/upfront/packages/core/tests
/Users/USER/workspace/doctolib/upfront/packages/create-upfront
/Users/USER/workspace/doctolib/upfront/packages/create-upfront/docs-assets
/Users/USER/workspace/doct
…(truncated, 1232 more chars)
Tools used:
- Bash: find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records -type f 2>/dev/null | sort | head -80
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/.swc/plugins/macos_aarch64_23.0.0/083f0289b1f0a2c1f1b04fc8633128e22b64719df071637b52da9d8610d235e9.wasmer-v7
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/.swc/plugins/macos_aarch64_23.0.0/5acf025db021a59295bdd2ae122efcaf720a22a7520bb471b94260e1b74e7b1d.wasmer-v7
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/.swc/plugins/macos_aarch64_23.0.0
…(truncated, 12484 more chars)
Tools used:
- Bash: find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src -type f | sort
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.test.ts
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.ts
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/adapters/parseHl7DateToIso.test.ts
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/adapters/parseHl7DateToI
…(truncated, 4697 more chars)
Tools used:
- Bash: find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/shared_patient_file_and_appointment_page_components/src/desktop/PatientCard -type f | sort
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/shared_patient_file_and_appointment_page_components/src/desktop/PatientCard/PatientCard.scss
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/shared_patient_file_and_appointment_page_components/src/desktop/PatientCard/PatientCard.test.tsx
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/shared_patient_file_and_appointment_page_components/src/desktop/PatientCard/PatientCard.tsx
/Users/USER/workspace/doctolib/doctolib/p
…(truncated, 3838 more chars)
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/index.ts
Tool results:
→ result (ok): 1 export { useNationalHealthRecords, type UseNhrOperations } from './hooks/useNationalHealthRecords'
2 export { useDmpNhr } from './hooks/useDmpNhr'
3 export { useNhrDocumentListVariant } from './variants/useNhrDocumentListVariant'
4 export type { DocumentSearchOptions, NhrDocumentListVariant } from './variants/types'
5 export { actionsBuilder, type NhrActionsBuilder } from './business/builders/actionsBuilder'
6 export { useGetDocumentsContent } from './hooks/useGetDocumentsContent'
7
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useNationalHealthRecords.ts
Tool results:
→ result (ok): 1 import type {
2 NhrDocumentSearchProps,
3 NhrDocumentSearchResult,
4 NhrGetDocumentsContentProps,
5 NhrDocumentContentResult,
6 NhrDocumentMetadataUpdateProps,
7 NhrDocumentMetadataUpdateResult,
8 } from '@doctolib/tpf-national-health-records'
9 import { useProductLineVariation, ProductLineKey } from '@doctolib/variation_management'
10 import type { Patient } from 'monolith_DEPRECATED/types/doctor/api/Patient'
11 import { useDmpNhr } from './useDmpNhr'
12
13 export type UseNhrOper
…(truncated, 966 more chars)
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useNationalHealthRecords.ts
Tool results:
→ result (ok): File unchanged since last read. The content from the earlier Read tool_result in this conversation is still current — refer to that instead of re-reading.
Tools used:
- Bash: find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src -type d | sort
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/adapters
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/builders
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/constants
/
…(truncated, 1095 more chars)
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.ts
Tool results:
→ result (ok): 1 import type { NhrDocument } from '@doctolib/tpf-national-health-records'
2 import type { NhrVisibilityEntry } from '@doctolib/tpf-national-health-records-ui'
3 import { DOCUMENT_STATUS, DOCUMENT_VISIBILITY } from '@doctolib/dmp'
4
5 const CLASS_CODE_SYSTEM = 'dmp:classCode'
6 const TYPE_CODE_SYSTEM = 'dmp:typeCode'
7 const PATIENT_CODE = '90' // EX_3.1-1040: class code for patient-authored documents
8
9 // classification.codes may contain both a classCode (JDV_J06) and a typeCode (JDV_J07/LO
…(truncated, 2792 more chars)
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/shared_patient_file_and_appointment_page_components/src/desktop/PatientCard/PatientCard.tsx
Tool results:
→ result (ok): 1 import PatientFileIcon from 'images/icons/patient-file-icon.svg?as-react-component'
2 import PatientAppointmentIcon from 'images/icons/patient-appointment-icon.svg?as-react-component'
3 import { type ComponentType, lazy, useContext, useMemo, Suspense } from 'react'
4 import classNames from 'classnames'
5 import AccountContext from 'monolith_DEPRECATED/contexts/doctor/AccountContext'
6 import INSiAutomaticCallContext from '@doctolib/financial_os_api/public/contexts/INSiAutomaticCallContext'
7 i
…(truncated, 7359 more chars)
Tools used:
- Bash: find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src -name "types" -type d 2>/dev/null; find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib
…(truncated, 86 more chars)
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/variants/types.ts
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/builders/actionsBuilder.ts
Tool results:
→ result (ok): 1 import {
2 createMoreActionsAction as moreActionsActionFactory,
3 createViewDocumentAction as viewDocumentActionFactory,
4 type ActionConfig,
5 type DropdownActionOption,
6 } from '@doctolib/tpf-national-health-records-ui'
7 import type { NhrDocument } from '@doctolib/tpf-national-health-records'
8
9 export type NhrActionsBuilder = {
10 createViewDocumentAction: (onDocumentSelected: (document: NhrDocument) => Promise) => NhrActionsBuilder
11 createMoreActionsAction: (options
…(truncated, 563 more chars)
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useGetDocumentsContent.ts
Tool results:
→ result (ok): 1 import { useState, useCallback } from 'react'
2 import type { Patient } from 'monolith_DEPRECATED/types/doctor/api/Patient'
3 import type { NhrDocumentContentResult } from '@doctolib/tpf-national-health-records'
4 import type { GetDocumentsContent } from '../variants/types'
5 import { useNationalHealthRecords } from './useNationalHealthRecords'
6
7 export const useGetDocumentsContent = ({
8 patient,
9 }: {
10 patient: Patient
11 }): { getDocumentsContent: GetDocumentsContent; documentsCon
…(truncated, 1064 more chars)
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/variants/dmp/useDmpDocumentListVariant.ts
Tool results:
→ result (ok): 1 import { columnsFactory } from './factories/columnsFactory'
2 import { filtersFactory } from './factories/filtersFactory'
3 import type { NhrDocumentListVariant, DocumentSearchOptions } from '../types'
4 import { useSearchDocuments } from '../../hooks/useSearchDocuments'
5 import { mapFiltersToSearchDocumentsParams } from './mappers/mapFiltersToSearchDocumentsParams'
6
7 export const useDmpDocumentListVariant = (patient: DocumentSearchOptions['patient']): NhrDocumentListVariant => {
8 const
…(truncated, 205 more chars)
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/variants/types.ts
Tool results:
→ result (ok): 1 import type { ColumnConfig, FilterConfig, SearchDocumentsResult } from '@doctolib/tpf-national-health-records-ui'
2 import type { Patient } from 'monolith_DEPRECATED/types/doctor/api/Patient'
3 import type { NhrDocumentSearchParams } from '@doctolib/tpf-national-health-records'
4
5 export type { SearchDocumentsResult }
6
7 export type NhrDocumentListVariant = {
8 columns: ColumnConfig[]
9 filters: FilterConfig[]
10 searchDocuments: (appliedFilters?: Record) => Promise<
…(truncated, 820 more chars)
Tools used:
- Bash: find /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks -type f | sort
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useDmpNhr.test.ts
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useDmpNhr.ts
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useGetDocumentsContent.test.ts
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useGetDocumentsContent.ts
/Users/USER/workspace/doctolib/doctolib/
…(truncated, 441 more chars)
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useDmpNhr.ts
Tool results:
→ result (ok): 1 import { useMemo } from 'react'
2 import type { Patient } from 'monolith_DEPRECATED/types/doctor/api/Patient'
3 import { DmpApiImpl as DmpApi, useDmpSetUp } from '@doctolib/dmp'
4 import { createNhrService } from '@doctolib/tpf-national-health-records'
5 import { useDocumentCategorizationFacetsIndex } from 'engines/document_categorization/queries/document_categorization/facets'
6 import { DmpNhrAdapter } from '../business/adapters/DmpNhrAdapter'
7 import type { UseNhrOperations } from './useNa
…(truncated, 812 more chars)
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/mappers/toNhrPatientInformation.ts
Tool results:
→ result (ok): 1 import type { NhrPatientInformation } from '@doctolib/tpf-national-health-records'
2
3 export function toNhrPatientInformation(ins: string): NhrPatientInformation {
4 return {
5 nationalHealthIdentifier: ins,
6 }
7 }
8
Now I have enough grounding in the actual codebase. Let me check the PR files more carefully - particularly for the types/ directory placement and the isActive helper that's referenced but not found yet.
Tools used:
- Bash: grep -r "isActive" /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/ 2>/dev/null
Tool results:
→ result (ok): (Bash completed with no output)
Tools used:
- Bash: grep -r "NhrActionModalConfig\|nhrDocumentActions\|useInvalidateNhrDocuments\|useNhrDocumentStatusActions\|NhrDocumentActionDialog" /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/nati
…(truncated, 36 more chars)
Tool results:
→ result (ok): (Bash completed with no output)
Tools used:
- Bash: cd /Users/USER/workspace/doctolib/doctolib && git log --oneline -10 2>/dev/null || echo "not a git repo or no log"
Tools used:
- Bash: ls /Users/USER/workspace/doctolib/worktrees/doctolib/ 2>/dev/null
Tool results:
→ result (ok): e8b3e695da92 fix(FHIR-2215): pass undefined as second arg to DmpNhrAdapter constructor in tests
f36fbd44321d test(FHIR-2215): use explicit mock factories to avoid loading @doctolib/dmp module graph
5d22561f30c6 fix(FHIR-2215): adapt actionsBuilder and PatientCard to tpf-national-health-records-ui@15 API
0d4f4b5c4d00 refactor(FHIR-2215): merge consecutive early-return guards in useSearchDocuments
267255adb5df test(FHIR-2215): add coverage for undefined apiErrorCode and non-Error thrown value
6e1e
…(truncated, 473 more chars)
Tool results:
→ result (ok): fhir-2089
FHIR-2091-nhr-document-list-pagination
FHIR-2166-fix-nhr-mock-status-visibility
fhir-2169
fhir-2181
fhir-2189_class-code-label-map
fhir-2190_improve-filter-panel-ui
fhir-2209_fix-patient-ins-env-transformation
fhir-2216_fix-nhr-date-columns-and-document-type
fhir-2221_display-last-dmp-access-date
fhir-2222_add-visible-to-all-filter
fhir-2223_fix-column-widths-dmp
FHIR-2224
Tools used:
- Bash: ls /Users/USER/workspace/doctolib/worktrees/doctolib/fhir-2035-add_ui_components_dmp_val_page/ 2>/dev/null && find /Users/USER/workspace/doctolib/worktrees/doctolib/fhir-2035-add_ui_componen
…(truncated, 96 more chars)
Tool results:
→ result (ERROR): Exit code 2
Tools used:
- Bash: find /Users/USER/workspace/doctolib/worktrees/doctolib -maxdepth 1 -type d 2>/dev/null | sort
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/worktrees/doctolib
/Users/USER/workspace/doctolib/worktrees/doctolib/fhir-2089
/Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2091-nhr-document-list-pagination
/Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2166-fix-nhr-mock-status-visibility
/Users/USER/workspace/doctolib/worktrees/doctolib/fhir-2169
/Users/USER/workspace/doctolib/worktrees/doctolib/fhir-2181
/Users/USER/workspace/doctolib/worktrees/doctolib/fhir-2189_class-code-label-map
/Users/US
…(truncated, 585 more chars)
Tools used:
- Bash: find /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2224/packages/@doctolib/national-health-records/src -type f 2>/dev/null | sort
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2224/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.test.ts
/Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2224/packages/@doctolib/national-health-records/src/business/adapters/DmpNhrAdapter.ts
/Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2224/packages/@doctolib/national-health-records/src/business/adapters/parseHl7DateToIso.test.ts
/Users/USER/workspace/doctolib/worktrees/doctolib/FHIR-2224/
…(truncated, 5537 more chars)
The PR files are not in the worktree either — the branch is FHIR-2224 but doesn't contain the new files. The PR hasn't been checked out. I'll proceed from the PR diff provided in the prompt, but let me verify a few more things about the package structure to ground the review properly.
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/variants/dmp/mappers/dmpDocumentHelpers.ts (1–11)
Tool results:
→ result (ok): 1 import type { NhrDocument } from '@doctolib/tpf-national-health-records'
2 import type { NhrVisibilityEntry } from '@doctolib/tpf-national-health-records-ui'
3 import { DOCUMENT_STATUS, DOCUMENT_VISIBILITY } from '@doctolib/dmp'
4
5 const CLASS_CODE_SYSTEM = 'dmp:classCode'
6 const TYPE_CODE_SYSTEM = 'dmp:typeCode'
7 const PATIENT_CODE = '90' // EX_3.1-1040: class code for patient-authored documents
8
9 // classification.codes may contain both a classCode (JDV_J06) and a typeCode (JDV_J07/LO
…(truncated, 102 more chars)
Tools used:
- Bash: grep -r "isActive" /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/ 2>/dev/null | grep -v node_modules | grep -v ".swc"
Tool results:
→ result (ok): (Bash completed with no output)
Tools used:
- Bash: grep -r "useQueryClient\|queryClient\|invalidateQueries\|react-query\|@tanstack" /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/ 2>/dev/null | grep -v node
…(truncated, 8 more chars)
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useSearchDocuments.ts:import { useQueryClient } from '@tanstack/react-query-v5'
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useSearchDocuments.ts: const queryClient = useQueryClient()
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useSearchDocuments.ts: const result = await queryClient.fetchQuery({
/Users
…(truncated, 549 more chars)
Tools used:
- Bash: grep -r "useQueryClient\|queryClient\|invalidateQueries" /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/ 2>/dev/null | grep -v node_modules | grep -v ".swc"
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useSearchDocuments.ts:import { useQueryClient } from '@tanstack/react-query-v5'
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useSearchDocuments.ts: const queryClient = useQueryClient()
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useSearchDocuments.ts: const result = await queryClient.fetchQuery({
/Users
…(truncated, 353 more chars)
Tools used:
- Read: /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/hooks/useSearchDocuments.ts
Tool results:
→ result (ok): 1 import { useQueryClient } from '@tanstack/react-query-v5'
2 import type { Patient } from 'monolith_DEPRECATED/types/doctor/api/Patient'
3 import { isFeatureEnabled } from '@doctolib/variation_management'
4 import type { NhrDocumentListVariant, MapFiltersToSearchDocumentsParams, ServerFilters } from '../variants/types'
5 import { useNationalHealthRecords } from './useNationalHealthRecords'
6 import { generateNhrDocuments } from '../mocks/generateNhrDocuments'
7 import { filterMockedDocuments }
…(truncated, 2435 more chars)
Now I have all the context needed. The query key 'dmp-documents' is used in useSearchDocuments with the full key ['dmp-documents', ins, appliedFilters]. Let me also check package.json for path aliases and the existing isActive export situation.
Tools used:
- Bash: cat /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/package.json 2>/dev/null | grep -E '"exports|"main|"module|"#|aliases' | head -20
Tool results:
→ result (ok): "type": "module",
"exports": {
Tools used:
- Bash: grep -r "monolith_DEPRECATED" /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/ 2>/dev/null | grep -v node_modules | grep ".ts" | head -10
Tool results:
→ result (ok): /Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/variants/types.ts:import type { Patient } from 'monolith_DEPRECATED/types/doctor/api/Patient'
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/variants/dmp/constants.ts:import { LOINC_CODES_TO_KIND } from 'monolith_DEPRECATED/models/document/fr/DocumentLoincCodesToKind'
/Users/USER/workspace/doctolib/doctolib/packages/@doctolib/national-health-records/src/business/adapters
…(truncated, 1447 more chars)
I now have sufficient grounding in the actual codebase. Here is the full review.
---
UpFront Architecture Review — PR #241055
Critical Issues (must fix)
---
issue(correctness): Wrong import path in NhrDocumentActionDialog.tsx
The component is placed at:
packages/@doctolib/national-health-records/src/components/NhrDocumentActionDialog/NhrDocumentActionDialog.tsx
The import reads:
import type { NhrActionModalConfig } from '../types/nhrDocumentActions'
../ from that file resolves to src/components/, not src/. The types/ directory (new, introduced by this PR) must live under src/, so the correct path is:
import type { NhrActionModalConfig } from '../../types/nhrDocumentActions'
This is a compile error if src/components/types/ does not exist. The PR summary in the prompt flags this correctly; the file must be fixed before merge.
---
issue(architecture): useNhrDocumentStatusActions violates the hook classification rule
The architecture rule is explicit: hooks that mix data access with business logic belong in src/business/, not src/hooks/. src/hooks/ is reserved for platform API hooks (useOffline, useCopyToClipboard) and custom UX primitives that get promoted there when reused across components.
useNhrDocumentStatusActions does the following in a single hook:
- calls useNationalHealthRecords (data operation)
- calls useInvalidateNhrDocuments (cache mutation)
- owns modal UI state (modalState, isLoading, error)
- constructs DropdownActionOption[] with embedded i18n strings
- drives the full confirm/dismiss lifecycle
This is a shared business hook — it coordinates domain state and data access. It belongs at src/business/hooks/useNhrDocumentStatusActions.ts, following the same pattern as any hook that would be reused across presentational contexts.
---
issue(architecture): useInvalidateNhrDocuments placed in src/hooks/ for the wrong reason
src/hooks/useInvalidateNhrDocuments.ts wraps queryClient.invalidateQueries. Cache invalidation tied to a specific domain entity (nhr-documents) is not a platform API hook — it is a data-layer concern. It belongs in src/data/ if that subdirectory exists in this package, or otherwise should remain internal to the hook that uses it. Exporting it from the package index as a standalone hook is also premature (see index issues below).
---
issue(correctness): handleConfirm is not wrapped in useCallback
handleConfirm is an async function declared inline inside useNhrDocumentStatusActions. It is returned from the hook and passed as onConfirm to NhrDocumentActionDialog, and — based on the PatientCard usage shown — it is also a dependency of the nhrActions useMemo. Because it is recreated on every render, the useMemo for nhrActions in PatientCard will recompute on every render cycle even when neither getDocumentsContent nor options has changed. Wrap it:
const handleConfirm = useCallback(async () => {
if (!modalState || !nhrOperations || !patient.ins) return
// ...
}, [modalState, nhrOperations, patient.ins, invalidateNhrDocuments])
---
issue(correctness): handleDismiss closes over a stale isLoading reference
handleDismiss is defined as:
const handleDismiss = () => {
if (isLoading) return
setModalState(null)
setError(null)
}
It is not wrapped in useCallback and does not list isLoading in any dependency array. When isLoading changes from false to true mid-flight, the closure captured at definition time may still see the old value. Wrap it with useCallback([isLoading]) or use a ref to read the current value at call time.
---
Warnings (should fix)
---
warning(naming): src/components/ directory does not exist in this package — introducing it without a components/ convention being established here is inconsistent
The existing national-health-records package structure is:
src/business/
src/hooks/
src/variants/
src/mocks/
src/locales/
There is no src/components/ precedent. NhrDocumentActionDialog is a dialog tied directly to the DMP archive/unarchive workflow. Before adding src/components/ as a new top-level subdirectory, confirm this is intentional and that the package is meant to own presentational components. If yes, the addition is acceptable but must be reflected in the package README or architecture decision. If the dialog is DMP-variant-specific, it belongs under src/variants/dmp/components/NhrDocumentActionDialog/.
---
warning(naming): Missing index.ts re-exporter for the component folder
The UpFront Josh Comeau pattern for component directories requires an index.ts re-exporter:
src/components/NhrDocumentActionDialog/
NhrDocumentActionDialog.tsx ← component
index.ts ← re-exporter: export { NhrDocumentActionDialog } from './NhrDocumentActionDialog'
The PR does not include this file. The src/index.ts currently imports the component directly by filename, which is fine only if no index.ts re-exporter pattern is being enforced. If other components in the codebase follow this convention (check PatientRegularDoctorModule/ in the shared_patient_file package, which does have the pattern), the new component folder must too.
---
warning(exports): Re-exporting third-party types through the package index is not justified
export type { DropdownActionOption } from '@doctolib/tpf-national-health-records-ui'
export type { NhrDocument } from '@doctolib/tpf-national-health-records'
Re-exporting types that belong to other packages from @doctolib/national-health-records/src/index.ts creates a hidden coupling: consumers who need DropdownActionOption or NhrDocument should import them directly from their owning packages. The only valid reason to re-export a third-party type here is if the package wraps or extends that type in a way that would require consumers to use the re-export to satisfy type compatibility. That is not the case here. Remove these two re-exports and update PatientCard.tsx to import directly from @doctolib/tpf-national-health-records-ui and @doctolib/tpf-national-health-records.
---
warning(exports): useInvalidateNhrDocuments should not be exported from the package index
This hook exists to invalidate a query cache entry internal to the national-health-records package. Exporting it publicly means any consumer can invalidate the dmp-documents query from outside the package, bypassing encapsulation. If useNhrDocumentStatusActions needs it, it should be a module-private import, not an index export.
---
warning(exports): isActive is exported from src/index.ts but does not exist in dmpDocumentHelpers.ts
The PR index shows:
export { isActive, isArchived } from './variants/dmp/mappers/dmpDocumentHelpers'
Looking at the current dmpDocumentHelpers.ts, isArchived, isObsolete, isPatientAuthored, etc. are all defined, but isActive is not present in the base branch. The PR must add isActive to dmpDocumentHelpers.ts. If it is a new export, it needs a corresponding test in dmpDocumentHelpers.test.ts.
---
warning(query-key): Partial query key invalidation in useInvalidateNhrDocuments may over-invalidate
useSearchDocuments uses the key ['dmp-documents', ins, appliedFilters]. useInvalidateNhrDocuments calls:
queryClient.invalidateQueries({ queryKey: ['dmp-documents', patient.ins] })
This is correct in intent — it invalidates all queries for that patient's ins regardless of applied filters. However, the key string 'dmp-documents' is a magic string duplicated across two hooks with no shared constant. If either string changes independently, invalidation silently stops working. Extract a shared constant:
// src/hooks/dmpQueryKeys.ts
export const DMP_DOCUMENTS_QUERY_KEY = 'dmp-d
…(truncated, 2644 more chars)