From 8e96eb2f0a332047b69bf7dc576a0df2e8badc42 Mon Sep 17 00:00:00 2001 From: ColinBuyck <53269332+ColinBuyck@users.noreply.github.com> Date: Thu, 12 Oct 2023 08:27:57 -0700 Subject: [PATCH] 337/jurisdiction array (#373) --- .../src/jurisdictions/dto/jurisdiction.dto.ts | 10 ++++- .../dto/jurisdictions-list-query-params.ts | 16 ++++++++ .../jurisdictions/jurisdictions.controller.ts | 9 ++++- .../services/jurisdictions.service.ts | 21 +++++++--- build/docker/Dockerfile.sites-generic | 7 ++++ ci/buildspec/build_public.yml | 5 ++- sites/public/.env.template | 1 + sites/public/next.config.js | 4 ++ .../components/listings/ListingsCombined.tsx | 5 +-- .../src/components/listings/ListingsList.tsx | 5 +-- .../search/ListingsSearchCombined.tsx | 3 -- sites/public/src/pages/index.tsx | 23 ++--------- .../public/src/pages/listing/[id]/[slug].tsx | 1 - sites/public/src/pages/listings.tsx | 39 +++++-------------- 14 files changed, 79 insertions(+), 70 deletions(-) create mode 100644 backend/core/src/jurisdictions/dto/jurisdictions-list-query-params.ts diff --git a/backend/core/src/jurisdictions/dto/jurisdiction.dto.ts b/backend/core/src/jurisdictions/dto/jurisdiction.dto.ts index b15d8c5ef3..0789c4dc6e 100644 --- a/backend/core/src/jurisdictions/dto/jurisdiction.dto.ts +++ b/backend/core/src/jurisdictions/dto/jurisdiction.dto.ts @@ -1,6 +1,6 @@ import { OmitType } from "@nestjs/swagger" import { Expose, Type } from "class-transformer" -import { ArrayMaxSize, IsArray, IsString, ValidateNested } from "class-validator" +import { ArrayMaxSize, IsArray, IsBoolean, IsString, ValidateNested } from "class-validator" import { ValidationsGroupsEnum } from "../../shared/types/validations-groups-enum" import { Jurisdiction } from "../entities/jurisdiction.entity" import { IdDto } from "../../shared/dto/id.dto" @@ -19,4 +19,12 @@ export class JurisdictionSlimDto extends IdNameDto { @Expose() @IsString({ groups: [ValidationsGroupsEnum.default] }) publicUrl: string + + @Expose() + @IsBoolean({ groups: [ValidationsGroupsEnum.default] }) + enableAccessibilityFeatures: boolean | null + + @Expose() + @IsBoolean({ groups: [ValidationsGroupsEnum.default] }) + enableUtilitiesIncluded: boolean | null } diff --git a/backend/core/src/jurisdictions/dto/jurisdictions-list-query-params.ts b/backend/core/src/jurisdictions/dto/jurisdictions-list-query-params.ts new file mode 100644 index 0000000000..6f7db089c6 --- /dev/null +++ b/backend/core/src/jurisdictions/dto/jurisdictions-list-query-params.ts @@ -0,0 +1,16 @@ +import { Expose } from "class-transformer" +import { ApiProperty } from "@nestjs/swagger" +import { IsArray, IsOptional } from "class-validator" +import { ValidationsGroupsEnum } from "../../shared/types/validations-groups-enum" + +export class JurisdictionsListParams { + @Expose() + @ApiProperty({ + type: Array, + example: ["Bay Area", "Contra Costa"], + required: false, + }) + @IsOptional({ groups: [ValidationsGroupsEnum.default] }) + @IsArray({ groups: [ValidationsGroupsEnum.default] }) + names?: string[] +} diff --git a/backend/core/src/jurisdictions/jurisdictions.controller.ts b/backend/core/src/jurisdictions/jurisdictions.controller.ts index dad91aeb90..7edad489d3 100644 --- a/backend/core/src/jurisdictions/jurisdictions.controller.ts +++ b/backend/core/src/jurisdictions/jurisdictions.controller.ts @@ -6,6 +6,7 @@ import { Param, Post, Put, + Query, UseGuards, UsePipes, ValidationPipe, @@ -21,6 +22,7 @@ import { JurisdictionDto } from "./dto/jurisdiction.dto" import { JurisdictionCreateDto } from "./dto/jurisdiction-create.dto" import { JurisdictionUpdateDto } from "./dto/jurisdiction-update.dto" import { IdDto } from "../shared/dto/id.dto" +import { JurisdictionsListParams } from "./dto/jurisdictions-list-query-params" @Controller("jurisdictions") @ApiTags("jurisdictions") @@ -33,8 +35,11 @@ export class JurisdictionsController { @Get() @ApiOperation({ summary: "List jurisdictions", operationId: "list" }) - async list(): Promise { - return mapTo(JurisdictionDto, await this.jurisdictionsService.list()) + async list( + @Query() + queryParams: JurisdictionsListParams + ): Promise { + return mapTo(JurisdictionDto, await this.jurisdictionsService.list(queryParams)) } @Post() diff --git a/backend/core/src/jurisdictions/services/jurisdictions.service.ts b/backend/core/src/jurisdictions/services/jurisdictions.service.ts index d5d3367dd8..66153b4083 100644 --- a/backend/core/src/jurisdictions/services/jurisdictions.service.ts +++ b/backend/core/src/jurisdictions/services/jurisdictions.service.ts @@ -1,10 +1,11 @@ import { NotFoundException } from "@nestjs/common" import { InjectRepository } from "@nestjs/typeorm" -import { FindOneOptions, Repository } from "typeorm" +import { FindOneOptions, In, Repository } from "typeorm" import { Jurisdiction } from "../entities/jurisdiction.entity" import { JurisdictionCreateDto } from "../dto/jurisdiction-create.dto" import { JurisdictionUpdateDto } from "../dto/jurisdiction-update.dto" import { assignDefined } from "../../shared/utils/assign-defined" +import { JurisdictionsListParams } from "../dto/jurisdictions-list-query-params" export class JurisdictionsService { constructor( @@ -18,10 +19,20 @@ export class JurisdictionsService { }, } - list(): Promise { - return this.repository.find({ - join: this.joinOptions, - }) + async list(queryParams?: JurisdictionsListParams): Promise { + const obj = queryParams?.names + ? await this.repository.find({ + where: { name: In([...queryParams.names]) }, + join: this.joinOptions, + }) + : await this.repository.find({ + join: this.joinOptions, + }) + + if (!obj) { + throw new NotFoundException() + } + return obj } async create(dto: JurisdictionCreateDto): Promise { diff --git a/build/docker/Dockerfile.sites-generic b/build/docker/Dockerfile.sites-generic index 07275630c2..e3893788da 100644 --- a/build/docker/Dockerfile.sites-generic +++ b/build/docker/Dockerfile.sites-generic @@ -14,6 +14,8 @@ ARG GTM_KEY # feature flags ARG FEATURE_LISTINGS_APPROVAL ARG SHOW_PROFESSIONAL_PARTNERS +ARG NOTIFICATIONS_SIGN_UP_URL + # The base image will contain all the source code needed for our site FROM node:18.14-alpine AS base @@ -118,6 +120,8 @@ ARG MAPBOX_TOKEN ARG GTM_KEY ARG FEATURE_LISTINGS_APPROVAL ARG SHOW_PROFESSIONAL_PARTNERS +ARG NOTIFICATIONS_SIGN_UP_URL + # We need to have this nested 2 layers deep due to hardcoded paths in package.json WORKDIR /app/sites/${SITE} @@ -138,6 +142,9 @@ ENV GTM_KEY=$GTM_KEY # feature flags ENV FEATURE_LISTINGS_APPROVAL=$FEATURE_LISTINGS_APPROVAL ENV SHOW_PROFESSIONAL_PARTNERS=$SHOW_PROFESSIONAL_PARTNERS +ENV NOTIFICATIONS_SIGN_UP_URL=$NOTIFICATIONS_SIGN_UP_URL + + # Build/compile RUN yarn build diff --git a/ci/buildspec/build_public.yml b/ci/buildspec/build_public.yml index 3225494e02..c75604cb11 100644 --- a/ci/buildspec/build_public.yml +++ b/ci/buildspec/build_public.yml @@ -39,6 +39,7 @@ phases: --build-arg "MAPBOX_TOKEN=${MAPBOX_TOKEN}" --build-arg "GTM_KEY=${GTM_KEY}" --build-arg "SHOW_PROFESSIONAL_PARTNERS=$SHOW_PROFESSIONAL_PARTNERS" + --build-arg "NOTIFICATIONS_SIGN_UP_URL=$NOTIFICATIONS_SIGN_UP_URL" --target test -t sites/public:test . @@ -62,11 +63,11 @@ phases: --build-arg "MAPBOX_TOKEN=${MAPBOX_TOKEN}" --build-arg "GTM_KEY=${GTM_KEY}" --build-arg "SHOW_PROFESSIONAL_PARTNERS=$SHOW_PROFESSIONAL_PARTNERS" + --build-arg "NOTIFICATIONS_SIGN_UP_URL=$NOTIFICATIONS_SIGN_UP_URL" --target run -t sites/public:run-candidate . - - + # Tag the run image - docker tag sites/public:run-candidate "${ECR_REPO}/public:run-${CODEBUILD_RESOLVED_SOURCE_VERSION:0:8}" diff --git a/sites/public/.env.template b/sites/public/.env.template index a4cfd2a01f..bf0724b5c0 100644 --- a/sites/public/.env.template +++ b/sites/public/.env.template @@ -8,6 +8,7 @@ MAPBOX_TOKEN= LANGUAGES=en,es,zh,vi,tl IDLE_TIMEOUT=5 JURISDICTION_NAME=Bay Area +NOTIFICATIONS_SIGN_UP_URL=https://public.govdelivery.com/accounts/CAMTC/signup/36832 CLOUDINARY_CLOUD_NAME=exygy # next js cache revalidate CACHE_REVALIDATE=60 diff --git a/sites/public/next.config.js b/sites/public/next.config.js index a58612aab7..ad280f0d81 100644 --- a/sites/public/next.config.js +++ b/sites/public/next.config.js @@ -41,6 +41,9 @@ module.exports = withBundleAnalyzer( withTM({ env: { backendApiBase: BACKEND_API_BASE, // this has to be set for tests + backendProxyBase: process.env.BACKEND_PROXY_BASE, + googleMapsApiKey: process.env.GOOGLE_MAPS_API_KEY, + listingsQuery: LISTINGS_QUERY, listingPhotoSize: process.env.LISTING_PHOTO_SIZE || "1302", mapBoxToken: MAPBOX_TOKEN, housingCounselorServiceUrl: HOUSING_COUNSELOR_SERVICE_URL, @@ -50,6 +53,7 @@ module.exports = withBundleAnalyzer( cacheRevalidate: process.env.CACHE_REVALIDATE ? Number(process.env.CACHE_REVALIDATE) : 60, cloudinaryCloudName: process.env.CLOUDINARY_CLOUD_NAME, showProfessionalPartners: process.env.SHOW_PROFESSIONAL_PARTNERS === "TRUE", + notificationsSignUpUrl: process.env.NOTIFICATIONS_SIGN_UP_URL || null, // start Doorway env variables //googleMapsApiKey: process.env.GOOGLE_MAPS_API_KEY, // moved to runtime config diff --git a/sites/public/src/components/listings/ListingsCombined.tsx b/sites/public/src/components/listings/ListingsCombined.tsx index 46a8370dd3..4121cb9250 100644 --- a/sites/public/src/components/listings/ListingsCombined.tsx +++ b/sites/public/src/components/listings/ListingsCombined.tsx @@ -1,12 +1,11 @@ import React, { useState } from "react" -import { Jurisdiction, Listing } from "@bloom-housing/backend-core/types" +import { Listing } from "@bloom-housing/backend-core/types" import { ListingsMap } from "./ListingsMap" import { ListingsList } from "./ListingsList" import { useSwipeable } from "react-swipeable" import styles from "./ListingsCombined.module.scss" type ListingsCombinedProps = { - jurisdiction: Jurisdiction listings: Listing[] currentPage: number lastPage: number @@ -68,7 +67,6 @@ const ListingsCombined = (props: ListingsCombinedProps) => {
{
{ className="is-normal-primary-lighter" > diff --git a/sites/public/src/components/listings/search/ListingsSearchCombined.tsx b/sites/public/src/components/listings/search/ListingsSearchCombined.tsx index 50b5cce3ad..165e74eb61 100644 --- a/sites/public/src/components/listings/search/ListingsSearchCombined.tsx +++ b/sites/public/src/components/listings/search/ListingsSearchCombined.tsx @@ -4,14 +4,12 @@ import { ListingList, pushGtmEvent, AuthContext } from "@bloom-housing/shared-he import { ListingSearchParams, generateSearchQuery } from "../../../lib/listings/search" import { ListingService } from "../../../lib/listings/listing-service" import { ListingsCombined } from "../ListingsCombined" -import { Jurisdiction } from "@bloom-housing/backend-core" import { AppearanceSizeType, Button } from "@bloom-housing/doorway-ui-components" import { FormOption, ListingsSearchModal } from "./ListingsSearchModal" import { AppearanceBorderType, t } from "@bloom-housing/ui-components" type ListingsSearchCombinedProps = { - jurisdiction: Jurisdiction searchString?: string googleMapsApiKey: string listingsEndpoint: string @@ -127,7 +125,6 @@ function ListingsSearchCombined(props: ListingsSearchCombinedProps) { /> - +
- {props.jurisdiction && props.jurisdiction.notificationsSignUpURL && ( + {notificationsSignUpURL && ( @@ -189,17 +188,3 @@ export default function Home(props: IndexProps) { ) } - -export async function getServerSideProps() { - const jurisdiction = await fetchJurisdictionByName( - runtimeConfig.getBackendApiBase(), - runtimeConfig.getJurisdictionName() - ) - - return { - props: { - jurisdiction, - counties: locations, - }, - } -} diff --git a/sites/public/src/pages/listing/[id]/[slug].tsx b/sites/public/src/pages/listing/[id]/[slug].tsx index baaa564666..378a072f6c 100644 --- a/sites/public/src/pages/listing/[id]/[slug].tsx +++ b/sites/public/src/pages/listing/[id]/[slug].tsx @@ -126,7 +126,6 @@ export async function getServerSideProps(context: { locale: string }) { let response - const listingServiceUrl = runtimeConfig.getListingServiceUrl() try { diff --git a/sites/public/src/pages/listings.tsx b/sites/public/src/pages/listings.tsx index c01db04c75..80bf5b4732 100644 --- a/sites/public/src/pages/listings.tsx +++ b/sites/public/src/pages/listings.tsx @@ -6,29 +6,28 @@ import ListingsSearchCombined, { locations, } from "../components/listings/search/ListingsSearchCombined" import { FormOption } from "../components/listings/search/ListingsSearchModal" -import { runtimeConfig } from "../lib/runtime-config" -import { fetchJurisdictionByName } from "../lib/hooks" -import { Jurisdiction } from "@bloom-housing/backend-core/types" import Layout from "../layouts/application" export interface ListingsProps { - jurisdiction: Jurisdiction listingsEndpoint: string googleMapsApiKey: string - initialSearch?: string bedrooms: FormOption[] bathrooms: FormOption[] - locations: FormOption[] } export default function ListingsPage(props: ListingsProps) { const pageTitle = `${t("pageTitle.rent")} - ${t("nav.siteTitle")}` const metaDescription = t("pageDescription.welcome") const metaImage = "" // TODO: replace with hero image - let searchString = props.initialSearch || "" + let searchString = + "counties:Alameda,Contra Costa,Marin,Napa,San Francisco,San Mateo,Santa Clara,Solano,Sonoma" const url = new URL(document.location.toString()) const searchParam = url.searchParams.get("search") + const listingsEndpoint = `${process.env.backendProxyBase || process.env.backendApiBase}${ + process.env.listingsQuery + }` + const googleMapsApiKey = process.env.googleMapsApiKey // override the search value if present in url if (searchParam) { @@ -42,33 +41,13 @@ export default function ListingsPage(props: ListingsProps) { ) } - -export async function getServerSideProps() { - const jurisdiction = await fetchJurisdictionByName( - runtimeConfig.getBackendApiBase(), - runtimeConfig.getJurisdictionName() - ) - - return { - props: { - jurisdiction, - listingsEndpoint: runtimeConfig.getListingServiceUrl(), - googleMapsApiKey: runtimeConfig.getGoogleMapsApiKey(), - // show Bloom counties by default - initialSearch: - "counties:Alameda,Contra Costa,Marin,Napa,San Francisco,San Mateo,Santa Clara,Solano,Sonoma", - locations: locations, - }, - } -}