From b2629e96f04c819a7baeda7986716fdefad08bc2 Mon Sep 17 00:00:00 2001 From: "Efrain A. Davila" <105945226+EfrainAD@users.noreply.github.com> Date: Mon, 7 Aug 2023 19:59:19 -0400 Subject: [PATCH 01/41] Feature: The 'Completed' column is now presented as a button if the answer is yes. When clicked, it navigates the user to the survey. 1. I utilized the useGetSurveyVisitsQuery to retrieve all survey data. 2. Within the "Completed" column, I replaced the 'Yes' response with a button that facilitates user navigation to the survey. 3. Next, I regenerated the house data by appending completed: true and survey_id: visit.id. Please note that currently, the built-in method for searching survey visits by quiries is on the to-do list, according to https://docs.google.com/document/d/1QAek7K-pvnCJe4wxm38QdPCbszEE-esw3w-tuhEtMDQ/edit. So, I couldn't directly retrieve it. 4. Should any errors arise from survey visits, a CustomSnackbar is triggered to inform the user. However, the table still loads without interruption. --- .../front/src/pages/Admin/home/HomeTable.js | 80 +++++++++++++++---- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index b9735f0d..eee2f062 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -8,7 +8,11 @@ import CustomSnackbar from "../../../components/CustomSnackbar"; import { DataGrid } from "@mui/x-data-grid"; import Loader from "../../../components/Loader"; import React from "react"; -import { useGetHomesQuery } from "../../../api/apiSlice"; +import { + useGetHomesQuery, + useGetSurveyVisitsQuery +} from "../../../api/apiSlice"; +import { useNavigate } from "react-router-dom"; // Formats addresses export const getAddress = (params) => { @@ -24,6 +28,7 @@ export const getAddress = (params) => { const HomeTable = () => { const goToBreadcrumb = useGoToBreadcrumb(); + const navigate = useNavigate(); useInitBreadcrumbs([ { url: "/admin/dashboard", description: "dashboard" }, @@ -31,12 +36,17 @@ const HomeTable = () => { ]); const handleHomeLink = (home) => goToBreadcrumb("home", home); + const handleUserLink = (visit) => navigate('/admin/survey/visit/' + visit) const handleAssignmentLink = (assignment) => goToBreadcrumb("assignment", assignment); const columns = [ - { field: "id", headerName: "Id", minWidth: 80 }, + { + field: "id", + headerName: "Id", + minWidth: 80 + }, { field: "address", valueGetter: getAddress, @@ -61,7 +71,15 @@ const HomeTable = () => { { field: "completed", headerName: "Completed", - renderCell: (params) => (params.row.completed === "true" ? "Yes" : "No"), + renderCell: (params) => (params.row.completed === true ? handleUserLink(params.row.survey_id)} + > + Yes + : "No"), minWidth: 100, maxWidth: 150, flex: 0.8, @@ -99,33 +117,61 @@ const HomeTable = () => { ]; const { - data: homesData, - isError: isHomesError, + data: fetchedHomesData, + isError: isFetchedHomesError, isLoading: isHomesDataLoading, } = useGetHomesQuery(); + const { + data: surveyVisitsData, + isError: isSurveyVisitsError, + isLoading: isSurveyVisitsDataLoading, + } = useGetSurveyVisitsQuery() - if (isHomesDataLoading) { + let homesData = []; + + if (surveyVisitsData && fetchedHomesData) { + homesData = Object.values(fetchedHomesData).map(home => { + const visit = surveyVisitsData.find(visit => visit.home_id === home.id); + if (visit) { + return { ...home, completed: true, survey_id: visit.id }; + } + return home; + }); + } + + const isDataReady = !isHomesDataLoading && !isSurveyVisitsDataLoading && fetchedHomesData + + if (!isDataReady) { return ; } return ( - {isHomesError ? ( + {isFetchedHomesError ? ( ) : ( - - )} + <> + {isSurveyVisitsError && ( + )} + + > + ) +} ); }; From 626f895f7378c4268d497fe7448f82d7d37ad35b Mon Sep 17 00:00:00 2001 From: "Efrain A. Davila" <105945226+EfrainAD@users.noreply.github.com> Date: Sat, 12 Aug 2023 21:58:12 -0400 Subject: [PATCH 02/41] formatted the file with prettier --- .../front/src/pages/Admin/home/HomeTable.js | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index eee2f062..f0fbbd04 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -8,9 +8,9 @@ import CustomSnackbar from "../../../components/CustomSnackbar"; import { DataGrid } from "@mui/x-data-grid"; import Loader from "../../../components/Loader"; import React from "react"; -import { - useGetHomesQuery, - useGetSurveyVisitsQuery +import { + useGetHomesQuery, + useGetSurveyVisitsQuery, } from "../../../api/apiSlice"; import { useNavigate } from "react-router-dom"; @@ -36,16 +36,16 @@ const HomeTable = () => { ]); const handleHomeLink = (home) => goToBreadcrumb("home", home); - const handleUserLink = (visit) => navigate('/admin/survey/visit/' + visit) + const handleUserLink = (visit) => navigate("/admin/survey/visit/" + visit); const handleAssignmentLink = (assignment) => goToBreadcrumb("assignment", assignment); const columns = [ { - field: "id", - headerName: "Id", - minWidth: 80 + field: "id", + headerName: "Id", + minWidth: 80, }, { field: "address", @@ -71,15 +71,20 @@ const HomeTable = () => { { field: "completed", headerName: "Completed", - renderCell: (params) => (params.row.completed === true ? handleUserLink(params.row.survey_id)} - > - Yes - : "No"), + renderCell: (params) => + params.row.completed === true ? ( + handleUserLink(params.row.survey_id)} + > + Yes + + ) : ( + "No" + ), minWidth: 100, maxWidth: 150, flex: 0.8, @@ -125,22 +130,23 @@ const HomeTable = () => { data: surveyVisitsData, isError: isSurveyVisitsError, isLoading: isSurveyVisitsDataLoading, - } = useGetSurveyVisitsQuery() + } = useGetSurveyVisitsQuery(); let homesData = []; if (surveyVisitsData && fetchedHomesData) { - homesData = Object.values(fetchedHomesData).map(home => { - const visit = surveyVisitsData.find(visit => visit.home_id === home.id); + homesData = Object.values(fetchedHomesData).map((home) => { + const visit = surveyVisitsData.find((visit) => visit.home_id === home.id); if (visit) { return { ...home, completed: true, survey_id: visit.id }; } return home; }); } - - const isDataReady = !isHomesDataLoading && !isSurveyVisitsDataLoading && fetchedHomesData - + + const isDataReady = + !isHomesDataLoading && !isSurveyVisitsDataLoading && fetchedHomesData; + if (!isDataReady) { return ; } @@ -160,18 +166,18 @@ const HomeTable = () => { open={isSurveyVisitsError} message="Error fetching Survey Visits data." severity="error" - />)} - + )} + > - ) -} + )} ); }; From 3fa6f7c88e573d822182abfe1dca158be5512e76 Mon Sep 17 00:00:00 2001 From: "Efrain A. Davila" <105945226+EfrainAD@users.noreply.github.com> Date: Sat, 12 Aug 2023 22:02:08 -0400 Subject: [PATCH 03/41] did what eslint told me so it could pass --- frontend/front/package.json | 1 + frontend/front/yarn.lock | 48 ++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/frontend/front/package.json b/frontend/front/package.json index ef9f67ac..f42afb39 100644 --- a/frontend/front/package.json +++ b/frontend/front/package.json @@ -59,6 +59,7 @@ ] }, "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "eslint": "^8.44.0", "npm-run-all": "^4.1.5", "prettier": "^2.8.8" diff --git a/frontend/front/yarn.lock b/frontend/front/yarn.lock index 00852e0b..e9e79865 100644 --- a/frontend/front/yarn.lock +++ b/frontend/front/yarn.lock @@ -86,7 +86,7 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" -"@babel/helper-annotate-as-pure@^7.22.5": +"@babel/helper-annotate-as-pure@^7.18.6", "@babel/helper-annotate-as-pure@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== @@ -126,6 +126,21 @@ "@babel/helper-split-export-declaration" "^7.22.5" semver "^6.3.0" +"@babel/helper-create-class-features-plugin@^7.21.0": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.10.tgz#dd2612d59eac45588021ac3d6fa976d08f4e95a3" + integrity sha512-5IBb77txKYQPpOEdUdIhBx8VrZyDCQ+H82H0+5dX1TmuscP5vJKEE3cKurjtIw/vFwzbVH48VweE78kVDBrqjA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" + "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.5.tgz#bb2bf0debfe39b831986a4efbf4066586819c6e4" @@ -229,6 +244,15 @@ "@babel/traverse" "^7.22.5" "@babel/types" "^7.22.5" +"@babel/helper-replace-supers@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz#cbdc27d6d8d18cd22c81ae4293765a5d9afd0779" + integrity sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-simple-access@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" @@ -250,6 +274,13 @@ dependencies: "@babel/types" "^7.22.5" +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-string-parser@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" @@ -371,6 +402,16 @@ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== +"@babel/plugin-proposal-private-property-in-object@^7.21.11": + version "7.21.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz#69d597086b6760c4126525cfa154f34631ff272c" + integrity sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.21.0" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" @@ -8626,6 +8667,11 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: version "7.5.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" From 4c64c45d94893629398f1744690597dbdd7ab360 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Tue, 8 Aug 2023 20:50:00 -0400 Subject: [PATCH 04/41] Remove completed attribute from survey_response and calculate instead (#405) * Remove completed attribute from survey_responses Co-authored-by: Anna Westland-Tegart Co-authored-by: Linden Huhmann * Add visited? attribute to home Add a visited attribute to the homes model, which indicates whether it has any survey_visits. Eager load the survey_visits for a home inside the homes and assignments controllers to avoid N+1 queries issue. * Fix bug and rubocop issue * Add completed attribute to homes model * Update order of home attributes on assignment view Make the attribute order consistent when seeing home details from homes controller and from assignments controller. * Fix bug when filtering assignments by surveyor * Return viewed/completed attributes without question marks --------- Co-authored-by: Anna Westland-Tegart Co-authored-by: Linden Huhmann --- backend/app/controllers/assignments_controller.rb | 8 +++++--- backend/app/controllers/homes_controller.rb | 4 ++-- backend/app/models/assignment.rb | 2 ++ backend/app/models/home.rb | 10 ++++++++++ .../app/views/assignments/_assignment.json.jbuilder | 4 ++-- ...0621000051_remove_completed_from_survey_response.rb | 7 +++++++ backend/db/schema.rb | 1 - 7 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 backend/db/migrate/20230621000051_remove_completed_from_survey_response.rb diff --git a/backend/app/controllers/assignments_controller.rb b/backend/app/controllers/assignments_controller.rb index c29731de..7a382974 100644 --- a/backend/app/controllers/assignments_controller.rb +++ b/backend/app/controllers/assignments_controller.rb @@ -5,10 +5,12 @@ class AssignmentsController < ApplicationController # GET /assignments or /assignments.json def index + coll = Assignment.includes(homes: { survey_visits: :survey_response }) + @assignments = if search_params[:surveyor_id] - Assignment.joins(:surveyors).where({ surveyors: { id: search_params[:surveyor_id] } }) + coll.filter_by_surveyor [search_params[:surveyor_id]] else - Assignment.all + coll.all end end @@ -60,7 +62,7 @@ def destroy # Use callbacks to share common setup or constraints between actions. def set_assignment - @assignment = Assignment.find(params[:id]) + @assignment = Assignment.includes(homes: { survey_visits: :survey_response }).find(params[:id]) end # Only allow a list of trusted parameters through. diff --git a/backend/app/controllers/homes_controller.rb b/backend/app/controllers/homes_controller.rb index ae05b875..9163836a 100644 --- a/backend/app/controllers/homes_controller.rb +++ b/backend/app/controllers/homes_controller.rb @@ -5,7 +5,7 @@ class HomesController < ApplicationController # GET /homes or /homes.json def index - @homes = Home.where(search_params) + @homes = Home.includes(survey_visits: :survey_response).where(search_params) end # GET /homes/1 or /homes/1.json @@ -56,7 +56,7 @@ def destroy # Use callbacks to share common setup or constraints between actions. def set_home - @home = Home.find(params[:id]) + @home = Home.includes(survey_visits: :survey_response).find(params[:id]) end # Only allow a list of trusted parameters through. diff --git a/backend/app/models/assignment.rb b/backend/app/models/assignment.rb index 77c175d3..57454d80 100644 --- a/backend/app/models/assignment.rb +++ b/backend/app/models/assignment.rb @@ -4,4 +4,6 @@ class Assignment < ApplicationRecord has_and_belongs_to_many :surveyors has_many :homes, dependent: nil validates :region_code, numericality: true + + scope :filter_by_surveyor, ->(surveyor_ids) { joins(:surveyors).where(surveyors: { id: surveyor_ids }) } end diff --git a/backend/app/models/home.rb b/backend/app/models/home.rb index 3aa965e9..7912afbc 100644 --- a/backend/app/models/home.rb +++ b/backend/app/models/home.rb @@ -11,4 +11,14 @@ class Home < ApplicationRecord # Ensure visit_order has a value iff assignment_id does validates :visit_order, presence: true, if: :assignment_id validates :assignment_id, presence: true, if: :visit_order + + def visited? + !survey_visits.empty? + end + + def completed? + # We consider a home completed if any of its survey_visits + # have an associated survey_response + survey_visits.any? { |sv| !sv.survey_response.nil? } + end end diff --git a/backend/app/views/assignments/_assignment.json.jbuilder b/backend/app/views/assignments/_assignment.json.jbuilder index e9bcbe49..0064b165 100644 --- a/backend/app/views/assignments/_assignment.json.jbuilder +++ b/backend/app/views/assignments/_assignment.json.jbuilder @@ -9,6 +9,6 @@ end json.homes do json.array!(assignment.homes.sort_by do |h| h[:visit_order] - end, :id, :visit_order, :street_number, :street_name, :unit_number, :city, :state, :zip_code, - :building_type) + end, :id, :street_number, :street_name, :unit_number, :city, :state, :zip_code, + :building_type, :visit_order, :visited?, :completed?) end diff --git a/backend/db/migrate/20230621000051_remove_completed_from_survey_response.rb b/backend/db/migrate/20230621000051_remove_completed_from_survey_response.rb new file mode 100644 index 00000000..d0ab8c12 --- /dev/null +++ b/backend/db/migrate/20230621000051_remove_completed_from_survey_response.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class RemoveCompletedFromSurveyResponse < ActiveRecord::Migration[7.0] + def change + remove_column :survey_responses, :completed, :boolean + end +end diff --git a/backend/db/schema.rb b/backend/db/schema.rb index 8ed535db..2432eb99 100644 --- a/backend/db/schema.rb +++ b/backend/db/schema.rb @@ -96,7 +96,6 @@ t.datetime "updated_at", null: false t.string "ip" t.float "recaptcha_score" - t.boolean "completed" t.index ["survey_id"], name: "index_survey_responses_on_survey_id" t.index ["survey_visit_id"], name: "index_survey_responses_on_survey_visit_id" end From 16402ed30097025265dc8be8e965f9de2a1c1e64 Mon Sep 17 00:00:00 2001 From: Matt DelSordo Date: Tue, 8 Aug 2023 20:50:46 -0400 Subject: [PATCH 05/41] commit format on save setting --- .gitignore | 1 - .vscode/settings.json | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index ed651eff..b629fa6d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ # ignore IDE settings .idea -.vscode frontend/front/.env node_modules yarn.lock \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..9bf4d12b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true +} From 6b19fb4648b677ff2b76fa47031d394c2855d26c Mon Sep 17 00:00:00 2001 From: Matt DelSordo Date: Sun, 6 Aug 2023 14:31:25 -0400 Subject: [PATCH 06/41] routing fixes --- .github/workflows/test.yml | 4 +- backend/Dockerfile | 6 ++- .../assignments/_assignment.json.jbuilder | 2 +- backend/docker-compose.yml | 5 ++- frontend/front/src/components/AddressUtils.js | 45 ++++++++++++++----- .../Surveyor/dashboard/AssignmentUnit.js | 6 ++- .../front/src/pages/Surveyor/map/mapUtils.js | 2 +- 7 files changed, 50 insertions(+), 20 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6f22c799..9369f65c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -78,7 +78,7 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: backend + working-directory: . needs: [test-backend] steps: - name: Check out code @@ -106,4 +106,4 @@ jobs: ECR_REPOSITORY: urban-league-heat-pump-accelerator IMAGE_TAG: ${{ github.sha }} run: | - docker buildx build --platform linux/arm64 -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . --push + docker buildx build --platform linux/arm64 -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -f ./backend/Dockerfile . --push diff --git a/backend/Dockerfile b/backend/Dockerfile index 088f73ee..4dadf9e9 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -2,12 +2,14 @@ FROM ruby:3.1.3-alpine RUN apk update && apk upgrade && apk add build-base libpq-dev postgresql-client gcompat tzdata WORKDIR /usr/src/app -COPY Gemfile Gemfile.lock ./ +# path context is the repo root +COPY backend/Gemfile backend/Gemfile.lock ./ # add x86_64 for support on ARM platform - nokogiri expects x86 for distribution RUN bundle lock --add-platform x86_64-linux RUN bundle install -COPY . . +COPY ./backend . +COPY ./data-analysis/* /usr/src/data-analysis/ EXPOSE 3000 RUN chmod +x start.sh diff --git a/backend/app/views/assignments/_assignment.json.jbuilder b/backend/app/views/assignments/_assignment.json.jbuilder index 0064b165..8ecc2a6b 100644 --- a/backend/app/views/assignments/_assignment.json.jbuilder +++ b/backend/app/views/assignments/_assignment.json.jbuilder @@ -10,5 +10,5 @@ json.homes do json.array!(assignment.homes.sort_by do |h| h[:visit_order] end, :id, :street_number, :street_name, :unit_number, :city, :state, :zip_code, - :building_type, :visit_order, :visited?, :completed?) + :building_type, :visit_order, :visited?, :completed?, :latitude, :longitude) end diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index 54482375..5201d33a 100644 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -3,7 +3,10 @@ services: environment: DATABASE_URL: 'postgres://postgres:password123@db' JWT_SECRET_KEY: '${JWT_SECRET_KEY}' - build: . + build: + dockerfile: ./backend/Dockerfile + # set context to repo root so that the data can be passed in + context: ../ ports: - '3000:3000' links: diff --git a/frontend/front/src/components/AddressUtils.js b/frontend/front/src/components/AddressUtils.js index 9387e7d1..c4430a03 100644 --- a/frontend/front/src/components/AddressUtils.js +++ b/frontend/front/src/components/AddressUtils.js @@ -1,20 +1,41 @@ -import React from "react"; +import React, { useMemo } from "react"; import { Card, CardContent } from "@mui/material"; /** * Component for displaying a home address */ -export const AddressComponent = ({ home }) => ( - - - - {"Address:"} - {`${home?.street_number} ${home?.street_name} #${home?.unit_number}`} - {`${home?.city}, ${home?.state} ${home?.zip_code}`} - - - -); +export const AddressComponent = ({ home }) => { + const line1 = useMemo(() => { + if (home) { + let line = `${home.street_number} ${home.street_name}`; + if (home.unit_number) { + line += ` #${home.unit_number}`; + } + return line; + } + + return ""; + }, [home]); + + const line2 = useMemo(() => { + if (home) { + return `${home.city}, ${home.state} ${home.zip_code}`; + } + return ""; + }, [home]); + + return ( + + + + {"Address:"} + {line1} + {line2} + + + + ); +}; export const houseToString = (home) => { if (!home) { diff --git a/frontend/front/src/pages/Surveyor/dashboard/AssignmentUnit.js b/frontend/front/src/pages/Surveyor/dashboard/AssignmentUnit.js index 6ed3cd4c..6f8c9e93 100644 --- a/frontend/front/src/pages/Surveyor/dashboard/AssignmentUnit.js +++ b/frontend/front/src/pages/Surveyor/dashboard/AssignmentUnit.js @@ -59,7 +59,11 @@ const AssignmentUnit = ({ data }) => { generateGoogleMap(checked)} + onClick={() => + generateGoogleMap( + checked.map((id) => data.find((d) => d.id === id)) + ) + } disabled={checked.length === 0} > GENERATE MAP diff --git a/frontend/front/src/pages/Surveyor/map/mapUtils.js b/frontend/front/src/pages/Surveyor/map/mapUtils.js index 10896c06..dd529d73 100644 --- a/frontend/front/src/pages/Surveyor/map/mapUtils.js +++ b/frontend/front/src/pages/Surveyor/map/mapUtils.js @@ -7,5 +7,5 @@ export const generateMapsLink = (locations) => { .map((location) => `${location.latitude},${location.longitude}`) .join("|"); - return `https://www.google.com/maps/dir/?api=1&origin=${origin.lat},${origin.lng}&destination=${destination.lat},${destination.lng}&waypoints=${waypoints}&travelmode=walking`; + return `https://www.google.com/maps/dir/?api=1&destination=${destination.latitude},${destination.longitude}&waypoints=${waypoints}&travelmode=walking`; }; From 18b190551860e37c33df34d625f7f9faf3dca281 Mon Sep 17 00:00:00 2001 From: Matt DelSordo Date: Tue, 25 Jul 2023 22:20:08 -0400 Subject: [PATCH 07/41] This trying fix my branch 438: query survey_visits to mark things completed This isn't 100% what we want, since it can't check the survey_responses on the survey_visits. Should be removed pending #405. --- frontend/front/src/api/apiSlice.js | 2 +- .../front/src/hooks/useHomesWithCompleted.js | 38 +++++++++++++++++++ .../src/pages/Admin/assignment/AssignTable.js | 13 +++++-- .../front/src/pages/Admin/home/HomeTable.js | 16 +------- .../Surveyor/dashboard/AssignmentHome.js | 4 +- .../src/pages/Surveyor/dashboard/ListView.js | 13 +++++-- frontend/front/src/util/surveyUtils.js | 1 - 7 files changed, 61 insertions(+), 26 deletions(-) create mode 100644 frontend/front/src/hooks/useHomesWithCompleted.js diff --git a/frontend/front/src/api/apiSlice.js b/frontend/front/src/api/apiSlice.js index e9ea4350..d5fbaa7d 100644 --- a/frontend/front/src/api/apiSlice.js +++ b/frontend/front/src/api/apiSlice.js @@ -310,7 +310,7 @@ export const apiSlice = createApi({ .map((a) => ({ ...a, // derive assignment completeness from home completeness - completed: a.homes.some((h) => h.completed === true), + completed: a.homes.every((h) => h.completed === true), })) .sort(sortById) : [], diff --git a/frontend/front/src/hooks/useHomesWithCompleted.js b/frontend/front/src/hooks/useHomesWithCompleted.js new file mode 100644 index 00000000..804c6fd3 --- /dev/null +++ b/frontend/front/src/hooks/useHomesWithCompleted.js @@ -0,0 +1,38 @@ +import { useMemo } from "react"; +import { useGetSurveyVisitsQuery } from "../api/apiSlice"; + +/** + * Workaround until https://github.com/codeforboston/urban-league-heat-pump-accelerator/pull/405 is merged + */ + +export const setHomesCompleted = (homes, surveyVisits) => + (homes || []).map((home) => ({ + ...home, + completed: !!surveyVisits?.find((sv) => sv.home_id === home.id), + })); + +export const useHomesWithCompleted = (homes) => { + const { data: surveyVisits } = useGetSurveyVisitsQuery(); + + return useMemo( + () => setHomesCompleted(homes, surveyVisits), + [homes, surveyVisits] + ); +}; + +export const useAssignmentsWithCompleted = (assignments) => { + const { data: surveyVisits } = useGetSurveyVisitsQuery(); + + return useMemo( + () => + (assignments || []).map((a) => { + const newHomes = setHomesCompleted(a.homes, surveyVisits); + return { + ...a, + homes: newHomes, + completed: a.homes.every((h) => h.completed === true), + }; + }), + [assignments, surveyVisits] + ); +}; diff --git a/frontend/front/src/pages/Admin/assignment/AssignTable.js b/frontend/front/src/pages/Admin/assignment/AssignTable.js index a86affc5..65e7ad05 100644 --- a/frontend/front/src/pages/Admin/assignment/AssignTable.js +++ b/frontend/front/src/pages/Admin/assignment/AssignTable.js @@ -17,6 +17,7 @@ import FormControl from "@mui/material/FormControl"; import InputLabel from "@mui/material/InputLabel"; import Loader from "../../../components/Loader"; import Select from "@mui/material/Select"; +import { useAssignmentsWithCompleted } from "../../../hooks/useHomesWithCompleted"; const AssignTable = () => { const goToBreadcrumb = useGoToBreadcrumb(); @@ -50,17 +51,19 @@ const AssignTable = () => { isLoading: isSurveyorsDataLoading, } = useGetSurveyorsQuery(); + const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); + const tableData = useMemo( () => - assignmentsData && surveyorsData - ? assignmentsData.map((a) => ({ + assignmentsWithCompleted && surveyorsData + ? assignmentsWithCompleted.map((a) => ({ ...a, surveyorData: a.surveyor_ids.map((id) => surveyorsData.find((s) => s.id === id) ), })) : [], - [assignmentsData, surveyorsData] + [assignmentsWithCompleted, surveyorsData] ); const [ @@ -136,7 +139,9 @@ const AssignTable = () => { completed++; } }); - return `${completed}/${params.row.homes.length}`; + return `${completed}/${params.row.homes.length} ${ + completed === params.row.homes.length && completed > 0 ? "✅" : "" + }`; }, }, { diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index f0fbbd04..e0e2b631 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -122,7 +122,7 @@ const HomeTable = () => { ]; const { - data: fetchedHomesData, + data: homesData, isError: isFetchedHomesError, isLoading: isHomesDataLoading, } = useGetHomesQuery(); @@ -132,20 +132,8 @@ const HomeTable = () => { isLoading: isSurveyVisitsDataLoading, } = useGetSurveyVisitsQuery(); - let homesData = []; - - if (surveyVisitsData && fetchedHomesData) { - homesData = Object.values(fetchedHomesData).map((home) => { - const visit = surveyVisitsData.find((visit) => visit.home_id === home.id); - if (visit) { - return { ...home, completed: true, survey_id: visit.id }; - } - return home; - }); - } - const isDataReady = - !isHomesDataLoading && !isSurveyVisitsDataLoading && fetchedHomesData; + !isHomesDataLoading && !isSurveyVisitsDataLoading && homesData; if (!isDataReady) { return ; diff --git a/frontend/front/src/pages/Surveyor/dashboard/AssignmentHome.js b/frontend/front/src/pages/Surveyor/dashboard/AssignmentHome.js index 8132f1a3..7e740295 100644 --- a/frontend/front/src/pages/Surveyor/dashboard/AssignmentHome.js +++ b/frontend/front/src/pages/Surveyor/dashboard/AssignmentHome.js @@ -59,8 +59,8 @@ export const AssignmentHome = ({ : `0${home?.zip_code}` }`} - {home.completed === "true" ? ( - Completed + {home.completed === true ? ( + {"Completed ✅"} ) : ( Incomplete )} diff --git a/frontend/front/src/pages/Surveyor/dashboard/ListView.js b/frontend/front/src/pages/Surveyor/dashboard/ListView.js index 908ab8f1..e92bd1ec 100644 --- a/frontend/front/src/pages/Surveyor/dashboard/ListView.js +++ b/frontend/front/src/pages/Surveyor/dashboard/ListView.js @@ -10,6 +10,7 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import Loader from "../../../components/Loader"; import { useAssignmentsForCurrentUser } from "../../../hooks/useDataForSurveyor"; import { useSearchParams } from "react-router-dom"; +import { useAssignmentsWithCompleted } from "../../../hooks/useHomesWithCompleted"; const ListView = () => { const { @@ -18,14 +19,18 @@ const ListView = () => { error: isAssignmentsError, } = useAssignmentsForCurrentUser(); + const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); + const [openAccordion, setOpenAccordion] = useState(); const [searchParams] = useSearchParams(); // open the accordion of the first incomplete assignment when the page opens useEffect(() => { - setOpenAccordion((assignmentsData || []).find((a) => !a.completed)?.id); - }, [assignmentsData]); + setOpenAccordion( + (assignmentsWithCompleted || []).find((a) => !a.completed)?.id + ); + }, [assignmentsWithCompleted]); return ( @@ -49,12 +54,12 @@ const ListView = () => { Your Assignments - {(!assignmentsData || assignmentsData.length === 0) && ( + {(!assignmentsWithCompleted || assignmentsData.length === 0) && ( No assignments found. )} - {assignmentsData?.map((item, i) => { + {assignmentsWithCompleted?.map((item, i) => { return ( { surveyor_id: surveyorId, survey_response_attributes: { survey_id: surveyId, - completed: "true", survey_answers_attributes: answersObject, }, }, From e066c412aae7b0c953b7908859e3573ea61f5ee3 Mon Sep 17 00:00:00 2001 From: Matt DelSordo Date: Thu, 10 Aug 2023 17:29:43 -0400 Subject: [PATCH 08/41] 438: actually integrate with completed field --- .../assignments/_assignment.json.jbuilder | 14 ++++--- backend/app/views/homes/_home.json.jbuilder | 2 + frontend/front/src/api/apiSlice.js | 8 +++- .../front/src/hooks/useHomesWithCompleted.js | 38 ------------------- .../src/pages/Admin/assignment/AssignTable.js | 9 ++--- .../src/pages/Surveyor/dashboard/ListView.js | 13 ++----- 6 files changed, 24 insertions(+), 60 deletions(-) delete mode 100644 frontend/front/src/hooks/useHomesWithCompleted.js diff --git a/backend/app/views/assignments/_assignment.json.jbuilder b/backend/app/views/assignments/_assignment.json.jbuilder index 8ecc2a6b..5062dd2e 100644 --- a/backend/app/views/assignments/_assignment.json.jbuilder +++ b/backend/app/views/assignments/_assignment.json.jbuilder @@ -6,9 +6,13 @@ json.surveyor_ids do json.array!(assignment.surveyors.map { |s| s[:id] }) end -json.homes do - json.array!(assignment.homes.sort_by do |h| - h[:visit_order] - end, :id, :street_number, :street_name, :unit_number, :city, :state, :zip_code, - :building_type, :visit_order, :visited?, :completed?, :latitude, :longitude) +@sorted_homes = assignment.homes.sort_by do |h| + h[:visit_order] +end + +json.homes @sorted_homes do |home| + json.extract! home, :id, :street_number, :street_name, :unit_number, :city, :state, :zip_code, + :building_type, :visit_order, :latitude, :longitude + json.visited home.visited? + json.completed home.completed? end diff --git a/backend/app/views/homes/_home.json.jbuilder b/backend/app/views/homes/_home.json.jbuilder index 8221c038..0ef6d611 100644 --- a/backend/app/views/homes/_home.json.jbuilder +++ b/backend/app/views/homes/_home.json.jbuilder @@ -2,4 +2,6 @@ json.extract! home, :id, :street_number, :street_name, :unit_number, :city, :state, :zip_code, :building_type, :assignment_id, :visit_order, :latitude, :longitude +json.visited home.visited? +json.completed home.completed? json.url home_url(home, format: :json) diff --git a/frontend/front/src/api/apiSlice.js b/frontend/front/src/api/apiSlice.js index d5fbaa7d..7227e577 100644 --- a/frontend/front/src/api/apiSlice.js +++ b/frontend/front/src/api/apiSlice.js @@ -187,8 +187,12 @@ export const apiSlice = createApi({ body: surveyVisit, headers: [[`Recaptcha-Token`, recaptcha]], }), - // invalidate Assignment so that the dashboard updates appropriately - invalidatesTags: ["SurveyVisit", "Assignment"], + // invalidate Assignment and Home so that the dashboard updates appropriately + invalidatesTags: (result, error, arg) => [ + "SurveyVisit", + "Assignment", + { type: "Home", id: arg.surveyVisit.home_id }, + ], }), updateSurveyVisit: builder.mutation({ query: ({ id, body }) => { diff --git a/frontend/front/src/hooks/useHomesWithCompleted.js b/frontend/front/src/hooks/useHomesWithCompleted.js deleted file mode 100644 index 804c6fd3..00000000 --- a/frontend/front/src/hooks/useHomesWithCompleted.js +++ /dev/null @@ -1,38 +0,0 @@ -import { useMemo } from "react"; -import { useGetSurveyVisitsQuery } from "../api/apiSlice"; - -/** - * Workaround until https://github.com/codeforboston/urban-league-heat-pump-accelerator/pull/405 is merged - */ - -export const setHomesCompleted = (homes, surveyVisits) => - (homes || []).map((home) => ({ - ...home, - completed: !!surveyVisits?.find((sv) => sv.home_id === home.id), - })); - -export const useHomesWithCompleted = (homes) => { - const { data: surveyVisits } = useGetSurveyVisitsQuery(); - - return useMemo( - () => setHomesCompleted(homes, surveyVisits), - [homes, surveyVisits] - ); -}; - -export const useAssignmentsWithCompleted = (assignments) => { - const { data: surveyVisits } = useGetSurveyVisitsQuery(); - - return useMemo( - () => - (assignments || []).map((a) => { - const newHomes = setHomesCompleted(a.homes, surveyVisits); - return { - ...a, - homes: newHomes, - completed: a.homes.every((h) => h.completed === true), - }; - }), - [assignments, surveyVisits] - ); -}; diff --git a/frontend/front/src/pages/Admin/assignment/AssignTable.js b/frontend/front/src/pages/Admin/assignment/AssignTable.js index 65e7ad05..266a7aa3 100644 --- a/frontend/front/src/pages/Admin/assignment/AssignTable.js +++ b/frontend/front/src/pages/Admin/assignment/AssignTable.js @@ -17,7 +17,6 @@ import FormControl from "@mui/material/FormControl"; import InputLabel from "@mui/material/InputLabel"; import Loader from "../../../components/Loader"; import Select from "@mui/material/Select"; -import { useAssignmentsWithCompleted } from "../../../hooks/useHomesWithCompleted"; const AssignTable = () => { const goToBreadcrumb = useGoToBreadcrumb(); @@ -51,19 +50,17 @@ const AssignTable = () => { isLoading: isSurveyorsDataLoading, } = useGetSurveyorsQuery(); - const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); - const tableData = useMemo( () => - assignmentsWithCompleted && surveyorsData - ? assignmentsWithCompleted.map((a) => ({ + assignmentsData && surveyorsData + ? assignmentsData.map((a) => ({ ...a, surveyorData: a.surveyor_ids.map((id) => surveyorsData.find((s) => s.id === id) ), })) : [], - [assignmentsWithCompleted, surveyorsData] + [assignmentsData, surveyorsData] ); const [ diff --git a/frontend/front/src/pages/Surveyor/dashboard/ListView.js b/frontend/front/src/pages/Surveyor/dashboard/ListView.js index e92bd1ec..908ab8f1 100644 --- a/frontend/front/src/pages/Surveyor/dashboard/ListView.js +++ b/frontend/front/src/pages/Surveyor/dashboard/ListView.js @@ -10,7 +10,6 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import Loader from "../../../components/Loader"; import { useAssignmentsForCurrentUser } from "../../../hooks/useDataForSurveyor"; import { useSearchParams } from "react-router-dom"; -import { useAssignmentsWithCompleted } from "../../../hooks/useHomesWithCompleted"; const ListView = () => { const { @@ -19,18 +18,14 @@ const ListView = () => { error: isAssignmentsError, } = useAssignmentsForCurrentUser(); - const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); - const [openAccordion, setOpenAccordion] = useState(); const [searchParams] = useSearchParams(); // open the accordion of the first incomplete assignment when the page opens useEffect(() => { - setOpenAccordion( - (assignmentsWithCompleted || []).find((a) => !a.completed)?.id - ); - }, [assignmentsWithCompleted]); + setOpenAccordion((assignmentsData || []).find((a) => !a.completed)?.id); + }, [assignmentsData]); return ( @@ -54,12 +49,12 @@ const ListView = () => { Your Assignments - {(!assignmentsWithCompleted || assignmentsData.length === 0) && ( + {(!assignmentsData || assignmentsData.length === 0) && ( No assignments found. )} - {assignmentsWithCompleted?.map((item, i) => { + {assignmentsData?.map((item, i) => { return ( Date: Sun, 23 Jul 2023 20:28:48 -0400 Subject: [PATCH 09/41] 438: replace admin dashboard with tabs --- frontend/front/src/hooks/breadcrumbHooks.js | 6 +- .../front/src/pages/Admin/AdminContainer.js | 76 ++++++++++++++----- .../pages/Admin/assignment/AssignProfile.js | 10 ++- .../src/pages/Admin/assignment/AssignTable.js | 9 ++- .../src/pages/Admin/dashboard/Dashboard.js | 67 ---------------- .../src/pages/Admin/home/CreateNewHome.js | 4 +- .../front/src/pages/Admin/home/HomeProfile.js | 3 +- .../front/src/pages/Admin/home/HomeTable.js | 9 ++- .../pages/Admin/home/SurveyVisitProfile.js | 3 +- frontend/front/src/pages/Admin/nav/Nav.js | 3 - .../src/pages/Admin/survey/SurveyProfile.js | 10 ++- .../src/pages/Admin/survey/SurveyTable.js | 9 ++- .../src/pages/Admin/user/CreateNewUser.js | 3 +- .../front/src/pages/Admin/user/UserProfile.js | 3 +- .../front/src/pages/Admin/user/UserTable.js | 17 ++--- frontend/front/src/pages/Surveyor/nav/Nav.js | 3 +- frontend/front/src/routing/routes.js | 23 +++++- 17 files changed, 132 insertions(+), 126 deletions(-) delete mode 100644 frontend/front/src/pages/Admin/dashboard/Dashboard.js diff --git a/frontend/front/src/hooks/breadcrumbHooks.js b/frontend/front/src/hooks/breadcrumbHooks.js index 9461d04d..d71e3a3a 100644 --- a/frontend/front/src/hooks/breadcrumbHooks.js +++ b/frontend/front/src/hooks/breadcrumbHooks.js @@ -54,13 +54,13 @@ export const useGoToBreadcrumb = () => { }; }; -export const useInitBreadcrumbs = (breadcrumbs) => { +export const useInitBreadcrumbs = (breadcrumbs, overwrite) => { const dispatch = useDispatch(); const thereAreBreadcrumbs = useSelector(selectBreadcrumbsExist); useEffect(() => { - if (!thereAreBreadcrumbs) { + if (!thereAreBreadcrumbs || overwrite) { dispatch(setBreadcrumbs(breadcrumbs)); } - }, [dispatch, breadcrumbs, thereAreBreadcrumbs]); + }, [dispatch, breadcrumbs, thereAreBreadcrumbs, overwrite]); }; diff --git a/frontend/front/src/pages/Admin/AdminContainer.js b/frontend/front/src/pages/Admin/AdminContainer.js index e199cefb..4b529e51 100644 --- a/frontend/front/src/pages/Admin/AdminContainer.js +++ b/frontend/front/src/pages/Admin/AdminContainer.js @@ -1,46 +1,84 @@ -import { Route, Routes } from "react-router-dom"; - +import { Navigate, Route, Routes, useLocation, Link } from "react-router-dom"; import AssignProfile from "./assignment/AssignProfile"; import Assignment from "./assignment/Assignment"; -import { Box } from "@mui/material"; +import { Box, Tabs, Tab } from "@mui/material"; import { BreadcrumbNav } from "../../features/breadcrumb/BreadcrumbNav"; import CreateNewHome from "./home/CreateNewHome"; import CreateNewUser from "./user/CreateNewUser"; -import Dashboard from "./dashboard/Dashboard"; import Home from "./home/Home"; import HomeProfile from "./home/HomeProfile"; import Nav from "./nav/Nav"; -import React from "react"; +import React, { useMemo } from "react"; import Survey from "./survey/Survey"; import SurveyEditor from "./survey/SurveyProfile"; import SurveyVisit from "./home/SurveyVisitProfile"; import Unassigned from "./assignment/Unassigned"; import User from "./user/User"; import UserProfile from "./user/UserProfile"; +import * as routes from "../../routing/routes"; const AdminContainer = () => { + const location = useLocation(); + + const tabValue = useMemo(() => { + const splitPathname = location.pathname.split("/"); + if (splitPathname.length > 2) { + return splitPathname[2]; + } + return routes.ADMIN_HOME; + }, [location.pathname]); + return ( + + + + + + - }> - }> - }> - }> - }> - }> - }> - }> - }> - }> - }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> } - >{" "} - }> + /> + } + /> + } /> diff --git a/frontend/front/src/pages/Admin/assignment/AssignProfile.js b/frontend/front/src/pages/Admin/assignment/AssignProfile.js index 68a5dee3..7a486c05 100644 --- a/frontend/front/src/pages/Admin/assignment/AssignProfile.js +++ b/frontend/front/src/pages/Admin/assignment/AssignProfile.js @@ -15,16 +15,20 @@ import Loader from "../../../components/Loader"; import React from "react"; import { getAddress } from "../home/HomeTable"; import { useParams } from "react-router-dom"; +import { + adminAssignmentProfile, + ADMIN_ASSIGNMENT, + withAdminPrefix, +} from "../../../routing/routes"; const AssignProfile = () => { const { aid } = useParams(); const goToBreadcrumb = useGoToBreadcrumb(); useInitBreadcrumbs([ - { url: "/admin/dashboard", description: "dashboard" }, - { url: "/admin/assignment", description: "assignments" }, + { url: withAdminPrefix(ADMIN_ASSIGNMENT), description: "assignments" }, { - url: `/admin/assignment/assignProfile/${aid}`, + url: withAdminPrefix(adminAssignmentProfile(aid)), description: `assignment ${aid}`, }, ]); diff --git a/frontend/front/src/pages/Admin/assignment/AssignTable.js b/frontend/front/src/pages/Admin/assignment/AssignTable.js index 266a7aa3..4cd00d9f 100644 --- a/frontend/front/src/pages/Admin/assignment/AssignTable.js +++ b/frontend/front/src/pages/Admin/assignment/AssignTable.js @@ -17,13 +17,14 @@ import FormControl from "@mui/material/FormControl"; import InputLabel from "@mui/material/InputLabel"; import Loader from "../../../components/Loader"; import Select from "@mui/material/Select"; +import { ADMIN_ASSIGNMENT, withAdminPrefix } from "../../../routing/routes"; const AssignTable = () => { const goToBreadcrumb = useGoToBreadcrumb(); - useInitBreadcrumbs([ - { url: "/admin/dashboard", description: "dashboard" }, - { url: "/admin/assignment", description: "assignments" }, - ]); + useInitBreadcrumbs( + [{ url: withAdminPrefix(ADMIN_ASSIGNMENT), description: "assignments" }], + true + ); const [selectedSurveyor, setSelectedSurveyor] = useState(""); const [selectedAssignments, setSelectedAssignments] = useState([]); diff --git a/frontend/front/src/pages/Admin/dashboard/Dashboard.js b/frontend/front/src/pages/Admin/dashboard/Dashboard.js deleted file mode 100644 index 2d29d465..00000000 --- a/frontend/front/src/pages/Admin/dashboard/Dashboard.js +++ /dev/null @@ -1,67 +0,0 @@ -import { Box, Button, Stack } from "@mui/material"; -import React, { useEffect } from "react"; - -import { Link } from "react-router-dom"; -import { setBreadcrumbs } from "../../../features/breadcrumb/breadcrumbSlice"; -import { useDispatch } from "react-redux"; - -const Dashboard = () => { - const dispatch = useDispatch(); - - useEffect(() => { - dispatch(setBreadcrumbs([])); - }, [dispatch]); - - return ( - - - - HOMES - - - USERS - - - - SURVEYS - - - - AssignmentS - - - - ); -}; - -export default Dashboard; diff --git a/frontend/front/src/pages/Admin/home/CreateNewHome.js b/frontend/front/src/pages/Admin/home/CreateNewHome.js index 056cfec2..546c299c 100644 --- a/frontend/front/src/pages/Admin/home/CreateNewHome.js +++ b/frontend/front/src/pages/Admin/home/CreateNewHome.js @@ -4,6 +4,8 @@ import { Controller, useForm } from "react-hook-form"; import React from "react"; import { useNavigate } from "react-router-dom"; +import { withAdminPrefix, ADMIN_HOME } from "../../../routing/routes"; + const CreateNewHome = () => { const navigate = useNavigate(); const { handleSubmit, control } = useForm({ @@ -18,7 +20,7 @@ const CreateNewHome = () => { const onSubmit = (data) => console.log(data); const handleCancel = () => { - navigate("/admin/home"); + navigate(withAdminPrefix(ADMIN_HOME)); }; return ( diff --git a/frontend/front/src/pages/Admin/home/HomeProfile.js b/frontend/front/src/pages/Admin/home/HomeProfile.js index a4ca9d55..5d33f7ff 100644 --- a/frontend/front/src/pages/Admin/home/HomeProfile.js +++ b/frontend/front/src/pages/Admin/home/HomeProfile.js @@ -5,6 +5,7 @@ import { useGetHomeQuery } from "../../../api/apiSlice"; import Loader from "../../../../src/components/Loader.js"; import CustomSnackbar from "../../../components/CustomSnackbar"; import { AdminBackButton } from "../../Surveyor/Components/AdminBackButton"; +import { ADMIN_HOME, withAdminPrefix } from "../../../routing/routes"; const HomeProfile = () => { const { hid } = useParams(); @@ -64,7 +65,7 @@ const HomeProfile = () => { alignItems="center" flexDirection="column" > - + {isHomeDataLoading ? ( ) : isHomeDataError ? ( diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index e0e2b631..6f3a426c 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -13,6 +13,7 @@ import { useGetSurveyVisitsQuery, } from "../../../api/apiSlice"; import { useNavigate } from "react-router-dom"; +import { ADMIN_HOME, withAdminPrefix } from "../../../routing/routes"; // Formats addresses export const getAddress = (params) => { @@ -30,10 +31,10 @@ const HomeTable = () => { const goToBreadcrumb = useGoToBreadcrumb(); const navigate = useNavigate(); - useInitBreadcrumbs([ - { url: "/admin/dashboard", description: "dashboard" }, - { url: "/admin/home", description: "homes" }, - ]); + useInitBreadcrumbs( + [{ url: withAdminPrefix(ADMIN_HOME), description: "homes" }], + true + ); const handleHomeLink = (home) => goToBreadcrumb("home", home); const handleUserLink = (visit) => navigate("/admin/survey/visit/" + visit); diff --git a/frontend/front/src/pages/Admin/home/SurveyVisitProfile.js b/frontend/front/src/pages/Admin/home/SurveyVisitProfile.js index 9e101074..d3d568c5 100644 --- a/frontend/front/src/pages/Admin/home/SurveyVisitProfile.js +++ b/frontend/front/src/pages/Admin/home/SurveyVisitProfile.js @@ -13,6 +13,7 @@ import Loader from "../../../components/Loader"; import { SurveyError } from "../survey/SurveyError"; import { formatISODate } from "../../../components/DateUtils"; import { houseToString } from "../../../components/AddressUtils"; +import { withAdminPrefix, ADMIN_SURVEY } from "../../../routing/routes"; const SurveyProfile = () => { const navigate = useNavigate(); @@ -60,7 +61,7 @@ const SurveyProfile = () => { const onDelete = useCallback(() => { deleteSurveyVisit(surveyVisitId); - navigate("/admin/survey"); + navigate(withAdminPrefix(ADMIN_SURVEY)); }, [deleteSurveyVisit, surveyVisitId, navigate]); return ( diff --git a/frontend/front/src/pages/Admin/nav/Nav.js b/frontend/front/src/pages/Admin/nav/Nav.js index 9817bef7..decde38f 100644 --- a/frontend/front/src/pages/Admin/nav/Nav.js +++ b/frontend/front/src/pages/Admin/nav/Nav.js @@ -12,9 +12,6 @@ const Nav = () => { - - DASHBOARD - SURVEYOR MODE diff --git a/frontend/front/src/pages/Admin/survey/SurveyProfile.js b/frontend/front/src/pages/Admin/survey/SurveyProfile.js index 17a4e574..309c3b26 100644 --- a/frontend/front/src/pages/Admin/survey/SurveyProfile.js +++ b/frontend/front/src/pages/Admin/survey/SurveyProfile.js @@ -7,15 +7,19 @@ import { SurveyEditorForm } from "./SurveyEditorForm"; import { useGetSurveyStructureQuery } from "../../../api/apiSlice"; import { useInitBreadcrumbs } from "../../../hooks/breadcrumbHooks"; import { useParams } from "react-router-dom"; +import { + adminSurveyEdit, + ADMIN_SURVEY, + withAdminPrefix, +} from "../../../routing/routes"; const SurveyProfile = () => { const { uid: surveyVisitId } = useParams(); useInitBreadcrumbs([ - { url: "/admin/dashboard", description: "dashboard" }, - { url: "/admin/survey", description: "surveys" }, + { url: withAdminPrefix(ADMIN_SURVEY), description: "surveys" }, { - url: `/admin/survey/edit/${surveyVisitId}`, + url: withAdminPrefix(adminSurveyEdit(surveyVisitId)), description: `survey ${surveyVisitId}`, }, ]); diff --git a/frontend/front/src/pages/Admin/survey/SurveyTable.js b/frontend/front/src/pages/Admin/survey/SurveyTable.js index 902c6ae0..bd825245 100644 --- a/frontend/front/src/pages/Admin/survey/SurveyTable.js +++ b/frontend/front/src/pages/Admin/survey/SurveyTable.js @@ -8,6 +8,7 @@ import Loader from "../../../components/Loader"; import { SurveyError } from "./SurveyError"; import { formatISODate } from "../../../components/DateUtils"; import { useGetSurveysQuery } from "../../../api/apiSlice"; +import { ADMIN_SURVEY, withAdminPrefix } from "../../../routing/routes"; const COLUMNS = [ { field: "id", headerName: "ID", flex: 1 }, @@ -19,10 +20,10 @@ const COLUMNS = [ const SurveyTable = () => { const goToBreadcrumb = useGoToBreadcrumb(); - useInitBreadcrumbs([ - { url: "/admin/dashboard", description: "dashboard" }, - { url: "/admin/survey", description: "surveys" }, - ]); + useInitBreadcrumbs( + [{ url: withAdminPrefix(ADMIN_SURVEY), description: "surveys" }], + true + ); const { data: surveyData, diff --git a/frontend/front/src/pages/Admin/user/CreateNewUser.js b/frontend/front/src/pages/Admin/user/CreateNewUser.js index 4db2f3b1..08f8e264 100644 --- a/frontend/front/src/pages/Admin/user/CreateNewUser.js +++ b/frontend/front/src/pages/Admin/user/CreateNewUser.js @@ -24,6 +24,7 @@ import { HeatPumpTextField } from "../../../components/SurveyComponent/HeatPumpT import Loader from "../../../components/Loader"; import { useForm } from "react-hook-form"; import { useNavigate } from "react-router-dom"; +import { withAdminPrefix, ADMIN_USER } from "../../../routing/routes"; const ACTION_BACK = "BACK"; const ACTION_NEW = "NEW"; @@ -53,7 +54,7 @@ const CreateNewUser = () => { const [createSurveyor] = useCreateSurveyorMutation(); const handleCancel = useCallback(() => { - navigate("/admin/user"); + navigate(withAdminPrefix(ADMIN_USER)); }, [navigate]); const onSubmit = useCallback( diff --git a/frontend/front/src/pages/Admin/user/UserProfile.js b/frontend/front/src/pages/Admin/user/UserProfile.js index 5f188677..89bb4817 100644 --- a/frontend/front/src/pages/Admin/user/UserProfile.js +++ b/frontend/front/src/pages/Admin/user/UserProfile.js @@ -8,6 +8,7 @@ import CustomSnackbar from "../../../components/CustomSnackbar"; import Loader from "../../../components/Loader"; import { useGetSurveyorQuery } from "../../../api/apiSlice"; import { useParams } from "react-router-dom"; +import { ADMIN_USER, withAdminPrefix } from "../../../routing/routes"; const UserProfile = () => { const { uid } = useParams(); @@ -92,7 +93,7 @@ const UserProfile = () => { alignItems="center" flexDirection="column" > - + {isSurveyorDataLoading ? ( ) : isSurveyorError ? ( diff --git a/frontend/front/src/pages/Admin/user/UserTable.js b/frontend/front/src/pages/Admin/user/UserTable.js index 8083fa68..43373173 100644 --- a/frontend/front/src/pages/Admin/user/UserTable.js +++ b/frontend/front/src/pages/Admin/user/UserTable.js @@ -10,10 +10,12 @@ import TableContainer from "@mui/material/TableContainer"; import TableHead from "@mui/material/TableHead"; import TablePagination from "@mui/material/TablePagination"; import TableRow from "@mui/material/TableRow"; -import { setBreadcrumbs } from "../../../features/breadcrumb/breadcrumbSlice"; -import { useDispatch } from "react-redux"; import { useGetSurveyorsQuery } from "../../../api/apiSlice"; -import { useGoToBreadcrumb } from "../../../hooks/breadcrumbHooks"; +import { + useGoToBreadcrumb, + useInitBreadcrumbs, +} from "../../../hooks/breadcrumbHooks"; +import { ADMIN_USER, withAdminPrefix } from "../../../routing/routes"; const columns = [ { id: "id", label: "UserID", minWidth: 50 }, @@ -26,14 +28,11 @@ const columns = [ ]; const UserTable = () => { - const dispatch = useDispatch(); const goToBreadcrumb = useGoToBreadcrumb(); - dispatch( - setBreadcrumbs([ - { url: "/admin/dashboard", description: "dashboard" }, - { url: "/admin/user", description: "users" }, - ]) + useInitBreadcrumbs( + [{ url: withAdminPrefix(ADMIN_USER), description: "users" }], + true ); const { diff --git a/frontend/front/src/pages/Surveyor/nav/Nav.js b/frontend/front/src/pages/Surveyor/nav/Nav.js index 2aaeb9f7..a375bde3 100644 --- a/frontend/front/src/pages/Surveyor/nav/Nav.js +++ b/frontend/front/src/pages/Surveyor/nav/Nav.js @@ -10,6 +10,7 @@ import React from "react"; import { selectCurrentUserEmail } from "../../../features/login/loginSlice"; import { useLogoutUserMutation } from "../../../api/apiSlice"; import { useSelector } from "react-redux"; +import { ADMIN_ROUTE } from "../../../routing/routes"; const Nav = () => { const [logout] = useLogoutUserMutation(); @@ -32,7 +33,7 @@ const Nav = () => { {userIsAdmin && ( - + ADMIN MODE diff --git a/frontend/front/src/routing/routes.js b/frontend/front/src/routing/routes.js index af634bfe..4993bbc5 100644 --- a/frontend/front/src/routing/routes.js +++ b/frontend/front/src/routing/routes.js @@ -11,4 +11,25 @@ export const SURVEYOR_ACCOUNT_ROUTE = `${SURVEYOR_ROUTE}/account`; export const SURVEYOR_EDIT_ACCOUNT_ROUTE = `${SURVEYOR_ACCOUNT_ROUTE}/edit`; export const SURVEYOR_HOUSE_ROUTE = `${SURVEYOR_ROUTE}/house`; -export const ADMIN_DASHBOARD_ROUTE = `${ADMIN_ROUTE}/dashboard`; +export const ADMIN_DASHBOARD_ROUTE = `${ADMIN_ROUTE}/`; +export const withAdminPrefix = (path) => `${ADMIN_ROUTE}/${path}`; + +export const ADMIN_HOME = "home"; +export const adminHomeProfile = (hid = ":hid") => + `${ADMIN_HOME}/homeprofile/${hid}`; +export const ADMIN_CREATE_HOME = `${ADMIN_HOME}/createHome`; + +export const ADMIN_USER = "user"; +export const adminUserProfile = (uid = ":uid") => + `${ADMIN_USER}/userprofile/${uid}`; +export const ADMIN_CREATE_USER = `${ADMIN_USER}/createUser`; + +export const ADMIN_SURVEY = "survey"; +export const adminSurveyEdit = (uid = ":uid") => `${ADMIN_SURVEY}/edit/${uid}`; +export const adminSurveyVisit = (uid = ":uid") => + `${ADMIN_SURVEY}/visit/${uid}`; + +export const ADMIN_ASSIGNMENT = "assignment"; +export const adminAssignmentProfile = (aid = ":aid") => + `${ADMIN_ASSIGNMENT}/assignProfile/${aid}`; +export const ADMIN_ASSIGNMENT_UNASSIGNED = `${ADMIN_ASSIGNMENT}/unassigned`; From 104e81e555f20e4821eb5f39b0a7a28f2eb791d5 Mon Sep 17 00:00:00 2001 From: thiagobadini Date: Tue, 18 Jul 2023 16:35:40 -0400 Subject: [PATCH 10/41] Creating a new vercel link --- frontend/front/src/pages/Public/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/front/src/pages/Public/Readme.md b/frontend/front/src/pages/Public/Readme.md index 705602fa..aa151a11 100644 --- a/frontend/front/src/pages/Public/Readme.md +++ b/frontend/front/src/pages/Public/Readme.md @@ -25,4 +25,4 @@ - As an authorized user, I want to be able to login. - As an authorized user, I want to be able to change my password. - As an authorized user, I want to be able to login/logout successfully. -- As an authorized user, I am not able to create new users. +- As an authorized user, I am not able to create new users. \ No newline at end of file From eaec95aa579bf99f0684671f6844565020062655 Mon Sep 17 00:00:00 2001 From: thiagobadini Date: Tue, 18 Jul 2023 16:36:03 -0400 Subject: [PATCH 11/41] Creating a new vercel link --- frontend/front/src/pages/Public/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/front/src/pages/Public/Readme.md b/frontend/front/src/pages/Public/Readme.md index aa151a11..5fd7cfa1 100644 --- a/frontend/front/src/pages/Public/Readme.md +++ b/frontend/front/src/pages/Public/Readme.md @@ -25,4 +25,4 @@ - As an authorized user, I want to be able to login. - As an authorized user, I want to be able to change my password. - As an authorized user, I want to be able to login/logout successfully. -- As an authorized user, I am not able to create new users. \ No newline at end of file +- As an authorized user, I am not able to create new users \ No newline at end of file From dfad68c8206bbefe03881547673f27b277b2b899 Mon Sep 17 00:00:00 2001 From: thiagobadini Date: Tue, 1 Aug 2023 18:54:57 -0400 Subject: [PATCH 12/41] 7/18 - Implemented the design suggestions provided by the UX team --- .../pages/Public/Components/CardsSection.js | 80 ++++++++++++++----- .../Pages/AboutHeatPump/AboutHeatPump.js | 33 ++++++-- .../pages/Public/Pages/BenefitsHeatPumps.js | 6 +- .../src/pages/Public/Pages/GetInvolved.js | 4 +- .../pages/Public/Pages/Home/CarrouselHero.js | 4 +- 5 files changed, 93 insertions(+), 34 deletions(-) diff --git a/frontend/front/src/pages/Public/Components/CardsSection.js b/frontend/front/src/pages/Public/Components/CardsSection.js index 78476991..de59b7b4 100644 --- a/frontend/front/src/pages/Public/Components/CardsSection.js +++ b/frontend/front/src/pages/Public/Components/CardsSection.js @@ -3,7 +3,6 @@ import { Card, CardActions, CardContent, - CardMedia, Button, Typography, } from "@mui/material"; @@ -16,13 +15,57 @@ function CardsSection({ body, linkDescription, linkDownload, + link, }) { - const handleDownloadPDF = () => { - const pdfUrl = linkDownload; - const link = document.createElement("a"); - link.href = pdfUrl; - link.download = linkDescription; - link.click(); + const handleClick = () => { + if (link) { + const externalLink = document.createElement("a"); + externalLink.href = link; + externalLink.target = "_blank"; + externalLink.rel = "noopener noreferrer"; + externalLink.click(); + } else { + const pdfUrl = linkDownload; + const downloadLink = document.createElement("a"); + downloadLink.href = pdfUrl; + downloadLink.download = linkDescription; + downloadLink.click(); + } + }; + + const renderMedia = () => { + if (mediaType === "img") { + return ( + + ); + } else if (mediaType === "iframe") { + return ( + + ); + } else { + return null; + } }; return ( @@ -35,13 +78,17 @@ function CardsSection({ }} > - {body} @@ -54,24 +101,13 @@ function CardsSection({ textDecorationColor: "var(--color-text-2)", textTransform: "none", }} - onClick={handleDownloadPDF} + onClick={handleClick} > {linkDescription} - + {renderMedia()} ); } diff --git a/frontend/front/src/pages/Public/Pages/AboutHeatPump/AboutHeatPump.js b/frontend/front/src/pages/Public/Pages/AboutHeatPump/AboutHeatPump.js index 9231afc3..2c793ae5 100644 --- a/frontend/front/src/pages/Public/Pages/AboutHeatPump/AboutHeatPump.js +++ b/frontend/front/src/pages/Public/Pages/AboutHeatPump/AboutHeatPump.js @@ -6,6 +6,7 @@ import Heading1 from "../../Components/Typography/Heading1"; import Heading1BlueBgGround from "../../Components/Typography/Heading1BlueBgGround"; import Heading4 from "../../Components/Typography/Heading4"; import AboutHeatPumpCards from "./AboutHeatPumpsCards"; +import CardsSection from "../../Components/CardsSection"; const cardContent = [ { @@ -51,7 +52,7 @@ function AboutHeatPump() { > - + {/* {isSmallerThanMd ? ( > )} - - + */} + {/* {cardContent.map((card, index) => { return ( ); })} - - + */} + + + {cardContent.map((card, index) => { + return ( + + ); + })} + + diff --git a/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js b/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js index a02eba75..8fafdc9e 100644 --- a/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js +++ b/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js @@ -24,7 +24,7 @@ const cardBenefits = [ { icon: moneyIcon, title: "Saving Money", - body: "Air source heat pumps (ASHPs) can reduce electricity usage for heating by up to 50% compared to electrical furnaces and baseboard heaters. (Environmental Protection Agency - link). For cooling, ASHPs are roughly equivalent to “central air conditioning” and far more efficient than window AC units. Together, this can translate into homeowner savings of 20%-40% off of their annual heating and cooling bills. To compare your system and to see how much you could save, ", + body: "Air source heat pumps (ASHPs) can reduce electricity usage for heating by up to 50% compared to electrical furnaces and baseboard heaters. For cooling, ASHPs are roughly equivalent to “central air conditioning” and far more efficient than window AC units. Together, this can translate into homeowner savings of 20%-40% off of their annual heating and cooling bills. To compare your system and to see how much you could save, ", link: "https://www.masssave.com/residential/heating-comparison-calculator", }, { @@ -65,7 +65,7 @@ const BenefitsHeatPumps = () => { - + {/* {isSmallerThanSmm ? ( { > )} - + */} {cardBenefits.map((card) => ( diff --git a/frontend/front/src/pages/Public/Pages/GetInvolved.js b/frontend/front/src/pages/Public/Pages/GetInvolved.js index ef2bbbd3..496afeaf 100644 --- a/frontend/front/src/pages/Public/Pages/GetInvolved.js +++ b/frontend/front/src/pages/Public/Pages/GetInvolved.js @@ -56,12 +56,12 @@ function GetInvolved() { > - + {/* - + */} ), }, @@ -53,7 +53,7 @@ function CarrouselHero(props) { interval="8000" indicators={false} cycleNavigation={false} - // autoPlay={false} + autoPlay={false} styles={{ height: { heroHeight }, minHeight: "100vh", From 50d8b9e7234d2a16b2312d0c850b76ac13fe606e Mon Sep 17 00:00:00 2001 From: thiagobadini Date: Tue, 1 Aug 2023 21:14:09 -0400 Subject: [PATCH 13/41] added text --- frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js b/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js index 8fafdc9e..203adcb5 100644 --- a/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js +++ b/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js @@ -24,7 +24,7 @@ const cardBenefits = [ { icon: moneyIcon, title: "Saving Money", - body: "Air source heat pumps (ASHPs) can reduce electricity usage for heating by up to 50% compared to electrical furnaces and baseboard heaters. For cooling, ASHPs are roughly equivalent to “central air conditioning” and far more efficient than window AC units. Together, this can translate into homeowner savings of 20%-40% off of their annual heating and cooling bills. To compare your system and to see how much you could save, ", + body: "Air source heat pumps (ASHPs) can reduce electricity usage for heating by up to 50% compared to electrical furnaces and baseboard heaters (source). For cooling, ASHPs are roughly equivalent to “central air conditioning” and far more efficient than window AC units. Together, this can translate into homeowner savings of 20%-40% off of their annual heating and cooling bills. To compare your system and to see how much you could save, ", link: "https://www.masssave.com/residential/heating-comparison-calculator", }, { From 471bee96aff95bc436ea9cc6d026d1ef5228d043 Mon Sep 17 00:00:00 2001 From: thiagobadini Date: Tue, 15 Aug 2023 18:29:14 -0400 Subject: [PATCH 14/41] Added the links to the logos - about us --- .../src/pages/Public/Pages/AboutUs/AboutUs.js | 20 ++++++++--------- .../pages/Public/Pages/AboutUs/PartnerTile.js | 22 +++++++++---------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/frontend/front/src/pages/Public/Pages/AboutUs/AboutUs.js b/frontend/front/src/pages/Public/Pages/AboutUs/AboutUs.js index ce20ff3c..930c23da 100644 --- a/frontend/front/src/pages/Public/Pages/AboutUs/AboutUs.js +++ b/frontend/front/src/pages/Public/Pages/AboutUs/AboutUs.js @@ -48,17 +48,15 @@ function AboutUs() { alignContent={"flex-start"} flexDirection={{ xs: "column", md: "row" }} > - - + + + The Urban League of Eastern Massachusetts (ULEM) is the diff --git a/frontend/front/src/pages/Public/Pages/AboutUs/PartnerTile.js b/frontend/front/src/pages/Public/Pages/AboutUs/PartnerTile.js index ae6e13a7..9c4e4e66 100644 --- a/frontend/front/src/pages/Public/Pages/AboutUs/PartnerTile.js +++ b/frontend/front/src/pages/Public/Pages/AboutUs/PartnerTile.js @@ -8,17 +8,17 @@ const PartnerTile = ({ partnerName, paragraphText, image, website }) => { direction={{ xs: "column", md: "row" }} alignItems={{ xs: "center", md: "flex-start" }} > - - + + + {partnerName} {paragraphText} From a05fc029fe1698b7da09c451fc2349ac31008801 Mon Sep 17 00:00:00 2001 From: thiagobadini Date: Tue, 15 Aug 2023 18:34:05 -0400 Subject: [PATCH 15/41] Added links to the partners names - about us --- .../src/pages/Public/Pages/AboutUs/AboutUs.js | 24 +++++++++++++------ .../pages/Public/Pages/AboutUs/PartnerTile.js | 13 +++++++++- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/frontend/front/src/pages/Public/Pages/AboutUs/AboutUs.js b/frontend/front/src/pages/Public/Pages/AboutUs/AboutUs.js index 930c23da..f831ad30 100644 --- a/frontend/front/src/pages/Public/Pages/AboutUs/AboutUs.js +++ b/frontend/front/src/pages/Public/Pages/AboutUs/AboutUs.js @@ -59,13 +59,23 @@ function AboutUs() { - The Urban League of Eastern Massachusetts (ULEM) is the - sponsor of the BHPA effort. Since 1919, ULEM has delivered - workforce and economic development services and programs to - increase self-reliance of residents of the Boston community - and surrounding metropolitan areas. ULEM is a 501c3 nonprofit - organization and one of the oldest affiliates within the - National Urban League movement.{" "} + + The Urban League of Eastern Massachusetts (ULEM) + {" "} + is the sponsor of the BHPA effort. Since 1919, ULEM has + delivered workforce and economic development services and + programs to increase self-reliance of residents of the Boston + community and surrounding metropolitan areas. ULEM is a 501c3 + nonprofit organization and one of the oldest affiliates within + the National Urban League movement.{" "} diff --git a/frontend/front/src/pages/Public/Pages/AboutUs/PartnerTile.js b/frontend/front/src/pages/Public/Pages/AboutUs/PartnerTile.js index 9c4e4e66..4dbb4505 100644 --- a/frontend/front/src/pages/Public/Pages/AboutUs/PartnerTile.js +++ b/frontend/front/src/pages/Public/Pages/AboutUs/PartnerTile.js @@ -21,7 +21,18 @@ const PartnerTile = ({ partnerName, paragraphText, image, website }) => { - {partnerName} {paragraphText} + + {partnerName} + {" "} + {paragraphText} From 1c8ae99bc04e25094159dd8f9051b4478564cdf0 Mon Sep 17 00:00:00 2001 From: thiagobadini Date: Tue, 15 Aug 2023 18:47:13 -0400 Subject: [PATCH 16/41] Added source link - Benefits of Heat Pump --- .../pages/Public/Pages/BenefitsHeatPumps.js | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js b/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js index 203adcb5..7ca1df4f 100644 --- a/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js +++ b/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js @@ -10,7 +10,6 @@ import { Icon, } from "@mui/material"; import Heading1BlueBgGround from "../Components/Typography/Heading1BlueBgGround"; -import Heading1 from "../Components/Typography/Heading1"; import Heading3 from "../Components/Typography/Heading3"; import Heading4 from "../Components/Typography/Heading4"; import moneyIcon from "../../../assets/images/Icons/money.png"; @@ -24,25 +23,32 @@ const cardBenefits = [ { icon: moneyIcon, title: "Saving Money", - body: "Air source heat pumps (ASHPs) can reduce electricity usage for heating by up to 50% compared to electrical furnaces and baseboard heaters (source). For cooling, ASHPs are roughly equivalent to “central air conditioning” and far more efficient than window AC units. Together, this can translate into homeowner savings of 20%-40% off of their annual heating and cooling bills. To compare your system and to see how much you could save, ", + body: "Air source heat pumps (ASHPs) can reduce electricity usage for heating by up to 50% compared to electrical furnaces and baseboard heaters (", + bodyLink: + "https://www.amerenmissourisavings.com/hvac-air-source-heat-pump-education-flyer/", + body2: + "). For cooling, ASHPs are roughly equivalent to “central air conditioning” and far more efficient than window AC units. Together, this can translate into homeowner savings of 20%-40% off of their annual heating and cooling bills. To compare your system and to see how much you could save, ", link: "https://www.masssave.com/residential/heating-comparison-calculator", }, { icon: snowSunIcon, title: "Improved Heating & Cooling", body: "Heat pumps are an excellent way to heat and cool your home. They’re nearly silent, draw less electricity, and they are continuous: heat pumps’ continuous, low-level operation provides constant heating or cooling, eliminating the blasts of hot or cold that legacy systems usually create. To learn more about ASHP operation and benefits, ", + bodyLink: "", link: "https://goclean.masscec.com/clean-energy-solutions/air-source-heat-pumps", }, { icon: communityIcon, title: "Strengthening Community", body: "Boston residents want to stay in their homes and keep their communities strong, even while facing challenges from rising costs. Switching to heat pumps can lower utility costs, reducing the financial challenge of staying in the community. By also adding active cooling capacity, ASHPs also improve the “housing resiliency” of entire neighborhoods as annual temperatures rise. With both energy bills and temperatures on the rise, housing resiliency is more important than ever to empower communities to stay strong and stay together. To learn more, ", + bodyLink: "", link: "https://www.energy.gov/policy/articles/heat-pumps-keep-homes-warm-and-bills-low-winter", }, { icon: heatIcon, title: "Reducing Carbon Emissions", body: "Heat pumps are highly efficient heating and cooling systems that are electrically-powered. As such, they become “cleaner” whenever the source of their electric power becomes cleaner. Gas or oil fueled heating/cooling cannot benefit in the same way. How much of a difference will switching to ASHPs make in your case? Find specifics on the climate impact of a switch to heat pumps, ", + bodyLink: "", link: "https://goclean.masscec.com/clean-energy-solutions/", }, ]; @@ -50,7 +56,6 @@ const cardBenefits = [ const BenefitsHeatPumps = () => { const theme = useTheme(); const isSmallerThanSm = useMediaQuery(theme.breakpoints.down("sm")); - const isSmallerThanSmm = useMediaQuery(theme.breakpoints.down("smm")); return ( { - {/* - {isSmallerThanSmm ? ( - - ) : ( - <> - - - > - )} - */} {cardBenefits.map((card) => ( @@ -105,6 +97,26 @@ const BenefitsHeatPumps = () => { {card.body} + {card.bodyLink !== "" && ( + <> + + source + + {card.body2} + > + )} {card.link !== "" && ( Date: Tue, 15 Aug 2023 21:53:51 -0400 Subject: [PATCH 17/41] Try for Deployment to OpenShift --- backend/Dockerfile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 4dadf9e9..c20a9118 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,15 +1,17 @@ # syntax=docker/dockerfile:1 FROM ruby:3.1.3-alpine RUN apk update && apk upgrade && apk add build-base libpq-dev postgresql-client gcompat tzdata +RUN adduser rails root +USER rails WORKDIR /usr/src/app -# path context is the repo root -COPY backend/Gemfile backend/Gemfile.lock ./ +COPY Gemfile Gemfile.lock ./ + +RUN chmod -R 775 /usr/src/app +RUN chown -R rails:root /usr/src/app # add x86_64 for support on ARM platform - nokogiri expects x86 for distribution RUN bundle lock --add-platform x86_64-linux RUN bundle install -COPY ./backend . -COPY ./data-analysis/* /usr/src/data-analysis/ EXPOSE 3000 RUN chmod +x start.sh From 343baea0c1044823d89a5786cf67a23a1dc71894 Mon Sep 17 00:00:00 2001 From: Matthew Zagaja Date: Tue, 15 Aug 2023 22:01:09 -0400 Subject: [PATCH 18/41] ADD USER RIGHT NOW --- backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index c20a9118..b2f1fd65 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 FROM ruby:3.1.3-alpine RUN apk update && apk upgrade && apk add build-base libpq-dev postgresql-client gcompat tzdata -RUN adduser rails root +RUN adduser -S rails -G root USER rails WORKDIR /usr/src/app COPY Gemfile Gemfile.lock ./ From cec7f484e0b7418394443cd26edca9a996f9c4c1 Mon Sep 17 00:00:00 2001 From: Matthew Zagaja Date: Tue, 15 Aug 2023 22:03:33 -0400 Subject: [PATCH 19/41] Fix Copy --- backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index b2f1fd65..7a66d061 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -4,7 +4,7 @@ RUN apk update && apk upgrade && apk add build-base libpq-dev postgresql-client RUN adduser -S rails -G root USER rails WORKDIR /usr/src/app -COPY Gemfile Gemfile.lock ./ +COPY backend/Gemfile backend/Gemfile.lock ./ RUN chmod -R 775 /usr/src/app RUN chown -R rails:root /usr/src/app From 5b495734ef9b17f4a147099dfea9985eb1835684 Mon Sep 17 00:00:00 2001 From: Matthew Zagaja Date: Tue, 15 Aug 2023 22:07:39 -0400 Subject: [PATCH 20/41] Third Time is the Charm --- backend/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 7a66d061..cd987bfe 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -2,12 +2,13 @@ FROM ruby:3.1.3-alpine RUN apk update && apk upgrade && apk add build-base libpq-dev postgresql-client gcompat tzdata RUN adduser -S rails -G root +RUN chmod -R 775 /usr/src/app +RUN chown -R rails:root /usr/src/app + USER rails WORKDIR /usr/src/app COPY backend/Gemfile backend/Gemfile.lock ./ -RUN chmod -R 775 /usr/src/app -RUN chown -R rails:root /usr/src/app # add x86_64 for support on ARM platform - nokogiri expects x86 for distribution RUN bundle lock --add-platform x86_64-linux RUN bundle install From 16f8c142b3a2298cc6d16dec67f472a1a2a2078f Mon Sep 17 00:00:00 2001 From: Matthew Zagaja Date: Tue, 15 Aug 2023 22:09:21 -0400 Subject: [PATCH 21/41] =?UTF-8?q?4=20Try=20Matt=20They=E2=80=99ll=20Call?= =?UTF-8?q?=20Me?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index cd987bfe..f0ca4714 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -2,11 +2,11 @@ FROM ruby:3.1.3-alpine RUN apk update && apk upgrade && apk add build-base libpq-dev postgresql-client gcompat tzdata RUN adduser -S rails -G root +WORKDIR /usr/src/app RUN chmod -R 775 /usr/src/app RUN chown -R rails:root /usr/src/app USER rails -WORKDIR /usr/src/app COPY backend/Gemfile backend/Gemfile.lock ./ # add x86_64 for support on ARM platform - nokogiri expects x86 for distribution From 9a3d51593191bc0c17ef025d27f2914eebe10bd0 Mon Sep 17 00:00:00 2001 From: Matthew Zagaja Date: Tue, 15 Aug 2023 22:18:22 -0400 Subject: [PATCH 22/41] Stay On Target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don’t need to make this executable since the other change does this for us now. --- backend/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index f0ca4714..3cd4e1cc 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -14,6 +14,5 @@ RUN bundle lock --add-platform x86_64-linux RUN bundle install EXPOSE 3000 -RUN chmod +x start.sh ENTRYPOINT ["sh", "start.sh"] From 7e77faae361fa538a052214c0eec4ea2ec15f587 Mon Sep 17 00:00:00 2001 From: Matthew Zagaja Date: Tue, 15 Aug 2023 22:34:30 -0400 Subject: [PATCH 23/41] COPY Backend Directory --- backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 3cd4e1cc..16d244d0 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -2,12 +2,12 @@ FROM ruby:3.1.3-alpine RUN apk update && apk upgrade && apk add build-base libpq-dev postgresql-client gcompat tzdata RUN adduser -S rails -G root +COPY backend/ /usr/src/app/ WORKDIR /usr/src/app RUN chmod -R 775 /usr/src/app RUN chown -R rails:root /usr/src/app USER rails -COPY backend/Gemfile backend/Gemfile.lock ./ # add x86_64 for support on ARM platform - nokogiri expects x86 for distribution RUN bundle lock --add-platform x86_64-linux From 7eb4d190c2b586f56dae37e246f42dbd1d91fcbf Mon Sep 17 00:00:00 2001 From: "Efrain A. Davila" <105945226+EfrainAD@users.noreply.github.com> Date: Mon, 7 Aug 2023 19:59:19 -0400 Subject: [PATCH 24/41] Feature: The 'Completed' column is now presented as a button if the answer is yes. When clicked, it navigates the user to the survey. 1. I utilized the useGetSurveyVisitsQuery to retrieve all survey data. 2. Within the "Completed" column, I replaced the 'Yes' response with a button that facilitates user navigation to the survey. 3. Next, I regenerated the house data by appending completed: true and survey_id: visit.id. Please note that currently, the built-in method for searching survey visits by quiries is on the to-do list, according to https://docs.google.com/document/d/1QAek7K-pvnCJe4wxm38QdPCbszEE-esw3w-tuhEtMDQ/edit. So, I couldn't directly retrieve it. 4. Should any errors arise from survey visits, a CustomSnackbar is triggered to inform the user. However, the table still loads without interruption. --- frontend/front/src/pages/Admin/home/HomeTable.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index 6f3a426c..d1540536 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -13,8 +13,15 @@ import { useGetSurveyVisitsQuery, } from "../../../api/apiSlice"; import { useNavigate } from "react-router-dom"; + import { ADMIN_HOME, withAdminPrefix } from "../../../routing/routes"; +import { + useGetHomesQuery, + useGetSurveyVisitsQuery, +} from "../../../api/apiSlice"; +import { useNavigate } from "react-router-dom"; + // Formats addresses export const getAddress = (params) => { let unit_number = ""; @@ -81,7 +88,7 @@ const HomeTable = () => { size="small" onClick={() => handleUserLink(params.row.survey_id)} > - Yes + Yes ✅ ) : ( "No" From bcc58035b6193ef5c24a630617c2df06e600c498 Mon Sep 17 00:00:00 2001 From: "Efrain A. Davila" <105945226+EfrainAD@users.noreply.github.com> Date: Sat, 19 Aug 2023 22:23:14 -0400 Subject: [PATCH 25/41] Optimization: Improve efficiency by introducing homeIdToSurveyVisitIdMap and remove the mapping of every home --- .../front/src/pages/Admin/home/HomeTable.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index d1540536..d84da798 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -16,12 +16,6 @@ import { useNavigate } from "react-router-dom"; import { ADMIN_HOME, withAdminPrefix } from "../../../routing/routes"; -import { - useGetHomesQuery, - useGetSurveyVisitsQuery, -} from "../../../api/apiSlice"; -import { useNavigate } from "react-router-dom"; - // Formats addresses export const getAddress = (params) => { let unit_number = ""; @@ -44,7 +38,10 @@ const HomeTable = () => { ); const handleHomeLink = (home) => goToBreadcrumb("home", home); - const handleUserLink = (visit) => navigate("/admin/survey/visit/" + visit); + + const handleUserLink = (home) => { + navigate("/admin/survey/visit/" + homeIdToSurveyVisitIdMap[home.id]); + }; const handleAssignmentLink = (assignment) => goToBreadcrumb("assignment", assignment); @@ -86,7 +83,7 @@ const HomeTable = () => { sx={{ minWidth: "unset", padding: "0px" }} color="primary" size="small" - onClick={() => handleUserLink(params.row.survey_id)} + onClick={() => handleUserLink(params.row)} > Yes ✅ @@ -140,6 +137,12 @@ const HomeTable = () => { isLoading: isSurveyVisitsDataLoading, } = useGetSurveyVisitsQuery(); + const homeIdToSurveyVisitIdMap = surveyVisitsData + ? surveyVisitsData.reduce((acc, visit) => { + return { ...acc, [visit.home_id]: visit.id }; + }, {}) + : {}; + const isDataReady = !isHomesDataLoading && !isSurveyVisitsDataLoading && homesData; From 9b1832bfd329b9a6c46f20fbae614cac9d7e53ab Mon Sep 17 00:00:00 2001 From: Matt DelSordo Date: Tue, 25 Jul 2023 22:20:08 -0400 Subject: [PATCH 26/41] 438: query survey_visits to mark things completed This isn't 100% what we want, since it can't check the survey_responses on the survey_visits. Should be removed pending #405. --- .../front/src/hooks/useHomesWithCompleted.js | 38 +++++++++++++++++++ .../src/pages/Admin/assignment/AssignTable.js | 8 ++-- .../front/src/pages/Admin/home/HomeTable.js | 21 ++++++++++ .../src/pages/Surveyor/dashboard/ListView.js | 13 +++++-- 4 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 frontend/front/src/hooks/useHomesWithCompleted.js diff --git a/frontend/front/src/hooks/useHomesWithCompleted.js b/frontend/front/src/hooks/useHomesWithCompleted.js new file mode 100644 index 00000000..804c6fd3 --- /dev/null +++ b/frontend/front/src/hooks/useHomesWithCompleted.js @@ -0,0 +1,38 @@ +import { useMemo } from "react"; +import { useGetSurveyVisitsQuery } from "../api/apiSlice"; + +/** + * Workaround until https://github.com/codeforboston/urban-league-heat-pump-accelerator/pull/405 is merged + */ + +export const setHomesCompleted = (homes, surveyVisits) => + (homes || []).map((home) => ({ + ...home, + completed: !!surveyVisits?.find((sv) => sv.home_id === home.id), + })); + +export const useHomesWithCompleted = (homes) => { + const { data: surveyVisits } = useGetSurveyVisitsQuery(); + + return useMemo( + () => setHomesCompleted(homes, surveyVisits), + [homes, surveyVisits] + ); +}; + +export const useAssignmentsWithCompleted = (assignments) => { + const { data: surveyVisits } = useGetSurveyVisitsQuery(); + + return useMemo( + () => + (assignments || []).map((a) => { + const newHomes = setHomesCompleted(a.homes, surveyVisits); + return { + ...a, + homes: newHomes, + completed: a.homes.every((h) => h.completed === true), + }; + }), + [assignments, surveyVisits] + ); +}; diff --git a/frontend/front/src/pages/Admin/assignment/AssignTable.js b/frontend/front/src/pages/Admin/assignment/AssignTable.js index 4cd00d9f..58d3d880 100644 --- a/frontend/front/src/pages/Admin/assignment/AssignTable.js +++ b/frontend/front/src/pages/Admin/assignment/AssignTable.js @@ -51,17 +51,19 @@ const AssignTable = () => { isLoading: isSurveyorsDataLoading, } = useGetSurveyorsQuery(); + const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); + const tableData = useMemo( () => - assignmentsData && surveyorsData - ? assignmentsData.map((a) => ({ + assignmentsWithCompleted && surveyorsData + ? assignmentsWithCompleted.map((a) => ({ ...a, surveyorData: a.surveyor_ids.map((id) => surveyorsData.find((s) => s.id === id) ), })) : [], - [assignmentsData, surveyorsData] + [assignmentsWithCompleted, surveyorsData] ); const [ diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index d84da798..b78291da 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -76,6 +76,7 @@ const HomeTable = () => { { field: "completed", headerName: "Completed", +<<<<<<< HEAD renderCell: (params) => params.row.completed === true ? ( { ) : ( "No" ), +======= + renderCell: (params) => (params.row.completed === true ? "Yes ✅" : "No"), +>>>>>>> bf45d58 (438: query survey_visits to mark things completed) minWidth: 100, maxWidth: 150, flex: 0.8, @@ -137,6 +141,7 @@ const HomeTable = () => { isLoading: isSurveyVisitsDataLoading, } = useGetSurveyVisitsQuery(); +<<<<<<< HEAD const homeIdToSurveyVisitIdMap = surveyVisitsData ? surveyVisitsData.reduce((acc, visit) => { return { ...acc, [visit.home_id]: visit.id }; @@ -147,6 +152,11 @@ const HomeTable = () => { !isHomesDataLoading && !isSurveyVisitsDataLoading && homesData; if (!isDataReady) { +======= + const homesWithCompleted = useHomesWithCompleted(homesData); + + if (isHomesDataLoading) { +>>>>>>> bf45d58 (438: query survey_visits to mark things completed) return ; } @@ -159,6 +169,7 @@ const HomeTable = () => { severity="error" /> ) : ( +<<<<<<< HEAD <> {isSurveyVisitsError && ( { autoHeight /> > +======= + +>>>>>>> bf45d58 (438: query survey_visits to mark things completed) )} ); diff --git a/frontend/front/src/pages/Surveyor/dashboard/ListView.js b/frontend/front/src/pages/Surveyor/dashboard/ListView.js index 908ab8f1..e92bd1ec 100644 --- a/frontend/front/src/pages/Surveyor/dashboard/ListView.js +++ b/frontend/front/src/pages/Surveyor/dashboard/ListView.js @@ -10,6 +10,7 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import Loader from "../../../components/Loader"; import { useAssignmentsForCurrentUser } from "../../../hooks/useDataForSurveyor"; import { useSearchParams } from "react-router-dom"; +import { useAssignmentsWithCompleted } from "../../../hooks/useHomesWithCompleted"; const ListView = () => { const { @@ -18,14 +19,18 @@ const ListView = () => { error: isAssignmentsError, } = useAssignmentsForCurrentUser(); + const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); + const [openAccordion, setOpenAccordion] = useState(); const [searchParams] = useSearchParams(); // open the accordion of the first incomplete assignment when the page opens useEffect(() => { - setOpenAccordion((assignmentsData || []).find((a) => !a.completed)?.id); - }, [assignmentsData]); + setOpenAccordion( + (assignmentsWithCompleted || []).find((a) => !a.completed)?.id + ); + }, [assignmentsWithCompleted]); return ( @@ -49,12 +54,12 @@ const ListView = () => { Your Assignments - {(!assignmentsData || assignmentsData.length === 0) && ( + {(!assignmentsWithCompleted || assignmentsData.length === 0) && ( No assignments found. )} - {assignmentsData?.map((item, i) => { + {assignmentsWithCompleted?.map((item, i) => { return ( Date: Thu, 10 Aug 2023 17:29:43 -0400 Subject: [PATCH 27/41] 438: actually integrate with completed field --- .../front/src/hooks/useHomesWithCompleted.js | 38 ------------------- .../src/pages/Admin/assignment/AssignTable.js | 8 ++-- .../front/src/pages/Admin/home/HomeTable.js | 21 ---------- .../src/pages/Surveyor/dashboard/ListView.js | 13 ++----- 4 files changed, 7 insertions(+), 73 deletions(-) delete mode 100644 frontend/front/src/hooks/useHomesWithCompleted.js diff --git a/frontend/front/src/hooks/useHomesWithCompleted.js b/frontend/front/src/hooks/useHomesWithCompleted.js deleted file mode 100644 index 804c6fd3..00000000 --- a/frontend/front/src/hooks/useHomesWithCompleted.js +++ /dev/null @@ -1,38 +0,0 @@ -import { useMemo } from "react"; -import { useGetSurveyVisitsQuery } from "../api/apiSlice"; - -/** - * Workaround until https://github.com/codeforboston/urban-league-heat-pump-accelerator/pull/405 is merged - */ - -export const setHomesCompleted = (homes, surveyVisits) => - (homes || []).map((home) => ({ - ...home, - completed: !!surveyVisits?.find((sv) => sv.home_id === home.id), - })); - -export const useHomesWithCompleted = (homes) => { - const { data: surveyVisits } = useGetSurveyVisitsQuery(); - - return useMemo( - () => setHomesCompleted(homes, surveyVisits), - [homes, surveyVisits] - ); -}; - -export const useAssignmentsWithCompleted = (assignments) => { - const { data: surveyVisits } = useGetSurveyVisitsQuery(); - - return useMemo( - () => - (assignments || []).map((a) => { - const newHomes = setHomesCompleted(a.homes, surveyVisits); - return { - ...a, - homes: newHomes, - completed: a.homes.every((h) => h.completed === true), - }; - }), - [assignments, surveyVisits] - ); -}; diff --git a/frontend/front/src/pages/Admin/assignment/AssignTable.js b/frontend/front/src/pages/Admin/assignment/AssignTable.js index 58d3d880..4cd00d9f 100644 --- a/frontend/front/src/pages/Admin/assignment/AssignTable.js +++ b/frontend/front/src/pages/Admin/assignment/AssignTable.js @@ -51,19 +51,17 @@ const AssignTable = () => { isLoading: isSurveyorsDataLoading, } = useGetSurveyorsQuery(); - const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); - const tableData = useMemo( () => - assignmentsWithCompleted && surveyorsData - ? assignmentsWithCompleted.map((a) => ({ + assignmentsData && surveyorsData + ? assignmentsData.map((a) => ({ ...a, surveyorData: a.surveyor_ids.map((id) => surveyorsData.find((s) => s.id === id) ), })) : [], - [assignmentsWithCompleted, surveyorsData] + [assignmentsData, surveyorsData] ); const [ diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index b78291da..d84da798 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -76,7 +76,6 @@ const HomeTable = () => { { field: "completed", headerName: "Completed", -<<<<<<< HEAD renderCell: (params) => params.row.completed === true ? ( { ) : ( "No" ), -======= - renderCell: (params) => (params.row.completed === true ? "Yes ✅" : "No"), ->>>>>>> bf45d58 (438: query survey_visits to mark things completed) minWidth: 100, maxWidth: 150, flex: 0.8, @@ -141,7 +137,6 @@ const HomeTable = () => { isLoading: isSurveyVisitsDataLoading, } = useGetSurveyVisitsQuery(); -<<<<<<< HEAD const homeIdToSurveyVisitIdMap = surveyVisitsData ? surveyVisitsData.reduce((acc, visit) => { return { ...acc, [visit.home_id]: visit.id }; @@ -152,11 +147,6 @@ const HomeTable = () => { !isHomesDataLoading && !isSurveyVisitsDataLoading && homesData; if (!isDataReady) { -======= - const homesWithCompleted = useHomesWithCompleted(homesData); - - if (isHomesDataLoading) { ->>>>>>> bf45d58 (438: query survey_visits to mark things completed) return ; } @@ -169,7 +159,6 @@ const HomeTable = () => { severity="error" /> ) : ( -<<<<<<< HEAD <> {isSurveyVisitsError && ( { autoHeight /> > -======= - ->>>>>>> bf45d58 (438: query survey_visits to mark things completed) )} ); diff --git a/frontend/front/src/pages/Surveyor/dashboard/ListView.js b/frontend/front/src/pages/Surveyor/dashboard/ListView.js index e92bd1ec..908ab8f1 100644 --- a/frontend/front/src/pages/Surveyor/dashboard/ListView.js +++ b/frontend/front/src/pages/Surveyor/dashboard/ListView.js @@ -10,7 +10,6 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import Loader from "../../../components/Loader"; import { useAssignmentsForCurrentUser } from "../../../hooks/useDataForSurveyor"; import { useSearchParams } from "react-router-dom"; -import { useAssignmentsWithCompleted } from "../../../hooks/useHomesWithCompleted"; const ListView = () => { const { @@ -19,18 +18,14 @@ const ListView = () => { error: isAssignmentsError, } = useAssignmentsForCurrentUser(); - const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); - const [openAccordion, setOpenAccordion] = useState(); const [searchParams] = useSearchParams(); // open the accordion of the first incomplete assignment when the page opens useEffect(() => { - setOpenAccordion( - (assignmentsWithCompleted || []).find((a) => !a.completed)?.id - ); - }, [assignmentsWithCompleted]); + setOpenAccordion((assignmentsData || []).find((a) => !a.completed)?.id); + }, [assignmentsData]); return ( @@ -54,12 +49,12 @@ const ListView = () => { Your Assignments - {(!assignmentsWithCompleted || assignmentsData.length === 0) && ( + {(!assignmentsData || assignmentsData.length === 0) && ( No assignments found. )} - {assignmentsWithCompleted?.map((item, i) => { + {assignmentsData?.map((item, i) => { return ( Date: Wed, 16 Aug 2023 19:58:32 -0400 Subject: [PATCH 28/41] Responsiveness (#443) * prevent LOG OUT button from wrapping * move Assignment link on Assignments table to onRowClick function * stack buttons for multiple surveyors and format the surveyor button properly * replace rowClick function with assignment link button * * stack down add/remove buttons on assignTable at breakpoint * scrolling surveyor names * fix UserProfile responsiveness (width -> maxWidth * Stack down surveyors in assignprofile at 600px * assignprofile address now links to the home, and home column is removed * implement adminTheme.js * integrate AdminTheme * fix homeProfile responsiveness (width->maxWidth) * stack down create home button at breakpoint 450px * hometable optimized * Matt's changes * drop in responsiveFontSizes * prevent LOG OUT button from wrapping move Assignment link on Assignments table to onRowClick function stack buttons for multiple surveyors and format the surveyor button properly replace rowClick function with assignment link button * stack down add/remove buttons on assignTable at breakpoint * scrolling surveyor names fix UserProfile responsiveness (width -> maxWidth) Stack down surveyors in assignprofile at 600px assignprofile address now links to the home, and home column is removed implement adminTheme.js integrate AdminTheme fix homeProfile responsiveness (width->maxWidth) stack down create home button at breakpoint 450px hometable optimized Matt's changes drop in responsiveFontSizes --- .../pages/Admin/assignment/AssignProfile.js | 72 +++++++------ .../src/pages/Admin/assignment/AssignTable.js | 101 +++++++++++------- frontend/front/src/pages/Admin/home/Home.js | 34 +++--- .../front/src/pages/Admin/home/HomeProfile.js | 2 +- .../front/src/pages/Admin/home/HomeTable.js | 34 +++--- frontend/front/src/pages/Admin/nav/Nav.js | 7 +- .../front/src/pages/Admin/user/UserProfile.js | 2 +- .../src/pages/Public/Assets/adminTheme.js | 19 ++++ frontend/front/yarn.lock | 2 +- 9 files changed, 164 insertions(+), 109 deletions(-) create mode 100644 frontend/front/src/pages/Public/Assets/adminTheme.js diff --git a/frontend/front/src/pages/Admin/assignment/AssignProfile.js b/frontend/front/src/pages/Admin/assignment/AssignProfile.js index 7a486c05..dc415ec2 100644 --- a/frontend/front/src/pages/Admin/assignment/AssignProfile.js +++ b/frontend/front/src/pages/Admin/assignment/AssignProfile.js @@ -1,4 +1,4 @@ -import { Box, Button, Typography } from "@mui/material"; +import { Box, Button, Stack, Typography } from "@mui/material"; import { useGetAssignmentQuery, useGetSurveyorsQuery, @@ -52,18 +52,32 @@ const AssignProfile = () => { : "Unassigned"; const handleUserLink = (user) => goToBreadcrumb("user", user); - const handleHomeLink = (home) => goToBreadcrumb("home", home); + const handleHomeLink = (home) => { + goToBreadcrumb("home", home); + }; const columns = [ - { field: "id", headerName: "HomeId", maxWidth: 100, flex: 1 }, { field: "visit_order", headerName: "Visit order", maxWidth: 100, flex: 1 }, { field: "address", valueGetter: getAddress, headerName: "Address", - minWidth: 200, - maxWidth: 300, - flex: 1.5, + minWidth: 300, + + renderCell: (params) => ( + + handleHomeLink(params.row)} + sx={{ + textAlign: "left", + minWidth: "max-content", + padding: 0, + }} + > + {params.value} + + + ), }, { field: "zip_code", @@ -100,22 +114,6 @@ const AssignProfile = () => { ), }, - { - field: "hid", - headerName: "Home", - minWidth: 50, - maxWidth: 80, - renderCell: (params) => ( - handleHomeLink(params.row)} - > - View - - ), - }, { field: "unassign", headerName: "Unassign", @@ -154,25 +152,29 @@ const AssignProfile = () => { /> ) : ( - Assigned Surveyor(s): - {surveyors.map((surveyor) => ( - handleUserLink(surveyor)} - > - {`${surveyor.lastname}, ${surveyor.firstname}`} - - ))} - + + {surveyors.map((surveyor) => ( + handleUserLink(surveyor)} + > + {`${surveyor.lastname}, ${surveyor.firstname}`} + + ))} + + { const handleUserLink = (user) => goToBreadcrumb("user", user); - const handleAssignmentLink = (assignment) => + const handleAssignmentLink = (assignment) => { goToBreadcrumb("assignment", assignment); - + }; // DataGrid columns const columns = [ - { field: "id", headerName: "Assign. Id", maxWidth: 100, flex: 1 }, { - field: "assignment", - headerName: "Assignment", - minWidth: 110, + field: "id", + headerName: "Id #", + maxWidth: 50, flex: 1, renderCell: (params) => ( handleAssignmentLink(params.row)} + sx={{ minWidth: "fit-content", width: "auto" }} > - View + {params.row.id} ), }, + { + field: "surveyorData", + headerName: "Surveyor(s)", + flex: 1, + renderCell: (params) => { + return params.row.surveyorData ? ( + + {params.row.surveyorData.map((surveyor) => { + return ( + handleUserLink(surveyor)} + sx={{ + textAlign: "left", + minWidth: "max-content", + }} + > + {`${surveyor.firstname} ${surveyor.lastname}`} + + ); + })} + + ) : ( + "Unassigned" + ); + }, + }, { field: "completed", headerName: "Completion", - width: 110, + width: "min-content", + maxWidth: 110, flex: 1, renderCell: (params) => { let completed = 0; @@ -142,26 +175,6 @@ const AssignTable = () => { }`; }, }, - { - field: "surveyorData", - headerName: "Surveyor(s)", - width: 150, - flex: 1, - renderCell: (params) => { - return params.row.surveyorData - ? params.row.surveyorData.map((surveyor) => { - return ( - handleUserLink(surveyor)} - > - {`${surveyor.firstname} ${surveyor.lastname}`} - - ); - }) - : "Unassigned"; - }, - }, ]; return ( @@ -187,7 +200,12 @@ const AssignTable = () => { )} - + Surveyor @@ -206,12 +224,18 @@ const AssignTable = () => { - - Add - - - Remove - + + + Add + + + Remove + + { columns={columns} pageSize={20} rowsPerPageOptions={[20]} + getRowHeight={() => "auto"} disableSelectionOnClick autoHeight checkboxSelection diff --git a/frontend/front/src/pages/Admin/home/Home.js b/frontend/front/src/pages/Admin/home/Home.js index 9ca0ed31..1d7e1cf6 100644 --- a/frontend/front/src/pages/Admin/home/Home.js +++ b/frontend/front/src/pages/Admin/home/Home.js @@ -1,4 +1,4 @@ -import { Box, Button, IconButton, TextField } from "@mui/material"; +import { Box, Button, IconButton, Stack, TextField } from "@mui/material"; import AddIcon from "@mui/icons-material/Add"; import ContainerTitle from "../component/ContainerTitle"; @@ -10,29 +10,33 @@ import SearchIcon from "@mui/icons-material/Search"; const Home = () => { return ( - - + + - - } - to="createHome" - > - Create New Home - - - + } + to="createHome" + > + Create New Home + + diff --git a/frontend/front/src/pages/Admin/home/HomeProfile.js b/frontend/front/src/pages/Admin/home/HomeProfile.js index 5d33f7ff..eb8d9073 100644 --- a/frontend/front/src/pages/Admin/home/HomeProfile.js +++ b/frontend/front/src/pages/Admin/home/HomeProfile.js @@ -76,7 +76,7 @@ const HomeProfile = () => { /> ) : ( <> - + Home Profile: {hid} diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index d84da798..c3cdcb62 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -56,8 +56,23 @@ const HomeTable = () => { field: "address", valueGetter: getAddress, headerName: "Address", - minWidth: 200, - flex: 1, + minWidth: 300, + // maxWidth: 300, + // flex: 1.5, + renderCell: (params) => ( + + handleHomeLink(params.row)} + sx={{ + textAlign: "left", + minWidth: "max-content", + padding: 0, + }} + > + {params.value} + + + ), }, { field: "city", @@ -109,21 +124,6 @@ const HomeTable = () => { headerName: "Assignment", width: 110, }, - { - field: "home", - renderCell: (params) => ( - handleHomeLink(params.row)} - > - View - - ), - headerName: "Home", - maxWidth: 80, - }, ]; const { diff --git a/frontend/front/src/pages/Admin/nav/Nav.js b/frontend/front/src/pages/Admin/nav/Nav.js index decde38f..23114c2b 100644 --- a/frontend/front/src/pages/Admin/nav/Nav.js +++ b/frontend/front/src/pages/Admin/nav/Nav.js @@ -16,7 +16,12 @@ const Nav = () => { SURVEYOR MODE - + LOG OUT diff --git a/frontend/front/src/pages/Admin/user/UserProfile.js b/frontend/front/src/pages/Admin/user/UserProfile.js index 89bb4817..d6a7bcc8 100644 --- a/frontend/front/src/pages/Admin/user/UserProfile.js +++ b/frontend/front/src/pages/Admin/user/UserProfile.js @@ -113,7 +113,7 @@ const UserProfile = () => { title="Confirm Delete" message="Please confirm to delete this user." /> - + User Profile: {uid} {/* Could add user ID to header. */} diff --git a/frontend/front/src/pages/Public/Assets/adminTheme.js b/frontend/front/src/pages/Public/Assets/adminTheme.js new file mode 100644 index 00000000..26295145 --- /dev/null +++ b/frontend/front/src/pages/Public/Assets/adminTheme.js @@ -0,0 +1,19 @@ +import { createTheme, responsiveFontSizes } from "@mui/material"; + +/* The custom colors palette is located in the Index.css file. */ + +let adminTheme = createTheme({ + breakpoints: { + values: { + xs: 0, + xxs: 330, // Custom breakpoint + smm: 450, // Custom breakpoint + sm: 600, + md: 960, + lg: 1280, + xl: 1920, + }, + }, +}); + +export default responsiveFontSizes(adminTheme); diff --git a/frontend/front/yarn.lock b/frontend/front/yarn.lock index e9e79865..a47bd893 100644 --- a/frontend/front/yarn.lock +++ b/frontend/front/yarn.lock @@ -10135,4 +10135,4 @@ yargs@^16.2.0: yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== \ No newline at end of file From 0305355f927e962bee8a3fc73089022ed3c0cb89 Mon Sep 17 00:00:00 2001 From: Matt DelSordo Date: Tue, 15 Aug 2023 21:11:31 -0400 Subject: [PATCH 29/41] 455: return survey answers in survey visit response --- .../app/views/survey_visits/_survey_visit.json.jbuilder | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/app/views/survey_visits/_survey_visit.json.jbuilder b/backend/app/views/survey_visits/_survey_visit.json.jbuilder index 72b9169c..380e8e8a 100644 --- a/backend/app/views/survey_visits/_survey_visit.json.jbuilder +++ b/backend/app/views/survey_visits/_survey_visit.json.jbuilder @@ -2,3 +2,12 @@ json.extract! survey_visit, :id, :surveyor_id, :home_id, :created_at, :updated_at json.url survey_visit_url(survey_visit, format: :json) +json.survey_response do + json.id survey_visit.survey_response.id + json.survey_id survey_visit.survey_response.survey_id + json.survey_answers survey_visit.survey_response.survey_answers do |sa| + json.id sa.id + json.survey_question_id sa.survey_question_id + json.answer sa.answer + end +end From 4effd6abd40d2bea96c13a81474a8913068837d8 Mon Sep 17 00:00:00 2001 From: Matt DelSordo Date: Tue, 15 Aug 2023 21:14:44 -0400 Subject: [PATCH 30/41] appease prettier --- frontend/front/src/pages/Public/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/front/src/pages/Public/Readme.md b/frontend/front/src/pages/Public/Readme.md index 5fd7cfa1..797892c5 100644 --- a/frontend/front/src/pages/Public/Readme.md +++ b/frontend/front/src/pages/Public/Readme.md @@ -25,4 +25,4 @@ - As an authorized user, I want to be able to login. - As an authorized user, I want to be able to change my password. - As an authorized user, I want to be able to login/logout successfully. -- As an authorized user, I am not able to create new users \ No newline at end of file +- As an authorized user, I am not able to create new users From fd2f67beaf6c50390db648c318412707880d03ab Mon Sep 17 00:00:00 2001 From: Matt DelSordo Date: Thu, 17 Aug 2023 16:54:44 -0400 Subject: [PATCH 31/41] add survey_visit_ids to home response This will make linking between homes and survey_visits on the admin homes table a lot easier. Elsewhere we can filter survey_visits on home_id. --- backend/app/views/homes/_home.json.jbuilder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/views/homes/_home.json.jbuilder b/backend/app/views/homes/_home.json.jbuilder index 0ef6d611..ab3ae7e4 100644 --- a/backend/app/views/homes/_home.json.jbuilder +++ b/backend/app/views/homes/_home.json.jbuilder @@ -1,7 +1,7 @@ # frozen_string_literal: true json.extract! home, :id, :street_number, :street_name, :unit_number, :city, :state, :zip_code, :building_type, - :assignment_id, :visit_order, :latitude, :longitude + :assignment_id, :visit_order, :latitude, :longitude, :survey_visit_ids json.visited home.visited? json.completed home.completed? json.url home_url(home, format: :json) From 89bc727a3756cee373ffd7b19e199572d92adbfa Mon Sep 17 00:00:00 2001 From: "Efrain A. Davila" <105945226+EfrainAD@users.noreply.github.com> Date: Mon, 7 Aug 2023 19:59:19 -0400 Subject: [PATCH 32/41] Feature: The 'Completed' column is now presented as a button if the answer is yes. When clicked, it navigates the user to the survey. 1. I utilized the useGetSurveyVisitsQuery to retrieve all survey data. 2. Within the "Completed" column, I replaced the 'Yes' response with a button that facilitates user navigation to the survey. 3. Next, I regenerated the house data by appending completed: true and survey_id: visit.id. Please note that currently, the built-in method for searching survey visits by quiries is on the to-do list, according to https://docs.google.com/document/d/1QAek7K-pvnCJe4wxm38QdPCbszEE-esw3w-tuhEtMDQ/edit. So, I couldn't directly retrieve it. 4. Should any errors arise from survey visits, a CustomSnackbar is triggered to inform the user. However, the table still loads without interruption. --- frontend/front/src/pages/Admin/home/HomeTable.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index c3cdcb62..3fc66fb3 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -15,6 +15,11 @@ import { import { useNavigate } from "react-router-dom"; import { ADMIN_HOME, withAdminPrefix } from "../../../routing/routes"; +import { + useGetHomesQuery, + useGetSurveyVisitsQuery, +} from "../../../api/apiSlice"; +import { useNavigate } from "react-router-dom"; // Formats addresses export const getAddress = (params) => { From d81216a2ee1453d64bc46332daecd9c59ae708b8 Mon Sep 17 00:00:00 2001 From: Matt DelSordo Date: Tue, 25 Jul 2023 22:20:08 -0400 Subject: [PATCH 33/41] This trying fix my branch 438: query survey_visits to mark things completed This isn't 100% what we want, since it can't check the survey_responses on the survey_visits. Should be removed pending #405. --- .../front/src/hooks/useHomesWithCompleted.js | 38 +++++++++++++++++++ .../src/pages/Admin/assignment/AssignTable.js | 29 ++++++++++++-- .../src/pages/Surveyor/dashboard/ListView.js | 13 +++++-- 3 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 frontend/front/src/hooks/useHomesWithCompleted.js diff --git a/frontend/front/src/hooks/useHomesWithCompleted.js b/frontend/front/src/hooks/useHomesWithCompleted.js new file mode 100644 index 00000000..804c6fd3 --- /dev/null +++ b/frontend/front/src/hooks/useHomesWithCompleted.js @@ -0,0 +1,38 @@ +import { useMemo } from "react"; +import { useGetSurveyVisitsQuery } from "../api/apiSlice"; + +/** + * Workaround until https://github.com/codeforboston/urban-league-heat-pump-accelerator/pull/405 is merged + */ + +export const setHomesCompleted = (homes, surveyVisits) => + (homes || []).map((home) => ({ + ...home, + completed: !!surveyVisits?.find((sv) => sv.home_id === home.id), + })); + +export const useHomesWithCompleted = (homes) => { + const { data: surveyVisits } = useGetSurveyVisitsQuery(); + + return useMemo( + () => setHomesCompleted(homes, surveyVisits), + [homes, surveyVisits] + ); +}; + +export const useAssignmentsWithCompleted = (assignments) => { + const { data: surveyVisits } = useGetSurveyVisitsQuery(); + + return useMemo( + () => + (assignments || []).map((a) => { + const newHomes = setHomesCompleted(a.homes, surveyVisits); + return { + ...a, + homes: newHomes, + completed: a.homes.every((h) => h.completed === true), + }; + }), + [assignments, surveyVisits] + ); +}; diff --git a/frontend/front/src/pages/Admin/assignment/AssignTable.js b/frontend/front/src/pages/Admin/assignment/AssignTable.js index cf65ce32..49cd91e6 100644 --- a/frontend/front/src/pages/Admin/assignment/AssignTable.js +++ b/frontend/front/src/pages/Admin/assignment/AssignTable.js @@ -18,6 +18,7 @@ import InputLabel from "@mui/material/InputLabel"; import Loader from "../../../components/Loader"; import Select from "@mui/material/Select"; import { ADMIN_ASSIGNMENT, withAdminPrefix } from "../../../routing/routes"; +import { useAssignmentsWithCompleted } from "../../../hooks/useHomesWithCompleted"; const AssignTable = () => { const goToBreadcrumb = useGoToBreadcrumb(); @@ -51,17 +52,19 @@ const AssignTable = () => { isLoading: isSurveyorsDataLoading, } = useGetSurveyorsQuery(); + const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); + const tableData = useMemo( () => - assignmentsData && surveyorsData - ? assignmentsData.map((a) => ({ + assignmentsWithCompleted && surveyorsData + ? assignmentsWithCompleted.map((a) => ({ ...a, surveyorData: a.surveyor_ids.map((id) => surveyorsData.find((s) => s.id === id) ), })) : [], - [assignmentsData, surveyorsData] + [assignmentsWithCompleted, surveyorsData] ); const [ @@ -175,6 +178,26 @@ const AssignTable = () => { }`; }, }, + { + field: "surveyorData", + headerName: "Surveyor(s)", + width: 150, + flex: 1, + renderCell: (params) => { + return params.row.surveyorData + ? params.row.surveyorData.map((surveyor) => { + return ( + handleUserLink(surveyor)} + > + {`${surveyor.firstname} ${surveyor.lastname}`} + + ); + }) + : "Unassigned"; + }, + }, ]; return ( diff --git a/frontend/front/src/pages/Surveyor/dashboard/ListView.js b/frontend/front/src/pages/Surveyor/dashboard/ListView.js index 908ab8f1..e92bd1ec 100644 --- a/frontend/front/src/pages/Surveyor/dashboard/ListView.js +++ b/frontend/front/src/pages/Surveyor/dashboard/ListView.js @@ -10,6 +10,7 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import Loader from "../../../components/Loader"; import { useAssignmentsForCurrentUser } from "../../../hooks/useDataForSurveyor"; import { useSearchParams } from "react-router-dom"; +import { useAssignmentsWithCompleted } from "../../../hooks/useHomesWithCompleted"; const ListView = () => { const { @@ -18,14 +19,18 @@ const ListView = () => { error: isAssignmentsError, } = useAssignmentsForCurrentUser(); + const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); + const [openAccordion, setOpenAccordion] = useState(); const [searchParams] = useSearchParams(); // open the accordion of the first incomplete assignment when the page opens useEffect(() => { - setOpenAccordion((assignmentsData || []).find((a) => !a.completed)?.id); - }, [assignmentsData]); + setOpenAccordion( + (assignmentsWithCompleted || []).find((a) => !a.completed)?.id + ); + }, [assignmentsWithCompleted]); return ( @@ -49,12 +54,12 @@ const ListView = () => { Your Assignments - {(!assignmentsData || assignmentsData.length === 0) && ( + {(!assignmentsWithCompleted || assignmentsData.length === 0) && ( No assignments found. )} - {assignmentsData?.map((item, i) => { + {assignmentsWithCompleted?.map((item, i) => { return ( Date: Thu, 10 Aug 2023 17:29:43 -0400 Subject: [PATCH 34/41] 438: actually integrate with completed field --- .../front/src/hooks/useHomesWithCompleted.js | 38 ------------------- .../src/pages/Admin/assignment/AssignTable.js | 9 ++--- .../src/pages/Surveyor/dashboard/ListView.js | 13 ++----- 3 files changed, 7 insertions(+), 53 deletions(-) delete mode 100644 frontend/front/src/hooks/useHomesWithCompleted.js diff --git a/frontend/front/src/hooks/useHomesWithCompleted.js b/frontend/front/src/hooks/useHomesWithCompleted.js deleted file mode 100644 index 804c6fd3..00000000 --- a/frontend/front/src/hooks/useHomesWithCompleted.js +++ /dev/null @@ -1,38 +0,0 @@ -import { useMemo } from "react"; -import { useGetSurveyVisitsQuery } from "../api/apiSlice"; - -/** - * Workaround until https://github.com/codeforboston/urban-league-heat-pump-accelerator/pull/405 is merged - */ - -export const setHomesCompleted = (homes, surveyVisits) => - (homes || []).map((home) => ({ - ...home, - completed: !!surveyVisits?.find((sv) => sv.home_id === home.id), - })); - -export const useHomesWithCompleted = (homes) => { - const { data: surveyVisits } = useGetSurveyVisitsQuery(); - - return useMemo( - () => setHomesCompleted(homes, surveyVisits), - [homes, surveyVisits] - ); -}; - -export const useAssignmentsWithCompleted = (assignments) => { - const { data: surveyVisits } = useGetSurveyVisitsQuery(); - - return useMemo( - () => - (assignments || []).map((a) => { - const newHomes = setHomesCompleted(a.homes, surveyVisits); - return { - ...a, - homes: newHomes, - completed: a.homes.every((h) => h.completed === true), - }; - }), - [assignments, surveyVisits] - ); -}; diff --git a/frontend/front/src/pages/Admin/assignment/AssignTable.js b/frontend/front/src/pages/Admin/assignment/AssignTable.js index 49cd91e6..b777462c 100644 --- a/frontend/front/src/pages/Admin/assignment/AssignTable.js +++ b/frontend/front/src/pages/Admin/assignment/AssignTable.js @@ -18,7 +18,6 @@ import InputLabel from "@mui/material/InputLabel"; import Loader from "../../../components/Loader"; import Select from "@mui/material/Select"; import { ADMIN_ASSIGNMENT, withAdminPrefix } from "../../../routing/routes"; -import { useAssignmentsWithCompleted } from "../../../hooks/useHomesWithCompleted"; const AssignTable = () => { const goToBreadcrumb = useGoToBreadcrumb(); @@ -52,19 +51,17 @@ const AssignTable = () => { isLoading: isSurveyorsDataLoading, } = useGetSurveyorsQuery(); - const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); - const tableData = useMemo( () => - assignmentsWithCompleted && surveyorsData - ? assignmentsWithCompleted.map((a) => ({ + assignmentsData && surveyorsData + ? assignmentsData.map((a) => ({ ...a, surveyorData: a.surveyor_ids.map((id) => surveyorsData.find((s) => s.id === id) ), })) : [], - [assignmentsWithCompleted, surveyorsData] + [assignmentsData, surveyorsData] ); const [ diff --git a/frontend/front/src/pages/Surveyor/dashboard/ListView.js b/frontend/front/src/pages/Surveyor/dashboard/ListView.js index e92bd1ec..908ab8f1 100644 --- a/frontend/front/src/pages/Surveyor/dashboard/ListView.js +++ b/frontend/front/src/pages/Surveyor/dashboard/ListView.js @@ -10,7 +10,6 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import Loader from "../../../components/Loader"; import { useAssignmentsForCurrentUser } from "../../../hooks/useDataForSurveyor"; import { useSearchParams } from "react-router-dom"; -import { useAssignmentsWithCompleted } from "../../../hooks/useHomesWithCompleted"; const ListView = () => { const { @@ -19,18 +18,14 @@ const ListView = () => { error: isAssignmentsError, } = useAssignmentsForCurrentUser(); - const assignmentsWithCompleted = useAssignmentsWithCompleted(assignmentsData); - const [openAccordion, setOpenAccordion] = useState(); const [searchParams] = useSearchParams(); // open the accordion of the first incomplete assignment when the page opens useEffect(() => { - setOpenAccordion( - (assignmentsWithCompleted || []).find((a) => !a.completed)?.id - ); - }, [assignmentsWithCompleted]); + setOpenAccordion((assignmentsData || []).find((a) => !a.completed)?.id); + }, [assignmentsData]); return ( @@ -54,12 +49,12 @@ const ListView = () => { Your Assignments - {(!assignmentsWithCompleted || assignmentsData.length === 0) && ( + {(!assignmentsData || assignmentsData.length === 0) && ( No assignments found. )} - {assignmentsWithCompleted?.map((item, i) => { + {assignmentsData?.map((item, i) => { return ( Date: Sun, 23 Jul 2023 20:28:48 -0400 Subject: [PATCH 35/41] 438: replace admin dashboard with tabs --- frontend/front/src/pages/Admin/home/HomeTable.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index 3fc66fb3..3b08af50 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -20,6 +20,7 @@ import { useGetSurveyVisitsQuery, } from "../../../api/apiSlice"; import { useNavigate } from "react-router-dom"; +import { ADMIN_HOME, withAdminPrefix } from "../../../routing/routes"; // Formats addresses export const getAddress = (params) => { From 9f217f70d60e210f9172bacdc758fe81c963d8f6 Mon Sep 17 00:00:00 2001 From: "Efrain A. Davila" <105945226+EfrainAD@users.noreply.github.com> Date: Sun, 20 Aug 2023 01:11:38 -0400 Subject: [PATCH 36/41] bug fix from rebase --- frontend/front/src/pages/Admin/home/HomeTable.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index 3b08af50..923c1a06 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -8,13 +8,7 @@ import CustomSnackbar from "../../../components/CustomSnackbar"; import { DataGrid } from "@mui/x-data-grid"; import Loader from "../../../components/Loader"; import React from "react"; -import { - useGetHomesQuery, - useGetSurveyVisitsQuery, -} from "../../../api/apiSlice"; -import { useNavigate } from "react-router-dom"; -import { ADMIN_HOME, withAdminPrefix } from "../../../routing/routes"; import { useGetHomesQuery, useGetSurveyVisitsQuery, From 7d32c7950964498f7a7feaaa46f3514e142c675c Mon Sep 17 00:00:00 2001 From: "Efrain A. Davila" <105945226+EfrainAD@users.noreply.github.com> Date: Sun, 20 Aug 2023 14:59:27 -0400 Subject: [PATCH 37/41] Updated the survey visit id with the new updates to the backend --- .../front/src/pages/Admin/home/HomeTable.js | 54 +++++-------------- 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index 923c1a06..92724706 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -9,10 +9,7 @@ import { DataGrid } from "@mui/x-data-grid"; import Loader from "../../../components/Loader"; import React from "react"; -import { - useGetHomesQuery, - useGetSurveyVisitsQuery, -} from "../../../api/apiSlice"; +import { useGetHomesQuery } from "../../../api/apiSlice"; import { useNavigate } from "react-router-dom"; import { ADMIN_HOME, withAdminPrefix } from "../../../routing/routes"; @@ -40,7 +37,7 @@ const HomeTable = () => { const handleHomeLink = (home) => goToBreadcrumb("home", home); const handleUserLink = (home) => { - navigate("/admin/survey/visit/" + homeIdToSurveyVisitIdMap[home.id]); + navigate("/admin/survey/visit/" + home.survey_visit_ids[0]); }; const handleAssignmentLink = (assignment) => @@ -128,54 +125,31 @@ const HomeTable = () => { const { data: homesData, - isError: isFetchedHomesError, + isError: isHomesError, isLoading: isHomesDataLoading, } = useGetHomesQuery(); - const { - data: surveyVisitsData, - isError: isSurveyVisitsError, - isLoading: isSurveyVisitsDataLoading, - } = useGetSurveyVisitsQuery(); - - const homeIdToSurveyVisitIdMap = surveyVisitsData - ? surveyVisitsData.reduce((acc, visit) => { - return { ...acc, [visit.home_id]: visit.id }; - }, {}) - : {}; - const isDataReady = - !isHomesDataLoading && !isSurveyVisitsDataLoading && homesData; - - if (!isDataReady) { + if (isHomesDataLoading) { return ; } return ( - {isFetchedHomesError ? ( + {isHomesError ? ( ) : ( - <> - {isSurveyVisitsError && ( - - )} - - > + )} ); From 96996be8fff2482017438e7107858917b5fd01da Mon Sep 17 00:00:00 2001 From: "Efrain A. Davila" <105945226+EfrainAD@users.noreply.github.com> Date: Mon, 21 Aug 2023 23:52:00 -0400 Subject: [PATCH 38/41] PR Feedback: 1. Switch to string interpolation 2. style change that was commented on --- frontend/front/src/pages/Admin/home/HomeTable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/front/src/pages/Admin/home/HomeTable.js b/frontend/front/src/pages/Admin/home/HomeTable.js index 92724706..9e6bc398 100644 --- a/frontend/front/src/pages/Admin/home/HomeTable.js +++ b/frontend/front/src/pages/Admin/home/HomeTable.js @@ -37,7 +37,7 @@ const HomeTable = () => { const handleHomeLink = (home) => goToBreadcrumb("home", home); const handleUserLink = (home) => { - navigate("/admin/survey/visit/" + home.survey_visit_ids[0]); + navigate(`/admin/survey/visit/${home.survey_visit_ids[0]}`); }; const handleAssignmentLink = (assignment) => @@ -89,7 +89,7 @@ const HomeTable = () => { field: "completed", headerName: "Completed", renderCell: (params) => - params.row.completed === true ? ( + params.row.completed ? ( Date: Sat, 26 Aug 2023 14:33:04 -0400 Subject: [PATCH 39/41] removed some code that is not part of this issue --- .../src/pages/Admin/assignment/AssignTable.js | 52 ------------------- 1 file changed, 52 deletions(-) diff --git a/frontend/front/src/pages/Admin/assignment/AssignTable.js b/frontend/front/src/pages/Admin/assignment/AssignTable.js index 80dbc65d..cf65ce32 100644 --- a/frontend/front/src/pages/Admin/assignment/AssignTable.js +++ b/frontend/front/src/pages/Admin/assignment/AssignTable.js @@ -175,58 +175,6 @@ const AssignTable = () => { }`; }, }, - { - field: "surveyorData", - headerName: "Surveyor(s)", - flex: 1, - renderCell: (params) => { - return params.row.surveyorData ? ( - - {params.row.surveyorData.map((surveyor) => { - return ( - handleUserLink(surveyor)} - sx={{ - textAlign: "left", - minWidth: "max-content", - }} - > - {`${surveyor.firstname} ${surveyor.lastname}`} - - ); - })} - - ) : ( - "Unassigned" - ); - }, - }, - { - field: "completed", - headerName: "Completion", - width: "min-content", - maxWidth: 110, - flex: 1, - renderCell: (params) => { - let completed = 0; - params.row.homes.forEach((home) => { - if (home?.completed === true) { - completed++; - } - }); - return `${completed}/${params.row.homes.length} ${ - completed === params.row.homes.length && completed > 0 ? "✅" : "" - }`; - }, - }, ]; return ( From 8b1d3f502e5b59f19526af12b69e3cdab685e0a8 Mon Sep 17 00:00:00 2001 From: thiagobardini Date: Wed, 13 Sep 2023 12:26:01 -0400 Subject: [PATCH 40/41] Implemented the design suggestions provided by the UX team --- .../front/src/pages/Public/Assets/theme.js | 2 +- .../Public/Components/Button/ButtonWhite.js | 4 +- .../Public/Components/Typography/Heading2.js | 2 + .../Public/Components/Typography/Heading3.js | 2 + .../front/src/pages/Public/Layout/Footer.js | 38 ++++++++++++++----- .../pages/Public/Pages/BenefitsHeatPumps.js | 8 ++-- .../src/pages/Public/Pages/GetInvolved.js | 1 - .../Public/Pages/Home/CardBenefitsSection.js | 12 +++--- .../Public/Pages/Home/CardLinksSection.js | 16 ++++---- .../pages/Public/Pages/Home/CarrouselHero.js | 20 ++++++++-- .../src/pages/Public/Pages/Home/HeroPage.js | 30 ++++++++++++--- .../front/src/pages/Public/Pages/Home/Home.js | 18 ++++----- .../src/pages/Public/Pages/Home/Partners.js | 13 +++---- .../pages/Public/Pages/Home/Testimonial.js | 5 ++- 14 files changed, 113 insertions(+), 58 deletions(-) diff --git a/frontend/front/src/pages/Public/Assets/theme.js b/frontend/front/src/pages/Public/Assets/theme.js index 69fda2f9..e78c5806 100644 --- a/frontend/front/src/pages/Public/Assets/theme.js +++ b/frontend/front/src/pages/Public/Assets/theme.js @@ -18,7 +18,7 @@ const theme = createTheme({ // body body: { margin: 0, - fontWeight: 400, + // fontWeight: 400, fontSize: "16px", lineHeight: 1.5, letterSpacing: "0.00938em", diff --git a/frontend/front/src/pages/Public/Components/Button/ButtonWhite.js b/frontend/front/src/pages/Public/Components/Button/ButtonWhite.js index 4b734716..4d140051 100644 --- a/frontend/front/src/pages/Public/Components/Button/ButtonWhite.js +++ b/frontend/front/src/pages/Public/Components/Button/ButtonWhite.js @@ -14,7 +14,9 @@ const ButtonWhite = ({ text, to, children }) => { to={to} onClick={() => window.scrollTo(0, 0)} sx={{ - width: "200px", + width: "auto", + minWidth: "200px", + maxWidth: "250px", height: "50px", color: "var(--color-text-2)", background: "var(--bgColor-3)", diff --git a/frontend/front/src/pages/Public/Components/Typography/Heading2.js b/frontend/front/src/pages/Public/Components/Typography/Heading2.js index 10441919..0b181015 100644 --- a/frontend/front/src/pages/Public/Components/Typography/Heading2.js +++ b/frontend/front/src/pages/Public/Components/Typography/Heading2.js @@ -4,6 +4,7 @@ function Heading2({ text, textDecoration = "none" }) { return ( {text} diff --git a/frontend/front/src/pages/Public/Components/Typography/Heading3.js b/frontend/front/src/pages/Public/Components/Typography/Heading3.js index 6aead3bc..ac534aec 100644 --- a/frontend/front/src/pages/Public/Components/Typography/Heading3.js +++ b/frontend/front/src/pages/Public/Components/Typography/Heading3.js @@ -12,6 +12,7 @@ function Heading3({ text, icon = null, textDecoration = "none" }) { fontFamily: "var(--font-family-1)", color: "var(--color-text-2)", fontWeight: "600", + textTransform: "capitalize", }} > {text} @@ -27,6 +28,7 @@ function Heading3({ text, icon = null, textDecoration = "none" }) { textDecoration: textDecoration, textUnderlinePosition: "under", textDecorationColor: "var(--color-text-2)", + textTransform: "capitalize", }} > {text} diff --git a/frontend/front/src/pages/Public/Layout/Footer.js b/frontend/front/src/pages/Public/Layout/Footer.js index ab9813f0..1d058095 100644 --- a/frontend/front/src/pages/Public/Layout/Footer.js +++ b/frontend/front/src/pages/Public/Layout/Footer.js @@ -27,7 +27,6 @@ const footerItems = { "About Heat Pumps": { link: "about-heat-pump" }, "Benefits of Heat Pumps": { link: "benefits-heat-pump" }, "Get Involved": { link: "get-involved" }, - "Our Partners": { link: "our-partners-section" }, Testimonials: { link: "testimonial-section" }, }; @@ -36,8 +35,8 @@ const FooterWrapper = styled("div")(({ theme }) => ({ color: "var(--color-text-1)", position: "relative", "& .subtitle-footer": { - fontWeight: "bold", - textDecoration: "underline", + fontWeight: "700", + textDecoration: "none", }, })); @@ -87,7 +86,7 @@ const Footer = () => { - {/* BENEFITS OF HEAT PUMPS */} + {/* LEARN MORE */} { sx={{ color: "var(--color-text-1)", }} + primaryTypographyProps={{ + fontWeight: "300", + }} /> @@ -166,7 +168,12 @@ const Footer = () => { window.scrollTo(0, 0)} @@ -176,13 +183,16 @@ const Footer = () => { sx={{ color: "var(--color-text-1)", }} + primaryTypographyProps={{ + fontWeight: "300", + }} /> - {/* GET IN TOUCH */} + {/* CONTACT US */} { }} > <> - - Get to Know Us + + Contact Us { 617-635-4500 @@ -229,7 +243,11 @@ const Footer = () => { help@bostonhpa.org diff --git a/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js b/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js index 7ca1df4f..19d5d821 100644 --- a/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js +++ b/frontend/front/src/pages/Public/Pages/BenefitsHeatPumps.js @@ -22,7 +22,7 @@ import ButtonDarkBlue from "../Components/Button/ButtonDarkBlue"; const cardBenefits = [ { icon: moneyIcon, - title: "Saving Money", + title: "Lower utility bills", body: "Air source heat pumps (ASHPs) can reduce electricity usage for heating by up to 50% compared to electrical furnaces and baseboard heaters (", bodyLink: "https://www.amerenmissourisavings.com/hvac-air-source-heat-pump-education-flyer/", @@ -32,21 +32,21 @@ const cardBenefits = [ }, { icon: snowSunIcon, - title: "Improved Heating & Cooling", + title: "Better Heating & Cooling", body: "Heat pumps are an excellent way to heat and cool your home. They’re nearly silent, draw less electricity, and they are continuous: heat pumps’ continuous, low-level operation provides constant heating or cooling, eliminating the blasts of hot or cold that legacy systems usually create. To learn more about ASHP operation and benefits, ", bodyLink: "", link: "https://goclean.masscec.com/clean-energy-solutions/air-source-heat-pumps", }, { icon: communityIcon, - title: "Strengthening Community", + title: "Stronger Communities", body: "Boston residents want to stay in their homes and keep their communities strong, even while facing challenges from rising costs. Switching to heat pumps can lower utility costs, reducing the financial challenge of staying in the community. By also adding active cooling capacity, ASHPs also improve the “housing resiliency” of entire neighborhoods as annual temperatures rise. With both energy bills and temperatures on the rise, housing resiliency is more important than ever to empower communities to stay strong and stay together. To learn more, ", bodyLink: "", link: "https://www.energy.gov/policy/articles/heat-pumps-keep-homes-warm-and-bills-low-winter", }, { icon: heatIcon, - title: "Reducing Carbon Emissions", + title: "Lower Carbon Emissions", body: "Heat pumps are highly efficient heating and cooling systems that are electrically-powered. As such, they become “cleaner” whenever the source of their electric power becomes cleaner. Gas or oil fueled heating/cooling cannot benefit in the same way. How much of a difference will switching to ASHPs make in your case? Find specifics on the climate impact of a switch to heat pumps, ", bodyLink: "", link: "https://goclean.masscec.com/clean-energy-solutions/", diff --git a/frontend/front/src/pages/Public/Pages/GetInvolved.js b/frontend/front/src/pages/Public/Pages/GetInvolved.js index 496afeaf..aec3f3a0 100644 --- a/frontend/front/src/pages/Public/Pages/GetInvolved.js +++ b/frontend/front/src/pages/Public/Pages/GetInvolved.js @@ -33,7 +33,6 @@ function GetInvolved() { mediaSource: card3, title: "Discuss with your community", body: "You can host any sort of event and share flyers about how to help your neighbors save money by getting a heat pump!", - linkDescription: "Download informational flyer", linkDownload: CommunityFlyer, }, { diff --git a/frontend/front/src/pages/Public/Pages/Home/CardBenefitsSection.js b/frontend/front/src/pages/Public/Pages/Home/CardBenefitsSection.js index 45507111..7a57925b 100644 --- a/frontend/front/src/pages/Public/Pages/Home/CardBenefitsSection.js +++ b/frontend/front/src/pages/Public/Pages/Home/CardBenefitsSection.js @@ -41,7 +41,7 @@ const CardBenefitsSection = () => { id: 2, title: "Experience The All In One Comfort", paragraphs: [ - "Heat pumps can help you keep cool in the summer and warm in the winter. They are efficient, nearly silent, and convenient, providing comfort throughout the home.", + "The same heat pump that helps to cool in the summer can then provide warmth in the winter- it's one system that is efficient, quiet, and convenient, providing comfort throughout the home.", ], image: imageTwo, buttonText: "", @@ -49,9 +49,9 @@ const CardBenefitsSection = () => { }, { id: 3, - title: "Strengthen Community", + title: "Stronger communities", paragraphs: [ - "Because heat pumps can lower your utility bills, they can help seniors and low-income residents stay in their homes longer.", + "By helping to lower utility bills, heat pumps can lower the cost of living for residents, which in turn can support residents living on fixed- or low-incomes to remain in their homes longer, strengthening communities.", ], image: strengthenCommunity, buttonText: "", @@ -59,9 +59,9 @@ const CardBenefitsSection = () => { }, { id: 4, - title: "Environmentally Friendly ", + title: "Cleaner air", paragraphs: [ - "Heat pumps use electricity that can be produced by renewable sources, making them much more eco-friendly than gas or oil-fueled systems. With a single “green-powered” unit that heats and cools, your home’s carbon footprint is as low as it can go.", + "Heat pumps use electricity that can be produced by renewable sources. As the grid becomes more green, heat pumps become much more eco-friendly than gas or oil-fueled systems. With a single “green-powered” unit that heats and cools, your home’s carbon footprint is as low as it can go.", ], image: beEnvironmentally, buttonText: "", @@ -91,7 +91,7 @@ const CardBenefitsSection = () => { variant="body" sx={{ color: "var(--color-text-3)", display: "inline-block" }} > - Learn more about + Learn more about the diff --git a/frontend/front/src/pages/Public/Pages/Home/CardLinksSection.js b/frontend/front/src/pages/Public/Pages/Home/CardLinksSection.js index 6dfcc06b..a5738799 100644 --- a/frontend/front/src/pages/Public/Pages/Home/CardLinksSection.js +++ b/frontend/front/src/pages/Public/Pages/Home/CardLinksSection.js @@ -30,7 +30,7 @@ const GridLinkWrapper = styled(Grid)(({ theme }) => ({ justifyContent: "center", flexWrap: "nowrap", gap: "2rem", - [theme.breakpoints.down("md")]: { + [theme.breakpoints.down("lg")]: { flexWrap: "wrap", }, })); @@ -39,26 +39,27 @@ const CardLinksSection = () => { const linkCards = [ { id: 1, - title: "Add Your Voice", + title: "What is a heat pump?", paragraph: - "To a collections of homeowner’s questions and thoughts about heat pumps.", + "A heat pump is an energy-efficient system that heats your home in the winter, and cools your home in the summer.", button: { text: "Take the survey", to: "survey", }, idCSS: "survey-link-section", - image: imageVoice, + image: imageAbout, }, { id: 2, title: "About Us", - paragraph: "Empowering Boston residents to save, stay, and sustain.", + paragraph: + "The Boston Heat Pump Accelerator is an initiative of the Urban League of Eastern Massachusetts, in partnership with local and national organizations.", button: { text: "Learn more", to: "about-us", }, idCSS: "learnmore-link-section", - image: imageAbout, + image: imageVoice, }, ]; @@ -72,7 +73,8 @@ const CardLinksSection = () => { background: "var(--bgColor-3)", display: "flex", flexDirection: { xs: "column", sm: "row" }, - minWidth: "260px", + width: "100%", + minWidth: { xs: "260px", lg: "634px" }, maxWidth: { xs: "468px", sm: "680px" }, borderRadius: "2%", }} diff --git a/frontend/front/src/pages/Public/Pages/Home/CarrouselHero.js b/frontend/front/src/pages/Public/Pages/Home/CarrouselHero.js index 65e0cb93..59524290 100644 --- a/frontend/front/src/pages/Public/Pages/Home/CarrouselHero.js +++ b/frontend/front/src/pages/Public/Pages/Home/CarrouselHero.js @@ -22,16 +22,28 @@ function CarrouselHero(props) { { component: ( ), }, + // component: ( + // + // ), + // }, // { // component: ( // ({ display: "flex", @@ -70,7 +71,7 @@ const HeroPage = ({ {text1} {link !== "" && ( - {textBold} - + )} {text2} - + window.scrollTo(0, 0)} + sx={{ + width: "auto", + minWidth: "200px", + maxWidth: "250px", + height: "50px", + color: "var(--color-text-2)", + background: "var(--bgColor-3)", + borderRadius: "50px", + px: 3, + "&:hover": { + backgroundColor: "var(--bgColor-3)", + }, + }} + > + Benefits of heat pumps + diff --git a/frontend/front/src/pages/Public/Pages/Home/Home.js b/frontend/front/src/pages/Public/Pages/Home/Home.js index af2643e3..5049db91 100644 --- a/frontend/front/src/pages/Public/Pages/Home/Home.js +++ b/frontend/front/src/pages/Public/Pages/Home/Home.js @@ -35,28 +35,28 @@ const Home = () => { {/* TESTIMONIALS */} - + - {/* PARTNERS LOGO */} - - - - - - {/* CARDS BENEFITS */} + + {/* PARTNERS LOGO */} + + + + + ); }; diff --git a/frontend/front/src/pages/Public/Pages/Home/Partners.js b/frontend/front/src/pages/Public/Pages/Home/Partners.js index b8c4791c..4bd46900 100644 --- a/frontend/front/src/pages/Public/Pages/Home/Partners.js +++ b/frontend/front/src/pages/Public/Pages/Home/Partners.js @@ -7,7 +7,6 @@ import codeForAmericaLogo from "../../../../assets/images/partnersLogo/CFA.png"; import codeForBostonLogo from "../../../../assets/images/partnersLogo/CFB.png"; import pcb from "../../../../assets/images/partnersLogo/powercorp-boston.jpeg"; import AnimatedBox from "../../Components/AnimatedBox"; -import ButtonDarkBklue from "../../Components/Button/ButtonDarkBlue"; import Heading1 from "../../Components/Typography/Heading1"; const Partners = () => { @@ -91,22 +90,20 @@ const Partners = () => { sx={{ color: "var(--color-text-3)" }} textAlign={{ xs: "center", sm: "left" }} > - This initiative is a collaboration of Massachusetts government and - nonprofit organizations working together to help{" "} + The Boston Heat Pump Accelerator is an initiative of the Urban + League of Eastern Massachusetts, in partnership with local and + national organizations.{" "} - make heat pumps more available to low-income residents + Learn more . - - - diff --git a/frontend/front/src/pages/Public/Pages/Home/Testimonial.js b/frontend/front/src/pages/Public/Pages/Home/Testimonial.js index 6ac70ba7..63663a76 100644 --- a/frontend/front/src/pages/Public/Pages/Home/Testimonial.js +++ b/frontend/front/src/pages/Public/Pages/Home/Testimonial.js @@ -66,10 +66,11 @@ const Testimonial = () => { that again!” - + - Hear what else people have to say about their heat pumps! + Stories from other Massachusetts residents about their heat + pumps. Date: Wed, 13 Sep 2023 12:47:04 -0400 Subject: [PATCH 41/41] Text improvements --- .../front/src/pages/Public/Pages/Home/CardBenefitsSection.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/front/src/pages/Public/Pages/Home/CardBenefitsSection.js b/frontend/front/src/pages/Public/Pages/Home/CardBenefitsSection.js index 7a57925b..e0e08183 100644 --- a/frontend/front/src/pages/Public/Pages/Home/CardBenefitsSection.js +++ b/frontend/front/src/pages/Public/Pages/Home/CardBenefitsSection.js @@ -29,7 +29,7 @@ const CardBenefitsSection = () => { const cards = [ { id: 1, - title: "Saving Money", + title: "Lower energy bills", paragraphs: [ "Heat pumps are so energy efficient that they can lead to significant savings on monthly utility bills and lower maintenance, repair and replacement costs.", ], @@ -39,7 +39,7 @@ const CardBenefitsSection = () => { }, { id: 2, - title: "Experience The All In One Comfort", + title: "Comfort at home", paragraphs: [ "The same heat pump that helps to cool in the summer can then provide warmth in the winter- it's one system that is efficient, quiet, and convenient, providing comfort throughout the home.", ],