diff --git a/administration-panel/default.nix b/administration-panel/default.nix index d32320a..3820214 100644 --- a/administration-panel/default.nix +++ b/administration-panel/default.nix @@ -12,7 +12,7 @@ buildNpmPackage { nodejs ]; src = nix-gitignore.gitignoreSource [] ./.; - npmDepsHash = "sha256-0oOi5EVRR6Fl9Zlp9XEkIeSP2P45JdBwm0V8RfWfspo="; + npmDepsHash = "sha256-Kh+9ri5JnjO0fqZOZuQxA7gzHMYGHSrcKuKyvb+tjxA="; configurePhase = '' echo '${config-json}' > config.json diff --git a/administration-panel/package-lock.json b/administration-panel/package-lock.json index 477368d..236290c 100644 --- a/administration-panel/package-lock.json +++ b/administration-panel/package-lock.json @@ -14,6 +14,7 @@ "@fontsource/roboto": "^5.0.8", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.5", + "@mui/x-data-grid": "^6.12.0", "@supabase/postgrest-js": "^1.8.0", "keycloak-js": "^22.0.1", "react": "^18.2.0", @@ -216,9 +217,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", - "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.11.tgz", + "integrity": "sha512-ee7jVNlWN09+KftVOu9n7S8gQzD/Z6hN/I8VBRXW4P1+Xe7kJGXMwu8vds4aGIMHZnNbdpSWCfZZtinytpcAvA==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -699,6 +700,31 @@ "react": "^17.0.0 || ^18.0.0" } }, + "node_modules/@mui/x-data-grid": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-6.12.0.tgz", + "integrity": "sha512-ZuQ8Uq/dF6gjrE/qU6VvP3tgy9n78DdCMD6hbXy/uDIoddJ4J8hSn9S6flnFnFQbRZzF/Q/pPWXZTR4oeg8NQg==", + "dependencies": { + "@babel/runtime": "^7.22.11", + "@mui/utils": "^5.14.5", + "clsx": "^2.0.0", + "prop-types": "^15.8.1", + "reselect": "^4.1.8" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@mui/material": "^5.4.1", + "@mui/system": "^5.4.1", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -4223,6 +4249,11 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, + "node_modules/reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "node_modules/resolve": { "version": "1.22.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", diff --git a/administration-panel/package.json b/administration-panel/package.json index 2d47ea5..95a2c1e 100644 --- a/administration-panel/package.json +++ b/administration-panel/package.json @@ -30,6 +30,7 @@ "@fontsource/roboto": "^5.0.8", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.5", + "@mui/x-data-grid": "^6.12.0", "@supabase/postgrest-js": "^1.8.0", "keycloak-js": "^22.0.1", "react": "^18.2.0", diff --git a/administration-panel/src/pages/MembersTable.tsx b/administration-panel/src/pages/MembersTable.tsx index 8726c3e..10a5700 100644 --- a/administration-panel/src/pages/MembersTable.tsx +++ b/administration-panel/src/pages/MembersTable.tsx @@ -1,73 +1,131 @@ -import * as React from 'react'; -import { PostgrestClient, PostgrestSingleResponse } from '@supabase/postgrest-js' +import * as React from "react"; +import { + PostgrestClient, + PostgrestSingleResponse, +} from "@supabase/postgrest-js"; +import { DataGrid, GridColDef, GridValueGetterParams } from "@mui/x-data-grid"; +import Box from "@mui/material/Box"; interface Props { - postgrest: PostgrestClient; + postgrest: PostgrestClient; } interface Member { - email: string; - first_name: string; - last_name: string; - occupations: [Occupation]; + member_number: number; + id: string; + email: string; + first_name: string; + last_name: string; + phone_number: string; } interface Occupation { - company_name: string | null; - position: string | null; + company_name: string | null; + position: string | null; } interface State { - data: Member[] | null; // TODO: fix me - isLoading: boolean; -} - -const TableRow = (member: Member) => { - return ( - - {member.email} - {member.first_name} - {member.last_name} - {member.occupations.length > 0 ? member.occupations[0].company_name : null} - - ) + data: Member[] | []; + isLoading: boolean; + initialDataLoaded: boolean; } const MembersTable = (props: Props) => { - const [state, setState] = React.useState({ - data: null, - isLoading: false, - }); + const [state, setState] = React.useState({ + data: [], + isLoading: false, + initialDataLoaded: false, + }); - const columns = ['email', 'first_name', 'last_name', 'occupations(company_name, position)']; - React.useEffect(() => { - if (state.data !== null || state.isLoading) { - return; + const columns = [ + "member_number", + "id", + "email", + "first_name", + "last_name", + "phone_number", + ]; + React.useEffect(() => { + if (state.initialDataLoaded !== false || state.isLoading) { + return; + } + setState({ ...state, isLoading: true }); + props.postgrest + .from("members") + .select(columns.join(",")) + .then((result: PostgrestSingleResponse) => { + if (result.data !== null) { + setState({ + ...state, + initialDataLoaded: true, + data: result.data, + isLoading: false, + }); + } else { + setState({ ...state, isLoading: false }); } - setState({ ...state, isLoading: true }); - props.postgrest.from('members').select(columns.join(',')) - .then((result: PostgrestSingleResponse) => setState({ ...state, data: result.data, isLoading: false })) - }); + }); + }); - return ( -
-
Table
- - - - {columns.map((v) => { - return ( - - ) - })} - - - - {(state.data || []).map(TableRow)} - -
{v}
-
- ) -} + const gridcolumns: GridColDef[] = [ + { + field: "member_number", + headerName: "Member Number", + headerClassName: "table-header", //TODO: refactor so the classname is generated + description: "Member number", + flex: 0.5, + minWidth: 120, + }, + { + field: "last_name", + headerName: "Last name", + headerClassName: "table-header", + flex: 1.5, + minWidth: 150, + }, + { + field: "first_name", + headerName: "First Name", + headerClassName: "table-header", + flex: 1.5, + minWidth: 150, + }, + { + field: "phone_number", + headerName: "Phone number", + headerClassName: "table-header", + flex: 1.0, + minWidth: 150, + }, + { + field: "email", + headerName: "Email", + headerClassName: "table-header", + flex: 1.5, + minWidth: 150, + }, + ]; + + return ( +
+

Members Table

+ + + +
+ ); +}; export default MembersTable; diff --git a/administration-panel/src/styles/index.css b/administration-panel/src/styles/index.css index acfd1d1..5097f7a 100644 --- a/administration-panel/src/styles/index.css +++ b/administration-panel/src/styles/index.css @@ -1,22 +1,30 @@ -html, body { - padding: 0; - margin: 0; - height: 100%; +html, +body { + font-family: "Roboto", sans-serif; + padding: 0; + margin: 0; + height: 100%; } #app { - height: 100%; + height: 100%; } .app-wrapper { - display: flex; - flex-direction: column; - gap: 24px; - min-height: 100%; + display: flex; + flex-direction: column; + gap: 24px; + min-height: 100%; } .app-main { - flex-grow: 1; - flex-shrink: 0; - padding: 0 24px; + flex-grow: 1; + flex-shrink: 0; + padding: 0 24px; +} + +.table-header { + background-color: #42a5f5; + color: white; + font-weight: bold; } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..bcb7bf7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "main-system", + "lockfileVersion": 2, + "requires": true, + "packages": {} +}