diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index 88316ae..e36a14e 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -31,6 +31,7 @@ module.exports = { "react/no-array-index-key": "off", "jsx-a11y/click-events-have-key-events": "off", "jsx-a11y/no-static-element-interactions": "off", + "react/prop-types": "off", }, ignorePatterns: ["build/*"], }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5c076c8..0fcf136 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -42,6 +42,7 @@ "react-jsonschema-form": "^1.8.1", "react-router-dom": "^5.2.0", "react-scripts": "4.0.2", + "react-select": "^5.8.0", "react-table": "^7.7.0", "typescript": "^4.1.2", "web-vitals": "^1.0.1" @@ -2733,6 +2734,28 @@ "node": ">=8" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz", + "integrity": "sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==", + "dependencies": { + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz", + "integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==", + "dependencies": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz", + "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==" + }, "node_modules/@graphql-typed-document-node/core": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz", @@ -14422,6 +14445,11 @@ "node": ">= 0.6" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -18659,6 +18687,26 @@ "node": ">=0.10.0" } }, + "node_modules/react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-shallow-renderer": { "version": "16.15.0", "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", @@ -22103,6 +22151,19 @@ } } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", @@ -25619,6 +25680,28 @@ } } }, + "@floating-ui/core": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz", + "integrity": "sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==", + "requires": { + "@floating-ui/utils": "^0.2.0" + } + }, + "@floating-ui/dom": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz", + "integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==", + "requires": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "@floating-ui/utils": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz", + "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==" + }, "@graphql-typed-document-node/core": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz", @@ -34065,6 +34148,11 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -37048,6 +37136,22 @@ } } }, + "react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "requires": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + } + }, "react-shallow-renderer": { "version": "16.15.0", "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", @@ -39511,6 +39615,12 @@ "tslib": "^2.0.0" } }, + "use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "requires": {} + }, "use-sidecar": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 7530e2b..b14c92b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -37,6 +37,7 @@ "react-jsonschema-form": "^1.8.1", "react-router-dom": "^5.2.0", "react-scripts": "4.0.2", + "react-select": "^5.8.0", "react-table": "^7.7.0", "typescript": "^4.1.2", "web-vitals": "^1.0.1" diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 932ffb4..438dd2f 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -13,6 +13,7 @@ import SimpleEntityDisplayPage from "./components/pages/SimpleEntityDisplayPage" import NotFound from "./components/pages/NotFound"; import UpdatePage from "./components/pages/UpdatePage"; import SimpleEntityUpdatePage from "./components/pages/SimpleEntityUpdatePage"; +import DashboardPage from "./components/pages/DashboardPage"; import * as Routes from "./constants/Routes"; import AUTHENTICATED_USER_KEY from "./constants/AuthConstants"; import AuthContext from "./contexts/AuthContext"; @@ -57,6 +58,8 @@ const App = (): React.ReactElement => { + {/* TODO: Move to private route eventually */} + { return ; } - // For testing purposes - const filter = { - causes: [],//empty array will include all causes - frequencies: ["Monthly", "One-time"], //if not empty, only donations with these frequencies will be included - years: [] -}; - return (

Login

@@ -108,8 +99,6 @@ const Login = (): React.ReactElement => { Sign Up
- {/* For testing purposes */} - ); }; diff --git a/frontend/src/components/common/DonationsTable.tsx b/frontend/src/components/common/DonationsTable.tsx index 2e8154b..096f865 100644 --- a/frontend/src/components/common/DonationsTable.tsx +++ b/frontend/src/components/common/DonationsTable.tsx @@ -12,27 +12,25 @@ import { Box, } from '@chakra-ui/react' -type Donation = { +interface Donation { Cause: string; - Date: string; - Time: string; + Date: Date; Amount: number; Frequency: string; -}; +} -type Filter = { +interface Filter { causes?: string[]; frequencies?: string[]; years?: string[]; -}; +} -type DonationsTableProps = { +interface DonationsTableProps { filter: Filter; data: Donation[]; } const DonationsTable: React.FC = ({ filter, data }) => { - const filterData = () => { return data.filter(donation => { return (!filter.causes || filter.causes.length === 0 || filter.causes.includes(donation.Cause)) && @@ -48,31 +46,29 @@ const DonationsTable: React.FC = ({ filter, data }) => { // @ts-ignore - - Donations - - - - - - - - - - - {filteredData.map((donation, index) => ( - - - - - - - + {filteredData.map((donation, index) => ( + + + + + + + + ))} + +
CauseDateTimeAmountFrequency -
{donation.Cause}{donation.Date}{donation.Time}{donation.Amount}{donation.Frequency} + + Donations + + + + + + + - ))} - -
CauseDateTimeAmountFrequency
+ +
{donation.Cause}{donation.Date.toLocaleDateString()}{donation.Date.toLocaleDateString()}{donation.Amount}{donation.Frequency}
); diff --git a/frontend/src/components/common/FilterDropdown.tsx b/frontend/src/components/common/FilterDropdown.tsx new file mode 100644 index 0000000..5530eb2 --- /dev/null +++ b/frontend/src/components/common/FilterDropdown.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import Select from 'react-select'; +import { + FormControl, + FormLabel, +} from '@chakra-ui/react'; + +interface FilterDropdownProps { + label: string; + options: { value: string; label: string }[]; + selectedOptions: { value: string; label: string }[]; + onChange: (selectedOptions: { value: string; label: string }[]) => void; + isMulti?: boolean; +} + +const FilterDropdown: React.FC = ({ + label, + options, + selectedOptions, + onChange, + isMulti = false, +}) => { + const handleChange = (selected: any) => { + onChange(selected || []); + }; + + return ( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + + {label} +