Skip to content

DocumentLibraryView #408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 53 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
9cf48bf
Start of DocumentLibraryView
reneefromhold Feb 10, 2025
620dc37
Update languages and missing main export
reneefromhold Feb 19, 2025
4a13f99
Merge branch 'main' into renee/DocumentLibaryView
reneefromhold Feb 19, 2025
91d229a
Fix build errors from translation files
reneefromhold Feb 19, 2025
0a7fe74
more fixes
reneefromhold Feb 19, 2025
8a554b3
Clean up delete. Do not show DetailView modal. Remove surveyName para…
reneefromhold Feb 20, 2025
8a74f3f
Unit tests for data layer
reneefromhold Feb 20, 2025
f4133b9
DocumentLibraryPreview component + misc
reneefromhold Feb 21, 2025
a31ea2c
2.68.1-DocumentLibaryView.0
reneefromhold Feb 21, 2025
3976e4c
Add missing export of DocumentLibraryPreview
reneefromhold Feb 21, 2025
d035032
2.68.1-DocumentLibaryView.1
reneefromhold Feb 21, 2025
545f56b
2.68.1-DocumentLibaryView.2
reneefromhold Feb 21, 2025
e22b005
2.68.1-DocumentLibaryView.3
reneefromhold Feb 21, 2025
272024c
Update export
reneefromhold Feb 24, 2025
471e45e
2.68.1-DocumentLibaryView.4
reneefromhold Feb 24, 2025
954a415
Undo version in package.json.
reneefromhold Feb 24, 2025
e29a9e1
2.69.1-DocumentLibaryView.0
reneefromhold Feb 24, 2025
75e5462
Changes to onClick of DocumentLibraryPreview
reneefromhold Feb 24, 2025
387c7f1
2.69.1-DocumentLibaryView.1
reneefromhold Feb 24, 2025
7c40963
Fix count on document library preview
reneefromhold Feb 25, 2025
238d209
2.69.1-DocumentLibaryView.2
reneefromhold Feb 25, 2025
fd8eb05
Some clean up and layout experimentation
reneefromhold Feb 27, 2025
a97d369
2.69.1-DocumentLibaryView.3
reneefromhold Feb 27, 2025
41ffb57
More
reneefromhold Feb 27, 2025
8082b77
2.69.1-DocumentLibaryView.4
reneefromhold Feb 27, 2025
9f90617
Merge branch 'main' into renee/DocumentLibaryView
greinard Feb 27, 2025
3bc95c0
2.72.1-DocumentLibaryView.0
greinard Feb 27, 2025
a02003e
manually copy in rollup fixes
reneefromhold Feb 28, 2025
04dde7c
2.72.1-DocumentLibaryView.1
reneefromhold Feb 28, 2025
146b40b
Remove unnecassary urlsearchparam
reneefromhold Feb 28, 2025
5593bdb
2.72.1-DocumentLibaryView.2
reneefromhold Feb 28, 2025
00e0002
2.72.1-DocumentLibaryView.2
reneefromhold Feb 28, 2025
1dda0b1
Replace iFrame with download button
reneefromhold Mar 3, 2025
631ee2e
Merge branch 'renee/DocumentLibaryView' of https://github.com/CareEvo…
reneefromhold Mar 3, 2025
cab510d
Remove showDownload from Preview data
reneefromhold Mar 3, 2025
94f8fda
2.72.1-DocumentLibaryView.3
reneefromhold Mar 4, 2025
9c761eb
2.72.1-DocumentLibaryView.4
reneefromhold Mar 4, 2025
b679caf
2.72.1-DocumentLibaryView.5
reneefromhold Mar 4, 2025
4f97e8b
2.72.1-DocumentLibaryView.6
reneefromhold Mar 4, 2025
0cd7830
2.72.1-DocumentLibaryView.7
reneefromhold Mar 5, 2025
feb7032
2.72.1-DocumentLibaryView.8
reneefromhold Mar 5, 2025
6161bcd
2.72.1-DocumentLibaryView.9
reneefromhold Mar 5, 2025
8131c9f
2.72.1-DocumentLibaryView.10
reneefromhold Mar 6, 2025
514efcc
2.72.1-DocumentLibaryView.11
reneefromhold Mar 6, 2025
2819772
Improve display across viewports and with empty optional fields
reneefromhold Mar 10, 2025
a3793c6
Tighten up code for optional fields
reneefromhold Mar 10, 2025
e0a5fb5
2.72.1-DocumentLibaryView.12
reneefromhold Mar 10, 2025
a4bfad0
More support for undefined type
reneefromhold Mar 10, 2025
385754f
2.72.1-DocumentLibaryView.13
reneefromhold Mar 10, 2025
9c5cdf8
Use back vs dismiss
reneefromhold Mar 10, 2025
9000851
2.72.1-DocumentLibaryView.14
reneefromhold Mar 10, 2025
ea5a068
Long notes wrap
reneefromhold Mar 10, 2025
644a255
2.72.1-DocumentLibaryView.15
reneefromhold Mar 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions __tests__/helpers/query-all-survey-files.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { deleteSurveyResultFiles, queryAllSurveyFiles, SurveyUploadedFile } from "../../src/helpers";
import MyDataHelps, { SurveyAnswer } from '@careevolution/mydatahelps-js';

