From 4156f32e0d60ad3b6d10ffe8cce5b8565a8d776e Mon Sep 17 00:00:00 2001 From: akinola Olanrewaju Date: Wed, 6 Dec 2023 11:16:23 -0800 Subject: [PATCH 1/3] created new estimate list --- .../api/v1/admin/customers_controller.rb | 9 + .../api/v1/admin/subscribers_controller.rb | 9 + frontend/package-lock.json | 702 +++++++++++++++++- frontend/package.json | 6 + .../components/estimate-list/EstimateList.jsx | 141 ++++ frontend/src/pages/admin/Admin.jsx | 16 +- 6 files changed, 851 insertions(+), 32 deletions(-) create mode 100644 backend/app/controllers/api/v1/admin/customers_controller.rb create mode 100644 backend/app/controllers/api/v1/admin/subscribers_controller.rb create mode 100644 frontend/src/components/estimate-list/EstimateList.jsx diff --git a/backend/app/controllers/api/v1/admin/customers_controller.rb b/backend/app/controllers/api/v1/admin/customers_controller.rb new file mode 100644 index 0000000..bd67e8e --- /dev/null +++ b/backend/app/controllers/api/v1/admin/customers_controller.rb @@ -0,0 +1,9 @@ +class Api::V1::Admin::CustomersController < ApplicationController +include ActionController::HttpAuthentication::Basic::ControllerMethods + http_basic_authenticate_with name: ENV['ADMIN_USERNAME'], password: ENV['ADMIN_PASSWORD'] + def index + @customers = Customer.all + + render json: @customers + end + end diff --git a/backend/app/controllers/api/v1/admin/subscribers_controller.rb b/backend/app/controllers/api/v1/admin/subscribers_controller.rb new file mode 100644 index 0000000..1158c24 --- /dev/null +++ b/backend/app/controllers/api/v1/admin/subscribers_controller.rb @@ -0,0 +1,9 @@ +class Api::V1::Admin::SubscribersController < ApplicationController + include ActionController::HttpAuthentication::Basic::ControllerMethods + http_basic_authenticate_with name: ENV['ADMIN_USERNAME'], password: ENV['ADMIN_PASSWORD'] + def index + @subscribers = Subscriber.all + + render json: @subscribers + end + end \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9f5c8e0..0f5a6bd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -5,9 +5,15 @@ "requires": true, "packages": { "": { + "name": "frontend", "version": "0.1.0", "dependencies": { "@babel/plugin-proposal-private-property-in-object": "*", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@mui/material": "^5.14.20", + "@mui/styled-engine-sc": "^6.0.0-alpha.7", + "@mui/x-data-grid": "^6.18.3", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -23,6 +29,7 @@ "react-simple-snackbar": "^1.1.11", "sass": "^1.69.5", "scss": "^0.2.4", + "styled-components": "^6.1.1", "web-vitals": "^2.1.4" } }, @@ -1964,9 +1971,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", + "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2354,6 +2361,14 @@ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", + "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, "node_modules/@emotion/memoize": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", @@ -2399,6 +2414,28 @@ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" }, + "node_modules/@emotion/styled": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", + "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/is-prop-valid": "^1.2.1", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@emotion/unitless": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", @@ -2552,6 +2589,18 @@ "@floating-ui/utils": "^0.1.3" } }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", + "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", + "dependencies": { + "@floating-ui/dom": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@floating-ui/utils": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", @@ -3331,6 +3380,282 @@ "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.26", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.26.tgz", + "integrity": "sha512-gPMRKC84VRw+tjqYoyBzyrBUqHQucMXdlBpYazHa5rCXrb91fYEQk5SqQ2U5kjxx9QxZxTBvWAmZ6DblIgaGhQ==", + "dependencies": { + "@babel/runtime": "^7.23.4", + "@floating-ui/react-dom": "^2.0.4", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "@popperjs/core": "^2.11.8", + "clsx": "^2.0.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.20.tgz", + "integrity": "sha512-fXoGe8VOrIYajqALysFuyal1q1YmBARqJ3tmnWYDVl0scu8f6h6tZQbS2K8BY28QwkWNGyv4WRfuUkzN5HR3Ow==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/material": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.20.tgz", + "integrity": "sha512-SUcPZnN6e0h1AtrDktEl76Dsyo/7pyEUQ+SAVe9XhHg/iliA0b4Vo+Eg4HbNkELsMbpDsUF4WHp7rgflPG7qYQ==", + "dependencies": { + "@babel/runtime": "^7.23.4", + "@mui/base": "5.0.0-beta.26", + "@mui/core-downloads-tracker": "^5.14.20", + "@mui/system": "^5.14.20", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "@types/react-transition-group": "^4.4.9", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/@mui/private-theming": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.20.tgz", + "integrity": "sha512-WV560e1vhs2IHCh0pgUaWHznrcrVoW9+cDCahU1VTkuwPokWVvb71ccWQ1f8Y3tRBPPcNkU2dChkkRJChLmQlQ==", + "dependencies": { + "@babel/runtime": "^7.23.4", + "@mui/utils": "^5.14.20", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.20.tgz", + "integrity": "sha512-Vs4nGptd9wRslo9zeRkuWcZeIEp+oYbODy+fiZKqqr4CH1Gfi9fdP0Q1tGYk8OiJ2EPB/tZSAyOy62Hyp/iP7g==", + "dependencies": { + "@babel/runtime": "^7.23.4", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine-sc": { + "version": "6.0.0-alpha.7", + "resolved": "https://registry.npmjs.org/@mui/styled-engine-sc/-/styled-engine-sc-6.0.0-alpha.7.tgz", + "integrity": "sha512-7g2TWpbOBeNf4AtbNZSENeNupp2lOt1K3tpAW/g5CWUapEgJA/XKT8GVloGAZ14HlX+mLN5hE0KlRg4h5I5WNg==", + "dependencies": { + "@babel/runtime": "^7.23.4", + "csstype": "^3.1.2", + "hoist-non-react-statics": "^3.3.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "styled-components": "^6.0.0" + } + }, + "node_modules/@mui/system": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.20.tgz", + "integrity": "sha512-jKOGtK4VfYZG5kdaryUHss4X6hzcfh0AihT8gmnkfqRtWP7xjY+vPaUhhuSeibE5sqA5wCtdY75z6ep9pxFnIg==", + "dependencies": { + "@babel/runtime": "^7.23.4", + "@mui/private-theming": "^5.14.20", + "@mui/styled-engine": "^5.14.19", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.10", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz", + "integrity": "sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.20.tgz", + "integrity": "sha512-Y6yL5MoFmtQml20DZnaaK1znrCEwG6/vRSzW8PKOTrzhyqKIql0FazZRUR7sA5EPASgiyKZfq0FPwISRXm5NdA==", + "dependencies": { + "@babel/runtime": "^7.23.4", + "@types/prop-types": "^15.7.11", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, + "node_modules/@mui/x-data-grid": { + "version": "6.18.3", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-6.18.3.tgz", + "integrity": "sha512-0XTLW6e7cB3QBQKoAgdZN2M4WKxbmy0pJHRA9RrSUn91nInqZgwtxpI5fi7aTpX9vffRaUfKi7epr/zNyvxPOQ==", + "dependencies": { + "@babel/runtime": "^7.23.2", + "@mui/utils": "^5.14.16", + "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/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -3440,6 +3765,15 @@ } } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@remix-run/router": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.12.0.tgz", @@ -4432,9 +4766,9 @@ "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" }, "node_modules/@types/prop-types": { - "version": "15.7.10", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.10.tgz", - "integrity": "sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A==" + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/q": { "version": "1.5.8", @@ -4540,6 +4874,11 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" }, + "node_modules/@types/stylis": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.4.tgz", + "integrity": "sha512-36ZrGJ8fgtBr6nwNnuJ9jXIj+bn/pF6UoqmrQT7+Y99+tFFeHHsoR54+194dHdyhPjgbeoNz3Qru0oRt0l6ASQ==" + }, "node_modules/@types/testing-library__jest-dom": { "version": "5.14.9", "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", @@ -5076,8 +5415,6 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "optional": true, - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -5092,9 +5429,7 @@ "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "optional": true, - "peer": true + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/ansi-escapes": { "version": "4.3.2", @@ -6007,6 +6342,14 @@ "node": ">= 6" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -6164,6 +6507,14 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -6442,6 +6793,14 @@ "postcss": "^8.4" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "engines": { + "node": ">=4" + } + }, "node_modules/css-declaration-sorter": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", @@ -6603,6 +6962,16 @@ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/css-tree": { "version": "1.0.0-alpha.37", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", @@ -15281,6 +15650,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "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.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -15911,6 +16285,11 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -16407,6 +16786,38 @@ "webpack": "^5.0.0" } }, + "node_modules/styled-components": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.1.tgz", + "integrity": "sha512-cpZZP5RrKRIClBW5Eby4JM1wElLVP4NQrJbJ0h10TidTyJf4SIIwa3zLXOoPb4gJi8MsJ8mjq5mu2IrEhZIAcQ==", + "dependencies": { + "@emotion/is-prop-valid": "^1.2.1", + "@emotion/unitless": "^0.8.0", + "@types/stylis": "^4.0.2", + "css-to-react-native": "^3.2.0", + "csstype": "^3.1.2", + "postcss": "^8.4.31", + "shallowequal": "^1.1.0", + "stylis": "^4.3.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/stylis": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.0.tgz", + "integrity": "sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==" + }, "node_modules/stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", @@ -17055,6 +17466,19 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -19453,9 +19877,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", + "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", "requires": { "regenerator-runtime": "^0.14.0" } @@ -19680,6 +20104,14 @@ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" }, + "@emotion/is-prop-valid": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", + "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", + "requires": { + "@emotion/memoize": "^0.8.1" + } + }, "@emotion/memoize": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", @@ -19717,6 +20149,19 @@ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" }, + "@emotion/styled": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", + "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/is-prop-valid": "^1.2.1", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1" + } + }, "@emotion/unitless": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", @@ -19833,6 +20278,14 @@ "@floating-ui/utils": "^0.1.3" } }, + "@floating-ui/react-dom": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", + "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", + "requires": { + "@floating-ui/dom": "^1.5.1" + } + }, "@floating-ui/utils": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", @@ -20413,6 +20866,134 @@ "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, + "@mui/base": { + "version": "5.0.0-beta.26", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.26.tgz", + "integrity": "sha512-gPMRKC84VRw+tjqYoyBzyrBUqHQucMXdlBpYazHa5rCXrb91fYEQk5SqQ2U5kjxx9QxZxTBvWAmZ6DblIgaGhQ==", + "requires": { + "@babel/runtime": "^7.23.4", + "@floating-ui/react-dom": "^2.0.4", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "@popperjs/core": "^2.11.8", + "clsx": "^2.0.0", + "prop-types": "^15.8.1" + } + }, + "@mui/core-downloads-tracker": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.20.tgz", + "integrity": "sha512-fXoGe8VOrIYajqALysFuyal1q1YmBARqJ3tmnWYDVl0scu8f6h6tZQbS2K8BY28QwkWNGyv4WRfuUkzN5HR3Ow==" + }, + "@mui/material": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.20.tgz", + "integrity": "sha512-SUcPZnN6e0h1AtrDktEl76Dsyo/7pyEUQ+SAVe9XhHg/iliA0b4Vo+Eg4HbNkELsMbpDsUF4WHp7rgflPG7qYQ==", + "requires": { + "@babel/runtime": "^7.23.4", + "@mui/base": "5.0.0-beta.26", + "@mui/core-downloads-tracker": "^5.14.20", + "@mui/system": "^5.14.20", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "@types/react-transition-group": "^4.4.9", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, + "@mui/private-theming": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.20.tgz", + "integrity": "sha512-WV560e1vhs2IHCh0pgUaWHznrcrVoW9+cDCahU1VTkuwPokWVvb71ccWQ1f8Y3tRBPPcNkU2dChkkRJChLmQlQ==", + "requires": { + "@babel/runtime": "^7.23.4", + "@mui/utils": "^5.14.20", + "prop-types": "^15.8.1" + } + }, + "@mui/styled-engine": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.20.tgz", + "integrity": "sha512-Vs4nGptd9wRslo9zeRkuWcZeIEp+oYbODy+fiZKqqr4CH1Gfi9fdP0Q1tGYk8OiJ2EPB/tZSAyOy62Hyp/iP7g==", + "requires": { + "@babel/runtime": "^7.23.4", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + } + }, + "@mui/styled-engine-sc": { + "version": "6.0.0-alpha.7", + "resolved": "https://registry.npmjs.org/@mui/styled-engine-sc/-/styled-engine-sc-6.0.0-alpha.7.tgz", + "integrity": "sha512-7g2TWpbOBeNf4AtbNZSENeNupp2lOt1K3tpAW/g5CWUapEgJA/XKT8GVloGAZ14HlX+mLN5hE0KlRg4h5I5WNg==", + "requires": { + "@babel/runtime": "^7.23.4", + "csstype": "^3.1.2", + "hoist-non-react-statics": "^3.3.2", + "prop-types": "^15.8.1" + } + }, + "@mui/system": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.20.tgz", + "integrity": "sha512-jKOGtK4VfYZG5kdaryUHss4X6hzcfh0AihT8gmnkfqRtWP7xjY+vPaUhhuSeibE5sqA5wCtdY75z6ep9pxFnIg==", + "requires": { + "@babel/runtime": "^7.23.4", + "@mui/private-theming": "^5.14.20", + "@mui/styled-engine": "^5.14.19", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1" + } + }, + "@mui/types": { + "version": "7.2.10", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz", + "integrity": "sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==", + "requires": {} + }, + "@mui/utils": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.20.tgz", + "integrity": "sha512-Y6yL5MoFmtQml20DZnaaK1znrCEwG6/vRSzW8PKOTrzhyqKIql0FazZRUR7sA5EPASgiyKZfq0FPwISRXm5NdA==", + "requires": { + "@babel/runtime": "^7.23.4", + "@types/prop-types": "^15.7.11", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, + "@mui/x-data-grid": { + "version": "6.18.3", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-6.18.3.tgz", + "integrity": "sha512-0XTLW6e7cB3QBQKoAgdZN2M4WKxbmy0pJHRA9RrSUn91nInqZgwtxpI5fi7aTpX9vffRaUfKi7epr/zNyvxPOQ==", + "requires": { + "@babel/runtime": "^7.23.2", + "@mui/utils": "^5.14.16", + "clsx": "^2.0.0", + "prop-types": "^15.8.1", + "reselect": "^4.1.8" + } + }, "@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -20476,6 +21057,11 @@ "source-map": "^0.7.3" } }, + "@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" + }, "@remix-run/router": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.12.0.tgz", @@ -21225,9 +21811,9 @@ "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" }, "@types/prop-types": { - "version": "15.7.10", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.10.tgz", - "integrity": "sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A==" + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "@types/q": { "version": "1.5.8", @@ -21333,6 +21919,11 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" }, + "@types/stylis": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.4.tgz", + "integrity": "sha512-36ZrGJ8fgtBr6nwNnuJ9jXIj+bn/pF6UoqmrQT7+Y99+tFFeHHsoR54+194dHdyhPjgbeoNz3Qru0oRt0l6ASQ==" + }, "@types/testing-library__jest-dom": { "version": "5.14.9", "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", @@ -21717,13 +22308,14 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "requires": {}, + "requires": { + "ajv": "^8.0.0" + }, "dependencies": { "ajv": { - "version": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "optional": true, - "peer": true, "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -21734,9 +22326,7 @@ "json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "optional": true, - "peer": true + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" } } }, @@ -22414,6 +23004,11 @@ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" }, + "camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==" + }, "caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -22520,6 +23115,11 @@ "wrap-ansi": "^7.0.0" } }, + "clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -22734,6 +23334,11 @@ "postcss-selector-parser": "^6.0.9" } }, + "css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==" + }, "css-declaration-sorter": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", @@ -22825,6 +23430,16 @@ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" }, + "css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "requires": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "css-tree": { "version": "1.0.0-alpha.37", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", @@ -28953,6 +29568,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -29399,6 +30019,11 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -29771,6 +30396,29 @@ "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", "requires": {} }, + "styled-components": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.1.tgz", + "integrity": "sha512-cpZZP5RrKRIClBW5Eby4JM1wElLVP4NQrJbJ0h10TidTyJf4SIIwa3zLXOoPb4gJi8MsJ8mjq5mu2IrEhZIAcQ==", + "requires": { + "@emotion/is-prop-valid": "^1.2.1", + "@emotion/unitless": "^0.8.0", + "@types/stylis": "^4.0.2", + "css-to-react-native": "^3.2.0", + "csstype": "^3.1.2", + "postcss": "^8.4.31", + "shallowequal": "^1.1.0", + "stylis": "^4.3.0", + "tslib": "^2.5.0" + }, + "dependencies": { + "stylis": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.0.tgz", + "integrity": "sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==" + } + } + }, "stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", @@ -30257,6 +30905,12 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "peer": true + }, "unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index ccb30ab..0331176 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,6 +4,11 @@ "private": true, "dependencies": { "@babel/plugin-proposal-private-property-in-object": "*", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@mui/material": "^5.14.20", + "@mui/styled-engine-sc": "^6.0.0-alpha.7", + "@mui/x-data-grid": "^6.18.3", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -19,6 +24,7 @@ "react-simple-snackbar": "^1.1.11", "sass": "^1.69.5", "scss": "^0.2.4", + "styled-components": "^6.1.1", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/frontend/src/components/estimate-list/EstimateList.jsx b/frontend/src/components/estimate-list/EstimateList.jsx new file mode 100644 index 0000000..4b324cd --- /dev/null +++ b/frontend/src/components/estimate-list/EstimateList.jsx @@ -0,0 +1,141 @@ +import React, { useEffect, useState } from 'react'; +import { Box, Typography } from '@mui/material'; +import { DataGrid } from '@mui/x-data-grid'; +import { useMemo } from 'react'; +import axios from 'axios'; + +const URL = process.env.REACT_APP_BACKEND_URL; +const PORT = process.env.REACT_APP_PORT; + +const EstimateList = () => { + const [estimateLists, setEstimateLists] = useState([]); + + const [rowId, setRowId] = useState(null); + + //fetch all the estimates from database + const getAllEstimates = () => { + axios + .get(`${URL}${PORT}/api/v1/customers`) + .then((res) => { + const result = res.data; + setEstimateLists(result); + }) + .catch((error) => { + console.error(error); + }); + }; + + useEffect(() => { + getAllEstimates(); + }, []); + + const handleOption = (params) => { + const { id, field, value } = params; + console.log('Cell Edit:', { id, field, value }); + const updatedEstimateLists = [...estimateLists]; + const updatedRow = updatedEstimateLists.find((row) => row.id === id); + + if (updatedRow && field === 'request_status') { + // Update the local state + updatedRow[field] = value; + setEstimateLists(updatedEstimateLists); + + // axios + // .patch(`${URL}${PORT}/api/v1/customers/${row.id}`, { + // ...row, + // request_status: selectedOption.value + // }) + // .then((res) => { + // setEstimateRow(res.data); + // }) + // .catch((error) => { + // console.log('error', error); + // }); + axios + .patch(`${URL}${PORT}/api/v1/customers/${id}`, { + request_status: value + }) + .then((res) => { + // Handle the response if needed + console.log('Update successful:', res.data); + const updatedEstimateLists = estimateLists.map((row) => + row.id === id ? { ...row, request_status: value } : row + ); + setEstimateLists(updatedEstimateLists); + console.log(estimateLists); + }) + .catch((error) => { + console.error('Error updating status:', error); + }); + } + }; + const columns = useMemo( + () => [ + { field: 'id', headerName: 'S/N', flex: 1, maxWidth: 100 }, + { field: 'first_name', headerName: 'Name', flex: 1, maxWidth: 100 }, + { field: 'last_name', headerName: 'Last Name', flex: 1, maxWidth: 100 }, + { field: 'phone_number', headerName: 'Phone Number', flex: 1, maxWidth: 100 }, + { + field: 'email_address', + headerName: 'Email Address', + flex: 1, + maxWidth: 400, + filterable: false + }, + { field: 'home_address', headerName: 'Home Address', flex: 1, maxWidth: 400 }, + { field: 'service', headerName: 'Service Rquested', flex: 1, maxWidth: 400 }, + { field: 'additional_info', headerName: 'Additional Info', flex: 1, maxWidth: 400 }, + { + field: 'request_status', + headerName: 'Status', + flex: 1, + maxWidth: 150, + type: 'singleSelect', + valueOptions: [ + { value: 'pending', label: 'Pending' }, + { value: 'in process', label: 'In Process' }, + { value: 'completed', label: 'Completed' }, + { value: 'canceled', label: 'Canceled' } + ], + editable: true + } + ], + [] + ); + + const rows = estimateLists; + const handleCellEditCommit = (params) => { + console.log('onCellEditCommit triggered:', params); + handleOption(params); + }; + return ( + + + EstimateList + +
+ true} + pageSize={5} + rowsPerPageOptions={[10, 15, 20]} + loading={!estimateLists.length} + getRowId={(row) => { + const rowId = row.id; + console.log('Row ID:', rowId); + return rowId; + }} + /> +
+
+ ); +}; + +export default EstimateList; diff --git a/frontend/src/pages/admin/Admin.jsx b/frontend/src/pages/admin/Admin.jsx index 547dbc8..638a5af 100644 --- a/frontend/src/pages/admin/Admin.jsx +++ b/frontend/src/pages/admin/Admin.jsx @@ -1,17 +1,17 @@ -import React from "react"; -import "./Admin.scss"; -import AdminEmail from "../../components/admin-email/admin-email"; -import AdminEstimateList from "../../components/admin-estimate/AdminEstimateList"; +import React from 'react'; +import './Admin.scss'; +import AdminEmail from '../../components/admin-email/admin-email'; +import AdminEstimateList from '../../components/admin-estimate/AdminEstimateList'; +import EstimateList from '../../components/estimate-list/EstimateList'; function Admin() { - return (
- +
- ) + ); } -export default Admin; \ No newline at end of file +export default Admin; From cf4e880c3f447a6c14723d91d50be0e11abf9140 Mon Sep 17 00:00:00 2001 From: akinola Olanrewaju Date: Wed, 6 Dec 2023 23:10:36 -0800 Subject: [PATCH 2/3] style admin tables --- frontend/package-lock.json | 1 + frontend/package.json | 1 + .../components/admin-email/admin-email.jsx | 106 +++++----- .../components/admin-email/admin-email.scss | 103 ++++++---- .../components/estimate-list/EstimateList.jsx | 184 ++++++++++++++---- frontend/src/pages/admin/Admin.jsx | 2 +- frontend/src/pages/admin/Admin.scss | 31 +-- 7 files changed, 290 insertions(+), 138 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ce6b161..7d37b38 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,6 +13,7 @@ "@emotion/styled": "^11.11.0", "@mui/material": "^5.14.20", "@mui/styled-engine-sc": "^6.0.0-alpha.7", + "@mui/system": "^5.14.20", "@mui/x-data-grid": "^6.18.3", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", diff --git a/frontend/package.json b/frontend/package.json index b56158c..85fe1d0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,6 +8,7 @@ "@emotion/styled": "^11.11.0", "@mui/material": "^5.14.20", "@mui/styled-engine-sc": "^6.0.0-alpha.7", + "@mui/system": "^5.14.20", "@mui/x-data-grid": "^6.18.3", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", diff --git a/frontend/src/components/admin-email/admin-email.jsx b/frontend/src/components/admin-email/admin-email.jsx index 73b9247..66ce2cc 100644 --- a/frontend/src/components/admin-email/admin-email.jsx +++ b/frontend/src/components/admin-email/admin-email.jsx @@ -1,64 +1,68 @@ -import React, { useEffect, useState } from "react"; -import "./admin-email.scss"; -import axios from "axios"; -import { CSVLink } from "react-csv"; +import React, { useEffect, useState } from 'react'; +import './admin-email.scss'; +import axios from 'axios'; +import { CSVLink } from 'react-csv'; const URL = process.env.REACT_APP_BACKEND_URL; const PORT = process.env.REACT_APP_PORT; function AdminEmail() { - const [subscribers, setSubscribers] = useState([]); + const [subscribers, setSubscribers] = useState([]); - // this is to get all info for subscribers from api - const getAllSubscribers = () => { - axios - .get(`${URL}${PORT}/api/v1/subscribers`) - .then((res) => { - const result = res.data; - setSubscribers(result); - }) - .catch((error) => { - console.error(error); - }); - }; + // this is to get all info for subscribers from api + const getAllSubscribers = () => { + axios + .get(`${URL}${PORT}/api/v1/subscribers`) + .then((res) => { + const result = res.data; + setSubscribers(result); + }) + .catch((error) => { + console.error(error); + }); + }; - useEffect(() => { - getAllSubscribers(); - }, []); + useEffect(() => { + getAllSubscribers(); + }, []); - // everything getting installed from api to CSV (if you add 'id', then id will also be installed) - const headers = [ - { label: "First Name", key: "first_name" }, - { label: "Email Address", key: "email_address" }, - ]; + // everything getting installed from api to CSV (if you add 'id', then id will also be installed) + const headers = [ + { label: 'First Name', key: 'first_name' }, + { label: 'Email Address', key: 'email_address' } + ]; - // table for subscribers - const subscriberList = subscribers.map((subscriber) => { - return ( - - {subscriber.first_name} - {subscriber.email_address} - - ); - }); + // table for subscribers + const subscriberList = subscribers.map((subscriber) => { + return ( + + {subscriber.id} + {subscriber.first_name} + {subscriber.email_address} + + ); + }); - return ( -
-

Subcriber List

- - - - - - - - {subscriberList} -
NameEmail
- - Download CSV - -
- ); + return ( +
+
+

Subcribers List

+ + Download CSV + +
+ + + + + + + + + {subscriberList} +
S/NNameEmail
+
+ ); } export default AdminEmail; diff --git a/frontend/src/components/admin-email/admin-email.scss b/frontend/src/components/admin-email/admin-email.scss index 7a16b30..b18a8ca 100644 --- a/frontend/src/components/admin-email/admin-email.scss +++ b/frontend/src/components/admin-email/admin-email.scss @@ -1,42 +1,67 @@ -@use "../../styles/partials/index" as *; -@use "../../styles/partials/breakpoints" as breakpoints; +@use '../../styles/partials/index' as *; +@use '../../styles/partials/breakpoints' as breakpoints; .admin { - margin-bottom: 40px; - display: flex; - flex-direction: column; - - &_table { - border-collapse: collapse; - width: 100%; - - &-info { - font-size: 1.2rem; - width: 20rem; - - @include breakpoints.large { - font-size: 1.5rem; - } - } - } - - &_link { - @include button; - @include mobile-text-buttons; - color: black; - background-color: rgb(57 208 66); - margin: auto; - - &:hover { - text-decoration: none; - outline: none; - color: $color-primary-light; - border: none; - } - - &:focus { - outline: none; - text-decoration: none; - } - } + margin-bottom: 40px; + display: flex; + flex-direction: column; + + &_table { + border-collapse: collapse; + width: 100%; + + &_top { + display: flex; + justify-content: space-between; + align-items: center; + } + &-info { + font-size: 1.2rem; + width: 20rem; + + @include breakpoints.large { + font-size: 1.5rem; + } + } + } + + &_link { + @include button; + @include mobile-text-buttons; + color: black; + background-color: rgb(57 208 66); + margin-bottom: 10px; + + &:hover { + text-decoration: none; + outline: none; + color: $color-primary-light; + border: none; + } + + &:focus { + outline: none; + text-decoration: none; + } + } +} + +.table { + &_header { + height: 3.5rem; + font-size: 14px; + text-align: center; + color: #ffffff; + } + &_title { + font-size: 30px; + } + &_row { + height: 50px; + text-align: center; + vertical-align: middle; + } +} +.table td { + vertical-align: middle; } diff --git a/frontend/src/components/estimate-list/EstimateList.jsx b/frontend/src/components/estimate-list/EstimateList.jsx index 4b324cd..2931469 100644 --- a/frontend/src/components/estimate-list/EstimateList.jsx +++ b/frontend/src/components/estimate-list/EstimateList.jsx @@ -3,6 +3,62 @@ import { Box, Typography } from '@mui/material'; import { DataGrid } from '@mui/x-data-grid'; import { useMemo } from 'react'; import axios from 'axios'; +import { css } from '@emotion/react'; + +const datagridSx = { + borderRadius: 2, + '& .MuiDataGrid-main': { borderRadius: 2 }, + '& div[data-rowIndex][role="row"]': { + color: '#212529', + fontSize: 14, + //risky + minHeight: '70px !important', + + '& div': { + minHeight: '70px !important', + // height: 50, + lineHeight: '25px !important' + } + }, + '& .MuiDataGrid-virtualScrollerRenderZone': { + '& .MuiDataGrid-row': { + '&:nth-child(2n)': { backgroundColor: 'rgba(235, 235, 235, .7)' } + } + }, + '& .MuiDataGrid-columnHeaders': { + backgroundColor: '#212529', + color: '#ffffff', + fontSize: 14, + height: 'unset !important' + }, + '& .MuiDataGrid-columnHeaderTitle': { + whiteSpace: 'normal', + lineHeight: 'normal' + }, + + '& .MuiDataGrid-cellContent': { + whiteSpace: 'normal', + wordWrap: 'break-word', + textAlign: 'center' + }, + '& .wrap-text-cell': { + whiteSpace: 'normal', + wordWrap: 'break-word', + display: 'flex', + alignItems: 'center' // Vertically center the content + }, + '& .MuiDataGrid-row': { + display: 'flex', + alignItems: 'center' // Vertically center the row content + }, + '& .MuiTablePagination-displayedRows': { + fontSize: 14 + } +}; +const wrapTextCellStyle = css` + white-space: normal; + word-wrap: break-word; +`; const URL = process.env.REACT_APP_BACKEND_URL; const PORT = process.env.REACT_APP_PORT; @@ -10,8 +66,6 @@ const PORT = process.env.REACT_APP_PORT; const EstimateList = () => { const [estimateLists, setEstimateLists] = useState([]); - const [rowId, setRowId] = useState(null); - //fetch all the estimates from database const getAllEstimates = () => { axios @@ -40,17 +94,6 @@ const EstimateList = () => { updatedRow[field] = value; setEstimateLists(updatedEstimateLists); - // axios - // .patch(`${URL}${PORT}/api/v1/customers/${row.id}`, { - // ...row, - // request_status: selectedOption.value - // }) - // .then((res) => { - // setEstimateRow(res.data); - // }) - // .catch((error) => { - // console.log('error', error); - // }); axios .patch(`${URL}${PORT}/api/v1/customers/${id}`, { request_status: value @@ -71,23 +114,97 @@ const EstimateList = () => { }; const columns = useMemo( () => [ - { field: 'id', headerName: 'S/N', flex: 1, maxWidth: 100 }, - { field: 'first_name', headerName: 'Name', flex: 1, maxWidth: 100 }, - { field: 'last_name', headerName: 'Last Name', flex: 1, maxWidth: 100 }, - { field: 'phone_number', headerName: 'Phone Number', flex: 1, maxWidth: 100 }, + { + field: 'id', + headerName: 'S/N', + headerClassName: 'super-app-theme--header', + headerAlign: 'center', + align: 'center', + flex: 0.5, + maxWidth: 100 + }, + { + field: 'first_name', + headerName: 'Name', + headerClassName: 'super-app-theme--header', + headerAlign: 'center', + align: 'center', + flex: 1, + maxWidth: 100 + }, + { + field: 'last_name', + headerName: 'Last Name', + headerClassName: 'super-app-theme--header', + headerAlign: 'center', + align: 'center', + flex: 1, + maxWidth: 100 + }, + { + field: 'phone_number', + headerName: 'Phone Number', + headerClassName: 'super-app-theme--header', + headerAlign: 'center', + align: 'center', + flex: 1, + maxWidth: 150, + filterable: false, + disableColumnMenu: true, + sortable: false + }, { field: 'email_address', headerName: 'Email Address', - flex: 1, + headerClassName: 'super-app-theme--header', + headerAlign: 'center', + align: 'center', + flex: 2, + maxWidth: 400, + filterable: false, + disableColumnMenu: true, + sortable: false + }, + { + field: 'home_address', + headerName: 'Home Address', + headerClassName: 'super-app-theme--header', + headerAlign: 'center', + align: 'center', + flex: 2, maxWidth: 400, - filterable: false + disableColumnMenu: true, + sortable: false + }, + { + field: 'service', + headerName: 'Service Rquested', + headerClassName: 'super-app-theme--header', + headerAlign: 'center', + align: 'center', + flex: 2.5, + maxWidth: 400, + disableColumnMenu: true, + sortable: false + }, + { + field: 'additional_info', + headerName: 'Additional Info', + headerClassName: 'super-app-theme--header', + headerAlign: 'center', + align: 'center', + flex: 2.5, + maxWidth: 400, + disableColumnMenu: true, + sortable: false, + cellClassName: wrapTextCellStyle }, - { field: 'home_address', headerName: 'Home Address', flex: 1, maxWidth: 400 }, - { field: 'service', headerName: 'Service Rquested', flex: 1, maxWidth: 400 }, - { field: 'additional_info', headerName: 'Additional Info', flex: 1, maxWidth: 400 }, { field: 'request_status', headerName: 'Status', + headerClassName: 'super-app-theme--header', + headerAlign: 'center', + align: 'center', flex: 1, maxWidth: 150, type: 'singleSelect', @@ -109,32 +226,31 @@ const EstimateList = () => { handleOption(params); }; return ( - - - EstimateList + <> + + Customer Estimate requests -
+
true} - pageSize={5} - rowsPerPageOptions={[10, 15, 20]} loading={!estimateLists.length} getRowId={(row) => { const rowId = row.id; console.log('Row ID:', rowId); return rowId; }} + sx={datagridSx} />
- + ); }; diff --git a/frontend/src/pages/admin/Admin.jsx b/frontend/src/pages/admin/Admin.jsx index cb4e16f..6d8d7d0 100644 --- a/frontend/src/pages/admin/Admin.jsx +++ b/frontend/src/pages/admin/Admin.jsx @@ -10,7 +10,7 @@ function Admin() { const switchAdmin = () => setAdminDisplay(adminDisplay === 'email' ? 'estimate' : 'email'); return ( -
+
Show {adminDisplay === 'email' ? 'Estimate' : 'Email'} List diff --git a/frontend/src/pages/admin/Admin.scss b/frontend/src/pages/admin/Admin.scss index 08e6e23..a2d64b0 100644 --- a/frontend/src/pages/admin/Admin.scss +++ b/frontend/src/pages/admin/Admin.scss @@ -1,18 +1,23 @@ -@use "../../styles/partials/index" as *; -@use "../../styles/partials/breakpoints" as breakpoints; +@use '../../styles/partials/index' as *; +@use '../../styles/partials/breakpoints' as breakpoints; .button { - display: inline-block; - @include button; - @include mobile-text-buttons; + display: inline-block; + @include button; + @include mobile-text-buttons; - margin: 2rem; + margin: 2rem; - &:hover { - text-decoration: none; - } - &:focus { - outline: none; - text-decoration: none; - } + &:hover { + text-decoration: none; + } + &:focus { + outline: none; + text-decoration: none; + } +} + +.Admin { + max-width: 1500px; + margin: 1rem auto; } From b44cd2e7ca6a12173f6a16e42c0b8083b9cb7108 Mon Sep 17 00:00:00 2001 From: akinola Olanrewaju Date: Wed, 6 Dec 2023 23:25:14 -0800 Subject: [PATCH 3/3] adjust faker data for subscribers --- backend/db/seeds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/db/seeds.rb b/backend/db/seeds.rb index 31b7de6..4caabd4 100644 --- a/backend/db/seeds.rb +++ b/backend/db/seeds.rb @@ -1,7 +1,7 @@ require 'faker' -20.times do +10.times do fn=Faker::Name.first_name ln=Faker::Name.last_name Subscriber.create(