generated from CDCgov/template
-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16792 from CDCgov/experience/16070/message-bank-page
Experience/16070/message bank page
- Loading branch information
Showing
9 changed files
with
361 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
178 changes: 42 additions & 136 deletions
178
frontend-react/src/components/Admin/EditReceiverSettings.tsx
Large diffs are not rendered by default.
Oops, something went wrong.
64 changes: 64 additions & 0 deletions
64
frontend-react/src/components/Admin/MessageTesting/CustomMessage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { Button, Textarea } from "@trussworks/react-uswds"; | ||
import { ChangeEvent, Dispatch, SetStateAction, useState } from "react"; | ||
import { RSMessage } from "../../../config/endpoints/settings"; | ||
|
||
export const CustomMessage = ({ | ||
customMessageNumber, | ||
currentTestMessages, | ||
setCustomMessageNumber, | ||
setCurrentTestMessages, | ||
setOpenCustomMessage, | ||
}: { | ||
customMessageNumber: number; | ||
currentTestMessages: { fileName: string; reportBody: string }[]; | ||
setCustomMessageNumber: (value: number) => void; | ||
setCurrentTestMessages: Dispatch<SetStateAction<RSMessage[] | null>>; | ||
setOpenCustomMessage: (value: boolean) => void; | ||
}) => { | ||
const [text, setText] = useState(""); | ||
const handleTextareaChange = (event: ChangeEvent<HTMLTextAreaElement>) => { | ||
setText(event.target.value); | ||
}; | ||
const handleAddCustomMessage = () => { | ||
const dateCreated = new Date(); | ||
setCurrentTestMessages([ | ||
...currentTestMessages, | ||
{ | ||
dateCreated: dateCreated.toString(), | ||
fileName: `Custom message ${customMessageNumber}`, | ||
reportBody: text, | ||
}, | ||
]); | ||
setCustomMessageNumber(customMessageNumber + 1); | ||
setText(""); | ||
setOpenCustomMessage(false); | ||
}; | ||
|
||
return ( | ||
<div className="width-full"> | ||
<p className="text-bold">Enter custom message</p> | ||
<p>Custom messages do not save to the bank after you log out.</p> | ||
<Textarea | ||
value={text} | ||
onChange={handleTextareaChange} | ||
id="custom-message-text" | ||
name="custom-message-text" | ||
className="width-full maxw-full margin-bottom-205" | ||
/> | ||
<div className="width-full text-right"> | ||
<Button | ||
type="button" | ||
outline | ||
onClick={() => { | ||
setOpenCustomMessage(false); | ||
}} | ||
> | ||
Cancel | ||
</Button> | ||
<Button type="button" onClick={handleAddCustomMessage} disabled={text.length === 0}> | ||
Add | ||
</Button> | ||
</div> | ||
</div> | ||
); | ||
}; |
114 changes: 114 additions & 0 deletions
114
frontend-react/src/components/Admin/MessageTesting/MessageTesting.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { Button, GridContainer } from "@trussworks/react-uswds"; | ||
import { ChangeEvent, useState } from "react"; | ||
import { Helmet } from "react-helmet-async"; | ||
import { useParams } from "react-router"; | ||
import { CustomMessage } from "./CustomMessage"; | ||
import { RadioField } from "./RadioField"; | ||
import useTestMessages from "../../../hooks/api/messages/UseTestMessages"; | ||
import { FeatureName } from "../../../utils/FeatureName"; | ||
import AdminFetchAlert from "../../alerts/AdminFetchAlert"; | ||
import Crumbs, { CrumbsProps } from "../../Crumbs"; | ||
import Spinner from "../../Spinner"; | ||
import Title from "../../Title"; | ||
import { AdminFormWrapper } from "../AdminFormWrapper"; | ||
import { EditReceiverSettingsParams } from "../EditReceiverSettings"; | ||
|
||
function ReportTesting() { | ||
const { orgname, receivername } = useParams<EditReceiverSettingsParams>(); | ||
const { testMessages, isDisabled, isLoading } = useTestMessages(); | ||
const [selectedOption, setSelectedOption] = useState<string | null>(null); | ||
const [currentTestMessages, setCurrentTestMessages] = useState(testMessages); | ||
const [openCustomMessage, setOpenCustomMessage] = useState(false); | ||
const [customMessageNumber, setCustomMessageNumber] = useState(1); | ||
const crumbProps: CrumbsProps = { | ||
crumbList: [ | ||
{ | ||
label: FeatureName.RECEIVER_SETTINGS, | ||
path: `/admin/orgreceiversettings/org/${orgname}/receiver/${receivername}/action/edit`, | ||
}, | ||
{ label: FeatureName.MESSAGE_TESTING }, | ||
], | ||
}; | ||
|
||
if (isDisabled) { | ||
return <AdminFetchAlert />; | ||
} | ||
if (isLoading || !currentTestMessages) return <Spinner />; | ||
|
||
const handleSelect = (event: ChangeEvent<HTMLInputElement>) => { | ||
setSelectedOption(event.target.value); | ||
}; | ||
|
||
const handleAddCustomMessage = () => { | ||
setSelectedOption(null); | ||
setOpenCustomMessage(true); | ||
}; | ||
|
||
return ( | ||
<> | ||
<Helmet> | ||
<title>Message testing - ReportStream</title> | ||
</Helmet> | ||
<GridContainer> | ||
<Crumbs {...crumbProps}></Crumbs> | ||
</GridContainer> | ||
<AdminFormWrapper | ||
header={ | ||
<> | ||
<Title title={"Message testing"} /> | ||
<h2 className="margin-bottom-0"> | ||
<span className="text-normal font-body-md text-base margin-bottom-0"> | ||
Org name: {orgname} | ||
<br /> | ||
Receiver name: {receivername} | ||
</span> | ||
</h2> | ||
</> | ||
} | ||
> | ||
<GridContainer> | ||
<p> | ||
Test a message from the message bank or by entering a custom message. You can view test results | ||
in this window while you are logged in. To save for later reference, you can open messages, test | ||
results and output messages in separate tabs. | ||
</p> | ||
<hr /> | ||
<p className="font-sans-xl text-bold">Test message bank</p> | ||
<form> | ||
<fieldset className="usa-fieldset bg-base-lightest padding-3"> | ||
{currentTestMessages?.map((item, index) => ( | ||
<RadioField | ||
key={index} | ||
index={index} | ||
title={item.fileName} | ||
body={item.reportBody} | ||
handleSelect={handleSelect} | ||
selectedOption={selectedOption} | ||
/> | ||
))} | ||
{openCustomMessage && ( | ||
<CustomMessage | ||
customMessageNumber={customMessageNumber} | ||
currentTestMessages={currentTestMessages} | ||
setCustomMessageNumber={setCustomMessageNumber} | ||
setCurrentTestMessages={setCurrentTestMessages} | ||
setOpenCustomMessage={setOpenCustomMessage} | ||
/> | ||
)} | ||
</fieldset> | ||
<div className="padding-top-4"> | ||
<Button type="button" outline onClick={handleAddCustomMessage}> | ||
Test custom message | ||
</Button> | ||
<Button disabled={!selectedOption} type="button"> | ||
Run test | ||
</Button> | ||
</div> | ||
</form> | ||
</GridContainer> | ||
</AdminFormWrapper> | ||
</> | ||
); | ||
} | ||
|
||
export default ReportTesting; |
57 changes: 57 additions & 0 deletions
57
frontend-react/src/components/Admin/MessageTesting/RadioField.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { Button, Icon, Radio } from "@trussworks/react-uswds"; | ||
import { ChangeEvent } from "react"; | ||
|
||
export const RadioField = ({ | ||
title, | ||
body, | ||
index, | ||
handleSelect, | ||
selectedOption, | ||
}: { | ||
title: string; | ||
body: string; | ||
index: number; | ||
handleSelect: (event: ChangeEvent<HTMLInputElement>) => void; | ||
selectedOption: string | null; | ||
}) => { | ||
const openTextInNewTab = () => { | ||
let formattedContent = body; | ||
|
||
// Check if the content is JSON and format it | ||
try { | ||
formattedContent = JSON.stringify(JSON.parse(body), null, 2); | ||
} catch { | ||
formattedContent = body; | ||
} | ||
|
||
const blob = new Blob([formattedContent], { type: "text/plain" }); | ||
|
||
const url = URL.createObjectURL(blob); | ||
|
||
window.open(url, "_blank"); | ||
|
||
// Revoke the URL to free up memory | ||
URL.revokeObjectURL(url); | ||
}; | ||
|
||
return ( | ||
<Radio | ||
id={`message-${index}`} | ||
name="message-test-form" | ||
value={body} | ||
onChange={handleSelect} | ||
checked={selectedOption === body} | ||
className="usa-radio bg-base-lightest padding-2 border-bottom-1px border-gray-30" | ||
label={ | ||
<> | ||
{" "} | ||
{title}{" "} | ||
<Button type="button" unstyled onClick={openTextInNewTab}> | ||
View message | ||
<Icon.Visibility className="text-tbottom margin-left-05" aria-label="View message" /> | ||
</Button> | ||
</> | ||
} | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { useSuspenseQuery } from "@tanstack/react-query"; | ||
import { useCallback } from "react"; | ||
import { reportsEndpoints, RSMessage } from "../../../config/endpoints/settings"; | ||
import useSessionContext from "../../../contexts/Session/useSessionContext"; | ||
import { Organizations } from "../../UseAdminSafeOrganizationName/UseAdminSafeOrganizationName"; | ||
|
||
const { testing } = reportsEndpoints; | ||
|
||
/** | ||
* Custom hook to fetch and manage "Test Messages" data for the current session. | ||
* | ||
* @description | ||
* This hook fetches "Test Messages" from the backend. While the UI and design refer to this feature as | ||
* "Test Messages," the corresponding API endpoint is `/api/reports/testing`, which uses the "Reports" nomenclature. | ||
* This discrepancy exists between the backend naming convention ("Reports") and the frontend display ("Messages"). | ||
* | ||
* @returns {object} The hook returns the following: | ||
* - `testMessages` (`RSMessage[] | undefined`): The fetched array of test messages. | ||
* - `isDisabled` (`boolean`): Indicates whether the feature is disabled for the current user. | ||
* - Other properties from `useSuspenseQuery` (e.g., `isLoading`, `isError`, `error`). | ||
*/ | ||
|
||
const useTestMessages = () => { | ||
const { activeMembership, authorizedFetch } = useSessionContext(); | ||
const parsedName = activeMembership?.parsedName; | ||
const isAdmin = Boolean(parsedName) && parsedName === Organizations.PRIMEADMINS; | ||
|
||
const memoizedDataFetch = useCallback(() => { | ||
if (isAdmin) { | ||
return authorizedFetch<RSMessage[]>({}, testing); | ||
} | ||
return null; | ||
}, [isAdmin, authorizedFetch]); | ||
const useSuspenseQueryResult = useSuspenseQuery({ | ||
queryKey: [testing.queryKey, activeMembership], | ||
queryFn: memoizedDataFetch, | ||
}); | ||
|
||
const { data } = useSuspenseQueryResult; | ||
|
||
return { | ||
...useSuspenseQueryResult, | ||
testMessages: data, | ||
isDisabled: !isAdmin, | ||
}; | ||
}; | ||
|
||
export default useTestMessages; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
export enum FeatureName { | ||
ADMIN = "Admin", | ||
DAILY_DATA = "Daily Data", | ||
DATA_DASHBOARD = "Data Dashboard", | ||
FACILITIES_PROVIDERS = "All facilities & providers", | ||
MESSAGE_TESTING = "Message testing", | ||
PUBLIC_KEY = "Public Key", | ||
RECEIVER_SETTINGS = "Receiver settings", | ||
REPORT_DETAILS = "Report Details", | ||
SUBMISSIONS = "Submissions", | ||
SUPPORT = "Support", | ||
ADMIN = "Admin", | ||
UPLOAD = "Upload", | ||
FACILITIES_PROVIDERS = "All facilities & providers", | ||
DATA_DASHBOARD = "Data Dashboard", | ||
REPORT_DETAILS = "Report Details", | ||
PUBLIC_KEY = "Public Key", | ||
} |
Oops, something went wrong.