Skip to content

Commit 7d5894a

Browse files
committed
add export to data table
1 parent 68a756c commit 7d5894a

1 file changed

Lines changed: 172 additions & 87 deletions

File tree

apps/web/src/routes/_app/datahub/index.tsx

Lines changed: 172 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
Heading,
1010
SearchBar
1111
} from '@douglasneuroinformatics/libui/components';
12+
import type { TanstackTable } from '@douglasneuroinformatics/libui/components';
1213
import { useDownload, useNotificationsStore, useTranslation } from '@douglasneuroinformatics/libui/hooks';
1314
import type { InstrumentRecordsExport } from '@opendatacapture/schemas/instrument-records';
1415
import type { Subject } from '@opendatacapture/schemas/subject';
@@ -29,70 +30,14 @@ type MasterDataTableProps = {
2930
onSelect: (subject: Subject) => void;
3031
};
3132

32-
const MasterDataTable = ({ data, onSelect }: MasterDataTableProps) => {
33+
const Toggles: React.FC<{ table: TanstackTable.Table<Subject> }> = ({ table }) => {
3334
const { t } = useTranslation();
34-
const subjectIdDisplaySetting = useAppStore((store) => store.currentGroup?.settings.subjectIdDisplayLength);
35-
36-
return (
37-
<div>
38-
<DataTable
39-
columns={[
40-
{
41-
accessorFn: (subject) => removeSubjectIdScope(subject.id).slice(0, subjectIdDisplaySetting ?? 9),
42-
header: t('datahub.index.table.subject'),
43-
id: 'subjectId'
44-
},
45-
{
46-
accessorFn: (subject) => (subject.dateOfBirth ? toBasicISOString(new Date(subject.dateOfBirth)) : 'NULL'),
47-
header: t('core.identificationData.dateOfBirth.label'),
48-
id: 'date-of-birth'
49-
},
50-
{
51-
accessorFn: (subject) => {
52-
switch (subject.sex) {
53-
case 'FEMALE':
54-
return t('core.identificationData.sex.female');
55-
case 'MALE':
56-
return t('core.identificationData.sex.male');
57-
default:
58-
return 'NULL';
59-
}
60-
},
61-
header: t('core.identificationData.sex.label'),
62-
id: 'sex'
63-
}
64-
]}
65-
data={data}
66-
data-testid="master-data-table"
67-
rowActions={[
68-
{
69-
label: t({ en: 'View', fr: 'Voir' }),
70-
onSelect
71-
}
72-
]}
73-
onSearchChange={(value, table) => {
74-
const subjectIdColumn = table.getColumn('subjectId')!;
75-
subjectIdColumn.setFilterValue(value);
76-
}}
77-
/>
78-
</div>
79-
);
80-
};
81-
82-
const RouteComponent = () => {
83-
const [isLookupOpen, setIsLookupOpen] = useState(false);
84-
85-
const currentGroup = useAppStore((store) => store.currentGroup);
86-
const currentUser = useAppStore((store) => store.currentUser);
8735

8836
const download = useDownload();
8937
const addNotification = useNotificationsStore((store) => store.addNotification);
90-
const { t } = useTranslation();
91-
const navigate = useNavigate();
9238

93-
const { data } = useSubjectsQuery({ params: { groupId: currentGroup?.id } });
94-
const [tableData, setTableData] = useState<Subject[]>(data ?? []);
95-
const [searchString, setSearchString] = useState('');
39+
const currentGroup = useAppStore((store) => store.currentGroup);
40+
const currentUser = useAppStore((store) => store.currentUser);
9641

9742
const getExportRecords = async () => {
9843
const response = await axios.get<InstrumentRecordsExport>('/v1/instrument-records/export', {
@@ -107,9 +52,9 @@ const RouteComponent = () => {
10752
const baseFilename = `${currentUser!.username}_${new Date().toISOString()}`;
10853
getExportRecords()
10954
.then((data): any => {
110-
const listedSubjects = tableData.map((record) => {
111-
return removeSubjectIdScope(record.id);
112-
});
55+
const listedSubjects = table
56+
.getRowModel()
57+
.rows.flatMap((row) => row.getVisibleCells().map((cell) => removeSubjectIdScope(cell.row.original.id)));
11358

11459
const filteredData = data.filter((dataEntry) => listedSubjects.includes(dataEntry.subjectId));
11560

@@ -160,33 +105,173 @@ const RouteComponent = () => {
160105
});
161106
};
162107

163-
const lookupSubject = async ({ id }: { id: string }) => {
164-
const response = await axios.get<Subject>(`/v1/subjects/${id}`, {
165-
validateStatus: (status) => status === 200 || status === 404
166-
});
167-
if (response.status === 404) {
168-
addNotification({ message: t('core.notFound'), type: 'warning' });
169-
setIsLookupOpen(false);
170-
} else {
171-
addNotification({ type: 'success' });
172-
await navigate({ to: `./${response.data.id}/table` });
173-
}
174-
};
108+
return (
109+
<>
110+
<ActionDropdown
111+
widthFull
112+
className="min-w-48"
113+
data-spotlight-type="export-data-dropdown"
114+
data-testid="datahub-export-dropdown"
115+
options={['CSV', 'JSON', 'Excel']}
116+
title={t('datahub.index.table.export')}
117+
onSelection={handleExportSelection}
118+
/>
119+
</>
120+
);
121+
// const table = useDataTableHandle('table', true);
122+
// const columns = table.getAllColumns();
123+
// const statusColumn = columns.find((column) => column.id === 'status')!;
124+
125+
// const filterValue = statusColumn.getFilterValue() as PaymentStatus[];
126+
127+
// return (
128+
// <>
129+
// <DropdownMenu>
130+
// <DropdownMenu.Trigger asChild>
131+
// <Button className="flex items-center gap-2" variant="outline">
132+
// Columns
133+
// <ChevronDownIcon />
134+
// </Button>
135+
// </DropdownMenu.Trigger>
136+
// <DropdownMenu.Content align="end">
137+
// {columns
138+
// .filter((column) => column.getCanHide())
139+
// .map((column) => {
140+
// return (
141+
// <DropdownMenu.CheckboxItem
142+
// checked={column.getIsVisible()}
143+
// className="capitalize"
144+
// key={column.id}
145+
// onCheckedChange={(value) => column.toggleVisibility(!!value)}
146+
// >
147+
// {column.id}
148+
// </DropdownMenu.CheckboxItem>
149+
// );
150+
// })}
151+
// </DropdownMenu.Content>
152+
// </DropdownMenu>
153+
// <DropdownMenu>
154+
// <DropdownMenu.Trigger asChild>
155+
// <Button className="flex items-center gap-2" variant="outline">
156+
// Filters
157+
// <ChevronDownIcon />
158+
// </Button>
159+
// </DropdownMenu.Trigger>
160+
// <DropdownMenu.Content widthFull align="start">
161+
// {statuses.map((option) => (
162+
// <DropdownMenu.CheckboxItem
163+
// checked={filterValue.includes(option)}
164+
// className="capitalize"
165+
// key={option}
166+
// onCheckedChange={(checked) => {
167+
// statusColumn.setFilterValue((prevValue: PaymentStatus[]) => {
168+
// if (checked) {
169+
// return [...prevValue, option];
170+
// }
171+
// return prevValue.filter((item) => item !== option);
172+
// });
173+
// }}
174+
// >
175+
// {option}
176+
// </DropdownMenu.CheckboxItem>
177+
// ))}
178+
// </DropdownMenu.Content>
179+
// </DropdownMenu>
180+
// </>
181+
// );
182+
};
183+
184+
const MasterDataTable = ({ data, onSelect }: MasterDataTableProps) => {
185+
const { t } = useTranslation();
186+
const subjectIdDisplaySetting = useAppStore((store) => store.currentGroup?.settings.subjectIdDisplayLength);
187+
188+
return (
189+
<div>
190+
<DataTable
191+
columns={[
192+
{
193+
accessorFn: (subject) => removeSubjectIdScope(subject.id).slice(0, subjectIdDisplaySetting ?? 9),
194+
header: t('datahub.index.table.subject'),
195+
id: 'subjectId'
196+
},
197+
{
198+
accessorFn: (subject) => (subject.dateOfBirth ? toBasicISOString(new Date(subject.dateOfBirth)) : 'NULL'),
199+
header: t('core.identificationData.dateOfBirth.label'),
200+
id: 'date-of-birth'
201+
},
202+
{
203+
accessorFn: (subject) => {
204+
switch (subject.sex) {
205+
case 'FEMALE':
206+
return t('core.identificationData.sex.female');
207+
case 'MALE':
208+
return t('core.identificationData.sex.male');
209+
default:
210+
return 'NULL';
211+
}
212+
},
213+
header: t('core.identificationData.sex.label'),
214+
id: 'sex'
215+
}
216+
]}
217+
data={data}
218+
data-testid="master-data-table"
219+
rowActions={[
220+
{
221+
label: t({ en: 'View', fr: 'Voir' }),
222+
onSelect
223+
}
224+
]}
225+
togglesComponent={Toggles}
226+
onSearchChange={(value, table) => {
227+
const subjectIdColumn = table.getColumn('subjectId')!;
228+
subjectIdColumn.setFilterValue(value);
229+
}}
230+
/>
231+
</div>
232+
);
233+
};
234+
235+
const RouteComponent = () => {
236+
const [isLookupOpen, setIsLookupOpen] = useState(false);
237+
238+
const currentGroup = useAppStore((store) => store.currentGroup);
239+
const currentUser = useAppStore((store) => store.currentUser);
240+
241+
const { t } = useTranslation();
242+
const navigate = useNavigate();
243+
244+
const { data } = useSubjectsQuery({ params: { groupId: currentGroup?.id } });
245+
const [tableData, setTableData] = useState<Subject[]>(data ?? []);
246+
const [searchString, setSearchString] = useState('');
247+
248+
// const lookupSubject = async ({ id }: { id: string }) => {
249+
// const response = await axios.get<Subject>(`/v1/subjects/${id}`, {
250+
// validateStatus: (status) => status === 200 || status === 404
251+
// });
252+
// if (response.status === 404) {
253+
// addNotification({ message: t('core.notFound'), type: 'warning' });
254+
// setIsLookupOpen(false);
255+
// } else {
256+
// addNotification({ type: 'success' });
257+
// await navigate({ to: `./${response.data.id}/table` });
258+
// }
259+
// };
175260

176-
useEffect(() => {
177-
const definedTableData = data ?? [];
261+
// useEffect(() => {
262+
// const definedTableData = data ?? [];
178263

179-
if (!searchString) {
180-
setTableData(definedTableData);
181-
return;
182-
}
264+
// if (!searchString) {
265+
// setTableData(definedTableData);
266+
// return;
267+
// }
183268

184-
const filtered = data.filter((record) =>
185-
removeSubjectIdScope(record.id).toLowerCase().includes(searchString.toLowerCase())
186-
);
269+
// const filtered = data.filter((record) =>
270+
// removeSubjectIdScope(record.id).toLowerCase().includes(searchString.toLowerCase())
271+
// );
187272

188-
setTableData(filtered);
189-
}, [searchString, data]);
273+
// setTableData(filtered);
274+
// }, [searchString, data]);
190275

191276
return (
192277
<React.Fragment>
@@ -233,14 +318,14 @@ const RouteComponent = () => {
233318
</Dialog.Content>
234319
</Dialog>
235320
<div className="flex min-w-60 gap-2 lg:shrink">
236-
<ActionDropdown
321+
{/* <ActionDropdown
237322
widthFull
238323
data-spotlight-type="export-data-dropdown"
239324
data-testid="datahub-export-dropdown"
240325
options={['CSV', 'JSON', 'Excel']}
241326
title={t('datahub.index.table.export')}
242327
onSelection={handleExportSelection}
243-
/>
328+
/> */}
244329
</div>
245330
</div>
246331
<MasterDataTable

0 commit comments

Comments
 (0)