From 69657a39289413c5eea8a40992eae09fc94b667f Mon Sep 17 00:00:00 2001 From: joshunrau Date: Tue, 9 Dec 2025 20:02:28 -0500 Subject: [PATCH 1/4] add qr-code to assignments and fix flashing with slider --- apps/web/package.json | 2 + apps/web/src/components/QRCode.tsx | 32 +++++ .../_app/datahub/$subjectId/assignments.tsx | 26 ++-- pnpm-lock.yaml | 113 +++++++++++++++++- 4 files changed, 158 insertions(+), 15 deletions(-) create mode 100644 apps/web/src/components/QRCode.tsx diff --git a/apps/web/package.json b/apps/web/package.json index 22417aeea..3229faa76 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -46,6 +46,7 @@ "lucide-react": "^0.507.0", "motion": "catalog:", "papaparse": "workspace:papaparse__5.x@*", + "qrcode": "^1.5.4", "react": "workspace:react__19.x@*", "react-dom": "workspace:react-dom__19.x@*", "recharts": "^2.15.2", @@ -65,6 +66,7 @@ "@tanstack/router-plugin": "^1.127.3", "@testing-library/dom": "^10.4.0", "@testing-library/react": "16.2.0", + "@types/qrcode": "^1.5.6", "@vitejs/plugin-react-swc": "^3.9.0", "happy-dom": "catalog:", "tailwindcss": "catalog:", diff --git a/apps/web/src/components/QRCode.tsx b/apps/web/src/components/QRCode.tsx new file mode 100644 index 000000000..0a7634951 --- /dev/null +++ b/apps/web/src/components/QRCode.tsx @@ -0,0 +1,32 @@ +import { useEffect, useRef } from 'react'; + +import { useTheme } from '@douglasneuroinformatics/libui/hooks'; +import qrcode from 'qrcode'; + +export const QRCode = ({ url }: { url: string }) => { + const ref = useRef(null); + + const [theme] = useTheme(); + + useEffect(() => { + qrcode.toCanvas( + ref.current, + url, + { + color: { + dark: theme === 'dark' ? '#f1f5f9' : '#0f172a', + light: '#0000' + }, + margin: 2, + scale: 6 + }, + (error) => { + if (error) { + console.error(error); + } + } + ); + }, [theme, url]); + + return ; +}; diff --git a/apps/web/src/routes/_app/datahub/$subjectId/assignments.tsx b/apps/web/src/routes/_app/datahub/$subjectId/assignments.tsx index 1b428be9d..f2443d27f 100644 --- a/apps/web/src/routes/_app/datahub/$subjectId/assignments.tsx +++ b/apps/web/src/routes/_app/datahub/$subjectId/assignments.tsx @@ -21,6 +21,7 @@ import type { UnilingualInstrumentInfo } from '@opendatacapture/schemas/instrume import { createFileRoute } from '@tanstack/react-router'; import { z } from 'zod/v4'; +import { QRCode } from '@/components/QRCode'; import { useAssignmentsQuery } from '@/hooks/useAssignmentsQuery'; import { useCreateAssignment } from '@/hooks/useCreateAssignment'; import { useInstrument } from '@/hooks/useInstrument'; @@ -40,26 +41,25 @@ const AssignmentSlider: React.FC<{ const instrument = useInstrument(assignment?.instrumentId ?? null); return ( - + {instrument?.details.title} {t('datahub.assignments.assignmentSliderDesc')} - {instrument && ( -
- -
- - -
+
diff --git a/packages/react-core/src/components/InstrumentSummary/InstrumentSummary.tsx b/packages/react-core/src/components/InstrumentSummary/InstrumentSummary.tsx index 5809433a8..acbc85feb 100644 --- a/packages/react-core/src/components/InstrumentSummary/InstrumentSummary.tsx +++ b/packages/react-core/src/components/InstrumentSummary/InstrumentSummary.tsx @@ -14,12 +14,19 @@ import type { SubjectDisplayInfo } from '../../types'; export type InstrumentSummaryProps = { data: any; + displayAllMeasures?: boolean; instrument: AnyUnilingualInstrument; subject?: SubjectDisplayInfo; timeCollected: number; }; -export const InstrumentSummary = ({ data, instrument, subject, timeCollected }: InstrumentSummaryProps) => { +export const InstrumentSummary = ({ + data, + displayAllMeasures, + instrument, + subject, + timeCollected +}: InstrumentSummaryProps) => { const download = useDownload(); const { resolvedLanguage, t } = useTranslation(); @@ -28,6 +35,9 @@ export const InstrumentSummary = ({ data, instrument, subject, timeCollected }: } const computedMeasures = filter(computeInstrumentMeasures(instrument, data), (_, key) => { + if (displayAllMeasures) { + return true; + } const measure = instrument.measures?.[key]; if (measure?.visibility === 'hidden' || measure?.hidden === true) { return false; diff --git a/packages/react-core/src/index.ts b/packages/react-core/src/index.ts index 2f19eb3dc..da795b439 100644 --- a/packages/react-core/src/index.ts +++ b/packages/react-core/src/index.ts @@ -5,6 +5,7 @@ export * from './components/ErrorPage'; export * from './components/InstrumentIcon'; export { InstrumentRenderer, type InstrumentRendererProps } from './components/InstrumentRenderer'; export { ScalarInstrumentRenderer, type ScalarInstrumentRendererProps } from './components/InstrumentRenderer'; +export * from './components/InstrumentSummary'; export * from './components/LoadingPage'; export * from './components/Logo'; export * from './types'; From 6843f36dd46cc7d1b9ed0544d348995080e82882 Mon Sep 17 00:00:00 2001 From: joshunrau Date: Tue, 9 Dec 2025 20:03:25 -0500 Subject: [PATCH 3/4] reorder subject page tabs in datahub --- apps/web/src/routes/_app/datahub/$subjectId/route.tsx | 4 ++-- apps/web/src/routes/_app/datahub/$subjectId/table.tsx | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/web/src/routes/_app/datahub/$subjectId/route.tsx b/apps/web/src/routes/_app/datahub/$subjectId/route.tsx index c3fcdd09e..f043f5cc5 100644 --- a/apps/web/src/routes/_app/datahub/$subjectId/route.tsx +++ b/apps/web/src/routes/_app/datahub/$subjectId/route.tsx @@ -53,6 +53,8 @@ const RouteComponent = () => {
+ + {config.setup.isGatewayEnabled && ( { testId="subject-assignment" /> )} - -
}> diff --git a/apps/web/src/routes/_app/datahub/$subjectId/table.tsx b/apps/web/src/routes/_app/datahub/$subjectId/table.tsx index ac3b146ae..79d7d5dac 100644 --- a/apps/web/src/routes/_app/datahub/$subjectId/table.tsx +++ b/apps/web/src/routes/_app/datahub/$subjectId/table.tsx @@ -8,6 +8,7 @@ import { TimeDropdown } from '@/components/TimeDropdown'; import { useInstrumentVisualization } from '@/hooks/useInstrumentVisualization'; const RouteComponent = () => { + const navigate = Route.useNavigate(); const params = Route.useParams(); const { dl, instrumentId, instrumentOptions, records, setInstrumentId, setMinDate } = useInstrumentVisualization({ params: { subjectId: params.subjectId } @@ -60,6 +61,9 @@ const RouteComponent = () => { data-testid="subject-table" entriesPerPage={15} minRows={15} + onEntryClick={(row) => { + void navigate({ params: { recordId: row.__id__ }, to: '/datahub/$subjectId/$recordId' }); + }} /> ); From 861d4c2836172b2d80ae9fbdd53fcb5f02cdaaec Mon Sep 17 00:00:00 2001 From: joshunrau Date: Tue, 9 Dec 2025 20:12:55 -0500 Subject: [PATCH 4/4] fix test failure caused by change by omitting __id__ from export --- apps/web/src/hooks/useInstrumentVisualization.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/hooks/useInstrumentVisualization.ts b/apps/web/src/hooks/useInstrumentVisualization.ts index 530452aae..28ec5f427 100644 --- a/apps/web/src/hooks/useInstrumentVisualization.ts +++ b/apps/web/src/hooks/useInstrumentVisualization.ts @@ -77,7 +77,7 @@ export function useInstrumentVisualization({ params }: UseInstrumentVisualizatio instrument.internal.edition }_${new Date().toISOString()}`; - const exportRecords = records.map((record) => omit(record, ['__time__'])); + const exportRecords = records.map((record) => omit(record, ['__time__', '__id__'])); const makeWideRows = () => { const columnNames = Object.keys(exportRecords[0]!);