Skip to content

Commit d2f899b

Browse files
committed
add dynamic list of instruments, navigate to datahub onclick of subjects card
1 parent e0305a0 commit d2f899b

1 file changed

Lines changed: 81 additions & 15 deletions

File tree

apps/web/src/routes/_app/dashboard.tsx

Lines changed: 81 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22

3-
import { Heading, Select, StatisticCard } from '@douglasneuroinformatics/libui/components';
3+
import { Dialog, Heading, Select, StatisticCard } from '@douglasneuroinformatics/libui/components';
44
import { useTheme, useTranslation } from '@douglasneuroinformatics/libui/hooks';
55
import type { Theme } from '@douglasneuroinformatics/libui/hooks';
66
import { ClipboardDocumentIcon, DocumentTextIcon, UserIcon, UsersIcon } from '@heroicons/react/24/solid';
77
import type { AppSubjectName } from '@opendatacapture/schemas/core';
8-
import { createFileRoute, redirect } from '@tanstack/react-router';
8+
import { createFileRoute, redirect, useNavigate } from '@tanstack/react-router';
9+
import { AnimatePresence, motion } from 'motion/react';
910
import { Area, AreaChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
1011

1112
import { PageHeader } from '@/components/PageHeader';
13+
import { useInstrumentInfoQuery } from '@/hooks/useInstrumentInfoQuery';
1214
import { summaryQueryOptions, useSummaryQuery } from '@/hooks/useSummaryQuery';
1315
import { useAppStore } from '@/store';
1416

@@ -19,6 +21,9 @@ const RouteComponent = () => {
1921
const { t } = useTranslation();
2022
const [theme] = useTheme();
2123
const summaryQuery = useSummaryQuery({ params: { groupId: currentGroup?.id } });
24+
const navigate = useNavigate();
25+
const [isLookupOpen, setIsLookupOpen] = useState(false);
26+
const instrumentInfoQuery = useInstrumentInfoQuery();
2227

2328
const chartColors = {
2429
records: {
@@ -90,6 +95,19 @@ const RouteComponent = () => {
9095
});
9196
}
9297

98+
const instrumentData = currentGroup
99+
? instrumentInfoQuery.data?.filter((instrument) => {
100+
return currentGroup.accessibleInstrumentIds.includes(instrument.id);
101+
})
102+
: instrumentInfoQuery.data;
103+
104+
const instrumentInfo = instrumentData?.map((record) => {
105+
return {
106+
kind: record.kind,
107+
title: record.details.title
108+
};
109+
});
110+
93111
// should never happen, as data is ensured in loader, but avoid crashing the app if someone changes this
94112
if (!summaryQuery.data) {
95113
return null;
@@ -145,9 +163,14 @@ const RouteComponent = () => {
145163
value={summaryQuery.data.counts.users}
146164
/>
147165
</div>
148-
<div
166+
<button
149167
className="group transform transition-all duration-300 hover:scale-105"
150168
data-testid="statistic-subjects"
169+
onClick={() => {
170+
void navigate({
171+
to: '/datahub'
172+
});
173+
}}
151174
>
152175
<StatisticCard
153176
icon={
@@ -159,21 +182,64 @@ const RouteComponent = () => {
159182
})}
160183
value={summaryQuery.data.counts.subjects}
161184
/>
162-
</div>
185+
</button>
163186
<div
164187
className="group transform transition-all duration-300 hover:scale-105"
165188
data-testid="statistic-instruments"
166189
>
167-
<StatisticCard
168-
icon={
169-
<ClipboardDocumentIcon className="h-12 w-12 text-amber-600 transition-transform duration-300 group-hover:scale-110 dark:text-amber-400" />
170-
}
171-
label={t({
172-
en: 'Total Instruments',
173-
fr: "Nombre d'instruments"
174-
})}
175-
value={summaryQuery.data.counts.instruments}
176-
/>
190+
<Dialog open={isLookupOpen} onOpenChange={setIsLookupOpen}>
191+
<Dialog.Trigger className="grow">
192+
<StatisticCard
193+
icon={
194+
<ClipboardDocumentIcon className="h-12 w-12 text-amber-600 transition-transform duration-300 group-hover:scale-110 dark:text-amber-400" />
195+
}
196+
label={t({
197+
en: 'Total Instruments',
198+
fr: "Nombre d'instruments"
199+
})}
200+
value={summaryQuery.data.counts.instruments}
201+
></StatisticCard>
202+
</Dialog.Trigger>
203+
<Dialog.Content data-spotlight-type="subject-lookup-modal" data-testid="datahub-subject-lookup-dialog">
204+
<Dialog.Header>
205+
<Dialog.Title>
206+
{t({
207+
en: 'Available Instruments',
208+
fr: 'Les instruments'
209+
})}
210+
</Dialog.Title>
211+
</Dialog.Header>
212+
<ul className="flex flex-col gap-5">
213+
<AnimatePresence mode="popLayout">
214+
<div className="flex justify-between gap-4 font-bold">
215+
<p>
216+
{t({
217+
en: 'Title',
218+
fr: 'Titre'
219+
})}
220+
</p>{' '}
221+
<p>{t({ en: 'Kind' })}</p>
222+
</div>
223+
{instrumentInfo?.map((instrument, i) => {
224+
return (
225+
<motion.li
226+
layout
227+
animate={{ opacity: 1, y: 0 }}
228+
exit={{ opacity: 0 }}
229+
initial={{ opacity: 0 }}
230+
key={instrument.title}
231+
transition={{ bounce: 0.2, delay: 0.15 * i, duration: 1.5, type: 'spring' }}
232+
>
233+
<div className="flex justify-between gap-4">
234+
<p>{instrument.title}</p> <p>{instrument.kind}</p>
235+
</div>
236+
</motion.li>
237+
);
238+
})}
239+
</AnimatePresence>
240+
</ul>
241+
</Dialog.Content>
242+
</Dialog>
177243
</div>
178244
<div
179245
className="group transform transition-all duration-300 hover:scale-105"

0 commit comments

Comments
 (0)