jest.mock('@careevolution/mydatahelps-js', () => {
const answers : SurveyAnswer[] = [
{id: "abc123", surveyResultID: "abc123", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "fileName", answers: ["Colonoscopy Report"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "def456", surveyResultID: "abc123", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "file", answers: ["Colon.txt"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "ghi789", surveyResultID: "abc123", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "fileNotes", answers: ["Notes on colonoscopy"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "jkl012", surveyResultID: "abc123", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "fileType", answers: ["Other"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "mno345", surveyResultID: "abc123", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "fileDate", answers: ["2025-01-01"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "pqr678", surveyResultID: "pqr678", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "fileName", answers: ["BCBS Insurance"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "stu901", surveyResultID: "pqr678", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "file", answers: ["BCBS.png"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "vwx234", surveyResultID: "pqr678", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "fileNotes", answers: [], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "yza567", surveyResultID: "pqr6789", surveyName: "wrong-test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "fileType", answers: ["Insurance"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "bcd890", surveyResultID: "pqr678", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "fileDate", answers: ["2025-02-01"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "efg123", surveyResultID: "pqr678", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2021-01-01", stepIdentifier: "step1", resultIdentifier: "result11", answers: ["answer11"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "a3c123", surveyResultID: "456abc", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2025-01-01", stepIdentifier: "step1", resultIdentifier: "fileName", answers: ["Mammography Report"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "d3f456", surveyResultID: "456abc", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2025-01-01", stepIdentifier: "step1", resultIdentifier: "file", answers: ["TestsResults.pdf"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "g3i789", surveyResultID: "456abc", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2025-01-01", stepIdentifier: "step1", resultIdentifier: "fileNotes", answers: ["These are in the portal"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "j3l012", surveyResultID: "456abc", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2025-01-01", stepIdentifier: "step1", resultIdentifier: "fileType", answers: ["Results"], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
{id: "m3o345", surveyResultID: "456abc", surveyName: "test-survey", surveyDisplayName: "Test Survey", date: "2024-01-01", stepIdentifier: "step1", resultIdentifier: "fileDate", answers: [""], insertedDate: "2021-01-01", surveyID: "123456", surveyVersion: 1},
];

const answersPage = {
surveyAnswers: answers
};

return {
__esModule: true,
default: {
token: { access_token: '1' },
getCurrentLanguage: () => jest.fn(),
deleteSurveyResult: jest.fn().mockResolvedValue(undefined),
deleteFile: jest.fn().mockResolvedValue(undefined),
querySurveyAnswers: jest.fn(() => {
return Promise.resolve(answersPage);
}),
on: jest.fn(),
off: jest.fn()
}
}
});

afterEach(() => {
jest.clearAllMocks();
});

const colonoscopyReport : SurveyUploadedFile = {
surveyResultId: "abc123",
fileCategory: "surveyresult_abc123",
title: "Colonoscopy Report",
fileName: "Colon.txt",
type: "Other",
notes: "Notes on colonoscopy",
date: new Date("2025-01-01T00:00:00")
};

const mammographyReport : SurveyUploadedFile = {
surveyResultId: "456abc",
fileCategory: "surveyresult_456abc",
title: "Mammography Report",
fileName: "TestsResults.pdf",
type: "Results",
notes: "These are in the portal",
date: new Date("2024-01-01T00:00:00") //confirms use of result date when answer not on file
};

const emptyOptionalFieldsReport : SurveyUploadedFile = {
surveyResultId: "pqr678",
fileCategory: "surveyresult_pqr678",
title: "BCBS Insurance",
fileName: "BCBS.png",
date: new Date("2025-02-01T00:00:00")
};

test("a SurveyUploadedFile is returned when all required fields are on file", async () => {
const surveyFiles = await queryAllSurveyFiles({
uploadDocumentSurveyName: "test-survey",
fileResultIdentifier: "file",
typeResultIdentifier: "fileType",
nameResultIdentifier: "fileName",
dateResultIdentifier: "fileDate",
notesResultIdentifier: "fileNotes"
});

expect(surveyFiles).toHaveLength(3);
expect(surveyFiles).toContainEqual(mammographyReport);
expect(surveyFiles).toContainEqual(colonoscopyReport);
expect(surveyFiles).toContainEqual(emptyOptionalFieldsReport);
});

test("should call both MyDataHelps.deleteSurveyResult and MyDataHelps.deleteFile", async () => {
await deleteSurveyResultFiles("test-id", "test-file-key");
expect(MyDataHelps.deleteSurveyResult).toHaveBeenCalledWith("test-id");
expect(MyDataHelps.deleteFile).toHaveBeenCalledWith("test-file-key");
});

test("should not delete file if MyDataHelps.deleteSurveyResult fails", async () => {
(MyDataHelps.deleteSurveyResult as jest.Mock).mockRejectedValueOnce(new Error("Failed to delete survey result"));
await deleteSurveyResultFiles("test-id", "test-file-key");
expect(MyDataHelps.deleteSurveyResult).toHaveBeenCalledWith("test-id");
expect(MyDataHelps.deleteFile).toHaveBeenCalledTimes(0);
});

test("should not call either MyDataHelps.deleteSurveyResult and MyDataHelps.deleteFile if surveyResultId is empty string", async () => {
await deleteSurveyResultFiles("", "test-file-key");
expect(MyDataHelps.deleteSurveyResult).toHaveBeenCalledTimes(0);
expect(MyDataHelps.deleteFile).toHaveBeenCalledTimes(0);
});

test("should not call either MyDataHelps.deleteSurveyResult and MyDataHelps.deleteFile if fileKey is empty string", async () => {
await deleteSurveyResultFiles("test-id", "");
expect(MyDataHelps.deleteSurveyResult).toHaveBeenCalledTimes(0);
expect(MyDataHelps.deleteFile).toHaveBeenCalledTimes(0);
});
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@careevolution/mydatahelps-ui",
"version": "2.72.0",
"version": "2.72.1-DocumentLibaryView.15",
"description": "MyDataHelps UI Library",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.mdhui-document-library-preview .file-title {
font-size: .88em;
color: var(--mdhui-text-color-2);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function getPreviewData(): string[] {
return [
"Insurance Card",
"Mammogram Results",
"Blood Test Results",
];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from "react"
import { Meta, StoryObj } from "@storybook/react"
import { Description } from "@storybook/blocks"
import DocumentLibraryPreview, { DocumentLibraryPreviewProps } from "./DocumentLibraryPreview";
import { Layout } from "../../presentational";

const meta: Meta<typeof DocumentLibraryPreview> = {
title: "Container/DocumentLibraryPreview",
component: DocumentLibraryPreview,
parameters: {
layout: 'fullscreen',
docs: {
Description: <Description />
}
}
};

export default meta;
type Story = StoryObj<typeof DocumentLibraryPreview>;

const render = (args: DocumentLibraryPreviewProps) =>
<Layout colorScheme="auto">
<DocumentLibraryPreview {...args} />
</Layout>;

const defaultProps: DocumentLibraryPreviewProps = {
uploadDocumentSurveyName: 'UploadDocument',
fileResultIdentifier: 'document',
typeResultIdentifier: 'document_type',
nameResultIdentifier: 'document_name',
dateResultIdentifier: 'document_date',
notesResultIdentifier: 'document_notes',
documentLibraryViewBaseUrl: ''
};

export const NoUploadedFiles: Story = {
args: { ...defaultProps, preview: 'PreviewNoDocuments' },
render: render
};

export const UploadedFiles: Story = {
args: { ...defaultProps, preview: 'PreviewDocuments' },
render: render
};

export const Loading: Story = {
args: { ...defaultProps, preview: 'PreviewLoading' },
render: render
};

export const Live: Story = {
args: { ...defaultProps },
render: render
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React from "react";
import { language, queryAllSurveyFiles, SurveyUploadedFile, SurveyUploadedFileQueryParameters, useInitializeView } from "../../../helpers";
import { Action, Button, Card, LoadingIndicator } from "../../presentational";
import { FontAwesomeSvgIcon } from "react-fontawesome-svg-icon";
import { faCamera } from "@fortawesome/free-solid-svg-icons";
import MyDataHelps from "@careevolution/mydatahelps-js";
import { getPreviewData } from "./DocumentLibraryPreview.previewData";
import "./DocumentLibraryPreview.css";
import { noop } from "../../../helpers/functions";

export interface DocumentLibraryPreviewProps {
preview?: "PreviewNoDocuments" | "PreviewDocuments" | "PreviewLoading",
uploadDocumentSurveyName: string,
fileResultIdentifier: string,
typeResultIdentifier: string,
nameResultIdentifier: string,
dateResultIdentifier: string,
notesResultIdentifier: string,
documentLibraryViewBaseUrl: string,
innerRef?: React.Ref<HTMLDivElement>;
}

export default function DocumentLibraryPreview(props: DocumentLibraryPreviewProps) {
const [surveyFiles, setSurveyFiles] = React.useState<string[] | undefined>(undefined);
const [surveyCount, setSurveyCount] = React.useState<number>(0);

async function initialize() {
if (props.preview) {
if (props.preview === "PreviewNoDocuments") {
setSurveyCount(0);
setSurveyFiles([]);
} else if (props.preview === "PreviewDocuments") {
setSurveyCount(6);
setSurveyFiles(getPreviewData());
}
return;
}

const params: SurveyUploadedFileQueryParameters = {
uploadDocumentSurveyName: props.uploadDocumentSurveyName,
fileResultIdentifier: props.fileResultIdentifier,
typeResultIdentifier: props.typeResultIdentifier,
nameResultIdentifier: props.nameResultIdentifier,
dateResultIdentifier: props.dateResultIdentifier,
notesResultIdentifier: props.notesResultIdentifier
};

queryAllSurveyFiles({ ...params }).then((uploadedFiles: SurveyUploadedFile[]) => {
const sortedFiles = uploadedFiles.sort((a, b) => {
return a.date > b.date ? -1 : 1;
});

setSurveyCount(uploadedFiles.length);
const top3Files = sortedFiles.slice(0, 3).map((file: SurveyUploadedFile, index: number) =>
file.title
);
setSurveyFiles(top3Files);
});
}

const onShowDocumentLibraryClick = () => {
if (props.preview || !props.documentLibraryViewBaseUrl) {
console.log("onShowDocumentLibraryClick");
return;
}

const params = new URLSearchParams({
uploadDocumentSurveyName: props.uploadDocumentSurveyName,
fileResultIdentifier: props.fileResultIdentifier,
typeResultIdentifier: props.typeResultIdentifier,
nameResultIdentifier: props.nameResultIdentifier,
dateResultIdentifier: props.dateResultIdentifier,
notesResultIdentifier: props.notesResultIdentifier
});

const separator = props.documentLibraryViewBaseUrl.includes('?') ? '&' : '?';
const documentLibraryViewUrl = `${props.documentLibraryViewBaseUrl}${separator}${params.toString()}`;
MyDataHelps.openApplication(documentLibraryViewUrl);
}

const onUploadClick = () => {
if (props.preview) {
console.log("onUploadClick");
return;
}

MyDataHelps.startSurvey(props.uploadDocumentSurveyName);
}

useInitializeView(() => {
initialize();
}, [], []);

return (
<div ref={props.innerRef} className="mdhui-document-library-preview">
{!surveyFiles && <LoadingIndicator />}
{surveyFiles &&
<Card>
<Action title={` ${language("uploaded-documents")}`}
renderAs="div"
className="font-size"
indicatorPosition="default"
subtitle={surveyFiles.length === 0
? language("upload-documents-subtitle")
: ""}
titleIcon={<FontAwesomeSvgIcon icon={faCamera} />}
indicatorValue={surveyCount > 0 ? surveyCount.toString() : undefined}
onClick={surveyFiles.length === 0
? undefined :
onShowDocumentLibraryClick}
indicator={surveyFiles.length === 0
? <Button variant="default" fullWidth={false} onClick={onUploadClick}>{language("upload")}</Button>
: undefined}
>
{surveyFiles.length > 0
? surveyFiles.map((file, index) => <div className="file-title" key={index}>{file}</div>)
: undefined
}
</Action>
</Card>
}
</div>
)
}
1 change: 1 addition & 0 deletions src/components/container/DocumentLibraryPreview/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./DocumentLibraryPreview";
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export var previewIncompleteTasks: SurveyTask[] =
"surveyDescription": "10 minutes",
"status": "incomplete",
"hasSavedProgress": false,
"dueDate": null,
"dueDate": undefined,
"insertedDate": "2022-03-15T16:56:26.703Z",
"modifiedDate": "2022-03-15T16:56:26.703Z",
linkIdentifier: "1"
Expand Down
1 change: 1 addition & 0 deletions src/components/container/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export { default as DailyDataChart } from "./DailyDataChart"
export { default as DailyDataGoal } from "./DailyDataGoal"
export { default as DeviceDataMonthChart, DeviceDataChartLine } from "./DeviceDataMonthChart"
export { default as DeviceDataMonthCharts } from "./DeviceDataMonthCharts"
export { default as DocumentLibraryPreview } from "./DocumentLibraryPreview"
export { default as EhrNewsFeed, EhrNewsFeedEventReference } from "./EhrNewsFeed"
export { default as EhrNewsFeedEventDetail } from "./EhrNewsFeedEventDetail"
export { default as ExternalAccountConnectionAlert } from "./ExternalAccountConnectionAlert"
Expand Down
Loading
Loading