From 044c98f348913d92b06fc7370acdec5ffbef74ef Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sun, 23 Oct 2022 11:16:19 +0200 Subject: [PATCH] improved ReportsList.tsx --- package.json | 2 + src/components/DecryptReport.tsx | 44 ++++++- src/hocs/WithEncryptionRequired.tsx | 2 - .../AuthenticateRoute/NavigationButton.tsx | 10 +- .../ReportsRoute/ReportsList.tsx | 123 ++++++++++++++++++ src/routes/AuthenticatedRoute.tsx | 2 +- src/routes/ReportDetailRoute.tsx | 93 ++++++++----- src/routes/ReportsRoute.tsx | 24 ++-- 8 files changed, 236 insertions(+), 64 deletions(-) create mode 100644 src/route-widgets/ReportsRoute/ReportsList.tsx diff --git a/package.json b/package.json index 7215662..a56d8ea 100755 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "react-router-dom": "^6.4.2", "react-use": "^17.4.0", "secure-random-password": "^0.2.3", + "sort-array": "^4.1.5", "ua-parser-js": "^1.0.2", "use-system-theme": "^0.1.1", "yup": "^0.32.11" @@ -46,6 +47,7 @@ "@types/react-router": "^5.1.19", "@types/react-router-dom": "^5.3.3", "@types/secure-random-password": "^0.2.1", + "@types/sort-array": "^4.1.0", "@types/ua-parser-js": "^0.7.36", "@types/yup": "^0.32.0", "@typescript-eslint/eslint-plugin": "^5.40.0", diff --git a/src/components/DecryptReport.tsx b/src/components/DecryptReport.tsx index 7980d97..42f1095 100644 --- a/src/components/DecryptReport.tsx +++ b/src/components/DecryptReport.tsx @@ -2,31 +2,63 @@ import {ReactElement, useContext} from "react" import {useAsync} from "react-use" import camelcaseKeys from "camelcase-keys" -import {DecryptedReportContent} from "~/server-types" +import {DecryptedReportContent, Report} from "~/server-types" import AuthContext from "~/AuthContext/AuthContext" import parseDecryptedReport from "~/apis/helpers/parse-decrypted-report" -export interface DecryptReportProps { +interface DecryptReportPropsBase { + encryptedContent?: string + reports?: Report[] + children: ( + report: DecryptedReportContent | DecryptedReportContent[], + ) => ReactElement +} + +interface DecryptReportPropsEncryptedContent { encryptedContent: string children: (report: DecryptedReportContent) => ReactElement } +interface DecryptReportPropsReports { + reports: Report[] + children: (reports: DecryptedReportContent[]) => ReactElement +} + +export type DecryptReportProps = DecryptReportPropsBase & + (DecryptReportPropsEncryptedContent | DecryptReportPropsReports) + export default function DecryptReport({ encryptedContent, + reports, children: render, }: DecryptReportProps): ReactElement { const {_decryptUsingPrivateKey} = useContext(AuthContext) const {value} = useAsync(async () => { - const message = await _decryptUsingPrivateKey(encryptedContent) - const content = camelcaseKeys(JSON.parse(message), {deep: true}) + const decrypt = async ( + content: string, + ): Promise => + parseDecryptedReport( + camelcaseKeys( + JSON.parse(await _decryptUsingPrivateKey(content)), + {deep: true}, + ), + ) - return parseDecryptedReport(content) - }, [encryptedContent]) + if (encryptedContent) { + return decrypt(encryptedContent) + } else { + return await Promise.all( + reports!.map(report => decrypt(report.encryptedContent)), + ) + } + }, [encryptedContent, reports]) if (!value) { return <> } + console.log(value) + return render(value) } diff --git a/src/hocs/WithEncryptionRequired.tsx b/src/hocs/WithEncryptionRequired.tsx index 0c972d2..e6f07b0 100644 --- a/src/hocs/WithEncryptionRequired.tsx +++ b/src/hocs/WithEncryptionRequired.tsx @@ -12,8 +12,6 @@ export default function WithEncryptionRequired( return (props: any): ReactElement => { const user = useUser() - console.log("withencryption required", user) - if (!user.encryptedPassword) { return ( diff --git a/src/route-widgets/AuthenticateRoute/NavigationButton.tsx b/src/route-widgets/AuthenticateRoute/NavigationButton.tsx index ec68f5a..927a32c 100644 --- a/src/route-widgets/AuthenticateRoute/NavigationButton.tsx +++ b/src/route-widgets/AuthenticateRoute/NavigationButton.tsx @@ -34,10 +34,10 @@ const SECTION_TEXT_MAP: Record = { } const PATH_SECTION_MAP: Record = { - "/": NavigationSection.Overview, - "/aliases": NavigationSection.Aliases, - "/reports": NavigationSection.Reports, - "/settings": NavigationSection.Settings, + "": NavigationSection.Overview, + aliases: NavigationSection.Aliases, + reports: NavigationSection.Reports, + settings: NavigationSection.Settings, } export default function NavigationButton({ @@ -45,7 +45,7 @@ export default function NavigationButton({ }: NavigationButtonProps): ReactElement { const location = useLocation() - const currentSection = PATH_SECTION_MAP[location.pathname] + const currentSection = PATH_SECTION_MAP[location.pathname.split("/")[1]] const Icon = SECTION_ICON_MAP[section] const text = SECTION_TEXT_MAP[section] diff --git a/src/route-widgets/ReportsRoute/ReportsList.tsx b/src/route-widgets/ReportsRoute/ReportsList.tsx new file mode 100644 index 0000000..1ce2f80 --- /dev/null +++ b/src/route-widgets/ReportsRoute/ReportsList.tsx @@ -0,0 +1,123 @@ +import {ReactElement, useState} from "react" +import {MdList} from "react-icons/md" +import {FaMask} from "react-icons/fa" +import groupArray from "group-array" +import sortArray from "sort-array" + +import { + Grid, + InputAdornment, + MenuItem, + TextField, + Typography, +} from "@mui/material" + +import {DecryptedReportContent} from "~/server-types" + +import ReportInformationItem from "./ReportInformationItem" + +export interface ReportsListProps { + reports: DecryptedReportContent[] +} + +enum SortingView { + List = "List", + GroupByAlias = "GroupByAlias", +} + +const SORTING_VIEW_NAME_MAP: Record = { + [SortingView.List]: "List reports by their date", + [SortingView.GroupByAlias]: "Group reports by their aliases", +} + +const SORTING_VIEW_ICON_MAP: Record = { + [SortingView.List]: , + [SortingView.GroupByAlias]: , +} + +export default function ReportsList({reports}: ReportsListProps): ReactElement { + const [sortingView, setSortingView] = useState( + SortingView.List, + ) + + return ( + + + + Reports + + + + + setSortingView(event.target.value as SortingView) + } + label="Sorting" + id="sorting" + InputProps={{ + startAdornment: ( + + {SORTING_VIEW_ICON_MAP[sortingView]} + + ), + }} + select + > + {Object.keys(SORTING_VIEW_NAME_MAP).map(name => ( + + {SORTING_VIEW_NAME_MAP[name as SortingView]} + + ))} + + + + {(() => { + switch (sortingView) { + case SortingView.List: + return sortArray( + reports as DecryptedReportContent[], + { + by: "messageDetails.meta.createdAt", + order: "desc", + }, + ).map(report => ( + + )) + + case SortingView.GroupByAlias: + return Object.entries( + groupArray( + reports as DecryptedReportContent[], + "messageDetails.meta.to", + ), + ).map( + ([alias, reports]: [ + string, + DecryptedReportContent[], + ]) => ( + <> + + {alias} + + {reports.map(report => ( + + ))} + + ), + ) + } + })()} + + + ) +} diff --git a/src/routes/AuthenticatedRoute.tsx b/src/routes/AuthenticatedRoute.tsx index 0441b84..31cd79c 100644 --- a/src/routes/AuthenticatedRoute.tsx +++ b/src/routes/AuthenticatedRoute.tsx @@ -56,7 +56,7 @@ export default function AuthenticatedRoute(): ReactElement { - + diff --git a/src/routes/ReportDetailRoute.tsx b/src/routes/ReportDetailRoute.tsx index 0d8a5c4..33882d4 100644 --- a/src/routes/ReportDetailRoute.tsx +++ b/src/routes/ReportDetailRoute.tsx @@ -27,48 +27,71 @@ export default function ReportDetailRoute(): ReactElement { > {report => ( - + Email Report - + Email information - - - From - - - {report.messageDetails.meta.from} - - - - - To - - - {report.messageDetails.meta.to} - - - - - Subject - - - {report.messageDetails.content.subject} - - + + + + + From + + + { + report.messageDetails.meta + .from + } + + + + + + + To + + + {report.messageDetails.meta.to} + + + + + + + Subject + + + { + report.messageDetails + .content.subject + } + + + + diff --git a/src/routes/ReportsRoute.tsx b/src/routes/ReportsRoute.tsx index ddd57e9..a8abd01 100644 --- a/src/routes/ReportsRoute.tsx +++ b/src/routes/ReportsRoute.tsx @@ -4,12 +4,12 @@ import {AxiosError} from "axios" import {useQuery} from "@tanstack/react-query" import {List} from "@mui/material" -import {PaginationResult, Report} from "~/server-types" +import {DecryptedReportContent, PaginationResult, Report} from "~/server-types" import {getReports} from "~/apis" import {WithEncryptionRequired} from "~/hocs" import {DecryptReport} from "~/components" import QueryResult from "~/components/QueryResult" -import ReportInformationItem from "~/route-widgets/ReportsRoute/ReportInformationItem" +import ReportsList from "~/route-widgets/ReportsRoute/ReportsList" function ReportsRoute(): ReactElement { const query = useQuery, AxiosError>( @@ -21,19 +21,13 @@ function ReportsRoute(): ReactElement { > query={query}> {result => ( - {result.items.map(report => ( - - {report => ( - - )} - - ))} + + {reports => ( + + )} + )}